import { getActorByDiscordIdAndGuildDiscordId, getGuildByDiscordId, getTicketByGuild, } from "@stealth-developers/db"; import Elysia, { t } from "elysia"; import { hasAccessToTicket } from "../lib/access"; import { authPlugin } from "../lib/auth"; import { getTicketsByGuildId } from "../lib/db"; import { sanitiseTicket, sanitiseTicketAttachments, sanitiseTicketComments, sanitiseTicketMessages, sanitiseTicketParticipants, } from "../lib/sanitise"; import { ErrorSchema, GuildAccessSchema, TicketAttachmentSchema, TicketCommentSchema, TicketMessageSchema, TicketParticipantSchema, TicketSchema, TicketsResponseSchema, } from "../lib/schemas"; export const guildRoutes = new Elysia({ prefix: "/guilds/:guildId" }) .use(authPlugin) .resolve(async ({ params: { guildId }, session, status, user }) => { if (!session || !user?.discordId) return status(401, { message: "Unauthorised" }); const guild = await getGuildByDiscordId(guildId); if (!guild) return status(404, { message: "Guild not found" }); const actor = await getActorByDiscordIdAndGuildDiscordId(user.discordId, guildId); if (!actor) return status(403, { message: "No access to this guild" }); return { actor, guild }; }) .get( "/", ({ actor, guild }) => { return { id: guild.id, discordId: guild.discordId, name: guild.name, icon: guild.icon, actor: { username: actor.username, displayName: actor.displayName, avatar: actor.avatar, actorId: actor.id, userId: actor.userId, discordId: actor.discordId, }, }; }, { response: { 200: GuildAccessSchema, 401: ErrorSchema, 403: ErrorSchema, 404: ErrorSchema, }, tags: ["guilds"], }, ) .group("/tickets", (app) => app .get( "/", async ({ query: { limit, offset }, guild, actor }) => { const tickets = await getTicketsByGuildId( guild.id, actor.moderator ? undefined : actor.id, { limit, offset }, ); return { tickets: tickets.map((ticket) => sanitiseTicket(ticket, { isModerator: !!actor.moderator, anonymiseStaff: false }), ), count: tickets.length, }; }, { tags: ["tickets"], query: t.Object({ limit: t.Number({ default: 50 }), offset: t.Number({ default: 0 }), }), response: { 200: TicketsResponseSchema, 401: ErrorSchema, 403: ErrorSchema, 404: ErrorSchema, }, }, ) .group("/:ticketId", (ticketGroup) => ticketGroup .resolve(async ({ params: { ticketId }, guild, actor, status }) => { const ticket = await getTicketByGuild(guild.id, Number(ticketId)); if (!ticket) return status(404, { message: "Ticket not found" }); const hasAccess = hasAccessToTicket(actor, ticket); if (!hasAccess) return status(403, { message: "No access to this ticket" }); return { ticket }; }) .get( "/", ({ ticket, actor }) => { return sanitiseTicket(ticket, { isModerator: !!actor.moderator, anonymiseStaff: false, }); }, { response: { 200: TicketSchema, 401: ErrorSchema, 403: ErrorSchema, 404: ErrorSchema, }, tags: ["tickets"], }, ) .get( "/messages", ({ ticket, actor }) => { const messages = ticket.messages ?? []; return sanitiseTicketMessages(messages, { isModerator: !!actor.moderator, anonymiseStaff: false, }); }, { response: { 200: t.Array(TicketMessageSchema), 401: ErrorSchema, 403: ErrorSchema, 404: ErrorSchema, }, tags: ["tickets"], }, ) .get( "/participants", ({ ticket, actor }) => { const participants = ticket.participants ?? []; return sanitiseTicketParticipants(participants, { isModerator: !!actor.moderator, anonymiseStaff: false, }); }, { response: { 200: t.Array(TicketParticipantSchema), 401: ErrorSchema, 403: ErrorSchema, 404: ErrorSchema, }, tags: ["tickets"], }, ) .get( "/comments", ({ ticket, actor }) => { const comments = ticket.comments ?? []; return sanitiseTicketComments(comments, { isModerator: !!actor.moderator, anonymiseStaff: false, }); }, { response: { 200: t.Array(TicketCommentSchema), 401: ErrorSchema, 403: ErrorSchema, 404: ErrorSchema, }, tags: ["tickets"], }, ) .get( "/attachments", ({ ticket, actor }) => { const attachments = ticket.attachments ?? []; return sanitiseTicketAttachments(attachments, { isModerator: !!actor.moderator, anonymiseStaff: false, }); }, { response: { 200: t.Array(TicketAttachmentSchema), 401: ErrorSchema, 403: ErrorSchema, 404: ErrorSchema, }, tags: ["tickets"], }, ), ), );