diff --git a/prisma/schema.prisma b/prisma/schema.prisma index a9d2717..bb98b2f 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -137,11 +137,11 @@ model Question { id String @id @default(uuid()) category Category @relation(fields: [categoryId], references: [id], onDelete: Cascade) categoryId Int - label String + label String @db.VarChar(45) maxLength Int? @default(4000) minLength Int? @default(0) order Int - placeholder String? + placeholder String? @db.VarChar(100) required Boolean @default(true) style Int @default(2) value String? @db.Text diff --git a/src/i18n/en-GB.yml b/src/i18n/en-GB.yml index 2657f6a..8366a9d 100644 --- a/src/i18n/en-GB.yml +++ b/src/i18n/en-GB.yml @@ -6,11 +6,13 @@ log: joined: '{user} {verb} {targetType}' target: category: 'a category' + question: 'a question' settings: 'the settings' title: joined: '{targetType} {verb}' target: category: 'Category' + question: 'Question' settings: 'Settings' verb: create: 'created' diff --git a/src/lib/logging.js b/src/lib/logging.js index 19e7edf..5165780 100644 --- a/src/lib/logging.js +++ b/src/lib/logging.js @@ -4,15 +4,29 @@ const { } = require('discord.js'); const { diff: getDiff } = require('object-diffy'); + +const exists = thing => (typeof thing === 'string' && thing.length > 0) && thing !== null && thing !== undefined; + +const arrToObj = obj => { + for (const key in obj) { + if (obj[key] instanceof Array && obj[key][0]?.id) { + const temp = {}; + obj[key].forEach(v => (temp[v.id] = v)); + obj[key] = temp; + } + } + return obj; +}; + function makeDiff({ original, updated, }) { - const diff = getDiff(original, updated); + const diff = getDiff(arrToObj(original), arrToObj(updated)); const fields = []; for (const key in diff) { if (key === 'createdAt') continue; // object-diffy doesn't like dates - const from = diff[key].from === null ? '' : `- ${diff[key].from.toString().replace(/\n/g, '\\n')}\n`; - const to = diff[key].to === null ? '' : `+ ${diff[key].to.toString().replace(/\n/g, '\\n')}\n`; + const from = exists(diff[key].from) ? `- ${String(diff[key].from).replace(/\n/g, '\\n')}\n` : ''; + const to = exists(diff[key].to) ? `+ ${String(diff[key].to).replace(/\n/g, '\\n')}\n` : ''; fields.push({ inline: true, name: key, diff --git a/src/routes/api/admin/guilds/[guild]/categories/[category].js b/src/routes/api/admin/guilds/[guild]/categories/[category]/index.js similarity index 75% rename from src/routes/api/admin/guilds/[guild]/categories/[category].js rename to src/routes/api/admin/guilds/[guild]/categories/[category]/index.js index 6f9aa16..d4a09a5 100644 --- a/src/routes/api/admin/guilds/[guild]/categories/[category].js +++ b/src/routes/api/admin/guilds/[guild]/categories/[category]/index.js @@ -1,4 +1,4 @@ -const { logAdminEvent } = require('../../../../../../lib/logging'); +const { logAdminEvent } = require('../../../../../../../lib/logging'); const { randomUUID } = require('crypto'); module.exports.delete = fastify => ({ @@ -7,7 +7,7 @@ module.exports.delete = fastify => ({ const client = res.context.config.client; const guildId = req.params.guild; const categoryId = Number(req.params.category); - const original = req.params.category && await client.prisma.category.findUnique({ where: { id: categoryId } }); + const original = categoryId && await client.prisma.category.findUnique({ where: { id: categoryId } }); if (!original || original.guildId !== guildId) return res.status(404).send(new Error('Not Found')); const category = await client.prisma.category.delete({ where: { id: categoryId } }); @@ -68,9 +68,49 @@ module.exports.patch = fastify => ({ const categoryId = Number(req.params.category); const guild = client.guilds.cache.get(req.params.guild); const data = req.body; - const original = req.params.category && await client.prisma.category.findUnique({ where: { id: categoryId } }); - if (!original || original.guildId !== guildId) return res.status(404).send(new Error('Not Found')); + const select = { + channelName: true, + claiming: true, + // createdAt: true, + description: true, + discordCategory: true, + emoji: true, + enableFeedback: true, + guildId: true, + id: true, + image: true, + memberLimit: true, + name: true, + openingMessage: true, + pingRoles: true, + questions: { + select: { + // createdAt: true, + id: true, + label: true, + maxLength: true, + minLength: true, + order: true, + placeholder: true, + required: true, + style: true, + value: true, + }, + }, + ratelimit: true, + requireTopic: true, + requiredRoles: true, + staffRoles: true, + totalLimit: true, + }; + + const original = req.params.category && await client.prisma.category.findUnique({ + select, + where: { id: categoryId }, + }); + + if (!original || original.guildId !== guildId) return res.status(404).send(new Error('Not Found')); if (data.hasOwnProperty('id')) delete data.id; if (data.hasOwnProperty('createdAt')) delete data.createdAt; @@ -89,6 +129,7 @@ module.exports.patch = fastify => ({ }), }, }, + select, where: { id: categoryId }, }); diff --git a/src/routes/api/admin/guilds/[guild]/categories/[category]/questions/[question].js b/src/routes/api/admin/guilds/[guild]/categories/[category]/questions/[question].js new file mode 100644 index 0000000..213e102 --- /dev/null +++ b/src/routes/api/admin/guilds/[guild]/categories/[category]/questions/[question].js @@ -0,0 +1,29 @@ +const { logAdminEvent } = require('../../../../../../../../lib/logging'); + +module.exports.delete = fastify => ({ + handler: async (req, res) => { + /** @type {import('client')} */ + const client = res.context.config.client; + const guildId = req.params.guild; + const categoryId = Number(req.params.category); + const questionId = req.params.question; + const original = questionId && await client.prisma.question.findUnique({ where: { id: questionId } }); + const category = categoryId && await client.prisma.category.findUnique({ where: { id: categoryId } }); + if (original?.categoryId !== categoryId || category.guildId !== guildId) return res.status(404).send(new Error('Not Found')); + const question = await client.prisma.question.delete({ where: { id: questionId } }); + + logAdminEvent(client, { + action: 'delete', + guildId: req.params.guild, + target: { + id: question.id, + name: question.label, + type: 'question', + }, + userId: req.user.payload.id, + }); + + return question; + }, + onRequest: [fastify.authenticate, fastify.isAdmin], +}); \ No newline at end of file