mirror of
https://github.com/Drop-OSS/drop.git
synced 2025-11-10 04:22:09 +10:00
feat: partial user platform support + statusMessage -> message
This commit is contained in:
@ -106,7 +106,7 @@ function signin_wrapper() {
|
||||
router.push(route.query.redirect?.toString() ?? "/");
|
||||
})
|
||||
.catch((response) => {
|
||||
const message = response.statusMessage || t("errors.unknown");
|
||||
const message = response.message || t("errors.unknown");
|
||||
error.value = message;
|
||||
})
|
||||
.finally(() => {
|
||||
|
||||
@ -466,7 +466,7 @@ const game = defineModel<ModelType>() as Ref<ModelType>;
|
||||
if (!game.value)
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: "Game not provided to editor component",
|
||||
message: "Game not provided to editor component",
|
||||
});
|
||||
|
||||
const currentTags = ref<{ [key: string]: boolean }>(
|
||||
@ -553,7 +553,7 @@ function coreMetadataUpdate_wrapper() {
|
||||
{
|
||||
title: t("errors.game.metadata.title"),
|
||||
description: t("errors.game.metadata.description", [
|
||||
(e as H3Error)?.statusMessage ?? t("errors.unknown"),
|
||||
(e as H3Error)?.message ?? t("errors.unknown"),
|
||||
]),
|
||||
buttonText: t("common.close"),
|
||||
},
|
||||
@ -614,7 +614,7 @@ watch(descriptionHTML, (_v) => {
|
||||
{
|
||||
title: t("errors.game.description.title"),
|
||||
description: t("errors.game.description.description", [
|
||||
(e as H3Error)?.statusMessage ?? t("errors.unknown"),
|
||||
(e as H3Error)?.message ?? t("errors.unknown"),
|
||||
]),
|
||||
buttonText: t("common.close"),
|
||||
},
|
||||
@ -660,7 +660,7 @@ async function updateBannerImage(id: string) {
|
||||
{
|
||||
title: t("errors.game.banner.title"),
|
||||
description: t("errors.game.banner.description", [
|
||||
(e as H3Error)?.statusMessage ?? t("errors.unknown"),
|
||||
(e as H3Error)?.message ?? t("errors.unknown"),
|
||||
]),
|
||||
buttonText: t("common.close"),
|
||||
},
|
||||
@ -688,7 +688,7 @@ async function updateCoverImage(id: string) {
|
||||
{
|
||||
title: t("errors.game.cover.title"),
|
||||
description: t("errors.game.cover.description", [
|
||||
(e as H3Error)?.statusMessage ?? t("errors.unknown"),
|
||||
(e as H3Error)?.message ?? t("errors.unknown"),
|
||||
]),
|
||||
buttonText: t("common.close"),
|
||||
},
|
||||
@ -717,7 +717,7 @@ async function deleteImage(id: string) {
|
||||
{
|
||||
title: t("errors.game.deleteImage.title"),
|
||||
description: t("errors.game.deleteImage.description", [
|
||||
(e as H3Error)?.statusMessage ?? t("errors.unknown"),
|
||||
(e as H3Error)?.message ?? t("errors.unknown"),
|
||||
]),
|
||||
buttonText: t("common.close"),
|
||||
},
|
||||
@ -761,7 +761,7 @@ async function updateImageCarousel() {
|
||||
{
|
||||
title: t("errors.game.carousel.title"),
|
||||
description: t("errors.game.carousel.description", [
|
||||
(e as H3Error)?.statusMessage ?? t("errors.unknown"),
|
||||
(e as H3Error)?.message ?? t("errors.unknown"),
|
||||
]),
|
||||
buttonText: t("common.close"),
|
||||
},
|
||||
|
||||
@ -71,10 +71,6 @@
|
||||
}}
|
||||
</div>
|
||||
<div class="inline-flex items-center gap-x-2">
|
||||
<component
|
||||
:is="PLATFORM_ICONS[item.platform]"
|
||||
class="size-6 text-blue-600"
|
||||
/>
|
||||
<Bars3Icon
|
||||
class="cursor-move w-6 h-6 text-zinc-400 handle"
|
||||
/>
|
||||
@ -151,7 +147,7 @@ const game = defineModel<SerializeObject<GameAndVersions>>() as Ref<
|
||||
if (!game.value)
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: "Game not provided to editor component",
|
||||
message: "Game not provided to editor component",
|
||||
});
|
||||
|
||||
async function updateVersionOrder() {
|
||||
@ -170,7 +166,7 @@ async function updateVersionOrder() {
|
||||
{
|
||||
title: t("errors.version.order.title"),
|
||||
description: t("errors.version.order.desc", {
|
||||
error: (e as H3Error)?.statusMessage ?? t("errors.unknown"),
|
||||
error: (e as H3Error)?.message ?? t("errors.unknown"),
|
||||
}),
|
||||
buttonText: t("common.close"),
|
||||
},
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
<!-- eslint-disable vue/no-v-html -->
|
||||
<template>
|
||||
<div class="flex flex-row gap-x-4">
|
||||
<div class="relative size-24 bg-zinc-800 rounded-md overflow-hidden">
|
||||
@ -47,6 +48,83 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<SwitchGroup
|
||||
as="div"
|
||||
class="max-w-lg flex items-center justify-between gap-x-4"
|
||||
>
|
||||
<span class="flex flex-grow flex-col">
|
||||
<SwitchLabel
|
||||
as="span"
|
||||
class="text-sm font-medium leading-6 text-zinc-100"
|
||||
passive
|
||||
>Create as platform</SwitchLabel
|
||||
>
|
||||
<SwitchDescription as="span" class="text-sm text-zinc-400"
|
||||
>Versions for this redistributable will be able to take a series of
|
||||
launch commands. Intended to be used with emulators and similar
|
||||
programs.</SwitchDescription
|
||||
>
|
||||
</span>
|
||||
<Switch
|
||||
v-model="isPlatform"
|
||||
:class="[
|
||||
isPlatform ? 'bg-blue-600' : 'bg-zinc-800',
|
||||
'relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-blue-600 focus:ring-offset-2',
|
||||
]"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
:class="[
|
||||
isPlatform ? 'translate-x-5' : 'translate-x-0',
|
||||
'pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out',
|
||||
]"
|
||||
/>
|
||||
</Switch>
|
||||
</SwitchGroup>
|
||||
<div class="relative">
|
||||
<div class="flex flex-row gap-x-4">
|
||||
<div class="relative size-24 bg-zinc-800 rounded-md overflow-hidden">
|
||||
<input
|
||||
id="platform-icon-upload"
|
||||
type="file"
|
||||
class="hidden"
|
||||
accept="image/svg+xml"
|
||||
@change="addSvg"
|
||||
/>
|
||||
<div
|
||||
v-if="platform.icon"
|
||||
class="absolute inset-0 object-cover w-full h-full text-blue-600"
|
||||
v-html="platform.icon"
|
||||
/>
|
||||
<label
|
||||
for="platform-icon-upload"
|
||||
class="absolute inset-0 cursor-pointer flex flex-col gap-y-1 items-center justify-center text-zinc-300 bg-zinc-900/50"
|
||||
>
|
||||
<ArrowUpTrayIcon class="size-6" />
|
||||
<span class="text-xs font-bold font-display uppercase"
|
||||
>Upload SVG</span
|
||||
>
|
||||
</label>
|
||||
</div>
|
||||
<div class="grow flex flex-col gap-y-4">
|
||||
<div>
|
||||
<label
|
||||
for="platform-name"
|
||||
class="block text-sm font-medium text-zinc-100"
|
||||
>Platform Name</label
|
||||
>
|
||||
<input
|
||||
id="platform-name"
|
||||
v-model="platform.name"
|
||||
type="text"
|
||||
class="mt-1 block w-full rounded-md border-0 bg-zinc-950 py-1.5 text-white shadow-sm ring-1 ring-inset ring-zinc-700 placeholder:text-zinc-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 sm:text-sm sm:leading-6"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="!isPlatform" class="absolute inset-0 bg-zinc-950/20" />
|
||||
</div>
|
||||
<div>
|
||||
<LoadingButton
|
||||
class="w-fit"
|
||||
@ -73,6 +151,12 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
Switch,
|
||||
SwitchDescription,
|
||||
SwitchGroup,
|
||||
SwitchLabel,
|
||||
} from "@headlessui/vue";
|
||||
import { ArrowUpTrayIcon } from "@heroicons/vue/24/outline";
|
||||
|
||||
const currentFile = ref<File | undefined>(undefined);
|
||||
@ -81,11 +165,18 @@ const currentFileObjectUrl = ref<string | undefined>(undefined);
|
||||
const emit = defineEmits<{
|
||||
import: [
|
||||
metadata: { name: string; description: string; icon: File } | undefined,
|
||||
platform: typeof platform.value | undefined,
|
||||
];
|
||||
}>();
|
||||
|
||||
const name = ref("");
|
||||
const description = ref("");
|
||||
const isPlatform = ref(false);
|
||||
const platform = ref<{ name: string; icon: string; fileExts: string[] }>({
|
||||
name: "",
|
||||
icon: "",
|
||||
fileExts: [],
|
||||
});
|
||||
|
||||
function addFile(event: Event) {
|
||||
const file = (event.target as HTMLInputElement)?.files?.[0];
|
||||
@ -99,6 +190,32 @@ function addFile(event: Event) {
|
||||
currentFileObjectUrl.value = URL.createObjectURL(file);
|
||||
}
|
||||
|
||||
async function addSvg(event: Event) {
|
||||
const file = (event.target as HTMLInputElement)?.files?.[0];
|
||||
if (!file) return;
|
||||
|
||||
const svgContent = await file.text();
|
||||
const parser = new DOMParser();
|
||||
try {
|
||||
const document = parser.parseFromString(svgContent, "image/svg+xml");
|
||||
const svg = document.getElementsByTagName("svg").item(0);
|
||||
if (!svg) throw "No SVG in uploaded image.";
|
||||
svg.removeAttribute("width");
|
||||
svg.removeAttribute("height");
|
||||
platform.value.icon = svg.outerHTML;
|
||||
} catch (e) {
|
||||
createModal(
|
||||
ModalType.Notification,
|
||||
{
|
||||
title: "Failed to upload SVG",
|
||||
description: (e as string)?.toString() ?? e,
|
||||
},
|
||||
(_, c) => c(),
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
gameName: string;
|
||||
loading: boolean;
|
||||
@ -107,10 +224,14 @@ const props = defineProps<{
|
||||
|
||||
function importRedist() {
|
||||
if (!currentFile.value) return;
|
||||
emit("import", {
|
||||
name: name.value,
|
||||
description: description.value,
|
||||
icon: currentFile.value,
|
||||
});
|
||||
emit(
|
||||
"import",
|
||||
{
|
||||
name: name.value,
|
||||
description: description.value,
|
||||
icon: currentFile.value,
|
||||
},
|
||||
isPlatform.value ? platform.value : undefined,
|
||||
);
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -231,7 +231,7 @@ async function addGame() {
|
||||
emit("created", game, published.value, developed.value);
|
||||
} catch (e) {
|
||||
if (e instanceof FetchError) {
|
||||
addError.value = e.statusMessage ?? e.message ?? t("errors.unknown");
|
||||
addError.value = e.message ?? t("errors.unknown");
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
|
||||
@ -97,13 +97,13 @@ async function createCollection() {
|
||||
} catch (error) {
|
||||
console.error("Failed to create collection:", error);
|
||||
|
||||
const err = error as { statusMessage?: string };
|
||||
const err = error as { message?: string };
|
||||
createModal(
|
||||
ModalType.Notification,
|
||||
{
|
||||
title: t("errors.library.collection.create.title"),
|
||||
description: t("errors.library.collection.create.desc", [
|
||||
err?.statusMessage ?? t("errors.unknown"),
|
||||
err?.message ?? t("errors.unknown"),
|
||||
]),
|
||||
},
|
||||
(_, c) => c(),
|
||||
|
||||
@ -67,8 +67,8 @@ async function deleteCollection() {
|
||||
{
|
||||
title: t("errors.library.add.title"),
|
||||
description: t("errors.library.add.desc", [
|
||||
// @ts-expect-error attempt to display statusMessage on error
|
||||
e?.statusMessage ?? t("errors.unknown"),
|
||||
// @ts-expect-error attempt to display message on error
|
||||
e?.message ?? t("errors.unknown"),
|
||||
]),
|
||||
},
|
||||
(_, c) => c(),
|
||||
|
||||
@ -71,8 +71,8 @@ async function deleteArticle() {
|
||||
{
|
||||
title: t("errors.news.article.delete.title"),
|
||||
description: t("errors.news.article.delete.desc", [
|
||||
// @ts-expect-error attempt to display statusMessage on error
|
||||
e?.statusMessage ?? t("errors.unknown"),
|
||||
// @ts-expect-error attempt to display message on error
|
||||
e?.message ?? t("errors.unknown"),
|
||||
]),
|
||||
},
|
||||
(_, c) => c(),
|
||||
|
||||
@ -62,8 +62,8 @@ async function deleteUser() {
|
||||
{
|
||||
title: t("errors.admin.user.delete.title"),
|
||||
description: t("errors.admin.user.delete.desc", [
|
||||
// @ts-expect-error attempt to display statusMessage on error
|
||||
e?.statusMessage ?? t("errors.unknown"),
|
||||
// @ts-expect-error attempt to display message on error
|
||||
e?.message ?? t("errors.unknown"),
|
||||
]),
|
||||
},
|
||||
(_, c) => c(),
|
||||
|
||||
@ -177,7 +177,7 @@ function uploadFile_wrapper() {
|
||||
uploadLoading.value = true;
|
||||
uploadFile()
|
||||
.catch((error) => {
|
||||
uploadError.value = error.statusMessage ?? t("errors.unknown");
|
||||
uploadError.value = error.message ?? t("errors.unknown");
|
||||
})
|
||||
.finally(() => {
|
||||
uploadLoading.value = false;
|
||||
|
||||
@ -414,8 +414,8 @@ async function createArticle() {
|
||||
|
||||
modalOpen.value = false;
|
||||
} catch (e) {
|
||||
// @ts-expect-error attempt to get statusMessage on error
|
||||
error.value = e?.statusMessage ?? t("errors.unknown");
|
||||
// @ts-expect-error attempt to get message on error
|
||||
error.value = e?.message ?? t("errors.unknown");
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
|
||||
@ -377,6 +377,8 @@ const props = defineProps<{
|
||||
const tags =
|
||||
await $dropFetch<Array<SerializeObject<GameTagModel>>>("/api/v1/store/tags");
|
||||
|
||||
const userPlatforms = await $dropFetch("/api/v1/store/platforms");
|
||||
|
||||
const sorts: Array<StoreSortOption> = [
|
||||
{
|
||||
name: "Default",
|
||||
@ -408,7 +410,10 @@ const options: Array<StoreFilterOption> = [
|
||||
name: "Platform",
|
||||
param: "platform",
|
||||
multiple: true,
|
||||
options: Object.values(Platform).map((e) => ({ name: e, param: e })),
|
||||
options: [
|
||||
...Object.values(Platform).map((e) => ({ name: e, param: e })),
|
||||
...userPlatforms.map((e) => ({ name: e.platformName, param: e.id })),
|
||||
],
|
||||
},
|
||||
...(props.extraOptions ?? []),
|
||||
];
|
||||
|
||||
@ -60,7 +60,7 @@ export const $dropFetch: DropFetch = async (rawRequest, opts) => {
|
||||
{
|
||||
title: opts.failTitle,
|
||||
description:
|
||||
(e as FetchError)?.statusMessage ?? (e as string).toString(),
|
||||
(e as FetchError)?.message ?? (e as string).toString(),
|
||||
//buttonText: $t("common.close"),
|
||||
},
|
||||
(_, c) => c(),
|
||||
|
||||
@ -33,7 +33,7 @@ export class WebSocketHandler {
|
||||
case "unauthenticated": {
|
||||
const error = createError({
|
||||
statusCode: 403,
|
||||
statusMessage: "Unable to connect to websocket - unauthenticated",
|
||||
message: "Unable to connect to websocket - unauthenticated",
|
||||
});
|
||||
if (this.errorHandler) {
|
||||
return this.errorHandler(error);
|
||||
|
||||
Submodule drop-base updated: 4c42edf5ad...8d3c6fb825
@ -40,6 +40,7 @@
|
||||
"fast-fuzzy": "^1.12.0",
|
||||
"file-type-mime": "^0.4.3",
|
||||
"jdenticon": "^3.3.0",
|
||||
"jsdom": "^26.1.0",
|
||||
"luxon": "^3.6.1",
|
||||
"micromark": "^4.0.1",
|
||||
"normalize-url": "^8.0.2",
|
||||
@ -66,6 +67,7 @@
|
||||
"@tailwindcss/forms": "^0.5.9",
|
||||
"@tailwindcss/typography": "^0.5.15",
|
||||
"@types/bcryptjs": "^3.0.0",
|
||||
"@types/jsdom": "^21.1.7",
|
||||
"@types/luxon": "^3.6.2",
|
||||
"@types/node": "^22.13.16",
|
||||
"@types/semver": "^7.7.0",
|
||||
|
||||
@ -180,7 +180,7 @@ if (route.query.payload) {
|
||||
} catch {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Failed to parse the token create payload.",
|
||||
message: "Failed to parse the token create payload.",
|
||||
fatal: true,
|
||||
});
|
||||
}
|
||||
|
||||
@ -727,7 +727,7 @@ function startImport_wrapper() {
|
||||
importLoading.value = true;
|
||||
startImport()
|
||||
.catch((error) => {
|
||||
importError.value = error.statusMessage ?? t("errors.unknown");
|
||||
importError.value = error.message ?? t("errors.unknown");
|
||||
})
|
||||
.finally(() => {
|
||||
importLoading.value = false;
|
||||
|
||||
@ -202,7 +202,7 @@
|
||||
:game-name="games.unimportedGames[currentlySelectedGame].game"
|
||||
:loading="importLoading"
|
||||
:error="importError"
|
||||
@import="(v: unknown) => importModes[currentImportMode].import(v)"
|
||||
@import="(...v: unknown[]) => importModes[currentImportMode].import(...v)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@ -233,7 +233,7 @@ const importModes = shallowRef<{
|
||||
description: string;
|
||||
icon: Component;
|
||||
component: Component;
|
||||
import: (v: unknown) => void;
|
||||
import: (...v: unknown[]) => void;
|
||||
};
|
||||
}>({
|
||||
Game: {
|
||||
@ -249,7 +249,7 @@ const importModes = shallowRef<{
|
||||
"Redistributables are packaged dependencies for games, that are installed alongside and required to play certain games.",
|
||||
icon: ArchiveBoxIcon,
|
||||
component: ImportRedist,
|
||||
import: importRedist as (v: unknown) => void,
|
||||
import: importRedist as (v: unknown, k: unknown) => void,
|
||||
},
|
||||
});
|
||||
|
||||
@ -303,12 +303,12 @@ async function importGame_wrapper(
|
||||
} catch (error) {
|
||||
console.warn(error);
|
||||
importError.value =
|
||||
(error as FetchError)?.statusMessage || t("errors.unknown");
|
||||
(error as FetchError)?.message || t("errors.unknown");
|
||||
}
|
||||
importLoading.value = false;
|
||||
}
|
||||
|
||||
async function importRedist(data: object) {
|
||||
async function importRedist(data: object, platform: object | undefined) {
|
||||
importLoading.value = true;
|
||||
importError.value = undefined;
|
||||
try {
|
||||
@ -316,7 +316,19 @@ async function importRedist(data: object) {
|
||||
|
||||
const formData = new FormData();
|
||||
for (const [key, value] of Object.entries(data)) {
|
||||
formData.append(key, value);
|
||||
formData.append(
|
||||
key,
|
||||
typeof value === "object" ? JSON.stringify(value) : value,
|
||||
);
|
||||
}
|
||||
|
||||
if (platform) {
|
||||
for (const [key, value] of Object.entries(platform)) {
|
||||
formData.append(
|
||||
`platform.${key}`,
|
||||
typeof value === "object" ? JSON.stringify(value) : value,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
formData.append("library", option.library.id);
|
||||
@ -335,7 +347,7 @@ async function importRedist(data: object) {
|
||||
} catch (error) {
|
||||
console.warn(error);
|
||||
importError.value =
|
||||
(error as FetchError)?.statusMessage || t("errors.unknown");
|
||||
(error as FetchError)?.message || t("errors.unknown");
|
||||
}
|
||||
importLoading.value = false;
|
||||
}
|
||||
|
||||
@ -412,7 +412,7 @@ function performActionSource_wrapper() {
|
||||
})
|
||||
.catch((e) => {
|
||||
if (e instanceof FetchError) {
|
||||
modalError.value = e.statusMessage ?? e.message;
|
||||
modalError.value = e.message ?? e.message;
|
||||
} else {
|
||||
modalError.value = e as string;
|
||||
}
|
||||
@ -449,8 +449,8 @@ async function deleteSource(index: number) {
|
||||
{
|
||||
title: t("errors.library.source.delete.title"),
|
||||
description: t("errors.library.source.delete.desc", [
|
||||
// @ts-expect-error attempt to display statusMessage on error
|
||||
e?.statusMessage ?? t("errors.unknown"),
|
||||
// @ts-expect-error attempt to display message on error
|
||||
e?.message ?? t("errors.unknown"),
|
||||
]),
|
||||
},
|
||||
(_, c) => c(),
|
||||
|
||||
@ -96,7 +96,7 @@ async function saveSettings() {
|
||||
title: `Failed to save settings.`,
|
||||
description:
|
||||
e instanceof FetchError
|
||||
? (e.statusMessage ?? e.message)
|
||||
? (e.message)
|
||||
: (e as string).toString(),
|
||||
},
|
||||
(_, c) => c(),
|
||||
|
||||
@ -184,7 +184,7 @@ if (route.query.payload) {
|
||||
} catch {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Failed to parse the token create payload.",
|
||||
message: "Failed to parse the token create payload.",
|
||||
fatal: true,
|
||||
});
|
||||
}
|
||||
|
||||
@ -502,7 +502,7 @@ function invite_wrapper() {
|
||||
invitations.value.push(invitation);
|
||||
})
|
||||
.catch((response) => {
|
||||
const message = response.statusMessage || t("errors.unknown");
|
||||
const message = response.message || t("errors.unknown");
|
||||
error.value = message;
|
||||
})
|
||||
.finally(() => {
|
||||
|
||||
@ -203,7 +203,7 @@ const invitationId = route.query.id?.toString();
|
||||
if (!invitationId)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: t("errors.inviteRequired"),
|
||||
message: t("errors.inviteRequired"),
|
||||
});
|
||||
|
||||
const invitation = await $dropFetch(
|
||||
@ -271,7 +271,7 @@ function register_wrapper() {
|
||||
router.push("/auth/signin");
|
||||
})
|
||||
.catch((response) => {
|
||||
const message = response.statusMessage || t("errors.unknown");
|
||||
const message = response.message || t("errors.unknown");
|
||||
error.value = message;
|
||||
})
|
||||
.finally(() => {
|
||||
|
||||
@ -192,7 +192,7 @@ async function authorize() {
|
||||
}
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: "Unknown client auth mode: " + clientData.mode,
|
||||
message: "Unknown client auth mode: " + clientData.mode,
|
||||
fatal: true,
|
||||
});
|
||||
}
|
||||
@ -202,7 +202,7 @@ async function authorize_wrapper() {
|
||||
await authorize();
|
||||
} catch (e) {
|
||||
const errorMessage =
|
||||
(e as FetchError)?.statusMessage || "An unknown error occurred.";
|
||||
(e as FetchError)?.message || "An unknown error occurred.";
|
||||
error.value = errorMessage;
|
||||
} finally {
|
||||
completed.value = true;
|
||||
|
||||
@ -125,7 +125,7 @@ async function complete(code: string) {
|
||||
} catch (e) {
|
||||
if (e instanceof FetchError) {
|
||||
error.value =
|
||||
e.statusMessage ?? e.message ?? "An unknown error occurred.";
|
||||
e.message ?? "An unknown error occurred.";
|
||||
} else {
|
||||
error.value = (e as string)?.toString();
|
||||
}
|
||||
|
||||
@ -44,7 +44,8 @@ const collection = computed(() =>
|
||||
if (collection.value === undefined) {
|
||||
throw createError({
|
||||
statusCode: 404,
|
||||
statusMessage: t("library.collection.notFound"),
|
||||
message: t("library.collection.notFound"),
|
||||
fatal: true,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -99,7 +99,7 @@ const article = computed(() =>
|
||||
if (!article.value)
|
||||
throw createError({
|
||||
statusCode: 404,
|
||||
statusMessage: t("news.notFound"),
|
||||
message: t("news.notFound"),
|
||||
fatal: true,
|
||||
});
|
||||
|
||||
|
||||
@ -159,7 +159,7 @@ const token = route.query.token;
|
||||
if (!token)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "No token.",
|
||||
message: "No token.",
|
||||
fatal: true,
|
||||
});
|
||||
const bearerToken = `Bearer ${token}`;
|
||||
@ -170,7 +170,7 @@ const allowed = await $dropFetch("/api/v1/admin", {
|
||||
if (!allowed)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Invalid setup token. Please check the URL you opened.",
|
||||
message: "Invalid setup token. Please check the URL you opened.",
|
||||
fatal: true,
|
||||
});
|
||||
|
||||
|
||||
@ -73,15 +73,21 @@
|
||||
<td
|
||||
class="whitespace-nowrap inline-flex gap-x-4 px-3 py-4 text-sm text-zinc-400"
|
||||
>
|
||||
<component
|
||||
:is="PLATFORM_ICONS[platform]"
|
||||
<div
|
||||
v-for="platform in platforms"
|
||||
:key="platform"
|
||||
class="text-blue-600 w-6 h-6"
|
||||
/>
|
||||
:key="typeof platform === 'string' ? platform : platform.id"
|
||||
>
|
||||
<component
|
||||
:is="PLATFORM_ICONS[platform]"
|
||||
v-if="typeof platform === 'string'"
|
||||
class="text-blue-600 w-6 h-6"
|
||||
/>
|
||||
<div v-else class="text-blue-600 w-6 h-6" v-html="platform.iconSvg" />
|
||||
</div>
|
||||
|
||||
<span
|
||||
v-if="platforms.length == 0"
|
||||
class="font-semibold text-blue-600"
|
||||
class="font-display uppercase font-bold text-zinc-700"
|
||||
>{{ $t("store.commingSoon") }}</span
|
||||
>
|
||||
</td>
|
||||
@ -278,8 +284,9 @@ const descriptionHTML = micromark(game.mDescription);
|
||||
|
||||
const showReadMore = previewHTML != descriptionHTML;
|
||||
const platforms = game.versions
|
||||
.map((e) => e.platform)
|
||||
.map((e) => e.platform ?? e.userPlatform)
|
||||
.flat()
|
||||
.filter((e) => e !== null)
|
||||
.filter((e, i, u) => u.indexOf(e) === i);
|
||||
|
||||
// const rating = Math.round(game.mReviewRating * 5);
|
||||
|
||||
@ -1,35 +0,0 @@
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "public"."Version" DROP CONSTRAINT "addon_link";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "public"."Version" DROP CONSTRAINT "game_link";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "public"."Version" DROP CONSTRAINT "mod_link";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "public"."Version" DROP CONSTRAINT "redist_link";
|
||||
|
||||
-- DropIndex
|
||||
DROP INDEX "public"."GameTag_name_idx";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "public"."GameVersion" ADD COLUMN "setupArgs" TEXT NOT NULL DEFAULT '';
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "public"."GameVersionLaunch" ADD COLUMN "launchArgs" TEXT NOT NULL DEFAULT '';
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "GameTag_name_idx" ON "public"."GameTag" USING GIST ("name" gist_trgm_ops(siglen=32));
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."Version" ADD CONSTRAINT "game_link" FOREIGN KEY ("rootId") REFERENCES "public"."Game"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."Version" ADD CONSTRAINT "redist_link" FOREIGN KEY ("rootId") REFERENCES "public"."Redist"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."Version" ADD CONSTRAINT "addon_link" FOREIGN KEY ("rootId") REFERENCES "public"."Addon"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."Version" ADD CONSTRAINT "mod_link" FOREIGN KEY ("rootId") REFERENCES "public"."Mod"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@ -1,42 +0,0 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `rootId` on the `Version` table. All the data in the column will be lost.
|
||||
|
||||
*/
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "public"."Version" DROP CONSTRAINT "addon_link";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "public"."Version" DROP CONSTRAINT "game_link";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "public"."Version" DROP CONSTRAINT "mod_link";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "public"."Version" DROP CONSTRAINT "redist_link";
|
||||
|
||||
-- DropIndex
|
||||
DROP INDEX "public"."GameTag_name_idx";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "public"."Version" DROP COLUMN "rootId",
|
||||
ADD COLUMN "addonId" TEXT,
|
||||
ADD COLUMN "gameId" TEXT,
|
||||
ADD COLUMN "modId" TEXT,
|
||||
ADD COLUMN "redistId" TEXT;
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "GameTag_name_idx" ON "public"."GameTag" USING GIST ("name" gist_trgm_ops(siglen=32));
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."Version" ADD CONSTRAINT "game_link" FOREIGN KEY ("gameId") REFERENCES "public"."Game"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."Version" ADD CONSTRAINT "redist_link" FOREIGN KEY ("redistId") REFERENCES "public"."Redist"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."Version" ADD CONSTRAINT "addon_link" FOREIGN KEY ("addonId") REFERENCES "public"."Addon"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."Version" ADD CONSTRAINT "mod_link" FOREIGN KEY ("modId") REFERENCES "public"."Mod"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@ -1,35 +0,0 @@
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "public"."AddonVersion" DROP CONSTRAINT "AddonVersion_versionId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "public"."GameVersion" DROP CONSTRAINT "GameVersion_versionId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "public"."GameVersionLaunch" DROP CONSTRAINT "GameVersionLaunch_versionId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "public"."ModVersion" DROP CONSTRAINT "ModVersion_versionId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "public"."RedistVersion" DROP CONSTRAINT "RedistVersion_versionId_fkey";
|
||||
|
||||
-- DropIndex
|
||||
DROP INDEX "public"."GameTag_name_idx";
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "GameTag_name_idx" ON "public"."GameTag" USING GIST ("name" gist_trgm_ops(siglen=32));
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."GameVersion" ADD CONSTRAINT "GameVersion_versionId_fkey" FOREIGN KEY ("versionId") REFERENCES "public"."Version"("versionId") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."GameVersionLaunch" ADD CONSTRAINT "GameVersionLaunch_versionId_fkey" FOREIGN KEY ("versionId") REFERENCES "public"."GameVersion"("versionId") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."AddonVersion" ADD CONSTRAINT "AddonVersion_versionId_fkey" FOREIGN KEY ("versionId") REFERENCES "public"."Version"("versionId") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."RedistVersion" ADD CONSTRAINT "RedistVersion_versionId_fkey" FOREIGN KEY ("versionId") REFERENCES "public"."Version"("versionId") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."ModVersion" ADD CONSTRAINT "ModVersion_versionId_fkey" FOREIGN KEY ("versionId") REFERENCES "public"."Version"("versionId") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@ -1,8 +0,0 @@
|
||||
-- DropIndex
|
||||
DROP INDEX "public"."GameTag_name_idx";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "public"."Library" ADD COLUMN "mode" "public"."LibraryMode" NOT NULL DEFAULT 'Game';
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "GameTag_name_idx" ON "public"."GameTag" USING GIST ("name" gist_trgm_ops(siglen=32));
|
||||
@ -1,99 +0,0 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- The values [Addon] on the enum `LibraryMode` will be removed. If these variants are still used in the database, this will fail.
|
||||
- You are about to drop the column `addonId` on the `Version` table. All the data in the column will be lost.
|
||||
- You are about to drop the `Addon` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `AddonVersion` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `_AddonVersionToRedistVersion` table. If the table is not empty, all the data it contains will be lost.
|
||||
|
||||
*/
|
||||
-- AlterEnum
|
||||
BEGIN;
|
||||
CREATE TYPE "public"."LibraryMode_new" AS ENUM ('Game', 'Redist', 'DLC', 'Mod');
|
||||
ALTER TABLE "public"."Library" ALTER COLUMN "mode" DROP DEFAULT;
|
||||
ALTER TABLE "public"."Library" ALTER COLUMN "mode" TYPE "public"."LibraryMode_new" USING ("mode"::text::"public"."LibraryMode_new");
|
||||
ALTER TYPE "public"."LibraryMode" RENAME TO "LibraryMode_old";
|
||||
ALTER TYPE "public"."LibraryMode_new" RENAME TO "LibraryMode";
|
||||
DROP TYPE "public"."LibraryMode_old";
|
||||
ALTER TABLE "public"."Library" ALTER COLUMN "mode" SET DEFAULT 'Game';
|
||||
COMMIT;
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "public"."Addon" DROP CONSTRAINT "Addon_libraryId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "public"."AddonVersion" DROP CONSTRAINT "AddonVersion_versionId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "public"."Version" DROP CONSTRAINT "addon_link";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "public"."_AddonVersionToRedistVersion" DROP CONSTRAINT "_AddonVersionToRedistVersion_A_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "public"."_AddonVersionToRedistVersion" DROP CONSTRAINT "_AddonVersionToRedistVersion_B_fkey";
|
||||
|
||||
-- DropIndex
|
||||
DROP INDEX "public"."GameTag_name_idx";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "public"."Version" DROP COLUMN "addonId",
|
||||
ADD COLUMN "dlcId" TEXT;
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "public"."Addon";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "public"."AddonVersion";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "public"."_AddonVersionToRedistVersion";
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "public"."DLCVersion" (
|
||||
"versionId" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "DLCVersion_pkey" PRIMARY KEY ("versionId")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "public"."DLC" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"description" TEXT NOT NULL,
|
||||
"iconObjectId" TEXT NOT NULL,
|
||||
"libraryId" TEXT NOT NULL,
|
||||
"libraryPath" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "DLC_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "public"."_DLCVersionToRedistVersion" (
|
||||
"A" TEXT NOT NULL,
|
||||
"B" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "_DLCVersionToRedistVersion_AB_pkey" PRIMARY KEY ("A","B")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "_DLCVersionToRedistVersion_B_index" ON "public"."_DLCVersionToRedistVersion"("B");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "GameTag_name_idx" ON "public"."GameTag" USING GIST ("name" gist_trgm_ops(siglen=32));
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."Version" ADD CONSTRAINT "dlc_link" FOREIGN KEY ("dlcId") REFERENCES "public"."DLC"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."DLCVersion" ADD CONSTRAINT "DLCVersion_versionId_fkey" FOREIGN KEY ("versionId") REFERENCES "public"."Version"("versionId") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."DLC" ADD CONSTRAINT "DLC_libraryId_fkey" FOREIGN KEY ("libraryId") REFERENCES "public"."Library"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."_DLCVersionToRedistVersion" ADD CONSTRAINT "_DLCVersionToRedistVersion_A_fkey" FOREIGN KEY ("A") REFERENCES "public"."DLCVersion"("versionId") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."_DLCVersionToRedistVersion" ADD CONSTRAINT "_DLCVersionToRedistVersion_B_fkey" FOREIGN KEY ("B") REFERENCES "public"."RedistVersion"("versionId") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@ -1,8 +0,0 @@
|
||||
-- DropIndex
|
||||
DROP INDEX "GameTag_name_idx";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "APIToken" ADD COLUMN "expiresAt" TIMESTAMP(3);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "GameTag_name_idx" ON "GameTag" USING GIST ("name" gist_trgm_ops(siglen=32));
|
||||
@ -1,5 +0,0 @@
|
||||
-- DropIndex
|
||||
DROP INDEX "GameTag_name_idx";
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "GameTag_name_idx" ON "GameTag" USING GIST ("name" gist_trgm_ops(siglen=32));
|
||||
@ -1,4 +1,4 @@
|
||||
-- Add pg_trgm
|
||||
-- enable pg_trgm
|
||||
CREATE EXTENSION pg_trgm;
|
||||
|
||||
-- CreateEnum
|
||||
@ -8,7 +8,7 @@ CREATE TYPE "public"."Platform" AS ENUM ('windows', 'linux', 'macos');
|
||||
CREATE TYPE "public"."LibraryBackend" AS ENUM ('Filesystem', 'FlatFilesystem');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "public"."LibraryMode" AS ENUM ('Game', 'Redist', 'Addon', 'Mod');
|
||||
CREATE TYPE "public"."LibraryMode" AS ENUM ('Game', 'Redist', 'DLC', 'Mod');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "public"."AuthMec" AS ENUM ('Simple', 'OpenID');
|
||||
@ -40,6 +40,7 @@ CREATE TABLE "public"."Library" (
|
||||
"name" TEXT NOT NULL,
|
||||
"backend" "public"."LibraryBackend" NOT NULL,
|
||||
"options" JSONB NOT NULL,
|
||||
"mode" "public"."LibraryMode" NOT NULL DEFAULT 'Game',
|
||||
|
||||
CONSTRAINT "Library_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
@ -75,6 +76,7 @@ CREATE TABLE "public"."APIToken" (
|
||||
"userId" TEXT,
|
||||
"clientId" TEXT,
|
||||
"acls" TEXT[],
|
||||
"expiresAt" TIMESTAMP(3),
|
||||
|
||||
CONSTRAINT "APIToken_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
@ -129,14 +131,28 @@ CREATE TABLE "public"."CollectionEntry" (
|
||||
CONSTRAINT "CollectionEntry_pkey" PRIMARY KEY ("collectionId","gameId")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "public"."UserPlatform" (
|
||||
"id" TEXT NOT NULL,
|
||||
"redistId" TEXT,
|
||||
"platformName" TEXT NOT NULL,
|
||||
"iconSvg" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "UserPlatform_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "public"."Version" (
|
||||
"versionId" TEXT NOT NULL,
|
||||
"rootId" TEXT NOT NULL,
|
||||
"versionPath" TEXT NOT NULL,
|
||||
"versionName" TEXT NOT NULL,
|
||||
"created" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"platform" "public"."Platform" NOT NULL,
|
||||
"gameId" TEXT,
|
||||
"redistId" TEXT,
|
||||
"dlcId" TEXT,
|
||||
"modId" TEXT,
|
||||
"platform" "public"."Platform",
|
||||
"userPlatformRedistId" TEXT,
|
||||
"dropletManifest" JSONB NOT NULL,
|
||||
|
||||
CONSTRAINT "Version_pkey" PRIMARY KEY ("versionId")
|
||||
@ -145,31 +161,34 @@ CREATE TABLE "public"."Version" (
|
||||
-- CreateTable
|
||||
CREATE TABLE "public"."GameVersion" (
|
||||
"versionId" TEXT NOT NULL,
|
||||
"setup" TEXT NOT NULL DEFAULT '',
|
||||
"setupCommand" TEXT NOT NULL DEFAULT '',
|
||||
"setupArgs" TEXT NOT NULL DEFAULT '',
|
||||
"onlySetup" BOOLEAN NOT NULL DEFAULT false,
|
||||
"umuIdOverride" TEXT,
|
||||
"versionIndex" INTEGER NOT NULL,
|
||||
"delta" BOOLEAN NOT NULL DEFAULT false,
|
||||
"hidden" BOOLEAN NOT NULL DEFAULT false,
|
||||
|
||||
CONSTRAINT "GameVersion_pkey" PRIMARY KEY ("versionId")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "public"."GameVersionLaunch" (
|
||||
CREATE TABLE "public"."LaunchOption" (
|
||||
"launchId" TEXT NOT NULL,
|
||||
"versionId" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"description" TEXT NOT NULL,
|
||||
"launchCommand" TEXT NOT NULL,
|
||||
"launchArgs" TEXT NOT NULL DEFAULT '',
|
||||
|
||||
CONSTRAINT "GameVersionLaunch_pkey" PRIMARY KEY ("launchId")
|
||||
CONSTRAINT "LaunchOption_pkey" PRIMARY KEY ("launchId")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "public"."AddonVersion" (
|
||||
CREATE TABLE "public"."DLCVersion" (
|
||||
"versionId" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "AddonVersion_pkey" PRIMARY KEY ("versionId")
|
||||
CONSTRAINT "DLCVersion_pkey" PRIMARY KEY ("versionId")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
@ -255,7 +274,7 @@ CREATE TABLE "public"."Game" (
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "public"."Addon" (
|
||||
CREATE TABLE "public"."DLC" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"description" TEXT NOT NULL,
|
||||
@ -263,7 +282,7 @@ CREATE TABLE "public"."Addon" (
|
||||
"libraryId" TEXT NOT NULL,
|
||||
"libraryPath" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "Addon_pkey" PRIMARY KEY ("id")
|
||||
CONSTRAINT "DLC_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
@ -411,11 +430,11 @@ CREATE TABLE "public"."_GameVersionToRedistVersion" (
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "public"."_AddonVersionToRedistVersion" (
|
||||
CREATE TABLE "public"."_DLCVersionToRedistVersion" (
|
||||
"A" TEXT NOT NULL,
|
||||
"B" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "_AddonVersionToRedistVersion_AB_pkey" PRIMARY KEY ("A","B")
|
||||
CONSTRAINT "_DLCVersionToRedistVersion_AB_pkey" PRIMARY KEY ("A","B")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
@ -464,6 +483,9 @@ CREATE UNIQUE INDEX "APIToken_token_key" ON "public"."APIToken"("token");
|
||||
-- CreateIndex
|
||||
CREATE INDEX "APIToken_token_idx" ON "public"."APIToken"("token");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "UserPlatform_redistId_key" ON "public"."UserPlatform"("redistId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Version_versionId_key" ON "public"."Version"("versionId");
|
||||
|
||||
@ -510,7 +532,7 @@ CREATE UNIQUE INDEX "Notification_userId_nonce_key" ON "public"."Notification"("
|
||||
CREATE INDEX "_GameVersionToRedistVersion_B_index" ON "public"."_GameVersionToRedistVersion"("B");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "_AddonVersionToRedistVersion_B_index" ON "public"."_AddonVersionToRedistVersion"("B");
|
||||
CREATE INDEX "_DLCVersionToRedistVersion_B_index" ON "public"."_DLCVersionToRedistVersion"("B");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "_GameToGameTag_B_index" ON "public"."_GameToGameTag"("B");
|
||||
@ -552,31 +574,40 @@ ALTER TABLE "public"."CollectionEntry" ADD CONSTRAINT "CollectionEntry_collectio
|
||||
ALTER TABLE "public"."CollectionEntry" ADD CONSTRAINT "CollectionEntry_gameId_fkey" FOREIGN KEY ("gameId") REFERENCES "public"."Game"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."Version" ADD CONSTRAINT "game_link" FOREIGN KEY ("rootId") REFERENCES "public"."Game"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE "public"."UserPlatform" ADD CONSTRAINT "UserPlatform_redistId_fkey" FOREIGN KEY ("redistId") REFERENCES "public"."Redist"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."Version" ADD CONSTRAINT "redist_link" FOREIGN KEY ("rootId") REFERENCES "public"."Redist"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE "public"."Version" ADD CONSTRAINT "game_link" FOREIGN KEY ("gameId") REFERENCES "public"."Game"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."Version" ADD CONSTRAINT "addon_link" FOREIGN KEY ("rootId") REFERENCES "public"."Addon"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE "public"."Version" ADD CONSTRAINT "redist_link" FOREIGN KEY ("redistId") REFERENCES "public"."Redist"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."Version" ADD CONSTRAINT "mod_link" FOREIGN KEY ("rootId") REFERENCES "public"."Mod"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE "public"."Version" ADD CONSTRAINT "dlc_link" FOREIGN KEY ("dlcId") REFERENCES "public"."DLC"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."GameVersion" ADD CONSTRAINT "GameVersion_versionId_fkey" FOREIGN KEY ("versionId") REFERENCES "public"."Version"("versionId") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE "public"."Version" ADD CONSTRAINT "mod_link" FOREIGN KEY ("modId") REFERENCES "public"."Mod"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."GameVersionLaunch" ADD CONSTRAINT "GameVersionLaunch_versionId_fkey" FOREIGN KEY ("versionId") REFERENCES "public"."GameVersion"("versionId") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE "public"."Version" ADD CONSTRAINT "Version_userPlatformRedistId_fkey" FOREIGN KEY ("userPlatformRedistId") REFERENCES "public"."UserPlatform"("redistId") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."AddonVersion" ADD CONSTRAINT "AddonVersion_versionId_fkey" FOREIGN KEY ("versionId") REFERENCES "public"."Version"("versionId") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE "public"."GameVersion" ADD CONSTRAINT "GameVersion_versionId_fkey" FOREIGN KEY ("versionId") REFERENCES "public"."Version"("versionId") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."RedistVersion" ADD CONSTRAINT "RedistVersion_versionId_fkey" FOREIGN KEY ("versionId") REFERENCES "public"."Version"("versionId") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE "public"."LaunchOption" ADD CONSTRAINT "gameVersion_fkey" FOREIGN KEY ("versionId") REFERENCES "public"."GameVersion"("versionId") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."ModVersion" ADD CONSTRAINT "ModVersion_versionId_fkey" FOREIGN KEY ("versionId") REFERENCES "public"."Version"("versionId") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE "public"."LaunchOption" ADD CONSTRAINT "redistVersion_fkey" FOREIGN KEY ("versionId") REFERENCES "public"."RedistVersion"("versionId") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."DLCVersion" ADD CONSTRAINT "DLCVersion_versionId_fkey" FOREIGN KEY ("versionId") REFERENCES "public"."Version"("versionId") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."RedistVersion" ADD CONSTRAINT "RedistVersion_versionId_fkey" FOREIGN KEY ("versionId") REFERENCES "public"."Version"("versionId") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."ModVersion" ADD CONSTRAINT "ModVersion_versionId_fkey" FOREIGN KEY ("versionId") REFERENCES "public"."Version"("versionId") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."SaveSlot" ADD CONSTRAINT "SaveSlot_gameId_fkey" FOREIGN KEY ("gameId") REFERENCES "public"."Game"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@ -603,7 +634,7 @@ ALTER TABLE "public"."Playtime" ADD CONSTRAINT "Playtime_userId_fkey" FOREIGN KE
|
||||
ALTER TABLE "public"."Game" ADD CONSTRAINT "Game_libraryId_fkey" FOREIGN KEY ("libraryId") REFERENCES "public"."Library"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."Addon" ADD CONSTRAINT "Addon_libraryId_fkey" FOREIGN KEY ("libraryId") REFERENCES "public"."Library"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
ALTER TABLE "public"."DLC" ADD CONSTRAINT "DLC_libraryId_fkey" FOREIGN KEY ("libraryId") REFERENCES "public"."Library"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."Redist" ADD CONSTRAINT "Redist_libraryId_fkey" FOREIGN KEY ("libraryId") REFERENCES "public"."Library"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@ -630,10 +661,10 @@ ALTER TABLE "public"."_GameVersionToRedistVersion" ADD CONSTRAINT "_GameVersionT
|
||||
ALTER TABLE "public"."_GameVersionToRedistVersion" ADD CONSTRAINT "_GameVersionToRedistVersion_B_fkey" FOREIGN KEY ("B") REFERENCES "public"."RedistVersion"("versionId") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."_AddonVersionToRedistVersion" ADD CONSTRAINT "_AddonVersionToRedistVersion_A_fkey" FOREIGN KEY ("A") REFERENCES "public"."AddonVersion"("versionId") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
ALTER TABLE "public"."_DLCVersionToRedistVersion" ADD CONSTRAINT "_DLCVersionToRedistVersion_A_fkey" FOREIGN KEY ("A") REFERENCES "public"."DLCVersion"("versionId") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."_AddonVersionToRedistVersion" ADD CONSTRAINT "_AddonVersionToRedistVersion_B_fkey" FOREIGN KEY ("B") REFERENCES "public"."RedistVersion"("versionId") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
ALTER TABLE "public"."_DLCVersionToRedistVersion" ADD CONSTRAINT "_DLCVersionToRedistVersion_B_fkey" FOREIGN KEY ("B") REFERENCES "public"."RedistVersion"("versionId") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."_GameToGameTag" ADD CONSTRAINT "_GameToGameTag_A_fkey" FOREIGN KEY ("A") REFERENCES "public"."Game"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@ -2,7 +2,7 @@
|
||||
DROP INDEX "public"."GameTag_name_idx";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "public"."GameVersion" ADD COLUMN "hidden" BOOLEAN NOT NULL DEFAULT false;
|
||||
ALTER TABLE "public"."UserPlatform" ADD COLUMN "fileExtensions" TEXT[] DEFAULT ARRAY[]::TEXT[];
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "GameTag_name_idx" ON "public"."GameTag" USING GIST ("name" gist_trgm_ops(siglen=32));
|
||||
@ -1,3 +1,16 @@
|
||||
model UserPlatform {
|
||||
id String @id @default(uuid())
|
||||
|
||||
redistId String? @unique
|
||||
redist Redist? @relation(fields: [redistId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
||||
|
||||
platformName String
|
||||
iconSvg String
|
||||
fileExtensions String[] @default([])
|
||||
|
||||
versions Version[]
|
||||
}
|
||||
|
||||
model Version {
|
||||
versionId String @id @unique @default(uuid())
|
||||
|
||||
@ -22,7 +35,11 @@ model Version {
|
||||
mod Mod? @relation(fields: [modId], references: [id], map: "mod_link", onDelete: Cascade, onUpdate: Cascade)
|
||||
modVersion ModVersion?
|
||||
|
||||
platform Platform
|
||||
platform Platform?
|
||||
|
||||
userPlatformRedistId String?
|
||||
userPlatform UserPlatform? @relation(fields: [userPlatformRedistId], references: [redistId])
|
||||
|
||||
dropletManifest Json // Results from droplet
|
||||
}
|
||||
|
||||
@ -32,11 +49,11 @@ model GameVersion {
|
||||
|
||||
redistDeps RedistVersion[]
|
||||
|
||||
launches GameVersionLaunch[]
|
||||
launches LaunchOption[]
|
||||
|
||||
setup String @default("") // Command to setup game (dependencies and such)
|
||||
setupArgs String @default("")
|
||||
onlySetup Boolean @default(false)
|
||||
setupCommand String @default("")
|
||||
setupArgs String @default("")
|
||||
onlySetup Boolean @default(false)
|
||||
|
||||
umuIdOverride String?
|
||||
|
||||
@ -45,11 +62,12 @@ model GameVersion {
|
||||
hidden Boolean @default(false)
|
||||
}
|
||||
|
||||
model GameVersionLaunch {
|
||||
model LaunchOption {
|
||||
launchId String @id @default(uuid())
|
||||
versionId String
|
||||
|
||||
gameVersion GameVersion @relation(fields: [versionId], references: [versionId], onDelete: Cascade, onUpdate: Cascade)
|
||||
gameVersion GameVersion? @relation(fields: [versionId], references: [versionId], onDelete: Cascade, onUpdate: Cascade, map: "gameVersion_fkey")
|
||||
redistVersion RedistVersion? @relation(fields: [versionId], references: [versionId], onDelete: Cascade, onUpdate: Cascade, map: "redistVersion_fkey")
|
||||
|
||||
name String
|
||||
description String
|
||||
@ -69,8 +87,10 @@ model RedistVersion {
|
||||
versionId String @id
|
||||
version Version @relation(fields: [versionId], references: [versionId], onDelete: Cascade, onUpdate: Cascade)
|
||||
|
||||
gameDependees GameVersion[]
|
||||
dlcDependees DLCVersion[]
|
||||
launches LaunchOption[]
|
||||
|
||||
gameDependees GameVersion[]
|
||||
dlcDependees DLCVersion[]
|
||||
}
|
||||
|
||||
model ModVersion {
|
||||
|
||||
@ -79,7 +79,8 @@ 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")
|
||||
}
|
||||
|
||||
@ -15,13 +15,13 @@ export default defineEventHandler(async (h3) => {
|
||||
});
|
||||
|
||||
if (!company)
|
||||
throw createError({ statusCode: 400, statusMessage: "Invalid company id" });
|
||||
throw createError({ statusCode: 400, message: "Invalid company id" });
|
||||
|
||||
const result = await handleFileUpload(h3, {}, ["internal:read"], 1);
|
||||
if (!result)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "File upload required (multipart form)",
|
||||
message: "File upload required (multipart form)",
|
||||
});
|
||||
|
||||
const [ids, , pull, dump] = result;
|
||||
@ -29,7 +29,7 @@ export default defineEventHandler(async (h3) => {
|
||||
if (!id)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Upload at least one file.",
|
||||
message: "Upload at least one file.",
|
||||
});
|
||||
|
||||
try {
|
||||
|
||||
@ -20,7 +20,7 @@ export default defineEventHandler(async (h3) => {
|
||||
if (!body.published && !body.developed)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Must be related (either developed or published).",
|
||||
message: "Must be related (either developed or published).",
|
||||
});
|
||||
|
||||
const publisherConnect = body.published
|
||||
|
||||
@ -15,13 +15,13 @@ export default defineEventHandler(async (h3) => {
|
||||
});
|
||||
|
||||
if (!company)
|
||||
throw createError({ statusCode: 400, statusMessage: "Invalid company id" });
|
||||
throw createError({ statusCode: 400, message: "Invalid company id" });
|
||||
|
||||
const result = await handleFileUpload(h3, {}, ["internal:read"], 1);
|
||||
if (!result)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "File upload required (multipart form)",
|
||||
message: "File upload required (multipart form)",
|
||||
});
|
||||
|
||||
const [ids, , pull, dump] = result;
|
||||
@ -29,7 +29,7 @@ export default defineEventHandler(async (h3) => {
|
||||
if (!id)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Upload at least one file.",
|
||||
message: "Upload at least one file.",
|
||||
});
|
||||
|
||||
try {
|
||||
|
||||
@ -9,6 +9,6 @@ export default defineEventHandler(async (h3) => {
|
||||
|
||||
const company = await prisma.company.deleteMany({ where: { id } });
|
||||
if (company.count == 0)
|
||||
throw createError({ statusCode: 404, statusMessage: "Company not found" });
|
||||
throw createError({ statusCode: 404, message: "Company not found" });
|
||||
return;
|
||||
});
|
||||
|
||||
@ -23,7 +23,7 @@ export default defineEventHandler(async (h3) => {
|
||||
},
|
||||
});
|
||||
if (!company)
|
||||
throw createError({ statusCode: 404, statusMessage: "Company not found" });
|
||||
throw createError({ statusCode: 404, message: "Company not found" });
|
||||
const games = await prisma.game.findMany({
|
||||
where: {
|
||||
OR: [
|
||||
|
||||
@ -33,7 +33,7 @@ export default defineEventHandler(async (h3) => {
|
||||
});
|
||||
|
||||
if (!game || !game.libraryId)
|
||||
throw createError({ statusCode: 404, statusMessage: "Game ID not found" });
|
||||
throw createError({ statusCode: 404, message: "Game ID not found" });
|
||||
|
||||
const unimportedVersions = await libraryManager.fetchUnimportedGameVersions(
|
||||
game.libraryId,
|
||||
|
||||
@ -1,8 +1,14 @@
|
||||
import { ArkErrors, type } from "arktype";
|
||||
import type { Prisma } from "~/prisma/client/client";
|
||||
import aclManager from "~/server/internal/acls";
|
||||
import prisma from "~/server/internal/db/database";
|
||||
import { handleFileUpload } from "~/server/internal/utils/handlefileupload";
|
||||
|
||||
const UpdateMetadata = type({
|
||||
name: "string?",
|
||||
description: "string?",
|
||||
});
|
||||
|
||||
export default defineEventHandler(async (h3) => {
|
||||
const allowed = await aclManager.allowSystemACL(h3, ["game:update"]);
|
||||
if (!allowed) throw createError({ statusCode: 403 });
|
||||
@ -11,7 +17,7 @@ export default defineEventHandler(async (h3) => {
|
||||
if (!form)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "This endpoint requires multipart form data.",
|
||||
message: "This endpoint requires multipart form data.",
|
||||
});
|
||||
|
||||
const gameId = getRouterParam(h3, "id")!;
|
||||
@ -20,20 +26,20 @@ export default defineEventHandler(async (h3) => {
|
||||
if (!uploadResult)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Failed to upload file",
|
||||
message: "Failed to upload file",
|
||||
});
|
||||
|
||||
const [ids, options, pull, dump] = uploadResult;
|
||||
|
||||
const id = ids.at(0);
|
||||
|
||||
// handleFileUpload reads the rest of the options for us.
|
||||
const name = options.name;
|
||||
const description = options.description;
|
||||
const body = UpdateMetadata(options);
|
||||
if (body instanceof ArkErrors)
|
||||
throw createError({ statusCode: 400, message: body.summary });
|
||||
|
||||
const updateModel: Prisma.GameUpdateInput = {
|
||||
mName: name,
|
||||
mShortDescription: description,
|
||||
...(body.name ? { mName: body.name } : undefined),
|
||||
...(body.description ? { mShortDescription: body.description } : undefined),
|
||||
};
|
||||
|
||||
// handle if user uploaded new icon
|
||||
|
||||
@ -32,11 +32,11 @@ export default defineEventHandler<{
|
||||
});
|
||||
|
||||
if (!game)
|
||||
throw createError({ statusCode: 400, statusMessage: "Invalid game ID" });
|
||||
throw createError({ statusCode: 400, message: "Invalid game ID" });
|
||||
|
||||
const imageIndex = game.mImageLibraryObjectIds.findIndex((e) => e == imageId);
|
||||
if (imageIndex == -1)
|
||||
throw createError({ statusCode: 400, statusMessage: "Image not found" });
|
||||
throw createError({ statusCode: 400, message: "Image not found" });
|
||||
|
||||
game.mImageLibraryObjectIds.splice(imageIndex, 1);
|
||||
await objectHandler.deleteAsSystem(imageId);
|
||||
|
||||
@ -10,14 +10,14 @@ export default defineEventHandler(async (h3) => {
|
||||
if (!form)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "This endpoint requires multipart form data.",
|
||||
message: "This endpoint requires multipart form data.",
|
||||
});
|
||||
|
||||
const uploadResult = await handleFileUpload(h3, {}, ["internal:read"]);
|
||||
if (!uploadResult)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Failed to upload file",
|
||||
message: "Failed to upload file",
|
||||
});
|
||||
|
||||
const [ids, options, pull, dump] = uploadResult;
|
||||
@ -25,21 +25,21 @@ export default defineEventHandler(async (h3) => {
|
||||
dump();
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Did not upload a file",
|
||||
message: "Did not upload a file",
|
||||
});
|
||||
}
|
||||
|
||||
const gameId = options.id;
|
||||
const gameId = options.id as string;
|
||||
if (!gameId)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "No game ID attached",
|
||||
message: "No game ID attached",
|
||||
});
|
||||
|
||||
const hasGame = (await prisma.game.count({ where: { id: gameId } })) != 0;
|
||||
if (!hasGame) {
|
||||
dump();
|
||||
throw createError({ statusCode: 400, statusMessage: "Invalid game ID" });
|
||||
throw createError({ statusCode: 400, message: "Invalid game ID" });
|
||||
}
|
||||
|
||||
const result = await prisma.game.update({
|
||||
|
||||
@ -27,14 +27,14 @@ export default defineEventHandler<{ body: typeof ImportGameBody.infer }>(
|
||||
if (!path)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Path missing from body",
|
||||
message: "Path missing from body",
|
||||
});
|
||||
|
||||
const valid = await libraryManager.checkUnimportedGamePath(library, path);
|
||||
if (!valid)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Invalid library or game.",
|
||||
message: "Invalid library or game.",
|
||||
});
|
||||
|
||||
const taskId = metadata
|
||||
@ -44,7 +44,7 @@ export default defineEventHandler<{ body: typeof ImportGameBody.infer }>(
|
||||
if (!taskId)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage:
|
||||
message:
|
||||
"Duplicate metadata import. Please chose a different game or metadata provider.",
|
||||
});
|
||||
|
||||
|
||||
@ -8,14 +8,14 @@ export default defineEventHandler(async (h3) => {
|
||||
const query = getQuery(h3);
|
||||
const search = query.q?.toString();
|
||||
if (!search)
|
||||
throw createError({ statusCode: 400, statusMessage: "Invalid search" });
|
||||
throw createError({ statusCode: 400, message: "Invalid search" });
|
||||
|
||||
const results = await metadataHandler.search(search);
|
||||
|
||||
if (results.length == 0)
|
||||
throw createError({
|
||||
statusCode: 404,
|
||||
statusMessage: "No metadata provider returned search results.",
|
||||
message: "No metadata provider returned search results.",
|
||||
});
|
||||
|
||||
return results;
|
||||
|
||||
@ -4,6 +4,7 @@ import { handleFileUpload } from "~/server/internal/utils/handlefileupload";
|
||||
import * as jdenticon from "jdenticon";
|
||||
import prisma from "~/server/internal/db/database";
|
||||
import libraryManager from "~/server/internal/library";
|
||||
import jsdom from "jsdom";
|
||||
|
||||
export const ImportRedist = type({
|
||||
library: "string",
|
||||
@ -11,6 +12,12 @@ export const ImportRedist = type({
|
||||
|
||||
name: "string",
|
||||
description: "string",
|
||||
|
||||
"platform?": type({
|
||||
name: "string",
|
||||
icon: "string",
|
||||
fileExts: type("string").pipe.try((s) => JSON.parse(s), type("string[]")),
|
||||
}),
|
||||
});
|
||||
|
||||
export default defineEventHandler(async (h3) => {
|
||||
@ -18,14 +25,13 @@ export default defineEventHandler(async (h3) => {
|
||||
if (!allowed) throw createError({ statusCode: 403 });
|
||||
|
||||
const body = await handleFileUpload(h3, {}, ["internal:read"], 1);
|
||||
if (!body)
|
||||
throw createError({ statusCode: 400, statusMessage: "Body required." });
|
||||
if (!body) throw createError({ statusCode: 400, message: "Body required." });
|
||||
|
||||
const [[id], rawOptions, pull,, add] = body;
|
||||
const [[id], rawOptions, pull, , add] = body;
|
||||
|
||||
const options = ImportRedist(rawOptions);
|
||||
if (options instanceof ArkErrors)
|
||||
throw createError({ statusCode: 400, statusMessage: options.summary });
|
||||
throw createError({ statusCode: 400, message: options.summary });
|
||||
|
||||
const valid = await libraryManager.checkUnimportedGamePath(
|
||||
options.library,
|
||||
@ -34,11 +40,25 @@ export default defineEventHandler(async (h3) => {
|
||||
if (!valid)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Invalid library or game.",
|
||||
message: "Invalid library or game.",
|
||||
});
|
||||
|
||||
const icon = id ?? add(jdenticon.toPng(options.name, 512));
|
||||
|
||||
let svgContent = "";
|
||||
if (options.platform) {
|
||||
const dom = new jsdom.JSDOM(options.platform.icon);
|
||||
const svg = dom.window.document.getElementsByTagName("svg").item(0);
|
||||
if (!svg)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "No SVG in uploaded image.",
|
||||
});
|
||||
svg.removeAttribute("width");
|
||||
svg.removeAttribute("height");
|
||||
svgContent = svg.outerHTML;
|
||||
}
|
||||
|
||||
const redist = await prisma.redist.create({
|
||||
data: {
|
||||
libraryId: options.library,
|
||||
@ -47,6 +67,18 @@ export default defineEventHandler(async (h3) => {
|
||||
mName: options.name,
|
||||
mShortDescription: options.description,
|
||||
mIconObjectId: icon,
|
||||
|
||||
platform: {
|
||||
...(options.platform
|
||||
? {
|
||||
create: {
|
||||
platformName: options.platform.name,
|
||||
iconSvg: svgContent,
|
||||
fileExtensions: options.platform.fileExts,
|
||||
},
|
||||
}
|
||||
: undefined),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@ export default defineEventHandler(async (h3) => {
|
||||
if (!gameId)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Missing id in request params",
|
||||
message: "Missing id in request params",
|
||||
});
|
||||
|
||||
const game = await prisma.game.findUnique({
|
||||
@ -19,14 +19,14 @@ export default defineEventHandler(async (h3) => {
|
||||
select: { libraryId: true, libraryPath: true },
|
||||
});
|
||||
if (!game || !game.libraryId)
|
||||
throw createError({ statusCode: 404, statusMessage: "Game not found" });
|
||||
throw createError({ statusCode: 404, message: "Game not found" });
|
||||
|
||||
const unimportedVersions = await libraryManager.fetchUnimportedGameVersions(
|
||||
game.libraryId,
|
||||
game.libraryPath,
|
||||
);
|
||||
if (!unimportedVersions)
|
||||
throw createError({ statusCode: 400, statusMessage: "Invalid game ID" });
|
||||
throw createError({ statusCode: 400, message: "Invalid game ID" });
|
||||
|
||||
return unimportedVersions;
|
||||
});
|
||||
|
||||
@ -5,6 +5,13 @@ import aclManager from "~/server/internal/acls";
|
||||
import prisma from "~/server/internal/db/database";
|
||||
import libraryManager from "~/server/internal/library";
|
||||
|
||||
export const LaunchCommands = type({
|
||||
name: "string > 0",
|
||||
description: "string = ''",
|
||||
launchCommand: "string > 0",
|
||||
launchArgs: "string = ''",
|
||||
}).array();
|
||||
|
||||
export const ImportVersion = type({
|
||||
id: "string",
|
||||
version: "string",
|
||||
@ -17,12 +24,7 @@ export const ImportVersion = type({
|
||||
delta: "boolean = false",
|
||||
umuId: "string = ''",
|
||||
|
||||
launches: type({
|
||||
name: "string > 0",
|
||||
description: "string = ''",
|
||||
launchCommand: "string > 0",
|
||||
launchArgs: "string = ''",
|
||||
}).array(),
|
||||
launches: LaunchCommands,
|
||||
}).configure(throwingArktype);
|
||||
|
||||
export default defineEventHandler(async (h3) => {
|
||||
@ -41,7 +43,7 @@ export default defineEventHandler(async (h3) => {
|
||||
if (validOverlayVersions == 0)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage:
|
||||
message:
|
||||
"Update mode requires a pre-existing version for this platform.",
|
||||
});
|
||||
}
|
||||
@ -50,13 +52,13 @@ export default defineEventHandler(async (h3) => {
|
||||
if (!body.setup)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: 'Setup required in "setup mode".',
|
||||
message: 'Setup required in "setup mode".',
|
||||
});
|
||||
} else {
|
||||
if (!body.delta && body.launches.length == 0)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage:
|
||||
message:
|
||||
"At least one launch command is required for non-delta versions",
|
||||
});
|
||||
}
|
||||
@ -70,7 +72,7 @@ export default defineEventHandler(async (h3) => {
|
||||
if (!taskId)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Invalid options for import",
|
||||
message: "Invalid options for import",
|
||||
});
|
||||
|
||||
return { taskId: taskId };
|
||||
|
||||
@ -11,7 +11,7 @@ export default defineEventHandler(async (h3) => {
|
||||
if (!gameId || !versionName)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Missing id or version in request params",
|
||||
message: "Missing id or version in request params",
|
||||
});
|
||||
|
||||
const preload = await libraryManager.fetchUnimportedVersionInformation(
|
||||
@ -21,7 +21,7 @@ export default defineEventHandler(async (h3) => {
|
||||
if (!preload)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Invalid game or version id/name",
|
||||
message: "Invalid game or version id/name",
|
||||
});
|
||||
|
||||
return preload;
|
||||
|
||||
@ -26,7 +26,7 @@ export default defineEventHandler<{ body: typeof UpdateLibrarySource.infer }>(
|
||||
if (!source)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Library source not found",
|
||||
message: "Library source not found",
|
||||
});
|
||||
|
||||
const constructor = libraryConstructors[source.backend];
|
||||
@ -61,7 +61,7 @@ export default defineEventHandler<{ body: typeof UpdateLibrarySource.infer }>(
|
||||
} catch (e) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: `Failed to create source: ${e}`,
|
||||
message: `Failed to create source: ${e}`,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@ -29,7 +29,7 @@ export default defineEventHandler<{ body: typeof CreateLibrarySource.infer }>(
|
||||
if (!backend)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Invalid source backend.",
|
||||
message: "Invalid source backend.",
|
||||
});
|
||||
|
||||
const constructor = libraryConstructors[backend];
|
||||
@ -63,7 +63,7 @@ export default defineEventHandler<{ body: typeof CreateLibrarySource.infer }>(
|
||||
} catch (e) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: `Failed to create source: ${e}`,
|
||||
message: `Failed to create source: ${e}`,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@ -14,13 +14,13 @@ export default defineEventHandler(async (h3) => {
|
||||
const orderBy = query.order as "asc" | "desc";
|
||||
if (orderBy) {
|
||||
if (typeof orderBy !== "string" || !["asc", "desc"].includes(orderBy))
|
||||
throw createError({ statusCode: 400, statusMessage: "Invalid order" });
|
||||
throw createError({ statusCode: 400, message: "Invalid order" });
|
||||
}
|
||||
|
||||
const tags = query.tags as string[] | undefined;
|
||||
if (tags) {
|
||||
if (typeof tags !== "object" || !Array.isArray(tags))
|
||||
throw createError({ statusCode: 400, statusMessage: "Invalid tags" });
|
||||
throw createError({ statusCode: 400, message: "Invalid tags" });
|
||||
}
|
||||
|
||||
const options = {
|
||||
|
||||
@ -19,27 +19,27 @@ export default defineEventHandler(async (h3) => {
|
||||
if (!form)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "This endpoint requires multipart form data.",
|
||||
message: "This endpoint requires multipart form data.",
|
||||
});
|
||||
|
||||
const uploadResult = await handleFileUpload(h3, {}, ["internal:read"], 1);
|
||||
if (!uploadResult)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Failed to upload file",
|
||||
message: "Failed to upload file",
|
||||
});
|
||||
|
||||
const [imageIds, options, pull, _dump] = uploadResult;
|
||||
|
||||
const body = await CreateNews(options);
|
||||
if (body instanceof ArkErrors)
|
||||
throw createError({ statusCode: 400, statusMessage: body.summary });
|
||||
throw createError({ statusCode: 400, message: body.summary });
|
||||
|
||||
const parsedTags = JSON.parse(body.tags);
|
||||
if (typeof parsedTags !== "object" || !Array.isArray(parsedTags))
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Tags must be an array",
|
||||
message: "Tags must be an array",
|
||||
});
|
||||
|
||||
const imageId = imageIds.at(0);
|
||||
|
||||
@ -9,6 +9,6 @@ export default defineEventHandler(async (h3) => {
|
||||
|
||||
const tag = await prisma.gameTag.deleteMany({ where: { id } });
|
||||
if (tag.count == 0)
|
||||
throw createError({ statusCode: 404, statusMessage: "Tag not found" });
|
||||
throw createError({ statusCode: 404, message: "Tag not found" });
|
||||
return;
|
||||
});
|
||||
|
||||
@ -10,7 +10,7 @@ export default defineEventHandler(async (h3) => {
|
||||
if (!allAcls)
|
||||
throw createError({
|
||||
statusCode: 403,
|
||||
statusMessage: "Somehow no ACLs on authenticated request.",
|
||||
message: "Somehow no ACLs on authenticated request.",
|
||||
});
|
||||
|
||||
const runningTasks = (await taskHandler.runningTasks()).map((e) => e.id);
|
||||
|
||||
@ -18,14 +18,14 @@ export default defineEventHandler(async (h3) => {
|
||||
if (!taskGroups[taskGroup])
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Invalid task group.",
|
||||
message: "Invalid task group.",
|
||||
});
|
||||
|
||||
const task = await taskHandler.runTaskGroupByName(taskGroup);
|
||||
if (!task)
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: "Could not start task.",
|
||||
message: "Could not start task.",
|
||||
});
|
||||
return { id: task };
|
||||
});
|
||||
|
||||
@ -10,14 +10,14 @@ export default defineEventHandler(async (h3) => {
|
||||
if (!id)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "No id in router params",
|
||||
message: "No id in router params",
|
||||
});
|
||||
|
||||
const deleted = await prisma.aPIToken.delete({
|
||||
where: { id: id, mode: APITokenMode.System },
|
||||
})!;
|
||||
if (!deleted)
|
||||
throw createError({ statusCode: 404, statusMessage: "Token not found" });
|
||||
throw createError({ statusCode: 404, message: "Token not found" });
|
||||
|
||||
return;
|
||||
});
|
||||
|
||||
@ -22,7 +22,7 @@ export default defineEventHandler(async (h3) => {
|
||||
if (invalidACLs.length > 0)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: `Invalid ACLs: ${invalidACLs.join(", ")}`,
|
||||
message: `Invalid ACLs: ${invalidACLs.join(", ")}`,
|
||||
});
|
||||
|
||||
const token = await prisma.aPIToken.create({
|
||||
|
||||
@ -19,12 +19,12 @@ export default defineEventHandler(async (h3) => {
|
||||
if (userId === "system")
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Cannot interact with system user.",
|
||||
message: "Cannot interact with system user.",
|
||||
});
|
||||
|
||||
const user = await prisma.user.findUnique({ where: { id: userId } });
|
||||
if (!user)
|
||||
throw createError({ statusCode: 404, statusMessage: "User not found." });
|
||||
throw createError({ statusCode: 404, message: "User not found." });
|
||||
|
||||
await prisma.user.delete({ where: { id: userId } });
|
||||
return { success: true };
|
||||
|
||||
@ -9,18 +9,18 @@ export default defineEventHandler(async (h3) => {
|
||||
if (!userId)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "No userId in route.",
|
||||
message: "No userId in route.",
|
||||
});
|
||||
|
||||
if (userId == "system")
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Cannot fetch system user.",
|
||||
message: "Cannot fetch system user.",
|
||||
});
|
||||
|
||||
const user = await prisma.user.findUnique({ where: { id: userId } });
|
||||
if (!user)
|
||||
throw createError({ statusCode: 404, statusMessage: "User not found." });
|
||||
throw createError({ statusCode: 404, message: "User not found." });
|
||||
|
||||
return user;
|
||||
});
|
||||
|
||||
@ -23,7 +23,7 @@ export default defineEventHandler<{
|
||||
if (!authManager.getAuthProviders().Simple)
|
||||
throw createError({
|
||||
statusCode: 403,
|
||||
statusMessage: t("errors.auth.method.signinDisabled"),
|
||||
message: t("errors.auth.method.signinDisabled"),
|
||||
});
|
||||
|
||||
const body = signinValidator(await readBody(h3));
|
||||
@ -33,7 +33,7 @@ export default defineEventHandler<{
|
||||
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: body.summary,
|
||||
message: body.summary,
|
||||
});
|
||||
}
|
||||
|
||||
@ -57,13 +57,13 @@ export default defineEventHandler<{
|
||||
if (!authMek)
|
||||
throw createError({
|
||||
statusCode: 401,
|
||||
statusMessage: t("errors.auth.invalidUserOrPass"),
|
||||
message: t("errors.auth.invalidUserOrPass"),
|
||||
});
|
||||
|
||||
if (!authMek.user.enabled)
|
||||
throw createError({
|
||||
statusCode: 403,
|
||||
statusMessage: t("errors.auth.disabled"),
|
||||
message: t("errors.auth.disabled"),
|
||||
});
|
||||
|
||||
// LEGACY bcrypt
|
||||
@ -74,13 +74,13 @@ export default defineEventHandler<{
|
||||
if (!hash)
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: t("errors.auth.invalidPassState"),
|
||||
message: t("errors.auth.invalidPassState"),
|
||||
});
|
||||
|
||||
if (!(await checkHashBcrypt(body.password, hash)))
|
||||
throw createError({
|
||||
statusCode: 401,
|
||||
statusMessage: t("errors.auth.invalidUserOrPass"),
|
||||
message: t("errors.auth.invalidUserOrPass"),
|
||||
});
|
||||
|
||||
// TODO: send user to forgot password screen or something to force them to change their password to new system
|
||||
@ -93,13 +93,13 @@ export default defineEventHandler<{
|
||||
if (!hash || typeof hash !== "string")
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: t("errors.auth.invalidPassState"),
|
||||
message: t("errors.auth.invalidPassState"),
|
||||
});
|
||||
|
||||
if (!(await checkHashArgon2(body.password, hash)))
|
||||
throw createError({
|
||||
statusCode: 401,
|
||||
statusMessage: t("errors.auth.invalidUserOrPass"),
|
||||
message: t("errors.auth.invalidUserOrPass"),
|
||||
});
|
||||
|
||||
await sessionHandler.signin(h3, authMek.userId, body.rememberMe);
|
||||
|
||||
@ -8,7 +8,7 @@ export default defineEventHandler(async (h3) => {
|
||||
if (!authManager.getAuthProviders().Simple)
|
||||
throw createError({
|
||||
statusCode: 403,
|
||||
statusMessage: t("errors.auth.method.signinDisabled"),
|
||||
message: t("errors.auth.method.signinDisabled"),
|
||||
});
|
||||
|
||||
const query = getQuery(h3);
|
||||
@ -16,7 +16,7 @@ export default defineEventHandler(async (h3) => {
|
||||
if (!id)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: t("errors.auth.inviteIdRequired"),
|
||||
message: t("errors.auth.inviteIdRequired"),
|
||||
});
|
||||
taskHandler.runTaskGroupByName("cleanup:invitations");
|
||||
|
||||
@ -24,7 +24,7 @@ export default defineEventHandler(async (h3) => {
|
||||
if (!invitation)
|
||||
throw createError({
|
||||
statusCode: 404,
|
||||
statusMessage: t("errors.auth.invalidInvite"),
|
||||
message: t("errors.auth.invalidInvite"),
|
||||
});
|
||||
|
||||
return invitation;
|
||||
|
||||
@ -26,7 +26,7 @@ export default defineEventHandler<{
|
||||
if (!authManager.getAuthProviders().Simple)
|
||||
throw createError({
|
||||
statusCode: 403,
|
||||
statusMessage: t("errors.auth.method.signinDisabled"),
|
||||
message: t("errors.auth.method.signinDisabled"),
|
||||
});
|
||||
|
||||
const user = await readValidatedBody(h3, CreateUserValidator);
|
||||
@ -37,7 +37,7 @@ export default defineEventHandler<{
|
||||
if (!invitation)
|
||||
throw createError({
|
||||
statusCode: 401,
|
||||
statusMessage: t("errors.auth.invalidInvite"),
|
||||
message: t("errors.auth.invalidInvite"),
|
||||
});
|
||||
|
||||
// reuse items from invite
|
||||
@ -50,7 +50,7 @@ export default defineEventHandler<{
|
||||
if (existing > 0)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: t("errors.auth.usernameTaken"),
|
||||
message: t("errors.auth.usernameTaken"),
|
||||
});
|
||||
|
||||
const userId = randomUUID();
|
||||
|
||||
@ -12,13 +12,13 @@ export default defineEventHandler(async (h3) => {
|
||||
if (!client)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Invalid or expired client ID.",
|
||||
message: "Invalid or expired client ID.",
|
||||
});
|
||||
|
||||
if (client.userId != user.userId)
|
||||
throw createError({
|
||||
statusCode: 403,
|
||||
statusMessage: "Not allowed to authorize this client.",
|
||||
message: "Not allowed to authorize this client.",
|
||||
});
|
||||
|
||||
const token = await clientHandler.generateAuthToken(clientId);
|
||||
|
||||
@ -10,12 +10,12 @@ export default defineEventHandler(async (h3) => {
|
||||
if (!code)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Code required in query params.",
|
||||
message: "Code required in query params.",
|
||||
});
|
||||
|
||||
const clientId = await clientHandler.fetchClientIdByCode(code);
|
||||
if (!clientId)
|
||||
throw createError({ statusCode: 400, statusMessage: "Invalid code." });
|
||||
throw createError({ statusCode: 400, message: "Invalid code." });
|
||||
|
||||
return clientId;
|
||||
});
|
||||
|
||||
@ -12,19 +12,19 @@ export default defineEventHandler(async (h3) => {
|
||||
if (!client)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Invalid or expired client ID.",
|
||||
message: "Invalid or expired client ID.",
|
||||
});
|
||||
|
||||
if (client.userId != user.userId)
|
||||
throw createError({
|
||||
statusCode: 403,
|
||||
statusMessage: "Not allowed to authorize this client.",
|
||||
message: "Not allowed to authorize this client.",
|
||||
});
|
||||
|
||||
if (!client.peer)
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: "No client listening for authorization.",
|
||||
message: "No client listening for authorization.",
|
||||
});
|
||||
|
||||
const token = await clientHandler.generateAuthToken(clientId);
|
||||
|
||||
@ -9,14 +9,14 @@ export default defineWebSocketHandler({
|
||||
if (!code)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Code required in Authorization header.",
|
||||
message: "Code required in Authorization header.",
|
||||
});
|
||||
await clientHandler.connectCodeListener(code, peer);
|
||||
} catch (e) {
|
||||
peer.send(
|
||||
JSON.stringify({
|
||||
type: "error",
|
||||
value: (e as FetchError)?.statusMessage,
|
||||
value: (e as FetchError)?.message,
|
||||
}),
|
||||
);
|
||||
peer.close();
|
||||
|
||||
@ -8,24 +8,24 @@ export default defineEventHandler(async (h3) => {
|
||||
if (!clientId || !token)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Missing token or client ID from body",
|
||||
message: "Missing token or client ID from body",
|
||||
});
|
||||
|
||||
const metadata = await clientHandler.fetchClient(clientId);
|
||||
if (!metadata)
|
||||
throw createError({
|
||||
statusCode: 403,
|
||||
statusMessage: "Invalid client ID",
|
||||
message: "Invalid client ID",
|
||||
});
|
||||
if (!metadata.authToken || !metadata.userId)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Un-authorized client ID",
|
||||
message: "Un-authorized client ID",
|
||||
});
|
||||
if (metadata.authToken !== token)
|
||||
throw createError({
|
||||
statusCode: 403,
|
||||
statusMessage: "Invalid token",
|
||||
message: "Invalid token",
|
||||
});
|
||||
|
||||
const certificateAuthority = useCertificateAuthority();
|
||||
|
||||
@ -10,20 +10,20 @@ export default defineEventHandler(async (h3) => {
|
||||
if (!providedClientId)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Provide client ID in request params as 'id'",
|
||||
message: "Provide client ID in request params as 'id'",
|
||||
});
|
||||
|
||||
const client = await clientHandler.fetchClient(providedClientId);
|
||||
if (!client)
|
||||
throw createError({
|
||||
statusCode: 404,
|
||||
statusMessage: "Request not found.",
|
||||
message: "Request not found.",
|
||||
});
|
||||
|
||||
if (client.userId && user.userId !== client.userId)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Client already claimed.",
|
||||
message: "Client already claimed.",
|
||||
});
|
||||
|
||||
await clientHandler.attachUserId(providedClientId, user.userId);
|
||||
|
||||
@ -28,7 +28,7 @@ export default defineEventHandler(async (h3) => {
|
||||
if (!platform)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Invalid or unsupported platform",
|
||||
message: "Invalid or unsupported platform",
|
||||
});
|
||||
|
||||
const capabilityIterable = Object.entries(capabilities) as Array<
|
||||
@ -42,7 +42,7 @@ export default defineEventHandler(async (h3) => {
|
||||
)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Invalid capabilities.",
|
||||
message: "Invalid capabilities.",
|
||||
});
|
||||
|
||||
if (
|
||||
@ -57,7 +57,7 @@ export default defineEventHandler(async (h3) => {
|
||||
)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Invalid capability configuration.",
|
||||
message: "Invalid capability configuration.",
|
||||
});
|
||||
|
||||
const result = await clientHandler.initiate({
|
||||
|
||||
@ -14,13 +14,13 @@ export default defineClientEventHandler(
|
||||
if (!rawCapability || typeof rawCapability !== "string")
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "capability must be a string",
|
||||
message: "capability must be a string",
|
||||
});
|
||||
|
||||
if (!configuration || typeof configuration !== "object")
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "configuration must be an object",
|
||||
message: "configuration must be an object",
|
||||
});
|
||||
|
||||
const capability = rawCapability as InternalClientCapability;
|
||||
@ -28,7 +28,7 @@ export default defineClientEventHandler(
|
||||
if (!validCapabilities.includes(capability))
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Invalid capability.",
|
||||
message: "Invalid capability.",
|
||||
});
|
||||
|
||||
const isValid = await capabilityManager.validateCapabilityConfiguration(
|
||||
@ -38,7 +38,7 @@ export default defineClientEventHandler(
|
||||
if (!isValid)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Invalid capability configuration.",
|
||||
message: "Invalid capability configuration.",
|
||||
});
|
||||
|
||||
await capabilityManager.upsertClientCapability(
|
||||
|
||||
@ -20,7 +20,7 @@ export default defineClientEventHandler(async (h3) => {
|
||||
if (!gameId || !versionName || !filename || Number.isNaN(chunkIndex))
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Invalid chunk arguments",
|
||||
message: "Invalid chunk arguments",
|
||||
});
|
||||
|
||||
let game = await gameLookupCache.getItem(gameId);
|
||||
@ -35,7 +35,7 @@ export default defineClientEventHandler(async (h3) => {
|
||||
},
|
||||
});
|
||||
if (!game || !game.libraryId)
|
||||
throw createError({ statusCode: 400, statusMessage: "Invalid game ID" });
|
||||
throw createError({ statusCode: 400, message: "Invalid game ID" });
|
||||
|
||||
await gameLookupCache.setItem(gameId, game);
|
||||
}
|
||||
@ -43,7 +43,7 @@ export default defineClientEventHandler(async (h3) => {
|
||||
if (!game.libraryId)
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: "Somehow, we got here.",
|
||||
message: "Somehow, we got here.",
|
||||
});
|
||||
|
||||
const peek = await libraryManager.peekFile(
|
||||
@ -53,7 +53,7 @@ export default defineClientEventHandler(async (h3) => {
|
||||
filename,
|
||||
);
|
||||
if (!peek)
|
||||
throw createError({ status: 400, statusMessage: "Failed to peek file" });
|
||||
throw createError({ status: 400, message: "Failed to peek file" });
|
||||
|
||||
const start = chunkIndex * chunkSize;
|
||||
const end = Math.min((chunkIndex + 1) * chunkSize, peek.size);
|
||||
@ -63,7 +63,7 @@ export default defineClientEventHandler(async (h3) => {
|
||||
if (start >= end)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Invalid chunk index",
|
||||
message: "Invalid chunk index",
|
||||
});
|
||||
|
||||
const gameReadStream = await libraryManager.readFile(
|
||||
@ -76,7 +76,7 @@ export default defineClientEventHandler(async (h3) => {
|
||||
if (!gameReadStream)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Failed to create stream",
|
||||
message: "Failed to create stream",
|
||||
});
|
||||
|
||||
return sendStream(h3, gameReadStream);
|
||||
|
||||
@ -8,13 +8,13 @@ export default defineClientEventHandler(async (h3, { fetchUser }) => {
|
||||
if (!id)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "ID required in route params",
|
||||
message: "ID required in route params",
|
||||
});
|
||||
|
||||
const body = await readBody(h3);
|
||||
const gameId = body.id;
|
||||
if (!gameId)
|
||||
throw createError({ statusCode: 400, statusMessage: "Game ID required" });
|
||||
throw createError({ statusCode: 400, message: "Game ID required" });
|
||||
|
||||
const successful = await userLibraryManager.collectionRemove(
|
||||
gameId,
|
||||
@ -24,7 +24,7 @@ export default defineClientEventHandler(async (h3, { fetchUser }) => {
|
||||
if (!successful)
|
||||
throw createError({
|
||||
statusCode: 404,
|
||||
statusMessage: "Collection not found",
|
||||
message: "Collection not found",
|
||||
});
|
||||
return {};
|
||||
});
|
||||
|
||||
@ -8,13 +8,13 @@ export default defineClientEventHandler(async (h3, { fetchUser }) => {
|
||||
if (!id)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "ID required in route params",
|
||||
message: "ID required in route params",
|
||||
});
|
||||
|
||||
const body = await readBody(h3);
|
||||
const gameId = body.id;
|
||||
if (!gameId)
|
||||
throw createError({ statusCode: 400, statusMessage: "Game ID required" });
|
||||
throw createError({ statusCode: 400, message: "Game ID required" });
|
||||
|
||||
return await userLibraryManager.collectionAdd(gameId, id, user.id);
|
||||
});
|
||||
|
||||
@ -8,7 +8,7 @@ export default defineClientEventHandler(async (h3, { fetchUser }) => {
|
||||
if (!id)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "ID required in route params",
|
||||
message: "ID required in route params",
|
||||
});
|
||||
|
||||
// Verify collection exists and user owns it
|
||||
@ -17,13 +17,13 @@ export default defineClientEventHandler(async (h3, { fetchUser }) => {
|
||||
if (!collection)
|
||||
throw createError({
|
||||
statusCode: 404,
|
||||
statusMessage: "Collection not found",
|
||||
message: "Collection not found",
|
||||
});
|
||||
|
||||
if (collection.userId !== user.id)
|
||||
throw createError({
|
||||
statusCode: 403,
|
||||
statusMessage: "Not authorized to delete this collection",
|
||||
message: "Not authorized to delete this collection",
|
||||
});
|
||||
|
||||
await userLibraryManager.deleteCollection(id);
|
||||
|
||||
@ -8,7 +8,7 @@ export default defineClientEventHandler(async (h3, { fetchUser }) => {
|
||||
if (!id)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "ID required in route params",
|
||||
message: "ID required in route params",
|
||||
});
|
||||
|
||||
// Fetch specific collection
|
||||
@ -17,14 +17,14 @@ export default defineClientEventHandler(async (h3, { fetchUser }) => {
|
||||
if (!collection)
|
||||
throw createError({
|
||||
statusCode: 404,
|
||||
statusMessage: "Collection not found",
|
||||
message: "Collection not found",
|
||||
});
|
||||
|
||||
// Verify user owns this collection
|
||||
if (collection.userId !== user.id)
|
||||
throw createError({
|
||||
statusCode: 403,
|
||||
statusMessage: "Not authorized to access this collection",
|
||||
message: "Not authorized to access this collection",
|
||||
});
|
||||
|
||||
return collection;
|
||||
|
||||
@ -8,7 +8,7 @@ export default defineClientEventHandler(async (h3, { fetchUser }) => {
|
||||
|
||||
const gameId = body.id;
|
||||
if (!gameId)
|
||||
throw createError({ statusCode: 400, statusMessage: "Game ID required" });
|
||||
throw createError({ statusCode: 400, message: "Game ID required" });
|
||||
|
||||
await userLibraryManager.libraryRemove(gameId, user.id);
|
||||
return {};
|
||||
|
||||
@ -7,7 +7,7 @@ export default defineClientEventHandler(async (h3, { fetchUser }) => {
|
||||
const body = await readBody(h3);
|
||||
const gameId = body.id;
|
||||
if (!gameId)
|
||||
throw createError({ statusCode: 400, statusMessage: "Game ID required" });
|
||||
throw createError({ statusCode: 400, message: "Game ID required" });
|
||||
|
||||
// Add the game to the default collection
|
||||
await userLibraryManager.libraryAdd(gameId, user.id);
|
||||
|
||||
@ -8,7 +8,7 @@ export default defineClientEventHandler(async (h3, { fetchUser }) => {
|
||||
|
||||
const name = body.name;
|
||||
if (!name)
|
||||
throw createError({ statusCode: 400, statusMessage: "Requires name" });
|
||||
throw createError({ statusCode: 400, message: "Requires name" });
|
||||
|
||||
// Create the collection using the manager
|
||||
const newCollection = await userLibraryManager.collectionCreate(
|
||||
|
||||
@ -4,7 +4,7 @@ import prisma from "~/server/internal/db/database";
|
||||
export default defineClientEventHandler(async (h3) => {
|
||||
const id = getRouterParam(h3, "id");
|
||||
if (!id)
|
||||
throw createError({ statusCode: 400, statusMessage: "No ID in route" });
|
||||
throw createError({ statusCode: 400, message: "No ID in route" });
|
||||
|
||||
const game = await prisma.game.findUnique({
|
||||
where: {
|
||||
@ -12,7 +12,7 @@ export default defineClientEventHandler(async (h3) => {
|
||||
},
|
||||
});
|
||||
if (!game)
|
||||
throw createError({ statusCode: 404, statusMessage: "Game not found" });
|
||||
throw createError({ statusCode: 404, message: "Game not found" });
|
||||
|
||||
return game;
|
||||
});
|
||||
|
||||
@ -7,14 +7,14 @@ export default defineClientEventHandler(async (h3) => {
|
||||
if (!id)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Missing version id in query",
|
||||
message: "Missing version id in query",
|
||||
});
|
||||
|
||||
const manifest = await manifestGenerator.generateManifest(id);
|
||||
if (!manifest)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Invalid game or version, or no versions added.",
|
||||
message: "Invalid game or version, or no versions added.",
|
||||
});
|
||||
return manifest;
|
||||
});
|
||||
|
||||
@ -8,7 +8,7 @@ export default defineClientEventHandler(async (h3) => {
|
||||
if (!id || !version)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Missing id or version in query",
|
||||
message: "Missing id or version in query",
|
||||
});
|
||||
|
||||
const gameVersion = await prisma.gameVersion.findUnique({
|
||||
@ -20,7 +20,7 @@ export default defineClientEventHandler(async (h3) => {
|
||||
if (!gameVersion)
|
||||
throw createError({
|
||||
statusCode: 404,
|
||||
statusMessage: "Game version not found",
|
||||
message: "Game version not found",
|
||||
});
|
||||
|
||||
return gameVersion;
|
||||
|
||||
@ -7,7 +7,7 @@ export default defineClientEventHandler(async (h3) => {
|
||||
if (!id)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "No ID in request query",
|
||||
message: "No ID in request query",
|
||||
});
|
||||
|
||||
const versions = await prisma.gameVersion.findMany({
|
||||
|
||||
@ -7,13 +7,13 @@ export default defineClientEventHandler(async (h3) => {
|
||||
const orderBy = query.order as "asc" | "desc";
|
||||
if (orderBy) {
|
||||
if (typeof orderBy !== "string" || !["asc", "desc"].includes(orderBy))
|
||||
throw createError({ statusCode: 400, statusMessage: "Invalid order" });
|
||||
throw createError({ statusCode: 400, message: "Invalid order" });
|
||||
}
|
||||
|
||||
const tags = query.tags as string[] | undefined;
|
||||
if (tags) {
|
||||
if (typeof tags !== "object" || !Array.isArray(tags))
|
||||
throw createError({ statusCode: 400, statusMessage: "Invalid tags" });
|
||||
throw createError({ statusCode: 400, message: "Invalid tags" });
|
||||
}
|
||||
|
||||
const options = {
|
||||
|
||||
@ -3,13 +3,13 @@ import objectHandler from "~/server/internal/objects";
|
||||
|
||||
export default defineClientEventHandler(async (h3, utils) => {
|
||||
const id = getRouterParam(h3, "id");
|
||||
if (!id) throw createError({ statusCode: 400, statusMessage: "Invalid ID" });
|
||||
if (!id) throw createError({ statusCode: 400, message: "Invalid ID" });
|
||||
|
||||
const user = await utils.fetchUser();
|
||||
|
||||
const object = await objectHandler.fetchWithPermissions(id, user.id);
|
||||
if (!object)
|
||||
throw createError({ statusCode: 404, statusMessage: "Object not found" });
|
||||
throw createError({ statusCode: 404, message: "Object not found" });
|
||||
|
||||
setHeader(h3, "Content-Type", object.mime);
|
||||
return object.data;
|
||||
|
||||
@ -8,27 +8,27 @@ export default defineClientEventHandler(
|
||||
if (!client.capabilities.includes(ClientCapabilities.CloudSaves))
|
||||
throw createError({
|
||||
statusCode: 403,
|
||||
statusMessage: "Capability not allowed.",
|
||||
message: "Capability not allowed.",
|
||||
});
|
||||
const user = await fetchUser();
|
||||
const gameId = getRouterParam(h3, "gameid");
|
||||
if (!gameId)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "No gameID in route params",
|
||||
message: "No gameID in route params",
|
||||
});
|
||||
|
||||
const slotIndexString = getRouterParam(h3, "slotindex");
|
||||
if (!slotIndexString)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "No slotIndex in route params",
|
||||
message: "No slotIndex in route params",
|
||||
});
|
||||
const slotIndex = parseInt(slotIndexString);
|
||||
if (Number.isNaN(slotIndex))
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Invalid slotIndex",
|
||||
message: "Invalid slotIndex",
|
||||
});
|
||||
|
||||
const game = await prisma.game.findUnique({
|
||||
@ -36,7 +36,7 @@ export default defineClientEventHandler(
|
||||
select: { id: true },
|
||||
});
|
||||
if (!game)
|
||||
throw createError({ statusCode: 400, statusMessage: "Invalid game ID" });
|
||||
throw createError({ statusCode: 400, message: "Invalid game ID" });
|
||||
|
||||
const save = await prisma.saveSlot.delete({
|
||||
where: {
|
||||
@ -48,6 +48,6 @@ export default defineClientEventHandler(
|
||||
},
|
||||
});
|
||||
if (!save)
|
||||
throw createError({ statusCode: 404, statusMessage: "Save not found" });
|
||||
throw createError({ statusCode: 404, message: "Save not found" });
|
||||
},
|
||||
);
|
||||
|
||||
@ -8,27 +8,27 @@ export default defineClientEventHandler(
|
||||
if (!client.capabilities.includes(ClientCapabilities.CloudSaves))
|
||||
throw createError({
|
||||
statusCode: 403,
|
||||
statusMessage: "Capability not allowed.",
|
||||
message: "Capability not allowed.",
|
||||
});
|
||||
const user = await fetchUser();
|
||||
const gameId = getRouterParam(h3, "gameid");
|
||||
if (!gameId)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "No gameID in route params",
|
||||
message: "No gameID in route params",
|
||||
});
|
||||
|
||||
const slotIndexString = getRouterParam(h3, "slotindex");
|
||||
if (!slotIndexString)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "No slotIndex in route params",
|
||||
message: "No slotIndex in route params",
|
||||
});
|
||||
const slotIndex = parseInt(slotIndexString);
|
||||
if (Number.isNaN(slotIndex))
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Invalid slotIndex",
|
||||
message: "Invalid slotIndex",
|
||||
});
|
||||
|
||||
const game = await prisma.game.findUnique({
|
||||
@ -36,7 +36,7 @@ export default defineClientEventHandler(
|
||||
select: { id: true },
|
||||
});
|
||||
if (!game)
|
||||
throw createError({ statusCode: 400, statusMessage: "Invalid game ID" });
|
||||
throw createError({ statusCode: 400, message: "Invalid game ID" });
|
||||
|
||||
const save = await prisma.saveSlot.findUnique({
|
||||
where: {
|
||||
@ -48,7 +48,7 @@ export default defineClientEventHandler(
|
||||
},
|
||||
});
|
||||
if (!save)
|
||||
throw createError({ statusCode: 404, statusMessage: "Save not found" });
|
||||
throw createError({ statusCode: 404, message: "Save not found" });
|
||||
|
||||
return save;
|
||||
},
|
||||
|
||||
@ -9,27 +9,27 @@ export default defineClientEventHandler(
|
||||
if (!client.capabilities.includes(ClientCapabilities.CloudSaves))
|
||||
throw createError({
|
||||
statusCode: 403,
|
||||
statusMessage: "Capability not allowed.",
|
||||
message: "Capability not allowed.",
|
||||
});
|
||||
const user = await fetchUser();
|
||||
const gameId = getRouterParam(h3, "gameid");
|
||||
if (!gameId)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "No gameID in route params",
|
||||
message: "No gameID in route params",
|
||||
});
|
||||
|
||||
const slotIndexString = getRouterParam(h3, "slotindex");
|
||||
if (!slotIndexString)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "No slotIndex in route params",
|
||||
message: "No slotIndex in route params",
|
||||
});
|
||||
const slotIndex = parseInt(slotIndexString);
|
||||
if (Number.isNaN(slotIndex))
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Invalid slotIndex",
|
||||
message: "Invalid slotIndex",
|
||||
});
|
||||
|
||||
const game = await prisma.game.findUnique({
|
||||
@ -37,7 +37,7 @@ export default defineClientEventHandler(
|
||||
select: { id: true },
|
||||
});
|
||||
if (!game)
|
||||
throw createError({ statusCode: 400, statusMessage: "Invalid game ID" });
|
||||
throw createError({ statusCode: 400, message: "Invalid game ID" });
|
||||
|
||||
await saveManager.pushSave(
|
||||
gameId,
|
||||
|
||||
@ -8,14 +8,14 @@ export default defineClientEventHandler(
|
||||
if (!client.capabilities.includes(ClientCapabilities.CloudSaves))
|
||||
throw createError({
|
||||
statusCode: 403,
|
||||
statusMessage: "Capability not allowed.",
|
||||
message: "Capability not allowed.",
|
||||
});
|
||||
const user = await fetchUser();
|
||||
const gameId = getRouterParam(h3, "gameid");
|
||||
if (!gameId)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "No gameID in route params",
|
||||
message: "No gameID in route params",
|
||||
});
|
||||
|
||||
const game = await prisma.game.findUnique({
|
||||
@ -23,7 +23,7 @@ export default defineClientEventHandler(
|
||||
select: { id: true },
|
||||
});
|
||||
if (!game)
|
||||
throw createError({ statusCode: 400, statusMessage: "Invalid game ID" });
|
||||
throw createError({ statusCode: 400, message: "Invalid game ID" });
|
||||
|
||||
const saves = await prisma.saveSlot.findMany({
|
||||
where: {
|
||||
|
||||
@ -9,14 +9,14 @@ export default defineClientEventHandler(
|
||||
if (!client.capabilities.includes(ClientCapabilities.CloudSaves))
|
||||
throw createError({
|
||||
statusCode: 403,
|
||||
statusMessage: "Capability not allowed.",
|
||||
message: "Capability not allowed.",
|
||||
});
|
||||
const user = await fetchUser();
|
||||
const gameId = getRouterParam(h3, "gameid");
|
||||
if (!gameId)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "No gameID in route params",
|
||||
message: "No gameID in route params",
|
||||
});
|
||||
|
||||
const game = await prisma.game.findUnique({
|
||||
@ -24,7 +24,7 @@ export default defineClientEventHandler(
|
||||
select: { id: true },
|
||||
});
|
||||
if (!game)
|
||||
throw createError({ statusCode: 400, statusMessage: "Invalid game ID" });
|
||||
throw createError({ statusCode: 400, message: "Invalid game ID" });
|
||||
|
||||
const saves = await prisma.saveSlot.findMany({
|
||||
where: {
|
||||
@ -40,7 +40,7 @@ export default defineClientEventHandler(
|
||||
if (saves.length + 1 > limit)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Out of save slots",
|
||||
message: "Out of save slots",
|
||||
});
|
||||
|
||||
let firstIndex = 0;
|
||||
|
||||
@ -8,7 +8,7 @@ export default defineClientEventHandler(
|
||||
if (!client.capabilities.includes(ClientCapabilities.CloudSaves))
|
||||
throw createError({
|
||||
statusCode: 403,
|
||||
statusMessage: "Capability not allowed.",
|
||||
message: "Capability not allowed.",
|
||||
});
|
||||
const user = await fetchUser();
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@ export default defineClientEventHandler(async (_h3, { fetchClient }) => {
|
||||
if (!client.capabilities.includes(ClientCapabilities.CloudSaves))
|
||||
throw createError({
|
||||
statusCode: 403,
|
||||
statusMessage: "Capability not allowed.",
|
||||
message: "Capability not allowed.",
|
||||
});
|
||||
|
||||
const slotLimit = await applicationSettings.get("saveSlotCountLimit");
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user