From d1afefb0755630800c21f219350793c731e59fb9 Mon Sep 17 00:00:00 2001 From: Brian Date: Tue, 18 Jan 2022 11:35:22 -0500 Subject: [PATCH 1/4] enhance poap distribution --- CHANGELOG.md | 1 + src/app/events/VoiceStateUpdate.ts | 2 +- src/app/service/poap/DistributePOAP.ts | 19 ++- src/app/utils/Log.ts | 172 +++++++++++++++++-------- src/app/utils/POAPUtils.ts | 36 ++++-- src/app/utils/ServiceUtils.ts | 6 +- 6 files changed, 159 insertions(+), 77 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c12e82d7..1c47bb0d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ 5. Introduce basic `/claim` command and prompt user for opt-in on slash command 6. Increase poap max time to 12 hours 7. Add poap expiration cron job +8. Enhance poap distribution to work on public channels ## 2.6.2-RELEASE (2022-01-13) diff --git a/src/app/events/VoiceStateUpdate.ts b/src/app/events/VoiceStateUpdate.ts index ddc33ee8..c0494501 100644 --- a/src/app/events/VoiceStateUpdate.ts +++ b/src/app/events/VoiceStateUpdate.ts @@ -18,7 +18,7 @@ export default class implements DiscordEvent { */ async execute(oldState: VoiceState, newState: VoiceState): Promise { try { - await HandleParticipantDuringEvent(oldState, newState).catch(e => LogUtils.logError('failed to handle user in POAP event', e, oldState.guild.id)); + await HandleParticipantDuringEvent(oldState, newState).catch(e => LogUtils.logError('failed to handle user in POAP event', e)); } catch (e) { LogUtils.logError('failed to process event voiceStateUpdate', e); } diff --git a/src/app/service/poap/DistributePOAP.ts b/src/app/service/poap/DistributePOAP.ts index c7ad9010..8311ffee 100644 --- a/src/app/service/poap/DistributePOAP.ts +++ b/src/app/service/poap/DistributePOAP.ts @@ -31,10 +31,12 @@ export default async (ctx: CommandContext, guildMember: GuildMember, event: stri const isDmOn: boolean = await ServiceUtils.tryDMUser(guildMember, 'Hello! I can help you distribute POAPS.'); - if (!isDmOn) { - await ctx.sendFollowUp({ content: '⚠ Please make sure this is a private channel. I can help you distribute POAPs but anyone who has access to this channel can see private information! ⚠' }); - } else if (ctx) { + await ctx.defer(true); + + if (isDmOn) { await ctx.send({ content: 'Please check your DMs!', ephemeral: true }); + } else { + await ctx.send({ content: '⚠ Please make sure this is a private channel. I can help you distribute POAPs but anyone who has access to this channel can see private information! ⚠', ephemeral: true }); } let participantsList: POAPFileParticipant[] | TwitterPOAPFileParticipant[] = await askForParticipantsList(guildMember, platform, isDmOn, ctx); @@ -56,7 +58,7 @@ export default async (ctx: CommandContext, guildMember: GuildMember, event: stri if (isDmOn) { await guildMember.send({ content: msg }).catch(Log.error); } else { - await ctx.send({ content: msg }); + await ctx.send({ content: msg, ephemeral: true }); } throw Error('failed to parse'); } @@ -91,7 +93,7 @@ export const askForParticipantsList = async (guildMember: GuildMember, platform: if (isDmOn) { await guildMember.send({ content: csvPrompt }); } else { - await ctx.sendFollowUp({ content: csvPrompt }); + await ctx.send({ content: csvPrompt, ephemeral: true }); } Log.debug(`message: '${csvPrompt}' send to user`); @@ -104,8 +106,9 @@ export const askForParticipantsList = async (guildMember: GuildMember, platform: try { const message: Message | undefined = (await contextChannel.awaitMessages({ max: 1, - time: 180000, + time: 180_000, errors: ['time'], + filter: m => m.author.id == guildMember.id && m.attachments.size >= 1, })).first(); if (message == null) { throw new ValidationError('Invalid message'); @@ -120,6 +123,10 @@ export const askForParticipantsList = async (guildMember: GuildMember, platform: const fileResponse = await axios.get(participantAttachment.url); participantsList = ServiceUtils.parseCSVFile(fileResponse.data); + if (!isDmOn) { + await message.delete(); + } + if ((participantsList as POAPFileParticipant[])[0].discordUserId == null) { if ((participantsList as TwitterPOAPFileParticipant[])[0].twitterUserId == null) { throw new Error('missing ID'); diff --git a/src/app/utils/Log.ts b/src/app/utils/Log.ts index 93b69378..771728af 100644 --- a/src/app/utils/Log.ts +++ b/src/app/utils/Log.ts @@ -20,121 +20,176 @@ try { // eslint-disable-next-line no-console console.log('Please setup LogDNA token.'); // eslint-disable-next-line no-console - console.log(e); - throw new Error(); + console.error(e); } const Log = { info(statement: string | any, options?: Omit): void { - if (process.env.NODE_ENV != 'production' || !logger.info) { + try { + if (process.env.NODE_ENV != 'production' || !logger.info) { + // eslint-disable-next-line no-console + console.log(statement); + } else { + logger.info(statement, options); + } + } catch (e) { // eslint-disable-next-line no-console - console.log(statement); - } else { - logger.info(statement, options); + console.error(e); } }, warn(statement: string | any, options?: Omit): void { - if (process.env.NODE_ENV != 'production' || !logger.warn) { + try { + if (process.env.NODE_ENV != 'production' || !logger.warn) { + // eslint-disable-next-line no-console + console.log(statement); + } else { + logger.warn(statement, options); + } + } catch (e) { // eslint-disable-next-line no-console - console.log(statement); - } else { - logger.warn(statement, options); + console.error(e); } }, debug(statement: string | any, options?: Omit): void { - if (process.env.NODE_ENV != 'production' || !logger.debug) { + try { + if (process.env.NODE_ENV != 'production' || !logger.debug) { + // eslint-disable-next-line no-console + console.debug(statement); + } else { + logger.debug(statement, options); + } + } catch (e) { // eslint-disable-next-line no-console - console.debug(statement); - } else { - logger.debug(statement, options); + console.error(e); } }, error(statement: string | any, options?: Omit): void { - if (process.env.NODE_ENV != 'production' || !logger.error) { + try { + if (process.env.NODE_ENV != 'production' || !logger.error) { + // eslint-disable-next-line no-console + console.error(statement); + } else { + logger.error(statement, options); + } + } catch (e) { // eslint-disable-next-line no-console - console.error(statement); - } else { - logger.error(statement, options); + console.error(e); } }, fatal(statement: string | any, options?: Omit): void { - if (process.env.NODE_ENV != 'production' || !logger.fatal) { + try { + if (process.env.NODE_ENV != 'production' || !logger.fatal) { + // eslint-disable-next-line no-console + console.error(statement); + } else { + logger.fatal(statement, options); + } + } catch (e) { // eslint-disable-next-line no-console - console.error(statement); - } else { - logger.fatal(statement, options); + console.error(e); } }, trace(statement: string | any, options?: Omit): void { - if (process.env.NODE_ENV != 'production' || !logger.trace) { + try { + if (process.env.NODE_ENV != 'production' || !logger.trace) { + // eslint-disable-next-line no-console + console.log(statement); + } else { + logger.trace(statement, options); + } + } catch (e) { // eslint-disable-next-line no-console - console.log(statement); - } else { - logger.trace(statement, options); + console.error(e); } }, log(statement: string | any, options?: Omit): void { - if (process.env.NODE_ENV != 'production') { + try { + if (process.env.NODE_ENV != 'production') { + // eslint-disable-next-line no-console + console.log(statement); + } + logger.log(statement, options); + } catch (e) { // eslint-disable-next-line no-console - console.log(statement); + console.error(e); } - logger.log(statement, options); }, // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types addMetaProperty(key: string, value: any): void { - logger.addMetaProperty(key, value); + try { + logger.addMetaProperty(key, value); + } catch (e) { + // eslint-disable-next-line no-console + console.error(e); + } }, removeMetaProperty(key: string): void { - logger.removeMetaProperty(key); + try { + logger.removeMetaProperty(key); + } catch (e) { + // eslint-disable-next-line no-console + console.error(e); + } }, flush(): void { - logger.flush(); + try { + logger.flush(); + } catch(e) { + // eslint-disable-next-line no-console + console.error(e); + } }, }; export const LogUtils = { logCommandStart(ctx: CommandContext): void { - Log.info(`/${ctx.commandName} ran ${ctx.user.username}#${ctx.user.discriminator}`, { - indexMeta: true, - meta: { - guildId: ctx.guildID, - userTag: `${ctx.user.username}#${ctx.user.discriminator}`, - userId: ctx.user.id, - params: ctx.options, - }, - }); + try { + Log.info(`/${ctx.commandName} ran ${ctx.user.username}#${ctx.user.discriminator}`, { + indexMeta: true, + meta: { + guildId: ctx.guildID, + userTag: `${ctx.user.username}#${ctx.user.discriminator}`, + userId: ctx.user.id, + params: ctx.options, + }, + }); + } catch (e) { + // eslint-disable-next-line no-console + console.error(e); + } }, logCommandEnd(ctx: CommandContext): void { - Log.info(`/${ctx.commandName} ended ${ctx.user.username}#${ctx.user.discriminator}`, { - indexMeta: true, - meta: { - guildId: ctx.guildID, - userTag: `${ctx.user.username}#${ctx.user.discriminator}`, - userId: ctx.user.id, - params: ctx.options, - }, - }); + try { + Log.info(`/${ctx.commandName} ended ${ctx.user.username}#${ctx.user.discriminator}`, { + indexMeta: true, + meta: { + guildId: ctx.guildID, + userTag: `${ctx.user.username}#${ctx.user.discriminator}`, + userId: ctx.user.id, + params: ctx.options, + }, + }); + } catch (e) { + // eslint-disable-next-line no-console + console.error(e); + } }, logError(message: string, error: Error | any, guildId?: string): void { try { if (error != null && error instanceof Error) { - Sentry.captureException(error, { - tags: { - guildId: guildId, - }, - }); + Sentry.captureException(error); Log.error(message, { indexMeta: true, meta: { @@ -144,11 +199,16 @@ export const LogUtils = { guildId: guildId, }, }); + if (process.env.SENTRY_ENVIRONMENT == 'local') { + // eslint-disable-next-line no-console + console.error(error); + } } else { Log.error(message); } } catch (e) { - Log.warn(message); + // eslint-disable-next-line no-console + console.error(e); } }, }; diff --git a/src/app/utils/POAPUtils.ts b/src/app/utils/POAPUtils.ts index 2b305585..2790a83c 100644 --- a/src/app/utils/POAPUtils.ts +++ b/src/app/utils/POAPUtils.ts @@ -101,29 +101,29 @@ const POAPUtils = { adminChannel?: TextChannel | null, ): Promise { Log.debug('asking poap organizer for poap links attachment'); - const uploadLinksMsg = `Please upload the POAP links.txt file. This file should have a least ${numberOfParticipants} link(s). Each link should be on a new line. This file can be obtained from \`/poap mint\` command`; + const uploadLinksMsg = `Please upload the \`links.txt\` file. This file should have a least ${numberOfParticipants} link(s). Each link should be on a new line. This file can be obtained from \`/poap mint\` command.`; const replyOptions: AwaitMessagesOptions = { max: 1, - time: 900000, + time: 900_000, errors: ['time'], - filter: m => m.author.id == guildMember.user.id, + filter: m => m.author.id == guildMember.user.id && m.attachments.size >= 1, }; let message: Message | undefined; if (isDmOn) { - await guildMember.send({ content: uploadLinksMsg }); - const dmChannel: DMChannel = await guildMember.createDM(); + const promptMsg: Message = await guildMember.send({ content: uploadLinksMsg }); + const dmChannel: DMChannel = await promptMsg.channel.fetch() as DMChannel; message = (await dmChannel.awaitMessages(replyOptions).catch(() => { throw new ValidationError('Invalid attachment. Session ended, please try the command again.'); })).first(); } else if (ctx) { - await ctx.sendFollowUp(uploadLinksMsg); + await ctx.send({ content: uploadLinksMsg, ephemeral: true }); const guildChannel: TextChannel = await guildMember.guild.channels.fetch(ctx.channelID) as TextChannel; message = (await guildChannel.awaitMessages(replyOptions).catch(() => { throw new ValidationError('Invalid attachment. Session ended, please try the command again.'); })).first(); } else if (adminChannel != null) { - await adminChannel.send(uploadLinksMsg); + await adminChannel.send({ content: uploadLinksMsg }); message = (await adminChannel.awaitMessages(replyOptions).catch(() => { throw new ValidationError('Invalid attachment. Session ended, please try the command again.'); })).first(); @@ -139,6 +139,10 @@ const POAPUtils = { throw new ValidationError('Invalid attachment. Session ended, please try the command again.'); } + if (!isDmOn) { + await message.delete(); + } + Log.debug(`obtained poap links attachment in discord: ${poapLinksFile.url}`); return poapLinksFile; }, @@ -195,6 +199,9 @@ const POAPUtils = { const poapHostRegex = /^http[s]?:\/\/poap\.xyz\/.*$/gis; + const db: Db = await MongoDbUtils.connect(constants.DB_NAME_DEGEN); + const dbUsersCollection: MongoCollection = await db.collection(constants.DB_COLLECTION_DISCORD_USERS); + while (i < length) { const participant: POAPFileParticipant | undefined = listOfParticipants.pop(); if (participant == null) { @@ -203,6 +210,8 @@ const POAPUtils = { continue; } + Log.debug(participant); + let poapLink: string | undefined = ''; if (listOfPOAPLinks) { poapLink = listOfPOAPLinks.pop(); @@ -223,6 +232,7 @@ const POAPUtils = { if (participant.discordUserId.length < 17) { throw new ValidationError('There appears to be a parsing error. Please check that the discordUserID is greater than 16 digits.'); } + try { if (!poapLink.match(poapHostRegex)) { Log.warn('invalid POAP link provided', { @@ -239,11 +249,12 @@ const POAPUtils = { discordUserTag: participant.discordUserTag, poapLink: 'Invalid POAP link', }); + i++; continue; } const participantMember: GuildMember = await guildMember.guild.members.fetch(participant.discordUserId); - if (!(await ServiceUtils.isDMEnabledForUser(participantMember))) { + if (!(await ServiceUtils.isDMEnabledForUser(participantMember, dbUsersCollection))) { Log.debug('user has not opted in to DMs'); results.hasDMOff++; failedPOAPsList.push({ @@ -251,6 +262,7 @@ const POAPUtils = { discordUserTag: participant.discordUserTag, poapLink: poapLink, }); + i++; continue; } @@ -295,7 +307,10 @@ const POAPUtils = { }).then((_) => { message.edit({ content: 'Report received, thank you!', components: [] }); POAPUtils.reportPOAPOrganizer(guildMember).catch(Log.error); + }).catch(e => { + LogUtils.logError('failed to handle user poap link response', e); }); + results.successfullySent++; } catch (e) { LogUtils.logError('user might have been banned or has DMs off', e); @@ -518,6 +533,7 @@ const POAPUtils = { await guildMember.send(distributionEmbedMsg).catch(Log.error); } else if (ctx) { distributionEmbedMsg = distributionEmbedMsg as MessageOptionsSlash; + distributionEmbedMsg.ephemeral = true; distributionEmbedMsg.file = [{ name: 'failed_to_send_poaps.csv', file: failedPOAPsBuffer }]; await ctx.sendFollowUp(distributionEmbedMsg); } else if (channelExecution) { @@ -539,14 +555,14 @@ const POAPUtils = { if (isDmOn) { await guildMember.send({ content: deliveryMsg }).catch(Log.error); } else if (ctx) { - await ctx.sendFollowUp(deliveryMsg); + await ctx.send({ content: deliveryMsg, ephemeral: true }); } } else { const failedDeliveryMsg = `Looks like some degens have DMs off or they haven't oped in for delivery. They can claim their POAPs by sending \`gm\` to <@${ApiKeys.DISCORD_BOT_ID}> or executing slash command \`/poap claim\``; if (isDmOn) { await guildMember.send({ content: failedDeliveryMsg }); } else if (ctx) { - await ctx.sendFollowUp({ content: failedDeliveryMsg, ephemeral: true }); + await ctx.send({ content: failedDeliveryMsg, ephemeral: true }); } } }, diff --git a/src/app/utils/ServiceUtils.ts b/src/app/utils/ServiceUtils.ts index 32ee4e37..51f0928f 100644 --- a/src/app/utils/ServiceUtils.ts +++ b/src/app/utils/ServiceUtils.ts @@ -247,11 +247,9 @@ const ServiceUtils = { } as MessageOptionsSlash; }, - isDMEnabledForUser: async (member: GuildMember): Promise => { - const db: Db = await MongoDbUtils.connect(constants.DB_NAME_DEGEN); - const dbUsers: MongoCollection = await db.collection(constants.DB_COLLECTION_DISCORD_USERS); + isDMEnabledForUser: async (member: GuildMember, dbUsersCollection: MongoCollection): Promise => { await member.fetch(); - const result: DiscordUserCollection | null = await dbUsers.findOne({ + const result: DiscordUserCollection | null = await dbUsersCollection.findOne({ userId: member.id.toString(), }); From 644374aef9c38c44c8a25ad19ca24805d72f079c Mon Sep 17 00:00:00 2001 From: Brian Date: Tue, 18 Jan 2022 12:03:22 -0500 Subject: [PATCH 2/4] handle gm opt-in from in-channel --- CHANGELOG.md | 7 ++++++- src/app/service/account/UnlinkAccount.ts | 3 +-- src/app/service/account/VerifyTwitter.ts | 6 +++--- src/app/service/poap/ClaimPOAP.ts | 13 ++++++++----- src/app/service/poap/SchedulePOAP.ts | 4 ++-- src/app/utils/ServiceUtils.ts | 2 +- 6 files changed, 21 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c47bb0d..839d0aac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,12 @@ 5. Introduce basic `/claim` command and prompt user for opt-in on slash command 6. Increase poap max time to 12 hours 7. Add poap expiration cron job -8. Enhance poap distribution to work on public channels +8. Enhance poap distribution to with ephemeral + - fix timeout reply after poap distribution + - enhance poap distribution loop + - enhance poap end +9. Parse blank strings for msg embed display +10. Prompt users to DM delivery is /claim is executed from channel ## 2.6.2-RELEASE (2022-01-13) diff --git a/src/app/service/account/UnlinkAccount.ts b/src/app/service/account/UnlinkAccount.ts index 701bcbdd..2e0dbbe7 100644 --- a/src/app/service/account/UnlinkAccount.ts +++ b/src/app/service/account/UnlinkAccount.ts @@ -79,7 +79,7 @@ const promptToUnlink = async (ctx: CommandContext, guildMember: GuildMember, isD fields: [ { name: 'UserId', value: `${twitterUser.twitterUser.id_str}`, inline: false }, { name: 'Name', value: `${twitterUser.twitterUser.screen_name}`, inline: false }, - { name: 'Description', value: `${twitterUser.twitterUser.description}`, inline: false }, + { name: 'Description', value: `${ServiceUtils.prepEmbedField(twitterUser.twitterUser.description)}`, inline: false }, { name: 'Profile', value: `https://twitter.com/${twitterUser.twitterUser.screen_name}`, inline: false }, ], }, @@ -145,7 +145,6 @@ const promptToUnlink = async (ctx: CommandContext, guildMember: GuildMember, isD ]; Log.debug('attempting to send msg to user'); Log.debug(shouldUnlinkMsg); - await ctx.defer(true); const msgSlashResponse: MessageSlash = await ctx.send(shouldUnlinkMsg) as MessageSlash; Log.debug('ctx message on user confirmation sent'); shouldUnlinkPromise = new Promise((resolve, _) => { diff --git a/src/app/service/account/VerifyTwitter.ts b/src/app/service/account/VerifyTwitter.ts index 985d520f..d01d025b 100644 --- a/src/app/service/account/VerifyTwitter.ts +++ b/src/app/service/account/VerifyTwitter.ts @@ -64,7 +64,7 @@ const VerifyTwitter = async (ctx: CommandContext, guildMember: GuildMember, send }; export const retrieveVerifiedTwitter = async (guildMember: GuildMember): Promise => { - Log.debug('starting to link twitter account link'); + Log.debug('starting to retrieve twitter account'); const db: Db = await MongoDbUtils.connect(constants.DB_NAME_NEXTAUTH); const accountsCollection: Collection = db.collection(constants.DB_COLLECTION_NEXT_AUTH_ACCOUNTS); @@ -87,7 +87,7 @@ export const retrieveVerifiedTwitter = async (guildMember: GuildMember): Promise }); if (twitterCollection == null || twitterCollection.accessToken == null) { - Log.debug('twitter account not linked'); + Log.debug('twitter account not found'); return null; } @@ -120,7 +120,7 @@ export const retrieveVerifiedTwitter = async (guildMember: GuildMember): Promise return null; } - Log.debug('done linking twitter account'); + Log.debug('found twitter account'); return { twitterUser: userCall, twitterClientV1: userClient, diff --git a/src/app/service/poap/ClaimPOAP.ts b/src/app/service/poap/ClaimPOAP.ts index dd85b782..a670af47 100644 --- a/src/app/service/poap/ClaimPOAP.ts +++ b/src/app/service/poap/ClaimPOAP.ts @@ -41,11 +41,14 @@ const ClaimPOAP = async (ctx: CommandContext, platform: string, guildMember?: Gu await claimForDiscord(ctx.user.id, ctx); if (guildMember && ctx) { try { - const dmChannel: DMChannel = await guildMember.createDM(); - await OptInPOAP(guildMember.user, await dmChannel).catch(e => { - Log.error(e); - ServiceUtils.sendOutErrorMessageForDM(dmChannel).catch(Log.error); - }); + const isDmOn: boolean = await ServiceUtils.tryDMUser(guildMember, 'gm'); + if (isDmOn) { + const dmChannel: DMChannel = await guildMember.createDM(); + await OptInPOAP(guildMember.user, dmChannel).catch(e => { + Log.error(e); + ServiceUtils.sendOutErrorMessageForDM(dmChannel).catch(Log.error); + }); + } } catch (e) { LogUtils.logError('failed to ask for opt-in', e); } diff --git a/src/app/service/poap/SchedulePOAP.ts b/src/app/service/poap/SchedulePOAP.ts index 498aff08..15daa4ce 100644 --- a/src/app/service/poap/SchedulePOAP.ts +++ b/src/app/service/poap/SchedulePOAP.ts @@ -223,8 +223,8 @@ const SchedulePOAP = async (ctx: CommandContext, guildMember: GuildMember, numbe { name: 'Event Title', value: request.name }, { name: 'Event Description', value: request.description }, { name: 'Virtual Event', value: (request.virtual_event ? 'yes' : 'no'), inline: true }, - { name: 'City', value: `${request.city} `, inline: true }, - { name: 'Country', value: `${request.country} `, inline: true }, + { name: 'City', value: `${ServiceUtils.prepEmbedField(request.city)}`, inline: true }, + { name: 'Country', value: `${ServiceUtils.prepEmbedField(request.country)}`, inline: true }, { name: 'Event Start', value: request.start_date, inline: true }, { name: 'Event End', value: request.end_date, inline: true }, { name: 'Event URL', value: `${request.event_url} `, inline: true }, diff --git a/src/app/utils/ServiceUtils.ts b/src/app/utils/ServiceUtils.ts index 51f0928f..2a3eb9ae 100644 --- a/src/app/utils/ServiceUtils.ts +++ b/src/app/utils/ServiceUtils.ts @@ -136,7 +136,7 @@ const ServiceUtils = { } }, - prepEmbedField: (field: string | null): string => { + prepEmbedField: (field: string | null | undefined): string => { return (field) ? field : '-'; }, From aec8a0b3da1f97dca30765a6e0c1483fdf5bc4f2 Mon Sep 17 00:00:00 2001 From: Brian Date: Tue, 18 Jan 2022 12:36:58 -0500 Subject: [PATCH 3/4] enhance messaging --- CHANGELOG.md | 1 + src/app/service/poap/DistributePOAP.ts | 4 ++-- src/app/service/poap/start/StartChannelFlow.ts | 8 ++++---- src/app/service/poap/start/StartPOAP.ts | 2 ++ src/app/service/poap/start/StartTwitterFlow.ts | 8 ++------ src/app/utils/POAPUtils.ts | 2 +- 6 files changed, 12 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 839d0aac..d4496471 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ - enhance poap end 9. Parse blank strings for msg embed display 10. Prompt users to DM delivery is /claim is executed from channel +11. Message enhancements to twitter flow ## 2.6.2-RELEASE (2022-01-13) diff --git a/src/app/service/poap/DistributePOAP.ts b/src/app/service/poap/DistributePOAP.ts index 8311ffee..803f2a11 100644 --- a/src/app/service/poap/DistributePOAP.ts +++ b/src/app/service/poap/DistributePOAP.ts @@ -85,9 +85,9 @@ export const askForParticipantsList = async (guildMember: GuildMember, platform: Log.debug('preparing to ask for participants list csv file'); let csvPrompt = ''; if (platform == constants.PLATFORM_TYPE_DISCORD) { - csvPrompt = 'Please upload participants.csv file with header containing discordUserId. POAPs will be distributed to these degens.'; + csvPrompt = 'Please upload distribution file with header containing discordUserId. POAPs will be distributed to these degens.'; } else if (platform == constants.PLATFORM_TYPE_TWITTER) { - csvPrompt = 'Please upload participants.csv file with header containing twitterUserId. POAPs will be distributed to these degens.'; + csvPrompt = 'Please upload distribution file with header containing twitterUserId. POAPs will be distributed to these degens.'; } if (isDmOn) { diff --git a/src/app/service/poap/start/StartChannelFlow.ts b/src/app/service/poap/start/StartChannelFlow.ts index 72893ca5..da68b5f1 100644 --- a/src/app/service/poap/start/StartChannelFlow.ts +++ b/src/app/service/poap/start/StartChannelFlow.ts @@ -27,7 +27,6 @@ const StartChannelFlow = async ( Log.debug('starting channel flow for poap start'); const voiceChannels: Collection = ServiceUtils.getAllVoiceChannels(guildMember); - await ctx.sendFollowUp({ content: '⚠ **Please make sure this is a private channel.** I can help you setup the poap event! ⚠' }); const embedsVoiceChannels = generateVoiceChannelEmbedMessage(voiceChannels) as MessageEmbedOptionsSlash[]; const message = await ctx.sendFollowUp({ embeds: embedsVoiceChannels }); @@ -45,13 +44,13 @@ const StartChannelFlow = async ( if (poapSettingsDoc !== null && poapSettingsDoc.isActive) { Log.warn('unable to start due to active event'); - await ctx.sendFollowUp(`\`${channelChoice.name}\` is already active. Please reach out to <@${poapSettingsDoc.discordUserId}> to end event.`); + await ctx.send({ content: `\`${channelChoice.name}\` is already active. Please reach out to <@${poapSettingsDoc.discordUserId}> to end event.`, ephemeral: true }); return; } await setActiveEventInDb(guildMember, db, channelChoice, event, duration, ctx.channelID); - await ctx.sendFollowUp({ + await ctx.send({ embeds: [ { title: 'Event Started', @@ -65,9 +64,10 @@ const StartChannelFlow = async ( ], }, ], + ephemeral: true, }); - await ctx.sendFollowUp(({ content: 'Everything is set, catch you later!' })); + await ctx.sendFollowUp(({ content: 'Everything is set, catch you later!', ephemeral: true })); }; export default StartChannelFlow; \ No newline at end of file diff --git a/src/app/service/poap/start/StartPOAP.ts b/src/app/service/poap/start/StartPOAP.ts index e2d72d4e..52f812ab 100644 --- a/src/app/service/poap/start/StartPOAP.ts +++ b/src/app/service/poap/start/StartPOAP.ts @@ -52,6 +52,8 @@ export default async (ctx: CommandContext, guildMember: GuildMember, platform: s Log.debug('poap start validated'); + await ctx.defer(); + if (platform == constants.PLATFORM_TYPE_TWITTER) { await StartTwitterFlow(ctx, guildMember, db, event, duration); return; diff --git a/src/app/service/poap/start/StartTwitterFlow.ts b/src/app/service/poap/start/StartTwitterFlow.ts index 5b1a5417..d80559d1 100644 --- a/src/app/service/poap/start/StartTwitterFlow.ts +++ b/src/app/service/poap/start/StartTwitterFlow.ts @@ -54,14 +54,10 @@ const StartTwitterFlow = async (ctx: CommandContext, guildMember: GuildMember, d return; } - if (!isDmOn) { - await ctx.send({ content: '⚠ **Please make sure this is a private channel.** I can help you setup the poap event! ⚠', ephemeral: true }); - } - const twitterSpaceId: string = twitterSpaceResult.data[0]['id']; Log.debug(`twitter spaces event active: ${twitterSpaceId}`); - await ctx.send({ content: `Something really special is starting...:bird: https://twitter.com/i/spaces/${twitterSpaceId}` }); + await ctx.send({ content: `Twitter Spaces :bird: is live at https://twitter.com/i/spaces/${twitterSpaceId}` }); const poapTwitterSettings: Collection = db.collection(constants.DB_COLLECTION_POAP_TWITTER_SETTINGS); const activeSettings: POAPTwitterSettings | null = await poapTwitterSettings.findOne({ @@ -74,7 +70,7 @@ const StartTwitterFlow = async (ctx: CommandContext, guildMember: GuildMember, d Log.debug('unable to start twitter event due to active event'); const msg = 'Looks like you have an active twitter spaces event!'; if (isDmOn) { - await ctx.send({ content: msg }); + await ctx.send({ content: msg, ephemeral: true }); } throw new ValidationError(msg); } diff --git a/src/app/utils/POAPUtils.ts b/src/app/utils/POAPUtils.ts index 2790a83c..16375362 100644 --- a/src/app/utils/POAPUtils.ts +++ b/src/app/utils/POAPUtils.ts @@ -558,7 +558,7 @@ const POAPUtils = { await ctx.send({ content: deliveryMsg, ephemeral: true }); } } else { - const failedDeliveryMsg = `Looks like some degens have DMs off or they haven't oped in for delivery. They can claim their POAPs by sending \`gm\` to <@${ApiKeys.DISCORD_BOT_ID}> or executing slash command \`/poap claim\``; + const failedDeliveryMsg = `Looks like some degens have DMs off or they haven't opted in for delivery. They can claim their POAPs by sending \`gm\` to <@${ApiKeys.DISCORD_BOT_ID}> or executing slash command \`/poap claim\``; if (isDmOn) { await guildMember.send({ content: failedDeliveryMsg }); } else if (ctx) { From c00e0da7bd77fb73f5e5a16667ecf57dc9fbc5c5 Mon Sep 17 00:00:00 2001 From: Brian Date: Tue, 18 Jan 2022 19:13:09 -0500 Subject: [PATCH 4/4] fix poap end file --- src/app/service/poap/end/EndTwitterFlow.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/app/service/poap/end/EndTwitterFlow.ts b/src/app/service/poap/end/EndTwitterFlow.ts index cf37c675..9649baee 100644 --- a/src/app/service/poap/end/EndTwitterFlow.ts +++ b/src/app/service/poap/end/EndTwitterFlow.ts @@ -1,6 +1,7 @@ import { GuildMember, MessageAttachment, + MessageOptions, TextChannel, } from 'discord.js'; import { @@ -19,6 +20,7 @@ import POAPUtils, { TwitterPOAPFileParticipant } from '../../../utils/POAPUtils' import { Buffer } from 'buffer'; import { POAPDistributionResults } from '../../../types/poap/POAPDistributionResults'; import channelIds from '../../constants/channelIds'; +import { MessageOptions as MessageOptionsSlash } from 'slash-create/lib/structures/interfaces/messageInteraction'; const EndTwitterFlow = async (guildMember: GuildMember, db: Db, ctx?: CommandContext): Promise => { Log.debug('starting twitter poap end flow...'); @@ -81,7 +83,8 @@ const EndTwitterFlow = async (guildMember: GuildMember, db: Db, ctx?: CommandCon } const bufferFile: Buffer = ServiceUtils.generateCSVStringBuffer(listOfParticipants); - const embedTwitterEnd = { + const fileName = `twitter_participants_${numberOfParticipants}.csv`; + let embedTwitterEnd: MessageOptionsSlash | MessageOptions = { embeds: [ { title: 'Twitter Event Ended', @@ -92,11 +95,14 @@ const EndTwitterFlow = async (guildMember: GuildMember, db: Db, ctx?: CommandCon ], }, ], - files: [{ name: `twitter_participants_${numberOfParticipants}.csv`, attachment: bufferFile }], }; if (isDmOn) { + embedTwitterEnd = embedTwitterEnd as MessageOptions; + embedTwitterEnd.files = [{ name: fileName, attachment: bufferFile }]; await guildMember.send(embedTwitterEnd); } else if (ctx) { + embedTwitterEnd = embedTwitterEnd as MessageOptionsSlash; + embedTwitterEnd.file = [{ name: fileName, file: bufferFile }]; await ctx.send(embedTwitterEnd); }