Skip to content

Commit

Permalink
fix(graph): Fix graph and add combined graph
Browse files Browse the repository at this point in the history
  • Loading branch information
Marco Crespi committed Nov 25, 2019
1 parent 762297e commit e009c1a
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 62 deletions.
10 changes: 6 additions & 4 deletions i18n/bot/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@
"graph": {
"joins": {
"text": "This chart shows the number of users joining your server.",
"title": "User joining"
"title": "Users joining"
},
"leaves": {
"text": "This chart shows the number of users leaving your server.",
Expand All @@ -325,9 +325,11 @@
},
"description": "Shows graphs about various stats on this server."
},
"usage": {
"text": "This chart shows the usage of InviteManager commands on this server.",
"title": "Command usage"
"minDays": "You have to select at least {{{ days }}} days",
"maxDays": "You may select at most {{{ days }}} days",
"joinsAndLeaves": {
"title": "Users joining and leaving",
"text": "This chart shows the number of users joining and leaving your server."
}
},
"help": {
Expand Down
20 changes: 8 additions & 12 deletions src/framework/services/DatabaseService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -535,16 +535,14 @@ export class DatabaseService {
);
return rows as Array<{ total: string; invalidatedReason: JoinInvalidatedReason }>;
}
public async getJoinsPerDay(guildId: string, days: number) {
public async getJoinsPerDay(guildId: string, from: Date, to: Date) {
const [db, pool] = this.getDbInfo(guildId);
const [rows] = await pool.query<RowDataPacket[]>(
'SELECT YEAR(`createdAt`) AS year, MONTH(`createdAt`) AS month, DAY(`createdAt`) AS day, COUNT(`id`) AS total ' +
`FROM ${db}.${TABLE.joins} ` +
'WHERE `guildId` = ? ' +
'GROUP BY YEAR(`createdAt`), MONTH(`createdAt`), DAY(`createdAt`) ' +
'ORDER BY MAX(`createdAt`) ASC ' +
'LIMIT ? ',
[guildId, days]
'WHERE `guildId` = ? AND `createdAt` > ? AND `createdAt` < ? ' +
'GROUP BY YEAR(`createdAt`), MONTH(`createdAt`), DAY(`createdAt`)',
[guildId, from, to]
);
return rows as Array<{ year: string; month: string; day: string; total: string }>;
}
Expand Down Expand Up @@ -697,16 +695,14 @@ export class DatabaseService {
const res = await this.insertOrUpdate(TABLE.leaves, ['guildId', 'memberId', 'joinId'], [], [leave], l => l.guildId);
return res[0].insertId;
}
public async getLeavesPerDay(guildId: string, days: number) {
public async getLeavesPerDay(guildId: string, from: Date, to: Date) {
const [db, pool] = this.getDbInfo(guildId);
const [rows] = await pool.query<RowDataPacket[]>(
'SELECT YEAR(`createdAt`) AS year, MONTH(`createdAt`) AS month, DAY(`createdAt`) AS day, COUNT(`id`) AS total ' +
`FROM ${db}.${TABLE.leaves} ` +
'WHERE `guildId` = ? ' +
'GROUP BY YEAR(`createdAt`), MONTH(`createdAt`), DAY(`createdAt`) ' +
'ORDER BY MAX(`createdAt`) ASC ' +
'LIMIT ? ',
[guildId, days]
'WHERE `guildId` = ? AND `createdAt` > ? AND `createdAt` < ? ' +
'GROUP BY YEAR(`createdAt`), MONTH(`createdAt`), DAY(`createdAt`)',
[guildId, from, to]
);
return rows as Array<{ year: string; month: string; day: string; total: string }>;
}
Expand Down
122 changes: 77 additions & 45 deletions src/invites/commands/graph.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { Message } from 'eris';
import moment, { Duration } from 'moment';
import moment, { Moment } from 'moment';

import { IMClient } from '../../client';
import { Command, Context } from '../../framework/commands/Command';
import { DurationResolver, EnumResolver } from '../../framework/resolvers';
import { DateResolver, EnumResolver } from '../../framework/resolvers';
import { ChartType, CommandGroup, InvitesCommand } from '../../types';
import { Chart } from '../models/Chart';

const DEFAULT_DAYS = 30;
const COLORS = ['blue', 'red', 'black'];

export default class extends Command {
public constructor(client: IMClient) {
super(client, {
Expand All @@ -19,8 +22,12 @@ export default class extends Command {
required: true
},
{
name: 'duration',
resolver: DurationResolver
name: 'from',
resolver: DateResolver
},
{
name: 'to',
resolver: DateResolver
}
],
group: CommandGroup.Other,
Expand All @@ -32,69 +39,94 @@ export default class extends Command {

public async action(
message: Message,
[type, duration]: [ChartType, Duration],
[type, from, to]: [ChartType, Moment, Moment],
flags: {},
{ guild, t }: Context
): Promise<any> {
let days = 60;
if (duration) {
days = duration.asDays();
if (days < 5) {
days = 5;
} else if (days > 120) {
days = 120;
}
if (!to) {
to = moment();
}
if (!from) {
from = to.clone().subtract(DEFAULT_DAYS, 'days');
}

const start = moment().subtract(days, 'day');
const end = moment();
const days = to.diff(from, 'days');
if (days < 5) {
await this.sendReply(message, t('cmd.graph.minDays', { days: 5 }));
return;
} else if (days > 120) {
await this.sendReply(message, t('cmd.graph.maxDays', { days: 120 }));
return;
}

let title = '';
let description = '';
const vs: { [x: string]: number } = {};

if (type === ChartType.joins) {
const dates: Moment[] = [];
const vs: Map<string, number>[] = [];
for (const curr = from.clone(); to.diff(curr, 'days') >= 0; curr.add(1, 'days')) {
dates.push(curr.clone());
}

const addDataset = () => {
const map: Map<string, number> = new Map();
dates.forEach(date => map.set(date.format('YYYY-MM-DD'), 0));
vs.push(map);
return map;
};

if (type === ChartType.joinsAndLeaves) {
title = t('cmd.graph.joinsAndLeaves.title');
description = t('cmd.graph.joinsAndLeaves.text');

const joinsMap = addDataset();
const fs = await this.client.db.getJoinsPerDay(guild.id, from.toDate(), to.toDate());
fs.forEach(join => joinsMap.set(`${join.year}-${join.month}-${join.day}`, Number(join.total)));

const leavesMap = addDataset();
const lvs = await this.client.db.getLeavesPerDay(guild.id, from.toDate(), to.toDate());
lvs.forEach(leave => leavesMap.set(`${leave.year}-${leave.month}-${leave.day}`, Number(leave.total)));
} else if (type === ChartType.joins) {
title = t('cmd.graph.joins.title');
description = t('cmd.graph.joins.text');

const joins = await this.client.db.getJoinsPerDay(guild.id, days);
joins.forEach(join => (vs[`${join.year}-${join.month}-${join.day}`] = Number(join.total)));
const map = addDataset();
const joins = await this.client.db.getJoinsPerDay(guild.id, from.toDate(), to.toDate());
joins.forEach(join => map.set(`${join.year}-${join.month}-${join.day}`, Number(join.total)));
} else if (type === ChartType.leaves) {
title = t('cmd.graph.leaves.title');
description = t('cmd.graph.leaves.text');

const leaves = await this.client.db.getLeavesPerDay(guild.id, days);
leaves.forEach(leave => (vs[`${leave.year}-${leave.month}-${leave.day}`] = Number(leave.total)));
const map = addDataset();
const leaves = await this.client.db.getLeavesPerDay(guild.id, from.toDate(), to.toDate());
leaves.forEach(leave => map.set(`${leave.year}-${leave.month}-${leave.day}`, Number(leave.total)));
}

const labels: string[] = [];
const data: number[] = [];
const datasets: any[] = [];
for (const v of vs) {
const color = COLORS[datasets.length];
const data = [...v.entries()].sort((a, b) => a[0].localeCompare(b[0])).map(e => e[1]);

for (const m = moment(start); m.diff(end, 'days') <= 0; m.add(1, 'days')) {
labels.push(m.format('DD.MM.YYYY'));
const val = vs[m.format('YYYY-M-D')];
data.push(val ? val : 0);
datasets.push({
label: 'Data',
borderColor: color,
pointBorderColor: color,
pointBackgroundColor: color,
pointBorderWidth: 0,
pointRadius: 1,
fill: true,
borderWidth: 2,
data,
datalabels: {
align: 'end',
anchor: 'end'
}
});
}

const config = {
labels,
datasets: [
{
label: 'Data',
borderColor: 'black',
pointBorderColor: 'black',
pointBackgroundColor: 'black',
pointBorderWidth: 0,
pointRadius: 1,
fill: true,
borderWidth: 2,
data,
datalabels: {
align: 'end',
anchor: 'end'
}
}
]
labels: dates.map(d => d.format('DD.MM.YYYY')),
datasets
};

const chart = new Chart();
Expand Down
3 changes: 2 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ export enum ShardCommand {

export enum ChartType {
joins = 'joins',
leaves = 'leaves'
leaves = 'leaves',
joinsAndLeaves = 'joinsAndLeaves'
}

export enum BotCommand {
Expand Down

0 comments on commit e009c1a

Please sign in to comment.