Remove unused buckets and directory_upload pages

This commit is contained in:
2023-05-11 15:01:29 +02:00
parent 3f1318784e
commit f0847da15f
24 changed files with 121 additions and 469 deletions

View File

@@ -27,7 +27,7 @@ func main() {
// systemd's socket, else we'll create our own to serve on // systemd's socket, else we'll create our own to serve on
if *sock { if *sock {
// Socket activation enabled. Get the provided sockets and serve on them // Socket activation enabled. Get the provided sockets and serve on them
if listener, err = util.SystemdSocketByName("pd-web.socket"); err != nil { if listener, err = util.SystemdListenerByName("pd-web.socket"); err != nil {
panic("Socket pd-web.socket not found") panic("Socket pd-web.socket not found")
} }
} else { } else {

View File

@@ -1,26 +0,0 @@
{{define "directory_upload"}}<!DOCTYPE html>
<html lang="en">
<head>
{{template "meta_tags" "Directory upload"}}
<script>
window.api_endpoint = '{{.APIEndpoint}}';
window.user = {{.User}};
</script>
<link rel='stylesheet' href='/res/svelte/directory_upload.css?v{{cacheID}}'>
<script defer src='/res/svelte/directory_upload.js?v{{cacheID}}'></script>
</head>
<body>
{{template "page_top" .}}
<header>
<h1>Directory upload</h1>
</header>
<div id="page_content" class="page_content"></div>
{{template "page_bottom" .}}
{{template "analytics"}}
</body>
</html>
{{end}}

View File

@@ -1,16 +0,0 @@
{{define "user_buckets"}}<!DOCTYPE html>
<html lang="en">
<head>
{{template "meta_tags" "Buckets"}}
<script>window.api_endpoint = '{{.APIEndpoint}}';</script>
<link rel='stylesheet' href='/res/svelte/user_buckets.css?v{{cacheID}}'>
<script defer src='/res/svelte/user_buckets.js?v{{cacheID}}'></script>
</head>
<body>
{{template "menu" .}}
<div id="page_body" class="page_body"></div>
{{template "analytics"}}
</body>
</html>
{{end}}

View File

@@ -33,11 +33,9 @@ export default [
"filesystem", "filesystem",
"modal", "modal",
"user_home", "user_home",
"user_buckets",
"user_file_manager", "user_file_manager",
"admin_panel", "admin_panel",
"home_page", "home_page",
"directory_upload",
"text_upload", "text_upload",
].map((name, index) => ({ ].map((name, index) => ({
input: `src/${name}.js`, input: `src/${name}.js`,

View File

@@ -1,8 +0,0 @@
import App from './directory_upload/Uploader.svelte';
const app = new App({
target: document.getElementById("page_content"),
props: {}
});
export default app;

View File

@@ -1,52 +0,0 @@
<script>
import { tick } from "svelte";
import FileManager from "../filesystem/filemanager/FileManager.svelte";
import { fs_create_bucket, fs_get_node } from "../filesystem/FilesystemAPI.svelte";
let fm
let bucket_id = ""
let bucket_state = null
let write_password = ""
export const add_files = async files => {
if (bucket_id === "") {
write_password = gen_password(10)
try {
let bucket = await fs_create_bucket("", "", write_password)
bucket_id = bucket.id
bucket_state = await fs_get_node(bucket_id, "")
bucket_state.write_password = write_password
} catch (err) {
alert("Failed to create bucket! "+err)
}
}
await tick()
fm.upload(files)
}
const gen_password = len => {
var pw = "";
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for ( var i = 0; i < len; i++ ) {
pw += chars.charAt(Math.floor(Math.random() * chars.length));
}
return pw;
}
const navigate = async e => {
try {
let new_state = await fs_get_node(bucket_id, e.detail)
bucket_state = new_state
} catch (err) {
alert("Failed to create bucket! "+err)
}
}
</script>
{#if bucket_state !== null }
<FileManager bind:this={fm} state={bucket_state} on:navigate={navigate}></FileManager>
{/if}

View File

@@ -1,61 +0,0 @@
<script>
import DirectoryUploader from "./DirectoryUploader.svelte";
let uploader
let file_input_field
const file_input_change = e => {
// Start uploading the files async
uploader.add_files(e.target.files)
// This resets the file input field
file_input_field.nodeValue = ""
}
let dragging = false
const drop = e => {
dragging = false;
if (e.dataTransfer && e.dataTransfer.items.length > 0) {
e.preventDefault()
e.stopPropagation()
uploader.add_files(e.dataTransfer.files)
}
}
const paste = e => {
if (e.clipboardData.files[0]) {
e.preventDefault();
e.stopPropagation();
uploader.add_files(e.clipboardData.files)
}
}
</script>
<svelte:window
on:dragover|preventDefault|stopPropagation={() => { dragging = true }}
on:dragenter|preventDefault|stopPropagation={() => { dragging = true }}
on:dragleave|preventDefault|stopPropagation={() => { dragging = false }}
on:drop={drop}
on:paste={paste} />
<header style="padding-bottom: 50px;">
<h1>Directory uploader</h1>
<section>
<div class="highlight_red">
Pixeldrain's filesystem feature is still under development. Please
don't upload anything you can't afford to lose
</div>
</section>
</header>
<section>
<input bind:this={file_input_field} on:change={file_input_change} type="file" name="file" multiple="multiple"/>
<button on:click={() => { file_input_field.click() }} class="big_button button_highlight">
<i class="icon small">cloud_upload</i>
<u>U</u>pload Files
</button>
</section>
<DirectoryUploader bind:this={uploader}></DirectoryUploader>

View File

@@ -55,7 +55,7 @@ let embed_iframe = () => {
embed_html = `<iframe ` + embed_html = `<iframe ` +
`src="${url}" ` + `src="${url}" ` +
`style="border: none; width: 800px; max-width: 100%; height: 600px; max-height: 100%; border-radius: 16px;"` + `style="border: none; width: 800px; max-width: 100%; height: 600px; max-height: 100%; border-radius: 8px;"` +
`></iframe>` `></iframe>`
} }
let embed_hotlink = () => { let embed_hotlink = () => {

View File

@@ -1,7 +1,7 @@
<script> <script>
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { formatDate, formatDataVolume, formatThousands } from '../util/Formatting.svelte' import { formatDate, formatDataVolume, formatThousands } from '../util/Formatting.svelte'
import { fs_get_file_url, fs_get_node } from './FilesystemAPI.svelte' import { fs_get_file_url, fs_get_node } from './FilesystemAPI.js'
import Sharebar from './Sharebar.svelte' import Sharebar from './Sharebar.svelte'
import Modal from '../util/Modal.svelte' import Modal from '../util/Modal.svelte'
import FileManager from './filemanager/FileManager.svelte'; import FileManager from './filemanager/FileManager.svelte';

View File

@@ -0,0 +1,84 @@
const path_url = (bucket, path) => {
return window.api_endpoint + "/filesystem/" + bucket + encodeURIComponent(path)
}
export const fs_get_file_url = (bucket, path) => {
return path_url(bucket, path)
}
export const fs_mkdir = async (bucket, path, opts = null) => {
const form = new FormData()
form.append("action", "mkdir")
if (opts && opts.mode) {
form.append("mode", opts.mode)
}
const resp = await fetch(path_url(bucket, path), { method: "POST", body: form });
if (resp.status >= 400) {
throw new Error(await resp.text())
}
}
export const fs_get_node = async (bucket, path) => {
const resp = await fetch(path_url(bucket, path) + "?stat");
if (resp.status >= 400) {
throw new Error(await resp.text())
}
return resp.json()
}
// Updates a node's parameters. Available options are:
// - created, Date object
// - modified, Date object
// - mode, file mode formatted as octal string
// - shared, boolean. If true the node will receive a public ID
//
// Returns the modified filesystem node object
export const fs_update = async (bucket, path, opts) => {
const form = new FormData()
form.append("action", "update")
if (opts.created) {
form.append("created", opts.created.toISOString())
}
if (opts.modified) {
form.append("modified", opts.modified.toISOString())
}
if (opts.mode) {
form.append("mode", opts.mode)
}
if (opts.shared) {
form.append("shared", opts.shared)
}
const resp = await fetch(path_url(bucket, path), { method: "POST", body: form })
if (resp.status >= 400) {
throw new Error(await resp.text())
}
return resp.json()
}
export const fs_rename = async (bucket, old_path, new_path) => {
const form = new FormData()
form.append("action", "rename")
form.append("target", new_path)
const resp = await fetch(path_url(bucket, old_path), { method: "POST", body: form })
if (resp.status >= 400) {
throw new Error(await resp.text())
}
}
export const fs_delete = async (bucket, path) => {
const resp = await fetch(path_url(bucket, path), { method: "DELETE" });
if (resp.status >= 400) {
throw new Error(await resp.text())
}
}
export const fs_delete_all = async (bucket, path) => {
const resp = await fetch(path_url(bucket, path) + "?recursive", { method: "DELETE" });
if (resp.status >= 400) {
throw new Error(await resp.text())
}
}

View File

@@ -1,107 +0,0 @@
<script context="module">
export const fs_create_bucket = async (name = "", read_pw = "", write_pw = "") => {
const form = new FormData()
form.append("name", name)
form.append("read_password", read_pw)
form.append("write_password", write_pw)
const resp = await fetch(
window.api_endpoint+"/filesystem",
{ method: "POST", body: form }
);
if(resp.status >= 400) {
throw new Error(await resp.text());
}
return resp.json()
}
export const fs_get_buckets = async () => {
const resp = await fetch(window.api_endpoint+"/filesystem");
if(resp.status >= 400) {
throw new Error(await resp.text());
}
return resp.json();
}
export const fs_delete_bucket = async (id, recursive) => {
let uri = window.api_endpoint+"/filesystem/"+encodeURIComponent(id)
if (recursive) {
uri += "?recursive"
}
const resp = await fetch(uri, { method: "DELETE" });
if(resp.status >= 400) {
throw new Error(await resp.text());
}
}
export const fs_create_directory = async (bucket, path, dir_name) => {
if (!path.startsWith("/")) {
path = "/" + path
}
const form = new FormData()
form.append("type", "dir")
const resp = await fetch(
window.api_endpoint+"/filesystem/"+bucket+encodeURIComponent(path+"/"+dir_name),
{ method: "POST", body: form }
);
if(resp.status >= 400) {
throw new Error(await resp.text())
}
}
export const fs_get_node = async (bucket, path) => {
if (!path.startsWith("/")) {
path = "/" + path
}
const resp = await fetch(
window.api_endpoint+"/filesystem/"+bucket+encodeURIComponent(path)+"?stat"
);
if(resp.status >= 400) {
throw new Error(await resp.text())
}
return resp.json()
}
export const fs_get_file_url = (bucket, path) => {
if (!path.startsWith("/")) {
path = "/" + path
}
return window.api_endpoint + "/filesystem/" + bucket + encodeURIComponent(path)
}
export const fs_rename_node = async (bucket, old_path, new_path) => {
if (!old_path.startsWith("/")) { old_path = "/" + old_path }
if (!new_path.startsWith("/")) { new_path = "/" + new_path }
const form = new FormData()
form.append("move_to", new_path)
const resp = await fetch(
window.api_endpoint+"/filesystem/"+bucket+encodeURIComponent(old_path),
{ method: "PUT", body: form }
)
if (resp.status >= 400) {
throw new Error(await resp.text())
}
}
export const fs_delete_node = async (bucket, path) => {
if (!path.startsWith("/")) {
path = "/" + path
}
const resp = await fetch(
window.api_endpoint+"/filesystem/"+bucket+encodeURIComponent(path)+"?recursive",
{ method: "DELETE" }
);
if (resp.status >= 400) {
throw new Error(await resp.text())
}
}
</script>

View File

@@ -1,21 +1,21 @@
<script> <script>
import { onMount, createEventDispatcher } from "svelte"; import { onMount, createEventDispatcher } from "svelte";
import { fs_create_directory } from "../FilesystemAPI.svelte"; import { fs_mkdir } from "../FilesystemAPI.js";
let dispatch = createEventDispatcher() let dispatch = createEventDispatcher()
export let state; export let state;
let name_input; let name_input;
let create_dir_name = "" let new_dir_name = ""
let create_dir = () => { let create_dir = () => {
dispatch("loading", true) dispatch("loading", true)
let form = new FormData() let form = new FormData()
form.append("type", "dir") form.append("type", "dir")
fs_create_directory( fs_mkdir(
state.root.id, state.base.path, create_dir_name, state.root.id, state.base.path+"/"+new_dir_name,
).then(resp => { ).then(resp => {
create_dir_name = "" // Clear input field new_dir_name = "" // Clear input field
}).catch(err => { }).catch(err => {
alert("Error: "+err) alert("Error: "+err)
}).finally(() => { }).finally(() => {
@@ -28,7 +28,7 @@ onMount(() => { name_input.focus() })
<form class="create_dir highlight_shaded" on:submit|preventDefault={create_dir}> <form class="create_dir highlight_shaded" on:submit|preventDefault={create_dir}>
<img src="/res/img/mime/folder.png" class="icon" alt="icon"/> <img src="/res/img/mime/folder.png" class="icon" alt="icon"/>
<input class="dirname" type="text" style="width: 100%;" bind:this={name_input} bind:value={create_dir_name} /> <input class="dirname" type="text" style="width: 100%;" bind:this={name_input} bind:value={new_dir_name} />
<input class="submit" type="submit" value="create"/> <input class="submit" type="submit" value="create"/>
</form> </form>

View File

@@ -1,5 +1,5 @@
<script> <script>
import { fs_delete_node } from './../FilesystemAPI.svelte' import { fs_delete } from './../FilesystemAPI.js'
import { createEventDispatcher } from 'svelte' import { createEventDispatcher } from 'svelte'
import CreateDirectory from './CreateDirectory.svelte' import CreateDirectory from './CreateDirectory.svelte'
import FileUploader from './FileUploader.svelte' import FileUploader from './FileUploader.svelte'
@@ -67,7 +67,7 @@ const delete_selected = () => {
let promises = [] let promises = []
state.children.forEach(child => { state.children.forEach(child => {
if (!child.fm_selected) { return } if (!child.fm_selected) { return }
promises.push(fs_delete_node(state.root.id, child.path)) promises.push(fs_delete(state.root.id, child.path))
}) })
// Wait for all the promises to finish // Wait for all the promises to finish

View File

@@ -67,17 +67,13 @@ const upload_file = () => {
console.log(job); console.log(job);
let form = new FormData();
form.append("type", "file");
form.append("file", job.file);
let url = window.api_endpoint+"/filesystem/"+bucket_id+encodeURIComponent(job.target_dir + "/" + job.file.name) let url = window.api_endpoint+"/filesystem/"+bucket_id+encodeURIComponent(job.target_dir + "/" + job.file.name)
if (write_password) { if (write_password) {
url += "?write_password="+write_password url += "?write_password="+write_password
} }
let xhr = new XMLHttpRequest(); let xhr = new XMLHttpRequest();
xhr.open("POST", url, true); xhr.open("PUT", url, true);
xhr.timeout = 21600000; // 6 hours, to account for slow connections xhr.timeout = 21600000; // 6 hours, to account for slow connections
// Report progress updates back to the caller // Report progress updates back to the caller
@@ -147,7 +143,8 @@ const upload_file = () => {
upload_jobs = upload_jobs; upload_jobs = upload_jobs;
}; };
xhr.send(form);
xhr.send(job.file);
}; };
// File input dialog handling // File input dialog handling

View File

@@ -49,8 +49,9 @@ const node_icon = node => {
<div class="directory"> <div class="directory">
<tr> <tr>
<td></td> <td></td>
<td>name</td> <td>Name</td>
<td>size</td> <td>Size</td>
<td></td>
</tr> </tr>
{#each state.children as child, index (child.path)} {#each state.children as child, index (child.path)}
<a <a
@@ -71,6 +72,13 @@ const node_icon = node => {
{formatDataVolume(child.file_size, 3)} {formatDataVolume(child.file_size, 3)}
{/if} {/if}
</td> </td>
<td>
{#if child.id}
<a href="/d/{child.id}" on:click|stopPropagation>
<i class="icon" title="This file / directory is shared. Click to open public link">share</i>
</a>
{/if}
</td>
</a> </a>
{/each} {/each}
</div> </div>

View File

@@ -1,5 +1,5 @@
<script> <script>
import { fs_get_file_url } from "../FilesystemAPI.svelte"; import { fs_get_file_url } from "../FilesystemAPI.js";
import { createEventDispatcher, onMount } from 'svelte' import { createEventDispatcher, onMount } from 'svelte'
let dispatch = createEventDispatcher() let dispatch = createEventDispatcher()

View File

@@ -1,5 +1,5 @@
<script> <script>
import { fs_get_file_url } from "../FilesystemAPI.svelte"; import { fs_get_file_url } from "../FilesystemAPI.js";
export let state export let state

View File

@@ -1,5 +1,5 @@
<script> <script>
import { fs_get_file_url } from "../FilesystemAPI.svelte"; import { fs_get_file_url } from "../FilesystemAPI.js";
export let state export let state
</script> </script>

View File

@@ -1,5 +1,5 @@
<script> <script>
import { fs_get_file_url } from "../FilesystemAPI.svelte"; import { fs_get_file_url } from "../FilesystemAPI.js";
import { createEventDispatcher, onMount } from 'svelte' import { createEventDispatcher, onMount } from 'svelte'
let dispatch = createEventDispatcher() let dispatch = createEventDispatcher()

View File

@@ -1,8 +0,0 @@
import App from './user_buckets/UserBuckets.svelte';
const app = new App({
target: document.getElementById("page_body"),
props: {}
});
export default app;

View File

@@ -1,74 +0,0 @@
<script>
import { fs_delete_bucket } from "../filesystem/FilesystemAPI.svelte";
import { createEventDispatcher } from "svelte";
import Expandable from "../util/Expandable.svelte";
let dispatch = createEventDispatcher()
export let bucket
const save_bucket = () => {
alert("save")
}
const delete_bucket = async () => {
if (!confirm(
"Are you sure you want to delete this bucket? All the files within "+
"the bucket will be irrevocably deleted. There is no way to recover "+
"from this! Press OK to proceed"
)) {
return
}
try {
await fs_delete_bucket(bucket.id, true)
} catch (err) {
alert("Failed to delete bucket! "+err)
}
dispatch("refresh");
}
</script>
<Expandable highlight>
<div slot="header">
<a href={'/d/' + bucket.id} class="bucket_title">
<img class="bucket_icon" src="/res/img/mime/folder-remote.png" alt="Bucket icon"/>
{bucket.name}
</a>
</div>
<div>
<form on:submit|preventDefault={save_bucket}>
<table class="form">
<tr class="form">
<td>Name</td>
<td><input type="text" value={bucket.name} /></td>
</tr>
<tr class="form">
<td colspan="2">
<button class="button_red" on:click|preventDefault={delete_bucket}>
<i class="icon">delete</i> Delete
</button>
<button class="button_highlight" type="submit" style="float: right;">
<i class="icon">save</i> Save
</button>
</td>
</tr>
</table>
</form>
</div>
</Expandable>
<style>
.bucket_title {
flex: 1 1 auto;
align-self: center;
display: block;
text-decoration: none;
}
.bucket_icon {
height: 32px;
width: 32px;
margin: 4px;
vertical-align: middle;
}
</style>

View File

@@ -1,89 +0,0 @@
<script>
import { onMount } from "svelte";
import UserBucket from "./UserBucket.svelte";
import { fs_get_buckets, fs_create_bucket } from "../filesystem/FilesystemAPI.svelte";
import LoadingIndicator from "../util/LoadingIndicator.svelte";
import Footer from "../layout/Footer.svelte";
let loading = true
let buckets = []
let creating_bucket = false
let new_bucket_name
const get_buckets = async () => {
loading = true;
try {
buckets = await fs_get_buckets();
} catch (err) {
alert(err);
} finally {
loading = false;
}
};
const create_bucket = async () => {
if (!new_bucket_name.value) {
alert("Please enter a name!")
return
}
try {
let bucket = await fs_create_bucket(new_bucket_name.value)
console.log(bucket)
} catch (err) {
alert("Failed to create bucket! "+err)
}
creating_bucket = false
get_buckets();
}
onMount(get_buckets);
</script>
<LoadingIndicator loading={loading}/>
<header>
<h1>My Buckets</h1>
</header>
<div id="page_content" class="page_content">
<section>
<div class="toolbar" style="text-align: right;">
<button
class:button_highlight={creating_bucket}
on:click={() => {creating_bucket = !creating_bucket}}
>
<i class="icon">create_new_folder</i> New bucket
</button>
</div>
{#if creating_bucket}
<div class="highlight_shaded">
<form on:submit|preventDefault={create_bucket}>
<table class="form">
<tr>
<td>
Name
</td>
<td>
<input type="text" bind:this={new_bucket_name}/>
</td>
</tr>
<tr>
<td colspan="2">
<button class="button_highlight" type="submit" style="float: right;">
<i class="icon">save</i> Save
</button>
</td>
</tr>
</table>
</form>
</div>
{/if}
{#each buckets as bucket (bucket.id)}
<UserBucket bucket={bucket} on:refresh={get_buckets}></UserBucket>
{/each}
</section>
</div>
<Footer/>

View File

@@ -15,12 +15,20 @@ const header_click = () => {
} }
} }
const keypress = e => {
if (e.code === "Space") {
if (click_expand) {
toggle()
}
}
}
// Highlight the title bar if the user moves their mouse over it // Highlight the title bar if the user moves their mouse over it
export let highlight = false export let highlight = false
</script> </script>
<div class="expandable"> <div class="expandable">
<div class="header" class:click_expand class:highlight on:click={header_click}> <div class="header" class:click_expand class:highlight on:click={header_click} on:keypress={keypress}>
<div class="title"> <div class="title">
<slot name="header"></slot> <slot name="header"></slot>
</div> </div>

View File

@@ -154,7 +154,6 @@ func New(r *httprouter.Router, prefix string, conf Config) (wc *WebController) {
{GET, "limits" /* */, wc.serveMarkdown("limits.md", handlerOpts{})}, {GET, "limits" /* */, wc.serveMarkdown("limits.md", handlerOpts{})},
{GET, "abuse" /* */, wc.serveMarkdown("abuse.md", handlerOpts{})}, {GET, "abuse" /* */, wc.serveMarkdown("abuse.md", handlerOpts{})},
{GET, "apps" /* */, wc.serveTemplate("apps", handlerOpts{})}, {GET, "apps" /* */, wc.serveTemplate("apps", handlerOpts{})},
{GET, "directory_upload" /**/, wc.serveTemplate("directory_upload", handlerOpts{})},
// User account pages // User account pages
{GET, "register" /* */, wc.serveForm(wc.registerForm, handlerOpts{NoEmbed: true})}, {GET, "register" /* */, wc.serveForm(wc.registerForm, handlerOpts{NoEmbed: true})},
@@ -165,7 +164,6 @@ func New(r *httprouter.Router, prefix string, conf Config) (wc *WebController) {
{PST, "password_reset" /* */, wc.serveForm(wc.passwordResetForm, handlerOpts{NoEmbed: true})}, {PST, "password_reset" /* */, wc.serveForm(wc.passwordResetForm, handlerOpts{NoEmbed: true})},
{GET, "logout" /* */, wc.serveTemplate("logout", handlerOpts{Auth: true, NoEmbed: true})}, {GET, "logout" /* */, wc.serveTemplate("logout", handlerOpts{Auth: true, NoEmbed: true})},
{PST, "logout" /* */, wc.serveLogout}, {PST, "logout" /* */, wc.serveLogout},
{GET, "user/buckets" /* */, wc.serveTemplate("user_buckets", handlerOpts{Auth: true})},
{GET, "user/filemanager" /* */, wc.serveTemplate("file_manager", handlerOpts{Auth: true})}, {GET, "user/filemanager" /* */, wc.serveTemplate("file_manager", handlerOpts{Auth: true})},
{GET, "user/export/files" /**/, wc.serveUserExportFiles}, {GET, "user/export/files" /**/, wc.serveUserExportFiles},
{GET, "user/export/lists" /**/, wc.serveUserExportLists}, {GET, "user/export/lists" /**/, wc.serveUserExportLists},