diff --git a/prisma/migrations/20250828011430_add_game_dlc_metadata/migration.sql b/prisma/migrations/20250828011430_add_game_dlc_metadata/migration.sql
new file mode 100644
index 0000000..e1c6717
--- /dev/null
+++ b/prisma/migrations/20250828011430_add_game_dlc_metadata/migration.sql
@@ -0,0 +1,32 @@
+/*
+ Warnings:
+
+ - Added the required column `mReleased` to the `Mod` table without a default value. This is not possible if the table is not empty.
+
+*/
+-- DropIndex
+DROP INDEX "public"."GameTag_name_idx";
+
+-- AlterTable
+ALTER TABLE "public"."Mod" ADD COLUMN "mReleased" TIMESTAMP(3) NOT NULL;
+
+-- CreateTable
+CREATE TABLE "public"."GameDLCMetadata" (
+ "id" TEXT NOT NULL,
+ "mName" TEXT NOT NULL,
+ "mShortDescription" TEXT NOT NULL,
+ "mDescription" TEXT NOT NULL,
+ "mIconObjectId" TEXT NOT NULL,
+ "mBannerObjectId" TEXT NOT NULL,
+ "mCoverObjectId" TEXT NOT NULL,
+ "mImageCarouselObjectIds" TEXT[],
+ "mImageLibraryObjectIds" TEXT[],
+
+ CONSTRAINT "GameDLCMetadata_pkey" PRIMARY KEY ("id")
+);
+
+-- CreateIndex
+CREATE INDEX "GameTag_name_idx" ON "public"."GameTag" USING GIST ("name" gist_trgm_ops(siglen=32));
+
+-- AddForeignKey
+ALTER TABLE "public"."GameDLCMetadata" ADD CONSTRAINT "GameDLCMetadata_id_fkey" FOREIGN KEY ("id") REFERENCES "public"."DLC"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
diff --git a/prisma/models/content.prisma b/prisma/models/content.prisma
index e08d192..a84e28c 100644
--- a/prisma/models/content.prisma
+++ b/prisma/models/content.prisma
@@ -74,6 +74,8 @@ model LaunchOption {
launchCommand String
launchArgs String @default("")
+
+
}
model DLCVersion {
diff --git a/prisma/models/metadata.prisma b/prisma/models/metadata.prisma
index 627aceb..33b2023 100644
--- a/prisma/models/metadata.prisma
+++ b/prisma/models/metadata.prisma
@@ -63,6 +63,22 @@ model DLC {
libraryPath String
versions Version[]
+ metadata GameDLCMetadata?
+}
+
+model GameDLCMetadata {
+ id String @id
+ dlc DLC @relation(fields: [id], references: [id])
+
+ mName String
+ mShortDescription String
+ mDescription String
+
+ mIconObjectId String // linked to objects in s3
+ mBannerObjectId String // linked to objects in s3
+ mCoverObjectId String
+ mImageCarouselObjectIds String[] // linked to below array
+ mImageLibraryObjectIds String[] // linked to objects in s3
}
model Redist {
@@ -77,7 +93,7 @@ model Redist {
library Library @relation(fields: [libraryId], references: [id], onDelete: Cascade, onUpdate: Cascade)
libraryPath String
- versions Version[]
+ versions Version[]
platform UserPlatform?
@@unique([libraryId, libraryPath], name: "libraryKey")
@@ -97,6 +113,8 @@ model Mod {
mShortDescription String
mDescription String
+ mReleased DateTime
+
mIconObjectId String // linked to objects in s3
mBannerObjectId String // linked to objects in s3
mCoverObjectId String
diff --git a/server/api/v1/admin/redist/[id]/index.get.ts b/server/api/v1/admin/redist/[id]/index.get.ts
new file mode 100644
index 0000000..161c8fe
--- /dev/null
+++ b/server/api/v1/admin/redist/[id]/index.get.ts
@@ -0,0 +1,38 @@
+import aclManager from "~/server/internal/acls";
+import prisma from "~/server/internal/db/database";
+import libraryManager from "~/server/internal/library";
+
+export default defineEventHandler(async (h3) => {
+ const allowed = await aclManager.allowSystemACL(h3, ["redist:read"]);
+ if (!allowed) throw createError({ statusCode: 403 });
+
+ const id = getRouterParam(h3, "id")!;
+
+ const redist = await prisma.redist.findUnique({
+ where: {
+ id,
+ },
+ include: {
+ platform: true,
+ versions: true,
+ },
+ });
+ if (!redist)
+ throw createError({
+ statusCode: 404,
+ message: "Redistributable not found.",
+ });
+
+ const unimportedVersions = await libraryManager.fetchUnimportedGameVersions(
+ redist.libraryId,
+ redist.libraryPath,
+ );
+
+ if (!unimportedVersions)
+ throw createError({
+ statusCode: 500,
+ message: "Failed to fetch unimported versions for redistributable.",
+ });
+
+ return { redist, unimportedVersions };
+});
diff --git a/server/api/v1/admin/redist/[id]/index.patch.ts b/server/api/v1/admin/redist/[id]/index.patch.ts
new file mode 100644
index 0000000..77d7d9a
--- /dev/null
+++ b/server/api/v1/admin/redist/[id]/index.patch.ts
@@ -0,0 +1,27 @@
+import aclManager from "~/server/internal/acls";
+import prisma from "~/server/internal/db/database";
+
+export default defineEventHandler(async (h3) => {
+ const allowed = await aclManager.allowSystemACL(h3, ["redist:update"]);
+ if (!allowed) throw createError({ statusCode: 403 });
+
+ const body = await readBody(h3);
+
+ const id = body.id;
+ if (!id || typeof id !== "string")
+ throw createError({ statusCode: 400, message: "ID required in body." });
+
+ const updateParams = body;
+ delete updateParams["id"];
+
+ try {
+ return await prisma.redist.update({
+ where: {
+ id,
+ },
+ data: updateParams,
+ });
+ } catch (e) {
+ throw createError({ statusCode: 400, message: (e as string)?.toString() });
+ }
+});