diff options
Diffstat (limited to 'src/lib/models/instance')
-rw-r--r-- | src/lib/models/instance/ActivePunishment.ts | 91 | ||||
-rw-r--r-- | src/lib/models/instance/Guild.ts | 414 | ||||
-rw-r--r-- | src/lib/models/instance/Level.ts | 75 | ||||
-rw-r--r-- | src/lib/models/instance/ModLog.ts | 124 | ||||
-rw-r--r-- | src/lib/models/instance/Reminder.ts | 81 | ||||
-rw-r--r-- | src/lib/models/instance/StickyRole.ts | 55 |
6 files changed, 840 insertions, 0 deletions
diff --git a/src/lib/models/instance/ActivePunishment.ts b/src/lib/models/instance/ActivePunishment.ts new file mode 100644 index 0000000..1d6104f --- /dev/null +++ b/src/lib/models/instance/ActivePunishment.ts @@ -0,0 +1,91 @@ +import { type Snowflake } from 'discord.js'; +import { nanoid } from 'nanoid'; +import { type Sequelize } from 'sequelize'; +import { BaseModel } from '../BaseModel.js'; +const { DataTypes } = (await import('sequelize')).default; + +export enum ActivePunishmentType { + BAN = 'BAN', + MUTE = 'MUTE', + ROLE = 'ROLE', + BLOCK = 'BLOCK' +} + +export interface ActivePunishmentModel { + id: string; + type: ActivePunishmentType; + user: Snowflake; + guild: Snowflake; + extraInfo: Snowflake; + expires: Date | null; + modlog: string; +} + +export interface ActivePunishmentModelCreationAttributes { + id?: string; + type: ActivePunishmentType; + user: Snowflake; + guild: Snowflake; + extraInfo?: Snowflake; + expires?: Date; + modlog: string; +} + +export class ActivePunishment + extends BaseModel<ActivePunishmentModel, ActivePunishmentModelCreationAttributes> + implements ActivePunishmentModel +{ + /** + * The ID of this punishment (no real use just for a primary key) + */ + public declare id: string; + + /** + * The type of punishment. + */ + public declare type: ActivePunishmentType; + + /** + * The user who is punished. + */ + public declare user: Snowflake; + + /** + * The guild they are punished in. + */ + public declare guild: Snowflake; + + /** + * Additional info about the punishment if applicable. The channel id for channel blocks and role for punishment roles. + */ + public declare extraInfo: Snowflake; + + /** + * The date when this punishment expires (optional). + */ + public declare expires: Date | null; + + /** + * The reference to the modlog entry. + */ + public declare modlog: string; + + /** + * Initializes the model. + * @param sequelize The sequelize instance. + */ + public static initModel(sequelize: Sequelize): void { + ActivePunishment.init( + { + id: { type: DataTypes.STRING, primaryKey: true, allowNull: false, defaultValue: nanoid }, + type: { type: DataTypes.STRING, allowNull: false }, + user: { type: DataTypes.STRING, allowNull: false }, + guild: { type: DataTypes.STRING, allowNull: false, references: { model: 'Guilds', key: 'id' } }, + extraInfo: { type: DataTypes.STRING, allowNull: true }, + expires: { type: DataTypes.DATE, allowNull: true }, + modlog: { type: DataTypes.STRING, allowNull: true, references: { model: 'ModLogs', key: 'id' } } + }, + { sequelize } + ); + } +} diff --git a/src/lib/models/instance/Guild.ts b/src/lib/models/instance/Guild.ts new file mode 100644 index 0000000..11469d2 --- /dev/null +++ b/src/lib/models/instance/Guild.ts @@ -0,0 +1,414 @@ +import { ChannelType, type Snowflake } from 'discord.js'; +import { type Sequelize } from 'sequelize'; +import { BadWordDetails } from '../../common/AutoMod.js'; +import { type BushClient } from '../../extensions/discord-akairo/BushClient.js'; +import { BaseModel } from '../BaseModel.js'; +const { DataTypes } = (await import('sequelize')).default; + +export interface GuildModel { + id: Snowflake; + prefix: string; + autoPublishChannels: Snowflake[]; + blacklistedChannels: Snowflake[]; + blacklistedUsers: Snowflake[]; + welcomeChannel: Snowflake; + muteRole: Snowflake; + punishmentEnding: string; + disabledCommands: string[]; + lockdownChannels: Snowflake[]; + autoModPhases: BadWordDetails[]; + enabledFeatures: GuildFeatures[]; + joinRoles: Snowflake[]; + logChannels: LogChannelDB; + bypassChannelBlacklist: Snowflake[]; + noXpChannels: Snowflake[]; + levelRoles: { [level: number]: Snowflake }; + levelUpChannel: 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?: BadWordDetails[]; + enabledFeatures?: GuildFeatures[]; + joinRoles?: Snowflake[]; + logChannels?: LogChannelDB; + bypassChannelBlacklist?: Snowflake[]; + noXpChannels?: Snowflake[]; + levelRoles?: { [level: number]: Snowflake }; + levelUpChannel?: Snowflake; +} + +export class Guild extends BaseModel<GuildModel, GuildModelCreationAttributes> implements GuildModel { + /** + * The ID of the guild + */ + public declare id: Snowflake; + + /** + * The bot's prefix for the guild + */ + public declare prefix: string; + + /** + * Channels that will have their messages automatically published + */ + public declare autoPublishChannels: Snowflake[]; + + /** + * Channels where the bot won't respond in. + */ + public declare blacklistedChannels: Snowflake[]; + + /** + * Users that the bot ignores in this guild + */ + public declare blacklistedUsers: Snowflake[]; + + /** + * The channels where the welcome messages are sent + */ + public declare welcomeChannel: Snowflake; + + /** + * The role given out when muting someone + */ + public declare muteRole: Snowflake; + + /** + * The message that gets sent after someone gets a punishment dm + */ + public declare punishmentEnding: string; + + /** + * Guild specific disabled commands + */ + public declare disabledCommands: string[]; + + /** + * Channels that should get locked down when the lockdown command gets used. + */ + public declare lockdownChannels: Snowflake[]; + + /** + * Custom automod phases + */ + public declare autoModPhases: BadWordDetails[]; + + /** + * The features enabled in a guild + */ + public declare enabledFeatures: GuildFeatures[]; + + /** + * The roles to assign to a user if they are not assigned sticky roles + */ + public declare joinRoles: Snowflake[]; + + /** + * The channels where logging messages will be sent. + */ + public declare logChannels: LogChannelDB; + + /** + * These users will be able to use commands in channels blacklisted + */ + public declare bypassChannelBlacklist: Snowflake[]; + + /** + * Channels where users will not earn xp for leveling. + */ + public declare noXpChannels: Snowflake[]; + + /** + * What roles get given to users when they reach certain levels. + */ + public declare levelRoles: { [level: number]: Snowflake }; + + /** + * The channel to send level up messages in instead of last channel. + */ + public declare levelUpChannel: Snowflake; + + /** + * Initializes the model. + * @param sequelize The sequelize instance. + */ + public static initModel(sequelize: Sequelize, client: BushClient): void { + Guild.init( + { + id: { type: DataTypes.STRING, primaryKey: true }, + prefix: { type: DataTypes.TEXT, allowNull: false, defaultValue: client.config.prefix }, + autoPublishChannels: { type: DataTypes.JSONB, allowNull: false, defaultValue: [] }, + blacklistedChannels: { type: DataTypes.JSONB, allowNull: false, defaultValue: [] }, + blacklistedUsers: { type: DataTypes.JSONB, allowNull: false, defaultValue: [] }, + welcomeChannel: { type: DataTypes.STRING, allowNull: true }, + muteRole: { type: DataTypes.STRING, allowNull: true }, + punishmentEnding: { type: DataTypes.TEXT, allowNull: true }, + disabledCommands: { type: DataTypes.JSONB, allowNull: false, defaultValue: [] }, + lockdownChannels: { type: DataTypes.JSONB, allowNull: false, defaultValue: [] }, + autoModPhases: { type: DataTypes.JSONB, allowNull: false, defaultValue: [] }, + enabledFeatures: { + type: DataTypes.JSONB, + allowNull: false, + defaultValue: Object.keys(guildFeaturesObj).filter( + (key) => guildFeaturesObj[key as keyof typeof guildFeaturesObj].default + ) + }, + joinRoles: { type: DataTypes.JSONB, allowNull: false, defaultValue: [] }, + logChannels: { type: DataTypes.JSONB, allowNull: false, defaultValue: {} }, + bypassChannelBlacklist: { type: DataTypes.JSONB, allowNull: false, defaultValue: [] }, + noXpChannels: { type: DataTypes.JSONB, allowNull: false, defaultValue: [] }, + levelRoles: { type: DataTypes.JSONB, allowNull: false, defaultValue: {} }, + levelUpChannel: { type: DataTypes.STRING, allowNull: true } + }, + { sequelize } + ); + } +} + +export type BaseGuildSetting = 'channel' | 'role' | 'user'; +export type GuildSettingType = 'string' | 'custom' | BaseGuildSetting | `${BaseGuildSetting}-array`; + +export interface GuildSetting { + name: string; + description: string; + type: GuildSettingType; + subType: ChannelType[] | undefined; + configurable: boolean; +} +const asGuildSetting = <T>(et: { [K in keyof T]: GuildSetting }) => et; + +export const guildSettingsObj = asGuildSetting({ + prefix: { + name: 'Prefix', + description: 'The phrase required to trigger text commands in this server.', + type: 'string', + subType: undefined, + configurable: true + }, + autoPublishChannels: { + name: 'Auto Publish Channels', + description: 'Channels were every message is automatically published.', + type: 'channel-array', + subType: [ChannelType.GuildNews], + configurable: true + }, + welcomeChannel: { + name: 'Welcome Channel', + description: 'The channel where the bot will send join and leave message.', + type: 'channel', + subType: [ + ChannelType.GuildText, + ChannelType.GuildNews, + ChannelType.GuildNewsThread, + ChannelType.GuildPublicThread, + ChannelType.GuildPrivateThread + ], + configurable: true + }, + muteRole: { + name: 'Mute Role', + description: 'The role assigned when muting someone.', + type: 'role', + subType: undefined, + configurable: true + }, + punishmentEnding: { + name: 'Punishment Ending', + description: 'The message after punishment information to a user in a dm.', + type: 'string', + subType: undefined, + configurable: true + }, + lockdownChannels: { + name: 'Lockdown Channels', + description: 'Channels that are locked down when a mass lockdown is specified.', + type: 'channel-array', + subType: [ChannelType.GuildText], + configurable: true + }, + joinRoles: { + name: 'Join Roles', + description: 'Roles assigned to users on join who do not have sticky role information.', + type: 'role-array', + subType: undefined, + configurable: true + }, + bypassChannelBlacklist: { + name: 'Bypass Channel Blacklist', + description: 'These users will be able to use commands in channels blacklisted.', + type: 'user-array', + subType: undefined, + configurable: true + }, + logChannels: { + name: 'Log Channels', + description: 'The channel were logs are sent.', + type: 'custom', + subType: [ChannelType.GuildText], + configurable: false + }, + autoModPhases: { + name: 'Automod Phases', + description: 'Custom phrases to be detected by automod.', + type: 'custom', + subType: undefined, + configurable: false + }, + noXpChannels: { + name: 'No Xp Channels', + description: 'Channels where users will not earn xp for leveling.', + type: 'channel-array', + subType: [ + ChannelType.GuildText, + ChannelType.GuildNews, + ChannelType.GuildNewsThread, + ChannelType.GuildPublicThread, + ChannelType.GuildPrivateThread + ], + configurable: true + }, + levelRoles: { + name: 'Level Roles', + description: 'What roles get given to users when they reach certain levels.', + type: 'custom', + subType: undefined, + configurable: false + }, + levelUpChannel: { + name: 'Level Up Channel', + description: 'The channel to send level up messages in instead of last channel.', + type: 'channel', + subType: [ + ChannelType.GuildText, + ChannelType.GuildNews, + ChannelType.GuildNewsThread, + ChannelType.GuildPublicThread, + ChannelType.GuildPrivateThread + ], + configurable: true + } +}); + +export type GuildSettings = keyof typeof guildSettingsObj; +export const settingsArr = Object.keys(guildSettingsObj).filter( + (s) => guildSettingsObj[s as GuildSettings].configurable +) as GuildSettings[]; + +interface GuildFeature { + name: string; + description: string; + default: boolean; +} +const asGuildFeature = <T>(gf: { [K in keyof T]: GuildFeature }) => gf; + +export const guildFeaturesObj = asGuildFeature({ + automod: { + name: 'Automod', + description: 'Deletes offensive content as well as phishing links.', + default: false + }, + excludeDefaultAutomod: { + name: 'Exclude Default Automod', + description: 'Opt out of using the default automod options.', + default: false + }, + excludeAutomodScamLinks: { + name: 'Exclude Automod Scam Links', + description: 'Opt out of having automod delete scam links.', + default: false + }, + delScamMentions: { + name: 'Delete Scam Mentions', + description: 'Deletes messages with @everyone and @here mentions that have common scam phrases.', + default: false + }, + autoPublish: { + name: 'Auto Publish', + description: 'Publishes messages in configured announcement channels.', + default: false + }, + // todo implement a better auto thread system + // autoThread: { + // name: 'Auto Thread', + // description: 'Creates a new thread for messages in configured channels.', + // default: false + // }, + blacklistedFile: { + name: 'Blacklisted File', + description: 'Automatically deletes malicious files.', + default: false + }, + boosterMessageReact: { + name: 'Booster Message React', + description: 'Reacts to booster messages with the boost emoji.', + default: false + }, + leveling: { + name: 'Leveling', + description: "Tracks users' messages and assigns them xp.", + default: false + }, + stickyRoles: { + name: 'Sticky Roles', + description: 'Restores past roles to a user when they rejoin.', + default: false + }, + reporting: { + name: 'Reporting', + description: 'Allow users to make reports.', + default: false + }, + modsCanPunishMods: { + name: 'Mods Can Punish Mods', + description: 'Allow moderators to punish other moderators.', + default: false + }, + sendLevelUpMessages: { + name: 'Send Level Up Messages', + description: 'Send a message when a user levels up.', + default: true + }, + logManualPunishments: { + name: 'Log Manual Punishments', + description: "Adds manual punishment to the user's modlogs and the logging channels.", + default: true + } +}); + +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 + }, + report: { + description: 'Logs user reports.', + configurable: true + }, + error: { + description: 'Logs errors that occur with the bot.', + 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[]; diff --git a/src/lib/models/instance/Level.ts b/src/lib/models/instance/Level.ts new file mode 100644 index 0000000..e18753d --- /dev/null +++ b/src/lib/models/instance/Level.ts @@ -0,0 +1,75 @@ +import { type Snowflake } from 'discord.js'; +import { type Sequelize } from 'sequelize'; +import { BaseModel } from '../BaseModel.js'; +const { DataTypes } = (await import('sequelize')).default; + +export interface LevelModel { + user: Snowflake; + guild: Snowflake; + xp: number; +} + +export interface LevelModelCreationAttributes { + user: Snowflake; + guild: Snowflake; + xp?: number; +} + +export class Level extends BaseModel<LevelModel, LevelModelCreationAttributes> implements LevelModel { + /** + * The user's id. + */ + public declare user: Snowflake; + + /** + * The guild where the user is gaining xp. + */ + public declare guild: Snowflake; + + /** + * The user's xp. + */ + public declare xp: number; + + /** + * The user's level. + */ + public get level(): number { + return Level.convertXpToLevel(this.xp); + } + + /** + * Initializes the model. + * @param sequelize The sequelize instance. + */ + public static initModel(sequelize: Sequelize): void { + Level.init( + { + user: { type: DataTypes.STRING, allowNull: false }, + guild: { type: DataTypes.STRING, allowNull: false }, + xp: { type: DataTypes.INTEGER, allowNull: false, defaultValue: 0 } + }, + { sequelize } + ); + } + + public static convertXpToLevel(xp: number): number { + let i = 0; + while (Level.convertLevelToXp(i + 1) < xp) { + i++; + } + return i; + } + + public static convertLevelToXp(level: number): number { + let xp = 0; + for (let i = 0; i < level; i++) { + xp += 100 * i + 75; + } + return xp; + } + + public static genRandomizedXp(): number { + return Math.floor(Math.random() * (40 - 15 + 1)) + 15; + } +} diff --git a/src/lib/models/instance/ModLog.ts b/src/lib/models/instance/ModLog.ts new file mode 100644 index 0000000..bcccbb4 --- /dev/null +++ b/src/lib/models/instance/ModLog.ts @@ -0,0 +1,124 @@ +import { type Snowflake } from 'discord.js'; +import { nanoid } from 'nanoid'; +import { type Sequelize } from 'sequelize'; +import { BaseModel } from '../BaseModel.js'; +const { DataTypes } = (await import('sequelize')).default; + +export enum ModLogType { + PERM_BAN = 'PERM_BAN', + TEMP_BAN = 'TEMP_BAN', + UNBAN = 'UNBAN', + KICK = 'KICK', + PERM_MUTE = 'PERM_MUTE', + TEMP_MUTE = 'TEMP_MUTE', + UNMUTE = 'UNMUTE', + WARN = 'WARN', + PERM_PUNISHMENT_ROLE = 'PERM_PUNISHMENT_ROLE', + TEMP_PUNISHMENT_ROLE = 'TEMP_PUNISHMENT_ROLE', + REMOVE_PUNISHMENT_ROLE = 'REMOVE_PUNISHMENT_ROLE', + PERM_CHANNEL_BLOCK = 'PERM_CHANNEL_BLOCK', + TEMP_CHANNEL_BLOCK = 'TEMP_CHANNEL_BLOCK', + CHANNEL_UNBLOCK = 'CHANNEL_UNBLOCK', + TIMEOUT = 'TIMEOUT', + REMOVE_TIMEOUT = 'REMOVE_TIMEOUT' +} + +export interface ModLogModel { + id: string; + type: ModLogType; + user: Snowflake; + moderator: Snowflake; + reason: string | null; + duration: number | null; + guild: Snowflake; + evidence: string; + pseudo: boolean; + hidden: boolean; +} + +export interface ModLogModelCreationAttributes { + id?: string; + type: ModLogType; + user: Snowflake; + moderator: Snowflake; + reason?: string | null; + duration?: number; + guild: Snowflake; + evidence?: string; + pseudo?: boolean; + hidden?: boolean; +} + +export class ModLog extends BaseModel<ModLogModel, ModLogModelCreationAttributes> implements ModLogModel { + /** + * The primary key of the modlog entry. + */ + public declare id: string; + + /** + * The type of punishment. + */ + public declare type: ModLogType; + + /** + * The user being punished. + */ + public declare user: Snowflake; + + /** + * The user carrying out the punishment. + */ + public declare moderator: Snowflake; + + /** + * The reason the user is getting punished. + */ + public declare reason: string | null; + + /** + * The amount of time the user is getting punished for. + */ + public declare duration: number | null; + + /** + * The guild the user is getting punished in. + */ + public declare guild: Snowflake; + + /** + * Evidence of what the user is getting punished for. + */ + public declare evidence: string; + + /** + * Not an actual modlog just used so a punishment entry can be made. + */ + public declare pseudo: boolean; + + /** + * Hides from the modlog command unless show hidden is specified. + */ + public declare hidden: boolean; + + /** + * Initializes the model. + * @param sequelize The sequelize instance. + */ + public static initModel(sequelize: Sequelize): void { + ModLog.init( + { + id: { type: DataTypes.STRING, primaryKey: true, allowNull: false, defaultValue: nanoid }, + type: { type: DataTypes.STRING, allowNull: false }, //? This is not an enum because of a sequelize issue: https://github.com/sequelize/sequelize/issues/2554 + user: { type: DataTypes.STRING, allowNull: false }, + moderator: { type: DataTypes.STRING, allowNull: false }, + duration: { type: DataTypes.STRING, allowNull: true }, + reason: { type: DataTypes.TEXT, allowNull: true }, + guild: { type: DataTypes.STRING, references: { model: 'Guilds', key: 'id' } }, + evidence: { type: DataTypes.TEXT, allowNull: true }, + pseudo: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: false }, + hidden: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: false } + }, + { sequelize } + ); + } +} diff --git a/src/lib/models/instance/Reminder.ts b/src/lib/models/instance/Reminder.ts new file mode 100644 index 0000000..9ca78f1 --- /dev/null +++ b/src/lib/models/instance/Reminder.ts @@ -0,0 +1,81 @@ +import { Snowflake } from 'discord.js'; +import { nanoid } from 'nanoid'; +import { type Sequelize } from 'sequelize'; +import { BaseModel } from '../BaseModel.js'; +const { DataTypes } = (await import('sequelize')).default; + +export interface ReminderModel { + id: string; + user: Snowflake; + messageUrl: string; + content: string; + created: Date; + expires: Date; + notified: boolean; +} + +export interface ReminderModelCreationAttributes { + id?: string; + user: Snowflake; + messageUrl: string; + content: string; + created: Date; + expires: Date; + notified?: boolean; +} + +export class Reminder extends BaseModel<ReminderModel, ReminderModelCreationAttributes> implements ReminderModel { + /** + * The id of the reminder. + */ + public declare id: string; + + /** + * The user that the reminder is for. + */ + public declare user: Snowflake; + + /** + * The url of the message where the reminder was created. + */ + public declare messageUrl: string; + + /** + * The content of the reminder. + */ + public declare content: string; + + /** + * The date the reminder was created. + */ + public declare created: Date; + + /** + * The date when the reminder expires. + */ + public declare expires: Date; + + /** + * Whether the user has been notified about the reminder. + */ + public declare notified: boolean; + + /** + * Initializes the model. + * @param sequelize The sequelize instance. + */ + public static initModel(sequelize: Sequelize): void { + Reminder.init( + { + id: { type: DataTypes.STRING, primaryKey: true, defaultValue: nanoid }, + user: { type: DataTypes.STRING, allowNull: false }, + messageUrl: { type: DataTypes.STRING, allowNull: false }, + content: { type: DataTypes.TEXT, allowNull: false }, + created: { type: DataTypes.DATE, allowNull: false }, + expires: { type: DataTypes.DATE, allowNull: false }, + notified: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: false } + }, + { sequelize } + ); + } +} diff --git a/src/lib/models/instance/StickyRole.ts b/src/lib/models/instance/StickyRole.ts new file mode 100644 index 0000000..fb1c30d --- /dev/null +++ b/src/lib/models/instance/StickyRole.ts @@ -0,0 +1,55 @@ +import { type Snowflake } from 'discord.js'; +import { type Sequelize } from 'sequelize'; +import { BaseModel } from '../BaseModel.js'; +const { DataTypes } = (await import('sequelize')).default; + +export interface StickyRoleModel { + user: Snowflake; + guild: Snowflake; + roles: Snowflake[]; + nickname: string; +} +export interface StickyRoleModelCreationAttributes { + user: Snowflake; + guild: Snowflake; + roles: Snowflake[]; + nickname?: string; +} + +export class StickyRole extends BaseModel<StickyRoleModel, StickyRoleModelCreationAttributes> implements StickyRoleModel { + /** + * The id of the user the roles belongs to. + */ + public declare user: Snowflake; + + /** + * The guild where this should happen. + */ + public declare guild: Snowflake; + + /** + * The roles that the user should have returned + */ + public declare roles: Snowflake[]; + + /** + * The user's previous nickname + */ + public declare nickname: string; + + /** + * Initializes the model. + * @param sequelize The sequelize instance. + */ + public static initModel(sequelize: Sequelize): void { + StickyRole.init( + { + user: { type: DataTypes.STRING, allowNull: false }, + guild: { type: DataTypes.STRING, allowNull: false }, + roles: { type: DataTypes.JSONB, allowNull: false, defaultValue: [] }, + nickname: { type: DataTypes.STRING, allowNull: true } + }, + { sequelize } + ); + } +} |