FILEUP



LOG | FILES | OVERVIEW


F diff --git a/INIT_DATABASE.sql b/INIT_DATABASE.sql deleted file mode 100644 --- a/INIT_DATABASE.sql +++ /dev/null
- create database if not exists fileup;
- use fileup;
-
- /*BEWARE!*/
- drop table if exists node_access;
- drop table if exists users;
- drop table if exists node_links;
- drop table if exists trash;
- drop table if exists super_trash;
- drop table if exists shared_nodes;
- drop table if exists nodes;
-
-
-
- drop trigger if exists delete_on_zero_links;
- drop trigger if exists delete_links;
- drop trigger if exists del_node;
- drop trigger if exists supper_del_node;
-
-
-
-
-
- create table nodes (
- node_id int not null auto_increment,
- is_directory boolean default false,
- relative_path varchar(500) not null,
- type varchar(20) not null default 'data',
- code varchar(100) not null default "error",
- primary key (node_id)
- );
-
- /*base user information*/
- create table users (
- user_id int not null auto_increment,
- username varchar(50) not null unique,
- password varchar(255) not null,
- email varchar(50),
- home_directory int not null,
- primary key (user_id),
- foreign key (home_directory) references nodes(node_id) on delete cascade
- );
-
- create table node_access (
- node_id int not null,
- user_id int not null,
-
- can_view boolean not null default true,
- can_edit boolean not null default false,
- foreign key (node_id) references nodes(node_id) on delete cascade,
- foreign key (user_id) references users(user_id) on delete cascade
- );
- /*we can name a node in many different ways */
- create table node_links (
- directory_id int not null,
- node_id int not null,
- name varchar(100) not null default 'no name',
- note varchar(200) not null default "",
- foreign key (directory_id) references nodes(node_id) on delete cascade,
- foreign key (node_id) references nodes(node_id) on delete cascade
- );
-
- /*we store passwords for the shared links here, it doesn't really have anything to do with the filesystem*/
- create table shared_nodes (
- node_id int not null,
- passcode varchar(100) default "",
- code varchar(100) default "",
- foreign key (node_id) references nodes(node_id) on delete cascade
- );
-
- create table trash (
- node_id int not null
- );
- create table super_trash (
- node_id int not null
- );
-
-
- create trigger delete_on_zero_links
- after delete
- on node_links
- for each row
- insert into trash
- select nodes.node_id
- from nodes
- where nodes.node_id not in (select node_id from node_links) and
- (nodes.node_id=old.node_id );
-
- create trigger del_node
- after delete
- on trash
- for each row
- insert into super_trash(node_id)
- select node_id
- from nodes
- where nodes.node_id=old.node_id;
-
-
- create trigger supper_del_node
- after delete
- on super_trash
- for each row
- insert into trash
- select node_id
- from nodes
- where nodes.node_id=old.node_id;
-
- create trigger delete_links
- before delete
- on super_trash
- for each row
- delete from node_links
- where directory_id=old.node_id;
F diff --git a/loggedin.js b/loggedin.js --- a/loggedin.js +++ b/loggedin.js
- // This should be only set to false for debugging purposes
- // If it's set to false, the upload requests will be synchronous
- // and you will be able to see PHP's echo output in the browser
var FORM_ASYNC = true;
- // A FileView is an entry inside the explorer window
- class FileView {
- constructor(filename, visuals, mimetype, is_directory) {
- this.filename = filename;
- this.visuals = visuals; // The DOM object with the icon and the filenam text
- this.mimetype = mimetype;
- this.is_directory = is_directory;
- }
- }
-
- // An array of all fileviews currently open
- var files = [];
-
- class Window {
- constructor(pwd) {
- this.pwd = pwd; // pwd = [ "Folder1", "Folder2" ] means the current directory of that window is /Folder1/Folder2
- this.visuals = null; // The DOM object
- this.h2 = null; // The titlebar of the window
- }
- }
-
- // An array with all the windows on the screen
- var windows = [];
-
- // The focused window
- var focus = null;
-
- // Those all belong to the hidden file upload form
const 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_parent_directory = document.getElementById("upload_parent_directory");
- // Some elements have custom right click context menus
- // If there's a custom context menu active, this will be it
- var context_menu = null;
+ the_file.onchange = on_file_added;
+ var windows = [];
+ var focus = null;
- // If we're currently dragging something (a window or a file), this is the DOM object we're dragging
- // dragging_offset_x and dragging_offset_y are the difference between the objec's top left point and the cursor position
- // this is then added to the cursor position when the mouse is moved
+ var context_menu = null;
var dragging = null;
- var dragging_offset_x = 0, dragging_offset_y = 0;
- // If we have pressed down a window's title bar but haven't yet started dragging it, it's the drag candidate
- // This is needed because we don't yet know whether we want to start dragging the window or click an element in the titlebar
- // Once the mouse has moved sufficiently far away from dragging_candidate_x or y, we start dragging
var dragging_candidate = null;
var dragging_candidate_x, dragging_candidate_y;
- // If we're dragging a fileview, this is set to the fileview class instance itself, because 'dragging' is just a DOM object
- // The placeholder is a dummy DIV that we insert in the object's place on the grid to keep things nicely aligned
var dragging_fileview;
var dragging_placeholder = null;
+ var dragging_offset_x = 0, dragging_offset_y = 0;
- // Windows have a z-index. When we click a window it is sent to the top this will be its new z-index
- // We then increment the depth, and the next window we click will go on top of the current one
var depth = 20;
-
-
- function main() {
- // Create a window that looks at the root directory
- var root_window = make_window([]);
-
- // Focus that window and load the directory
- focus_window(root_window);
- openfile(true);
- }
-
- function focus_window(wnd) {
- // Unfocus the old window
- if (focus)
- focus.visuals.classList.remove('focus');
- focus = wnd;
- // And focus the new one!
- if (wnd) {
- wnd.visuals.classList.add('focus');
- wnd.visuals.style.zIndex = depth ++;
+ class FileView {
+ constructor(filename, visuals, mimetype, is_directory) {
+ this.filename = filename;
+ this.visuals = visuals;
+ this.mimetype = mimetype;
+ this.is_directory = is_directory;
}
}
- // Delete the focused window
- function delete_window() {
- var index = windows.indexOf(focus);
- if (index >= 0)
- windows.splice(index, 1);
-
- focus.visuals.parentNode.removeChild(focus.visuals);
- fous = null;
- }
-
- // Create a right click context menu
- function context(e, entries) {
- if (context_menu)
- context_menu.remove();
-
- context_menu = mk(document.body, 'ul', 'context');
-
- context_menu.onmousedown = (e) => {
- e.stopPropagation();
- }
-
- context_menu.onclick = (e) => {
- context_menu.remove();
- context_menu = null;
- }
-
-
- context_menu.style.left = e.clientX + "px";
- context_menu.style.top = e.clientY + "px";
-
- for (const e of entries) {
- const li = document.createElement('li');
- li.innerText = e[0];
- li.onclick = e[1];
- context_menu.appendChild(li);
+ class PendingUpload {
+ constructor(fileview) {
+ this.fileview = fileview;
}
}
+ var files = [];
- // This is called whenever the <input type="file">'s value changes
function on_file_added(_e) {
if (the_file.files.length >= 1) {
filename_input.value = the_file.files[0].name;
body: new FormData(upload_form)
}).then((resp) => {
if (resp.status == 200) {
- // Reload the directory so the user can see the newly uploaded file
openfile(true);
} else {
alert("Upload failed");
}
}
- // It's honestly really sad that we need this
- // We have an image viewer, but we load the uploaded via the XMLHttpRequest API, which gives us an array buffer
- // We need to base64 encode the image data so we can feed it into the <img src="...">
- // and the standart base64 encode API is shit
// https://stackoverflow.com/questions/7370943/retrieving-binary-file-content-using-javascript-base64-encode-it-and-reverse-de
function base64ArrayBuffer(arrayBuffer) {
var base64 = ''
return base64
}
-
- // This updates the path of the window's DOM (the "Root > Folder1 > Folder2 > foo.png")
function update_path_visuals() {
var the_path = focus.visuals.getElementsByClassName('path')[0];
- // Remove the old path
while (the_path.children.length > 0)
the_path.removeChild(the_path.lastChild);
for (let i = -1; i < focus.pwd.length; i++) {
var d;
- // For each element after the first create a separator
if (i >= 0) {
d = focus.pwd[i];
var separator_div = mk(the_path, 'div', 'separator');
var entry = mk(the_path, 'button', 'pathentry');
entry.innerText = d;
- // When we click the entry, go to its folder
- entry.onclick = (e) => {
- if (length < focus.pwd.length) {
- focus.pwd.length = i + 1;
- openfile(true);
- }
- }
-
- // We can drop files onto the path, which will omve them to teh folder
- entry.onmouseup = (e) => {
- if (dragging && dragging_fileview) {
- var new_folder = get_path(i + 1);
- move_file(new_folder, dragging_fileview.filename);
- end_drag();
-
- e.preventDefault();
- e.stopPropagation();
- }
- }
+ add_link_functionality(entry, i + 1);
}
}
-
- // This asks the server for the contents of the specified file
- // The 'cb' callback is then called, which gives you the file as either text or binary
- // depending on whether or not text is true/false
function read_file_contents(text, cb, folder, filename) {
var data = new FormData();
data.append('folder', folder);
xhr.send(data);
}
-
- // This opens a file.
- // If the file has image/* mimetype, it will be displayed as an image
- // otherwise it will be displayed as plaintext
function openfile_nondir() {
var mimetype = "text/plain";
while (focus.filecontents.children.length > 0)
focus.filecontents.removeChild(focus.filecontents.lastChild);
- // Send a request to readfile.php, which will give us the contents
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);
xhr.send(data);
}
- // This is a tiny wrapper around the share_window.
function share(in_file, filename) {
if (in_file) {
var folder = get_path(focus.pwd.length - 1);
focus_window(wnd);
}
- // This loads the contents of the current directory
function opendir() {
update_path_visuals();
if (!json)
return;
- // Create the FileViews from the json response
for (const f of json) {
var view = new FileView(f.name, null, f.mimetype, f.is_directory && f.is_directory != "0");
files.push(view);
}
- // Sort the files nicely before adding their visuals
- // Folders come first, then files, then the special trash directory
- // Everything inside the categories is lexically sorted
files.sort((a, b) => {
if (get_path() == "/" && a.filename == "trash")
return 2;
focus.foldercontents.style.display = 'block';
}
-
function openfile(is_directory) {
if (is_directory) {
opendir();
move_file(new_directory, filename, new_filename);
}
-
- // This deletes the file, *for real*
- // move_to_trash is what is actually called when the user clicks 'Delete'
function delete_file(filename) {
var data = new FormData();
data.append('folder', get_path());
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;
xhr.send(data);
}
-
- // Dragging a fileview is a bit different from dragging a window
- // This does some setup work before calling the common begin_drag
function begin_drag_fileview(e, fileview) {
if (dragging)
end_drag();
- // The dragging_placeholder is inserted into its place by the begin_drag function
+ // Inserted in place by begin_drag
dragging_placeholder = document.createElement('div');
dragging_fileview = fileview;
begin_drag(e, fileview.visuals);
}
- // Start dragging the 'obj' DOM element
- // e is a DOM event, this should only get called in response of a DOM event
function begin_drag(e, obj, dont_set_width) {
dragging = obj;
dragging_candidate = null;
}
function end_drag(_e) {
- // If there's a dragging palceholder remove it and put the dragged node back into its place
if (dragging_placeholder) {
dragging_placeholder.parentNode.insertBefore(dragging, dragging_placeholder);
dragging_placeholder.remove();
dragging_placeholder = null;
}
- // If we were dragging a FileView, we need to reset some CSS
if (dragging_fileview) {
dragging.style.removeProperty("position");
dragging.style.removeProperty("width");
dragging = null;
}
- // This creates the parts of a window that are common between all window types
- // This should only really be called by another function that will then fill up the window
+ function drop_handler(dst, src) {
+ if (dst.is_directory) {
+ if (get_path() == "/" && dst.filename == "trash") {
+ move_to_trash(src.filename);
+ } else {
+ move_file(path_combine(get_path(), dst.filename), src.filename);
+ }
+ } else {
+ alert(`Dropped ${dst.filename} on ${src.filename}`);
+ }
+ }
+
+ function add_link_functionality(link, length) {
+ link.onclick = (e) => {
+ if (length < focus.pwd.length) {
+ focus.pwd.length = length;
+ openfile(true);
+ }
+ }
+
+ link.onmouseup = (e) => {
+ if (dragging && dragging_fileview) {
+ var new_folder = get_path(length);
+ move_file(new_folder, dragging_fileview.filename);
+ end_drag();
+
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ }
+ }
+
+ class Window {
+ constructor(pwd) {
+ this.pwd = pwd;
+ }
+ }
+
+ function focus_window(wnd) {
+ if (focus)
+ focus.visuals.classList.remove('focus');
+ focus = wnd;
+ if (wnd) {
+ wnd.visuals.classList.add('focus');
+ wnd.visuals.style.zIndex = depth ++;
+ }
+ }
+
function make_window_base(pwd, x, y, w, h) {
var wnd = new Window(pwd);
windows.push(wnd);
return wnd;
}
- // This is a widely abused helper function that creates a DOM element, attaches it as the
- // last child of 'parent' and possibly gives it a class
function mk(parent, type, _class) {
var el = document.createElement(type);
parent.appendChild(el);
return el;
}
- // Crate a horizontal div
function mkhdiv(parent) {
var hdiv = mk(parent, 'div');
- hdiv.style.display = "flex";
+ hdiv.style.display = "flex";
hdiv.style.alignItems = "center";
- hdiv.style.padding = "0.3rem";
- hdiv.style.gap = "0.3rem";
+ hdiv.style.padding = "0.3rem";
+ hdiv.style.gap = "0.3rem";
return hdiv;
}
- // Create a checkbocx with a label.
- // togglefn will be called when its value changes with an argument that's either true/false
function mkcheckbox(parent, label, togglefn) {
var hdiv = mkhdiv(parent);
};
}
- // This monstrocity creates the 'Share file' window
function make_share_window(folder, filename) {
var wnd = make_window_base(null, 400, 400, 400, 0);
wnd.h2.style.padding = "0.0rem 0rem 0.0rem 0.8rem";
wnd.h2.style.display = 'flex';
- // The title of the window. WE set its 'flex' to 1 1 0 so it fills up the titlebar
- // and pushes the X button to the very right
var heading = mk(wnd.h2, 'span');
heading.innerText = "Share " + filename;
heading.style.display = 'flex';
heading.style.alignItems = 'center';
heading.style.flex = "1 1 0";
- // Close button
var x_button = mk(wnd.h2, 'button', 'close_button');
x_button.innerText = "X";
x_button.onclick = delete_window;
wnd.foldercontents = mk(wnd.visuals, 'div', 'share_dialog_contents');
wnd.foldercontents.style.padding = "0.5rem";
- // This is the data that will be sent when we hit "Generate link"
var data = {
write_permissions: false,
private: false,
userlist: [],
}
- // If private link is clicked, show the "Add user" button and the user list
var userlist, add_user;
mkcheckbox(wnd.foldercontents, "Private link", (toggled) => {
add_user.style.display = toggled ? "block" : "none";
add_user.innerText = "Add user";
add_user.style.display = "none";
- // When we hit 'Add user', add an input field for a new user
add_user.onclick = (e) => {
var i = mk(userlist, 'input');
i.value = 'John Doe';
}
}
- // Click the add_user once to add a default user, since a URL that nobody can use makes no sense
+ // Click the add_user to add a default user
add_user.click();
mkcheckbox(wnd.foldercontents, "Give write permissions", (toggled) => {
data.write_permissions = toggled;
});
- // If 'Password protected' is checked, show the password field
let password_container;
mkcheckbox(wnd.foldercontents, "Password protected", (toggled) => {
data.has_password = toggled;
generate_url_button.onclick = () => {
console.log(data);
- // The backend expects the users to be either an empty string, if the URL is public
- // or a comma separated list of usernaems
var users = "";
if (data.private) {
users = data.userlist.join(',');
form_data.append('folder', folder);
form_data.append('filename', filename);
form_data.append('users', users);
- // 0 = No permissions, 1 = Read only, 2 = Write , 1|2 = 3 = RW
- // Only 1 and 3 make sense in the context of a URL
form_data.append('permissions', data.write_permissions ? 3 : 1);
form_data.append('password', data.has_password ? data.password : "");
}
function download_file(in_file, filename) {
+
if (in_file) {
var folder = get_path(focus.pwd.length - 1);
filename = focus.pwd[focus.pwd.length - 1];
var folder = get_path();
}
- // Read the file contents and then do DISGUSTING javascript things to download the ifle
- // We create a invisible <a> that we click and then delete
- // That <a> has its download attribute set so we download the contents instead of opening it in a new tab
- // and of course its href is a virtual object URL that has its content set to a blob
read_file_contents(false, (x) => {
var blob = new Blob([new Uint8Array(x, 0, x.length)]);
var url = URL.createObjectURL(blob);
- // make_window creates an explorer window - the kind that can list directories/open files
+
+ function delete_window() {
+ var index = windows.indexOf(focus);
+ if (index >= 0) {
+ windows.splice(index, 1);
+ }
+ focus.visuals.parentNode.removeChild(focus.visuals);
+ fous = null;
+ }
+
function make_window(pwd) {
var wnd = make_window_base(pwd, 100, 100, 800, 600);
path = mk(wnd.h2, 'div', 'path');
- // wnd.foldercontents is where the FileViews will be stored
- // it also has a subheader (h3) with 'Upload' and 'New FOlder' buttons
{
wnd.foldercontents = mk(wnd.visuals, 'div', 'foldercontents');
var h3 = mk(wnd.foldercontents, 'h3');
var upload_btn = mk(h3, 'button');
upload_btn.innerText = "Upload";
- upload_btn.onclick = () => { the_file.click(); }
+ upload_btn.onclick = () => { begin_upload(); }
mk(h3, 'div', 'separator');
wnd.filegrid = mk(wnd.foldercontents, 'div', 'files');
}
- // wnd.filecontentsroot is where the filedata will be stored for open files
- // it also has a subheader (h3) with Share and Download buttons
{
wnd.filecontentsroot = mk(wnd.visuals, 'div', 'filecontentsroot');
var h3 = mk(wnd.filecontentsroot, 'h3');
}
- // Create the visuals for a FileView
function add_file_visuals(fileview) {
- // Are we in a subdirectory of the trash folder?
+ // Are we in a subdirectory of the trash folder
var is_in_trash = focus.pwd.length > 0 && focus.pwd[0] == "trash";
-
- // Is the current filewview the trash folder itself?
+ // Is the current filewview the trash folder itself
var is_trash = focus.pwd.length == 0 && fileview.filename == "trash";
var visuals = mk(focus.filegrid, 'div');
if (!dragging) {
var context_list = [
- // Open is always in the context list
['Open', () => {
focus.pwd.push(fileview.filename);
openfile(fileview.is_directory);
];
if (is_in_trash) {
- // If we're in the trash, we can restore files or delete them forever
context_list.push(['Restore', () => { restore_from_trash(fileview.filename); }]);
context_list.push(['Delete forever', () => { delete_file(fileview.filename); }]);
} else if (!is_trash) {
- // If we;'re not in trash we can rename/share/download/move files to trash
context_list.push(
['Rename', () => { rename_file(fileview.filename); }],
);
visuals.onmouseup = (e) => {
if (dragging) {
- if (fileview.is_directory) {
- if (get_path() == "/" && fileview.filename == "trash") {
- // If we've dragged something onto the trashcan, it's trash
- move_to_trash(dragging_fileview.filename);
- } else {
- // If we've dragged something onto a directory, move it into that directory
- move_file(path_combine(get_path(), fileview.filename), dragging_fileview.filename);
- }
- } else {
- // alert(`Dropped ${dst.filename} on ${src.filename}`);
- }
+ drop_handler(fileview, dragging_fileview);
end_drag();
}
e.preventDefault();
}
+ function begin_upload() {
+ the_file.click();
+ }
+
+ function context(e, entries) {
+ if (context_menu)
+ context_menu.remove();
+
+ context_menu = mk(document.body, 'ul', 'context');
+
+ context_menu.onmousedown = (e) => {
+ e.stopPropagation();
+ }
+
+ context_menu.style.left = e.clientX + "px";
+ context_menu.style.top = e.clientY + "px";
+
+ for (const e of entries) {
+ const li = document.createElement('li');
+ li.innerText = e[0];
+ li.onclick = e[1];
+ context_menu.appendChild(li);
+ }
+ }
- // Reads the 'pwd' of the focused window
- // If pwd is ['foo', 'bar', 'baz'], this returns '/foo/bar/baz'
function get_path(max_length) {
if (max_length == undefined) {
max_length = focus.pwd.length;
return a + "/" + b;
}
-
- // When we click anywhere, remove the context menu
- // The context menu itself has a onmousedown that prevents propagation so we can click its elements
- document.body.onmousedown = (_e) => {
- if (context_menu) {
+ document.body.onclick = () => {
+ if (context_menu)
context_menu.remove();
- context_menu = null;
- }
}
document.body.onmousemove = (e) => {
}
}
+ document.body.onmousedown = (_e) => {
+ if (context_menu)
+ context_menu.remove();
+ }
+
document.body.onmouseup = (_e) => {
if (dragging_candidate)
dragging_candidate = null;
end_drag();
e.preventDefault();
}
- if (context_menu) {
+ if (context_menu)
context_menu.remove();
- context_menu = null;
- }
}
- the_file.onchange = on_file_added;
-
- main();
> \ No newline at end of file
+ var root_window = make_window([]);
+ focus_window(root_window);
+ openfile(true);
F diff --git a/php/configuration.php b/php/configuration.php --- a/php/configuration.php +++ b/php/configuration.php
<?php
-
- $use_https = false;
-
- // The server needs to know its domain name so it can generate download links
- $domain_name="localhost";
-
- // MySQL database name/user/password location
- // VOLATILE - database_name is hard coded in INIT_DATABASE.sql, if you change it here you MUST change that as well
- $database_name="fileup";
- $database_username="root";
- $database_password="";
- $database_location="127.0.0.1";
-
- // This directory MUST exist and PHP's configuration must be able to read/write/delete files inside it
- $storage_root = "C:\\fileup_storage";
-
-
- // Are we using the /trash directory?
+ /*should be placed outside of document root*/
+
+ $use_https=true;
+
+ if (file_exists("/home/alex")) {
+ $domain_name="localhost";
+ $database_name="alex";
+ $database_username="alex";
+ $database_password="lol";
+ $database_location="127.0.0.1";
+
+ $storage_root = "/home/alex/fileup_storage";
+ }
+ else {
+ $domain_name="testing";
+ $database_name="fileup_testing";
+ $database_username="outsider";
+ $database_password="parola123";
+ $database_location="localhost";
+ /*storage root must be in the webroot*/
+ $storage_root = "/srv/apache/testing/project/files/";
+ }
+
+ /*if we save deleted files just in case of an error*/
$has_trash=true;
-
$password_hash_algo=PASSWORD_BCRYPT;
$has_email_verification=false;
-
- @include_once("$_SERVER[HOME]/.fileup.config.php");
-
- ?>
> \ No newline at end of file
+ ?>
F diff --git a/php/database.php b/php/database.php --- a/php/database.php +++ b/php/database.php
$this->pdo=new PDO("mysql:dbname={$database_name};host={$database_location}",$database_username,$database_password);
}
- /*returns NULL if this isn't a user, otherwise returns the user*/
+ /*returns NULL if this isn't a user, otherwise returns the user in the form of the User class*/
function get_user(string $user)
{
$ret=new User;
}
}
- /*returns assoc array*/
+ /*returns assoc array , or NULL on error*/
function get_nodes_with_name($name)
{
$statement=$this->pdo->prepare(
return $statement->fetchAll(PDO::FETCH_ASSOC);
}
- /*returns id*/
+ /*returns id or NULL on error*/
function get_node_with_code($code)
{
$statement=$this->pdo->prepare(
}
}
- function create_shared_node(string $password,int $node_id)
+ function create_shared_node(string $password,int $node_id,string $users)
{
$code=$this->get_random_node_name("");
- $prep=$this->pdo->prepare("insert into shared_nodes(node_id,passcode,code)
- values (:id,:pass,:code)
+ $prep=$this->pdo->prepare("insert into shared_nodes(node_id,passcode,code,is_public)
+ values (:id,:pass,:code,:is_public)
");
$prep->bindParam(':id',$node_id);
$prep->bindParam(':pass',$password);
$prep->bindParam(':code',$code);
+ if($users=="")
+ {
+ $prep->bindParam(':is_public',true);
+ }else
+ {
+ $prep->bindParam(':is_public',false);
+ }
if($prep->execute()==false)
{
error_log("could not create shared node in create_shared_node");
F diff --git a/php/move.php b/php/move.php --- a/php/move.php +++ b/php/move.php
$old_dir = get_directory($old_folder, $user);
$new_dir = get_directory($new_folder, $user);
- if (!$old_dir || !$new_dir) {
+ $trash_dir = get_directory("/trash",$user);
+ $share_dir = get_directory("/share",$user);
+ if (!$old_dir || !$new_dir || $old_dir==$user->home_directory || $old_dir==$trash_dir || $old_dir==$share_dir) {
error_log("invalid src/dst dir");
http_response_code(409);
exit(0);
F diff --git a/php/node.php b/php/node.php --- a/php/node.php +++ b/php/node.php
{
global $database;
$parent_dir_id=get_directory($abstract_path,$user);
+ if($parent_dir_id==$user->home_directory && ($filename=="share" || $filename=="trash"))
+ {
+ return ;
+ }
$database->unlink_nodes($parent_dir_id,$filename);
}
function create_share_link(string $abstract_path,string $filename,string $password,
{
return NULL;
}
- $shared_node=$database->create_shared_node($password,$node_id);
+ $shared_node=$database->create_shared_node($password,$node_id,$users);
if($shared_node==NULL)
{
return NULL;
F diff --git a/php/share.php b/php/share.php --- a/php/share.php +++ b/php/share.php
session_start();
- $user=$_SESSION['user_object'];
if($_SERVER["REQUEST_METHOD"] == "POST")
{
+ if(!isset($_SESSION['user_object']) || !isset($_POST["folder"]) || !isset($_POST["filename"]) || !isset($_POST["users"]) || !isset($_POST["password"]) || !isset($_POST["premissions"]) )
+ {
+ http_response_code(409);
+ exit(0);
+ }
+ $user=$_SESSION['user_object'];
$path=$_POST["folder"];
/*this could be a directory as well*/
$filename=$_POST["filename"];
exit(0);
}else if($_SERVER["REQUEST_METHOD"]== "GET")
{
+ if(!isset($_GET["file"]))
+ {
+ http_response_code(409);
+ exit(0);
+ }
$code=$_GET["file"];
- $password=$_GET["password"];
+ if(isset($_GET["password"]))
+ {
+ $password=$_GET["password"];
+ }else
+ {
+ $password="";
+ }
$shared_node=$database->get_shared_node($code);
if($shared_node==NULL || $shared_node->password!=$password)
F diff --git a/sql/fileshare.sql b/sql/fileshare.sql new file mode 100644 --- /dev/null +++ b/sql/fileshare.sql
+ /*BEWARE!*/
+ drop table if exists node_access;
+ drop table if exists users;
+ drop table if exists node_links;
+ drop table if exists trash;
+ drop table if exists super_trash;
+ drop table if exists shared_nodes;
+ drop table if exists nodes;
+
+
+
+ drop trigger if exists delete_on_zero_links;
+ drop trigger if exists delete_links;
+ drop trigger if exists del_node;
+ drop trigger if exists supper_del_node;
+
+
+
+
+
+ create table nodes (
+ node_id int not null auto_increment,
+ is_directory boolean default false,
+ relative_path varchar(500) not null,
+ type varchar(20) not null default 'data',
+ code varchar(100) not null default "error",
+ primary key (node_id)
+ );
+
+ /*base user information*/
+ create table users (
+ user_id int not null auto_increment,
+ username varchar(50) not null unique,
+ password varchar(255) not null,
+ email varchar(50),
+ home_directory int not null,
+ primary key (user_id),
+ foreign key (home_directory) references nodes(node_id) on delete cascade
+ );
+
+ create table node_access (
+ node_id int not null,
+ user_id int not null,
+
+ can_view boolean not null default true,
+ can_edit boolean not null default false,
+ foreign key (node_id) references nodes(node_id) on delete cascade,
+ foreign key (user_id) references users(user_id) on delete cascade
+ );
+ /*we can name a node in many different ways */
+ create table node_links (
+ directory_id int not null,
+ node_id int not null,
+ name varchar(100) not null default 'no name',
+ note varchar(200) not null default "",
+ foreign key (directory_id) references nodes(node_id) on delete cascade,
+ foreign key (node_id) references nodes(node_id) on delete cascade
+ );
+
+ /*we store passwords for the shared links here, it doesn't really have anything to do with the filesystem*/
+ create table shared_nodes (
+ node_id int not null,
+ passcode varchar(100) default "",
+ code varchar(100) default "",
+ is_public boolean default false,
+ foreign key (node_id) references nodes(node_id) on delete cascade
+ );
+
+ create table trash (
+ node_id int not null
+ );
+ create table super_trash (
+ node_id int not null
+ );
+
+
+ create trigger delete_on_zero_links
+ after delete
+ on node_links
+ for each row
+ insert into trash
+ select nodes.node_id
+ from nodes
+ where nodes.node_id not in (select node_id from node_links) and
+ (nodes.node_id=old.node_id );
+
+ create trigger del_node
+ after delete
+ on trash
+ for each row
+ insert into super_trash(node_id)
+ select node_id
+ from nodes
+ where nodes.node_id=old.node_id;
+
+
+ create trigger supper_del_node
+ after delete
+ on super_trash
+ for each row
+ insert into trash
+ select node_id
+ from nodes
+ where nodes.node_id=old.node_id;
+
+ create trigger delete_links
+ before delete
+ on super_trash
+ for each row
+ delete from node_links
+ where directory_id=old.node_id;
+
+