diff --git a/.env.sample b/.env.sample index c40eeaa..bf3df0f 100644 --- a/.env.sample +++ b/.env.sample @@ -2,9 +2,6 @@ BOT_TOKEN = #used for adding bot/application to server CLIENT_ID = -# invite link: -# https://discord.com/api/oauth2/authorize?CLIENT_ID=&permissions=0&scope=bot%20applications.commands -SERVER_ID = # Mongo configuration MONGO_URI= MONGO_PORT= diff --git a/package.json b/package.json index 1b25ad0..25d5f8a 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,6 @@ "build": "npm run deldist && tsc -p .", "start:ts-node": "ts-node src/main.ts", "start": "nest start", - "tunnel": "ngrok http 3000", "start:debug": "nest start --debug --watch", "build:prod": "docker build --pull --rm -f \"dockerfiles\\Dockerfile.prod\" -t ghcr.io/blvckleg/bingusboingus:latest \".\"", "build:test": "docker build --pull --rm -f \"dockerfiles\\Dockerfile.test\" -t ghcr.io/blvckleg/bingusboingus:test \".\"", diff --git a/src/deployment/deploy.service.ts b/src/deployment/deploy.service.ts index c3775e1..9988b22 100644 --- a/src/deployment/deploy.service.ts +++ b/src/deployment/deploy.service.ts @@ -1,4 +1,8 @@ -import { REST, RESTPostAPIChatInputApplicationCommandsJSONBody, Routes } from 'discord.js'; +import { + REST, + RESTPostAPIChatInputApplicationCommandsJSONBody, + Routes, +} from 'discord.js'; import { Injectable } from '@nestjs/common'; import { CommandService } from '../modules/command/command.service'; import { AppConfigService } from '../config/config.service'; @@ -18,18 +22,25 @@ export class DeployServcice { return commands.map((command) => command.data.toJSON()); } - async deployCommands(commands: RESTPostAPIChatInputApplicationCommandsJSONBody[]) { + async deployCommands( + commands: RESTPostAPIChatInputApplicationCommandsJSONBody[], + ) { // Construct and prepare an instance of the REST module const rest = new REST().setToken(this.configService.botToken); // and deploy your commands! try { - console.log(`Started refreshing ${commands.length} application (/) commands.`); + console.log( + `Started refreshing ${commands.length} application (/) commands.`, + ); // The put method is used to fully refresh all commands in the guild with the current set - const data = await rest.put(Routes.applicationGuildCommands(process.env.CLIENT_ID ?? '', process.env.SERVER_ID ?? ''), { - body: commands, - }); + const data = await rest.put( + Routes.applicationCommands(process.env.CLIENT_ID ?? ''), + { + body: commands, + }, + ); let log = ''; if (Array.isArray(data)) log = data.length + ' '; diff --git a/src/modules/command/command.module.ts b/src/modules/command/command.module.ts index 0ae4977..bab0dc2 100644 --- a/src/modules/command/command.module.ts +++ b/src/modules/command/command.module.ts @@ -18,6 +18,8 @@ import { SomeoneOnceSaidModule } from '../models/someone-once-said/module/someon import { PollModule } from '../models/poll/module/poll.module'; import { VersionModule } from '../models/version/module/version.module'; import { BirthdayEntryModule } from '../models/birthday/module/birthday-entry.module'; +import ConfigureServerChannelCommand from './commands/server-config'; +import { ServerConfigModule } from '../models/config/module/server-config.module'; @Module({ providers: [ @@ -34,10 +36,17 @@ import { BirthdayEntryModule } from '../models/birthday/module/birthday-entry.mo PollCommand, VersionCommand, AddBirthdayEntryCommand, + ConfigureServerChannelCommand, DeactivateBirthdayEntryShoutoutCommand, ActivateBirthdayEntryShoutoutCommand, ], - imports: [SomeoneOnceSaidModule, PollModule, VersionModule, BirthdayEntryModule], + imports: [ + SomeoneOnceSaidModule, + PollModule, + VersionModule, + BirthdayEntryModule, + ServerConfigModule, + ], exports: [CommandService], }) export class CommandModule {} diff --git a/src/modules/command/command.service.ts b/src/modules/command/command.service.ts index 05e756b..2c98b60 100644 --- a/src/modules/command/command.service.ts +++ b/src/modules/command/command.service.ts @@ -14,6 +14,7 @@ import { BirthdayEntry } from '../../schemas/birthday-entry.schema'; import AddBirthdayEntryCommand from './commands/add-birthday-entry'; import DeactivateBirthdayEntryShoutoutCommand from './commands/deactivate-birthday-shoutout'; import ActivateBirthdayEntryShoutoutCommand from './commands/activate-birthday-shoutout'; +import ConfigureServerChannelCommand from './commands/server-config'; @Injectable() export class CommandService { @@ -34,6 +35,7 @@ export class CommandService { addBirthdayEntryModule: AddBirthdayEntryCommand, deactivateBirthdayEntryShoutoutModule: DeactivateBirthdayEntryShoutoutCommand, activateBirthdayEntryShoutoutModule: ActivateBirthdayEntryShoutoutCommand, + configureServerChannelIdModule: ConfigureServerChannelCommand, ) { const commands: ACommand[] = [ //pingpongModule, @@ -50,6 +52,7 @@ export class CommandService { addBirthdayEntryModule, deactivateBirthdayEntryShoutoutModule, activateBirthdayEntryShoutoutModule, + configureServerChannelIdModule, ]; commands.forEach((command) => { if (command.data.name && !!command.execute) { diff --git a/src/modules/command/commands/activate-birthday-shoutout.ts b/src/modules/command/commands/activate-birthday-shoutout.ts index 05968ad..00d48b4 100644 --- a/src/modules/command/commands/activate-birthday-shoutout.ts +++ b/src/modules/command/commands/activate-birthday-shoutout.ts @@ -27,6 +27,7 @@ export default class ActivateBirthdayEntryShoutoutCommand extends ACommand { const instance: CreateOrUpdateBirthdayEntryDto = { username: arg.user.username, secName: arg.user.displayName, + serverId: arg.guildId, active: true, }; const inactive = diff --git a/src/modules/command/commands/add-birthday-entry.ts b/src/modules/command/commands/add-birthday-entry.ts index 15483b0..5ebd1a9 100644 --- a/src/modules/command/commands/add-birthday-entry.ts +++ b/src/modules/command/commands/add-birthday-entry.ts @@ -8,10 +8,6 @@ import { ACommand } from '../command.abstract'; import { Inject } from '@nestjs/common'; import { BirthdayEntryService } from '../../models/birthday/service/birthday-entry.service'; import { CreateOrUpdateBirthdayEntryDto } from '../../models/birthday/dto/create-or-update-birthday-entry.dto'; -import { - CommandAccessLevel, - Role, -} from '../../../common/decoratos/role.decorator'; export default class AddBirthdayEntryCommand extends ACommand { constructor( @@ -56,6 +52,7 @@ export default class AddBirthdayEntryCommand extends ACommand { birthDate: dateValue, username: arg.user.username, secName: arg.user.displayName, + serverId: arg.guildId, active: true, }; const created = diff --git a/src/modules/command/commands/deactivate-birthday-shoutout.ts b/src/modules/command/commands/deactivate-birthday-shoutout.ts index 0761f13..14e4fbf 100644 --- a/src/modules/command/commands/deactivate-birthday-shoutout.ts +++ b/src/modules/command/commands/deactivate-birthday-shoutout.ts @@ -27,6 +27,7 @@ export default class DeactivateBirthdayEntryShoutoutCommand extends ACommand { const instance: CreateOrUpdateBirthdayEntryDto = { username: arg.user.username, secName: arg.user.displayName, + serverId: arg.guildId, active: false, }; const inactive = diff --git a/src/modules/command/commands/get-a-quote.ts b/src/modules/command/commands/get-a-quote.ts index cd8232a..f71522e 100644 --- a/src/modules/command/commands/get-a-quote.ts +++ b/src/modules/command/commands/get-a-quote.ts @@ -25,7 +25,9 @@ export default class GetRandomQuote extends ACommand { // @Role(CommandAccessLevel.member) async execute(arg: CommandInteraction): Promise { - const someoneOnceSaid = await this.someoneonceSaidService.getRandomQuote(); + const someoneOnceSaid = await this.someoneonceSaidService.getRandomQuote( + arg.guildId, + ); if (!someoneOnceSaid) return; const quoteEmbed = new EmbedBuilder() .setTitle( diff --git a/src/modules/command/commands/server-config.ts b/src/modules/command/commands/server-config.ts new file mode 100644 index 0000000..03167c1 --- /dev/null +++ b/src/modules/command/commands/server-config.ts @@ -0,0 +1,57 @@ +import { + CacheType, + CommandInteraction, + EmbedBuilder, + SlashCommandBuilder, +} from 'discord.js'; +import { ACommand } from '../command.abstract'; +import { Inject } from '@nestjs/common'; +import { ServerConfigService } from '../../models/config/service/server-config.service'; +import { CreateOrUpdateServerConfigDto } from '../../models/config/dto/create-or-update-server-config.dto'; + +export default class ConfigureServerChannelCommand extends ACommand { + constructor( + @Inject(ServerConfigService) + private readonly configService: ServerConfigService, + ) { + super(); + } + data = new SlashCommandBuilder() + .setName('configure') + .setDescription( + 'set the channel id where the bot will send all scheduled messages', + ) + .addStringOption((option) => + option.setName('channelid').setDescription('the Id of the text-channel'), + ); + + // @Role(CommandAccessLevel.member) + async execute(arg: CommandInteraction): Promise { + const channelId = arg.options.get('channelid'); + if (!channelId) { + await arg.reply({ + content: 'you need to provide a valid channel Id! 🤓', + ephemeral: true, + }); + return false; + } + await arg.deferReply(); + const channelIdValue = channelId.value as unknown as string; + const instance: CreateOrUpdateServerConfigDto = { + channelId: channelIdValue, + serverId: arg.guildId, + }; + const created = + await this.configService.createOrUpdateServerConfig(instance); + const quoteEmbed = new EmbedBuilder() + .setTitle('Your scheduled messages textchannel was configured! 🤓') + .setDescription('🤓') + .setFooter({ + text: 'scheduled messages activated', + }) + .setTimestamp(new Date()); + await arg.editReply({ embeds: [quoteEmbed] }); + return true; + } +} + diff --git a/src/modules/command/commands/someone-once-said.ts b/src/modules/command/commands/someone-once-said.ts index 2108abc..ba58d86 100644 --- a/src/modules/command/commands/someone-once-said.ts +++ b/src/modules/command/commands/someone-once-said.ts @@ -12,6 +12,7 @@ import { CommandAccessLevel, Role, } from '../../../common/decoratos/role.decorator'; +import { server } from 'typescript'; export default class SomeoneOnceSaidCommand extends ACommand { constructor( @@ -46,6 +47,7 @@ export default class SomeoneOnceSaidCommand extends ACommand { phrase: phraseValue, username: arg.user.username, secName: arg.user.displayName, + serverId: arg.guildId, }); const created = await this.someoneonceSaidService.create(instance); const quoteEmbed = new EmbedBuilder() diff --git a/src/modules/cron-tasks/cron.service.ts b/src/modules/cron-tasks/cron.service.ts index 02e3d54..dc7f7ea 100644 --- a/src/modules/cron-tasks/cron.service.ts +++ b/src/modules/cron-tasks/cron.service.ts @@ -1,4 +1,4 @@ -import { Client, TextChannel } from 'discord.js'; +import { TextChannel } from 'discord.js'; import BirthdayShoutoutTask from './tasks/birthday-shoutout.task'; import { Inject, Injectable } from '@nestjs/common'; import WakeUpTask from './tasks/wake-up.task'; @@ -6,6 +6,8 @@ import * as cron from 'node-cron'; import { BirthdayEntryService } from '../models/birthday/service/birthday-entry.service'; import { TaskEntry } from './interfaces/task-entry.interface'; import { DiscordService } from '../discord/discord.service'; +import { ServerConfigService } from '../models/config/service/server-config.service'; +import { ServerConfigDocument } from '../../schemas/server-config.schema'; @Injectable() export class CronService { @@ -17,6 +19,8 @@ export class CronService { private readonly birthdayService: BirthdayEntryService, @Inject(DiscordService) private readonly discordService: DiscordService, + @Inject(ServerConfigService) + private readonly serverConfigService: ServerConfigService, ) { if (CronService.instance) { throw new Error(`ERROR: An instance has already been created.`); @@ -29,28 +33,32 @@ export class CronService { return CronService.instance; } - public init() { - this.tasks = [ - { + public async init() { + const servers: ServerConfigDocument[] = + await this.serverConfigService.getAll(); + let birthdayTasks = []; + servers.forEach((server) => { + const birthdayChannel = this.discordService.client.channels.cache.find( + (channel) => channel.id === server.channelId, + ) as TextChannel; + birthdayTasks.push({ name: 'birthday-shoutout', schedule: '0 10 * * *', - task: new BirthdayShoutoutTask( - this.discordService.client.channels.cache.find( - (channel) => channel.id === '447554141724737548', - ) as TextChannel, - this.birthdayService, - ), - }, - { + task: new BirthdayShoutoutTask(birthdayChannel, this.birthdayService), + }); + }); + let wakeUpTasks = []; + servers.forEach((server) => { + const wakeUpChannel = this.discordService.client.channels.cache.find( + (channel) => channel.id === server.channelId, + ) as TextChannel; + wakeUpTasks.push({ name: 'first-of-the-month', schedule: '0 12 1 * *', - task: new WakeUpTask( - this.discordService.client.channels.cache.find( - (channel) => channel.id === '447554141724737548', - ) as TextChannel, - ), - }, - ]; + task: new WakeUpTask(wakeUpChannel), + }); + }); + this.tasks = [...birthdayTasks, ...wakeUpTasks]; this.registerTasks(); } diff --git a/src/modules/cron-tasks/task.module.ts b/src/modules/cron-tasks/task.module.ts index 98edce4..dd515ce 100644 --- a/src/modules/cron-tasks/task.module.ts +++ b/src/modules/cron-tasks/task.module.ts @@ -2,9 +2,10 @@ import { Module } from '@nestjs/common'; import { BirthdayEntryModule } from '../models/birthday/module/birthday-entry.module'; import { CronService } from './cron.service'; import { DiscordModule } from '../discord/discord.module'; +import { ServerConfigModule } from '../models/config/module/server-config.module'; @Module({ - imports: [DiscordModule, BirthdayEntryModule], + imports: [DiscordModule, BirthdayEntryModule, ServerConfigModule], providers: [CronService], exports: [CronService], }) diff --git a/src/modules/cron-tasks/tasks/birthday-shoutout.task.ts b/src/modules/cron-tasks/tasks/birthday-shoutout.task.ts index bc9a222..ed56fc8 100644 --- a/src/modules/cron-tasks/tasks/birthday-shoutout.task.ts +++ b/src/modules/cron-tasks/tasks/birthday-shoutout.task.ts @@ -1,35 +1,46 @@ -import { EmbedBuilder, TextChannel } from 'discord.js' -import { ITask } from './interfaces/task.interface' -import { BirthdayEntryService } from '../../models/birthday/service/birthday-entry.service' +import { EmbedBuilder, TextChannel } from 'discord.js'; +import { ITask } from './interfaces/task.interface'; +import { BirthdayEntryService } from '../../models/birthday/service/birthday-entry.service'; export default class BirthdayShoutoutTask implements ITask { - private channel: TextChannel + private channel: TextChannel; - constructor(channel: TextChannel, private readonly birthdayService: BirthdayEntryService) { - this.channel = channel - } - - async execute(): Promise { - const birthDayEntries = await this.birthdayService.getEntryForToday() + constructor( + channel: TextChannel, + private readonly birthdayService: BirthdayEntryService, + ) { + this.channel = channel; + } - if (!birthDayEntries || birthDayEntries.length < 1) { - return - } + async execute(): Promise { + const birthDayEntries = await this.birthdayService.getEntryForToday(); - birthDayEntries.forEach((entry) => { - const creator = this.channel.members.find((member) => member.user.username === entry.username || member.user.displayName === entry.secName) + if (!birthDayEntries || birthDayEntries.length < 1) { + return; + } - const embed = new EmbedBuilder() - .setTitle(`🚨 Birthday Alert!! 🚨`) - .setColor('Random') - .setDescription(`${entry.username ?? entry.secName} is turning **${new Date().getFullYear() - entry.birthDate.getFullYear()}** years old today! 🎉🎂🎈`) - .setFooter({ - text: creator?.user.username ?? 'bingus', - iconURL: creator?.displayAvatarURL() ?? undefined, - }) - .setTimestamp(new Date()) + birthDayEntries.forEach((entry) => { + const creator = this.channel.members.find( + (member) => + member.user.username === entry.username || + member.user.displayName === entry.secName, + ); - this.channel.send({ embeds: [embed] }) + const embed = new EmbedBuilder() + .setTitle(`🚨 Birthday Alert!! 🚨`) + .setColor('Random') + .setDescription( + `${entry.username ?? entry.secName} is turning **${ + new Date().getFullYear() - entry.birthDate.getFullYear() + }** years old today! 🎉🎂🎈`, + ) + .setFooter({ + text: creator?.user.username ?? 'bingus', + iconURL: creator?.displayAvatarURL() ?? undefined, }) - } -} \ No newline at end of file + .setTimestamp(new Date()); + + this.channel.send({ embeds: [embed] }); + }); + } +} diff --git a/src/modules/event/services/clientReady.ts b/src/modules/event/services/clientReady.ts index f79a88a..8894ef2 100644 --- a/src/modules/event/services/clientReady.ts +++ b/src/modules/event/services/clientReady.ts @@ -16,6 +16,6 @@ export class ClientReady extends AEvent { console.log('Successfully connected to Discord'); console.log(`logged in as ${args[0].user.username}`); - this.cronService.init(); + await this.cronService.init(); } } diff --git a/src/modules/models/birthday/dto/create-or-update-birthday-entry.dto.ts b/src/modules/models/birthday/dto/create-or-update-birthday-entry.dto.ts index efe2a3f..78e8048 100644 --- a/src/modules/models/birthday/dto/create-or-update-birthday-entry.dto.ts +++ b/src/modules/models/birthday/dto/create-or-update-birthday-entry.dto.ts @@ -18,6 +18,14 @@ export class CreateOrUpdateBirthdayEntryDto { @IsOptional() secName: string; + @ApiProperty({ + example: '12398182390132', + description: 'The discord serverId the interaction comes from', + type: String, + }) + @IsNotEmpty() + serverId: string; + @ApiProperty({ example: '2024-01-01T00:00:00.000Z', description: 'The birthdate of the user in ISO format', diff --git a/src/modules/models/birthday/service/birthday-entry.service.ts b/src/modules/models/birthday/service/birthday-entry.service.ts index 1a7ae60..d23940d 100644 --- a/src/modules/models/birthday/service/birthday-entry.service.ts +++ b/src/modules/models/birthday/service/birthday-entry.service.ts @@ -8,8 +8,13 @@ export class BirthdayEntryService { @InjectModel('BirthdayEntry') private readonly birthdayEntry: Model, ) {} - async createOrUpdateBirthdayEntry(birthdayEntryDto: CreateOrUpdateBirthdayEntryDto,) { - const birthdayEntry = await this.birthdayEntry.findOne({ username: birthdayEntryDto.username }); + async createOrUpdateBirthdayEntry( + birthdayEntryDto: CreateOrUpdateBirthdayEntryDto, + ) { + const birthdayEntry = await this.birthdayEntry.findOne({ + username: birthdayEntryDto.username, + serverId: birthdayEntryDto.serverId, + }); if (birthdayEntry) { return await this.updateBirthdayEntry(birthdayEntryDto); } else { @@ -26,6 +31,7 @@ export class BirthdayEntryService { secName: birthdayEntryDto?.secName, birthDate: birthdayEntryDto.birthDate, active: true, + serverId: birthdayEntryDto.serverId, createdAt: new Date(), }); } catch (e) { @@ -33,7 +39,9 @@ export class BirthdayEntryService { } } - async updateBirthdayEntry(birthdayEntryDto: CreateOrUpdateBirthdayEntryDto): Promise { + async updateBirthdayEntry( + birthdayEntryDto: CreateOrUpdateBirthdayEntryDto, + ): Promise { try { return await this.birthdayEntry.findOneAndUpdate( { username: birthdayEntryDto.username }, @@ -51,22 +59,23 @@ export class BirthdayEntryService { async getEntryForToday(): Promise { try { - const entries = await this.birthdayEntry.find({ active: true }); + const entries = await this.birthdayEntry.find({ + active: true, + }); if (!entries) { - return null + return null; } - const today = new Date() + const today = new Date(); - return entries - .filter((entry) => { - const date = new Date(entry.birthDate) - return ( - date.getFullYear() !== today.getFullYear() && - date.getMonth() === today.getMonth() && - date.getDate() === today.getDate() - ) - }) + return entries.filter((entry) => { + const date = new Date(entry.birthDate); + return ( + date.getFullYear() !== today.getFullYear() && + date.getMonth() === today.getMonth() && + date.getDate() === today.getDate() + ); + }); } catch (e) { return null; } diff --git a/src/modules/models/config/dto/create-or-update-server-config.dto.ts b/src/modules/models/config/dto/create-or-update-server-config.dto.ts new file mode 100644 index 0000000..35ac0e8 --- /dev/null +++ b/src/modules/models/config/dto/create-or-update-server-config.dto.ts @@ -0,0 +1,21 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { IsNotEmpty } from 'class-validator'; + +export class CreateOrUpdateServerConfigDto { + @ApiProperty({ + example: '239123321', + description: 'The discord serverId', + type: String, + }) + @IsNotEmpty() + serverId: string; + + @ApiProperty({ + example: '321123312123', + description: 'The discord channelId for cron tasks', + type: String, + }) + @IsNotEmpty() + channelId: string; +} + diff --git a/src/modules/models/config/module/server-config.module.ts b/src/modules/models/config/module/server-config.module.ts new file mode 100644 index 0000000..0d20ecb --- /dev/null +++ b/src/modules/models/config/module/server-config.module.ts @@ -0,0 +1,22 @@ +import { Module } from '@nestjs/common'; +import { MongooseModule } from '@nestjs/mongoose'; +import { ServerConfigService } from '../service/server-config.service'; +import { + ServerConfig, + ServerConfigSchema, +} from '../../../../schemas/server-config.schema'; + +@Module({ + imports: [ + MongooseModule.forFeature([ + { + name: ServerConfig.name, + schema: ServerConfigSchema, + }, + ]), + ], + controllers: [], + providers: [ServerConfigService], + exports: [ServerConfigService], +}) +export class ServerConfigModule {} diff --git a/src/modules/models/config/service/server-config.service.ts b/src/modules/models/config/service/server-config.service.ts new file mode 100644 index 0000000..768f926 --- /dev/null +++ b/src/modules/models/config/service/server-config.service.ts @@ -0,0 +1,76 @@ +import { InjectModel } from '@nestjs/mongoose'; +import { Model } from 'mongoose'; +import { CreateOrUpdateServerConfigDto } from '../dto/create-or-update-server-config.dto'; +import { ServerConfigDocument } from '../../../../schemas/server-config.schema'; + +export class ServerConfigService { + constructor( + @InjectModel('ServerConfig') + private readonly serverConfig: Model, + ) {} + async createOrUpdateServerConfig( + serverConfigDto: CreateOrUpdateServerConfigDto, + ) { + const entry = await this.serverConfig.findOne({ + channelId: serverConfigDto.channelId, + serverId: serverConfigDto.serverId, + }); + if (entry) { + return await this.updateEntry(serverConfigDto); + } else { + return await this.create(serverConfigDto); + } + } + + async create( + birthdayEntryDto: CreateOrUpdateServerConfigDto, + ): Promise { + try { + return await this.serverConfig.create({ + channelId: birthdayEntryDto.channelId, + serverId: birthdayEntryDto.serverId, + }); + } catch (e) { + return null; + } + } + + async updateEntry( + dto: CreateOrUpdateServerConfigDto, + ): Promise { + try { + return await this.serverConfig.findOneAndUpdate( + { serverId: dto.serverId }, + { + channelId: dto.channelId, + }, + { new: true }, + ); + } catch (e) { + return null; + } + } + + async getEntryForServer(serverId: string): Promise { + try { + const entry = await this.serverConfig.findOne({ + serverId: serverId, + }); + if (!entry) { + return null; + } + + return entry; + } catch (e) { + return null; + } + } + + async getAll(): Promise { + try { + return await this.serverConfig.find(); + } catch (e) { + return null; + } + } +} diff --git a/src/modules/models/poll/dto/update-poll.dto.ts b/src/modules/models/poll/dto/update-poll.dto.ts index ade9487..095f8b7 100644 --- a/src/modules/models/poll/dto/update-poll.dto.ts +++ b/src/modules/models/poll/dto/update-poll.dto.ts @@ -1,26 +1,27 @@ -import { IsNotEmpty, IsOptional } from "class-validator"; +import { IsNotEmpty, IsOptional } from 'class-validator'; export class UpdatePollDto { - @IsNotEmpty() - msg: string; + @IsNotEmpty() + msg: string; - @IsNotEmpty() - upvotes: number; + @IsNotEmpty() + upvotes: number; - @IsNotEmpty() - downvotes: number; + @IsNotEmpty() + downvotes: number; - @IsOptional() - active: boolean; + @IsNotEmpty() + serverId: string; - @IsOptional() - ownerName: string; + @IsOptional() + active: boolean; - @IsOptional() - downMembers: string[] + @IsOptional() + ownerName: string; - @IsOptional() - upMembers: string[] + @IsOptional() + downMembers: string[]; - -} \ No newline at end of file + @IsOptional() + upMembers: string[]; +} diff --git a/src/modules/models/poll/service/db-poll.service.ts b/src/modules/models/poll/service/db-poll.service.ts index 45bd9da..2efa682 100644 --- a/src/modules/models/poll/service/db-poll.service.ts +++ b/src/modules/models/poll/service/db-poll.service.ts @@ -19,6 +19,7 @@ export class DbPollService { downvotes: pollDto.downvotes, upMembers: pollDto?.upMembers ?? [], downMembers: pollDto?.downMembers ?? [], + serverId: pollDto.serverId, active: true, createdAt: new Date(), }); @@ -28,10 +29,12 @@ export class DbPollService { } } - async update(updateDto: UpdatePollDto): Promise { + async update( + updateDto: UpdatePollDto, + ): Promise { try { return await this.pollModel.findOneAndUpdate( - { msg: updateDto.msg }, + { msg: updateDto.msg, serverId: updateDto.serverId }, { upvotes: updateDto.upvotes, downvotes: updateDto?.downvotes, @@ -46,10 +49,14 @@ export class DbPollService { } } - async get(messageId: string): Promise { + async get( + messageId: string, + serverId: string, + ): Promise { try { const test = await this.pollModel.findOne({ msg: messageId, + serverId: serverId, active: true, }); return test; diff --git a/src/modules/models/poll/service/poll.service.ts b/src/modules/models/poll/service/poll.service.ts index c8615c7..8e501cf 100644 --- a/src/modules/models/poll/service/poll.service.ts +++ b/src/modules/models/poll/service/poll.service.ts @@ -65,6 +65,7 @@ export class PollService { downMembers: [], active: true, ownerName: arg.user.username, + serverId: arg.guild.id, createdAt: new Date(), }); } @@ -79,7 +80,10 @@ export class PollService { } public async upVote(interaction: ButtonInteraction) { - const data = await this.dbPollService.get(interaction.message.id); + const data = await this.dbPollService.get( + interaction.message.id, + interaction.guild.id, + ); if (!data) return; const msg = await interaction.channel.messages.fetch(data.msg); @@ -103,7 +107,10 @@ export class PollService { } public async downVote(interaction: ButtonInteraction) { - const data = await this.dbPollService.get(interaction.message.id); + const data = await this.dbPollService.get( + interaction.message.id, + interaction.guild.id, + ); if (!data) return; const msg = await interaction.channel.messages.fetch(data.msg); @@ -127,7 +134,10 @@ export class PollService { } public async closePoll(interaction: ButtonInteraction) { - const data = await this.dbPollService.get(interaction.message.id); + const data = await this.dbPollService.get( + interaction.message.id, + interaction.guild.id, + ); if (!data) return; const msg = await interaction.channel.messages.fetch(data.msg); if (interaction.user.username == data.ownerName) { diff --git a/src/modules/models/someone-once-said/service/someone-once-said.service.spec.ts b/src/modules/models/someone-once-said/service/someone-once-said.service.spec.ts index 3bc98dd..7cbcbf9 100644 --- a/src/modules/models/someone-once-said/service/someone-once-said.service.spec.ts +++ b/src/modules/models/someone-once-said/service/someone-once-said.service.spec.ts @@ -14,6 +14,7 @@ describe('SomeoneOnceSaidService', () => { phrase: 'Test quote', username: 'testUser', secName: 'Teschter', + serverId: 'someid', createdAt: mockDate, }; const mockQuoteDocument: SomeoneOnceSaidDocument = { @@ -64,6 +65,7 @@ describe('SomeoneOnceSaidService', () => { const mockQuoteDto: SomeoneOnceSaidEntity = { phrase: 'Test quote', username: 'testUser', + serverId: 'someid', createdAt: mockDate, }; (modelMock as any).create = jest.fn((p) => new Error('Test error')); @@ -74,7 +76,6 @@ describe('SomeoneOnceSaidService', () => { }); }); - describe('getRandomQuote', () => { it('should return a random quote', async () => { (modelMock as any).findOne = jest.fn((p) => ({ @@ -85,7 +86,7 @@ describe('SomeoneOnceSaidService', () => { const countSpy = jest.spyOn(modelMock, 'countDocuments'); const findOneSpy = jest.spyOn(modelMock, 'findOne'); - const result = await service.getRandomQuote(); + const result = await service.getRandomQuote('someid'); expect(result).toStrictEqual(mockQuoteDocument); expect(countSpy).toHaveBeenCalled(); @@ -97,7 +98,7 @@ describe('SomeoneOnceSaidService', () => { (p) => new Error('Test error'), ); - const result = await service.getRandomQuote(); + const result = await service.getRandomQuote('someid'); expect(result).toBeNull(); }); diff --git a/src/modules/models/someone-once-said/service/someone-once-said.service.ts b/src/modules/models/someone-once-said/service/someone-once-said.service.ts index 8494e05..447630a 100644 --- a/src/modules/models/someone-once-said/service/someone-once-said.service.ts +++ b/src/modules/models/someone-once-said/service/someone-once-said.service.ts @@ -17,21 +17,26 @@ export class SomeoneOnceSaidService { phrase: quoteDto.phrase, username: quoteDto.username, secName: quoteDto?.secName, + serverId: quoteDto.serverId, createdAt: new Date(), }); } catch (e) { return null; } } - - async getRandomQuote(): Promise { + + async getRandomQuote( + serverId: string, + ): Promise { try { - const count = await this.someoneOnceSaid.countDocuments(); + const count = await this.someoneOnceSaid.countDocuments({ + serverId: serverId, + }); const randomIndex = Math.floor(Math.random() * count); const randomQuote = await this.someoneOnceSaid - .findOne() + .findOne({ serverId: serverId }) .skip(randomIndex) .limit(1); diff --git a/src/schemas/birthday-entry.model.ts b/src/schemas/birthday-entry.model.ts index 773ef5f..6b12618 100644 --- a/src/schemas/birthday-entry.model.ts +++ b/src/schemas/birthday-entry.model.ts @@ -1,8 +1,8 @@ export class BirthdayEntryEntity { - username: string; - secName: string; - birthDate: Date; - createdAt: Date; - active?: boolean; - } - \ No newline at end of file + username: string; + secName: string; + birthDate: Date; + serverId: string; + createdAt: Date; + active?: boolean; +} diff --git a/src/schemas/birthday-entry.schema.ts b/src/schemas/birthday-entry.schema.ts index df61799..853386f 100644 --- a/src/schemas/birthday-entry.schema.ts +++ b/src/schemas/birthday-entry.schema.ts @@ -7,13 +7,16 @@ export class BirthdayEntry { @Prop({ required: false }) secName: string; - + @Prop({ required: true }) birthDate: Date; @Prop({ required: true }) active: boolean; + @Prop({ required: true }) + serverId: string; + @Prop({ required: true }) createdAt: Date; @@ -24,5 +27,4 @@ export class BirthdayEntry { export type BirthdayEntryDocument = BirthdayEntry & Document; -export const BirthdayEntrySchema = - SchemaFactory.createForClass(BirthdayEntry); +export const BirthdayEntrySchema = SchemaFactory.createForClass(BirthdayEntry); diff --git a/src/schemas/poll-entity.model.ts b/src/schemas/poll-entity.model.ts index ebd4a96..d931b41 100644 --- a/src/schemas/poll-entity.model.ts +++ b/src/schemas/poll-entity.model.ts @@ -1,11 +1,11 @@ export class PollEntity { - msg: string; - ownerName: string; - upvotes: number; - downvotes: number; - upMembers?: string[]; - downMembers?: string[]; - active: boolean; - createdAt: Date; - } - \ No newline at end of file + msg: string; + ownerName: string; + upvotes: number; + downvotes: number; + upMembers?: string[]; + downMembers?: string[]; + active: boolean; + serverId: string; + createdAt: Date; +} diff --git a/src/schemas/poll.schema.ts b/src/schemas/poll.schema.ts index 35d77fe..262e5aa 100644 --- a/src/schemas/poll.schema.ts +++ b/src/schemas/poll.schema.ts @@ -23,6 +23,9 @@ export class Poll { @Prop({ required: true }) active: boolean; + @Prop({ required: true }) + serverId: string; + @Prop({ required: true }) createdAt: Date; @@ -33,5 +36,4 @@ export class Poll { export type PollDocument = Poll & Document; -export const PollSchema = - SchemaFactory.createForClass(Poll); +export const PollSchema = SchemaFactory.createForClass(Poll); diff --git a/src/schemas/server-config.schema.ts b/src/schemas/server-config.schema.ts new file mode 100644 index 0000000..5061fb5 --- /dev/null +++ b/src/schemas/server-config.schema.ts @@ -0,0 +1,19 @@ +import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; + +@Schema() +export class ServerConfig { + @Prop({ required: true }) + channelId: string; + + @Prop({ required: true, unique: true }) + serverId: string; + + constructor(data) { + Object.assign(this, data); + } +} + +export type ServerConfigDocument = ServerConfig & Document; + +export const ServerConfigSchema = SchemaFactory.createForClass(ServerConfig); + diff --git a/src/schemas/someone-once-said-entity.model.ts b/src/schemas/someone-once-said-entity.model.ts index 0eb6d1a..3689343 100644 --- a/src/schemas/someone-once-said-entity.model.ts +++ b/src/schemas/someone-once-said-entity.model.ts @@ -3,4 +3,5 @@ export class SomeoneOnceSaidEntity { username: string; secName?: string; createdAt: Date; + serverId: string; } diff --git a/src/schemas/someone-once-said.schema.ts b/src/schemas/someone-once-said.schema.ts index 1392e66..2117f2f 100644 --- a/src/schemas/someone-once-said.schema.ts +++ b/src/schemas/someone-once-said.schema.ts @@ -11,6 +11,9 @@ export class SomeoneOnceSaid { @Prop({ required: false }) secName: string; + @Prop({ required: true }) + serverId: string; + @Prop({ required: true }) createdAt: Date;