diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/commands/config/features.ts | 1 | ||||
-rw-r--r-- | src/commands/config/log.ts | 86 | ||||
-rw-r--r-- | src/lib/models/Guild.ts | 115 | ||||
-rw-r--r-- | src/lib/models/__helpers.ts | 6 | ||||
-rw-r--r-- | src/listeners/message/automodCreate.ts | 39 |
5 files changed, 182 insertions, 65 deletions
diff --git a/src/commands/config/features.ts b/src/commands/config/features.ts index 7a7c3bb..3c607c7 100644 --- a/src/commands/config/features.ts +++ b/src/commands/config/features.ts @@ -19,6 +19,7 @@ export default class FeaturesCommand extends BushCommand { } public override async exec(message: BushMessage | BushSlashMessage): Promise<unknown> { if (!message.guild) return await message.util.reply(`${util.emojis.error} This command can only be used in servers.`); + const featureEmbed = new MessageEmbed().setTitle(`${message.guild!.name}'s Features`).setColor(util.colors.default); const enabledFeatures = await message.guild!.getSetting('enabledFeatures'); diff --git a/src/commands/config/log.ts b/src/commands/config/log.ts new file mode 100644 index 0000000..592f700 --- /dev/null +++ b/src/commands/config/log.ts @@ -0,0 +1,86 @@ +import { BushCommand, BushMessage, BushSlashMessage, guildLogsArr, GuildLogType } from '@lib'; +import { ArgumentOptions, Flag } from 'discord-akairo'; +import { TextChannel } from 'discord.js'; + +export default class LogCommand extends BushCommand { + public constructor() { + super('log', { + aliases: ['log', 'logging'], + category: 'config', + description: { + content: 'Set or remove a log channel.', + usage: 'log <logType> [channel]', + examples: ['log automod #automod-logs'] + }, + slash: true, + slashOptions: [ + { + name: 'log_type', + description: 'What log type would you like to change?', + type: 'STRING', + required: true, + choices: guildLogsArr.map((log) => ({ name: log, value: log })) + }, + { + name: 'channel', + description: 'What channel would you like these logs to be sent in?', + type: 'CHANNEL', + required: false + } + ], + channel: 'guild', + clientPermissions: ['SEND_MESSAGES'], + userPermissions: ['SEND_MESSAGES', 'MANAGE_GUILD'] + }); + } + + *args(): IterableIterator<ArgumentOptions | Flag> { + const log_type = yield { + id: 'log', + type: guildLogsArr, + prompt: { + start: 'What log type would you like to change?', + retry: `{error} Choose either ${util.oxford( + guildLogsArr.map((l) => `\`${l}\``), + 'or' + )}`, + optional: false + } + }; + + const channel = yield { + id: 'channel', + type: 'textChannel', + prompt: { + start: `What channel would you like ${log_type} logs to be sent in?`, + retry: `{error} Choose a valid text channel for ${log_type} logs to be sent in.` + } + }; + + return { log_type, channel }; + } + + public override async exec( + message: BushMessage | BushSlashMessage, + args: { log_type: GuildLogType; channel: TextChannel } + ): Promise<unknown> { + if (!message.guild) return await message.util.reply(`${util.emojis.error} This command can only be used in servers.`); + const currentLogs = await message.guild.getSetting('logChannels'); + const oldChannel = currentLogs[args.log_type] ?? undefined; + + const action = !!args.channel; + + action ? (currentLogs[args.log_type] = args.channel.id) : delete currentLogs[args.log_type]; + + const success = await message.guild.setSetting('logChannels', currentLogs); + return await message.util.reply( + `${ + success + ? `${util.emojis.success} Successfully ${oldChannel ? 'changed' : 'set'}` + : `${util.emojis.error} Unable to ${oldChannel ? 'change' : 'set'}` + } ${ + oldChannel ? ` the \`${args.log_type}\` log channel from <#${oldChannel}>` : ` the \`${args.log_type}\` log channel` + } to ${args.channel ? `<#${args.channel.id}>` : '`disabled`'}` + ); + } +} diff --git a/src/lib/models/Guild.ts b/src/lib/models/Guild.ts index 1974725..38b5127 100644 --- a/src/lib/models/Guild.ts +++ b/src/lib/models/Guild.ts @@ -2,41 +2,7 @@ import { Snowflake } from 'discord.js'; import { DataTypes, Sequelize } from 'sequelize'; import { BushClient } from '../extensions/discord-akairo/BushClient'; import { BaseModel } from './BaseModel'; -import { jsonArrayInit, NEVER_USED } from './__helpers'; - -export interface GuildModel { - id: Snowflake; - prefix: string; - autoPublishChannels: Snowflake[]; - blacklistedChannels: Snowflake[]; - blacklistedUsers: Snowflake[]; - welcomeChannel: Snowflake; - muteRole: Snowflake; - punishmentEnding: string; - disabledCommands: string[]; - lockdownChannels: Snowflake[]; - autoModPhases: string[]; - enabledFeatures: GuildFeatures[]; - joinRoles: Snowflake[]; - automodLogChannel: Snowflake; -} - -export interface GuildModelCreationAttributes { - id: Snowflake; - prefix?: string; - autoPublishChannels?: Snowflake[]; - blacklistedChannels?: Snowflake[]; - blacklistedUsers?: Snowflake[]; - welcomeChannel?: Snowflake; - muteRole?: Snowflake; - punishmentEnding?: string; - disabledCommands?: string[]; - lockdownChannels?: Snowflake[]; - autoModPhases?: string[]; - enabledFeatures?: GuildFeatures[]; - joinRoles?: Snowflake[]; - automodLogChannel?: Snowflake; -} +import { jsonArrayInit, jsonParseGet, jsonParseSet, NEVER_USED } from './__helpers'; export const guildSettingsObj = { prefix: { @@ -80,12 +46,6 @@ export const guildSettingsObj = { description: 'Roles assigned to users on join who do not have sticky role information.', type: 'role-array', configurable: true - }, - automodLogChannel: { - name: 'Automod Log Channel', - description: 'The channel where all automod information is sent.', - type: 'channel', - configurable: true } }; export type GuildSettings = keyof typeof guildSettingsObj; @@ -121,12 +81,66 @@ export const guildFeaturesObj = { stickyRoles: { name: 'Sticky Roles', description: 'Restores past roles to a user when they rejoin.' + }, + modsCanPunishMods: { + name: 'Mods Can Punish Mods', + description: 'Allow moderators to punish other moderators.' } }; +export const guildLogsObj = { + automod: { + description: 'Sends a message in this channel every time automod is activated.', + configurable: true + }, + moderation: { + description: 'Sends a message in this channel every time a moderation action is performed.', + configurable: true + } +}; +export type GuildLogType = keyof typeof guildLogsObj; +export const guildLogsArr = Object.keys(guildLogsObj).filter( + (s) => guildLogsObj[s as GuildLogType].configurable +) as GuildLogType[]; +type LogChannelDB = { [x in keyof typeof guildLogsObj]?: Snowflake }; + export type GuildFeatures = keyof typeof guildFeaturesObj; export const guildFeaturesArr: GuildFeatures[] = Object.keys(guildFeaturesObj) as GuildFeatures[]; +export interface GuildModel { + id: Snowflake; + prefix: string; + autoPublishChannels: Snowflake[]; + blacklistedChannels: Snowflake[]; + blacklistedUsers: Snowflake[]; + welcomeChannel: Snowflake; + muteRole: Snowflake; + punishmentEnding: string; + disabledCommands: string[]; + lockdownChannels: Snowflake[]; + autoModPhases: string[]; + enabledFeatures: GuildFeatures[]; + joinRoles: Snowflake[]; + logChannels: LogChannelDB; +} + +export interface GuildModelCreationAttributes { + id: Snowflake; + prefix?: string; + autoPublishChannels?: Snowflake[]; + blacklistedChannels?: Snowflake[]; + blacklistedUsers?: Snowflake[]; + welcomeChannel?: Snowflake; + muteRole?: Snowflake; + punishmentEnding?: string; + disabledCommands?: string[]; + lockdownChannels?: Snowflake[]; + autoModPhases?: string[]; + enabledFeatures?: GuildFeatures[]; + joinRoles?: Snowflake[]; + logChannels?: LogChannelDB; +} + export class Guild extends BaseModel<GuildModel, GuildModelCreationAttributes> implements GuildModel { /** * The ID of the guild @@ -259,12 +273,12 @@ export class Guild extends BaseModel<GuildModel, GuildModelCreationAttributes> i } /** - * The channel to send automod logs to. + * The channels where logging messages will be sent. */ - public get automodLogChannel(): Snowflake { + public get logChannels(): LogChannelDB { throw new Error(NEVER_USED); } - public set automodLogChannel(_: Snowflake) { + public set logChannels(_: LogChannelDB) { throw new Error(NEVER_USED); } @@ -300,9 +314,16 @@ export class Guild extends BaseModel<GuildModel, GuildModelCreationAttributes> i autoModPhases: jsonArrayInit('autoModPhases'), enabledFeatures: jsonArrayInit('enabledFeatures'), joinRoles: jsonArrayInit('joinRoles'), - automodLogChannel: { - type: DataTypes.STRING, - allowNull: true + logChannels: { + type: DataTypes.TEXT, + get: function (): LogChannelDB { + return jsonParseGet('logChannels', this); + }, + set: function (val: LogChannelDB) { + return jsonParseSet('logChannels', this, val); + }, + allowNull: false, + defaultValue: '{}' } }, { sequelize: sequelize } diff --git a/src/lib/models/__helpers.ts b/src/lib/models/__helpers.ts index f558ecb..b65c014 100644 --- a/src/lib/models/__helpers.ts +++ b/src/lib/models/__helpers.ts @@ -1,17 +1,17 @@ import { DataTypes, Model } from 'sequelize'; export const NEVER_USED = 'This should never be executed'; -function jsonParseGet(key: string, that: Model): any { +export function jsonParseGet(key: string, that: Model): any { return JSON.parse(that.getDataValue(key)); } -function jsonParseSet(key: string, that: Model, value: any): any { +export function jsonParseSet(key: string, that: Model, value: any): any { return that.setDataValue(key, JSON.stringify(value)); } export function jsonArrayInit(key: string): any { return { type: DataTypes.TEXT, - get: function () { + get: function (): string[] { return jsonParseGet(key, this); }, set: function (val: string[]) { diff --git a/src/listeners/message/automodCreate.ts b/src/listeners/message/automodCreate.ts index 638e8d5..5993e7a 100644 --- a/src/listeners/message/automodCreate.ts +++ b/src/listeners/message/automodCreate.ts @@ -24,7 +24,9 @@ export default class AutomodMessageCreateListener extends BushListener { public static async automod(message: BushMessage): Promise<unknown> { if (message.channel.type === 'DM' || !message.guild) return; if (!(await message.guild.hasFeature('automod'))) return; + /* await message.guild.getSetting('autoModPhases'); */ + const badLinks: { [key: string]: number } = {}; let temp = _badLinks; if (_badLinksSecret) temp = temp.concat(_badLinksSecret); @@ -97,20 +99,27 @@ export default class AutomodMessageCreateListener extends BushListener { : highestOffence === 2 ? util.colors.orange : util.colors.red; - // TODO: remove hard coded value - void (message.guild.channels.cache.get('783088333055066212') as TextChannel).send({ - embeds: [ - new MessageEmbed() - .setTitle(`[Severity ${highestOffence}] Automod Action Performed`) - .setDescription( - `**User:** ${message.author} (${message.author.tag})\n**Sent From**: <#${message.channel.id}> [Jump to context](${ - message.url - })\n**Blacklisted Words:** ${util.surroundArray(Object.keys(offences), '`').join(', ')}` - ) - .addField('Message Content', `${await util.codeblock(message.content, 1024)}`) - .setColor(color) - .setTimestamp() - ] - }); + + const automodChannel = (await message.guild.getSetting('logChannels')).automod; + if (!automodChannel) return; + const fetchedChannel = (message.guild.channels.cache.get(automodChannel) ?? + (await message.guild.channels.fetch(automodChannel).catch(() => null))) as TextChannel; + if (!fetchedChannel) return; + + if (fetchedChannel.permissionsFor(message.guild.me!.id)?.has(['VIEW_CHANNEL', 'SEND_MESSAGES', 'EMBED_LINKS'])) + void fetchedChannel.send({ + embeds: [ + new MessageEmbed() + .setTitle(`[Severity ${highestOffence}] Automod Action Performed`) + .setDescription( + `**User:** ${message.author} (${message.author.tag})\n**Sent From**: <#${message.channel.id}> [Jump to context](${ + message.url + })\n**Blacklisted Words:** ${util.surroundArray(Object.keys(offences), '`').join(', ')}` + ) + .addField('Message Content', `${await util.codeblock(message.content, 1024)}`) + .setColor(color) + .setTimestamp() + ] + }); } } |