From 726861294b367ecc52b5956d179cf8588f2a10a1 Mon Sep 17 00:00:00 2001 From: derpystuff <3515180-derpystuff@users.noreply.gitlab.com> Date: Mon, 23 May 2022 23:14:57 +0200 Subject: [PATCH] a lot of thingssss --- commands/message/core/help.js | 84 ++++++++++++++++++++++-- commands/message/core/undo.js | 53 +++++++++++++++ commands/message/dev/debug/attachment.js | 28 ++++++++ commands/message/dev/debug/test.js | 18 ++++- commands/message/fun/inferkit.js | 36 ++++++++++ commands/message/info/avatar.js | 25 +++++++ commands/message/mod/purge.js | 76 +++++++++++++++++++++ labscore/api/endpoints.js | 4 +- labscore/api/index.js | 6 ++ labscore/client.js | 10 +-- labscore/constants.js | 12 ++-- labscore/utils/attachment.js | 57 ++++++++++++++++ labscore/utils/statics.js | 7 +- labscore/utils/users.js | 28 ++++++++ 14 files changed, 420 insertions(+), 24 deletions(-) create mode 100644 commands/message/core/undo.js create mode 100644 commands/message/dev/debug/attachment.js create mode 100644 commands/message/fun/inferkit.js create mode 100644 commands/message/info/avatar.js create mode 100644 commands/message/mod/purge.js create mode 100644 labscore/utils/attachment.js create mode 100644 labscore/utils/users.js diff --git a/commands/message/core/help.js b/commands/message/core/help.js index 5ed075a..2fd18ed 100644 --- a/commands/message/core/help.js +++ b/commands/message/core/help.js @@ -1,7 +1,10 @@ -const { codeblock, highlight, icon } = require('../../../labscore/utils/markdown') +const { codeblock, highlight, icon, link } = require('../../../labscore/utils/markdown') const { createEmbed, formatPaginationEmbeds } = require('../../../labscore/utils/embed') +const { DISCORD_INVITE } = require('../../../labscore/constants') + const { paginator } = require('../../../labscore/client'); +const { editOrReply } = require('../../../labscore/utils/message'); function createHelpPage(context, title, contents){ return { @@ -15,13 +18,44 @@ function createHelpPage(context, title, contents){ } } +function createCommandPage(context, prefix, command){ + let page = createEmbed("default", context, { + description: `**${prefix}${command.name}**\n${command.metadata.description}`, + fields: [] + }) + if(command.aliases.length >= 1) page.fields.push({ + name: `${icon("activity")} Aliases`, + value: command.aliases.join(', '), + inline: true + }) + if(command.metadata.usage) page.fields.push({ + name: `${icon("util")} Usage`, + value: codeblock("ansi", [prefix + command.metadata.usage]), + inline: true + }) + if(command.metadata.examples){ + let ex = [] + for(const e of command.metadata.examples) ex.push(prefix + e) + page.fields.push({ + name: `${icon("info")} Examples`, + value: codeblock("ansi", ex), + inline: false + }) + } + return { + embeds: [page] + }; +} + // These categories will be displayed to users, add them in the correct order const categories = { "core": `${icon("house")} Core Commands`, - "search": `${icon("search")} Search Commands`, - "dev": `${icon("analytics")} Development` + "info": `${icon("info")} Information Commands`, + "mod": `${icon("moderation")} Moderation Commands`, + "search": `${icon("search")} Search Commands` } + module.exports = { name: 'help', label: 'command', @@ -33,12 +67,50 @@ module.exports = { }, run: async (context, args) => { context.triggerTyping(); - if(args.label){ + if(args.command){ // Detailed command view + let results = [] + + for(const c of context.commandClient.commands){ + if(c.name.includes(args.command) || c.aliases.filter((f)=>{return f.includes(args.command)}).length >= 1) results.push(c) + } + + let pages = [] + let prefix = context.commandClient.prefixes.custom.first() + try{ + + if(results.length == 0) return editOrReply(context, {embeds: [createEmbed("warning", context, "No commands found for the provided query.")]}) + + if(results.length > 1) { + // Command overview + pages.push({embeds:[ + createEmbed("default", context, { + description: `Check pages for detailed command descriptions.\n` + codeblock("ansi", [(prefix + results.map((m)=>{return m.name}).splice(0, 10).join('\n' + prefix))]) + `\n${icon("question")} Need help with something else? Contact us via our ${link(DISCORD_INVITE, "Support Server")}.` + }) + ]}) + + // Generate command detail pages + for(const c of results){ + pages.push(createCommandPage(context, prefix, c)) + } + + pages = formatPaginationEmbeds(pages) + const message = context.message + const paging = await paginator.createPaginator({ + message, + pages + }); + return; + } else { + return editOrReply(context, createCommandPage(context, prefix, results[0])) + } + }catch(e){ + console.log(e) + } } else { // Full command list - let commands = { - } + let commands = {} + let prefix = context.commandClient.prefixes.custom.first() for(const c of context.commandClient.commands){ if(!categories[c.metadata.category]) continue; diff --git a/commands/message/core/undo.js b/commands/message/core/undo.js new file mode 100644 index 0000000..70b160e --- /dev/null +++ b/commands/message/core/undo.js @@ -0,0 +1,53 @@ +const { format } = require('../../../labscore/utils/ansi') +const { codeblock, icon, highlight } = require('../../../labscore/utils/markdown') +const { createEmbed } = require('../../../labscore/utils/embed') +const { editOrReply } = require('../../../labscore/utils/message') + +module.exports = { + name: 'undo', + default: 1, + label: 'amount', + metadata: { + description: 'undo your last bot command(s)', + examples: ['undo 5'], + category: 'core', + usage: 'undo []' + }, + run: async (context, args) => { + try{ + context.triggerTyping(); + if(typeof(args.amount) == "string") args.amount = parseInt(args.amount) + if(!args.amount) args.amount = 1 + if(args.amount >= 6 || args.amount <= 0) return await editOrReply(context, {embeds:[createEmbed("warning", context, "Invalid Argument (amount)")]}) + let cmds = []; + let found = 0; + for(const c of context.commandClient.replies.toArray().reverse()){ + if(found > args.amount) break; + if (c.context.channelId !== context.channelId || c.context.userId !== context.userId) continue; + if (c.context.message.canDelete) cmds.push(c.context.message.id) + if (c.reply.canDelete && !c.reply.deleted) { + cmds.push(c.reply.id); + found++; + } + } + if (cmds.length == 1 || !context.canManage) { + for (let id of cmds) { + await context.channel.deleteMessage(id); + } + } else { + await context.channel.bulkDelete(cmds); + } + if(context.canManage) await context.message.delete() + let resp = await editOrReply(context, { + "content": `${icon("success_simple")} Deleted ${highlight(found)} command replies.` + }) + + console.log(resp) + setTimeout(async () => { + await context.channel.deleteMessage(resp.id) + }, 5000) + }catch(e){ + console.log(e) + } + }, +}; \ No newline at end of file diff --git a/commands/message/dev/debug/attachment.js b/commands/message/dev/debug/attachment.js new file mode 100644 index 0000000..78823a7 --- /dev/null +++ b/commands/message/dev/debug/attachment.js @@ -0,0 +1,28 @@ +const { getRecentImage } = require("../../../../labscore/utils/attachment"); +const { createEmbed } = require("../../../../labscore/utils/embed"); +const { editOrReply } = require("../../../../labscore/utils/message"); + +module.exports = { + name: 'attachment', + metadata: { + description: 'test', + examples: ['attachment'], + category: 'dev', + usage: 'attachment' + }, + run: async (context) => { + try{ + + let image = await getRecentImage(context, 50) + console.log(image) + if(!image) return editOrReply(context, { embeds: [createEmbed("warning", context, "No images found.")] }) + return editOrReply(context, { embeds: [createEmbed("default", context, { + image: { + url: image + } + })] }) + }catch(e){ + console.log(e) + } + }, +}; \ No newline at end of file diff --git a/commands/message/dev/debug/test.js b/commands/message/dev/debug/test.js index 2904c59..0c5ee59 100644 --- a/commands/message/dev/debug/test.js +++ b/commands/message/dev/debug/test.js @@ -1,14 +1,26 @@ - +const { createEmbed } = require("../../../../labscore/utils/embed"); +const { editOrReply } = require("../../../../labscore/utils/message"); +const { getUser } = require("../../../../labscore/utils/users"); module.exports = { name: 'test', + label: 'input', metadata: { description: 'test', examples: ['test'], category: 'dev', usage: 'test' }, - run: async (context) => { - return context.editOrReply('test successful.') + run: async (context, args) => { + try{ + + let u = await getUser(context, args.input) + if(!u) return editOrReply(context, { embeds: [createEmbed("warning", context, "No users found.")] }) + return editOrReply(context, { embeds: [createEmbed("default", context, { + description: u.mention + })] }) + }catch(e){ + console.log(e) + } }, }; \ No newline at end of file diff --git a/commands/message/fun/inferkit.js b/commands/message/fun/inferkit.js new file mode 100644 index 0000000..80eb76e --- /dev/null +++ b/commands/message/fun/inferkit.js @@ -0,0 +1,36 @@ +const { createEmbed } = require('../../../labscore/utils/embed') +const { format } = require('../../../labscore/utils/ansi') +const { editOrReply } = require('../../../labscore/utils/message') +const { STATICS } = require('../../../labscore/utils/statics') + +const { inferkit } = require('../../../labscore/api') +const { codeblock } = require('../../../labscore/utils/markdown') + +module.exports = { + name: 'inferkit', + aliases: ['complete'], + label: 'text', + metadata: { + description: 'make ai continue your text', + examples: ['complete The Fitness Gram Pacer'], + category: 'fun', + usage: 'inferkit ' + }, + run: async (context, args) => { + context.triggerTyping(); + if(!args.text) return editOrReply(context, {embeds:[createEmbed("warning", context, `Missing Parameter (text).`)]}) + try{ + let res = await inferkit(context, args.text) + return editOrReply(context, {embeds:[createEmbed("default", context, { + description: codeblock("ansi", [format(res.response.body.input, "cyan") + res.response.body.output]), + footer: { + iconUrl: STATICS.inferkit, + text: `InferKit • ${context.application.name} • Took ${res.timings}s` + } + })]}) + }catch(e){ + console.log(e) + return editOrReply(context, {embeds:[createEmbed("error", context, `Unable to generate text.`)]}) + } + } +}; \ No newline at end of file diff --git a/commands/message/info/avatar.js b/commands/message/info/avatar.js new file mode 100644 index 0000000..1b71430 --- /dev/null +++ b/commands/message/info/avatar.js @@ -0,0 +1,25 @@ +const { createEmbed } = require("../../../labscore/utils/embed"); +const { editOrReply } = require("../../../labscore/utils/message"); +const { getUser } = require("../../../labscore/utils/users"); + +module.exports = { + name: 'avatar', + label: 'user', + aliases: ['a'], + metadata: { + description: 'avatar', + examples: ['avatar labsCore'], + category: 'info', + usage: 'avatar []' + }, + run: async (context, args) => { + let u; + if(!args.user) { u = context.user } else { u = await getUser(context, args.user) } + if(!u) return editOrReply(context, { embeds: [createEmbed("warning", context, "No users found.")] }) + return editOrReply(context, { embeds: [createEmbed("default", context, { + image: { + url: u.avatarUrl + '?size=4096' + } + })] }) + }, +}; \ No newline at end of file diff --git a/commands/message/mod/purge.js b/commands/message/mod/purge.js new file mode 100644 index 0000000..329a940 --- /dev/null +++ b/commands/message/mod/purge.js @@ -0,0 +1,76 @@ +const { Constants } = require("detritus-client"); +const { icon } = require("../../../labscore/utils/markdown"); +const Permissions = Constants.Permissions; + +// TODO: copy pasted from v1, rework this eventually + +module.exports = { + label: "filter", + name: "purge", + metadata: { + description: 'Removes recent messages in chat. Allows you to optionally filter by message content to remove spam.\n\n`-amount` allows you to specify how many messages should be searched (default: 20)\n`-case` specifies if the provided query should be case sensitive or not (default: true)', + examples: ['purge Spam -amount 25'], + category: 'mod', + usage: 'purge [] [-amount <1-50>] [-case ]' + }, + args: [ + {default: 20, name: 'amount', type: 'integer'}, + {default: true, name: 'case', type: 'bool'}, + ], + permissionsClient: [Permissions.MANAGE_MESSAGES], + permissions: [Permissions.MANAGE_MESSAGES], + onPermissionsFailClient: (context) => context.editOrReply(`${icon("failiure_simple")} ${context.message.author.mention}, the bot needs the \`Manage Messages\` permission to run this command.`), + onPermissionsFail: (context) => context.editOrReply(`${icon("failiure_simple")} ${context.message.author.mention}, you are lacking the permission \`Manage Messages\`.`), + ratelimit: { + type: 'guild', + limit: 1, + duration: 5000 + }, + permissionsClient: [Permissions.MANAGE_MESSAGES], + run: async (context, args) => { + await context.triggerTyping(); + if(args.amount >= 51 || args.amount <= 0){ + return context.editOrReply(`${icon("failiure_simple")} ${context.message.author.mention}, Invalid amount (1-50).`); + } + const messages = await context.message.channel.fetchMessages({limit: args.amount}); + let deleteIds = [] + messages.forEach(message => { + if(args.filter.length >= 1){ + if(message.canDelete){ + if(args.case == false){ + if(message.content.toLowerCase().includes(args.filter.toLowerCase())){ + deleteIds.push(message.id) + } + } else { + if(message.content.includes(args.filter)){ + deleteIds.push(message.id) + } + } + } + } else { + if(message.canDelete){ + deleteIds.push(message.id) + } + } + }) + + if(deleteIds.length == 0){ + return context.editOrReply(`${icon("failiure_simple")} No messages found.`); + } + if(deleteIds.length == 1){ + try{ + await context.client.rest.deleteMessage(context.channel.id, deleteIds[0]) + return context.editOrReply(`${icon("success_simple")} Removed \`1\` message.`); + }catch(e){ + await context.editOrReply(`${icon("failiure_simple")} Something went wrong while attempting to remove \`1\` message.`); + } + } else { + try{ + await context.client.rest.bulkDeleteMessages(context.channel.id, deleteIds) + return context.editOrReply(`${icon("success_simple")} Removed \`${deleteIds.length}\` messages.`); + }catch(e){ + await context.editOrReply(`${icon("failiure_simple")} Something went wrong while attempting to remove \`${deleteIds.length}\` messages.`); + } + } + } +}; \ No newline at end of file diff --git a/labscore/api/endpoints.js b/labscore/api/endpoints.js index 08553d1..a8d0613 100644 --- a/labscore/api/endpoints.js +++ b/labscore/api/endpoints.js @@ -16,7 +16,9 @@ const Api = Object.freeze({ SEARCH_BING_IMAGES: '/search/bing-images', SEARCH_WOLFRAM_ALPHA: '/search/wolfram-alpha', - PHOTOFUNIA_YACHT: '/photofunia/yacht' + PHOTOFUNIA_YACHT: '/photofunia/yacht', + + INFERKIT: '/inferkit', }) const Static = Object.freeze({ diff --git a/labscore/api/index.js b/labscore/api/index.js index e77c9c9..c21fab2 100644 --- a/labscore/api/index.js +++ b/labscore/api/index.js @@ -82,6 +82,12 @@ module.exports.yacht = async function(context, text){ }) } +module.exports.inferkit = async function(context, input){ + return await request(Api.INFERKIT, "GET", {}, { + input: input + }) +} + module.exports.emojiTwitter = async function(codepoint){ return Static.HOST + Static.TWITTER(codepoint) } \ No newline at end of file diff --git a/labscore/client.js b/labscore/client.js index 03367a9..18c7213 100644 --- a/labscore/client.js +++ b/labscore/client.js @@ -41,11 +41,11 @@ const paginator = new Paginator(cluster, { await commandClient.addMultipleIn('../commands/message/'); await commandClient.run() - commandClient.on('commandDelete', async ({reply}) => { - if (reply){ - reply.delete(); - } - }); + //commandClient.on('commandDelete', async ({reply}) => { + // if (reply){ + // reply.delete(); + // } + //}); })(); diff --git a/labscore/constants.js b/labscore/constants.js index 3bcca64..73c9092 100644 --- a/labscore/constants.js +++ b/labscore/constants.js @@ -1,4 +1,4 @@ -const COLORS = Object.freeze({ +module.exports.COLORS = Object.freeze({ "error": 15548997, "success": 6411359, "warning": 16426522, @@ -6,7 +6,7 @@ const COLORS = Object.freeze({ "brand": 6085465 }) -const ICONS = Object.freeze({ +module.exports.ICONS = Object.freeze({ "error": "<:ico_error:925832574239121429>", "warning": "<:ico_warning:925832574931189830>", "success": "<:ico_check:925813919929491516>", @@ -52,7 +52,7 @@ const ICONS = Object.freeze({ "question": "<:ico_question:949420315677691934>" }) -const WEB_ASSETS = Object.freeze({ +module.exports.WEB_ASSETS = Object.freeze({ "brands": { "genius": "357a0d4aaf1cedfa41dfb38bf3acb961", "labscore": "042e4a437e14580ee2fda8be217991d6" @@ -60,8 +60,4 @@ const WEB_ASSETS = Object.freeze({ "weather": "aab92e69374e4c7b8c6741fe02e574b9" }) -module.exports = { - COLORS, - ICONS, - WEB_ASSETS -} \ No newline at end of file +module.exports.DISCORD_INVITE = `https://discord.gg/8c4p6xcjru` \ No newline at end of file diff --git a/labscore/utils/attachment.js b/labscore/utils/attachment.js new file mode 100644 index 0000000..d8981c9 --- /dev/null +++ b/labscore/utils/attachment.js @@ -0,0 +1,57 @@ + + +const attachmentTypes = Object.freeze({ + image: ["image/png", "image/jpeg", "image/gif"] +}) + +async function getRecentMedia(context, limit){ + if (!context.message.channel) { + return undefined; + } else if (context.message.attachments.length > 0) { + return context.message.attachments.first(); + } + const messages = await context.message.channel.fetchMessages({ + limit + }); + + if (!messages) { + return undefined; + } + + let attachments = []; + for(const m of messages){ + let message = m[1] + if ( // First the attachment on the message + message.attachments.first() + ) { attachments.push(message.attachments.first()) + } else if ( // Then the embed image + message.embeds.length > 0 && + message.embeds.toArray()[0].image + ) { attachments.push(message.embeds.toArray()[0].image) + } else if ( + message.embeds.length > 0 && + message.embeds.toArray()[0].thumbnail + ) { attachments.push(message.embeds.toArray()[0].thumbnail) } + } + return attachments; +} + +// simple helpers + +async function getRecentImage(context, limit){ + let attachments = await getRecentMedia(context, limit) + let at; + let validImages = attachmentTypes.image + for(const a of attachments){ + if(a.contentType && validImages.includes(a.contentType) && at === undefined){ // discord attachment + at = a.url + } else if (!a.content_type && at === undefined){ // other form of media + at = a.url + } + } + return at; +} + +module.exports = { + getRecentImage +} \ No newline at end of file diff --git a/labscore/utils/statics.js b/labscore/utils/statics.js index b6e17f7..bc0e14b 100644 --- a/labscore/utils/statics.js +++ b/labscore/utils/statics.js @@ -21,6 +21,10 @@ const Statics = Object.freeze({ wolframalpha: { file: "brands/wolframalpha.png", revision: 0 + }, + inferkit: { + file: "brands/inferkit.png", + revision: 0 } } }) @@ -34,5 +38,6 @@ module.exports.STATICS = Object.freeze({ genius: staticAsset(Statics.brands.genius), bing: staticAsset(Statics.brands.bing), google: staticAsset(Statics.brands.google), - wolframalpha: staticAsset(Statics.brands.wolframalpha) + wolframalpha: staticAsset(Statics.brands.wolframalpha), + inferkit: staticAsset(Statics.brands.inferkit) }) \ No newline at end of file diff --git a/labscore/utils/users.js b/labscore/utils/users.js new file mode 100644 index 0000000..e59dcf2 --- /dev/null +++ b/labscore/utils/users.js @@ -0,0 +1,28 @@ +async function getUser(context, query){ + let user; + if(/[0-9]{18}/.test(query)){ // User ID supplied, use that + let uid = query.match(/[0-9]{18}/) + try{ + user = await context.client.rest.fetchUser(uid) + } catch(e){ + user = undefined + } + } else { + user = await getMember(context, query) + if(user) user = user.user + } + return user; +} + +async function getMember(context, query){ + if(!context.guild) return; + let members = await context.guild.fetchMembersSearch({ query }) + console.log(members) + if(members) return members.first() + return; +} + +module.exports = { + getUser, + getMember +} \ No newline at end of file