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 #279 from BanklessDAO/develop
Browse files Browse the repository at this point in the history
  • Loading branch information
SlinkyPotato authored Dec 15, 2021
2 parents 07e4d73 + 390e4c9 commit fc9a5dd
Show file tree
Hide file tree
Showing 33 changed files with 650 additions and 423 deletions.
2 changes: 1 addition & 1 deletion .env.prod
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
NODE_ENV=production
DISCORD_BOT_ACTIVITY="With Your POAPs, the DEGEN way"
DISCORD_BOT_ACTIVITY="Day 18: I made a new friend, I call him Mad Hatter"
MONGODB_PREFIX=mongodb+srv
FAQS_PAGE_ID=29353e63-e864-411a-abc0-061d04906c16
DISCORD_SERVER_ID=834499078434979890
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## 2.4.0-RELEASE (2021-12-14)

1. Enable twitter flow in channel
2. Enable tsconfig strict option
3. Misc cleanup and stability enhancements
4. Extend poap claim to 24 hours

## 2.3.0-RELEASE (2021-12-07)

1. Enable poap scheduling (POAP API integration)
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "degen",
"version": "2.3.0",
"version": "2.4.0",
"description": "Administrative and Utilitarian bot for the Bankless Discord Server.",
"main": "app.js",
"private": true,
Expand Down Expand Up @@ -54,6 +54,7 @@
},
"devDependencies": {
"@shelf/jest-mongodb": "^2.1.0",
"@types/bson": "^4.2.0",
"@types/jest": "^27.0.1",
"@types/mongodb": "^3.6.20",
"@typescript-eslint/eslint-plugin": "^4.26.0",
Expand Down
26 changes: 14 additions & 12 deletions src/app/api/poap/EventsAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,19 +72,21 @@ const EventsAPI = {
},
});
return response.data;
} catch (e) {
} catch (e: Error | undefined | any) {
LogUtils.logError('failed to send poap event to POAP BackOffice', e);
Log.warn('poap response', {
indexMeta: true,
meta: {
error: e.toJSON,
responseHeaders: e.response.headers,
responseStatus: e.response.status,
responseData: e.response.data,
},
});
if (e.response.status == '400') {
throw new ValidationError(`${e.response.data.message}`);
if (e) {
Log.warn('poap response', {
indexMeta: true,
meta: {
error: e.toJSON,
responseHeaders: e.response?.headers,
responseStatus: e.response?.status,
responseData: e.response?.data,
},
});
if (e.response?.status == '400') {
throw new ValidationError(`${e.response?.data?.message}`);
}
}
throw new Error('poap event request failed');
}
Expand Down
6 changes: 3 additions & 3 deletions src/app/api/poap/PoapAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,16 @@ const PoapAPI = {
expiresIn: response.data.expires_in,
tokenType: response.data.token_type,
};
} catch (e) {
} catch (e: Error | any) {
LogUtils.logError('failed to request poap auth token', e);
Log.warn('poap response', {
indexMeta: true,
meta: {
error: e.toJSON,
},
});
if (e.response.status == '400') {
throw new ValidationError(`${e.response.data.message}`);
if (e.response?.status == '400') {
throw new ValidationError(`${e.response?.data?.message}`);
}
throw new Error('poap auth request failed');
}
Expand Down
25 changes: 10 additions & 15 deletions src/app/app.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
// Libs
import { SlashCreator, GatewayServer, SlashCommand, CommandContext } from 'slash-create';
import {
SlashCreator,
GatewayServer,
SlashCommand,
CommandContext,
SlashCreatorOptions,
} from 'slash-create';
import Discord, { Client, ClientOptions, Intents, WSEventType } from 'discord.js';
import path from 'path';
import fs from 'fs';
import Log, { LogUtils } from './utils/Log';

// initialize logger
new Log();

const client: Client = initializeClient();
initializeEvents();

const creator = new SlashCreator({
applicationID: process.env.DISCORD_BOT_APPLICATION_ID,
publicKey: process.env.DISCORD_BOT_PUBLIC_KEY,
token: process.env.DISCORD_BOT_TOKEN,
});
} as SlashCreatorOptions);

creator.on('debug', (message) => Log.debug(`debug: ${ message }`));
creator.on('warn', (message) => Log.warn(`warn: ${ message }`));
Expand Down Expand Up @@ -48,7 +51,7 @@ creator
// Log client errors
client.on('error', Log.error);

client.login(process.env.DISCORD_BOT_TOKEN);
client.login(process.env.DISCORD_BOT_TOKEN).then(Log.debug);

function initializeClient(): Client {
const clientOptions: ClientOptions = {
Expand Down Expand Up @@ -80,15 +83,7 @@ function initializeEvents(): void {
client.on(event.name, (...args) => event.execute(...args, client));
}
} catch (e) {
Log.error('Event failed to process', {
indexMeta: true,
meta: {
name: e.name,
message: e.message,
stack: e.stack,
event,
},
});
LogUtils.logError('event failed to process', e);
}
});
}
Expand Down
19 changes: 15 additions & 4 deletions src/app/commands/admin/Account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { 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';

export default class Account extends SlashCommand {
constructor(creator: SlashCreator) {
Expand Down Expand Up @@ -42,12 +43,22 @@ export default class Account extends SlashCommand {
async run(ctx: CommandContext): Promise<any> {
LogUtils.logCommandStart(ctx);
if (ctx.user.bot) return;
const { guildMember } = await ServiceUtils.getGuildAndMember(ctx);

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

const { guildMember } = await ServiceUtils.getGuildAndMember(ctx.guildID, ctx.user.id);
try {
await VerifyTwitter(ctx, guildMember);
await VerifyTwitter(ctx, guildMember).catch(e => { throw e; });
} catch (e) {
LogUtils.logError('failed to verify user', e, guildMember.guild.id);
await ServiceUtils.sendOutErrorMessage(ctx);
if (e instanceof ValidationError) {
await ctx.send({ content: `${e.message}`, ephemeral: true });
} else {
LogUtils.logError('failed to verify user', e, guildMember.guild.id);
await ServiceUtils.sendOutErrorMessage(ctx);
}
}
}
}
5 changes: 4 additions & 1 deletion src/app/commands/help/Help.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ export default class Help extends SlashCommand {
case 'poap':
messageOptions = HowToPOAP();
break;
default:
messageOptions = { content: 'Invalid command selected' };
break;
}
return ctx.send(messageOptions);
await ctx.send(messageOptions);
}
}
56 changes: 32 additions & 24 deletions src/app/commands/poap/POAP.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import ServiceUtils from '../../utils/ServiceUtils';
import StartPOAP from '../../service/poap/start/StartPOAP';
import ValidationError from '../../errors/ValidationError';
import EarlyTermination from '../../errors/EarlyTermination';
import EndPOAP from '../../service/poap/EndPOAP';
import EndPOAP from '../../service/poap/end/EndPOAP';
import DistributePOAP from '../../service/poap/DistributePOAP';
import SchedulePOAP from '../../service/poap/SchedulePOAP';
import Log, { LogUtils } from '../../utils/Log';
Expand Down Expand Up @@ -105,7 +105,7 @@ module.exports = class poap extends SlashCommand {
required: true,
},
{
name: 'duration-minutes',
name: 'duration',
type: CommandOptionType.STRING,
description: 'Number of minutes the event will remain active.',
required: false,
Expand Down Expand Up @@ -216,55 +216,60 @@ module.exports = class poap extends SlashCommand {
LogUtils.logCommandStart(ctx);
if (ctx.user.bot) return;

let guildMember: GuildMember;
if (ctx.guildID != null) {
guildMember = (await ServiceUtils.getGuildAndMember(ctx)).guildMember;
}
const subCommand: string = ctx.subcommands[0];

let command: Promise<any>;
let guildMember: GuildMember | undefined;
let command: Promise<any> | null = null;
let authorizedRoles: any[];
let authorizedUsers: any[];
let platform: string;

try {
switch (ctx.subcommands[0]) {
if (ctx.guildID) {
guildMember = (await ServiceUtils.getGuildAndMember(ctx.guildID, ctx.user.id)).guildMember;
}

if (subCommand != 'claim' && !guildMember) {
await ctx.send({ content: 'Please try command within discord server.', ephemeral: true });
return;
}

switch (subCommand) {
case 'config':
if (ctx.subcommands[1] == 'status') {
command = StatusPOAP(ctx, guildMember);
command = StatusPOAP(ctx, guildMember as GuildMember);
} else if (ctx.subcommands[1] == 'modify') {
authorizedRoles = [ctx.options.config.modify['role-1'], ctx.options.config.modify['role-2'], ctx.options.config.modify['role-3']];
authorizedUsers = [ctx.options.config.modify['user-1'], ctx.options.config.modify['user-2'], ctx.options.config.modify['user-3']];
command = ModifyPOAP(ctx, guildMember, authorizedRoles, authorizedUsers);
command = ModifyPOAP(ctx, guildMember as GuildMember, authorizedRoles, authorizedUsers);
}
break;
case 'mint':
command = SchedulePOAP(ctx, guildMember, ctx.options.mint['mint-copies']);
command = SchedulePOAP(ctx, guildMember as GuildMember, ctx.options.mint['mint-copies']);
break;
case 'start':
platform = ctx.options.start['platform'] != null && ctx.options.start['platform'] != '' ? ctx.options.start['platform'] : constants.PLATFORM_TYPE_DISCORD;
Log.debug(`platform: ${platform}`);
command = StartPOAP(ctx, guildMember, platform, ctx.options.start.event, ctx.options.start['duration-minutes']);
command = StartPOAP(ctx, guildMember as GuildMember, platform, ctx.options.start.event, ctx.options.start['duration-minutes']);
break;
case 'end':
if (ctx.guildID == undefined) {
await ctx.send('I love your enthusiasm, but please return to a Discord channel to end the event.');
return;
}
platform = ctx.options.end['platform'] != null && ctx.options.end['platform'] != '' ? ctx.options.end['platform'] : constants.PLATFORM_TYPE_DISCORD;
Log.debug(`platform: ${platform}`);
command = EndPOAP(guildMember, platform, ctx);
command = EndPOAP(guildMember as GuildMember, platform, ctx);
break;
case 'distribute':
platform = ctx.options.distribute['platform'] != null && ctx.options.distribute['platform'] != '' ? ctx.options.distribute['platform'] : constants.PLATFORM_TYPE_DISCORD;
Log.debug(`platform: ${platform}`);
command = DistributePOAP(ctx, guildMember, ctx.options.distribute['event'], platform);
command = DistributePOAP(ctx, guildMember as GuildMember, ctx.options.distribute['event'], platform);
break;
case 'claim':
platform = ctx.options.claim.platform != null && ctx.options.claim.platform != '' ? ctx.options.claim.platform : constants.PLATFORM_TYPE_DISCORD;
Log.debug(`platform: ${platform}`);
command = ClaimPOAP(ctx, platform, guildMember);
break;
default:
return ctx.send(`${ctx.user.mention} Please try again.`);
await ctx.send(`${ctx.user.mention} Please try again.`).catch(Log.error);
return;
}
this.handleCommandError(ctx, command);
return;
Expand All @@ -275,19 +280,22 @@ module.exports = class poap extends SlashCommand {
}
}

handleCommandError(ctx: CommandContext, command: Promise<any>) {
handleCommandError(ctx: CommandContext, command?: Promise<any> | null) {
if (command == null) {
ServiceUtils.sendOutErrorMessage(ctx).catch(Log.error);
return;
}
command.catch(async e => {
if (e instanceof ValidationError) {
await ctx.sendFollowUp({ content: `${e.message}`, ephemeral: true });
await ctx.send({ content: `${e.message}`, ephemeral: true }).catch(Log.error);
return;
} else if (e instanceof EarlyTermination) {
await ctx.sendFollowUp({ content: `${e.message}`, ephemeral: true });
await ctx.send({ content: `${e.message}`, ephemeral: true }).catch(Log.error);
return;
} else {
LogUtils.logError('failed to handle poap command', e);
await ServiceUtils.sendOutErrorMessage(ctx);
return;
}
});
}
};
};
8 changes: 6 additions & 2 deletions src/app/events/Ready.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,13 @@ export default class implements DiscordEvent {

async execute(client: Client): Promise<any> {
try {
Log.info('The Sun will never set on the DAO. Neither will I. DEGEN & Serendipity are ready for service.');
Log.info('The Sun will never set on the DAO. Neither will I. DEGEN is ready for service.');

if (client.user) {
Log.debug(`setting status: ${process.env.DISCORD_BOT_ACTIVITY}`);
client.user.setActivity(process.env.DISCORD_BOT_ACTIVITY as string);
}

client.user.setActivity(process.env.DISCORD_BOT_ACTIVITY);
client.guilds.cache.forEach((guild: Guild) => {
Log.info(`DEGEN active for: ${guild.id}, ${guild.name}`);
});
Expand Down
15 changes: 12 additions & 3 deletions src/app/events/poap/AddUserForEvent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { POAPSettings } from '../../types/poap/POAPSettings';
import { POAPParticipant } from '../../types/poap/POAPParticipant';
import Log, { LogUtils } from '../../utils/Log';
import dayjs, { Dayjs } from 'dayjs';
import EndPOAP from '../../service/poap/EndPOAP';
import EndPOAP from '../../service/poap/end/EndPOAP';
import MongoDbUtils from '../../utils/MongoDbUtils';

export default async (oldState: VoiceState, newState: VoiceState): Promise<any> => {
Expand All @@ -15,7 +15,12 @@ export default async (oldState: VoiceState, newState: VoiceState): Promise<any>
}

const guild: Guild = (oldState.guild != null) ? oldState.guild : newState.guild;
const member: GuildMember = (oldState.guild != null) ? oldState.member : newState.member;
const member: GuildMember | null = (oldState.guild != null) ? oldState.member : newState.member;

if (member == null) {
// could not find member
return;
}

const db: Db = await MongoDbUtils.connect(constants.DB_NAME_DEGEN);
db.collection(constants.DB_COLLECTION_POAP_SETTINGS);
Expand All @@ -30,7 +35,11 @@ export default async (oldState: VoiceState, newState: VoiceState): Promise<any>
try {
const endDate: Dayjs = (poapSetting.endTime == null) ? currentDate : dayjs(poapSetting.endTime);
if (currentDate.isBefore(endDate)) {
const voiceChannel: GuildChannel = await guild.channels.fetch(poapSetting.voiceChannelId);
const voiceChannel: GuildChannel | null = await guild.channels.fetch(poapSetting.voiceChannelId);
if (voiceChannel == null) {
Log.warn('voice channel might have been deleted.');
return;
}
await addUserToDb(oldState, newState, db, voiceChannel, member);
} else {
Log.debug(`current date is after or equal to event end date, currentDate: ${currentDate}, endDate: ${endDate}`);
Expand Down
1 change: 1 addition & 0 deletions src/app/schema/poap/collectionsInit.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable */
// Mongosh operations to be done on database collections
db.poapSettings.createIndex({ voiceChannelId: 1, discordServerId: 1 }, { unique: true });
db.poapParticipants.createIndex({ voiceChannelId: 1, discordServerId: 1, discordUserId: 1 }, { unique: true });
Expand Down
7 changes: 6 additions & 1 deletion src/app/schema/poap/poapTwitterSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"twitterId",
"discordServerId",
"startDate",
"endDate"
"endDate",
"channelExecutionId"
],
"properties": {
"event": {
Expand Down Expand Up @@ -46,6 +47,10 @@
"minAttendance": {
"bsonType": "string",
"description": "Minimum attendance time required in minutes."
},
"channelExecutionId": {
"bsonType": ["string", "null"],
"description": "ChannelId of where the poap start command was executed"
}
}
}
Expand Down
Loading

0 comments on commit fc9a5dd

Please sign in to comment.