From 6fb3e07eab64d65e3d68b90c73f08496beeea2e5 Mon Sep 17 00:00:00 2001 From: pineafan Date: Fri, 20 May 2022 19:27:23 +0100 Subject: [PATCH] changes to how deleting tickets works, and UI when creating mod tickets --- .gitignore | 5 +- ClicksMigratingProblems/index.js | 147 ++++++++ ClicksMigratingProblems/package-lock.json | 389 ++++++++++++++++++++++ ClicksMigratingProblems/package.json | 16 + package.json | 1 + src/automations/createModActionTicket.ts | 3 +- src/automations/tickets/delete.ts | 154 +++++---- src/commands/mod/mute.ts | 1 - src/commands/mod/nick.ts | 8 +- src/commands/mod/purge.ts | 1 - src/commands/mod/unnamed.ts | 6 +- src/commands/mod/warn.ts | 10 +- src/config/default.json | 108 ++++++ src/index.ts | 11 +- src/utils/client.ts | 9 + src/utils/confirmationMessage.ts | 54 ++- src/utils/database.ts | 180 ++++++++++ src/utils/memory.ts | 2 +- src/utils/readConfig.ts | 164 +-------- 19 files changed, 995 insertions(+), 274 deletions(-) create mode 100644 ClicksMigratingProblems/index.js create mode 100644 ClicksMigratingProblems/package-lock.json create mode 100644 ClicksMigratingProblems/package.json create mode 100644 src/config/default.json create mode 100644 src/utils/client.ts create mode 100644 src/utils/database.ts diff --git a/.gitignore b/.gitignore index fcc5e39..72a0e85 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,7 @@ yarn.lock src/utils/temp/*.png src/utils/temp/*.webp src/utils/temp/*.jpeg -src/utils/temp/*.jpg \ No newline at end of file +src/utils/temp/*.jpg + +ClicksMigratingProblems/oldData/ +ClicksMigratingProblems/oldData copy/ \ No newline at end of file diff --git a/ClicksMigratingProblems/index.js b/ClicksMigratingProblems/index.js new file mode 100644 index 0000000..3c70cc2 --- /dev/null +++ b/ClicksMigratingProblems/index.js @@ -0,0 +1,147 @@ +import fs from 'fs'; +import { MongoClient } from 'mongodb'; + +const mongoClient = new MongoClient('mongodb://127.0.0.1:27017/local'); +await mongoClient.connect() +const database = mongoClient.db("Nucleus"); +const collection = database.collection("migrationTesting"); + +// Loop through all files in the oldData folder +const files = fs.readdirSync('./oldData'); +let x = 0 +for (const file of files) { + console.log(`┌ Processing file ${x} of ${files.length - 1} | ${file}`); + // Read the file as a json + let data + try { + data = JSON.parse(fs.readFileSync(`./oldData/${file}`)); + } catch { + console.log(`└ Error reading file ${file}`); + x++ + continue; + } + // Check if data version is 3 + if (data.version !== 3) { + console.log(`├ Version was too old on ${file}`); + console.log(`└ Skipping file`); + x++; + continue + } + // Convert to the new format + const newData = { + "id": data.guild_info.id.toString(), + "version": 1, + "singleEventNotifications": { + "statsChannelDeleted": false + }, + "filters": { + "images": { + "NSFW": !data.images.nsfw, + "size": data.images.toosmall + }, + "wordFilter": { + "enabled": true, + "words": { + "strict": data.wordfilter.strict, + "loose": data.wordfilter.soft + }, + "allowed": { + "users": data.wordfilter.ignore.members.map(user => user.toString()), + "roles": data.wordfilter.ignore.roles.map(role => role.toString()), + "channels": data.wordfilter.ignore.channels.map(channel => channel.toString()) + } + }, + "invite": { + "enabled": data.invite ? data.invite.enabled : false, + "allowed": { + "users": data.invite ? data.invite.whitelist.members.map(user => user.toString()) : [], + "channels": data.invite ? data.invite.whitelist.channels.map(channel => channel.toString()) : [], + "roles": data.invite ? data.invite.whitelist.roles.map(role => role.toString()) : [] + } + }, + "pings": { + "mass": 5, + "everyone": true, + "roles": true, + "allowed": { + "roles": [], + "rolesToMention": null, + "users": null, + "channels": null + } + } + }, + "welcome": { + "enabled": data.welcome ? (data.welcome.message.text !== null) : false, + "verificationRequired": { + "message": null, + "role": null, + }, + "welcomeRole": data.welcome ? (data.welcome.role !== null ? data.welcome.role.toString() : null) : null, + "channel": data.welcome ? (data.welcome.message.text !== null ? data.welcome.message.channel.toString() : null) : null, + "message": data.welcome ? (data.welcome.message.text) : null + }, + "stats": [], + "logging": { + "logs": { + "enabled": true, + "channel": data.log_info.log_channel ? data.log_info.log_channel.toString() : null, + "toLog": "3fffff" + }, + "staff": { + "channel": data.log_info.staff ? data.log_info.staff.toString() : null, + } + }, + "verify": { + "enabled": data.verify_role !== null, + "role": data.verify_role ? data.verify_role.toString() : null, + }, + "tickets": { + "enabled": data.modmail ? (data.modmail.cat !== null) : null, + "category": data.modmail ? (data.modmail.cat !== null ? data.modmail.cat.toString() : null) : null, + "types": "3f", + "customTypes": null, + "supportRole": data.modmail ? (data.modmail.mention !== null ? data.modmail.mention.toString() : null) : null, + "maxTickets": data.modmail ? (data.modmail.max) : 5 + }, + "moderation": { + "mute": { + "timeout": true, + "role": null, + "text": null, + "link": null + }, + "kick": { + "text": null, + "link": null + }, + "ban": { + "text": null, + "link": null + }, + "softban": { + "text": null, + "link": null + }, + "warn": { + "text": null, + "link": null + }, + "role": { + "role": null + } + }, + "tracks": [], + "roleMenu": [], + "tags": data.tags + } + // Insert the new data into the database + await collection.updateOne({ id: data.guild_info.id.toString() }, { $set: newData }, { upsert: true }); + // Delete the old file + fs.unlinkSync(`./oldData/${file}`); + console.log(`└ Successfully migrated file ${file}`); + x++; +} + + +// console.log((await collection.findOne({ id: "your mother" }))); diff --git a/ClicksMigratingProblems/package-lock.json b/ClicksMigratingProblems/package-lock.json new file mode 100644 index 0000000..d7c59c6 --- /dev/null +++ b/ClicksMigratingProblems/package-lock.json @@ -0,0 +1,389 @@ +{ + "name": "hi", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "hi", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "fs": "^0.0.1-security", + "mongodb": "^4.7.0" + } + }, + "node_modules/@types/node": { + "version": "17.0.41", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.41.tgz", + "integrity": "sha512-xA6drNNeqb5YyV5fO3OAEsnXLfO7uF0whiOfPTz5AeDo8KeZFmODKnvwPymMNO8qE/an8pVY/O50tig2SQCrGw==" + }, + "node_modules/@types/webidl-conversions": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-6.1.1.tgz", + "integrity": "sha512-XAahCdThVuCFDQLT7R7Pk/vqeObFNL3YqRyFZg+AqAP/W1/w3xHaIxuW7WszQqTbIBOPRcItYJIou3i/mppu3Q==" + }, + "node_modules/@types/whatwg-url": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.1.tgz", + "integrity": "sha512-2YubE1sjj5ifxievI5Ge1sckb9k/Er66HyR2c+3+I6VDUUg1TLPdYYTEbQ+DjRkS4nTxMJhgWfSfMRD2sl2EYQ==", + "dependencies": { + "@types/node": "*", + "@types/webidl-conversions": "*" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bson": { + "version": "4.6.4", + "resolved": "https://registry.npmjs.org/bson/-/bson-4.6.4.tgz", + "integrity": "sha512-TdQ3FzguAu5HKPPlr0kYQCyrYUYh8tFM+CMTpxjNzVzxeiJY00Rtuj3LXLHSgiGvmaWlZ8PE+4KyM2thqE38pQ==", + "dependencies": { + "buffer": "^5.6.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/denque": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.0.1.tgz", + "integrity": "sha512-tfiWc6BQLXNLpNiR5iGd0Ocu3P3VpxfzFiqubLgMfhfOw9WyvgJBd46CClNn9k3qfbjvT//0cf7AlYRX/OslMQ==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/fs": { + "version": "0.0.1-security", + "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz", + "integrity": "sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w==" + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ip": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", + "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==" + }, + "node_modules/memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "optional": true + }, + "node_modules/mongodb": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.7.0.tgz", + "integrity": "sha512-HhVar6hsUeMAVlIbwQwWtV36iyjKd9qdhY+s4wcU8K6TOj4Q331iiMy+FoPuxEntDIijTYWivwFJkLv8q/ZgvA==", + "dependencies": { + "bson": "^4.6.3", + "denque": "^2.0.1", + "mongodb-connection-string-url": "^2.5.2", + "socks": "^2.6.2" + }, + "engines": { + "node": ">=12.9.0" + }, + "optionalDependencies": { + "saslprep": "^1.0.3" + } + }, + "node_modules/mongodb-connection-string-url": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.5.2.tgz", + "integrity": "sha512-tWDyIG8cQlI5k3skB6ywaEA5F9f5OntrKKsT/Lteub2zgwSUlhqEN2inGgBTm8bpYJf8QYBdA/5naz65XDpczA==", + "dependencies": { + "@types/whatwg-url": "^8.2.1", + "whatwg-url": "^11.0.0" + } + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/saslprep": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", + "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", + "optional": true, + "dependencies": { + "sparse-bitfield": "^3.0.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz", + "integrity": "sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==", + "dependencies": { + "ip": "^1.1.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "optional": true, + "dependencies": { + "memory-pager": "^1.0.2" + } + }, + "node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + } + }, + "dependencies": { + "@types/node": { + "version": "17.0.41", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.41.tgz", + "integrity": "sha512-xA6drNNeqb5YyV5fO3OAEsnXLfO7uF0whiOfPTz5AeDo8KeZFmODKnvwPymMNO8qE/an8pVY/O50tig2SQCrGw==" + }, + "@types/webidl-conversions": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-6.1.1.tgz", + "integrity": "sha512-XAahCdThVuCFDQLT7R7Pk/vqeObFNL3YqRyFZg+AqAP/W1/w3xHaIxuW7WszQqTbIBOPRcItYJIou3i/mppu3Q==" + }, + "@types/whatwg-url": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.1.tgz", + "integrity": "sha512-2YubE1sjj5ifxievI5Ge1sckb9k/Er66HyR2c+3+I6VDUUg1TLPdYYTEbQ+DjRkS4nTxMJhgWfSfMRD2sl2EYQ==", + "requires": { + "@types/node": "*", + "@types/webidl-conversions": "*" + } + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "bson": { + "version": "4.6.4", + "resolved": "https://registry.npmjs.org/bson/-/bson-4.6.4.tgz", + "integrity": "sha512-TdQ3FzguAu5HKPPlr0kYQCyrYUYh8tFM+CMTpxjNzVzxeiJY00Rtuj3LXLHSgiGvmaWlZ8PE+4KyM2thqE38pQ==", + "requires": { + "buffer": "^5.6.0" + } + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "denque": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.0.1.tgz", + "integrity": "sha512-tfiWc6BQLXNLpNiR5iGd0Ocu3P3VpxfzFiqubLgMfhfOw9WyvgJBd46CClNn9k3qfbjvT//0cf7AlYRX/OslMQ==" + }, + "fs": { + "version": "0.0.1-security", + "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz", + "integrity": "sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w==" + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, + "ip": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", + "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==" + }, + "memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "optional": true + }, + "mongodb": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.7.0.tgz", + "integrity": "sha512-HhVar6hsUeMAVlIbwQwWtV36iyjKd9qdhY+s4wcU8K6TOj4Q331iiMy+FoPuxEntDIijTYWivwFJkLv8q/ZgvA==", + "requires": { + "bson": "^4.6.3", + "denque": "^2.0.1", + "mongodb-connection-string-url": "^2.5.2", + "saslprep": "^1.0.3", + "socks": "^2.6.2" + } + }, + "mongodb-connection-string-url": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.5.2.tgz", + "integrity": "sha512-tWDyIG8cQlI5k3skB6ywaEA5F9f5OntrKKsT/Lteub2zgwSUlhqEN2inGgBTm8bpYJf8QYBdA/5naz65XDpczA==", + "requires": { + "@types/whatwg-url": "^8.2.1", + "whatwg-url": "^11.0.0" + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "saslprep": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", + "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", + "optional": true, + "requires": { + "sparse-bitfield": "^3.0.3" + } + }, + "smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==" + }, + "socks": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz", + "integrity": "sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==", + "requires": { + "ip": "^1.1.5", + "smart-buffer": "^4.2.0" + } + }, + "sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "optional": true, + "requires": { + "memory-pager": "^1.0.2" + } + }, + "tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "requires": { + "punycode": "^2.1.1" + } + }, + "webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==" + }, + "whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "requires": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + } + } + } +} diff --git a/ClicksMigratingProblems/package.json b/ClicksMigratingProblems/package.json new file mode 100644 index 0000000..a4a5ec5 --- /dev/null +++ b/ClicksMigratingProblems/package.json @@ -0,0 +1,16 @@ +{ + "name": "hi", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "fs": "^0.0.1-security", + "mongodb": "^4.7.0" + }, + "type": "module" +} diff --git a/package.json b/package.json index 7287aef..9706070 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "humanize-duration": "^3.27.1", "jshaiku": "file:../haiku", "json-diff": "^0.7.1", + "mongodb": "^4.7.0", "node-tesseract": "^0.2.7", "structured-clone": "^0.2.2", "tesseract.js": "^2.1.5", diff --git a/src/automations/createModActionTicket.ts b/src/automations/createModActionTicket.ts index 4de2924..ef317b7 100644 --- a/src/automations/createModActionTicket.ts +++ b/src/automations/createModActionTicket.ts @@ -3,7 +3,7 @@ import readConfig from '../utils/readConfig.js' import generateEmojiEmbed from '../utils/generateEmojiEmbed.js'; import getEmojiByName from "../utils/getEmojiByName.js"; -export async function create(guild: Discord.Guild, member: Discord.User, client) { +export async function create(guild: Discord.Guild, member: Discord.User, createdBy: Discord.User, client) { let config = await readConfig(guild.id); // @ts-ignore const { log, NucleusColors, entry, renderUser, renderChannel, renderDelta } = client.logger @@ -70,6 +70,7 @@ export async function create(guild: Discord.Guild, member: Discord.User, client) }, list: { ticketFor: entry(member.id, renderUser(member)), + createdBy: entry(createdBy.id, renderUser(createdBy)), created: entry(new Date().getTime(), renderDelta(new Date().getTime())), ticketChannel: entry(c.id, renderChannel(c)), }, diff --git a/src/automations/tickets/delete.ts b/src/automations/tickets/delete.ts index 32315bc..17d889a 100644 --- a/src/automations/tickets/delete.ts +++ b/src/automations/tickets/delete.ts @@ -11,7 +11,7 @@ export default async function (interaction) { let channel = (interaction.channel as Discord.TextChannel) if (!channel.parent || config.tickets.category != channel.parent.id) { return interaction.reply({embeds: [new generateEmojiEmbed() - .setTitle("Close Ticket") + .setTitle("Deleting Ticket...") .setDescription("This ticket is not in your tickets category, so cannot be deleted. You cannot run close in a thread.") // TODO bridge to cross later! .setStatus("Danger") .setEmoji("CONTROL.BLOCKCROSS") @@ -19,96 +19,92 @@ export default async function (interaction) { } let status = channel.topic.split(" ")[1]; if (status == "Archived") { - interaction.reply({embeds: [new generateEmojiEmbed() - .setTitle("Close Ticket") - .setDescription("This ticket will be deleted in 3 seconds.") + await interaction.reply({embeds: [new generateEmojiEmbed() + .setTitle("Delete Ticket") + .setDescription("Your ticket is being deleted...") .setStatus("Danger") .setEmoji("GUILD.TICKET.CLOSE") ]}); - setTimeout(async () => { - let data = { - meta:{ - type: 'ticketClosed', - displayName: 'Ticket Closed', - calculateType: true, - color: NucleusColors.red, - emoji: 'GUILD.TICKET.CLOSE', - timestamp: new Date().getTime() - }, - list: { - ticketFor: entry(channel.topic.split(" ")[0], renderUser((await interaction.guild.members.fetch(channel.topic.split(" ")[0])).user)), - closedBy: entry(interaction.member.user.id, renderUser(interaction.member.user)), - closed: entry(new Date().getTime(), renderDelta(new Date().getTime())) - }, - hidden: { - guild: interaction.guild.id - } + let data = { + meta:{ + type: 'ticketDeleted', + displayName: 'Ticket Deleted', + calculateType: true, + color: NucleusColors.red, + emoji: 'GUILD.TICKET.CLOSE', + timestamp: new Date().getTime() + }, + list: { + ticketFor: entry(channel.topic.split(" ")[0], renderUser((await interaction.guild.members.fetch(channel.topic.split(" ")[0])).user)), + deletedBy: entry(interaction.member.user.id, renderUser(interaction.member.user)), + closed: entry(new Date().getTime(), renderDelta(new Date().getTime())) + }, + hidden: { + guild: interaction.guild.id } - log(data, interaction.client); - interaction.channel.delete(); - }, 3000); + } + log(data, interaction.client); + interaction.channel.delete(); return; } else if (status == "Active") { - interaction.reply({embeds: [new generateEmojiEmbed() + await interaction.reply({embeds: [new generateEmojiEmbed() .setTitle("Close Ticket") - .setDescription("This ticket will be archived in 3 seconds.") + .setDescription("Your ticket is being closed...") .setStatus("Warning") .setEmoji("GUILD.TICKET.ARCHIVED") ]}); - setTimeout(async () =>{ - let overwrites = [ - { - id: channel.topic.split(" ")[0], - deny: ["VIEW_CHANNEL"], - type: "member" - }, - { - id: interaction.guild.id, - deny: ["VIEW_CHANNEL"], - type: "role" - } - ] as Discord.OverwriteResolvable[]; - if (config.tickets.supportRole != null) { - overwrites.push({ - id: interaction.guild.roles.cache.get(config.tickets.supportRole), - allow: ["VIEW_CHANNEL", "SEND_MESSAGES", "ATTACH_FILES", "ADD_REACTIONS", "READ_MESSAGE_HISTORY"], - type: "role" - }) + let overwrites = [ + { + id: channel.topic.split(" ")[0], + deny: ["VIEW_CHANNEL"], + type: "member" + }, + { + id: interaction.guild.id, + deny: ["VIEW_CHANNEL"], + type: "role" } - channel.edit({permissionOverwrites: overwrites}) - channel.setTopic(`${channel.topic.split(" ")[0]} Archived`); - let data = { - meta:{ - type: 'ticketArchive', - displayName: 'Ticket Archived', - calculateType: true, - color: NucleusColors.yellow, - emoji: 'GUILD.TICKET.ARCHIVED', - timestamp: new Date().getTime() - }, - list: { - ticketFor: entry(channel.topic.split(" ")[0], renderUser((await interaction.guild.members.fetch(channel.topic.split(" ")[0])).user)), - archivedBy: entry(interaction.member.user.id, renderUser(interaction.member.user)), - archived: entry(new Date().getTime(), renderDelta(new Date().getTime())), - ticketChannel: entry(channel.id, renderChannel(channel)), - }, - hidden: { - guild: interaction.guild.id - } + ] as Discord.OverwriteResolvable[]; + if (config.tickets.supportRole != null) { + overwrites.push({ + id: interaction.guild.roles.cache.get(config.tickets.supportRole), + allow: ["VIEW_CHANNEL", "SEND_MESSAGES", "ATTACH_FILES", "ADD_REACTIONS", "READ_MESSAGE_HISTORY"], + type: "role" + }) + } + channel.edit({permissionOverwrites: overwrites}) + channel.setTopic(`${channel.topic.split(" ")[0]} Archived`); + let data = { + meta:{ + type: 'ticketClosed', + displayName: 'Ticket Closed', + calculateType: true, + color: NucleusColors.yellow, + emoji: 'GUILD.TICKET.ARCHIVED', + timestamp: new Date().getTime() + }, + list: { + ticketFor: entry(channel.topic.split(" ")[0], renderUser((await interaction.guild.members.fetch(channel.topic.split(" ")[0])).user)), + closedBy: entry(interaction.member.user.id, renderUser(interaction.member.user)), + closed: entry(new Date().getTime(), renderDelta(new Date().getTime())), + ticketChannel: entry(channel.id, renderChannel(channel)), + }, + hidden: { + guild: interaction.guild.id } - log(data, interaction.client); - await interaction.editReply({embeds: [new generateEmojiEmbed() - .setTitle("Close Ticket") - .setDescription("This ticket has been archived.\nType `/ticket close` to delete it.") - .setStatus("Warning") - .setEmoji("GUILD.TICKET.ARCHIVED") // TODO:[Premium] Add a transcript option ||\----/|| <- the bridge we will cross when we come to it - ], components: [new MessageActionRow().addComponents([new MessageButton() - .setLabel("Close") - .setStyle("DANGER") - .setCustomId("closeticket") - .setEmoji(getEmojiByName("CONTROL.CROSS", "id")) - ])]}); - }, 3000); + } + log(data, interaction.client); + await interaction.editReply({embeds: [new generateEmojiEmbed() + .setTitle("Close Ticket") + .setDescription("This ticket has been closed.\nType `/ticket close` again to delete it.") + .setStatus("Warning") + .setEmoji("GUILD.TICKET.ARCHIVED") // TODO:[Premium] Add a transcript option ||\----/|| <- the bridge we will cross when we come to it + ], components: [new MessageActionRow().addComponents([new MessageButton() + .setLabel("Delete") + .setStyle("DANGER") + .setCustomId("closeticket") + .setEmoji(getEmojiByName("CONTROL.CROSS", "id")) + ])]}); return; } } diff --git a/src/commands/mod/mute.ts b/src/commands/mod/mute.ts index d81a5cc..b2cc94e 100644 --- a/src/commands/mod/mute.ts +++ b/src/commands/mod/mute.ts @@ -6,7 +6,6 @@ import getEmojiByName from "../../utils/getEmojiByName.js"; import confirmationMessage from "../../utils/confirmationMessage.js"; import keyValueList from "../../utils/generateKeyValueList.js"; import humanizeDuration from "humanize-duration"; -import { create, areTicketsEnabled } from "../../automations/createModActionTicket.js"; import readConfig from "../../utils/readConfig.js"; const command = (builder: SlashCommandSubcommandBuilder) => diff --git a/src/commands/mod/nick.ts b/src/commands/mod/nick.ts index cd3a7af..e8463f4 100644 --- a/src/commands/mod/nick.ts +++ b/src/commands/mod/nick.ts @@ -29,10 +29,10 @@ const callback = async (interaction: CommandInteraction) => { + `The user **will${interaction.options.getString("notify") == "yes" ? '' : ' not'}** be notified\n\n` + `Are you sure you want to ${interaction.options.getString("name") ? "change" : "clear"} <@!${(interaction.options.getMember("user") as GuildMember).id}>'s nickname?`) .setColor("Danger") - .addCustomCallback( + .addCustomBoolean( "Create appeal ticket", !(await areTicketsEnabled(interaction.guild.id)), - () => { create(interaction.guild, interaction.options.getUser("user"), interaction.client)}, - "An appeal ticket was created") + async () => await create(interaction.guild, interaction.options.getUser("user"), interaction.user, interaction.client), + "An appeal ticket will be created when Confirm is clicked") // pluralize("day", interaction.options.getInteger("delete")) // const pluralize = (word: string, count: number) => { return count === 1 ? word : word + "s" } .send() @@ -96,7 +96,7 @@ const callback = async (interaction: CommandInteraction) => { await interaction.editReply({embeds: [new generateEmojiEmbed() .setEmoji(`PUNISH.NICKNAME.${failed ? "YELLOW" : "GREEN"}`) .setTitle(`Nickname`) - .setDescription("The members nickname was changed" + (failed ? ", but was not notified" : "")) + .setDescription("The members nickname was changed" + (failed ? ", but was not notified" : "") + (confirmation.response ? ` and an appeal ticket was opened in <#${confirmation.response}>` : ``)) .setStatus(failed ? "Warning" : "Success") ], components: []}) } else { diff --git a/src/commands/mod/purge.ts b/src/commands/mod/purge.ts index e388ea0..924e507 100644 --- a/src/commands/mod/purge.ts +++ b/src/commands/mod/purge.ts @@ -5,7 +5,6 @@ import confirmationMessage from "../../utils/confirmationMessage.js"; import generateEmojiEmbed from "../../utils/generateEmojiEmbed.js"; import keyValueList from "../../utils/generateKeyValueList.js"; import getEmojiByName from "../../utils/getEmojiByName.js"; -import { create, areTicketsEnabled } from "../../automations/createModActionTicket.js"; const command = (builder: SlashCommandSubcommandBuilder) => builder diff --git a/src/commands/mod/unnamed.ts b/src/commands/mod/unnamed.ts index 20ebc30..ca0bcef 100644 --- a/src/commands/mod/unnamed.ts +++ b/src/commands/mod/unnamed.ts @@ -129,10 +129,10 @@ const callback = async (interaction: CommandInteraction) => { + `The user **will${interaction.options.getString("notify") === "no" ? ' not' : ''}** be notified\n\n` + `Are you sure you want to mute <@!${(interaction.options.getMember("user") as GuildMember).id}>?`) // TODO .setColor("Danger") - .addCustomCallback( + .addCustomBoolean( "Create appeal ticket", !(await areTicketsEnabled(interaction.guild.id)), - () => { create(interaction.guild, interaction.options.getUser("user"), interaction.client)}, - "An appeal ticket was created") + async () => await create(interaction.guild, interaction.options.getUser("user"), interaction.user, interaction.client), + "An appeal ticket will be created when Confirm is clicked") // pluralize("day", interaction.options.getInteger("delete")) // const pluralize = (word: string, count: number) => { return count === 1 ? word : word + "s" } .send() diff --git a/src/commands/mod/warn.ts b/src/commands/mod/warn.ts index 3f63cce..ce54cfb 100644 --- a/src/commands/mod/warn.ts +++ b/src/commands/mod/warn.ts @@ -30,10 +30,10 @@ const callback = async (interaction: CommandInteraction) => { + `The user **will${interaction.options.getString("notify") === "no" ? ' not' : ''}** be notified\n\n` + `Are you sure you want to warn <@!${(interaction.options.getMember("user") as GuildMember).id}>?`) .setColor("Danger") - .addCustomCallback( + .addCustomBoolean( "Create appeal ticket", !(await areTicketsEnabled(interaction.guild.id)), - () => { create(interaction.guild, interaction.options.getUser("user"), interaction.client)}, - "An appeal ticket was created") + async () => await create(interaction.guild, interaction.options.getUser("user"), interaction.user, interaction.client), + "An appeal ticket will be created when Confirm is clicked") // pluralize("day", interaction.options.getInteger("delete")) // const pluralize = (word: string, count: number) => { return count === 1 ? word : word + "s" } .send() @@ -85,7 +85,7 @@ const callback = async (interaction: CommandInteraction) => { await interaction.editReply({embeds: [new generateEmojiEmbed() .setEmoji(`PUNISH.WARN.GREEN`) .setTitle(`Warn`) - .setDescription("The user was warned") + .setDescription("The user was warned" + (confirmation.response ? ` and an appeal ticket was opened in <#${confirmation.response}>` : ``)) .setStatus("Success") ], components: []}) } else { @@ -135,7 +135,7 @@ const callback = async (interaction: CommandInteraction) => { return await interaction.editReply({embeds: [new generateEmojiEmbed() .setEmoji(`PUNISH.WARN.GREEN`) .setTitle(`Warn`) - .setDescription("The user was warned") + .setDescription("The user was warned" + (confirmation.response ? ` and an appeal ticket was opened in <#${confirmation.response}>` : ``)) .setStatus("Success") ], components: []}) } else { diff --git a/src/config/default.json b/src/config/default.json new file mode 100644 index 0000000..129bfe9 --- /dev/null +++ b/src/config/default.json @@ -0,0 +1,108 @@ +{ + "id": "default", + "version": 1, + "singleEventNotifications": { + "statsChannelDeleted": false + }, + "filters": { + "images": { + "NSFW": false, + "size": false + }, + "malware": false, + "wordFilter": { + "enabled": false, + "words": { + "strict": [], + "loose": [] + }, + "allowed": { + "users": [], + "roles": [], + "channels": [] + } + }, + "invite": { + "enabled": false, + "allowed": { + "users": [], + "channels": [], + "roles": [] + } + }, + "pings": { + "mass": 5, + "everyone": true, + "roles": true, + "allowed": { + "roles": [], + "rolesToMention": [], + "users": [], + "channels": [] + } + } + }, + "welcome": { + "enabled": false, + "verificationRequired": { + "message": null, + "role": null + }, + "welcomeRole": null, + "channel": null, + "message": null + }, + "stats": [], + "logging": { + "logs": { + "enabled": true, + "channel": null, + "toLog": "3fffff" + }, + "staff": { + "channel": null + } + }, + "verify": { + "enabled": false, + "role": null + }, + "tickets": { + "enabled": false, + "category": null, + "types": "3f", + "customTypes": null, + "supportRole": null, + "maxTickets": 5 + }, + "moderation": { + "mute": { + "timeout": true, + "role": null, + "text": null, + "link": null + }, + "kick": { + "text": null, + "link": null + }, + "ban": { + "text": null, + "link": null + }, + "softban": { + "text": null, + "link": null + }, + "warn": { + "text": null, + "link": null + }, + "role": { + "role": null + } + }, + "tracks": [], + "roleMenu": [], + "tags": {} +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 306c5ee..2616f40 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,13 +1,10 @@ -import { HaikuClient } from 'jshaiku'; -import { Intents } from 'discord.js'; + import config from './config/main.json' assert {type: 'json'}; import { Logger } from './utils/log.js'; import runServer from './api/index.js'; import Memory from './utils/memory.js'; - -const client = new HaikuClient({ - intents: new Intents(32767).bitfield, // This is a way of specifying all intents w/o having to type them out -}, config); +import Database from './utils/database.js'; +import client from './utils/client.js'; await client.registerCommandsIn("./commands"); await client.registerEventsIn("./events"); @@ -19,5 +16,7 @@ client.logger = new Logger() client.verify = {} client.roleMenu = {} client.memory = new Memory() +client.database = await new Database(config.mongoUrl).connect() + await client.login(); \ No newline at end of file diff --git a/src/utils/client.ts b/src/utils/client.ts new file mode 100644 index 0000000..3f4a8a1 --- /dev/null +++ b/src/utils/client.ts @@ -0,0 +1,9 @@ +import { HaikuClient } from 'jshaiku'; +import { Intents } from 'discord.js'; +import config from '../config/main.json' assert {type: 'json'}; + +const client = new HaikuClient({ + intents: new Intents(32767).bitfield, // This is a way of specifying all intents w/o having to type them out +}, config); + +export default client; \ No newline at end of file diff --git a/src/utils/confirmationMessage.ts b/src/utils/confirmationMessage.ts index dd97603..7a06d83 100644 --- a/src/utils/confirmationMessage.ts +++ b/src/utils/confirmationMessage.ts @@ -14,6 +14,8 @@ class confirmationMessage { customCallbackString: string = ""; customCallbackClicked: boolean = false; customCallbackResponse: any = null; + customBoolean: () => any; + customBooleanClicked: boolean = null; inverted: boolean; constructor(interaction: CommandInteraction) { @@ -23,8 +25,9 @@ class confirmationMessage { this.emoji = ""; this.description = ""; this.color = ""; - this.inverted = false - this.customCallback = () => {} + this.inverted = false; + this.customCallback = () => {}; + this.customBoolean = () => {}; } setTitle(title: string) { this.title = title; return this } @@ -33,12 +36,23 @@ class confirmationMessage { setColor(color: string) { this.color = color; return this } setInverted(inverted: boolean) { this.inverted = inverted; return this } addCustomCallback(title: string, disabled: boolean, callback: () => any, callbackClicked: string) { + if (this.customButtonTitle) return this this.customButtonTitle = title; this.customButtonDisabled = disabled; this.customCallback = callback; this.customCallbackString = callbackClicked; return this; } + addCustomBoolean(title: string, disabled: boolean, callback: () => any, callbackClicked: string) { + if (this.customButtonTitle) return this + this.customButtonTitle = title; + this.customButtonDisabled = disabled; + this.customBoolean = callback; + this.customCallbackString = callbackClicked; + this.customBooleanClicked = false; + return this; + } + async send(editOnly?: boolean) { while (true) { @@ -49,7 +63,7 @@ class confirmationMessage { .setTitle(this.title) .setDescription(this.description) .setStatus(this.color) - .setFooter({text: this.customCallbackClicked ? this.customCallbackString : ""}) + .setFooter({text: (this.customBooleanClicked ?? this.customCallbackClicked) ? this.customCallbackString : ""}) ], components: [ new MessageActionRow().addComponents([ @@ -66,7 +80,10 @@ class confirmationMessage { ].concat(this.customButtonTitle ? [new Discord.MessageButton() .setCustomId("custom") .setLabel(this.customButtonTitle) - .setStyle("PRIMARY") + .setStyle(this.customBooleanClicked !== null ? + ( this.customBooleanClicked ? "SUCCESS" : "PRIMARY" ) : + "PRIMARY" + ) .setDisabled(this.customButtonDisabled) .setEmoji(getEmojiByName("CONTROL.TICKET", "id")) ] : [])) @@ -84,19 +101,36 @@ class confirmationMessage { try { component = await (m as Message).awaitMessageComponent({filter: (m) => m.user.id === this.interaction.user.id, time: 2.5 * 60 * 1000}); } catch (e) { - return { success: false, buttonClicked: this.customCallbackClicked, response: this.customCallbackResponse }; + return { + success: false, + buttonClicked: this.customBooleanClicked ?? this.customCallbackClicked, + response: this.customCallbackResponse + }; } if (component.customId === "yes") { component.deferUpdate(); - return { success: true, buttonClicked: this.customCallbackClicked, response: this.customCallbackResponse }; + if (this.customBooleanClicked === true) this.customCallbackResponse = await this.customBoolean(); + return { + success: true, + buttonClicked: this.customBooleanClicked ?? this.customCallbackClicked, + response: this.customCallbackResponse + }; } else if (component.customId === "no") { component.deferUpdate(); - return { success: false, buttonClicked: this.customCallbackClicked, response: this.customCallbackResponse }; + return { + success: false, + buttonClicked: this.customBooleanClicked ?? this.customCallbackClicked, + response: this.customCallbackResponse + }; } else if (component.customId === "custom") { component.deferUpdate(); - this.customCallbackResponse = this.customCallback(); - this.customCallbackClicked = true; - this.customButtonDisabled = true; + if (this.customBooleanClicked !== null) { + this.customBooleanClicked = !this.customBooleanClicked; + } else { + this.customCallbackResponse = await this.customCallback(); + this.customCallbackClicked = true; + this.customButtonDisabled = true; + } editOnly = true; } } diff --git a/src/utils/database.ts b/src/utils/database.ts new file mode 100644 index 0000000..53ccb97 --- /dev/null +++ b/src/utils/database.ts @@ -0,0 +1,180 @@ +import { Collection, Db, MongoClient } from 'mongodb'; + + +export const Entry = data => { + data = data ?? {}; + return { + get(target, prop, receiver) { + let dataToReturn = data[prop] + if (dataToReturn === null ) return Reflect.get(target, prop, receiver); + if (typeof dataToReturn === "object" && !Array.isArray(dataToReturn)) dataToReturn = new Proxy( + Reflect.get(target, prop, receiver), + Entry(dataToReturn), + ) + return dataToReturn ?? Reflect.get(target, prop, receiver); + } + } +} + + +export default class Database { + mongoClient: MongoClient; + database: Db; + guilds: Collection; + defaultData: GuildConfig; + + constructor(url) { + this.mongoClient = new MongoClient(url); + } + + async connect() { + await this.mongoClient.connect() + this.database = this.mongoClient.db("Nucleus"); + this.guilds = this.database.collection("guilds"); + await this.guilds.createIndex({ id: "text" }, { unique: true }); + this.defaultData = (await import("../config/default.json", { assert: { type: "json" }})).default as unknown as GuildConfig; + return this; + } + + async read(guild: string) { + let entry = await this.guilds.findOne({ id: guild }); + return new Proxy(this.defaultData, Entry(entry)) as unknown as GuildConfig + } + + async write(guild: string, config: GuildConfig) { + await this.guilds.updateOne({ id: guild }, { $set: config }, { upsert: true }); + } +} + +export interface GuildConfig { + id: string, + version: number, + singleEventNotifications: { + statsChannelDeleted: boolean + } + filters: { + images: { + NSFW: boolean, + size: boolean + }, + malware: boolean, + wordFilter: { + enabled: boolean, + words: { + strict: string[], + loose: string[] + }, + allowed: { + users: string[], + roles: string[], + channels: string[] + } + }, + invite: { + enabled: boolean, + allowed: { + users: string[], + channels: string[], + roles: string[] + } + }, + pings: { + mass: number, + everyone: boolean, + roles: boolean, + allowed: { + roles: string[], + rolesToMention: string[], + users: string[], + channels: string[] + } + } + } + welcome: { + enabled: boolean, + verificationRequired: { + message: boolean, + role: string + }, + welcomeRole: string, + channel: string, + message: string + } + stats: { + enabled: boolean, + channel: string, + text: string + }[] + logging: { + logs: { + enabled: boolean, + channel: string, + toLog: string + }, + staff: { + channel: string + } + } + verify: { + enabled: boolean, + role: string + } + tickets: { + enabled: boolean, + category: string, + types: string, + customTypes: string[], + supportRole: string, + maxTickets: number + } + moderation: { + mute: { + timeout: boolean, + role: string, + text: string, + link: string + }, + kick: { + text: string, + link: string + }, + ban: { + text: string, + link: string + }, + softban: { + text: string, + link: string + }, + warn: { + text: string, + link: string + }, + role: { + role: string + } + } + tracks: { + name: string, + retainPrevious: boolean, + nullable: boolean, + track: string[], + manageableBy: string[] + }[] + roleMenu: { + enabled: boolean, + allowWebUI: boolean, + options: { + name: string, + description: string, + min: number, + max: number, + options: { + name: string, + description: string, + role: string + }[] + }[] + } + tags: {} +}; \ No newline at end of file diff --git a/src/utils/memory.ts b/src/utils/memory.ts index a4f9501..0cbf955 100644 --- a/src/utils/memory.ts +++ b/src/utils/memory.ts @@ -14,7 +14,7 @@ class Memory { logging: guildData.logging, tickets: guildData.tickets, }; // TODO: REMOVE GUILD FROM MEMORY WHEN THESE UPDATE - } + } // TODO: Add a "lastAccessed" prop, delete after 15 minutes return this.memory[guild]; } } diff --git a/src/utils/readConfig.ts b/src/utils/readConfig.ts index 50cb6c6..b363fc0 100644 --- a/src/utils/readConfig.ts +++ b/src/utils/readConfig.ts @@ -1,165 +1,5 @@ +import client from './client.js'; export default async function readConfig(guild: string): Promise { - - let config = { - singleEventNotifications: { - statsChannelDeleted: false - }, - filters: { - images: { - NSFW: true, - size: true - }, - malware: true, - wordFilter: { - enabled: true, - words: { - strict: [], - loose: [] - }, - allowed: { - users: [], - roles: [], - channels: [] - } - }, - invite: { - enabled: false, - allowed: { - users: [], - channels: [], - roles: [] - } - }, - pings: { - mass: 5, - everyone: true, - roles: true, - allowed: { - roles: [], - rolesToMention: [], - users: [], - channels: [] - } - } - }, - welcome: { - enabled: true, - verificationRequired: { - message: false, - role: false - }, - welcomeRole: null, - channel: '895209752315961344', // null, channel ID or 'dm' - message: "Welcome to the server, {@}!" - }, - stats: [ - { - enabled: true, - channel: '951910554291818526', - text: "{count} members | {count:bots} bots | {count:humans} humans" - } - ], - logging: { - logs: { - enabled: true, - channel: '952247098437427260', - toLog: "3fffff" // "3ffffe" = - channelUpdate, "3fffff" = all - }, - staff: { - channel: "895212366252367933" - } - }, - verify: { - enabled: true, - role: '934941369137524816', - }, - tickets: { - enabled: true, - category: "952302254302584932", - types: "3f", - customTypes: null, - supportRole: null, - maxTickets: 5 - }, - moderation: { - mute: { - timeout: true, - role: "934941369137524816", // TODO: Remove this role after the time - text: null, - link: null - }, - kick: { - text: "Appeal here", - link: "https://clicks.codes" - }, - ban: { - text: null, - link: null - }, - softban: { - text: null, - link: null - }, - warn: { - text: null, - link: null - }, - role: { - role: "934941369137524816" - }, - }, - tracks: [ - { - name: "Moderation", - retainPrevious: false, - nullable: true, - track: [ - "934941369137524816", - "934941399806246984", - "934941408849186856", - "934941466734764092" - ], - manageableBy: [] - }, - { - name: "Verification", - retainPrevious: false, - nullable: true, - track: [ - "963166531318067250" - ], - manageableBy: [] - } - ], - roleMenu: { - enabled: true, - allowWebUI: true, - options: [ - { - name: "Gender", - description: "What's your gender?", - min: 1, - max: 1, - options: [ - { name: "Male", role: "959901318019948574" }, - { name: "Female", role: "959901346000154674" }, - { name: "Non Binary", description: "Better than the others", role: "959901378363420704"} - ] - }, - { - name: "Pick", - min: 0, - max: 4, - options: [ - { name: "Test Role 1", role: "934941369137524816" }, - { name: "Test Role 2", role: "934941399806246984" }, - { name: "Test Role 3", role: "934941408849186856" }, - { name: "Test Role 4", role: "934941466734764092" } - ] - } - ] - } - }; - return config; + return await client.database.read(guild); }