F diff --git a/css/style.css b/css/style.css --- a/css/style.css +++ b/css/style.cssdisplay: flex;flex: 1 0 0;align-items: stretch;-- user-select: none;- -webkit-user-select: none;- -ms-user-select: none;}#page > * {justify-content: center;}+ .filesystem > h2,form > h2 {color: #4d4d4d;margin: 0;border-top-right-radius: 0.5rem;}-- .window h3 button,- .window > h2 button- {- border: none;- padding: 0.3rem 1rem;- background: inherit;- border-radius: 0;- }-- .window h3 button:not(.pathentry):hover {- background: white;- }-- .window h3 > .separator {- flex: 0 0 1px;- align-self: stretch;- background: #bbb;- }-- .window > h2 > *:first-child {- border-top-left-radius: 0.5rem;- }form p {margin: 1rem 0px 0.3rem 0px;}+.hero_form_error {animation: fadein 0.2s;background-color: #ff4d4d;display: none;}- .window {- margin: 0rem;+ .filesystem {+ background: #fafafa;+ margin: 1rem;padding: 0;box-shadow: 0 0.8rem 1.3rem rgba(0,0,0,0.2);border-radius: 0.5rem;border: 1px solid #b9b9b9;display: block;- position: absolute;- top: 0;- left: 0;- width: 800px;- height: 600px;-- transition: opacity 0.3s;- display: flex;- flex-direction: column;- }-- .foldercontents, .filecontents {- background: rgba(250, 250, 250, .8);- flex: 1 0 0;- }-- .filecontents {- padding: 0.8rem;- font-size: 1.1rem;- }-- .window h3,- .window > h2 {- color: #4d4d4d;- background: #f0f0f0;- margin: 0;--- display: flex;- align-items: stretch;- font-weight: normal;- padding: 0rem;- border-bottom: 1px solid #bbb;- }-- .window > h2 {- font-size: 1.3rem;- border-top-left-radius: 0.5rem;- border-top-right-radius: 0.5rem;- cursor: grab;- }-- .window h3 {- font-size: 1.2rem;- }-- .window.dragged {- /* opacity: 0.9; */}.files {display: flex;flex-direction: column;align-items: center;- border: 1px solid rgba(0,0,0,0);+ border: 1px solid #fafafa;border-radius: 0.1rem;}}.file:hover:not(.dragged) {- background: rgba(255,255,255, 0.5);+ background: white;color: black;border-color: #ddd;}filter: brightness(120%);}+ .filesystem > h2 {+ display: flex;+ align-items: stretch;+ font-weight: normal;+ padding: 0rem;+ border-bottom: 1px solid #bbb;+ font-size: 1.3rem;+ }++ .filesystem > h2 button {+ border: none;+ padding: 0.3rem 1rem;+ background: inherit;+ border-radius: 0;+ }++ .filesystem > h2 button:not(.pathentry):hover {+ background: white;+ }++ .filesystem > h2 > .separator {+ flex: 0 0 1px;+ align-self: stretch;+ background: #bbb;+ }++ .filesystem > h2 > *:first-child {+ border-top-left-radius: 0.5rem;+ }+.path {display: flex;align-items: stretch;+ font-size: 0.8em;}.path > .separator {background: #2e91db;color: white;}-- .backdrop {- position: absolute;- width: 100%;- height: 100%;-- user-select: none;- -webkit-user-select: none;- -ms-user-select: none;- background-image: url("/img/backdrop.jpg");- background-size: cover;- }F diff --git a/img/backdrop.jpg b/img/backdrop.jpg deleted file mode 100644B Binary files a/img/backdrop.jpg and /dev/null differF diff --git a/loggedin.js b/loggedin.js --- a/loggedin.js +++ b/loggedin.jsconst upload_form = document.getElementById("upload_form");const the_file = document.getElementById("the_file");const filename_input = document.getElementById("filename");- const current_directory = document.getElementById("current_directory");+ const upload_btn = document.getElementById("upload_btn");+ const the_path = document.getElementById("the_path");+ const current_directory = document.getElementById("current_directory");const upload_parent_directory = document.getElementById("upload_parent_directory");the_file.onchange = on_file_added;- var windows = [];- var focus = null;+ var pwd = [];var context_menu = null;var dragging = null;body: new FormData(upload_form)}).then((resp) => {if (resp.status == 200) {- openfile(true);+ load_dir();} else {alert("Upload failed");}}}- function update_path_visuals() {- var the_path = focus.visuals.getElementsByClassName('path')[0];-- while (the_path.children.length > 0)+ function load_dir() {+ while (the_path.children.length > 1)the_path.removeChild(the_path.lastChild);- for (let i = -1; i < focus.pwd.length; i++) {- var d;- if (i >= 0) {- d = focus.pwd[i];- var separator_div = document.createElement('div');- separator_div.classList.add('separator');- the_path.appendChild(separator_div);- separator_div.innerText = "»";- }- else- d = "Root";+ for (let i = 0; i < pwd.length; i++) {+ var d = pwd[i];+ var separator_div = document.createElement('div');+ separator_div.classList.add('separator');+ the_path.appendChild(separator_div);+ separator_div.innerText = "»";var entry = document.createElement('button');entry.classList.add('pathentry');add_link_functionality(entry, i + 1);}- }-- function openfile_nondir() {- var data = new FormData();- data.append('folder', get_path(focus.pwd.length - 1));- data.append('filename', focus.pwd[focus.pwd.length - 1]);-- var xhr = new XMLHttpRequest();-- focus.pwd.push();-- update_path_visuals();-- xhr.open('POST', '/php/readfile.php', true);-- focus.filecontents.innerText = "Loading...";- focus.filecontents.style.display = 'block';- focus.foldercontents.style.display = 'none';-- xhr.onload = function () {- focus.filecontents.innerText = xhr.responseText;- };- xhr.send(data);- }-- function opendir() {-- update_path_visuals();var data = new FormData();data.append('path', get_path());};xhr.send(data);-- focus.filecontents.style.display = 'none';- focus.foldercontents.style.display = 'block';- }-- function openfile(is_directory) {- if (is_directory) {- opendir();- } else {- openfile_nondir();- }}function delete_file(filename) {var xhr = new XMLHttpRequest();xhr.open('POST', '/php/delete.php', true);xhr.onload = function () {- openfile(true);+ load_dir();};xhr.send(data);}var xhr = new XMLHttpRequest();xhr.open('POST', '/php/rename.php', true);xhr.onload = function () {- openfile(true);+ load_dir();};xhr.send(data);}var xhr = new XMLHttpRequest();xhr.open('POST', '/php/move.php', true);xhr.onload = function () {- openfile(true);+ load_dir();};xhr.send(data);}- function new_folder() { var dirname = prompt(`Directory name`, "New Folder");+ function new_folder() {+ var dirname = prompt(`Directory name`, "New Folder");if (!dirname)return;var xhr = new XMLHttpRequest();xhr.open('POST', '/php/mkdir.php', true);xhr.onload = function () {- openfile(true);+ load_dir();};xhr.send(data);}- function begin_drag_fileview(e, fileview) {+ function begin_drag(e, fileview) {if (dragging)end_drag();dragging_placeholder = document.createElement('div');- dragging_fileview = fileview;+ fileview.visuals.parentNode.insertBefore(dragging_placeholder, fileview.visuals);dragging = fileview.visuals;-- // document.body.appendChild(dragging);-- begin_drag(e, fileview.visuals,);- }-- function begin_drag(e, obj) {-- dragging = obj;+ dragging_fileview = fileview;dragging.classList.add("dragged");var elemRect = dragging.getBoundingClientRect();- dragging_offset_x = e.clientX - elemRect.left;- dragging_offset_y = -e.clientY + elemRect.top;-- if (dragging_placeholder)- obj.parentNode.insertBefore(dragging_placeholder, obj);-- dragging.style.left = (e.clientX - dragging_offset_x) + "px";- dragging.style.top = (e.clientY + dragging_offset_y) + "px";+ dragging_offset_x = elemRect.width - (elemRect.left - e.clientX);+ dragging_offset_y = elemRect.top - e.clientY;+ dragging.style.position = "absolute";dragging.style.width = elemRect.width + "px";dragging.style.height = elemRect.height + "px";-- dragging.style.position = "absolute";document.body.appendChild(dragging);- }- function end_drag(_e) {- if (dragging_placeholder) {- dragging_placeholder.parentNode.insertBefore(dragging, dragging_placeholder);- dragging_placeholder.remove();- dragging_placeholder = null;- }-- if (dragging_fileview) {- dragging.style.removeProperty("position");- dragging.style.removeProperty("width");- dragging.style.removeProperty("height");- dragging.style.removeProperty("left");- dragging.style.removeProperty("top");- dragging_fileview = null;- }+ dragging.style.left = (e.clientX - dragging_offset_x) + "px";+ dragging.style.top = (e.clientY + dragging_offset_y) + "px";+ }+ function end_drag(e) {+ dragging_placeholder.parentNode.insertBefore(dragging, dragging_placeholder);+ dragging_placeholder.remove();+ dragging.style.removeProperty("position");+ dragging.style.removeProperty("width");+ dragging.style.removeProperty("height");+ dragging.style.removeProperty("left");+ dragging.style.removeProperty("top");dragging.classList.remove("dragged");dragging = null;}function add_link_functionality(link, length) {link.onclick = () => {- focus.pwd.length = length,- openfile(true);+ pwd.length = length,+ load_dir();}link.onmouseup = (e) => {- if (dragging && dragging_fileview) {+ if (dragging) {var new_folder = get_path(length);move_file(new_folder, dragging_fileview.filename);end_drag();}}- class Window {- constructor(pwd) {- this.pwd = pwd;- }- }--- function make_window(pwd) {- var wnd = new Window(pwd);- windows.push(wnd);+ add_link_functionality(document.getElementById("home_path_entry"), 0);- var wnd_html = document.createElement('div');- wnd_html.classList.add('window');-- var h2 = document.createElement('h2');- wnd_html.appendChild(h2);+ function open_file(fileview) {+ var data = new FormData();+ data.append('folder', get_path());+ data.append('filename', fileview.filename);- h2.onmousedown = (e) => {- begin_drag(e, wnd_html);- e.preventDefault();+ var xhr = new XMLHttpRequest();+ xhr.open('POST', '/php/readfile.php', true);+ xhr.onload = function () {+ console.log(xhr.responseText);};-- path = document.createElement('div');- path.classList.add('path');- h2.appendChild(path);-- wnd_html.style.width = "800px";- wnd_html.style.height = "600px";- wnd_html.style.position = "absolute";- wnd_html.style.left = "300px";- wnd_html.style.top = "300px";-- wnd.visuals = wnd_html;-- {- wnd.foldercontents = document.createElement('div');- wnd.foldercontents.classList.add('foldercontents');- wnd_html.appendChild(wnd.foldercontents);-- var h3 = document.createElement('h3');- wnd.foldercontents.appendChild(h3);-- var upload_btn = document.createElement('button');- upload_btn.innerText = "Upload";- upload_btn.onclick = () => { begin_upload(); }- h3.appendChild(upload_btn);-- var separator = document.createElement('div');- separator.classList.add('separator');- h3.appendChild(separator);-- var new_folder_btn = document.createElement('button');- new_folder_btn.innerText = "New Folder";- new_folder_btn.onclick = () => { new_folder(); }- h3.appendChild(new_folder_btn);-- separator = document.createElement('div');- separator.classList.add('separator');- h3.appendChild(separator);-- wnd.filegrid = document.createElement('div');- wnd.filegrid.classList.add('files');- wnd.foldercontents.appendChild(wnd.filegrid);- }-- {- wnd.filecontents = document.createElement('div');- wnd.filecontents.classList.add('filecontents');- wnd_html.appendChild(wnd.filecontents);- }-- document.body.appendChild(wnd_html);- return wnd;+ xhr.send(data);}-function add_file_visuals(fileview) {var visuals = document.createElement('div');fileview.visuals = visuals;var filename = document.createElement('div');if (fileview.is_directory) {- if (fileview.filename == "trash")- img.src="/mimeicons/user-trash.png";- else- img.src="/mimeicons/directory.png";+ img.src="/mimeicons/directory.png";+ visuals.onclick = () => {+ pwd.push(fileview.filename);+ load_dir();+ }} else {img.src=`/mimeicons/${fileview.mimetype.replace("/", "-")}.png`;- }-- visuals.onclick = () => {- focus.pwd.push(fileview.filename);- openfile(fileview.is_directory);+ visuals.onclick = () => {+ open_file(fileview);+ }}visuals.oncontextmenu = (e) => {if (!dragging) {context(e, [['Open', () => {- focus.pwd.push(fileview.filename);- openfile(fileview.is_directory);+ if (fileview.is_directory) {+ pwd.push(fileview.filename);+ load_dir();+ } else {+ open_file(fileview);+ }}],- ['Open in New Window', () => {alert('not implemented')}],['Rename', () => { rename_file(fileview.filename); }],['Share', () => {alert('not implemented')}],['Delete', () => { delete_file(fileview.filename); }],}visuals.ondragstart = (e) => {- begin_drag_fileview(e, fileview);+ begin_drag(e, fileview);e.preventDefault();};visuals.appendChild(img);visuals.appendChild(filename);- focus.filegrid.appendChild(visuals);+ current_directory.appendChild(visuals);}function begin_upload() {function get_path(max_length) {if (max_length == undefined) {- max_length = focus.pwd.length;+ max_length = pwd.length;}var path = "/";for (let i = 0; i < max_length; i++) {- path += focus.pwd[i];+ path += pwd[i];if (i != max_length - 1)path += "/";}}}- document.body.onmouseup = (_e) => {+ document.body.onmouseup = (e) => {if (dragging)end_drag();}context_menu.remove();}-- var root_window = make_window([]);- focus = root_window;- openfile(true);+ load_dir();F diff --git a/loggedin.php b/loggedin.php --- a/loggedin.php +++ b/loggedin.php+ <div>+ <div class="filesystem">+ <h2 style="display: flex; gap: 0rem;">+ <button id="upload_btn" onclick="begin_upload()">Upload</button>+ <div class="separator"></div>+ <button id="upload_btn" onclick="new_folder()">New Folder</button>+ <div class="separator"></div>+ <div class="path" id="the_path">+ <button class="pathentry" id="home_path_entry">+ <?php+ $user=$_SESSION['user_object'];+ echo $user->username;+ ?>+ 's files</button>+ </div>+ </h2>- <div class="backdrop">+ <div class="files" id="current_directory">+ </div>+ </div>++ </div><form id="upload_form" style="display:none;" action="php/upload.php" method="post" enctype="multipart/form-data"><input id="filename" name="filename">F diff --git a/mimeicons/user-trash-full.png b/mimeicons/user-trash-full.png deleted file mode 100644B Binary files a/mimeicons/user-trash-full.png and /dev/null differF diff --git a/mimeicons/user-trash.png b/mimeicons/user-trash.png deleted file mode 100644B Binary files a/mimeicons/user-trash.png and /dev/null differF diff --git a/php/database.php b/php/database.php --- a/php/database.php +++ b/php/database.phpwe remove the node and1. move the file represented by the node to the trash folder2. remove the file+ 3. if node is a directory - delete all children nodesdepends on the conf file*/function delete_node_by_id(int $node_id)}}++ function unlink_nodes(int $dir_id, int $node_id)+ {+ $prep=$this->pdo->prepare("delete from node_links+ where directory_id=:dir_id and node_id=:node_id+ ");+ $prep->bindParam(':dir_id',$dir_id);+ $prep->bindParam(':node_id',$node_id);+ if($prep->execute()==false)+ {+ error_log("there was an error with the first statement in unlink_nodes");+ return;+ }+ $prep=$this->pdo->prepare("select node_id+ from node_links+ where node_id=:id+ ");+ $prep->bindParam(':id',$node_id);+ if($prep->execute()==false)+ {+ error_log("there was an error with the second statement in unlink_nodes");+ return;+ }+ if(count($prep->fetchALL(PDO::FETCH_ASSOC))==0)+ {+ delete_node_by_id($node_id);+ }+++ }+function create_home_directory():int{$ret=$this->create_dangling_directory();F diff --git a/php/readfile.php b/php/readfile.php --- a/php/readfile.php +++ b/php/readfile.php$dir = get_directory($folder, $user);if (!$dir) {- error_log("/php/readfile.php - invalid directory '$folder'");+ error_log("/php/readfile.php - invalid directory");http_response_code(409);exit(0);}}}if (!$file_node) {- error_log("/php/readfile.php - invalid filename '$filename'");+ error_log("/php/readfile.php - invalid filename");http_response_code(409);exit(0);}F diff --git a/sql/fileshare.sql b/sql/fileshare.sql --- a/sql/fileshare.sql +++ b/sql/fileshare.sqldrop table if exists node_access;drop table if exists users;drop table if exists node_links;+ drop table if exists trash;+ drop trigger if exists delete_on_zero_links;drop table if exists nodes;node_id int not null,name varchar(100) not null default 'no name',note varchar(200) not null default "",- check (directory_id != node_id),foreign key (directory_id) references nodes(node_id) on delete cascade,foreign key (node_id) references nodes(node_id) on delete cascade);+ create table trash (+ node_id int not null,+ foreign key (node_id) references nodes(node_id) on delete cascade+ );++ /*+ create trigger delete_on_zero_links+ after delete+ on node_links+ for each row+ insert into trash(node_id)+ select+ if(old.node_id not in (select node_id from node_links),+ old.node_id,+ select node_id from nodes where 1=0+ );++ */