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 #221 from BanklessDAO/pre-release
Browse files Browse the repository at this point in the history
Pre release
  • Loading branch information
frogmonkee authored Nov 4, 2021
2 parents 51571f8 + 717c5dc commit 354cda2
Show file tree
Hide file tree
Showing 18 changed files with 560 additions and 7 deletions.
3 changes: 2 additions & 1 deletion .env.prod
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ DISCORD_STAGE_COMMUNITY_CALL_ID=848928397010010112
DISCORD_CHANNEL_DEV_WORKROOM_ID=841349002330505266
DISCORD_CHANNEL_WRITERS_ROOM_ID=841332222946312232
DISCORD_CHANNEL_SCOAP_SQUAD_ID=897296738447159296
DISCORD_CHANNEL_SUPPORT_ID=834499078434979893

# Logger
LOGDNA_APP_NAME=degen
Expand All @@ -42,4 +43,4 @@ DAO_CURRENT_SEASON_END_DATE=2022-01-07T04:00:00.000Z
DAO_GUEST_PASS_EXPIRATION_DAYS=14

# URLs
DAO_BOUNTY_BOARD_URL=https://bountyboard.bankless.community/
DAO_BOUNTY_BOARD_URL=https://bountyboard.bankless.community/
7 changes: 5 additions & 2 deletions .github/workflows/build-test.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
name: Build and Test
on:
push:
branches:
- '**'
branches:
- '**'
pull_request:
branches:
- '**'
jobs:
build-test:
runs-on: ubuntu-20.04
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ build/Release
# Dependency directories
node_modules/
jspm_packages/
package-lock.json

# TypeScript v1 declaration files
typings/
Expand Down Expand Up @@ -115,3 +114,5 @@ build

# jest-mongodb output
globalConfig.json

https://discord.com/api/oauth2/authorize?client_id=901799442502516766&permissions=4027055222&scope=bot%20&applications.commands
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## 1.8.4-RELEASE (2021-11-03)

1. Introduce /coordinape form request command for BanklessDAO
2. Update feedback request form to canny
3. Add /timecard command
4. Run build-test action on every pull request

## 1.8.3-RELEASE (2021-10-26)

1. Check rate limit
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "degen",
"version": "1.8.3",
"version": "1.8.4",
"description": "Administrative and Utilitarian bot for the Bankless Discord Server.",
"main": "app.js",
"private": true,
Expand Down
88 changes: 88 additions & 0 deletions src/app/commands/coordinape/Coordinape.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import {
ApplicationCommandPermissionType,
CommandContext,
CommandOptionType,
SlashCommand,
SlashCreator,
} from 'slash-create';
import roleIds from '../../service/constants/roleIds';
import ServiceUtils from '../../utils/ServiceUtils';
import CoordinapeSendForm from '../../service/coordinape/CoordinapeSendForm';
import ValidationError from '../../errors/ValidationError';
import discordServerIds from '../../service/constants/discordServerIds';
import { LogUtils } from '../../utils/Log';

module.exports = class Coordinape extends SlashCommand {
constructor(creator: SlashCreator) {
super(creator, {
name: 'coordinape',
description: 'Commands to manage Coordinape rounds',
guildIDs: [discordServerIds.banklessDAO, discordServerIds.discordBotGarage],
options: [
{
name: 'form-request',
type: CommandOptionType.SUB_COMMAND,
description: 'Send correct for to coordinape participants.',
options: [],
},
],
throttling: {
usages: 1,
duration: 1,
},
defaultPermission: false,
permissions: {
[discordServerIds.banklessDAO]: [
{
type: ApplicationCommandPermissionType.ROLE,
id: roleIds.level2,
permission: true,
},
{
type: ApplicationCommandPermissionType.ROLE,
id: roleIds.level1,
permission: true,
},
],
[discordServerIds.discordBotGarage]: [
{
type: ApplicationCommandPermissionType.ROLE,
id: roleIds.level2,
permission: true,
},
{
type: ApplicationCommandPermissionType.ROLE,
id: roleIds.level1,
permission: true,
},
],
},
});
}

async run(ctx: CommandContext) {
LogUtils.logCommandStart(ctx);
if (ctx.user.bot) return;
const { guildMember } = await ServiceUtils.getGuildAndMember(ctx);
let command: Promise<any>;
switch (ctx.subcommands[0]) {
case 'form-request':
command = CoordinapeSendForm(guildMember, ctx);
break;
default:
return ctx.send(`${ctx.user.mention} Please try again.`);
}

this.handleCommandError(ctx, command);
}

handleCommandError(ctx: CommandContext, command: Promise<any>) {
command.catch(e => {
if (!(e instanceof ValidationError)) {
LogUtils.logError('failed to handle coordinape command', e);
return ctx.send('Sorry something is not working and our devs are looking into it');
}
});
}

};
4 changes: 2 additions & 2 deletions src/app/commands/help/FeatureRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ export default class FeatureRequest extends SlashCommand {
LogUtils.logCommandStart(ctx);
// Ignores commands from bots
if (ctx.user.bot) return;
const form = 'https://docs.google.com/forms/d/e/1FAIpQLSdTvYOyzF6A_YJKmco7iGeVDRzOBmJF2HfYKEiRnfATwcxjFw/viewform';

const form = 'https://degen.canny.io/';
await ctx.send(`Here you are ${ctx.user.mention}, the DEGEN feature request form: ${form}`);
}
}
94 changes: 94 additions & 0 deletions src/app/commands/timecard/Timecard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/* eslint-disable no-console */
import {
CommandContext,
CommandOptionType,
SlashCommand,
SlashCreator,
} from 'slash-create';
import ValidationError from '../../errors/ValidationError';
import ServiceUtils from '../../utils/ServiceUtils';
import Checkin from '../../service/timecard/Checkin';
import Checkout from '../../service/timecard/Checkout';
import Hours from '../../service/timecard/Hours';
import discordServerIds from '../../service/constants/discordServerIds';
import { LogUtils } from '../../utils/Log';

export default class Timecard extends SlashCommand {
constructor(creator: SlashCreator) {
super(creator, {
name: 'timecard',
description: 'Checkin, checkout, and calculate total hours',
guildIDs: [process.env.DISCORD_SERVER_ID, discordServerIds.discordBotGarage],
options: [
{
name: 'checkin',
type: CommandOptionType.SUB_COMMAND,
description: 'Initiate time card.',
},
{
name: 'checkout',
type: CommandOptionType.SUB_COMMAND,
description: 'End and log timecard.',
options: [
{
name: 'description',
type: CommandOptionType.STRING,
description: 'Brief description of what you are working on.',
required: true,
},
],
},
{
name: 'hours',
type: CommandOptionType.SUB_COMMAND,
description: 'Calculate total hours worked.',
},
],
throttling: {
usages: 2,
duration: 1,
},
defaultPermission: true,
});
}

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

const { guildMember } = await ServiceUtils.getGuildAndMember(ctx);
let command: Promise<any>;

try {
switch (ctx.subcommands[0]) {
case 'checkin':
command = Checkin(guildMember, Date.now());
break;
case 'checkout':
command = Checkout(guildMember, Date.now(), ctx.options.checkout['description']);
break;
case 'hours':
command = Hours(guildMember);
break;
default:
return ctx.send(`${ctx.user.mention} Please try again.`);
}
this.handleCommandError(ctx, command);
} catch (e) {
console.error(e);
}
}

handleCommandError(ctx: CommandContext, command: Promise<any>): void {
command.then(() => {
return ctx.send(`${ctx.user.mention} Sent you a DM with information.`);
}).catch(e => {
if (e instanceof ValidationError) {
return ctx.send(e.message);
} else {
LogUtils.logError('failed to handle timecard command', e);
return ctx.send('Sorry something is not working and our devs are looking into it.');
}
});
}
}
3 changes: 3 additions & 0 deletions src/app/schema/timecard/collectionsinit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Mongosh operations to be done on database collections
db.timecard.createIndex({ discordUserId: 1, isActive: 1, startTime: 1 }, { unique: true });
db.timecard.createIndex({ discordUserId: 1, duration: 1, discordServerId: 1 }, { unique: true });
40 changes: 40 additions & 0 deletions src/app/schema/timecard/timecard.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"$jsonSchema": {
"bsonType": "object",
"required": [
"discordUserId",
"startTime",
"endTime"
],
"properties": {
"isActive": {
"bsonType": "boolean",
"description": "Indicates if the Timecard is active"
},
"description": {
"bsonType": "string",
"description": "Brief description of what you are working on."
},
"startTime": {
"bsonType": ["string", "null"],
"description": "ISO8601 of when the meeting started."
},
"endTime": {
"bsonType": ["string", "null"],
"description": "ISO8601 of when the meeting ended."
},
"duration": {
"bsonType": ["number", "null"],
"description": "Duration of the timecard session in minutes"
},
"discordUserId": {
"bsonType": "string",
"description": "Discord Id of the user that initiated the Timecard."
},
"discordServerId": {
"bsonType": "string",
"description": "Identifier for the discord guild where Timecard was activated"
}
}
}
}
1 change: 1 addition & 0 deletions src/app/service/constants/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export default Object.freeze({
DB_NAME_DEGEN: 'degen',
DB_NAME_BOUNTY_BOARD: 'bountyboard',

DB_COLLECTION_TIMECARDS: 'timecards',
DB_COLLECTION_GUEST_USERS: 'guestUsers',
DB_COLLECTION_BOUNTIES: 'bounties',
DB_COLLECTION_POAP_SETTINGS: 'poapSettings',
Expand Down
27 changes: 27 additions & 0 deletions src/app/service/coordinape/CoordinapeSendForm.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { DMChannel, GuildMember } from 'discord.js';
import { CommandContext } from 'slash-create';
import roleIds from '../constants/roleIds';

export default async (member: GuildMember, ctx?: CommandContext): Promise<any> => {
ctx?.send(`Hi, ${ctx.user.mention}! I sent you a DM with more information.`);

const dmChannel: DMChannel = await member.user.createDM();

if (member.partial) {
member = await member.fetch();
}

for (const role of member.roles.cache.values()) {
if (role.id === roleIds.level1) {
for (const role2 of member.roles.cache.values()) {
if (role2.id === roleIds.level2) {
await dmChannel.send({ content: 'Here is your form: <https://docs.google.com/forms/d/16qaDbz14C7d31pTZoOTRiDVShfzOimiwZlxUBit0Fmw/>' });
return;
}
}

await dmChannel.send({ content: 'Here is your form: <https://docs.google.com/forms/d/1-_uHDxyWFjDD92hdujqsylZgLmTLLuUnbJDaMSUX_hY>' });
return;
}
}
};
42 changes: 42 additions & 0 deletions src/app/service/timecard/Checkin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { GuildMember } from 'discord.js';
import { Db, Collection } from 'mongodb';
import dbInstance from '../../utils/dbUtils';
import constants from '../constants/constants';
import { Timecard } from '../../types/timecard.ts/Timecard';
import dayjs from 'dayjs';
import ValidationError from '../../errors/ValidationError';

export default async (guildMember: GuildMember, date: number): Promise<any> => {
if (guildMember.user.id === null) {
throw new ValidationError(`No guildMember <@${guildMember.id}>.`);
}


const timecard = {
startTime: date,
description: null,
endTime: null,
discordUserId: guildMember.user.id,
discordServerId: guildMember.guild.id,
isActive: true,
};

const db: Db = await dbInstance.dbConnect(constants.DB_NAME_DEGEN);
const timecardDb: Collection = await db.collection(constants.DB_COLLECTION_TIMECARDS);

const activeTimecard: Timecard = await timecardDb.findOne({
discordUserId: guildMember.user.id,
discordServerId: guildMember.guild.id,
isActive: true,
});

if (activeTimecard) {
await guildMember.send('You already have an active timecard. Close out the active timecard with /timecard checkout then start a new one.');
return 'already checked in';
}

const dbCheckin = await timecardDb.insertOne(timecard);
await guildMember.send(`Timecard started at ${dayjs(date).format()}`);
return dbCheckin;
};

Loading

0 comments on commit 354cda2

Please sign in to comment.