diff --git a/apps/bot/commands/Moderation/warn.ts b/apps/bot/commands/Moderation/warn.ts index db8e1f14b0..3508482379 100644 --- a/apps/bot/commands/Moderation/warn.ts +++ b/apps/bot/commands/Moderation/warn.ts @@ -1,4 +1,4 @@ -import { clearWarns, listWarnings, warnUser, removeWarning } from "@majoexe/util/database"; +import { clearWarns, listWarns, warnUser, removeWarn } from "@majoexe/util/database"; import { ApplicationCommandType, ApplicationCommandOptionType, PermissionsBitField, EmbedBuilder, codeBlock, PermissionFlagsBits, InteractionContextType, ApplicationIntegrationType } from "discord.js"; import type { SlashCommand } from "@/util/types/Command"; @@ -135,7 +135,7 @@ export default { return client.errorMessages.createSlashError(interaction, "❌ You need to provide the ID of the warning to remove!"); } - const removedWarning = await removeWarning(interaction.guild.id, user.id, id); + const removedWarning = await removeWarn(interaction.guild.id, user.id, id); if (!removedWarning) { return client.errorMessages.createSlashError(interaction, "❌ I couldn't find a warning with that ID!"); @@ -161,7 +161,7 @@ export default { return client.errorMessages.createSlashError(interaction, "❌ You need to provide a user to list the warnings of!"); } - const warnings = await listWarnings(interaction.guild.id, user.id); + const warnings = await listWarns(interaction.guild.id, user.id); if (!warnings || warnings.length === 0) { return client.errorMessages.createSlashError(interaction, "❌ I couldn't find any warnings for that user!"); diff --git a/packages/utils/database/index.js b/packages/utils/database/index.js index 28a83a9b81..466031133b 100644 --- a/packages/utils/database/index.js +++ b/packages/utils/database/index.js @@ -2,7 +2,7 @@ export * from "./settings/XPSettings.js"; // Logs -export * from "./logs/fetchLogs.js"; +export * from "./logs/fetchLogs"; // AutoMod export * from "./moderation/automod/createDatabaseAutoModRule"; @@ -12,17 +12,17 @@ export * from "./moderation/automod/syncDatabaseAutoModRule"; export * from "./moderation/automod/updateDatabaseAutoModRule"; // Warnings -export * from "./moderation/warn/add.js"; -export * from "./moderation/warn/clear.js"; -export * from "./moderation/warn/list.js"; -export * from "./moderation/warn/remove.js"; +export * from "./moderation/warn/warnUser.js"; +export * from "./moderation/warn/clearWarns"; +export * from "./moderation/warn/listWarns"; +export * from "./moderation/warn/removeWarn"; // XP -export * from "./xp/check.js"; -export * from "./xp/reset.js"; +export * from "./xp/checkXP"; +export * from "./xp/resetXP"; // Reputation -export * from "./reputation/check.js"; +export * from "./reputation/checkReputation"; export * from "./reputation/give.js"; export * from "./reputation/take.js"; export * from "./reputation/set"; diff --git a/packages/utils/database/logs/fetchLogs.js b/packages/utils/database/logs/fetchLogs.js deleted file mode 100644 index 274f4b9380..0000000000 --- a/packages/utils/database/logs/fetchLogs.js +++ /dev/null @@ -1,55 +0,0 @@ -import prismaClient from "@majoexe/database"; - -/** - * Fetches logs for a guild. - * - * @param {string} guildId - The ID of the guild. - * @param {number} page - The page number to fetch. - * @param {number} [count=20] - The number of logs to fetch per page. - * @returns {Promise} - Returns an array of log objects for the specified guild. - * @throws {Error} - Throws an error if the operation fails. - */ -export async function fetchLogs(guildId, page, count = 20) { - try { - const logs = await prismaClient.guildLogs.findMany({ - where: { - guildId, - }, - take: count, - skip: (page - 1) * count, - orderBy: { - createdAt: "asc", - }, - include: { - user: true, - }, - }); - - return logs; - } catch (e) { - console.log("Failed to fetch logs:", e); - throw e; - } -} - -/** - * Counts the number of logs for a guild. - * - * @param {string} guildId - The ID of the guild. - * @returns {Promise} - Returns the number of logs for the specified guild. - * @throws {Error} - Throws an error if the operation fails. - */ -export async function countLogs(guildId) { - try { - const logs = await prismaClient.guildLogs.count({ - where: { - guildId, - }, - }); - - return logs; - } catch (e) { - console.log("Failed to count logs:", e); - throw e; - } -} diff --git a/packages/utils/database/moderation/warn/clear.js b/packages/utils/database/moderation/warn/clear.js deleted file mode 100644 index d111da4ec6..0000000000 --- a/packages/utils/database/moderation/warn/clear.js +++ /dev/null @@ -1,27 +0,0 @@ -import prismaClient from "@majoexe/database"; - -/** - * Clears all warnings for a guild member. - * - * @param {string} userId - The ID of the user. - * @param {string} guildId - The ID of the guild. - * @returns {Promise} - Returns the number of warnings that were cleared. - * @throws {Error} - Throws an error if the operation fails. - */ -export async function clearWarns(userId, guildId) { - try { - const allWarnings = await prismaClient.guildWarns.deleteMany({ - where: { - guildId, - user: { - discordId: userId, - }, - }, - }); - - return allWarnings?.count || 0; - } catch (error) { - console.error("Failed to clear warns:", error); - throw error; - } -} diff --git a/packages/utils/database/moderation/warn/clearWarns.ts b/packages/utils/database/moderation/warn/clearWarns.ts new file mode 100644 index 0000000000..75c4d2879b --- /dev/null +++ b/packages/utils/database/moderation/warn/clearWarns.ts @@ -0,0 +1,20 @@ +import prismaClient from "@majoexe/database"; +import { Snowflake } from "discord-api-types/globals"; + +export async function clearWarns(userId: Snowflake, guildId: Snowflake) { + try { + const allWarnings = await prismaClient.guildWarns.deleteMany({ + where: { + guildId, + user: { + discordId: userId, + }, + }, + }); + + return allWarnings?.count || 0; + } catch (error) { + console.error("Failed to clear warns:", error); + throw error; + } +} diff --git a/packages/utils/database/moderation/warn/list.js b/packages/utils/database/moderation/warn/list.js deleted file mode 100644 index 121cc300de..0000000000 --- a/packages/utils/database/moderation/warn/list.js +++ /dev/null @@ -1,27 +0,0 @@ -import prismaClient from "@majoexe/database"; - -/** - * Lists all warnings for a guild member. - * - * @param {string} guildId - The ID of the guild. - * @param {string} userId - The ID of the user. - * @returns {Promise} - Returns an array of warning objects for the specified user in the specified guild. - * @throws {Error} - Throws an error if the operation fails. - */ -export async function listWarnings(guildId, userId) { - try { - const warnings = await prismaClient.guildWarns.findMany({ - where: { - guildId, - user: { - discordId: userId, - }, - }, - }); - - return warnings; - } catch (error) { - console.error("Failed to list warnings:", error); - throw error; - } -} diff --git a/packages/utils/database/moderation/warn/listWarns.ts b/packages/utils/database/moderation/warn/listWarns.ts new file mode 100644 index 0000000000..e8c3788891 --- /dev/null +++ b/packages/utils/database/moderation/warn/listWarns.ts @@ -0,0 +1,20 @@ +import prismaClient from "@majoexe/database"; +import { Snowflake } from "discord-api-types/globals"; + +export async function listWarns(guildId: Snowflake, userId: Snowflake) { + try { + const warnings = await prismaClient.guildWarns.findMany({ + where: { + guildId, + user: { + discordId: userId, + }, + }, + }); + + return warnings; + } catch (error) { + console.error("Failed to list warnings:", error); + throw error; + } +} diff --git a/packages/utils/database/moderation/warn/remove.js b/packages/utils/database/moderation/warn/remove.js deleted file mode 100644 index 2724a62802..0000000000 --- a/packages/utils/database/moderation/warn/remove.js +++ /dev/null @@ -1,37 +0,0 @@ -import prismaClient from "@majoexe/database"; - -/** - * Removes a warning from a guild member. - * - * @param {string} guildId - The ID of the guild. - * @param {string} userId - The ID of the user. - * @param {number} warnId - The ID of the warning. - * @returns {Promise} - Returns the warning object if it was successfully removed, false otherwise. - * @throws {Error} - Throws an error if the operation fails. - */ -export async function removeWarning(guildId, userId, warnId) { - try { - const warning = await prismaClient.guildWarns.findFirst({ - where: { - guildId, - user: { - discordId: userId, - }, - warnId, - }, - }); - - if (!warning) return false; - - await prismaClient.guildWarns.delete({ - where: { - id: warning.id, - }, - }); - - return warning; - } catch (error) { - console.error("Failed to remove warning: ", error); - throw error; - } -} diff --git a/packages/utils/database/moderation/warn/removeWarn.ts b/packages/utils/database/moderation/warn/removeWarn.ts new file mode 100644 index 0000000000..b3d33689ad --- /dev/null +++ b/packages/utils/database/moderation/warn/removeWarn.ts @@ -0,0 +1,29 @@ +import prismaClient, { GuildWarns } from "@majoexe/database"; +import { Snowflake } from "discord-api-types/globals"; + +export async function removeWarn(guildId: Snowflake, userId: Snowflake, warnId: GuildWarns["warnId"]) { + try { + const warning = await prismaClient.guildWarns.findFirst({ + where: { + guildId, + user: { + discordId: userId, + }, + warnId, + }, + }); + + if (!warning) return false; + + await prismaClient.guildWarns.delete({ + where: { + id: warning.id, + }, + }); + + return warning; + } catch (error) { + console.error("Failed to remove warning: ", error); + throw error; + } +} diff --git a/packages/utils/database/moderation/warn/add.js b/packages/utils/database/moderation/warn/warnUser.js similarity index 100% rename from packages/utils/database/moderation/warn/add.js rename to packages/utils/database/moderation/warn/warnUser.js diff --git a/packages/utils/database/reputation/check.js b/packages/utils/database/reputation/check.js deleted file mode 100644 index 9c60af835f..0000000000 --- a/packages/utils/database/reputation/check.js +++ /dev/null @@ -1,26 +0,0 @@ -import prismaClient from "@majoexe/database"; - -/** - * Checks the reputation of a user in a guild. - * - * @param {string} userId - The ID of the user. - * @param {string} guildId - The ID of the guild. - * @returns {Promise} - Returns the reputation of the user in the guild, or 0 if the user has no reputation. - * @throws {Error} - Throws an error if the operation fails. - */ -export async function checkReputation(userId, guildId) { - try { - const rep = await prismaClient.reputation.findFirst({ - where: { - guildId, - userId, - }, - }); - - if (!rep) return 0; - return rep.reputation || 0; - } catch (error) { - console.error("Failed to check reputation:", error); - throw error; - } -} diff --git a/packages/utils/database/reputation/checkReputation.ts b/packages/utils/database/reputation/checkReputation.ts new file mode 100644 index 0000000000..5617a5f829 --- /dev/null +++ b/packages/utils/database/reputation/checkReputation.ts @@ -0,0 +1,19 @@ +import prismaClient from "@majoexe/database"; +import { Snowflake } from "discord-api-types/globals"; + +export async function checkReputation(userId: Snowflake, guildId: Snowflake) { + try { + const rep = await prismaClient.reputation.findFirst({ + where: { + guildId, + userId, + }, + }); + + if (!rep) return 0; + return rep.reputation || 0; + } catch (error) { + console.error("Failed to check reputation:", error); + throw error; + } +} diff --git a/packages/utils/database/xp/check.js b/packages/utils/database/xp/check.js deleted file mode 100644 index 432a04892d..0000000000 --- a/packages/utils/database/xp/check.js +++ /dev/null @@ -1,26 +0,0 @@ -import prismaClient from "@majoexe/database"; - -/** - * Check XP for user - * - * @param {string} userId - The ID of the user - * @param {string} guildId - The ID of the guild - * @returns {Promise} - The XP of the user in the guild - * @throws {Error} - Throws an error if the operation fails. - */ -export async function checkXP(userId, guildId) { - try { - const xp = await prismaClient.guildXp.findFirst({ - where: { - guildId, - userId, - }, - }); - - if (!xp) return 0; - return xp.xp || 0; - } catch (error) { - console.error("Failed to check XP:", error); - throw error; - } -} diff --git a/packages/utils/database/xp/checkXP.ts b/packages/utils/database/xp/checkXP.ts new file mode 100644 index 0000000000..2616ef433a --- /dev/null +++ b/packages/utils/database/xp/checkXP.ts @@ -0,0 +1,19 @@ +import prismaClient from "@majoexe/database"; +import { Snowflake } from "discord-api-types/globals"; + +export async function checkXP(userId: Snowflake, guildId: Snowflake) { + try { + const xp = await prismaClient.guildXp.findFirst({ + where: { + guildId, + userId, + }, + }); + + if (!xp) return 0; + return xp.xp || 0; + } catch (error) { + console.error("Failed to check XP:", error); + throw error; + } +} diff --git a/packages/utils/database/xp/reset.js b/packages/utils/database/xp/reset.js deleted file mode 100644 index 2f755b5f36..0000000000 --- a/packages/utils/database/xp/reset.js +++ /dev/null @@ -1,25 +0,0 @@ -import prismaClient from "@majoexe/database"; - -/** - * Reset XP for user - * - * @param {string} userId - The id of the user - * @param {string} guildId - The id of the guild - * @returns {Promise} - Whether the operation was successful - * @throws {Error} - Throws an error if the operation fails. - * */ -export async function resetXP(userId, guildId) { - try { - await prismaClient.guildXp.deleteMany({ - where: { - guildId, - userId, - }, - }); - - return true; - } catch (e) { - console.log("Failed to reset XP:", e); - throw e; - } -} diff --git a/packages/utils/database/xp/resetXP.ts b/packages/utils/database/xp/resetXP.ts new file mode 100644 index 0000000000..93da90243e --- /dev/null +++ b/packages/utils/database/xp/resetXP.ts @@ -0,0 +1,18 @@ +import prismaClient from "@majoexe/database"; +import { Snowflake } from "discord-api-types/globals"; + +export async function resetXP(userId: Snowflake, guildId: Snowflake) { + try { + const deleteAction = await prismaClient.guildXp.deleteMany({ + where: { + guildId, + userId, + }, + }); + + return deleteAction.count || 0; + } catch (e) { + console.log("Failed to reset XP:", e); + throw e; + } +} diff --git a/packages/utils/functions/automod/createDiscordAutoModRule.ts b/packages/utils/functions/automod/createDiscordAutoModRule.ts index a008b41854..5d708c46b1 100644 --- a/packages/utils/functions/automod/createDiscordAutoModRule.ts +++ b/packages/utils/functions/automod/createDiscordAutoModRule.ts @@ -1,6 +1,6 @@ import { globalConfig } from "@majoexe/config"; import { type APIAutoModerationRule, AutoModerationRuleTriggerType } from "discord-api-types/v10"; -import { createDatabaseAutoModRule, deleteDatabaseAutoModRule, syncDatabaseAutoModRule, updateDatabaseAutoModRule } from "../../database"; +import { createDatabaseAutoModRule, syncDatabaseAutoModRule, updateDatabaseAutoModRule } from "../../database"; import { fetchDiscordAutoModRules } from "./fetchDiscordAutoModRules"; import { deleteDiscordAutoModRules } from "./deleteDiscordAutoModRule"; diff --git a/packages/utils/functions/automod/index.ts b/packages/utils/functions/automod/index.ts index ba6f7f0a58..b19e1a6c92 100644 --- a/packages/utils/functions/automod/index.ts +++ b/packages/utils/functions/automod/index.ts @@ -1,4 +1,4 @@ export * from "./createDiscordAutoModRule"; -export * from "./validateAutoModIgnores.js"; +export * from "./validateAutoModIgnores"; export * from "./validateAutoModRuleActions"; export * from "./types"; diff --git a/packages/utils/functions/automod/validateAutoModIgnores.js b/packages/utils/functions/automod/validateAutoModIgnores.ts similarity index 65% rename from packages/utils/functions/automod/validateAutoModIgnores.js rename to packages/utils/functions/automod/validateAutoModIgnores.ts index 25db0b66fa..dbf97e2bc0 100644 --- a/packages/utils/functions/automod/validateAutoModIgnores.js +++ b/packages/utils/functions/automod/validateAutoModIgnores.ts @@ -1,6 +1,7 @@ -import { ChannelType } from "discord-api-types/v10"; +import { APIGuildChannel, GuildChannelType, APIRole, ChannelType } from "discord-api-types/v10"; +import { AutoModerationRuleCreationData } from "./types"; -export function validateAutoModIgnores(allChannels, allRoles, exemptRoles, exemptChannels) { +export async function validateAutoModIgnores(allChannels: APIGuildChannel[], allRoles: APIRole[], exemptRoles: AutoModerationRuleCreationData["exemptRoles"], exemptChannels: AutoModerationRuleCreationData["exemptChannels"]) { if (exemptChannels.length > 50) { return { error: "You can only have 50 ignored channels at once. Please remove some of the existing ignored channels before adding this one.", @@ -32,7 +33,9 @@ export function validateAutoModIgnores(allChannels, allRoles, exemptRoles, exemp }; } - if (allChannels.find((c) => c.id === channel).type !== ChannelType.GuildText) { + const foundChannel = allChannels.find((c) => c.id === channel); + + if (foundChannel && foundChannel.type !== ChannelType.GuildText) { return { error: `Channel #${allChannels.find((c) => c.id === channel)?.name || channel} is not a text channel`, code: 400, diff --git a/packages/utils/functions/files/index.ts b/packages/utils/functions/files/index.ts new file mode 100644 index 0000000000..f2d3456eae --- /dev/null +++ b/packages/utils/functions/files/index.ts @@ -0,0 +1 @@ +export * from "./readDir"; diff --git a/packages/utils/functions/files/readDir.js b/packages/utils/functions/files/readDir.js deleted file mode 100644 index 0ecd80b0a4..0000000000 --- a/packages/utils/functions/files/readDir.js +++ /dev/null @@ -1,39 +0,0 @@ -import { readdirSync, statSync } from "node:fs"; -import path from "node:path"; - -/** - * Read all files with specified extensions in a directory, optionally including subdirectories - * - * @param {string} dir - The directory to read - * @param {boolean} [recursive=false] - Whether to include subdirectories - * @param {string|string[]} [extensions=['.js']] - The file extension(s) to include - * @returns {string[]} - The files in the directory with the specified extensions - * @example - * const jsFiles = readDir("./src", true, '.js'); - * console.log(jsFiles); - * // => [ "./src/index.js", "./src/lib/util.js", ... ] - * - * const cssAndJsFiles = readDir("./src", true, ['.js', '.css']); - * console.log(cssAndJsFiles); - * // => [ "./src/index.js", "./src/style.css", "./src/lib/util.js", ... ] - */ -export function readDir(dir, recursive = false, extensions = [".js"]) { - if (typeof extensions === "string") { - extensions = [extensions]; - } - const files = readdirSync(dir); - let directories = []; - - files.forEach((file) => { - const filePath = path.join(dir, file); - const stat = statSync(filePath); - - if (stat.isDirectory() && recursive) { - directories = directories.concat(readDir(filePath, true, extensions)); - } else if (stat.isFile() && extensions.some((ext) => filePath.endsWith(ext))) { - directories.push(filePath.split(path.sep).join("/")); - } - }); - - return directories; -} diff --git a/packages/utils/functions/files/readDir.ts b/packages/utils/functions/files/readDir.ts new file mode 100644 index 0000000000..521fccb535 --- /dev/null +++ b/packages/utils/functions/files/readDir.ts @@ -0,0 +1,23 @@ +import { PathLike, readdirSync, statSync } from "node:fs"; +import path from "node:path"; + +export function readDir(dir: PathLike, recursive = false, extensions = [".js"]) { + if (typeof extensions === "string") { + extensions = [extensions]; + } + const files = readdirSync(dir.toString()); + let directories: string[] = []; + + files.forEach((file) => { + const filePath = path.join(dir.toString(), file); + const stat = statSync(filePath); + + if (stat.isDirectory() && recursive) { + directories = directories.concat(readDir(filePath, true, extensions)); + } else if (stat.isFile() && extensions.some((ext) => filePath.endsWith(ext))) { + directories.push(filePath.split(path.sep).join("/")); + } + }); + + return directories; +} diff --git a/packages/utils/package.json b/packages/utils/package.json index 20020a1bb0..5c122aa5a5 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -10,6 +10,7 @@ "./embeds/*": "./embeds/*", "./functions/automod": "./functions/automod/index.ts", "./functions/automod/*": "./functions/automod/*", + "./functions/files": "./functions/files/index.ts", "./functions/files/*": "./functions/files/*", "./functions/guild": "./functions/guild/index.ts", "./functions/guild/*": "./functions/guild/*",