(
toImport?: boolean;
offline?: boolean;
};
+ urlPrefix: string,
}
> {
return values.map((e) => {
@@ -418,6 +419,7 @@ function clientSideTransformation(
notifications: {
offline: true,
},
+ urlPrefix: type[0],
};
}
@@ -433,6 +435,7 @@ function clientSideTransformation(
},
hasNotifications: noVersions || toImport,
status: "online" as const,
+ urlPrefix: type[0],
};
});
}
diff --git a/app/pages/admin/library/r/[id]/import.vue b/app/pages/admin/library/r/[id]/import.vue
index 3553385..22b7d6b 100644
--- a/app/pages/admin/library/r/[id]/import.vue
+++ b/app/pages/admin/library/r/[id]/import.vue
@@ -1 +1,478 @@
-
+
+
+
updateCurrentlySelectedVersion(value)"
+ >
+ {{
+ $t("library.admin.import.version.version")
+ }}
+
+
+ {{
+ versions[currentlySelectedVersion]
+ }}
+ {{
+ $t("library.admin.import.selectDir")
+ }}
+
+
+
+
+
+
+
+
+
+ {{ version }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Shown to users when selecting what version to install.
+
+
+
+
+
+
+
+
+
+
+ {{ $t("library.admin.import.version.setupDesc") }}
+
+
+
+
+
+
+
+ {{ $t("library.admin.import.version.launchDesc") }}
+
+
+
+
+
+
+
+
+
+
+ No launch commands
+
+
+
+ versionSettings.launches!.push({
+ name: '',
+ description: '',
+ launchCommand: '',
+ launchArgs: '',
+ })
+ "
+ >
+ Add new
+
+
+
+
+
+
+
+ Executable to be run on uninstalling a game. Useful for installer-only
+ games.
+
+
+
+
+
+ {{ $t("library.admin.import.version.platform") }}
+
+
+
+
+ {{ $t("library.admin.import.version.updateMode") }}
+
+
+ {{ $t("library.admin.import.version.updateModeDesc") }}
+
+
+ (versionSettings.delta = v)"
+ >
+
+
+
+
+
+
+
+ {{ $t("library.admin.import.version.advancedOptions") }}
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t("library.admin.import.version.noAdv") }}
+
+
+
+
+
+ {{ $t("library.admin.import.import") }}
+
+
+
+
+
+
+
+
+ {{ importError }}
+
+
+
+
+
+
+ {{ $t("library.admin.import.version.loadingVersion") }}
+
+
+
+
+
+
diff --git a/server/api/v1/admin/import/version/index.get.ts b/server/api/v1/admin/import/version/index.get.ts
index 1476bf8..c10427a 100644
--- a/server/api/v1/admin/import/version/index.get.ts
+++ b/server/api/v1/admin/import/version/index.get.ts
@@ -1,29 +1,33 @@
+import { ArkErrors, type } from "arktype";
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
-import libraryManager from "~~/server/internal/library";
+import libraryManager, { VersionImportModes } from "~~/server/internal/library";
+
+export const PreloadQuery = type({
+ id: "string",
+ mode: type.enumerated(...VersionImportModes),
+});
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["import:version:read"]);
if (!allowed) throw createError({ statusCode: 403 });
- const query = await getQuery(h3);
- const gameId = query.id?.toString();
- if (!gameId)
- throw createError({
- statusCode: 400,
- message: "Missing id in request params",
- });
+ const rawQuery = await getQuery(h3);
+ const query = PreloadQuery(rawQuery);
+ if (query instanceof ArkErrors)
+ throw createError({ statusCode: 400, message: query.summary });
- const game = await prisma.game.findUnique({
- where: { id: gameId },
- select: { libraryId: true, libraryPath: true },
- });
- if (!game || !game.libraryId)
- throw createError({ statusCode: 404, message: "Game not found" });
+ const value: { libraryId: string; libraryPath: string } | undefined =
+ await // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ (prisma[query.mode] as any).findUnique({
+ where: { id: query.id },
+ select: { libraryId: true, libraryPath: true },
+ });
+ if (!value) throw createError({ statusCode: 404, message: "Not found" });
const unimportedVersions = await libraryManager.fetchUnimportedGameVersions(
- game.libraryId,
- game.libraryPath,
+ value.libraryId,
+ value.libraryPath,
);
if (!unimportedVersions)
throw createError({ statusCode: 400, message: "Invalid game ID" });
diff --git a/server/internal/library/index.ts b/server/internal/library/index.ts
index dcb86b5..7e71c9c 100644
--- a/server/internal/library/index.ts
+++ b/server/internal/library/index.ts
@@ -256,30 +256,30 @@ class LibraryManager {
currentIndex: number,
metadata: typeof ImportVersion.infer,
): Partial {
+ const installCreator = {
+ install: {
+ create: {
+ name: "",
+ description: "",
+ command: metadata.install!,
+ args: metadata.installArgs || "",
+ },
+ },
+ } satisfies Partial;
+
+ const uninstallCreator = {
+ uninstall: {
+ create: {
+ name: "",
+ description: "",
+ command: metadata.uninstall!,
+ args: metadata.uninstallArgs || "",
+ },
+ },
+ } satisfies Partial;
+
switch (metadata.mode) {
case "game": {
- const installCreator = {
- install: {
- create: {
- name: "",
- description: "",
- command: metadata.install!,
- args: metadata.installArgs || "",
- },
- },
- } satisfies Partial;
-
- const uninstallCreator = {
- uninstall: {
- create: {
- name: "",
- description: "",
- command: metadata.uninstall!,
- args: metadata.uninstallArgs || "",
- },
- },
- } satisfies Partial;
-
return {
gameId: id,
gameVersions: {
@@ -317,7 +317,38 @@ class LibraryManager {
};
}
case "redist":
- return {};
+ return {
+ redistId: id,
+ redistVersions: {
+ create: {
+ versionIndex: currentIndex,
+ delta: metadata.delta,
+
+ launches: {
+ createMany: {
+ data: metadata.launches.map(
+ (v) =>
+ ({
+ name: v.name,
+ description: v.description,
+ command: v.launchCommand,
+ args: v.launchArgs,
+ }) satisfies LaunchOptionCreateManyInput,
+ ),
+ },
+ },
+
+ ...(metadata.install ? installCreator : undefined),
+ ...(metadata.uninstall ? uninstallCreator : undefined),
+
+ platform: {
+ connect: {
+ id: metadata.platform,
+ },
+ },
+ },
+ },
+ };
}
}