diff --git a/package-lock.json b/package-lock.json index 3faf37b..228432c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "cld": "^2.9.1", "discord.js": "^14.15.2", "dotenv": "^16.4.5", + "mysql": "^2.18.1", "pouchdb": "^8.0.1", "redis": "^4.6.14" }, @@ -23,6 +24,7 @@ "@eslint/eslintrc": "^3.0.2", "@eslint/js": "^9.0.0", "@types/jest": "^29.5.12", + "@types/mysql": "^2.15.26", "@typescript-eslint/eslint-plugin": "^6.21.0", "eslint": "^8.57.0", "eslint-config-standard-with-typescript": "^43.0.1", @@ -1672,6 +1674,16 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, + "node_modules/@types/mysql": { + "version": "2.15.26", + "resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.26.tgz", + "integrity": "sha512-DSLCOXhkvfS5WNNPbfn2KdICAmk8lLc+/PNvnPnF7gOdMZCxopXduqv0OQ13y/yA/zXTSikZZqVgybUxOEg6YQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/node": { "version": "20.12.7", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", @@ -2388,6 +2400,15 @@ } ] }, + "node_modules/bignumber.js": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", + "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==", + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -5795,6 +5816,57 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node_modules/mysql": { + "version": "2.18.1", + "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz", + "integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==", + "license": "MIT", + "dependencies": { + "bignumber.js": "9.0.0", + "readable-stream": "2.3.7", + "safe-buffer": "5.1.2", + "sqlstring": "2.3.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mysql/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/mysql/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/mysql/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/mysql/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/napi-macros": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.0.0.tgz", @@ -6287,6 +6359,12 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, "node_modules/prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -6746,6 +6824,15 @@ "dev": true, "license": "BSD-3-Clause" }, + "node_modules/sqlstring": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", + "integrity": "sha512-ooAzh/7dxIG5+uDik1z/Rd1vli0+38izZhGzSa34FwR7IbelPWCCKSNIl8jlL/F7ERvy8CB2jNeM1E9i9mXMAQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/stack-utils": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", diff --git a/package.json b/package.json index f32e4ee..d837513 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "run:dev": "ts-node ./src/main.ts", "run:build": "node ./dist/main.js", "build": "tsc --build", - "update:commands": "ts-node ./src/registerCommands.ts" + "update:commands": "ts-node ./src/registerCommands.ts" }, "keywords": [], "author": "", @@ -20,6 +20,7 @@ "cld": "^2.9.1", "discord.js": "^14.15.2", "dotenv": "^16.4.5", + "mysql": "^2.18.1", "pouchdb": "^8.0.1", "redis": "^4.6.14" }, @@ -27,6 +28,7 @@ "@eslint/eslintrc": "^3.0.2", "@eslint/js": "^9.0.0", "@types/jest": "^29.5.12", + "@types/mysql": "^2.15.26", "@typescript-eslint/eslint-plugin": "^6.21.0", "eslint": "^8.57.0", "eslint-config-standard-with-typescript": "^43.0.1", diff --git a/src/Shork.ts b/src/Shork.ts index 41cd7ed..66a3067 100644 --- a/src/Shork.ts +++ b/src/Shork.ts @@ -68,7 +68,7 @@ class Shork extends Client { await this.login(token); return true; } catch (error) { - this.logger.log(`Error with starting: ${error}`, LogType.ERROR); + this.logger.log(`${error}`, LogType.ERROR); return false; } } diff --git a/src/commands/moderation/ban.ts b/src/commands/moderation/ban.ts new file mode 100644 index 0000000..ad234e6 --- /dev/null +++ b/src/commands/moderation/ban.ts @@ -0,0 +1,65 @@ +import { + ChatInputCommandInteraction, + GuildMember, + PermissionFlagsBits, + SlashCommandBuilder, +} from "discord.js"; +import { LogType, Logger } from "../../utils/logging"; +import mysql from 'mysql'; +import dotenv from 'dotenv'; + +dotenv.config(); + +async function timeOutUser(member: GuildMember, time: number, reason: string) { + await member.timeout(time * 60 * 1000, reason); +} + +async function addWarnToRecord( + db: mysql.Connection, + mod: GuildMember, + user: GuildMember, + reason: string +) { + const query = 'INSERT INTO mod_actions (userid, actiontype, moderatorid, reason) VALUES (?, ?, ?, ?)'; + const values = [user.user.id, 'warn', mod.user.id, reason]; + + return new Promise((resolve, reject) => { + db.query(query, values, (error, results) => { + if (error) { + return reject(error); + } + resolve(results); + }); + }); +} + +function connectToDatabase() { + return mysql.createConnection({ + user: process.env.DB_USER || 'root', + password: process.env.DB_PASSWORD || 'popcornpanties236P!', + host: process.env.DB_HOST || 'localhost', + database: process.env.DB_NAME || 'shork_db', + }); +} + +export default { + data: new SlashCommandBuilder() + .setName("ban") + .setDescription("Ban a user.") + .setDefaultMemberPermissions(PermissionFlagsBits.BanMembers) + .addMentionableOption(option => + option + .setName("user") + .setDescription("The user to ban.") + .setRequired(true) + ) + .addStringOption(option => + option + .setName("reason") + .setDescription("The reason you're banning the user for") + .setRequired(true) + ), + + async execute(interaction: ChatInputCommandInteraction) { + } +}; diff --git a/src/commands/moderation/warn.ts b/src/commands/moderation/warn.ts index 9445296..e2934ea 100644 --- a/src/commands/moderation/warn.ts +++ b/src/commands/moderation/warn.ts @@ -1,46 +1,103 @@ import { ChatInputCommandInteraction, + GuildMember, PermissionFlagsBits, SlashCommandBuilder, - SlashCommandMentionableOption, - SlashCommandStringOption, } from "discord.js"; import { LogType, Logger } from "../../utils/logging"; +import mysql from 'mysql'; +import dotenv from 'dotenv'; -import { shorkCache } from "../../db/cache"; +dotenv.config({ + path: 'S:\\shork\\.env' +}); + +async function timeOutUser(member: GuildMember, time: number, reason: string) { + await member.timeout(time * 60 * 1000, reason); +} + +async function addWarnToRecord( + db: mysql.Connection, + mod: GuildMember, + user: GuildMember, + reason: string +) { + const query = 'INSERT INTO mod_actions (userid, actiontype, moderatorid, reason) VALUES (?, ?, ?, ?)'; + const values = [user.user.id, 'warn', mod.user.id, reason]; + + return new Promise((resolve, reject) => { + db.query(query, values, (error, results) => { + if (error) { + return reject(error); + } + resolve(results); + }); + }); +} + +function connectToDatabase() { + return mysql.createConnection({ + user: process.env.DB_USER || 'root', + password: process.env.SQL_PASSWORD, + host: process.env.DB_HOST || 'localhost', + database: process.env.DB_NAME || 'shork_db', + }); +} export default { data: new SlashCommandBuilder() .setName("warn") .setDescription("Warn a user.") .setDefaultMemberPermissions(PermissionFlagsBits.ManageChannels) - .addMentionableOption((option) => + .addMentionableOption(option => option .setName("user") .setDescription("The user to warn.") .setRequired(true) ) - .addStringOption((option) => + .addStringOption(option => option .setName("reason") .setDescription("The reason you're warning the user for") .setRequired(false) - ) + ) .setDefaultMemberPermissions(PermissionFlagsBits.KickMembers), async execute(interaction: ChatInputCommandInteraction) { const logger = new Logger(__filename, LogType.DEBUG); - const options = interaction.options; - const member = options.getMentionable("user"); - const reason = options.getString("reason"); + const db = connectToDatabase(); - if (await shorkCache.hGetAll('warnings')) { - await shorkCache.hSet('warnings', {}) - } + db.connect(err => { + if (err) { + logger.log(`Error connecting to the database: ${err.stack}`); + if (interaction.isRepliable()) { + interaction.reply(`Error connecting to the database.`); + } + return; + } + logger.log(`Connected to database with thread ID: ${db.threadId}`); + }); - const warnings = await shorkCache.hGetAll('warnings') + const options = interaction.options; + const member = options.getMentionable("user") as GuildMember; + const reason = options.getString("reason") || "No reason provided"; - console.log(warnings) + try { + await addWarnToRecord(db, interaction.member as GuildMember, member, reason); + // await timeOutUser(member, 5, reason); + + if (interaction.isRepliable()) { + interaction.reply(`${member.user.username} has been warned for ${reason}`); + } + } catch (error) { + logger.log(`Error adding warning to record: ${error}`); + if (interaction.isRepliable()) { + interaction.reply(`There was an error warning ${member.user.username}. Please try again later.`); + } + } finally { + db.end(); + logger.log('Exited db', LogType.DEBUG) + } }, }; diff --git a/src/config.json b/src/config.json index cae7126..0f77b59 100644 --- a/src/config.json +++ b/src/config.json @@ -1,4 +1,7 @@ { "clientId": "1230659817077604442", - "guildId": "1195155703489384579" + "guildId": "1195155703489384579", + "moderation": { + "baseTimeout": "15" + } } \ No newline at end of file diff --git a/src/db/management/mod.d.ts b/src/db/management/mod.d.ts new file mode 100644 index 0000000..24ed65c --- /dev/null +++ b/src/db/management/mod.d.ts @@ -0,0 +1,6 @@ +interface ModAction { + userid: string, + actiontype: string, + moderatorid: string, + reason: string +} \ No newline at end of file diff --git a/src/db/management/mod_actions.sql b/src/db/management/mod_actions.sql new file mode 100644 index 0000000..2950581 --- /dev/null +++ b/src/db/management/mod_actions.sql @@ -0,0 +1,12 @@ +CREATE TABLE mod_actions( + userid text, + actiontype text, + moderatorid text, + reason text +); + +CREATE TABLE user_levels( + userid text, + xp int, + lvl int +); \ No newline at end of file diff --git a/src/events/messages/onCreate.ts b/src/events/messages/onCreate.ts index 28fcce6..fd4f73e 100644 --- a/src/events/messages/onCreate.ts +++ b/src/events/messages/onCreate.ts @@ -23,6 +23,10 @@ async function isEnglish(messageContent: string): Promise { return true } +async function flagMessage(message: Message) { + +} + export default { name: Events.MessageCreate, execute: async (message: Message) => {