diff --git a/src/controllers/api/media.ts b/src/controllers/api/media.ts index aa9db27..0d5115c 100644 --- a/src/controllers/api/media.ts +++ b/src/controllers/api/media.ts @@ -1,5 +1,6 @@ import { AppController } from '@/app.ts'; import { Conf } from '@/config.ts'; +import { insertUnattachedMedia } from '@/db/unattached-media.ts'; import { z } from '@/deps.ts'; import { fileSchema } from '@/schema.ts'; import { configUploader as uploader } from '@/uploaders/config.ts'; @@ -27,6 +28,17 @@ const mediaController: AppController = async (c) => { const { file, description } = result.data; const { cid } = await uploader.upload(file); + await insertUnattachedMedia({ + pukey: c.get('pubkey')!, + cid, + data: { + name: file.name, + mime: file.type, + size: file.size, + description, + }, + }); + const url = new URL(`/ipfs/${cid}`, Conf.mediaDomain).toString(); return c.json({ diff --git a/src/db.ts b/src/db.ts index e371ac9..eee165a 100644 --- a/src/db.ts +++ b/src/db.ts @@ -10,6 +10,7 @@ interface DittoDB { tags: TagRow; users: UserRow; relays: RelayRow; + unattached_media: UnattachedMediaRow; } interface EventRow { @@ -46,6 +47,14 @@ interface RelayRow { active: boolean; } +interface UnattachedMediaRow { + id: string; + pukey: string; + cid: string; + data: string; + uploaded_at: Date; +} + const db = new Kysely({ dialect: new DenoSqliteDialect({ database: new Sqlite(Conf.dbPath), diff --git a/src/db/migrations/007_unattached_media.ts b/src/db/migrations/007_unattached_media.ts new file mode 100644 index 0000000..ed37c5c --- /dev/null +++ b/src/db/migrations/007_unattached_media.ts @@ -0,0 +1,34 @@ +import { Kysely, sql } from '@/deps.ts'; + +export async function up(db: Kysely): Promise { + await db.schema + .createTable('unattached_media') + .addColumn('id', 'text', (c) => c.primaryKey()) + .addColumn('pukey', 'text', (c) => c.notNull()) + .addColumn('cid', 'text', (c) => c.notNull()) + .addColumn('data', 'text', (c) => c.notNull()) + .addColumn('uploaded_at', 'datetime', (c) => c.notNull().defaultTo(sql`CURRENT_TIMESTAMP`)) + .execute(); + + await db.schema + .createIndex('unattached_media_id') + .on('unattached_media') + .column('id') + .execute(); + + await db.schema + .createIndex('unattached_media_pukey') + .on('unattached_media') + .column('pukey') + .execute(); + + await db.schema + .createIndex('unattached_media_cid') + .on('unattached_media') + .column('cid') + .execute(); +} + +export async function down(db: Kysely): Promise { + await db.schema.dropTable('unattached_media').execute(); +} diff --git a/src/db/unattached-media.ts b/src/db/unattached-media.ts new file mode 100644 index 0000000..0018157 --- /dev/null +++ b/src/db/unattached-media.ts @@ -0,0 +1,30 @@ +import { db } from '@/db.ts'; +import { uuid62 } from '@/deps.ts'; + +interface UnattachedMedia { + id: string; + pukey: string; + cid: string; + data: { + name?: string; + mime?: string; + width?: number; + height?: number; + size?: number; + description?: string; + }; + uploaded_at: Date; +} + +function insertUnattachedMedia(media: Omit) { + return db.insertInto('unattached_media') + .values({ + id: uuid62.v4(), + uploaded_at: new Date(), + ...media, + data: JSON.stringify(media.data), + }) + .execute(); +} + +export { insertUnattachedMedia }; diff --git a/src/deps.ts b/src/deps.ts index 5b4547b..727bba1 100644 --- a/src/deps.ts +++ b/src/deps.ts @@ -68,5 +68,6 @@ export { default as tldts } from 'npm:tldts@^6.0.14'; export * as cron from 'https://deno.land/x/deno_cron@v1.0.0/cron.ts'; export { S3Client } from 'https://deno.land/x/s3_lite_client@0.6.1/mod.ts'; export { default as IpfsHash } from 'npm:ipfs-only-hash@^4.0.0'; +export { default as uuid62 } from 'npm:uuid62@^1.0.2'; export type * as TypeFest from 'npm:type-fest@^4.3.0';