Skip to content
This repository has been archived by the owner on Aug 26, 2022. It is now read-only.

Commit

Permalink
Merge pull request #303 from BanklessDAO/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
SlinkyPotato authored Jan 19, 2022
2 parents c3a5d9b + 447e7ee commit b6a766d
Show file tree
Hide file tree
Showing 32 changed files with 960 additions and 221 deletions.
2 changes: 1 addition & 1 deletion .env.prod
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ LOGDNA_DEFAULT_LEVEL=info

# POAP
POAP_REQUIRED_PARTICIPATION_DURATION=10
POAP_MAX_EVENT_DURATION_MINUTES=180
POAP_MAX_EVENT_DURATION_MINUTES=720

# Twitter
TWITTER_API_TOKEN=
Expand Down
2 changes: 1 addition & 1 deletion .env.qa
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ LOGDNA_DEFAULT_LEVEL=debug

# POAP
POAP_REQUIRED_PARTICIPATION_DURATION=10
POAP_MAX_EVENT_DURATION_MINUTES=180
POAP_MAX_EVENT_DURATION_MINUTES=720

# Twitter
TWITTER_API_TOKEN=
Expand Down
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
# Changelog

## 2.7.0-RELEASE (2022-01-18)

1. Add more stability to opt-in messages
2. Add account commands
- /account link (renamed from /account verify)
- /account list
- /account unlink
3. Restrict DEGEN to certain discord servers
4. Upgrade discord.js -> 13.6.0, upgrade slash-create -> 5.0.3
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 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
11. Message enhancements to twitter flow

## 2.6.2-RELEASE (2022-01-13)

1. Handle twitter spaces exceptions
Expand Down
8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "degen",
"version": "2.6.2",
"version": "2.7.0",
"description": "Administrative and Utilitarian bot for the Bankless Discord Server.",
"main": "app.js",
"private": true,
Expand Down Expand Up @@ -40,18 +40,20 @@
"@sentry/node": "^6.16.1",
"@sentry/tracing": "^6.16.1",
"@types/node": "^16.7.1",
"@types/node-cron": "^3.0.1",
"axios": "^0.21.4",
"csv-parse": "^5.0.3",
"csv-stringify": "^6.0.3",
"dayjs": "^1.10.7",
"discord.js": "^13.5.1",
"discord.js": "^13.6.0",
"dotenv": "^10.0.0",
"form-data": "^4.0.0",
"lodash.clonedeep": "^4.5.0",
"lodash.isequal": "^4.5.0",
"mongodb": "^3.6.9",
"node-cron": "^3.0.0",
"p-queue": "^6.6.2",
"slash-create": "^5.0.2",
"slash-create": "^5.0.3",
"twitter-api-v2": "^1.6.5",
"uuid": "^8.3.2"
},
Expand Down
63 changes: 53 additions & 10 deletions src/app/commands/admin/Account.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,45 @@
import { CommandContext, CommandOptionType, SlashCommand, SlashCreator } from 'slash-create';
import { LogUtils } from '../../utils/Log';
import Log, { LogUtils } from '../../utils/Log';
import VerifyTwitter from '../../service/account/VerifyTwitter';
import ServiceUtils from '../../utils/ServiceUtils';
import discordServerIds from '../../service/constants/discordServerIds';
import ValidationError from '../../errors/ValidationError';
import { command } from '../../utils/SentryUtils';
import UnlinkAccount from '../../service/account/UnlinkAccount';
import constants from '../../service/constants/constants';
import ListAccounts from '../../service/account/ListAccounts';

export default class Account extends SlashCommand {
constructor(creator: SlashCreator) {
super(creator, {
name: 'account',
description: 'Manage your account\'s integration.',
description: 'Manage external account integration.',
throttling: {
usages: 1,
duration: 2,
},
guildIDs: [discordServerIds.banklessDAO, discordServerIds.discordBotGarage],
defaultPermission: true,
options: [
{
name: 'verify',
name: 'link',
type: CommandOptionType.SUB_COMMAND,
description: 'Link DEGEN to your account or wallet.',
options: [
{
name: 'platform',
type: CommandOptionType.STRING,
description: 'Type of account or wallet to unlink from discord.',
required: true,
choices: [
{
name: 'Twitter',
value: constants.PLATFORM_TYPE_TWITTER,
},
],
},
],
},
{
name: 'unlink',
type: CommandOptionType.SUB_COMMAND,
description: 'Link DEGEN to your account or wallet.',
options: [
Expand All @@ -31,12 +51,18 @@ export default class Account extends SlashCommand {
choices: [
{
name: 'Twitter',
value: 'TWITTER_ACCOUNT',
value: constants.PLATFORM_TYPE_TWITTER,
},
],
},
],
},
{
name: 'list',
type: CommandOptionType.SUB_COMMAND,
description: 'Display all linked accounts.',
options: [],
},
],
});
}
Expand All @@ -47,18 +73,35 @@ export default class Account extends SlashCommand {
if (ctx.user.bot) return;

if (ctx.guildID == null) {
await ctx.send({ content: 'Please try this command within a discord server.' });
await ctx.send({ content: 'Please try command within a discord server.' });
return;
}

const { guildMember } = await ServiceUtils.getGuildAndMember(ctx.guildID, ctx.user.id);
const subCommand: string = ctx.subcommands[0];

try {
await VerifyTwitter(ctx, guildMember, true).catch(e => { throw e; });
const { guildMember } = await ServiceUtils.getGuildAndMember(ctx.guildID, ctx.user.id);

switch (subCommand) {
case 'link':
await VerifyTwitter(ctx, guildMember, true).catch(e => { throw e; });
break;
case 'unlink':
await UnlinkAccount(ctx, guildMember, ctx.options.unlink.platform).catch(e => { throw e; });
break;
case 'list':
await ListAccounts(ctx, guildMember).catch(e => { throw e; });
break;
default:
await ctx.send({ content: 'Please try again' }).catch(Log.error);
break;
}

} catch (e) {
if (e instanceof ValidationError) {
await ctx.send({ content: `${e.message}`, ephemeral: true });
} else {
LogUtils.logError('failed to verify user', e, guildMember.guild.id);
LogUtils.logError('failed to verify user', e);
await ServiceUtils.sendOutErrorMessage(ctx);
}
}
Expand Down
6 changes: 5 additions & 1 deletion src/app/commands/help/Help.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
import HowToPOAP from '../../service/help/HowToPOAP';
import { LogUtils } from '../../utils/Log';
import { command } from '../../utils/SentryUtils';
import HowToAccount from '../../service/help/HowToAccount';

export default class Help extends SlashCommand {
constructor(creator: SlashCreator) {
Expand All @@ -17,7 +18,7 @@ export default class Help extends SlashCommand {
{
name: 'poap',
type: CommandOptionType.SUB_COMMAND,
description: 'Information on how to start, stop, and optionally send out POAP links',
description: 'Information on how to claim, start, stop, and send out POAP links.',
},
],
throttling: {
Expand All @@ -38,6 +39,9 @@ export default class Help extends SlashCommand {
case 'poap':
messageOptions = HowToPOAP();
break;
case 'account':
messageOptions = HowToAccount();
break;
default:
messageOptions = { content: 'Invalid command selected' };
break;
Expand Down
63 changes: 63 additions & 0 deletions src/app/commands/poap/Claim.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import {
CommandContext,
SlashCommand,
SlashCreator,
} from 'slash-create';
import ServiceUtils from '../../utils/ServiceUtils';
import ValidationError from '../../errors/ValidationError';
import EarlyTermination from '../../errors/EarlyTermination';
import Log, { LogUtils } from '../../utils/Log';
import ClaimPOAP from '../../service/poap/ClaimPOAP';
import constants from '../../service/constants/constants';
import { GuildMember } from 'discord.js';
import { command } from '../../utils/SentryUtils';

export default class POAP extends SlashCommand {
constructor(creator: SlashCreator) {
super(creator, {
name: 'claim',
description: 'Claim your POAPs.',
throttling: {
usages: 20,
duration: 1,
},
defaultPermission: true,
});
}

@command
async run(ctx: CommandContext): Promise<void> {
LogUtils.logCommandStart(ctx);
if (ctx.user.bot) return;

let guildMember: GuildMember | undefined;
let commandPromise: Promise<any> | null = null;
let platform: string;

try {
if (ctx.guildID) {
guildMember = (await ServiceUtils.getGuildAndMember(ctx.guildID, ctx.user.id)).guildMember;
}

platform = ctx.options.platform != null && ctx.options.platform != '' ? ctx.options.platform : constants.PLATFORM_TYPE_DISCORD;
Log.debug(`platform: ${platform}`);
commandPromise = ClaimPOAP(ctx, platform, guildMember);
if (commandPromise == null) {
ServiceUtils.sendOutErrorMessage(ctx).catch(Log.error);
return;
}
} catch (e) {
LogUtils.logError('failed to process POAP command', e);
if (e instanceof ValidationError) {
await ServiceUtils.sendOutErrorMessage(ctx, `${e?.message}`);
return;
} else if (e instanceof EarlyTermination) {
await ctx.sendFollowUp({ content: `${e?.message}`, ephemeral: true }).catch(Log.error);
return;
} else {
LogUtils.logError('failed to handle poap command', e);
await ServiceUtils.sendOutErrorMessage(ctx);
}
}
}
}
12 changes: 6 additions & 6 deletions src/app/commands/poap/POAP.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ export default class POAP extends SlashCommand {
super(creator, {
name: 'poap',
description: 'Receive a list of all attendees in the specified voice channel and optionally send out POAP links.',
throttling: {
usages: 10,
duration: 1,
},
defaultPermission: true,
options: [
{
name: 'config',
Expand Down Expand Up @@ -184,7 +189,7 @@ export default class POAP extends SlashCommand {
{
name: 'claim',
type: CommandOptionType.SUB_COMMAND,
description: 'Claim POAPs for all the events DEGEN failed to deliver.',
description: 'Claim your POAPs.',
options: [
{
name: 'platform',
Expand All @@ -205,11 +210,6 @@ export default class POAP extends SlashCommand {
],
},
],
throttling: {
usages: 10,
duration: 1,
},
defaultPermission: true,
});
}

Expand Down
3 changes: 2 additions & 1 deletion src/app/events/Ready.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ export default class implements DiscordEvent {
// should not wait
POAPService.runAutoEndSetup(client, constants.PLATFORM_TYPE_DISCORD).catch(Log.error);
POAPService.runAutoEndSetup(client, constants.PLATFORM_TYPE_TWITTER).catch(Log.error);
await POAPService.clearExpiredPOAPs();
await POAPService.clearExpiredPOAPs().catch(Log.error);
POAPService.setupPOAPCleanupCronJob();

Log.info(`${constants.APP_NAME} is ready!`);
} catch (e) {
Expand Down
2 changes: 1 addition & 1 deletion src/app/events/VoiceStateUpdate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export default class implements DiscordEvent {
*/
async execute(oldState: VoiceState, newState: VoiceState): Promise<any> {
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);
}
Expand Down
5 changes: 3 additions & 2 deletions src/app/events/poap/HandleParticipantDuringEvent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,20 @@ type BasicUser = {

const HandleParticipantDuringEvent = async (oldState: VoiceState, newState: VoiceState): Promise<any> => {
if (hasUserBeenDeafened(oldState, newState)) {
Log.log(`user has deafened, userId: ${newState.id}`);
if (await isChannelActivePOAPEvent(oldState.channelId, oldState.guild.id)) {
Log.log(`user has deafened for previous channel, userId: ${newState.id}`);
await removeDeafenedUser(oldState.channelId, oldState.guild.id, oldState.id);
}
if (newState.channelId != oldState.channelId && await isChannelActivePOAPEvent(newState.channelId, newState.guild.id)) {
Log.log(`user has deafened for new channel, userId: ${newState.id}`);
await removeDeafenedUser(newState.channelId, newState.guild.id, newState.id);
}
return;
}

if (hasUserBeenUnDeafened(oldState, newState)) {
Log.log(`user has undeafened, userId: ${newState.id}`);
if (await isChannelActivePOAPEvent(newState.channelId, newState.guild.id)) {
Log.log(`user has undeafened for new channel, userId: ${newState.id}`);
await startTrackingUserParticipation({ id: newState.id, tag: newState.member?.user.tag }, newState.guild.id, newState.channelId);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/app/schema/discordUsers.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"required": [
"userId",
"tag",
"isDMEnabled",
"isDMEnabled"
],
"properties": {
"userId": {
Expand Down
Loading

0 comments on commit b6a766d

Please sign in to comment.