From 448a1e793f79377365e2765b74fe492e248c1e1f Mon Sep 17 00:00:00 2001 From: Isaac Date: Mon, 17 May 2021 00:04:14 +0100 Subject: [PATCH] "stats" command --- package.json | 1 + pnpm-lock.yaml | 12 ++++++++ src/commands/stats.js | 63 +++++++++++++++++++++++++++++++++++++++++- src/locales/en-GB.json | 19 ++++++++++++- 4 files changed, 93 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index b0f8a92..9e5feb3 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "cryptr": "^6.0.2", "discord.js": "^12.5.1", "dotenv": "^8.2.0", + "keyv": "^4.0.3", "leeks.js": "^0.2.2", "leekslazylogger-fastify": "^0.1.1", "node-emoji": "^1.10.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cc3c46d..a47cce9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,7 @@ specifiers: discord.js: ^12.5.1 dotenv: ^8.2.0 eslint: ^7.21.0 + keyv: ^4.0.3 leeks.js: ^0.2.2 leekslazylogger-fastify: ^0.1.1 mariadb: ^2.5.2 @@ -32,6 +33,7 @@ dependencies: cryptr: 6.0.2 discord.js: 12.5.1 dotenv: 8.2.0 + keyv: 4.0.3 leeks.js: 0.2.2 leekslazylogger-fastify: 0.1.1 node-emoji: 1.10.0 @@ -1399,6 +1401,10 @@ packages: resolution: {integrity: sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=} dev: true + /json-buffer/3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + dev: false + /json-schema-traverse/0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} @@ -1446,6 +1452,12 @@ packages: json-buffer: 3.0.0 dev: true + /keyv/4.0.3: + resolution: {integrity: sha512-zdGa2TOpSZPq5mU6iowDARnMBZgtCqJ11dJROFi6tg6kTn4nuUdU09lFyLFSaHrWqpIJ+EBq4E8/Dc0Vx5vLdA==} + dependencies: + json-buffer: 3.0.1 + dev: false + /latest-version/5.1.0: resolution: {integrity: sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==} engines: {node: '>=8'} diff --git a/src/commands/stats.js b/src/commands/stats.js index a735280..88e1e4d 100644 --- a/src/commands/stats.js +++ b/src/commands/stats.js @@ -1,4 +1,5 @@ const Command = require('../modules/commands/command'); +const Keyv = require('keyv'); const { MessageEmbed } = require('discord.js'); module.exports = class StatsCommand extends Command { @@ -13,10 +14,70 @@ module.exports = class StatsCommand extends Command { args: [], staff_only: true }); + + this.cache = new Keyv({ + namespace: 'cache.commands.stats' + }); } - async execute(message, args) { + async execute(message) { let settings = await message.guild.settings; const i18n = this.client.i18n.getLocale(settings.locale); + + const messages = await this.client.db.models.Message.findAndCountAll(); + + let stats = await this.cache.get(message.guild.id); + + if (!stats) { + let tickets = await this.client.db.models.Ticket.findAndCountAll({ + where: { + guild: message.guild.id + } + }); + + stats = { // maths + tickets: tickets.count, + messages: settings.log_messages + ? await messages.rows + .reduce(async (acc, row) => (await this.client.db.models.Ticket.findOne({ + where: { + id: row.ticket + } + })).guild === message.guild.id + ? await acc + 1 + : await acc, 0) + : null, + + response_time: Math.floor(tickets.rows.reduce((acc, row) => row.first_response + ? acc + ((Math.abs(new Date(row.createdAt) - new Date(row.first_response)) / 1000) / 60) + : acc, 0) / tickets.count) + }; + await this.cache.set(message.guild.id, stats, 60 * 60 * 1000); // cache for an hour + } + + let guild_embed = new MessageEmbed() + .setColor(settings.colour) + .setTitle(i18n('commands.stats.response.guild.title')) + .setDescription(i18n('commands.stats.response.guild.description')) + .addField(i18n('commands.stats.fields.tickets'), stats.tickets, true) + .addField(i18n('commands.stats.fields.response_time.title'), i18n('commands.stats.fields.response_time.minutes', stats.response_time), true) + .setFooter(settings.footer, message.guild.iconURL()); + + if (stats.messages) guild_embed.addField(i18n('commands.stats.fields.messages'), stats.messages, true); + + await message.channel.send(guild_embed); + + if (this.client.guilds.cache.size > 1) { + await message.channel.send( + new MessageEmbed() + .setColor(settings.colour) + .setTitle(i18n('commands.stats.response.global.title')) + .setDescription(i18n('commands.stats.response.global.description')) + .addField(i18n('commands.stats.fields.tickets'), stats.tickets, true) + .addField(i18n('commands.stats.fields.response_time.title'), i18n('commands.stats.fields.response_time.minutes', stats.response_time), true) + .addField(i18n('commands.stats.fields.messages'), stats.messages, true) + .setFooter(settings.footer, message.guild.iconURL()) + ); + } } }; \ No newline at end of file diff --git a/src/locales/en-GB.json b/src/locales/en-GB.json index e1da46d..1c80250 100644 --- a/src/locales/en-GB.json +++ b/src/locales/en-GB.json @@ -330,8 +330,25 @@ "aliases": {}, "args": {}, "description": "Display ticket statistics", + "fields": { + "messages": "Messages", + "response_time": { + "minutes": "%s minutes", + "title": "Avg. response time" + }, + "tickets": "Tickets" + }, "name": "stats", - "response": {} + "response": { + "global": { + "description": "Statistics about tickets across all guilds where this Discord TIckets instance is used.", + "title": "📊 Global stats" + }, + "guild": { + "description": "Statistics about tickets within this guild. This data is cached for an hour.", + "title": "📊 This server's stats" + } + } }, "topic": { "aliases": {},