diff --git a/prisma/migrations/20240706053728_internalname/migration.sql b/prisma/migrations/20240706053728_internalname/migration.sql new file mode 100644 index 0000000..a1fb7af --- /dev/null +++ b/prisma/migrations/20240706053728_internalname/migration.sql @@ -0,0 +1,8 @@ +/* + Warnings: + + - Added the required column `internalName` to the `Upload` table without a default value. This is not possible if the table is not empty. + +*/ +-- AlterTable +ALTER TABLE `Upload` ADD COLUMN `internalName` LONGTEXT NOT NULL; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 090c4f3..33e2c61 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -51,9 +51,10 @@ model Upload { uploader User @relation(fields: [uploaderId], references: [id]) uploaderId Int - fileName String @db.LongText - public Boolean @default(true) - uploaded DateTime @default(now()) + fileName String @db.LongText + internalName String @db.LongText + public Boolean @default(true) + uploaded DateTime @default(now()) } enum Role { diff --git a/src/lib/components/File.svelte b/src/lib/components/File.svelte index 452a384..8fc06dc 100644 --- a/src/lib/components/File.svelte +++ b/src/lib/components/File.svelte @@ -27,16 +27,15 @@
{#if url} - {file.name} + {file.name} {:else}

{file.name}

{/if} diff --git a/src/lib/components/Header.svelte b/src/lib/components/Header.svelte index 8c921b2..6e5bb15 100644 --- a/src/lib/components/Header.svelte +++ b/src/lib/components/Header.svelte @@ -13,14 +13,17 @@
Dashboard Uploads - Admin + Links + {#if $user?.role === 'ADMINISTRATOR'} + Admin + {/if}
diff --git a/src/lib/index.ts b/src/lib/index.ts index c774401..ca53bee 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -7,12 +7,10 @@ export function goBack() { } export function bytesToHumanReadable(bytes: number) { - if (bytes === 0) { - return '0 B'; - } - - let e = Math.floor(Math.log(bytes) / Math.log(1024)); - return (bytes / Math.pow(1024, e)).toFixed(2) + ' ' + ' KMGTP'.charAt(e) + 'B'; + let i = bytes == 0 ? 0 : Math.floor(Math.log(bytes) / Math.log(1024)); + return ( + +(bytes / Math.pow(1024, i)).toFixed(2) * 1 + ' ' + ['Bytes', 'KiB', 'MiB', 'GiB', 'TiB'][i] + ); } export function request( diff --git a/src/lib/server/database.ts b/src/lib/server/database.ts index dcb1c88..1d7132a 100644 --- a/src/lib/server/database.ts +++ b/src/lib/server/database.ts @@ -88,7 +88,12 @@ export async function deleteSession(id: string) { }); } -export async function createUpload(id: string, uploaderId: number, fileName: string) { +export async function createUpload( + id: string, + uploaderId: number, + fileName: string, + internalName: string +) { const settings = await prisma.userSettings.findFirst({ where: { id: uploaderId } }); @@ -98,6 +103,7 @@ export async function createUpload(id: string, uploaderId: number, fileName: str id, uploaderId, fileName, + internalName, public: settings?.newPostsPublic } }); @@ -113,6 +119,7 @@ export async function getUpload(id: string) { select: { id: true, fileName: true, + internalName: true, public: true, uploaded: true, uploader: true diff --git a/src/lib/server/minio.ts b/src/lib/server/minio.ts index 4154bcd..4b0cee9 100644 --- a/src/lib/server/minio.ts +++ b/src/lib/server/minio.ts @@ -25,5 +25,5 @@ function du() { if (!building) { du(); - setTimeout(du, 1000 * 60 * 10); + setTimeout(du, 1000 * 60 * 5); } diff --git a/src/routes/(app)/dashboard/+page.svelte b/src/routes/(app)/dashboard/+page.svelte index 361c0c8..37b145f 100644 --- a/src/routes/(app)/dashboard/+page.svelte +++ b/src/routes/(app)/dashboard/+page.svelte @@ -6,8 +6,11 @@ import FileComponent from '$lib/components/File.svelte'; import { get } from 'svelte/store'; import { request } from '$lib'; + import { toast } from 'svelte-sonner'; + import { onMount } from 'svelte'; export let data; + console.log(data); user.set(data?.user); let input: HTMLInputElement, @@ -16,6 +19,10 @@ let running = false; + onMount(() => { + fileProgress.set({}); + }); + // lazy again function progress(name: string, data: any) { let _ = get(fileProgress); @@ -37,11 +44,22 @@ const response = await request(body, (percent: number) => { progress(k, { percent }); }).catch(() => { + toast.error(k + ' failed to upload.'); progress(k, { error: true }); }); if (response && response.success) progress(k, { url: response.body }); - else progress(k, { error: true }); + else { + if (response && response.body) + try { + let body = JSON.parse(response.body); + toast.error(k + ' failed: ' + body.message); + } catch (_) { + toast.error(k + ' failed to upload.'); + } + + progress(k, { error: true }); + } }); } @@ -69,7 +87,7 @@

Welcome, {data.user.username}.

- Your max upload size is {data.user.maxUploadMB} MB. + Your max upload size is {data.user.maxUploadMB} MiB.

diff --git a/src/routes/(app)/links/+page.svelte b/src/routes/(app)/links/+page.svelte new file mode 100644 index 0000000..e69de29 diff --git a/src/routes/api/upload/+server.ts b/src/routes/api/upload/+server.ts index a6b2782..c42b658 100644 --- a/src/routes/api/upload/+server.ts +++ b/src/routes/api/upload/+server.ts @@ -15,15 +15,16 @@ export const POST = async ({ request, cookies }) => { const data = await request.formData(); const file = data.get('file') as File; - if (Math.floor(file.size / (1024 * 1024)) > user.maxUploadMB) + if (file.size / 1048576 >= user.maxUploadMB) return error(413, { status: 413, message: 'Content Too Large' }); let id = generateId(undefined, 10); + let internalName = `${Date.now()}-${file.name}`; const object = await minio .putObject( BUCKET, - `${user.id}/${file.name}`, + `${user.id}/${internalName}`, Buffer.from(await file.arrayBuffer()), file.size, { @@ -34,7 +35,7 @@ export const POST = async ({ request, cookies }) => { if (!object) return error(500, { status: 500, message: 'Internal Server Error - Contact Administrator' }); - const objectRecord = await createUpload(id, user.id, file.name); + const objectRecord = await createUpload(id, user.id, file.name, internalName); if (!objectRecord) return error(500, { status: 500, message: 'Internal Server Error - Contact Administrator' }); diff --git a/src/routes/download/[id]/+server.ts b/src/routes/download/[id]/+server.ts index f682c24..bed7d57 100644 --- a/src/routes/download/[id]/+server.ts +++ b/src/routes/download/[id]/+server.ts @@ -2,14 +2,17 @@ import { getUpload } from '$lib/server/database.js'; import minio, { BUCKET } from '$lib/server/minio'; import { error } from '@sveltejs/kit'; -export const GET = async ({ params }) => { +export const GET = async ({ params, locals }) => { const id = params.id; const file = await getUpload(id); if (!file) throw error(404, { status: 404, message: 'File Not Found' }); - const object = await minio.getObject(BUCKET, `${file.uploader.id}/${file.fileName}`); - const metadata = await minio.statObject(BUCKET, `${file.uploader.id}/${file.fileName}`); + if (!file.public && locals?.user?.id !== file.uploader.id) + throw error(403, { status: 403, message: 'Forbidden' }); + + const object = await minio.getObject(BUCKET, `${file.uploader.id}/${file.internalName}`); + const metadata = await minio.statObject(BUCKET, `${file.uploader.id}/${file.internalName}`); const ac = new AbortController(); diff --git a/src/routes/file/[id]/+page.server.ts b/src/routes/file/[id]/+page.server.ts index d098a52..3eae64f 100644 --- a/src/routes/file/[id]/+page.server.ts +++ b/src/routes/file/[id]/+page.server.ts @@ -2,14 +2,17 @@ import { getSettings, getUpload } from '$lib/server/database'; import minio, { BUCKET } from '$lib/server/minio'; import { error } from '@sveltejs/kit'; -export async function load({ params }) { +export async function load({ params, locals }) { const file = await getUpload(params.id); if (!file) throw error(404, { status: 404, message: 'File Not Found' }); + if (!file.public && locals?.user?.id !== file.uploader.id) + throw error(403, { status: 403, message: 'Forbidden' }); + const settings = await getSettings(file.uploader.id); if (!settings) throw error(500, { status: 500, message: 'Internal Server Error' }); - const metadata = await minio.statObject(BUCKET, `${file.uploader.id}/${file.fileName}`); + const metadata = await minio.statObject(BUCKET, `${file.uploader.id}/${file.internalName}`); function formatString(input: string) { if (file && metadata)