From 8fa16d4e096f453a87ddd211a771a972e9170fad Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Sun, 19 Nov 2023 10:36:54 -1000 Subject: [PATCH] Add media upload functionality and create uploads folder --- Postgres.Dockerfile | 21 ++ bun.lockb | Bin 329664 -> 329664 bytes classes/media.ts | 5 + database/datasource.ts | 14 +- index.ts | 5 +- .../20231119002951_init/migration.sql | 286 ++++++++++++++++++ prisma/migrations/migration_lock.toml | 3 + 7 files changed, 318 insertions(+), 16 deletions(-) create mode 100644 Postgres.Dockerfile create mode 100644 prisma/migrations/20231119002951_init/migration.sql create mode 100644 prisma/migrations/migration_lock.toml diff --git a/Postgres.Dockerfile b/Postgres.Dockerfile new file mode 100644 index 00000000..d6645bb6 --- /dev/null +++ b/Postgres.Dockerfile @@ -0,0 +1,21 @@ +# Use the latest Postgres Docker image based on Alpine +FROM postgres:alpine + +# Set working directory +WORKDIR /usr/src/app + +# Install curl +RUN apk add --no-cache curl + +RUN cd "$(mktemp -d)" \ + && curl -LO "https://github.com/fboulnois/pg_uuidv7/releases/download/v1.3.0/{pg_uuidv7.tar.gz,SHA256SUMS}" \ + && tar xf pg_uuidv7.tar.gz \ + && sha256sum -c SHA256SUMS \ + && PG_MAJOR=$(pg_config --version | sed 's/^.* \([0-9]\{1,\}\).*$/\1/') \ + && cp "$PG_MAJOR/pg_uuidv7.so" "$(pg_config --pkglibdir)" \ + && cp sql/pg_uuidv7--1.3.sql pg_uuidv7.control "$(pg_config --sharedir)/extension" +# Add a script to run the CREATE EXTENSION command +RUN echo '#!/bin/sh\npsql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "CREATE EXTENSION pg_uuidv7;"' > /docker-entrypoint-initdb.d/init.sh + +# Make the entrypoint script executable +RUN chmod +x /docker-entrypoint-initdb.d/init.sh \ No newline at end of file diff --git a/bun.lockb b/bun.lockb index c97db9f8f22ef7279c7ae927a9ee9d4d145cc146..5b0e9d77d6dd6dda03e7d61853a05609385fc197 100755 GIT binary patch delta 34 pcmX@mFLIz?q@jheg=q^ja|Q=voPnOPk)ByQcLwuz?hKZ#^8vzI3V{Fs delta 34 lcmX@mFLIz?q@jheg=q^ja|Qk#6 diff --git a/classes/media.ts b/classes/media.ts index 9eb6bfd6..60b1b00c 100644 --- a/classes/media.ts +++ b/classes/media.ts @@ -6,6 +6,7 @@ import { } from "@aws-sdk/client-s3"; import { ConfigType } from "@config"; import sharp from "sharp"; +import { exists, mkdir } from "fs/promises"; class MediaBackend { backend: string; @@ -223,6 +224,10 @@ export class LocalBackend extends MediaBackend { const hash = await super.addMedia(media); + if (!(await exists(`${process.cwd()}/uploads`))) { + await mkdir(`${process.cwd()}/uploads`); + } + await Bun.write(Bun.file(`${process.cwd()}/uploads/${hash}`), media); return hash; diff --git a/database/datasource.ts b/database/datasource.ts index 1bec9a7b..a12b19ea 100644 --- a/database/datasource.ts +++ b/database/datasource.ts @@ -1,22 +1,10 @@ -import { DataSource } from "typeorm"; import { getConfig } from "../utils/config"; import { PrismaClient } from "@prisma/client"; const config = getConfig(); -const AppDataSource = new DataSource({ - type: "postgres", - host: config.database.host, - port: config.database.port, - username: config.database.username, - password: config.database.password, - database: config.database.database, - synchronize: true, - entities: [process.cwd() + "/database/entities/*.ts"], -}); - const client = new PrismaClient({ datasourceUrl: `postgresql://${config.database.username}:${config.database.password}@${config.database.host}:${config.database.port}/${config.database.database}`, }); -export { AppDataSource, client }; +export { client }; diff --git a/index.ts b/index.ts index a0fb9166..456b76dc 100644 --- a/index.ts +++ b/index.ts @@ -5,9 +5,9 @@ import chalk from "chalk"; import { appendFile } from "fs/promises"; import { matches } from "ip-matching"; import "reflect-metadata"; -import { AppDataSource } from "~database/datasource"; import { AuthData, getFromRequest } from "~database/entities/User"; import { APIRouteMeta } from "~types/api"; +import { mkdir } from "fs/promises"; const router = new Bun.FileSystemRouter({ style: "nextjs", @@ -21,11 +21,10 @@ const requests_log = Bun.file(process.cwd() + "/logs/requests.log"); if (!(await requests_log.exists())) { console.log(`${chalk.green(`✓`)} ${chalk.bold("Creating logs folder...")}`); + await mkdir(process.cwd() + "/logs"); await Bun.write(process.cwd() + "/logs/requests.log", ""); } -if (!AppDataSource.isInitialized) await AppDataSource.initialize(); - Bun.serve({ port: config.http.bind_port, hostname: config.http.bind || "0.0.0.0", // defaults to "0.0.0.0" diff --git a/prisma/migrations/20231119002951_init/migration.sql b/prisma/migrations/20231119002951_init/migration.sql new file mode 100644 index 00000000..9b9c179b --- /dev/null +++ b/prisma/migrations/20231119002951_init/migration.sql @@ -0,0 +1,286 @@ +-- CreateExtension +CREATE EXTENSION IF NOT EXISTS "pg_uuidv7"; + +-- CreateTable +CREATE TABLE "Application" ( + "id" UUID NOT NULL DEFAULT uuid_generate_v7(), + "name" TEXT NOT NULL, + "website" TEXT, + "vapid_key" TEXT, + "client_id" TEXT NOT NULL, + "secret" TEXT NOT NULL, + "scopes" TEXT NOT NULL, + "redirect_uris" TEXT NOT NULL, + + CONSTRAINT "Application_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Emoji" ( + "id" UUID NOT NULL DEFAULT uuid_generate_v7(), + "shortcode" TEXT NOT NULL, + "url" TEXT NOT NULL, + "visible_in_picker" BOOLEAN NOT NULL, + "instanceId" UUID, + "alt" TEXT, + "content_type" TEXT NOT NULL, + + CONSTRAINT "Emoji_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Instance" ( + "id" UUID NOT NULL DEFAULT uuid_generate_v7(), + "base_url" TEXT NOT NULL, + "name" TEXT NOT NULL, + "version" TEXT NOT NULL, + "logo" JSONB NOT NULL, + + CONSTRAINT "Instance_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Like" ( + "id" UUID NOT NULL DEFAULT uuid_generate_v7(), + "likerId" UUID NOT NULL, + "likedId" UUID NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "Like_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "LysandObject" ( + "id" UUID NOT NULL DEFAULT uuid_generate_v7(), + "remote_id" TEXT NOT NULL, + "type" TEXT NOT NULL, + "uri" TEXT NOT NULL, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "authorId" UUID, + "extra_data" JSONB NOT NULL, + "extensions" JSONB NOT NULL, + + CONSTRAINT "LysandObject_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Relationship" ( + "id" UUID NOT NULL DEFAULT uuid_generate_v7(), + "ownerId" UUID NOT NULL, + "subjectId" UUID NOT NULL, + "following" BOOLEAN NOT NULL, + "showingReblogs" BOOLEAN NOT NULL, + "notifying" BOOLEAN NOT NULL, + "followedBy" BOOLEAN NOT NULL, + "blocking" BOOLEAN NOT NULL, + "blockedBy" BOOLEAN NOT NULL, + "muting" BOOLEAN NOT NULL, + "mutingNotifications" BOOLEAN NOT NULL, + "requested" BOOLEAN NOT NULL, + "domainBlocking" BOOLEAN NOT NULL, + "endorsed" BOOLEAN NOT NULL, + "languages" TEXT[], + "note" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Relationship_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Status" ( + "id" UUID NOT NULL DEFAULT uuid_generate_v7(), + "uri" TEXT NOT NULL, + "authorId" UUID NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "reblogId" UUID, + "isReblog" BOOLEAN NOT NULL, + "content" TEXT NOT NULL DEFAULT '', + "contentType" TEXT NOT NULL DEFAULT 'text/plain', + "visibility" TEXT NOT NULL, + "inReplyToPostId" UUID, + "quotingPostId" UUID, + "instanceId" UUID, + "sensitive" BOOLEAN NOT NULL, + "spoilerText" TEXT NOT NULL DEFAULT '', + "applicationId" UUID, + + CONSTRAINT "Status_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Token" ( + "id" UUID NOT NULL DEFAULT uuid_generate_v7(), + "token_type" TEXT NOT NULL, + "scope" TEXT NOT NULL, + "access_token" TEXT NOT NULL, + "code" TEXT NOT NULL, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "userId" UUID, + "applicationId" UUID, + + CONSTRAINT "Token_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "User" ( + "id" UUID NOT NULL DEFAULT uuid_generate_v7(), + "uri" TEXT NOT NULL, + "username" TEXT NOT NULL, + "displayName" TEXT NOT NULL, + "password" TEXT, + "email" TEXT, + "note" TEXT NOT NULL DEFAULT '', + "isAdmin" BOOLEAN NOT NULL DEFAULT false, + "endpoints" JSONB, + "source" JSONB NOT NULL, + "avatar" TEXT NOT NULL, + "header" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "isBot" BOOLEAN NOT NULL DEFAULT false, + "isLocked" BOOLEAN NOT NULL DEFAULT false, + "isDiscoverable" BOOLEAN NOT NULL DEFAULT false, + "sanctions" TEXT[] DEFAULT ARRAY[]::TEXT[], + "publicKey" TEXT NOT NULL, + "privateKey" TEXT, + "instanceId" UUID, + + CONSTRAINT "User_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "_EmojiToUser" ( + "A" UUID NOT NULL, + "B" UUID NOT NULL +); + +-- CreateTable +CREATE TABLE "_EmojiToStatus" ( + "A" UUID NOT NULL, + "B" UUID NOT NULL +); + +-- CreateTable +CREATE TABLE "_StatusToUser" ( + "A" UUID NOT NULL, + "B" UUID NOT NULL +); + +-- CreateTable +CREATE TABLE "_UserPinnedNotes" ( + "A" UUID NOT NULL, + "B" UUID NOT NULL +); + +-- CreateIndex +CREATE UNIQUE INDEX "LysandObject_remote_id_key" ON "LysandObject"("remote_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "LysandObject_uri_key" ON "LysandObject"("uri"); + +-- CreateIndex +CREATE UNIQUE INDEX "Status_uri_key" ON "Status"("uri"); + +-- CreateIndex +CREATE UNIQUE INDEX "User_uri_key" ON "User"("uri"); + +-- CreateIndex +CREATE UNIQUE INDEX "User_username_key" ON "User"("username"); + +-- CreateIndex +CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); + +-- CreateIndex +CREATE UNIQUE INDEX "_EmojiToUser_AB_unique" ON "_EmojiToUser"("A", "B"); + +-- CreateIndex +CREATE INDEX "_EmojiToUser_B_index" ON "_EmojiToUser"("B"); + +-- CreateIndex +CREATE UNIQUE INDEX "_EmojiToStatus_AB_unique" ON "_EmojiToStatus"("A", "B"); + +-- CreateIndex +CREATE INDEX "_EmojiToStatus_B_index" ON "_EmojiToStatus"("B"); + +-- CreateIndex +CREATE UNIQUE INDEX "_StatusToUser_AB_unique" ON "_StatusToUser"("A", "B"); + +-- CreateIndex +CREATE INDEX "_StatusToUser_B_index" ON "_StatusToUser"("B"); + +-- CreateIndex +CREATE UNIQUE INDEX "_UserPinnedNotes_AB_unique" ON "_UserPinnedNotes"("A", "B"); + +-- CreateIndex +CREATE INDEX "_UserPinnedNotes_B_index" ON "_UserPinnedNotes"("B"); + +-- AddForeignKey +ALTER TABLE "Emoji" ADD CONSTRAINT "Emoji_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Like" ADD CONSTRAINT "Like_likerId_fkey" FOREIGN KEY ("likerId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Like" ADD CONSTRAINT "Like_likedId_fkey" FOREIGN KEY ("likedId") REFERENCES "Status"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "LysandObject" ADD CONSTRAINT "LysandObject_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "LysandObject"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Relationship" ADD CONSTRAINT "Relationship_ownerId_fkey" FOREIGN KEY ("ownerId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Relationship" ADD CONSTRAINT "Relationship_subjectId_fkey" FOREIGN KEY ("subjectId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Status" ADD CONSTRAINT "Status_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Status" ADD CONSTRAINT "Status_reblogId_fkey" FOREIGN KEY ("reblogId") REFERENCES "Status"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Status" ADD CONSTRAINT "Status_inReplyToPostId_fkey" FOREIGN KEY ("inReplyToPostId") REFERENCES "Status"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Status" ADD CONSTRAINT "Status_quotingPostId_fkey" FOREIGN KEY ("quotingPostId") REFERENCES "Status"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Status" ADD CONSTRAINT "Status_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Status" ADD CONSTRAINT "Status_applicationId_fkey" FOREIGN KEY ("applicationId") REFERENCES "Application"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Token" ADD CONSTRAINT "Token_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Token" ADD CONSTRAINT "Token_applicationId_fkey" FOREIGN KEY ("applicationId") REFERENCES "Application"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "User" ADD CONSTRAINT "User_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_EmojiToUser" ADD CONSTRAINT "_EmojiToUser_A_fkey" FOREIGN KEY ("A") REFERENCES "Emoji"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_EmojiToUser" ADD CONSTRAINT "_EmojiToUser_B_fkey" FOREIGN KEY ("B") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_EmojiToStatus" ADD CONSTRAINT "_EmojiToStatus_A_fkey" FOREIGN KEY ("A") REFERENCES "Emoji"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_EmojiToStatus" ADD CONSTRAINT "_EmojiToStatus_B_fkey" FOREIGN KEY ("B") REFERENCES "Status"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_StatusToUser" ADD CONSTRAINT "_StatusToUser_A_fkey" FOREIGN KEY ("A") REFERENCES "Status"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_StatusToUser" ADD CONSTRAINT "_StatusToUser_B_fkey" FOREIGN KEY ("B") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_UserPinnedNotes" ADD CONSTRAINT "_UserPinnedNotes_A_fkey" FOREIGN KEY ("A") REFERENCES "Status"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_UserPinnedNotes" ADD CONSTRAINT "_UserPinnedNotes_B_fkey" FOREIGN KEY ("B") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml new file mode 100644 index 00000000..fbffa92c --- /dev/null +++ b/prisma/migrations/migration_lock.toml @@ -0,0 +1,3 @@ +# Please do not edit this file manually +# It should be added in your version-control system (i.e. Git) +provider = "postgresql" \ No newline at end of file