From 4164fab53ff27090136aef4b4c7e2ca9a83befe3 Mon Sep 17 00:00:00 2001 From: Michal Drla Date: Sat, 23 Sep 2023 17:58:55 +0200 Subject: [PATCH] feat: Add handling of banned and kicked reverifications Signed-off-by: Michal Drla --- src/app.ts | 2 + src/commands/verify.ts | 18 +++- src/listeners/actionListener.ts | 44 +++++++++ tests/verify.test.ts | 158 ++++++++++++++++++++++++++++++++ 4 files changed, 220 insertions(+), 2 deletions(-) create mode 100644 src/listeners/actionListener.ts diff --git a/src/app.ts b/src/app.ts index 986024c..128c5ef 100644 --- a/src/app.ts +++ b/src/app.ts @@ -23,6 +23,8 @@ export default () => { GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.GuildMessageReactions, + GatewayIntentBits.GuildMembers, + GatewayIntentBits.GuildModeration, ], }); client.login(token); diff --git a/src/commands/verify.ts b/src/commands/verify.ts index 6392548..0dea187 100644 --- a/src/commands/verify.ts +++ b/src/commands/verify.ts @@ -60,7 +60,7 @@ export async function execute(interaction: ChatInputCommandInteraction) { content: 'Verification failed! Contact admin.', }); } - if (user.length != 0) { + if (user.length != 0 && user[0].status !== 'removed') { return interaction.editReply({ content: 'User already verified! Contact admin if you need to verify again.', @@ -78,7 +78,7 @@ export async function execute(interaction: ChatInputCommandInteraction) { content: 'Verification failed! Contact admin.', }); } - if (user.length != 0) { + if (user.length != 0 && user[0].status !== 'removed') { return interaction.editReply({ content: 'This thesis is already used! Please contact admin.', }); @@ -100,6 +100,20 @@ export async function execute(interaction: ChatInputCommandInteraction) { }); } + if (user[0]?.status === 'removed') { + try { + await prisma.users.delete({ + where: { + id: user[0].id, + }, + }); + } catch (err) { + console.log(`Database error: ${err}`); + return interaction.editReply({ + content: 'Verification failed! Contact admin.', + }); + } + } const roleProgramm = await assignRole( interaction, scrapedConfirmationStudy, diff --git a/src/listeners/actionListener.ts b/src/listeners/actionListener.ts new file mode 100644 index 0000000..9c88503 --- /dev/null +++ b/src/listeners/actionListener.ts @@ -0,0 +1,44 @@ +/** + * Listenes for kick or ban actions and adds either a kick or ban value to user status if user is verified + */ + +import { Client, GuildBan } from 'discord.js'; +import { prisma } from '../model'; + +export default (client: Client) => { + client.on('guildBanAdd', async (guildBan: GuildBan) => { + const user = await prisma.users.findFirst({ + where: { + discordId: guildBan.user.id, + }, + }); + if (user) { + await prisma.users.update({ + where: { + id: user.id, + }, + data: { + status: 'banned', + }, + }); + } + }); + + client.on('guildMemberRemove', async (member) => { + const user = await prisma.users.findFirst({ + where: { + discordId: member.id, + }, + }); + if (user) { + await prisma.users.update({ + where: { + id: user.id, + }, + data: { + status: 'removed', + }, + }); + } + }); +}; diff --git a/tests/verify.test.ts b/tests/verify.test.ts index 2d1a187..ca941c8 100644 --- a/tests/verify.test.ts +++ b/tests/verify.test.ts @@ -24,6 +24,22 @@ const databaseUser = { joinDate: new Date(), }; +const databaseRemovedUser = { + id: '123', + discordId: '123', + idThesis: '2223121', + status: 'removed', + joinDate: new Date(), +}; + +const databaseBannedUser = { + id: '123', + discordId: '123', + idThesis: '2223121', + status: 'banned', + joinDate: new Date(), +}; + describe('Tests for verify command', () => { const interaction = mockDeep(); beforeEach(() => { @@ -207,6 +223,148 @@ describe('Tests for verify command', () => { }); }); + it('Verified user was removed verification should succeed', async () => { + prismaMock.users.findMany.mockResolvedValue([databaseRemovedUser]); + interaction.user.id = '123'; + interaction.options.getString + .calledWith('linktoconfirmationmuni') + .mockReturnValue( + 'https://is.muni.cz/confirmation-of-studies/cccxxd3?lang=en' + ); + interaction.options.getString + .calledWith('bachelorthesislink') + .mockReturnValue('https://dspace.vutbr.cz/handle/11012/2223121'); + jest.spyOn(utils, 'scrapeThesis').mockReturnValue( + Promise.resolve(nameUser) + ); + jest.spyOn(utils, 'scrapeConfirmationStudies').mockReturnValue( + Promise.resolve(dict) + ); + if (interaction.guild) { + interaction.guild.roles.cache.find.mockReturnValue( + 'test' as unknown as Role + ); + } + await verify.execute(interaction); + expect(interaction.editReply).toHaveBeenCalledWith({ + content: 'You have been successfully verified with role undefined.', + }); + }); + + it('Verified user was removed new user uses same thesis verification should succeed', async () => { + prismaMock.users.findMany.mockResolvedValue([databaseRemovedUser]); + interaction.user.id = '1234'; + interaction.options.getString + .calledWith('linktoconfirmationmuni') + .mockReturnValue( + 'https://is.muni.cz/confirmation-of-studies/cccxxd3?lang=en' + ); + interaction.options.getString + .calledWith('bachelorthesislink') + .mockReturnValue('https://dspace.vutbr.cz/handle/11012/2223121'); + jest.spyOn(utils, 'scrapeThesis').mockReturnValue( + Promise.resolve(nameUser) + ); + jest.spyOn(utils, 'scrapeConfirmationStudies').mockReturnValue( + Promise.resolve(dict) + ); + if (interaction.guild) { + interaction.guild.roles.cache.find.mockReturnValue( + 'test' as unknown as Role + ); + } + await verify.execute(interaction); + expect(interaction.editReply).toHaveBeenCalledWith({ + content: 'You have been successfully verified with role undefined.', + }); + }); + + it('Verified user was banned verification should fail', async () => { + prismaMock.users.findMany.mockResolvedValue([databaseBannedUser]); + interaction.user.id = '123'; + interaction.options.getString + .calledWith('linktoconfirmationmuni') + .mockReturnValue( + 'https://is.muni.cz/confirmation-of-studies/cccxxd3?lang=en' + ); + interaction.options.getString + .calledWith('bachelorthesislink') + .mockReturnValue('https://dspace.vutbr.cz/handle/11012/2223121'); + jest.spyOn(utils, 'scrapeThesis').mockReturnValue( + Promise.resolve(nameUser) + ); + jest.spyOn(utils, 'scrapeConfirmationStudies').mockReturnValue( + Promise.resolve(dict) + ); + if (interaction.guild) { + interaction.guild.roles.cache.find.mockReturnValue( + 'test' as unknown as Role + ); + } + await verify.execute(interaction); + expect(interaction.editReply).toHaveBeenCalledWith({ + content: + 'User already verified! Contact admin if you need to verify again.', + }); + }); + it('Verified user was banned verification should fail', async () => { + prismaMock.users.findMany.mockResolvedValue([databaseBannedUser]); + interaction.user.id = '123'; + interaction.options.getString + .calledWith('linktoconfirmationmuni') + .mockReturnValue( + 'https://is.muni.cz/confirmation-of-studies/cccxxd3?lang=en' + ); + interaction.options.getString + .calledWith('bachelorthesislink') + .mockReturnValue('https://dspace.vutbr.cz/handle/11012/2223121'); + jest.spyOn(utils, 'scrapeThesis').mockReturnValue( + Promise.resolve(nameUser) + ); + jest.spyOn(utils, 'scrapeConfirmationStudies').mockReturnValue( + Promise.resolve(dict) + ); + if (interaction.guild) { + interaction.guild.roles.cache.find.mockReturnValue( + 'test' as unknown as Role + ); + } + await verify.execute(interaction); + expect(interaction.editReply).toHaveBeenCalledWith({ + content: + 'User already verified! Contact admin if you need to verify again.', + }); + }); + + it('Verified user was banned verification should fail', async () => { + prismaMock.users.findMany.mockResolvedValue([databaseRemovedUser]); + interaction.user.id = '1234'; + interaction.options.getString + .calledWith('linktoconfirmationmuni') + .mockReturnValue( + 'https://is.muni.cz/confirmation-of-studies/cccxxd3?lang=en' + ); + interaction.options.getString + .calledWith('bachelorthesislink') + .mockReturnValue('https://dspace.vutbr.cz/handle/11012/2223121'); + jest.spyOn(utils, 'scrapeThesis').mockReturnValue( + Promise.resolve(nameUser) + ); + jest.spyOn(utils, 'scrapeConfirmationStudies').mockReturnValue( + Promise.resolve(dict) + ); + if (interaction.guild) { + interaction.guild.roles.cache.find.mockReturnValue( + 'test' as unknown as Role + ); + } + await verify.execute(interaction); + expect(interaction.editReply).toHaveBeenCalledWith({ + content: + 'User already verified! Contact admin if you need to verify again.', + }); + }); + it('User is using thesis which is assigned to different user', async () => { interaction.user.id = '123'; prismaMock.users.findMany