Log A Sanction
+This page allows our staff to log an official sanction from one of our platforms.
+diff --git a/.forgejo/issue_template/bug_report.yaml b/.gitea/issue_template/bug_report.yaml similarity index 98% rename from .forgejo/issue_template/bug_report.yaml rename to .gitea/issue_template/bug_report.yaml index 6deb616..bf17745 100644 --- a/.forgejo/issue_template/bug_report.yaml +++ b/.gitea/issue_template/bug_report.yaml @@ -2,7 +2,7 @@ name: 🐛 Bug Report description: Something isn't working as expected? Let us know! title: '[BUG] - ' labels: - - "🚦 status: awaiting triage" + - "status/awaiting triage" body: - type: checkboxes id: attestations diff --git a/.forgejo/issue_template/config.yml b/.gitea/issue_template/config.yml similarity index 100% rename from .forgejo/issue_template/config.yml rename to .gitea/issue_template/config.yml diff --git a/.forgejo/issue_template/feature_proposal.yml b/.gitea/issue_template/feature_proposal.yml similarity index 97% rename from .forgejo/issue_template/feature_proposal.yml rename to .gitea/issue_template/feature_proposal.yml index d833b94..b3fae97 100644 --- a/.forgejo/issue_template/feature_proposal.yml +++ b/.gitea/issue_template/feature_proposal.yml @@ -2,7 +2,7 @@ name: 💭 Feature Proposal description: Have an idea for how we can improve? Share it here! title: '[FEAT] - ' labels: - - "🚦 status: awaiting triage" + - "status/awaiting triage" body: - type: checkboxes id: attestations diff --git a/.forgejo/issue_template/other.yml b/.gitea/issue_template/other.yml similarity index 97% rename from .forgejo/issue_template/other.yml rename to .gitea/issue_template/other.yml index 680e7a7..2f1335f 100644 --- a/.forgejo/issue_template/other.yml +++ b/.gitea/issue_template/other.yml @@ -2,7 +2,7 @@ name: ❓ Other Issue description: I have something that is neither a bug nor a feature request. title: '[OTHER] - ' labels: - - "🚦 status: awaiting triage" + - "status/awaiting triage" body: - type: checkboxes id: attestations diff --git a/.forgejo/pull_request_template.yml b/.gitea/pull_request_template.yml similarity index 98% rename from .forgejo/pull_request_template.yml rename to .gitea/pull_request_template.yml index 37d43f4..2d2fbf3 100644 --- a/.forgejo/pull_request_template.yml +++ b/.gitea/pull_request_template.yml @@ -1,7 +1,5 @@ name: "Pull Request Template" about: "Template for pulls" -labels: - - "🔍 pull: ready for review" body: - type: textarea id: explain diff --git a/package.json b/package.json index 7d73853..23a6bb3 100644 --- a/package.json +++ b/package.json @@ -25,8 +25,8 @@ "typescript": "5.7.3" }, "dependencies": { + "@fastify/formbody": "8.0.2", "@prisma/client": "6.2.1", - "discord.js": "14.17.3", "fastify": "5.2.1" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 060d259..732f07c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,12 +8,12 @@ importers: .: dependencies: + '@fastify/formbody': + specifier: 8.0.2 + version: 8.0.2 '@prisma/client': specifier: 6.2.1 version: 6.2.1(prisma@6.2.1) - discord.js: - specifier: 14.17.3 - version: 14.17.3 fastify: specifier: 5.2.1 version: 5.2.1 @@ -47,34 +47,6 @@ packages: resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} engines: {node: '>=6.9.0'} - '@discordjs/builders@1.10.0': - resolution: {integrity: sha512-ikVZsZP+3shmVJ5S1oM+7SveUCK3L9fTyfA8aJ7uD9cNQlTqF+3Irbk2Y22KXTb3C3RNUahRkSInClJMkHrINg==} - engines: {node: '>=16.11.0'} - - '@discordjs/collection@1.5.3': - resolution: {integrity: sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ==} - engines: {node: '>=16.11.0'} - - '@discordjs/collection@2.1.1': - resolution: {integrity: sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg==} - engines: {node: '>=18'} - - '@discordjs/formatters@0.6.0': - resolution: {integrity: sha512-YIruKw4UILt/ivO4uISmrGq2GdMY6EkoTtD0oS0GvkJFRZbTSdPhzYiUILbJ/QslsvC9H9nTgGgnarnIl4jMfw==} - engines: {node: '>=16.11.0'} - - '@discordjs/rest@2.4.2': - resolution: {integrity: sha512-9bOvXYLQd5IBg/kKGuEFq3cstVxAMJ6wMxO2U3wjrgO+lHv8oNCT+BBRpuzVQh7BoXKvk/gpajceGvQUiRoJ8g==} - engines: {node: '>=18'} - - '@discordjs/util@1.1.1': - resolution: {integrity: sha512-eddz6UnOBEB1oITPinyrB2Pttej49M9FZQY8NxgEvc3tq6ZICZ19m70RsmzRdDHk80O9NoYN/25AqJl8vPVf/g==} - engines: {node: '>=18'} - - '@discordjs/ws@1.2.0': - resolution: {integrity: sha512-QH5CAFe3wHDiedbO+EI3OOiyipwWd+Q6BdoFZUw/Wf2fw5Cv2fgU/9UEtJRmJa9RecI+TAhdGPadMaEIur5yJg==} - engines: {node: '>=16.11.0'} - '@es-joy/jsdoccomment@0.49.0': resolution: {integrity: sha512-xjZTSFgECpb9Ohuk5yMX5RhUEbfeQcuOp8IF60e+wyzWEF0M5xeSgqsfLtvPEX8BIyOX9saZqzuGPmZ8oWc+5Q==} engines: {node: '>=16'} @@ -291,6 +263,9 @@ packages: '@fastify/fast-json-stringify-compiler@5.0.2': resolution: {integrity: sha512-YdR7gqlLg1xZAQa+SX4sMNzQHY5pC54fu9oC5aYSUqBhyn6fkLkrdtKlpVdCNPlwuUuXA1PjFTEmvMF6ZVXVGw==} + '@fastify/formbody@8.0.2': + resolution: {integrity: sha512-84v5J2KrkXzjgBpYnaNRPqwgMsmY7ZDjuj0YVuMR3NXCJRCgKEZy/taSP1wUYGn0onfxJpLyRGDLa+NMaDJtnA==} + '@fastify/forwarded@3.0.0': resolution: {integrity: sha512-kJExsp4JCms7ipzg7SJ3y8DwmePaELHxKYtg+tZow+k0znUTf3cb+npgyqm8+ATZOdmfgfydIebPDWM172wfyA==} @@ -477,18 +452,6 @@ packages: '@rtsao/scc@1.1.0': resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} - '@sapphire/async-queue@1.5.5': - resolution: {integrity: sha512-cvGzxbba6sav2zZkH8GPf2oGk9yYoD5qrNWdu9fRehifgnFZJMV+nuy2nON2roRO4yQQ+v7MK/Pktl/HgfsUXg==} - engines: {node: '>=v14.0.0', npm: '>=7.0.0'} - - '@sapphire/shapeshift@4.0.0': - resolution: {integrity: sha512-d9dUmWVA7MMiKobL3VpLF8P2aeanRTu6ypG2OIaEv/ZHH/SUQ2iHOVyi5wAPjQ+HmnMuL0whK9ez8I/raWbtIg==} - engines: {node: '>=v16'} - - '@sapphire/snowflake@3.5.3': - resolution: {integrity: sha512-jjmJywLAFoWeBi1W7994zZyiNWPIiqRRNAmSERxyg93xRGzNYvGjlZ0gR6x0F4gPRi2+0O6S71kOZYyr3cxaIQ==} - engines: {node: '>=v14.0.0', npm: '>=7.0.0'} - '@stylistic/eslint-plugin@2.12.1': resolution: {integrity: sha512-fubZKIHSPuo07FgRTn6S4Nl0uXPRPYVNpyZzIDGfp7Fny6JjNus6kReLD7NI380JXi4HtUTSOZ34LBuNPO1XLQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -510,9 +473,6 @@ packages: '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} - '@types/ws@8.5.13': - resolution: {integrity: sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==} - '@typescript-eslint/eslint-plugin@8.19.0': resolution: {integrity: sha512-NggSaEZCdSrFddbctrVjkVZvFC6KGfKfNK0CU7mNK/iKHGKbzT4Wmgm08dKpcZECBu9f5FypndoMyRHkdqfT1Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -654,10 +614,6 @@ packages: '@vitest/utils@3.0.2': resolution: {integrity: sha512-Qu01ZYZlgHvDP02JnMBRpX43nRaZtNpIzw3C1clDXmn8eakgX6iQVGzTQ/NjkIr64WD8ioqOjkaYRVvHQI5qiw==} - '@vladfrangu/async_event_emitter@2.4.6': - resolution: {integrity: sha512-RaI5qZo6D2CVS6sTHFKg1v5Ohq/+Bo2LZ5gzUEwZ/WkHhwtGTCB/sVLw8ijOkAUxasZ+WshN/Rzj4ywsABJ5ZA==} - engines: {node: '>=v14.0.0', npm: '>=7.0.0'} - abstract-logging@2.0.1: resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==} @@ -894,13 +850,6 @@ packages: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} - discord-api-types@0.37.117: - resolution: {integrity: sha512-d+Z6RKd7v3q22lsil7yASucqMfVVV0s0XSqu3cw7kyHVXiDO/mAnqMzqma26IYnIm2mk3TlupYJDGrdL908ZKA==} - - discord.js@14.17.3: - resolution: {integrity: sha512-8/j8udc3CU7dz3Eqch64UaSHoJtUT6IXK4da5ixjbav4NAXJicloWswD/iwn1ImZEMoAV3LscsdO0zhBh6H+0Q==} - engines: {node: '>=18'} - doctrine@2.1.0: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} @@ -1120,6 +1069,9 @@ packages: fast-uri@3.0.6: resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==} + fastify-plugin@5.0.1: + resolution: {integrity: sha512-HCxs+YnRaWzCl+cWRYFnHmeRFyR5GVnJTAaCJQiYzQSDwK9MgJdyAsuL3nh0EWRCYMgQ5MeziymvmAhUHYHDUQ==} + fastify@5.2.1: resolution: {integrity: sha512-rslrNBF67eg8/Gyn7P2URV8/6pz8kSAscFL4EThZJ8JBMaXacVdVE4hmUcnPNKERl5o/xTiBSLfdowBRhVF1WA==} @@ -1460,12 +1412,6 @@ packages: lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - lodash.snakecase@4.1.1: - resolution: {integrity: sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==} - - lodash@4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -1473,9 +1419,6 @@ packages: loupe@3.1.2: resolution: {integrity: sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==} - magic-bytes.js@1.10.0: - resolution: {integrity: sha512-/k20Lg2q8LE5xiaaSkMXk4sfvI+9EGEykFS4b0CHHGWqDYU0bGUFSwchNOMA56D7TCs9GwVTkqe9als1/ns8UQ==} - magic-string@0.30.17: resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} @@ -1963,9 +1906,6 @@ packages: peerDependencies: typescript: '>=4.8.4' - ts-mixer@6.0.4: - resolution: {integrity: sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==} - tsconfig-paths@3.15.0: resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} @@ -2016,10 +1956,6 @@ packages: undici-types@6.20.0: resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} - undici@6.19.8: - resolution: {integrity: sha512-U8uCCl2x9TK3WANvmBavymRzxbfFYG+tAu+fgx3zxQy3qdagQqBLwJVrdyO1TBfUXvfKveMKJZhpvUYoOjM+4g==} - engines: {node: '>=18.17'} - update-browserslist-db@1.1.2: resolution: {integrity: sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==} hasBin: true @@ -2132,18 +2068,6 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} - ws@8.18.0: - resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -2158,53 +2082,6 @@ snapshots: '@babel/helper-validator-identifier@7.25.9': {} - '@discordjs/builders@1.10.0': - dependencies: - '@discordjs/formatters': 0.6.0 - '@discordjs/util': 1.1.1 - '@sapphire/shapeshift': 4.0.0 - discord-api-types: 0.37.117 - fast-deep-equal: 3.1.3 - ts-mixer: 6.0.4 - tslib: 2.8.1 - - '@discordjs/collection@1.5.3': {} - - '@discordjs/collection@2.1.1': {} - - '@discordjs/formatters@0.6.0': - dependencies: - discord-api-types: 0.37.117 - - '@discordjs/rest@2.4.2': - dependencies: - '@discordjs/collection': 2.1.1 - '@discordjs/util': 1.1.1 - '@sapphire/async-queue': 1.5.5 - '@sapphire/snowflake': 3.5.3 - '@vladfrangu/async_event_emitter': 2.4.6 - discord-api-types: 0.37.117 - magic-bytes.js: 1.10.0 - tslib: 2.8.1 - undici: 6.19.8 - - '@discordjs/util@1.1.1': {} - - '@discordjs/ws@1.2.0': - dependencies: - '@discordjs/collection': 2.1.1 - '@discordjs/rest': 2.4.2 - '@discordjs/util': 1.1.1 - '@sapphire/async-queue': 1.5.5 - '@types/ws': 8.5.13 - '@vladfrangu/async_event_emitter': 2.4.6 - discord-api-types: 0.37.117 - tslib: 2.8.1 - ws: 8.18.0 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - '@es-joy/jsdoccomment@0.49.0': dependencies: comment-parser: 1.4.1 @@ -2352,6 +2229,11 @@ snapshots: dependencies: fast-json-stringify: 6.0.1 + '@fastify/formbody@8.0.2': + dependencies: + fast-querystring: 1.1.2 + fastify-plugin: 5.0.1 + '@fastify/forwarded@3.0.0': {} '@fastify/merge-json-schemas@0.2.1': @@ -2509,15 +2391,6 @@ snapshots: '@rtsao/scc@1.1.0': {} - '@sapphire/async-queue@1.5.5': {} - - '@sapphire/shapeshift@4.0.0': - dependencies: - fast-deep-equal: 3.1.3 - lodash: 4.17.21 - - '@sapphire/snowflake@3.5.3': {} - '@stylistic/eslint-plugin@2.12.1(eslint@9.18.0)(typescript@5.7.3)': dependencies: '@typescript-eslint/utils': 8.21.0(eslint@9.18.0)(typescript@5.7.3) @@ -2542,10 +2415,6 @@ snapshots: '@types/normalize-package-data@2.4.4': {} - '@types/ws@8.5.13': - dependencies: - '@types/node': 22.10.7 - '@typescript-eslint/eslint-plugin@8.19.0(@typescript-eslint/parser@8.19.0(eslint@9.18.0)(typescript@5.7.3))(eslint@9.18.0)(typescript@5.7.3)': dependencies: '@eslint-community/regexpp': 4.12.1 @@ -2746,8 +2615,6 @@ snapshots: loupe: 3.1.2 tinyrainbow: 2.0.0 - '@vladfrangu/async_event_emitter@2.4.6': {} - abstract-logging@2.0.1: {} acorn-jsx@5.3.2(acorn@7.4.1): @@ -3005,26 +2872,6 @@ snapshots: dependencies: path-type: 4.0.0 - discord-api-types@0.37.117: {} - - discord.js@14.17.3: - dependencies: - '@discordjs/builders': 1.10.0 - '@discordjs/collection': 1.5.3 - '@discordjs/formatters': 0.6.0 - '@discordjs/rest': 2.4.2 - '@discordjs/util': 1.1.1 - '@discordjs/ws': 1.2.0 - '@sapphire/snowflake': 3.5.3 - discord-api-types: 0.37.117 - fast-deep-equal: 3.1.3 - lodash.snakecase: 4.1.1 - tslib: 2.8.1 - undici: 6.19.8 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - doctrine@2.1.0: dependencies: esutils: 2.0.3 @@ -3416,6 +3263,8 @@ snapshots: fast-uri@3.0.6: {} + fastify-plugin@5.0.1: {} + fastify@5.2.1: dependencies: '@fastify/ajv-compiler': 4.0.2 @@ -3780,18 +3629,12 @@ snapshots: lodash.merge@4.6.2: {} - lodash.snakecase@4.1.1: {} - - lodash@4.17.21: {} - loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 loupe@3.1.2: {} - magic-bytes.js@1.10.0: {} - magic-string@0.30.17: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 @@ -4319,8 +4162,6 @@ snapshots: dependencies: typescript: 5.7.3 - ts-mixer@6.0.4: {} - tsconfig-paths@3.15.0: dependencies: '@types/json5': 0.0.29 @@ -4384,8 +4225,6 @@ snapshots: undici-types@6.20.0: {} - undici@6.19.8: {} - update-browserslist-db@1.1.2(browserslist@4.24.4): dependencies: browserslist: 4.24.4 @@ -4520,6 +4359,4 @@ snapshots: word-wrap@1.2.5: {} - ws@8.18.0: {} - yocto-queue@0.1.0: {} diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 1009fa9..826f4ed 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -8,14 +8,22 @@ datasource db { } model Sanctions { - id String @id @default(auto()) @map("_id") @db.ObjectId - date DateTime @default(now()) - number Int @unique + id String @id @default(auto()) @map("_id") @db.ObjectId + date DateTime @default(now()) + number Int @unique uuid String platform String action String + moderator String reason String - revoked Boolean @default(false) + revoked Boolean @default(false) + revokedBy String? revokeReason String? revokeDate DateTime? } + +model Tokens { + id String @id @default(auto()) @map("_id") @db.ObjectId + username String @unique + token String @unique +} diff --git a/src/commands/log.ts b/src/commands/log.ts deleted file mode 100644 index fdcfea1..0000000 --- a/src/commands/log.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { - ApplicationIntegrationType, - InteractionContextType, - SlashCommandBuilder, -} from "discord.js"; -import { errorHandler } from "../utils/errorHandler.js"; -import type { Command } from "../interfaces/command.js"; - -/** - * @copyright nhcarrigan - * @license Naomi's Public License - * @author Naomi Carrigan - */ -export const log: Command = { - data: new SlashCommandBuilder(). - setName("log"). - setDescription("Log a moderation action."). - setContexts([ - InteractionContextType.BotDM, - InteractionContextType.Guild, - InteractionContextType.PrivateChannel, - ]). - setIntegrationTypes([ ApplicationIntegrationType.UserInstall ]). - addStringOption((option) => { - return option. - setName("action"). - setDescription("The action to log."). - setRequired(true). - addChoices([ - { name: "Ban", value: "ban" }, - { name: "Kick", value: "kick" }, - { name: "Mute", value: "mute" }, - { name: "Warn", value: "warn" }, - { name: "Block", value: "block" }, - { name: "Suspend", value: "suspend" }, - ]); - }). - addStringOption((option) => { - return option. - setName("platform"). - setDescription("The platform to log the action on."). - setRequired(true). - addChoices([ - { name: "Discord", value: "discord" }, - { name: "Twitch", value: "twitch" }, - { name: "Codeberg", value: "codeberg" }, - { name: "Bluesky", value: "bluesky" }, - { name: "Forum", value: "forum" }, - { name: "Reddit", value: "reddit" }, - { name: "IRC", value: "irc" }, - { name: "Slack", value: "slack" }, - { name: "Mastodon", value: "mastodon" }, - { name: "Twitter", value: "twitter" }, - { name: "GitHub", value: "github" }, - { name: "LinkedIn", value: "linkedin" }, - { name: "Peerlist", value: "peerlist" }, - { name: "Signal", value: "signal" }, - { name: "WhatsApp", value: "whatsapp" }, - { name: "Snapchat", value: "snapchat" }, - ]); - }). - addStringOption((option) => { - return option. - setName("username"). - setDescription("Username or UUID of the targeted user."). - setRequired(true); - }). - addStringOption((option) => { - return option. - setName("reason"). - setDescription("Reason for the action."). - setRequired(true); - }), - run: async(app, interaction) => { - try { - await interaction.deferReply({ ephemeral: true }); - if (interaction.user.id !== "465650873650118659") { - await interaction.editReply({ - content: - // eslint-disable-next-line stylistic/max-len -- This is a single string. - "Only Naomi can use this app. Sorry! Feel free to join our Discord? https://chat.nhcarrigan.com", - }); - return; - } - - const action = interaction.options.getString("action", true); - const platform = interaction.options.getString("platform", true); - const uuid = interaction.options.getString("username", true); - const reason = interaction.options.getString("reason", true); - - const number = await app.database.sanctions.count() + 1; - await app.database.sanctions.create({ - data: { - action, - number, - platform, - reason, - uuid, - }, - }); - await interaction.editReply({ - content: `Logged ${action} #${String( - number, - )} on ${platform} for user ${uuid}.`, - }); - } catch (error) { - await errorHandler("log command", error); - await interaction.editReply({ - content: - "An error occurred while processing your command. Please try again.", - }); - } - }, -}; diff --git a/src/commands/revoke.ts b/src/commands/revoke.ts deleted file mode 100644 index a3d151d..0000000 --- a/src/commands/revoke.ts +++ /dev/null @@ -1,84 +0,0 @@ -/** - * @copyright nhcarrigan - * @license Naomi's Public License - * @author Naomi Carrigan - */ -import { - ApplicationIntegrationType, - InteractionContextType, - SlashCommandBuilder, -} from "discord.js"; -import { errorHandler } from "../utils/errorHandler.js"; -import type { Command } from "../interfaces/command.js"; - -export const revoke: Command = { - data: new SlashCommandBuilder(). - setName("revoke"). - setDescription("Revoke a moderation action."). - setContexts([ - InteractionContextType.BotDM, - InteractionContextType.Guild, - InteractionContextType.PrivateChannel, - ]). - setIntegrationTypes([ ApplicationIntegrationType.UserInstall ]). - addIntegerOption((option) => { - return option. - setName("case"). - setDescription("The case number to revoke."). - setRequired(true); - }). - addStringOption((option) => { - return option. - setName("reason"). - setDescription("The reason for revoking the case."). - setRequired(true); - }), - run: async(app, interaction) => { - try { - await interaction.deferReply({ ephemeral: true }); - if (interaction.user.id !== "465650873650118659") { - await interaction.editReply({ - content: - // eslint-disable-next-line stylistic/max-len -- This is a single string. - "Only Naomi can use this app. Sorry! Feel free to join our Discord? https://chat.nhcarrigan.com", - }); - return; - } - - const number = interaction.options.getInteger("case", true); - const reason = interaction.options.getString("reason", true); - - const exists = await app.database.sanctions.findUnique({ - where: { number }, - }); - - if (!exists) { - await interaction.editReply({ - content: `Case ${String(number)} does not exist.`, - }); - return; - } - - await app.database.sanctions.update({ - data: { - revokeDate: new Date(), - revokeReason: reason, - revoked: true, - }, - where: { - number, - }, - }); - - await interaction.editReply({ - content: `Revoked action ${String(number)} for ${reason}.`, - }); - } catch (error) { - await errorHandler("log command", error); - await interaction.editReply({ - content: - "An error occurred while processing your command. Please try again.", - }); - } - }, -}; diff --git a/src/config/form.ts b/src/config/form.ts new file mode 100644 index 0000000..ce7ea5d --- /dev/null +++ b/src/config/form.ts @@ -0,0 +1,74 @@ +/** + * @copyright nhcarrigan + * @license Naomi's Public License + * @author Naomi Carrigan + */ + +const formHtml = ` + + +
+This page allows our staff to log an official sanction from one of our platforms.
+This page allows our staff to indicate a sanction has been successfully appealed.
+This page lists all of our community moderation sanctions.
+This log was last updated at {{ timestamp }}.
${sanction.uuid}
${sanction.reason}
+Performed by: ${sanction.moderator} on ${sanction.date.toLocaleString("en-GB")}
Revoked:
-${sanction.revokeReason ?? "Undocumented."}
+${sanction.revokeReason}
+Revoked by: ${ + sanction.revokedBy + } on ${sanction.revokeDate.toLocaleString("en-GB")}
${sanction.uuid}
${sanction.reason}
+Performed by: ${sanction.moderator} on ${sanction.date.toLocaleString("en-GB")}