upload images to games
This commit is contained in:
@@ -28,7 +28,13 @@ export default defineEventHandler(async (h3) => {
|
||||
if (!game)
|
||||
throw createError({ statusCode: 400, statusMessage: "Invalid game ID" });
|
||||
|
||||
game.mImageLibrary = game.mImageLibrary.filter((e) => e != imageId);
|
||||
const imageIndex = game.mImageLibrary.findIndex((e) => e == imageId);
|
||||
if (imageIndex == -1)
|
||||
throw createError({ statusCode: 400, statusMessage: "Image not found" });
|
||||
|
||||
game.mImageLibrary.splice(imageIndex, 1);
|
||||
await h3.context.objects.delete(imageId);
|
||||
|
||||
if (game.mBannerId === imageId) {
|
||||
game.mBannerId = game.mImageLibrary[0];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import prisma from "~/server/internal/db/database";
|
||||
import { handleFileUpload } from "~/server/internal/utils/handlefileupload";
|
||||
|
||||
export default defineEventHandler(async (h3) => {
|
||||
const user = await h3.context.session.getAdminUser(h3);
|
||||
if (!user) throw createError({ statusCode: 403 });
|
||||
|
||||
const form = await readMultipartFormData(h3);
|
||||
if (!form)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "This endpoint requires multipart form data.",
|
||||
});
|
||||
|
||||
const uploadResult = await handleFileUpload(h3, {}, ["internal:read"]);
|
||||
if (!uploadResult)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Failed to upload file",
|
||||
});
|
||||
|
||||
const [id, options, pull, dump] = uploadResult;
|
||||
if (!id) {
|
||||
dump();
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Did not upload a file",
|
||||
});
|
||||
}
|
||||
|
||||
const gameId = options.id;
|
||||
if (!gameId)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "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" });
|
||||
}
|
||||
|
||||
const result = await prisma.game.update({
|
||||
where: {
|
||||
id: gameId,
|
||||
},
|
||||
data: {
|
||||
mImageLibrary: {
|
||||
push: id,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await pull();
|
||||
return result;
|
||||
});
|
||||
@@ -9,7 +9,7 @@ export default defineEventHandler(async (h3) => {
|
||||
id: true,
|
||||
mName: true,
|
||||
mShortDescription: true,
|
||||
mBannerId: true,
|
||||
mCoverId:true,
|
||||
mDevelopers: {
|
||||
select: {
|
||||
id: true,
|
||||
|
||||
@@ -6,12 +6,13 @@ import { Readable } from "stream";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { GlobalObjectHandler } from "~/server/plugins/objects";
|
||||
|
||||
type TransactionTable = { [key: string]: string }; // ID to URL
|
||||
type TransactionDataType = string | Readable | Buffer;
|
||||
type TransactionTable = { [key: string]: TransactionDataType }; // ID to data
|
||||
type GlobalTransactionRecord = { [key: string]: TransactionTable }; // Transaction ID to table
|
||||
|
||||
type Register = (url: string) => string;
|
||||
type Pull = () => Promise<void>;
|
||||
type Dump = () => void;
|
||||
export type Register = (url: TransactionDataType) => string;
|
||||
export type Pull = () => Promise<void>;
|
||||
export type Dump = () => void;
|
||||
|
||||
export class ObjectTransactionalHandler {
|
||||
private record: GlobalTransactionRecord = {};
|
||||
@@ -24,18 +25,23 @@ export class ObjectTransactionalHandler {
|
||||
|
||||
this.record[transactionId] ??= {};
|
||||
|
||||
const register = (url: string) => {
|
||||
const register = (data: TransactionDataType) => {
|
||||
const objectId = uuidv4();
|
||||
this.record[transactionId][objectId] = url;
|
||||
this.record[transactionId][objectId] = data;
|
||||
|
||||
return objectId;
|
||||
};
|
||||
|
||||
const pull = async () => {
|
||||
for (const [id, url] of Object.entries(this.record[transactionId])) {
|
||||
for (const [id, data] of Object.entries(this.record[transactionId])) {
|
||||
await GlobalObjectHandler.createFromSource(
|
||||
id,
|
||||
() => $fetch<Readable>(url, { responseType: "stream" }),
|
||||
() => {
|
||||
if (typeof data === "string") {
|
||||
return $fetch<Readable>(data, { responseType: "stream" });
|
||||
}
|
||||
return (async () => data)();
|
||||
},
|
||||
metadata,
|
||||
permissions
|
||||
);
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import { EventHandlerRequest, H3Event } from "h3";
|
||||
import { Dump, ObjectTransactionalHandler, Pull } from "../objects/transactional";
|
||||
|
||||
export async function handleFileUpload(
|
||||
h3: H3Event<EventHandlerRequest>,
|
||||
metadata: { [key: string]: string },
|
||||
permissions: Array<string>
|
||||
): Promise<[string | undefined, {[key: string]: string}, Pull, Dump] | undefined> {
|
||||
const formData = await readMultipartFormData(h3);
|
||||
if (!formData) return undefined;
|
||||
const transactionalHandler = new ObjectTransactionalHandler();
|
||||
const [add, pull, dump] = transactionalHandler.new(metadata, permissions);
|
||||
const options: { [key: string]: string } = {};
|
||||
let id;
|
||||
|
||||
for (const entry of formData) {
|
||||
if (entry.filename) {
|
||||
// Only pick one file
|
||||
if (id) continue;
|
||||
|
||||
// Add file to transaction handler so we can void it later if we error out
|
||||
id = add(entry.data);
|
||||
continue;
|
||||
}
|
||||
if (!entry.name) continue;
|
||||
|
||||
options[entry.name] = entry.data.toString("utf-8");
|
||||
}
|
||||
|
||||
return [id, options, pull, dump];
|
||||
}
|
||||
Reference in New Issue
Block a user