diff --git a/package-lock.json b/package-lock.json index b3cbcb27..bf8009e4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "ISC", "dependencies": { "@sentry/node": "^7.51.2", - "@togethercrew.dev/db": "^3.0.18", + "@togethercrew.dev/db": "^3.0.28", "@togethercrew.dev/tc-messagebroker": "^0.0.40", "babel-jest": "^29.5.0", "bullmq": "^3.14.0", @@ -3038,9 +3038,9 @@ } }, "node_modules/@togethercrew.dev/db": { - "version": "3.0.18", - "resolved": "https://registry.npmjs.org/@togethercrew.dev/db/-/db-3.0.18.tgz", - "integrity": "sha512-LIGkRnChhja1hnHnVk9qfaZXfCoruUsYVtMvt2v4IOzFLvUt6DeVqvrvSheK5yf63ikkwdiQMLyx62WNLbtUmw==", + "version": "3.0.28", + "resolved": "https://registry.npmjs.org/@togethercrew.dev/db/-/db-3.0.28.tgz", + "integrity": "sha512-/juK+lS2VjtpH0YTP5ItWlt4ZHg0xXimIkMc9k0IgVJyBUzmHdflYGe+iModVHIXHwJMNgSdDyqVw7oDp5Pbrg==", "dependencies": { "discord.js": "^14.7.1", "joi": "^17.7.0", @@ -9203,9 +9203,9 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/msgpackr": { - "version": "1.9.9", - "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.9.9.tgz", - "integrity": "sha512-sbn6mioS2w0lq1O6PpGtsv6Gy8roWM+o3o4Sqjd6DudrL/nOugY+KyJUimoWzHnf9OkO0T6broHFnYE/R05t9A==", + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.10.1.tgz", + "integrity": "sha512-r5VRLv9qouXuLiIBrLpl2d5ZvPt8svdQTl5/vMvE4nzDMyEX4sgW5yWhuBBj5UmgwOTWj8CIdSXn5sAfsHAWIQ==", "optionalDependencies": { "msgpackr-extract": "^3.0.2" } diff --git a/package.json b/package.json index c58495ab..d6f8cacf 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,9 @@ "lint": "eslint **/*.ts", "lint-fix": "eslint --fix **/*.ts", "format": "prettier --write src/**/*.ts", + "dev-migrate:create": "migrate create --template-file ./src/migrations/utils/template.ts --migrations-dir=\"./src/migrations/db\" --compiler=\"ts:./src/migrations/utils/ts-compiler.js\"", + "dev-migrate:up": "migrate --migrations-dir=\"./src/migrations/db\" up --compiler=\"ts:./src/migrations/utils/ts-compiler.js\"", + "dev-migrate:down": "migrate --migrations-dir=\"./src/migrations/db\" --compiler=\"ts:./src/migrations/utils/ts-compiler.js\" down", "migrate:create": "migrate create --template-file ./src/migrations/utils/template.ts --migrations-dir=\"./src/migrations/db\"", "migrate:up": "migrate --migrations-dir=\"./lib/migrations/db\" up", "migrate:down": "migrate --migrations-dir=\"./lib/migrations/db\" down" @@ -29,7 +32,7 @@ "homepage": "https://github.com/Behzad-rabiei/tc-discordBot#readme", "dependencies": { "@sentry/node": "^7.51.2", - "@togethercrew.dev/db": "^3.0.18", + "@togethercrew.dev/db": "^3.0.28", "@togethercrew.dev/tc-messagebroker": "^0.0.40", "babel-jest": "^29.5.0", "bullmq": "^3.14.0", diff --git a/src/events/channel/channelCreate.ts b/src/events/channel/channelCreate.ts index 8282b097..db27d57c 100644 --- a/src/events/channel/channelCreate.ts +++ b/src/events/channel/channelCreate.ts @@ -12,7 +12,7 @@ export default { if (channel instanceof TextChannel || channel instanceof VoiceChannel || channel instanceof CategoryChannel) { const logFields = { guild_id: channel.guild.id, channel_id: channel.id }; logger.info(logFields, 'event is running'); - const connection = DatabaseManager.getInstance().getTenantDb(channel.guild.id); + const connection = await DatabaseManager.getInstance().getTenantDb(channel.guild.id); try { await channelService.handelChannelChanges(connection, channel); logger.info(logFields, 'event is done'); diff --git a/src/events/channel/channelDelete.ts b/src/events/channel/channelDelete.ts index 31b5eb55..06896d46 100644 --- a/src/events/channel/channelDelete.ts +++ b/src/events/channel/channelDelete.ts @@ -12,7 +12,7 @@ export default { if (channel instanceof TextChannel || channel instanceof VoiceChannel || channel instanceof CategoryChannel) { const logFields = { guild_id: channel.guild.id, channel_id: channel.id }; logger.info(logFields, 'event is running'); - const connection = DatabaseManager.getInstance().getTenantDb(channel.guild.id); + const connection = await DatabaseManager.getInstance().getTenantDb(channel.guild.id); try { const channelDoc = await channelService.getChannel(connection, { channelId: channel.id }); await channelDoc?.softDelete(); diff --git a/src/events/channel/channelUpdate.ts b/src/events/channel/channelUpdate.ts index 1848d501..3eeb302e 100644 --- a/src/events/channel/channelUpdate.ts +++ b/src/events/channel/channelUpdate.ts @@ -16,7 +16,7 @@ export default { ) { const logFields = { guild_id: newChannel.guild.id, channel_id: newChannel.id }; logger.info(logFields, 'event is running'); - const connection = DatabaseManager.getInstance().getTenantDb(newChannel.guild.id); + const connection = await DatabaseManager.getInstance().getTenantDb(newChannel.guild.id); try { await channelService.handelChannelChanges(connection, newChannel); logger.info(logFields, 'event is done'); diff --git a/src/events/client/ready.ts b/src/events/client/ready.ts index 84a4f6c6..f6e9e49c 100644 --- a/src/events/client/ready.ts +++ b/src/events/client/ready.ts @@ -15,7 +15,7 @@ export default { logger.info('event is running'); const platforms = await platformService.getPlatforms({ disconnectedAt: null }); for (let i = 0; i < platforms.length; i++) { - const connection = DatabaseManager.getInstance().getTenantDb(platforms[i].metadata?.id); + const connection = await DatabaseManager.getInstance().getTenantDb(platforms[i].metadata?.id); try { logger.info({ platform_id: platforms[i].id }, 'Fetching guild members, roles,and channels'); await fetchMembers(connection, client, platforms[i]); diff --git a/src/events/member/guildMemberAdd.ts b/src/events/member/guildMemberAdd.ts index 1afc1d3f..0f009ae2 100644 --- a/src/events/member/guildMemberAdd.ts +++ b/src/events/member/guildMemberAdd.ts @@ -11,7 +11,7 @@ export default { async execute(member: GuildMember) { const logFields = { guild_id: member.guild.id, guild_member_id: member.user.id }; logger.info(logFields, 'event is running'); - const connection = DatabaseManager.getInstance().getTenantDb(member.guild.id); + const connection = await DatabaseManager.getInstance().getTenantDb(member.guild.id); try { await guildMemberService.handelGuildMemberChanges(connection, member); logger.info(logFields, 'event is done'); diff --git a/src/events/member/guildMemberRemove.ts b/src/events/member/guildMemberRemove.ts index 157e66e6..70360fca 100644 --- a/src/events/member/guildMemberRemove.ts +++ b/src/events/member/guildMemberRemove.ts @@ -11,7 +11,7 @@ export default { async execute(member: GuildMember) { const logFields = { guild_id: member.guild.id, guild_member_id: member.user.id }; logger.info(logFields, 'event is running'); - const connection = DatabaseManager.getInstance().getTenantDb(member.guild.id); + const connection = await DatabaseManager.getInstance().getTenantDb(member.guild.id); try { const guildMemberDoc = await guildMemberService.getGuildMember(connection, { discordId: member.user.id }); await guildMemberDoc?.softDelete(); diff --git a/src/events/member/guildMemberUpdate.ts b/src/events/member/guildMemberUpdate.ts index d79260db..3eef775d 100644 --- a/src/events/member/guildMemberUpdate.ts +++ b/src/events/member/guildMemberUpdate.ts @@ -11,7 +11,7 @@ export default { async execute(oldMember: GuildMember, newMember: GuildMember) { const logFields = { guild_id: newMember.guild.id, guild_member_id: newMember.user.id }; logger.info(logFields, 'event is running'); - const connection = DatabaseManager.getInstance().getTenantDb(newMember.guild.id); + const connection = await DatabaseManager.getInstance().getTenantDb(newMember.guild.id); try { await guildMemberService.handelGuildMemberChanges(connection, newMember); logger.info(logFields, 'event is done'); diff --git a/src/events/role/roleCreate.ts b/src/events/role/roleCreate.ts index 32677c2b..6e9f74a8 100644 --- a/src/events/role/roleCreate.ts +++ b/src/events/role/roleCreate.ts @@ -11,7 +11,7 @@ export default { async execute(role: Role) { const logFields = { guild_id: role.guild.id, role_id: role.id }; logger.info(logFields, 'event is running'); - const connection = DatabaseManager.getInstance().getTenantDb(role.guild.id); + const connection = await DatabaseManager.getInstance().getTenantDb(role.guild.id); try { await roleService.handelRoleChanges(connection, role); logger.info(logFields, 'event is done'); diff --git a/src/events/role/roleDelete.ts b/src/events/role/roleDelete.ts index bfc200d8..61678ff4 100644 --- a/src/events/role/roleDelete.ts +++ b/src/events/role/roleDelete.ts @@ -11,7 +11,7 @@ export default { async execute(role: Role) { const logFields = { guild_id: role.guild.id, role_id: role.id }; logger.info(logFields, 'event is running'); - const connection = DatabaseManager.getInstance().getTenantDb(role.guild.id); + const connection = await DatabaseManager.getInstance().getTenantDb(role.guild.id); try { const roleDoc = await roleService.getRole(connection, { roleId: role.id }); await roleDoc?.softDelete(); diff --git a/src/events/role/roleUpdate.ts b/src/events/role/roleUpdate.ts index 8b015e8f..0d26f1fd 100644 --- a/src/events/role/roleUpdate.ts +++ b/src/events/role/roleUpdate.ts @@ -11,7 +11,7 @@ export default { async execute(oldRole: Role, newRole: Role) { const logFields = { guild_id: newRole.guild.id, role_id: newRole.id }; logger.info(logFields, 'event is running'); - const connection = DatabaseManager.getInstance().getTenantDb(newRole.guild.id); + const connection = await DatabaseManager.getInstance().getTenantDb(newRole.guild.id); try { await roleService.handelRoleChanges(connection, newRole); logger.info(logFields, 'event is done'); diff --git a/src/events/user/userUpdate.ts b/src/events/user/userUpdate.ts index b92b003c..1dc6724b 100644 --- a/src/events/user/userUpdate.ts +++ b/src/events/user/userUpdate.ts @@ -13,7 +13,7 @@ export default { try { const platforms = await platformService.getPlatforms({ disconnectedAt: null }); for (let i = 0; i < platforms.length; i++) { - const connection = DatabaseManager.getInstance().getTenantDb(platforms[i].metadata?.id); + const connection = await DatabaseManager.getInstance().getTenantDb(platforms[i].metadata?.id); await guildMemberService.updateGuildMember( connection, { discordId: newUser.id }, diff --git a/src/functions/cronJon.ts b/src/functions/cronJon.ts index e9cda21f..3c4b8240 100644 --- a/src/functions/cronJon.ts +++ b/src/functions/cronJon.ts @@ -29,7 +29,7 @@ export default async function cronJob(client: Client) { logger.info('event is running'); const platforms = await platformService.getPlatforms({ disconnectedAt: null }); for (let i = 0; i < platforms.length; i++) { - const connection = DatabaseManager.getInstance().getTenantDb(platforms[i].metadata?.id); + const connection = await DatabaseManager.getInstance().getTenantDb(platforms[i].metadata?.id); try { logger.info({ platform_Id: platforms[i].metadata?.id }, 'is running cronJob for platform'); await guildExtraction(connection, client, platforms[i]); diff --git a/src/index.ts b/src/index.ts index cfe29625..140fcb90 100644 --- a/src/index.ts +++ b/src/index.ts @@ -55,7 +55,7 @@ const fetchMethod = async (msg: any) => { if (platform) { const isPlatformCreated = saga.data['created']; - const connection = DatabaseManager.getInstance().getTenantDb(platform.metadata?.id); + const connection = await DatabaseManager.getInstance().getTenantDb(platform.metadata?.id); if (isPlatformCreated) { await fetchChannels(connection, client, platform); await fetchMembers(connection, client, platform); @@ -99,7 +99,7 @@ const notifyUserAboutAnalysisFinish = async ( const fetchInitialData = async (platform: HydratedDocument) => { try { - const connection = DatabaseManager.getInstance().getTenantDb(platform.metadata?.id); + const connection = await DatabaseManager.getInstance().getTenantDb(platform.metadata?.id); await fetchChannels(connection, client, platform); await fetchRoles(connection, client, platform); await fetchMembers(connection, client, platform); diff --git a/src/migrations/db/1695210587863-add-isgeneratedbyweebhook-to-rawinfo-schema.ts b/src/migrations/db/1695210587863-add-isgeneratedbyweebhook-to-rawinfo-schema.ts deleted file mode 100644 index 4dc290b5..00000000 --- a/src/migrations/db/1695210587863-add-isgeneratedbyweebhook-to-rawinfo-schema.ts +++ /dev/null @@ -1,27 +0,0 @@ -import 'dotenv/config'; -import { Client, GatewayIntentBits, } from 'discord.js'; -import { platformService } from '../../database/services'; -import { connectDB } from '../../database'; -import config from '../../config'; -import webhookLogic from '../utils/webhookLogic'; -import { DatabaseManager } from '@togethercrew.dev/db'; - -const { Guilds, GuildMembers, GuildMessages, GuildPresences, DirectMessages } = GatewayIntentBits; - -export const up = async () => { - const client = new Client({ - intents: [Guilds, GuildMembers, GuildMessages, GuildPresences, DirectMessages], - }); - - await client.login(config.discord.botToken); - await connectDB(); - const platforms = await platformService.getPlatforms({}); - for (let i = 0; i < platforms.length; i++) { - const connection = DatabaseManager.getInstance().getTenantDb(platforms[i].metadata?.id); - await webhookLogic(connection, client, platforms[i].metadata?.id); - } -}; - -export const down = async () => { - // TODO: Implement rollback logic if needed -}; diff --git a/src/migrations/db/1706110397838-add-isbot-to-guildmember-schema.ts b/src/migrations/db/1706110397838-add-isbot-to-guildmember-schema.ts new file mode 100644 index 00000000..a9249770 --- /dev/null +++ b/src/migrations/db/1706110397838-add-isbot-to-guildmember-schema.ts @@ -0,0 +1,25 @@ +import 'dotenv/config'; +import { connectDB } from '../../database'; +import isBotLogic from '../utils/isBotLogic'; +import { DatabaseManager } from '@togethercrew.dev/db'; +import { Client, GatewayIntentBits } from 'discord.js'; +import config from '../../config'; +const { Guilds, GuildMembers, GuildMessages, GuildPresences, DirectMessages } = GatewayIntentBits; + + +export const up = async () => { + const client = new Client({ + intents: [Guilds, GuildMembers, GuildMessages, GuildPresences, DirectMessages], + }); + + await client.login(config.discord.botToken); + await connectDB(); + const connection1 = await DatabaseManager.getInstance().getTenantDb('1023936505321881641'); + const connection2 = await DatabaseManager.getInstance().getTenantDb('949124961187016764'); + await isBotLogic(connection1, client, '1023936505321881641'); + await isBotLogic(connection2, client, '949124961187016764'); +}; + +export const down = async () => { + // TODO: Implement rollback logic if needed +}; diff --git a/src/migrations/utils/isBotLogic.ts b/src/migrations/utils/isBotLogic.ts new file mode 100644 index 00000000..0f8e7715 --- /dev/null +++ b/src/migrations/utils/isBotLogic.ts @@ -0,0 +1,78 @@ +import { Client, Snowflake } from 'discord.js'; +import { GuildMember } from 'discord.js'; +import { Connection } from 'mongoose'; +import parentLogger from '../../config/logger'; +import { guildMemberService } from '../../database/services'; +import { IGuildMember, } from '@togethercrew.dev/db'; + +const logger = parentLogger.child({ module: 'Migration-isBot' }); + +/** + * Iterates over a list of guild members and pushes extracted data from each guild member to an array. + * @param {GuildMember[]} guildMembersArray - An array of guild members from which data is to be extracted. + * @returns {Promise} - A promise that resolves to the updated array containing the extracted data. + */ +function pushMembersToArray(arr: IGuildMember[], guildMembersArray: GuildMember[]): IGuildMember[] { + for (const guildMember of guildMembersArray) { + arr.push(guildMemberService.getNeededDateFromGuildMember(guildMember)); + } + return arr; +} + +/** + * + * @param {Connection} connection - Mongoose connection object for the database. + * @param {Snowflake} guildId - The identifier of the guild to extract information from. + */ +export default async function isBotLogic(connection: Connection, client: Client, guildId: Snowflake) { + logger.info({ guild_id: guildId }, 'add-isBot-to-guilbMember-schema migration is running'); + try { + const botGuildMembers = []; + const noneBotGuildMembers = []; + + const guild = await client.guilds.fetch(guildId); + const membersToStore: IGuildMember[] = []; + const fetchedMembers = await guild.members.fetch(); + const guildMembers = pushMembersToArray(membersToStore, [...fetchedMembers.values()]); + + console.log(guildMembers.length, guildId) + if (guildMembers) { + for (const guildMember of guildMembers) { + if (guildMember.isBot) { + botGuildMembers.push(guildMember.discordId); + } else { + noneBotGuildMembers.push(guildMember.discordId); + } + } + } + + if (botGuildMembers.length > 0) { + await guildMemberService.updateGuildMembers( + connection, + { discordId: { $in: botGuildMembers } }, + { isBot: true } + ); + } + + if (noneBotGuildMembers.length > 0) { + await guildMemberService.updateGuildMembers( + connection, + { discordId: { $in: noneBotGuildMembers } }, + { isBot: false } + ); + } + + const mergedArray = botGuildMembers.concat(noneBotGuildMembers); + if (mergedArray.length > 0) { + await guildMemberService.updateGuildMembers( + connection, + { discordId: { $nin: mergedArray } }, + { isBot: null } + ); + } + + } catch (err) { + logger.error({ guild_id: guildId, err }, 'add-isBot-to-guilbMember-schema migration is failed'); + } + logger.info({ guild_id: guildId }, 'add-isBot-to-guilbMember-schema migration is done'); +} \ No newline at end of file diff --git a/src/migrations/utils/template.ts b/src/migrations/utils/template.ts index 7f34638e..c75ecdee 100644 --- a/src/migrations/utils/template.ts +++ b/src/migrations/utils/template.ts @@ -3,10 +3,10 @@ import 'dotenv/config'; import { DatabaseManager } from '@togethercrew.dev/db'; export const up = async () => { - await connectDB(); - const connection = DatabaseManager.getInstance().getTenantDb("681946187490000803"); + await connectDB(); + const connection = await DatabaseManager.getInstance().getTenantDb("681946187490000803"); - await connection.createCollection('my_collection'); + await connection.createCollection('my_collection'); }; export const down = async () => {