diff --git a/src/builders/embeds.ts b/src/builders/embeds.ts index 1265655..050c670 100644 --- a/src/builders/embeds.ts +++ b/src/builders/embeds.ts @@ -412,14 +412,17 @@ const statsEmbeds = () => { const scope = opendiscord.stats.get("opendiscord:ticket") const participantsScope = opendiscord.stats.get("opendiscord:participants") - if (!scope || !participantsScope) return + const messagesScope = opendiscord.stats.get("opendiscord:messages") + if (!scope || !participantsScope || !messagesScope) return const data = await scope.render(scopeData.id.value,guild,channel,user) const participantsData = await participantsScope.render(scopeData.id.value,guild,channel,user) + const messagesData = await messagesScope.render(scopeData.id.value,guild,channel,user) instance.setColor(generalConfig.data.mainColor) instance.setTitle(scope.name) instance.setDescription(data) - instance.addFields({name:participantsScope.name,value:participantsData,inline:false}) + instance.addFields({name:participantsScope.name,value:participantsData,inline:true}) + instance.addFields({name:messagesScope.name,value:messagesData,inline:true}) }) ) diff --git a/src/core/api/defaults/stat.ts b/src/core/api/defaults/stat.ts index dd4c016..47e306c 100644 --- a/src/core/api/defaults/stat.ts +++ b/src/core/api/defaults/stat.ts @@ -13,7 +13,8 @@ export interface ODStatsManagerIds_Default { "opendiscord:system":ODStatGlobalScope_DefaultSystem, "opendiscord:user":ODStatScope_DefaultUser, "opendiscord:ticket":ODStatScope_DefaultTicket, - "opendiscord:participants":ODStatScope_DefaultParticipants + "opendiscord:participants":ODStatScope_DefaultParticipants, + "opendiscord:messages":ODStatScope_DefaultMessages, } /**## ODStatsManager_Default `default_class` @@ -60,7 +61,9 @@ export interface ODStatGlobalScopeIds_DefaultGlobal { "opendiscord:tickets-pinned":ODBasicStat, "opendiscord:tickets-moved":ODBasicStat, "opendiscord:users-blacklisted":ODBasicStat, - "opendiscord:transcripts-created":ODBasicStat + "opendiscord:transcripts-created":ODBasicStat, + "opendiscord:ticket-volume":ODDynamicStat, + "opendiscord:average-tickets":ODDynamicStat, } /**## ODStatGlobalScope_DefaultGlobal `default_class` @@ -98,6 +101,13 @@ export class ODStatGlobalScope_DefaultGlobal extends ODStatGlobalScope { return super.getStat(id) } + getAllStats(id:StatsId): Promise<{id:string,value:ODValidStatValue}[]> + getAllStats(id:ODValidId): Promise<{id:string,value:ODValidStatValue}[]> + + getAllStats(id:ODValidId): Promise<{id:string,value:ODValidStatValue}[]> { + return super.getAllStats(id) + } + setStat(id:StatsId, value:ODValidStatValue, mode:ODStatScopeSetMode): Promise setStat(id:ODValidId, value:ODValidStatValue, mode:ODStatScopeSetMode): Promise @@ -119,6 +129,7 @@ export class ODStatGlobalScope_DefaultGlobal extends ODStatGlobalScope { */ export interface ODStatGlobalScopeIds_DefaultSystem { "opendiscord:startup-date":ODDynamicStat, + "opendiscord:system-uptime":ODDynamicStat, "opendiscord:version":ODDynamicStat } @@ -157,6 +168,13 @@ export class ODStatGlobalScope_DefaultSystem extends ODStatGlobalScope { return super.getStat(id) } + getAllStats(id:StatsId): Promise<{id:string,value:ODValidStatValue}[]> + getAllStats(id:ODValidId): Promise<{id:string,value:ODValidStatValue}[]> + + getAllStats(id:ODValidId): Promise<{id:string,value:ODValidStatValue}[]> { + return super.getAllStats(id) + } + setStat(id:StatsId, value:ODValidStatValue, mode:ODStatScopeSetMode): Promise setStat(id:ODValidId, value:ODValidStatValue, mode:ODStatScopeSetMode): Promise @@ -187,7 +205,8 @@ export interface ODStatScopeIds_DefaultUser { "opendiscord:tickets-pinned":ODBasicStat, "opendiscord:tickets-moved":ODBasicStat, "opendiscord:users-blacklisted":ODBasicStat, - "opendiscord:transcripts-created":ODBasicStat + "opendiscord:transcripts-created":ODBasicStat, + "opendiscord:current-tickets":ODDynamicStat, } /**## ODStatScope_DefaultUser `default_class` @@ -225,6 +244,13 @@ export class ODStatScope_DefaultUser extends ODStatScope { return super.getStat(id,scopeId) } + getAllStats(id:StatsId): Promise<{id:string,value:ODValidStatValue}[]> + getAllStats(id:ODValidId): Promise<{id:string,value:ODValidStatValue}[]> + + getAllStats(id:ODValidId): Promise<{id:string,value:ODValidStatValue}[]> { + return super.getAllStats(id) + } + setStat(id:StatsId, scopeId:string, value:ODValidStatValue, mode:ODStatScopeSetMode): Promise setStat(id:ODValidId, scopeId:string, value:ODValidStatValue, mode:ODStatScopeSetMode): Promise @@ -250,7 +276,10 @@ export interface ODStatScopeIds_DefaultTicket { "opendiscord:claimed":ODDynamicStat, "opendiscord:pinned":ODDynamicStat, "opendiscord:creation-date":ODDynamicStat, - "opendiscord:creator":ODDynamicStat + "opendiscord:creator":ODDynamicStat, + "opendiscord:ticket-age":ODDynamicStat, + "opendiscord:response-time":ODDynamicStat, + "opendiscord:resolution-time":ODDynamicStat, } /**## ODStatScope_DefaultTicket `default_class` @@ -288,6 +317,13 @@ export class ODStatScope_DefaultTicket extends ODStatScope { return super.getStat(id,scopeId) } + getAllStats(id:StatsId): Promise<{id:string,value:ODValidStatValue}[]> + getAllStats(id:ODValidId): Promise<{id:string,value:ODValidStatValue}[]> + + getAllStats(id:ODValidId): Promise<{id:string,value:ODValidStatValue}[]> { + return super.getAllStats(id) + } + setStat(id:StatsId, scopeId:string, value:ODValidStatValue, mode:ODStatScopeSetMode): Promise setStat(id:ODValidId, scopeId:string, value:ODValidStatValue, mode:ODStatScopeSetMode): Promise @@ -346,6 +382,13 @@ export class ODStatScope_DefaultParticipants extends ODStatScope { return super.getStat(id,scopeId) } + getAllStats(id:StatsId): Promise<{id:string,value:ODValidStatValue}[]> + getAllStats(id:ODValidId): Promise<{id:string,value:ODValidStatValue}[]> + + getAllStats(id:ODValidId): Promise<{id:string,value:ODValidStatValue}[]> { + return super.getAllStats(id) + } + setStat(id:StatsId, scopeId:string, value:ODValidStatValue, mode:ODStatScopeSetMode): Promise setStat(id:ODValidId, scopeId:string, value:ODValidStatValue, mode:ODStatScopeSetMode): Promise @@ -356,6 +399,71 @@ export class ODStatScope_DefaultParticipants extends ODStatScope { resetStat(id:ODValidId, scopeId:string): Promise resetStat(id:ODValidId, scopeId:string): Promise + resetStat(id:ODValidId, scopeId:string): Promise { + return super.resetStat(id,scopeId) + } +} + +/**## ODStatScopeIds_DefaultMessages `type` + * This interface is a list of ids available in the `ODStatScope_DefaultMessages` class. + * It's used to generate typescript declarations for this class. + */ +export interface ODStatScopeIds_DefaultMessages { + "opendiscord:count":ODDynamicStat +} + +/**## ODStatScope_DefaultMessages `default_class` + * This is a special class that adds type definitions & typescript to the ODStatsManager class. + * It doesn't add any extra features! + * + * This default class is made for the `opendiscord:participants` category in `opendiscord.stats`! + */ +export class ODStatScope_DefaultMessages extends ODStatScope { + get(id:StatsId): ODStatScopeIds_DefaultMessages[StatsId] + get(id:ODValidId): ODStat|null + + get(id:ODValidId): ODStat|null { + return super.get(id) + } + + remove(id:StatsId): ODStatScopeIds_DefaultMessages[StatsId] + remove(id:ODValidId): ODStat|null + + remove(id:ODValidId): ODStat|null { + return super.remove(id) + } + + exists(id:keyof ODStatScopeIds_DefaultMessages): boolean + exists(id:ODValidId): boolean + + exists(id:ODValidId): boolean { + return super.exists(id) + } + + getStat(id:StatsId, scopeId:string): Promise + getStat(id:ODValidId, scopeId:string): Promise + + getStat(id:ODValidId, scopeId:string): Promise { + return super.getStat(id,scopeId) + } + + getAllStats(id:StatsId): Promise<{id:string,value:ODValidStatValue}[]> + getAllStats(id:ODValidId): Promise<{id:string,value:ODValidStatValue}[]> + + getAllStats(id:ODValidId): Promise<{id:string,value:ODValidStatValue}[]> { + return super.getAllStats(id) + } + + setStat(id:StatsId, scopeId:string, value:ODValidStatValue, mode:ODStatScopeSetMode): Promise + setStat(id:ODValidId, scopeId:string, value:ODValidStatValue, mode:ODStatScopeSetMode): Promise + + setStat(id:ODValidId, scopeId:string, value:ODValidStatValue, mode:ODStatScopeSetMode): Promise { + return super.setStat(id,scopeId,value,mode) + } + + resetStat(id:ODValidId, scopeId:string): Promise + resetStat(id:ODValidId, scopeId:string): Promise + resetStat(id:ODValidId, scopeId:string): Promise { return super.resetStat(id,scopeId) } diff --git a/src/core/api/main.ts b/src/core/api/main.ts index ddb8a25..cec0b11 100644 --- a/src/core/api/main.ts +++ b/src/core/api/main.ts @@ -132,7 +132,7 @@ export class ODMain { this.versions = new ODVersionManager_Default() this.versions.add(ODVersion.fromString("opendiscord:version","v4.1.0")) this.versions.add(ODVersion.fromString("opendiscord:api","v1.0.0")) - this.versions.add(ODVersion.fromString("opendiscord:transcripts","v2.0.0")) + this.versions.add(ODVersion.fromString("opendiscord:transcripts","v2.1.0")) this.versions.add(ODVersion.fromString("opendiscord:livestatus","v2.0.0")) this.debugfile = new ODDebugFileManager("./","otdebug.txt",5000,this.versions.get("opendiscord:version")) diff --git a/src/core/api/modules/stat.ts b/src/core/api/modules/stat.ts index 63ebcca..dccc1e6 100644 --- a/src/core/api/modules/stat.ts +++ b/src/core/api/modules/stat.ts @@ -140,6 +140,23 @@ export class ODStatScope extends ODManager { //return null on error return null } + /**Get the value of a statistic for all `scopeId`'s. The `scopeId` is the unique id of the user, channel, role, etc that the stats are related to. */ + async getAllStats(id:ODValidId): Promise<{id:string,value:ODValidStatValue}[]> { + if (!this.database) return [] + const newId = new ODId(id) + const data = await this.database.getCategory(this.id.value+"_"+newId.value) ?? [] + const output: {id:string,value:ODValidStatValue}[] = [] + + for (const stat of data){ + if (typeof stat.value == "string" || typeof stat.value == "boolean" || typeof stat.value == "number"){ + //return value received from database + output.push({id:stat.key,value:stat.value}) + } + } + + //return null on error + return output + } /**Set, increase or decrease the value of a statistic. The `scopeId` is the unique id of the user, channel, role, etc that the stats are related to. */ async setStat(id:ODValidId, scopeId:string, value:ODValidStatValue, mode:ODStatScopeSetMode): Promise { if (!this.database) return false @@ -213,6 +230,9 @@ export class ODStatGlobalScope extends ODStatScope { getStat(id:ODValidId): Promise { return super.getStat(id,"GLOBAL") } + getAllStats(id:ODValidId): Promise<{id:string,value:ODValidStatValue}[]> { + return super.getAllStats(id) + } setStat(id:ODValidId, value:ODValidStatValue, mode:ODStatScopeSetMode): Promise { return super.setStat(id,"GLOBAL",value,mode) } diff --git a/src/data/framework/statLoader.ts b/src/data/framework/statLoader.ts index 7f56020..50de840 100644 --- a/src/data/framework/statLoader.ts +++ b/src/data/framework/statLoader.ts @@ -10,6 +10,7 @@ export const loadAllStatScopes = async () => { stats.add(new api.ODStatScope("opendiscord:user",utilities.emojiTitle("📊",lang.getTranslation("stats.scopes.user")))) stats.add(new api.ODStatScope("opendiscord:ticket",utilities.emojiTitle("📊",lang.getTranslation("stats.scopes.ticket")))) stats.add(new api.ODStatScope("opendiscord:participants",utilities.emojiTitle("👥",lang.getTranslation("stats.scopes.participants")))) + stats.add(new api.ODStatScope("opendiscord:messages",utilities.emojiTitle("💬","Messages"))) //TODO TRANSLATION!!! } export const loadAllStats = async () => { @@ -18,24 +19,36 @@ export const loadAllStats = async () => { const global = stats.get("opendiscord:global") if (global){ - global.add(new api.ODBasicStat("opendiscord:tickets-created",10,lang.getTranslation("stats.properties.ticketsCreated"),0)) - global.add(new api.ODBasicStat("opendiscord:tickets-closed",9,lang.getTranslation("stats.properties.ticketsClosed"),0)) - global.add(new api.ODBasicStat("opendiscord:tickets-deleted",8,lang.getTranslation("stats.properties.ticketsDeleted"),0)) - global.add(new api.ODBasicStat("opendiscord:tickets-reopened",7,lang.getTranslation("stats.properties.ticketsReopened"),0)) - global.add(new api.ODBasicStat("opendiscord:tickets-autoclosed",6,lang.getTranslation("stats.properties.ticketsAutoclosed"),0)) - global.add(new api.ODBasicStat("opendiscord:tickets-autodeleted",5,"Tickets Autodeleted",0)) //TODO TRANSLATION!!! - global.add(new api.ODBasicStat("opendiscord:tickets-claimed",4,lang.getTranslation("stats.properties.ticketsClaimed"),0)) - global.add(new api.ODBasicStat("opendiscord:tickets-pinned",3,lang.getTranslation("stats.properties.ticketsPinned"),0)) - global.add(new api.ODBasicStat("opendiscord:tickets-moved",2,lang.getTranslation("stats.properties.ticketsMoved"),0)) - global.add(new api.ODBasicStat("opendiscord:users-blacklisted",1,lang.getTranslation("stats.properties.usersBlacklisted"),0)) - global.add(new api.ODBasicStat("opendiscord:transcripts-created",0,lang.getTranslation("stats.properties.transcriptsCreated"),0)) + global.add(new api.ODBasicStat("opendiscord:tickets-created",12,lang.getTranslation("stats.properties.ticketsCreated"),0)) + global.add(new api.ODBasicStat("opendiscord:tickets-closed",11,lang.getTranslation("stats.properties.ticketsClosed"),0)) + global.add(new api.ODBasicStat("opendiscord:tickets-deleted",10,lang.getTranslation("stats.properties.ticketsDeleted"),0)) + global.add(new api.ODBasicStat("opendiscord:tickets-reopened",9,lang.getTranslation("stats.properties.ticketsReopened"),0)) + global.add(new api.ODBasicStat("opendiscord:tickets-autoclosed",8,lang.getTranslation("stats.properties.ticketsAutoclosed"),0)) + global.add(new api.ODBasicStat("opendiscord:tickets-autodeleted",7,"Tickets Autodeleted",0)) //TODO TRANSLATION!!! + global.add(new api.ODBasicStat("opendiscord:tickets-claimed",6,lang.getTranslation("stats.properties.ticketsClaimed"),0)) + global.add(new api.ODBasicStat("opendiscord:tickets-pinned",5,lang.getTranslation("stats.properties.ticketsPinned"),0)) + global.add(new api.ODBasicStat("opendiscord:tickets-moved",4,lang.getTranslation("stats.properties.ticketsMoved"),0)) + global.add(new api.ODBasicStat("opendiscord:users-blacklisted",3,lang.getTranslation("stats.properties.usersBlacklisted"),0)) + global.add(new api.ODBasicStat("opendiscord:transcripts-created",2,lang.getTranslation("stats.properties.transcriptsCreated"),0)) + global.add(new api.ODDynamicStat("opendiscord:ticket-volume",1,() => { + return "Ticket Volume: `"+opendiscord.tickets.getLength()+"`" //TODO TRANSLATION!!! + })) + global.add(new api.ODDynamicStat("opendiscord:average-tickets",0,async () => { + const userTicketsCreated = await opendiscord.stats.get("opendiscord:user").getAllStats("opendiscord:tickets-created") + const average = userTicketsCreated.map((s) => s.value as number).filter((t) => t > 0).reduce((prev,curr) => prev+curr,0)/userTicketsCreated.length + const roundedAverage = Math.round(average*1000)/1000 + return "Average Tickets/User: `"+roundedAverage+"`" //TODO TRANSLATION!!! + })) } const system = stats.get("opendiscord:system") if (system){ - system.add(new api.ODDynamicStat("opendiscord:startup-date",1,() => { + system.add(new api.ODDynamicStat("opendiscord:startup-date",2,() => { return lang.getTranslation("params.uppercase.startupDate")+": "+discord.time(opendiscord.processStartupDate,"f") })) + system.add(new api.ODDynamicStat("opendiscord:system-uptime",1,() => { + return "System Uptime: "+discord.time(opendiscord.processStartupDate,"R") //TODO TRANSLATION!!! + })) system.add(new api.ODDynamicStat("opendiscord:version",0,() => { return lang.getTranslation("params.uppercase.version")+": `"+opendiscord.versions.get("opendiscord:version").toString()+"`" })) @@ -47,30 +60,29 @@ export const loadAllStats = async () => { return lang.getTranslation("params.uppercase.name")+": "+discord.userMention(scopeId) })) user.add(new api.ODDynamicStat("opendiscord:role",10,async (scopeId,guild,channel,user) => { - try{ - const scopeMember = await guild.members.fetch(scopeId) - if (!scopeMember) return "" + const scopeMember = await opendiscord.client.fetchGuildMember(guild,scopeId) + if (!scopeMember) return "" - const permissions = await opendiscord.permissions.getPermissions(scopeMember.user,channel,guild) - if (permissions.type == "developer") return lang.getTranslation("params.uppercase.role")+": 💻 `Developer`" //TODO TRANSLATION!!! - if (permissions.type == "owner") return lang.getTranslation("params.uppercase.role")+": 👑 `Server Owner`" //TODO TRANSLATION!!! - if (permissions.type == "admin") return lang.getTranslation("params.uppercase.role")+": 💼 `Server Admin`" //TODO TRANSLATION!!! - if (permissions.type == "moderator") return lang.getTranslation("params.uppercase.role")+": 🚔 `Moderator Team`" //TODO TRANSLATION!!! - if (permissions.type == "support") return lang.getTranslation("params.uppercase.role")+": 💬 `Support Team`" //TODO TRANSLATION!!! - else return lang.getTranslation("params.uppercase.role")+": 👤 `Member`" //TODO TRANSLATION!!! - }catch{ - return "" - } + const permissions = await opendiscord.permissions.getPermissions(scopeMember.user,channel,guild) + if (permissions.type == "developer") return lang.getTranslation("params.uppercase.role")+": 💻 `Developer`" //TODO TRANSLATION!!! + if (permissions.type == "owner") return lang.getTranslation("params.uppercase.role")+": 👑 `Server Owner`" //TODO TRANSLATION!!! + if (permissions.type == "admin") return lang.getTranslation("params.uppercase.role")+": 💼 `Server Admin`" //TODO TRANSLATION!!! + if (permissions.type == "moderator") return lang.getTranslation("params.uppercase.role")+": 🚔 `Moderator Team`" //TODO TRANSLATION!!! + if (permissions.type == "support") return lang.getTranslation("params.uppercase.role")+": 💬 `Support Team`" //TODO TRANSLATION!!! + else return lang.getTranslation("params.uppercase.role")+": 👤 `Member`" //TODO TRANSLATION!!! + })) + user.add(new api.ODBasicStat("opendiscord:tickets-created",9,lang.getTranslation("stats.properties.ticketsCreated"),0)) + user.add(new api.ODBasicStat("opendiscord:tickets-closed",8,lang.getTranslation("stats.properties.ticketsClosed"),0)) + user.add(new api.ODBasicStat("opendiscord:tickets-deleted",7,lang.getTranslation("stats.properties.ticketsDeleted"),0)) + user.add(new api.ODBasicStat("opendiscord:tickets-reopened",6,lang.getTranslation("stats.properties.ticketsReopened"),0)) + user.add(new api.ODBasicStat("opendiscord:tickets-claimed",5,lang.getTranslation("stats.properties.ticketsClaimed"),0)) + user.add(new api.ODBasicStat("opendiscord:tickets-pinned",4,lang.getTranslation("stats.properties.ticketsPinned"),0)) + user.add(new api.ODBasicStat("opendiscord:tickets-moved",3,lang.getTranslation("stats.properties.ticketsMoved"),0)) + user.add(new api.ODBasicStat("opendiscord:users-blacklisted",2,lang.getTranslation("stats.properties.usersBlacklisted"),0)) + user.add(new api.ODBasicStat("opendiscord:transcripts-created",1,lang.getTranslation("stats.properties.transcriptsCreated"),0)) + user.add(new api.ODDynamicStat("opendiscord:current-tickets",0,async (scopeId,guild,channel,user) => { + return "Current Tickets: `"+opendiscord.tickets.getFiltered((t) => t.get("opendiscord:opened-by").value === scopeId).length+"`" //TODO TRANSLATION!!! })) - user.add(new api.ODBasicStat("opendiscord:tickets-created",8,lang.getTranslation("stats.properties.ticketsCreated"),0)) - user.add(new api.ODBasicStat("opendiscord:tickets-closed",7,lang.getTranslation("stats.properties.ticketsClosed"),0)) - user.add(new api.ODBasicStat("opendiscord:tickets-deleted",6,lang.getTranslation("stats.properties.ticketsDeleted"),0)) - user.add(new api.ODBasicStat("opendiscord:tickets-reopened",5,lang.getTranslation("stats.properties.ticketsReopened"),0)) - user.add(new api.ODBasicStat("opendiscord:tickets-claimed",4,lang.getTranslation("stats.properties.ticketsClaimed"),0)) - user.add(new api.ODBasicStat("opendiscord:tickets-pinned",3,lang.getTranslation("stats.properties.ticketsPinned"),0)) - user.add(new api.ODBasicStat("opendiscord:tickets-moved",2,lang.getTranslation("stats.properties.ticketsMoved"),0)) - user.add(new api.ODBasicStat("opendiscord:users-blacklisted",1,lang.getTranslation("stats.properties.usersBlacklisted"),0)) - user.add(new api.ODBasicStat("opendiscord:transcripts-created",0,lang.getTranslation("stats.properties.transcriptsCreated"),0)) } const ticket = stats.get("opendiscord:ticket") @@ -114,6 +126,15 @@ export const loadAllStats = async () => { const creator = ticket.get("opendiscord:opened-by").value return lang.getTranslation("params.uppercase.creator")+": "+ (creator ? discord.userMention(creator) : "`unknown`") })) + ticket.add(new api.ODDynamicStat("opendiscord:ticket-age",1,async (scopeId,guild,channel,user) => { + const ticket = opendiscord.tickets.get(scopeId) + if (!ticket) return "" + + const rawDate = ticket.get("opendiscord:opened-on").value ?? new Date().getTime() + return "Ticket Age: "+discord.time(new Date(rawDate),"R") //TODO TRANSLATION!!! + })) + //TODO: opendiscord:response-time //TODO TRANSLATION!!! + //TODO: opendiscord:resolution-time //TODO TRANSLATION!!! } const participants = stats.get("opendiscord:participants") @@ -130,4 +151,37 @@ export const loadAllStats = async () => { })) } + + const messages = stats.get("opendiscord:messages") + if (messages){ + messages.add(new api.ODDynamicStat("opendiscord:count",0,async (scopeId,guild,channel,user) => { + const ticket = opendiscord.tickets.get(scopeId) + if (!ticket) return "" + + const messages = await opendiscord.transcripts.collector.collectAllMessages(ticket,{bots:true,client:true,users:true}) + if (!messages) return "" + const parsedMessages = await opendiscord.transcripts.collector.convertMessagesToTranscriptData(messages) + + let messageCount = parsedMessages.length + let embedCount = 0 + let fileCount = 0 + let componentCount = 0 + + for (const msg of parsedMessages){ + embedCount += msg.embeds.length + fileCount += msg.files.length + for (const row of msg.components){ + componentCount += row.components.length + } + } + + return [ + "Messages: `"+messageCount+"`", //TODO TRANSLATION!!! + "Embeds: `"+embedCount+"`", //TODO TRANSLATION!!! + "Files: `"+fileCount+"`", //TODO TRANSLATION!!! + "Components: `"+componentCount+"`" //TODO TRANSLATION!!! + ].join("\n") + })) + + } } \ No newline at end of file