From 388b0605dd334a3da670e4796943b84384bb6859 Mon Sep 17 00:00:00 2001 From: Roman Godmaire Date: Sun, 19 Nov 2023 15:27:15 -0500 Subject: [PATCH] feat: Upload new tracks --- package.json | 4 +++- pnpm-lock.yaml | 15 +++++++++++++ prisma/schema.prisma | 1 + src/hooks.server.ts | 4 ++-- src/lib/server/db/index.ts | 13 ++++++++--- src/lib/server/db/prisma.ts | 12 ++++++++++ src/lib/server/storage/index.ts | 2 +- src/lib/server/storage/s3.ts | 13 ++++++----- src/routes/upload/+page.server.ts | 37 +++++++++++++++++++++++++++++++ 9 files changed, 89 insertions(+), 12 deletions(-) create mode 100644 src/routes/upload/+page.server.ts diff --git a/package.json b/package.json index 0f0bc19..e717ec2 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "devDependencies": { "@sveltejs/adapter-auto": "^2.0.0", "@sveltejs/kit": "^1.27.4", + "@types/uuid": "^9.0.7", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", "eslint": "^8.28.0", @@ -36,6 +37,7 @@ "@lucia-auth/adapter-prisma": "^3.0.2", "@picocss/pico": "^1.5.10", "@prisma/client": "5.6.0", - "lucia": "^2.7.4" + "lucia": "^2.7.4", + "uuid": "^9.0.1" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 41c57b3..ab4b9f7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,6 +20,9 @@ dependencies: lucia: specifier: ^2.7.4 version: 2.7.4 + uuid: + specifier: ^9.0.1 + version: 9.0.1 devDependencies: '@sveltejs/adapter-auto': @@ -28,6 +31,9 @@ devDependencies: '@sveltejs/kit': specifier: ^1.27.4 version: 1.27.6(svelte@4.2.5)(vite@4.5.0) + '@types/uuid': + specifier: ^9.0.7 + version: 9.0.7 '@typescript-eslint/eslint-plugin': specifier: ^6.0.0 version: 6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.54.0)(typescript@5.2.2) @@ -1577,6 +1583,10 @@ packages: resolution: {integrity: sha512-+d+WYC1BxJ6yVOgUgzK8gWvp5qF8ssV5r4nsDcZWKRWcDQLQ619tvWAxJQYGgBrO1MnLJC7a5GtiYsAoQ47dJg==} dev: true + /@types/uuid@9.0.7: + resolution: {integrity: sha512-WUtIVRUZ9i5dYXefDEAI7sh9/O7jGvHg7Df/5O/gtH3Yabe5odI3UWopVR1qbPXQtvOxWu3mM4XxlYeZtMWF4g==} + dev: true + /@typescript-eslint/eslint-plugin@6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.54.0)(typescript@5.2.2): resolution: {integrity: sha512-uXnpZDc4VRjY4iuypDBKzW1rz9T5YBBK0snMn8MaTSNd2kMlj50LnLBABELjJiOL5YHk7ZD8hbSpI9ubzqYI0w==} engines: {node: ^16.0.0 || >=18.0.0} @@ -3207,6 +3217,11 @@ packages: hasBin: true dev: false + /uuid@9.0.1: + resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} + hasBin: true + dev: false + /vite-node@0.34.6(@types/node@20.9.2): resolution: {integrity: sha512-nlBMJ9x6n7/Amaz6F3zJ97EBwR2FkzhBRxF5e+jE6LA3yi6Wtc2lyTij1OnDMIr34v5g/tVQtsVAzhT0jc5ygA==} engines: {node: '>=v14.18.0'} diff --git a/prisma/schema.prisma b/prisma/schema.prisma index d46d1cf..dfdf7ee 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -41,6 +41,7 @@ model Key { model Track { id Int @id @default(autoincrement()) title String + objectKey String versions TrackVersion[] producer User @relation(fields: [producerId], references: [id], onDelete: Cascade) producerId String diff --git a/src/hooks.server.ts b/src/hooks.server.ts index 17ef5ec..c898810 100644 --- a/src/hooks.server.ts +++ b/src/hooks.server.ts @@ -1,12 +1,12 @@ import type { Handle } from '@sveltejs/kit'; -import { S3_STORAGE_URL } from '$env/static/private'; +import { S3_STORAGE_URL, S3_STORAGE_BUCKET } from '$env/static/private'; import { auth } from '$lib/server/lucia'; import { ObjectStorageS3 } from '$lib/server/storage/s3'; import { DatabasePrisma } from '$lib/server/db/prisma'; -const s3Client = new ObjectStorageS3(S3_STORAGE_URL); +const s3Client = new ObjectStorageS3(S3_STORAGE_URL, S3_STORAGE_BUCKET); const prismaClient = new DatabasePrisma(); export const handle: Handle = async ({ event, resolve }) => { diff --git a/src/lib/server/db/index.ts b/src/lib/server/db/index.ts index 08993b8..c340b2a 100644 --- a/src/lib/server/db/index.ts +++ b/src/lib/server/db/index.ts @@ -1,5 +1,12 @@ +import type { Track } from '@prisma/client'; + export interface Database { - listTracksWithProducer: ( - producerId: string - ) => Promise<{ title: string; producer: { username: string } }[]>; + listTracksWithProducer: (producerId: string) => Promise< + { + title: string; + producer: { username: string }; + }[] + >; + + insertTrack: (producerId: string, title: string, objectKey: string) => Promise; } diff --git a/src/lib/server/db/prisma.ts b/src/lib/server/db/prisma.ts index 87fb501..83e20eb 100644 --- a/src/lib/server/db/prisma.ts +++ b/src/lib/server/db/prisma.ts @@ -25,4 +25,16 @@ export class DatabasePrisma implements Database { return tracks; }; + + insertTrack = async (producerId: string, title: string, objectKey: string) => { + const track = await this.client.track.create({ + data: { + title, + objectKey, + producerId + } + }); + + return track; + }; } diff --git a/src/lib/server/storage/index.ts b/src/lib/server/storage/index.ts index 0a584bc..f369f2c 100644 --- a/src/lib/server/storage/index.ts +++ b/src/lib/server/storage/index.ts @@ -1,3 +1,3 @@ export interface ObjectStorage { - putObject: (obj: Buffer) => Promise; + putObject: (key: string, obj: Uint8Array) => Promise; } diff --git a/src/lib/server/storage/s3.ts b/src/lib/server/storage/s3.ts index 389f909..e358035 100644 --- a/src/lib/server/storage/s3.ts +++ b/src/lib/server/storage/s3.ts @@ -3,17 +3,20 @@ import { PutObjectCommand, S3Client, S3ServiceException } from '@aws-sdk/client- class ObjectStorageS3 implements ObjectStorage { client: S3Client; + bucket: string; - constructor(url: string) { + constructor(url: string, bucket: string) { + this.bucket = bucket; this.client = new S3Client({ - endpoint: url + endpoint: url, + region: 'us-east-1' }); } - putObject = async (obj: Buffer) => { + putObject = async (key: string, obj: Uint8Array) => { const command = new PutObjectCommand({ - Bucket: 'test-bucket', - Key: 'hello-s3.txt', + Bucket: this.bucket, + Key: key, Body: obj }); diff --git a/src/routes/upload/+page.server.ts b/src/routes/upload/+page.server.ts new file mode 100644 index 0000000..5eb911f --- /dev/null +++ b/src/routes/upload/+page.server.ts @@ -0,0 +1,37 @@ +import type { Actions, PageServerLoad } from './$types'; + +import { fail, redirect } from '@sveltejs/kit'; +import { v4 as uuidv4 } from 'uuid'; + +export const load: PageServerLoad = async ({ locals: { authReq } }) => { + const session = await authReq.validate(); + if (!session) throw redirect(302, '/login'); + return {}; +}; + +export const actions: Actions = { + default: async ({ request, locals: { authReq, database, objectStorage } }) => { + const session = await authReq.validate(); + if (!session) throw redirect(302, '/login'); + + const producerId = session.user.userId; + + const formData = await request.formData(); + const title = formData.get('title') as string; + const file = formData.get('file') as File; + + const objectKey = uuidv4(); + + const err = await objectStorage.putObject(objectKey, new Uint8Array(await file.arrayBuffer())); + if (err) { + console.log(err); + return fail(500, { + message: 'Failed to upload file.' + }); + } + + await database.insertTrack(producerId, title, objectKey); + + throw redirect(302, '/'); + } +};