Skip to content

Commit

Permalink
add audit log models
Browse files Browse the repository at this point in the history
  • Loading branch information
theADAMJR committed Apr 10, 2020
1 parent 1bc0bd2 commit 0a8ba68
Show file tree
Hide file tree
Showing 21 changed files with 269 additions and 108 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ Simple multi-purpose Discord bot made with TypeScript
"lavalink": { // used for music server
"password": "youshallnotpass"
},
"tests": {
"tests": { // optional -> used for tests
"guild": {
"id": "685862664223850497" // used for integration tests
"id": "yourTestGuildId" // used for integration tests
}
},
"mongoURL": "mongodb://localhost/2PG", // database URL (port 27017)
Expand Down
5 changes: 3 additions & 2 deletions api/modules/image/image-generator.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { registerFont, loadImage, Canvas } from 'canvas';
import { loadImage, Canvas } from 'canvas';
import config from '../../../config.json';

export default class ImageGenerator
{
Expand All @@ -8,7 +9,7 @@ export default class ImageGenerator

let background = null;
try {
background = await loadImage(backgroundURL || 'modules/image/wallpaper.png')
background = await loadImage(backgroundURL || config.api.defaultBackgroundPath)
}
catch { return; }

Expand Down
18 changes: 10 additions & 8 deletions api/modules/image/xp-card-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ export class XPCardGenerator extends ImageGenerator {

discordUser: User;

constructor(private user: UserDocument, private rank: number)
{
constructor(
private user: UserDocument,
private rank: number,
private xpPerMessage: number) {
super();

this.discordUser = bot.users.cache.get(user._id);
Expand All @@ -36,8 +38,8 @@ export class XPCardGenerator extends ImageGenerator {
const canvas = createCanvas(700, 250);
const context = canvas.getContext('2d');

const backgroundURL = this.user.xpCard.backgroundURL;
await super.addBackgroundToCanvas(context, canvas, backgroundURL);
await super.addBackgroundToCanvas(
context, canvas, this.user.xpCard.backgroundURL);
await this.addXPBar(context, canvas, savedMember);
this.addUserText(context, canvas);
await super.addAvatarToCanvas(context, this.discordUser.displayAvatarURL({ format: 'png' }));
Expand Down Expand Up @@ -69,23 +71,23 @@ export class XPCardGenerator extends ImageGenerator {
const position = { x: 275, y: canvas.height * 0.775 };
const height = 25;

const info = Leveling.xpInfo(member.xpMessages, 50); // TODO: add guild
const info = Leveling.xpInfo(member.xpMessages, this.xpPerMessage);
const nextLevelEXP = info.exp + info.xpForNextLevel;

context.fillStyle = card.secondary || this.colors.secondary;
context.fillRect(position.x, position.y, canvas.width - sizeOffset - 1, height);
context.fillStyle = card.primary || this.colors.tertiary;
context.fillRect(position.x, position.y,
(canvas.width - sizeOffset) * (info.exp / (info.exp + nextLevelEXP)), height);
(canvas.width - sizeOffset) * (info.exp / nextLevelEXP), height);

context.fillStyle = card.secondary || this.colors.secondary;
context.fillStyle = card.primary || this.colors.primary;
context.font = '16px Roboto, sans-serif';
context.fillText(info.exp, canvas.width / 2.5, canvas.height / 1.175);

context.fillStyle = '#0F0F0F';
context.fillText(`/`, canvas.width / 2.5 + context.measureText(info.exp).width, canvas.height / 1.175);

context.fillStyle = card.tertiary || this.colors.tertiary;
context.fillStyle = card.secondary || this.colors.secondary;
context.fillText(`${nextLevelEXP}XP`, canvas.width / 2.5 + context.measureText(`${info.exp}/`).width, canvas.height / 1.175);

context.fillStyle = card.primary || this.colors.primary;
Expand Down
12 changes: 12 additions & 0 deletions api/modules/ranks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { SavedMember, MemberDocument } from "../../models/member";
import { GuildMember } from "discord.js";

export default class Ranks {
static get(member: GuildMember, savedMembers: MemberDocument[]) {
const savedMember = savedMembers
.sort((a, b) => b.xpMessages - a.xpMessages)
.find(m => m.userId === member.id);

return savedMembers.indexOf(savedMember) + 1;
}
}
31 changes: 30 additions & 1 deletion api/routes/api-routes.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Router } from 'express';
import { SavedCommand, CommandDocument } from '../../models/command';
import { AuthClient } from '../server';
import { AuthClient, stripe } from '../server';
import * as config from '../../config.json';

import { router as guildsRoutes } from './guilds-routes';
import { router as userRoutes } from './user-routes';
Expand All @@ -21,6 +22,34 @@ router.get('/auth', async (req, res) => {
} catch { res.status(400).send('Bad Request'); }
});

const items = [
{
name: 'Plus',
description: 'Support 2PG',
amount: 500,
currency: 'usd',
quantity: 1,
}
];
router.get('/pay', async(req, res) => {
try {
const session = await stripe.checkout.sessions.create({
success_url: `${config.webapp.url}/payment-success`,
cancel_url: `${config.webapp.url}/plus`,
payment_method_types: ['card'],
mode: 'payment',
line_items: items
});
res.send(session);
} catch (error) { res.status(400).send(error); }
});

router.get('/invite', (req, res) =>
res.redirect(`https://discordapp.com/api/oauth2/authorize?client_id=${config.bot.id}&redirect_uri=${config.webapp.url}/dashboard&permissions=8&scope=bot`));

router.get('/login', (req, res) =>
res.redirect(`https://discordapp.com/oauth2/authorize?client_id=${config.bot.id}&redirect_uri=${config.webapp.url}/auth&response_type=code&scope=identify guilds`));

router.use('/guilds', guildsRoutes);
router.use('/user', userRoutes);

Expand Down
80 changes: 39 additions & 41 deletions api/routes/guilds-routes.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
import { Router } from 'express';
import config from '../../config.json';
import { SavedUser } from '../../models/user';
import { SavedGuild } from '../../models/guild';
import { SavedMember } from '../../models/member';
import Leveling from '../../modules/xp/leveling';
import { AuthClient } from '../server';
import { XPCardGenerator } from '../modules/image/xp-card-generator';
import { bot } from '../../bot';
import { Guild } from 'discord.js';
import Deps from '../../utils/deps';
import Members from '../../data/members';
import Ranks from '../modules/ranks';
import Users from '../../data/users';
import Guilds from '../../data/guilds';

export const router = Router();

router.get('/', async (req, res) => {
try {
try {
const guilds = await getManagableGuilds(req.query.key);
res.json(guilds);
} catch { res.status(400).send('Bad Request'); }
} catch (error) { res.status(400).send(error); }
});

router.put('/:id/:module', async (req, res) => {
Expand All @@ -38,7 +41,7 @@ router.put('/:id/:module', async (req, res) => {

router.get('/:id/config', async (req, res) => {
try {
const id = req.params.id;
const id = req.params.id;
const savedGuild = await SavedGuild.findById(id).lean();
res.json(savedGuild);
} catch { res.status(400).send('Bad Request'); }
Expand All @@ -48,7 +51,12 @@ router.get('/:id/channels', async (req, res) => {
try {
const guild = bot.guilds.cache.get(req.params.id);
res.send(guild.channels.cache);
} catch { res.status(404).send('Not Found'); }
} catch { res.status(400).send('Bad Request'); }
});

router.get('/:id/log', (req, res) => {
try {
} catch { res.status(400).send('Bad Request'); }
});

router.get('/:id/public', (req, res) => {
Expand Down Expand Up @@ -85,64 +93,54 @@ router.get('/:id/members', async (req, res) => {
rankedMembers.sort((a, b) => b.xpMessages - a.xpMessages);

res.json(rankedMembers);
} catch { res.status(404).send('Not Found'); }
} catch { res.status(400).send('Bad Request'); }
});

async function getManagableGuilds(key: string) {
let userGuilds = await AuthClient.getGuilds(key);

const guilds = new Map<string, Guild>();
for (const id of userGuilds.keys()) {
const authGuild = userGuilds.get(id);
const manageableGuilds = [];
let userGuilds = await AuthClient.getGuilds(key);
for (const id of userGuilds.keys()) {
const authGuild = userGuilds.get(id);
const hasManager = authGuild._permissions
.some(p => p === config.api.managerPermission);

if (!hasManager)
userGuilds.delete(id);
}
if (hasManager)
manageableGuilds.push(id);
}
return bot.guilds.cache
.filter(g => userGuilds.has(g.id));
.filter(g => manageableGuilds.some(id => id === g.id));
}

router.get('/:guildId/members/:memberId/xp-card', async (req, res) => {
try {
const { guildId, memberId } = req.params;

const savedUser = await getOrCreateSavedUser(memberId);
if (!savedUser)
return res.status(404).send('User not found');

const rank = 1;//Ranks.getUserRank(user, users);
const generator = new XPCardGenerator(savedUser, rank);
const user = bot.users.cache.get(memberId);
const savedUser = await Deps.get<Users>(Users).get(user);

console.log(savedUser);
const guild = bot.guilds.cache.get(guildId);
const member = guild?.members.cache.get(memberId);
if (!member)
throw Error();

const savedMember = await Deps.get<Members>(Members).get(member);
const members = await SavedMember.find({ guildId });
const rank = Ranks.get(member, members);

const member = await SavedMember.findOne({ id: memberId, guildId });
const image = await generator.generate(member);
const savedGuild = await Deps.get<Guilds>(Guilds).get(guild);
const generator = new XPCardGenerator(savedUser, rank,
savedGuild.xp.xpPerMessage);
const image = await generator.generate(savedMember);

res.set({'Content-Type': 'image/png'}).send(image);
}
catch (error) { res.status(400).send(error); }
catch (error) { res.status(400).send('Bad Request'); console.log(error);
}
});

async function getOrCreateSavedUser(id: string) {
const user = bot.users.cache.get(id);
if (!user)
throw new Error('Invalid user');

let savedUser = await SavedUser.findById(id);
if (!savedUser) {
savedUser = new SavedUser();
savedUser._id = id;
savedUser.save();
}
return savedUser;
}

async function validateGuildManager(key: string, id: string) {
const guilds = await getManagableGuilds(key);

if (!guilds.has(id))
throw Error();
}
}
31 changes: 9 additions & 22 deletions api/routes/user-routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { XPCardGenerator } from '../modules/image/xp-card-generator';
import { SavedMember } from '../../models/member';
import { AuthClient } from '../server';
import { bot } from '../../bot';
import { SavedUser } from '../../models/user';
import Deps from '../../utils/deps';
import Users from '../../data/users';

export const router = Router();

Expand All @@ -16,9 +17,9 @@ router.get('/', async (req, res) => {

router.get('/saved', async (req, res) => {
try {
const { id } = await getUser(req.query.key);
const user = await getOrCreateSavedUser(id);
res.json(user);
const user = await getUser(req.query.key);
const savedUser = await Deps.get<Users>(Users).get(user);
res.json(savedUser);
} catch { res.status(400).send('Bad Request'); }
});

Expand All @@ -27,12 +28,12 @@ router.get('/xp-card-preview', async (req, res) => {
delete req.query.cache;

const user = await getUser(req.query.key);
const savedUser = await getOrCreateSavedUser(user.id);
const savedUser = await Deps.get<Users>(Users).get(user);
if (!savedUser)
return res.status(404).send('User not found');

const rank = 1;
const generator = new XPCardGenerator(savedUser, rank);
const generator = new XPCardGenerator(savedUser, rank, 50);

const member = new SavedMember();
member.xpMessages = 50;
Expand All @@ -46,9 +47,9 @@ router.get('/xp-card-preview', async (req, res) => {

router.put('/xp-card', async (req, res) => {
try {
const { id } = await getUser(req.query.key);
const user = await getUser(req.query.key);
const savedUser = await Deps.get<Users>(Users).get(user);

const savedUser = await getOrCreateSavedUser(id);
savedUser.xpCard = req.body;
await savedUser.save();

Expand All @@ -59,18 +60,4 @@ router.put('/xp-card', async (req, res) => {
async function getUser(key: string) {
const { id } = await AuthClient.getUser(key);
return bot.users.cache.get(id);
}

async function getOrCreateSavedUser(id: string) {
const user = bot.users.cache.get(id);
if (!user)
throw new Error('Invalid user');

let savedUser = await SavedUser.findById(id);
if (!savedUser) {
savedUser = new SavedUser();
savedUser._id = id;
savedUser.save();
}
return savedUser;
}
5 changes: 4 additions & 1 deletion api/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@ import config from '../config.json';
import cors from 'cors';
import OAuthClient from 'disco-oauth';
import bodyParser from 'body-parser';
import { Stripe } from 'stripe';

import { router as apiRoutes } from './routes/api-routes';
import Log from '../utils/log';

export const app = express(),
AuthClient = new OAuthClient(config.bot.id, config.bot.secret);
AuthClient = new OAuthClient(config.bot.id, config.bot.secret),
stripe = new Stripe(config.api.stripe.apiKey,
{ apiVersion: '2020-03-02' });

export default class API {
constructor() {
Expand Down
5 changes: 4 additions & 1 deletion commands/xp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ export default class XPCommand implements Command {
cooldown = 3;
module: ModuleString = 'XP';

execute = async(ctx: CommandContext, userMention: string) => {
execute = (ctx: CommandContext, userMention: string) => {
const target = (userMention) ?
CommandUtils.getMemberFromMention(userMention, ctx.guild) : ctx.member;

if (target.user.bot)
throw new Error(`Bot users cannot earn XP`);

const xpCardURL = `${config.api.url}/guilds/${ctx.guild.id}/members/${target.id}/xp-card`;
return ctx.channel.send({ files: [{
Expand Down
3 changes: 3 additions & 0 deletions data/db-wrapper.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { Guild } from 'discord.js';
import { Document } from 'mongoose';

/*
* DBWrapper<Input, Output>
*/
export default abstract class DBWrapper<T1, T2 extends Document> {
get(type: T1) {
return this.getOrCreate(type);
Expand Down
Loading

0 comments on commit 0a8ba68

Please sign in to comment.