import { db } from "~/db/sql"; import { databaseTimestampNow } from "~/utils/dates"; import { concatUserSubmittedImagePrefix } from "~/utils/kysely.server"; import { IMAGES_TO_VALIDATE_AT_ONCE } from "./upload-constants"; import type { ImageUploadType } from "./upload-types"; /** Finds an unvalidated image by ID with associated calendar event data */ export function findById(id: number) { return db .selectFrom("UnvalidatedUserSubmittedImage") .leftJoin( "CalendarEvent", "CalendarEvent.avatarImgId", "UnvalidatedUserSubmittedImage.id", ) .select(["CalendarEvent.tournamentId"]) .where("UnvalidatedUserSubmittedImage.id", "=", id) .executeTakeFirst(); } /** Deletes an image and its associated art entry in a transaction */ export function deleteImageById(id: number) { return db.transaction().execute(async (trx) => { await trx.deleteFrom("Art").where("Art.imgId", "=", id).execute(); await trx .deleteFrom("UnvalidatedUserSubmittedImage") .where("id", "=", id) .execute(); }); } /** Counts unvalidated art images for a specific author */ export async function countUnvalidatedArt(authorId: number) { const result = await db .selectFrom("UnvalidatedUserSubmittedImage") .innerJoin("Art", "Art.imgId", "UnvalidatedUserSubmittedImage.id") .select(({ fn }) => fn.countAll().as("count")) .where("UnvalidatedUserSubmittedImage.validatedAt", "is", null) .where("Art.authorId", "=", authorId) .executeTakeFirstOrThrow(); return result.count; } const unvalidatedImagesBaseQuery = db .selectFrom("UnvalidatedUserSubmittedImage") .leftJoin("Team", (join) => join.on((eb) => eb.or([ eb("UnvalidatedUserSubmittedImage.id", "=", eb.ref("Team.avatarImgId")), eb("UnvalidatedUserSubmittedImage.id", "=", eb.ref("Team.bannerImgId")), ]), ), ) .leftJoin("Art", "UnvalidatedUserSubmittedImage.id", "Art.imgId") .leftJoin( "CalendarEvent", "UnvalidatedUserSubmittedImage.id", "CalendarEvent.avatarImgId", ) .where("UnvalidatedUserSubmittedImage.validatedAt", "is", null) .where((eb) => eb.or([ eb("Team.id", "is not", null), eb("Art.id", "is not", null), eb("CalendarEvent.id", "is not", null), ]), ); /** Counts all unvalidated images used in teams, art, or calendar events */ export async function countAllUnvalidated() { const result = await unvalidatedImagesBaseQuery .select(({ fn }) => fn.countAll().as("count")) .executeTakeFirstOrThrow(); return result.count; } /** Fetches unvalidated images for admin review with submitter info */ export function unvalidatedImages() { return unvalidatedImagesBaseQuery .leftJoin( "User", "UnvalidatedUserSubmittedImage.submitterUserId", "User.id", ) .select((eb) => [ "UnvalidatedUserSubmittedImage.id", concatUserSubmittedImagePrefix( eb.ref("UnvalidatedUserSubmittedImage.url"), ).as("url"), "UnvalidatedUserSubmittedImage.submitterUserId", "User.username", ]) .limit(IMAGES_TO_VALIDATE_AT_ONCE) .execute(); } /** Counts unvalidated team images submitted by a specific user */ export async function countUnvalidatedBySubmitterUserId(userId: number) { const result = await db .selectFrom("UnvalidatedUserSubmittedImage") .innerJoin("Team", (join) => join.on((eb) => eb.or([ eb( "UnvalidatedUserSubmittedImage.id", "=", eb.ref("Team.avatarImgId"), ), eb( "UnvalidatedUserSubmittedImage.id", "=", eb.ref("Team.bannerImgId"), ), ]), ), ) .select(({ fn }) => fn.countAll().as("count")) .where("UnvalidatedUserSubmittedImage.validatedAt", "is", null) .where("UnvalidatedUserSubmittedImage.submitterUserId", "=", userId) .executeTakeFirstOrThrow(); return result.count; } /** Marks an image as validated by setting the current timestamp */ export function validateImage(id: number) { return db .updateTable("UnvalidatedUserSubmittedImage") .set({ validatedAt: databaseTimestampNow() }) .where("id", "=", id) .execute(); } /** Creates a new image and associates it with a team or organization */ export function addNewImage({ submitterUserId, url, validatedAt, teamId, organizationId, type, }: { submitterUserId: number; url: string; validatedAt: number | null; teamId?: number; organizationId?: number; type: ImageUploadType; }) { return db.transaction().execute(async (trx) => { const img = await trx .insertInto("UnvalidatedUserSubmittedImage") .values({ submitterUserId, url, validatedAt }) .returningAll() .executeTakeFirstOrThrow(); if (type === "team-pfp" && teamId) { await trx .updateTable("AllTeam") .set({ avatarImgId: img.id }) .where("id", "=", teamId) .execute(); } else if (type === "team-banner" && teamId) { await trx .updateTable("AllTeam") .set({ bannerImgId: img.id }) .where("id", "=", teamId) .execute(); } else if (type === "org-pfp" && organizationId) { await trx .updateTable("TournamentOrganization") .set({ avatarImgId: img.id }) .where("id", "=", organizationId) .execute(); } return img; }); }