From 118d6cf647b4fce975e9a539210f353e015f85b7 Mon Sep 17 00:00:00 2001 From: WubzyGD Date: Thu, 8 Oct 2020 09:01:21 -0600 Subject: [PATCH 1/6] tag and tagfilter classes; added TS support in /util --- events/message.js | 2 +- util/tag.d.ts | 9 ++++++++ util/tag.js | 21 +++++++++++++++++++ util/tagfilter.d.ts | 10 +++++++++ util/tagfilter.js | 49 +++++++++++++++++++++++++++++++++++++++++++ util/test.js | 19 +++++++++++++++++ util/ts/tag.ts | 25 ++++++++++++++++++++++ util/ts/tagfilter.ts | 45 +++++++++++++++++++++++++++++++++++++++ util/ts/tsconfig.json | 11 ++++++++++ 9 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 util/tag.d.ts create mode 100644 util/tag.js create mode 100644 util/tagfilter.d.ts create mode 100644 util/tagfilter.js create mode 100644 util/test.js create mode 100644 util/ts/tag.ts create mode 100644 util/ts/tagfilter.ts create mode 100644 util/ts/tsconfig.json diff --git a/events/message.js b/events/message.js index d5e7eb2..71b4e07 100644 --- a/events/message.js +++ b/events/message.js @@ -16,7 +16,7 @@ module.exports = async (client, message) => { var msg = message.content.toLowerCase(); var mention = message.mentions.users.first(); var args = msg.startsWith(prefix) - ? message.content.slice(prefix.length).trim().split(/\s+/g) + ? message.content.slice(prefix.length).trim().split(/\s+/g) : msg.startsWith('<@!') ? message.content.slice(4 + client.user.id.length).trim().split(/\s+/g) : message.content.slice(3 + client.user.id.length).trim().split(/\s+/g); diff --git a/util/tag.d.ts b/util/tag.d.ts new file mode 100644 index 0000000..4421210 --- /dev/null +++ b/util/tag.d.ts @@ -0,0 +1,9 @@ +export declare class Tag { + triggers: string[]; + tagName: string; + filterType: TagFilterType; + constructor(triggers: string[], tagName: string, filterType: TagFilterType); + addTrigger(trigger: string): Tag; +} +declare type TagFilterType = "append" | "toggle"; +export {}; diff --git a/util/tag.js b/util/tag.js new file mode 100644 index 0000000..2a012a9 --- /dev/null +++ b/util/tag.js @@ -0,0 +1,21 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Tag = void 0; +class Tag { + constructor(triggers, tagName, filterType) { + this.triggers = []; + let trigger; + for (trigger of triggers) { + this.triggers.push(trigger.trim().startsWith("-") ? trigger.trim() : `-${trigger.trim()}`); + } + this.tagName = tagName; + this.filterType = filterType; + } + ; + addTrigger(trigger) { + this.triggers.push(trigger.trim().startsWith("-") ? trigger.trim() : `-${trigger.trim()}`); + return this; + } + ; +} +exports.Tag = Tag; diff --git a/util/tagfilter.d.ts b/util/tagfilter.d.ts new file mode 100644 index 0000000..0da5548 --- /dev/null +++ b/util/tagfilter.d.ts @@ -0,0 +1,10 @@ +import { Tag } from "./tag"; +export declare class TagFilter { + tags: Tag[]; + triggers: Map; + filterTypes: Map; + constructor(tags: Tag[]); + test(text: string): object; +} +declare type TagFilterType = "append" | "toggle"; +export {}; diff --git a/util/tagfilter.js b/util/tagfilter.js new file mode 100644 index 0000000..ed77f12 --- /dev/null +++ b/util/tagfilter.js @@ -0,0 +1,49 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.TagFilter = void 0; +class TagFilter { + constructor(tags) { + this.tags = tags; + this.triggers = new Map(); + this.filterTypes = new Map(); + let tag; + for (tag of this.tags) { + let trigger; + for (trigger of tag.triggers) { + this.triggers.set(trigger, tag.tagName); + } + if (!this.filterTypes.has(tag.tagName)) { + this.filterTypes.set(tag.tagName, tag.filterType); + } + } + } + test(text) { + var filtered = {}; + var reading = null; + let words = text.trim().split(/\s+/g); + let word; + for (word of words) { + if (word.startsWith('-') && word.length > 1 && this.triggers.has(word.trim())) { + reading = this.filterTypes.get(this.triggers.get(word.trim())) == "toggle" ? null : word.trim(); + if (!reading) { + filtered[`${this.triggers.get(word.trim())}`] = true; + } + else { + filtered[`${this.triggers.get(reading)}`] = ''; + } + } + else if (reading) { + filtered[`${this.triggers.get(reading)}`] = `${filtered[`${this.triggers.get(reading)}`]} ${word}`; + } + } + let key; + for (key of Object.keys(filtered)) { + if (typeof filtered[key] == 'string') { + filtered[key] = filtered[key].trim(); + } + } + return filtered; + } + ; +} +exports.TagFilter = TagFilter; diff --git a/util/test.js b/util/test.js new file mode 100644 index 0000000..6013ce5 --- /dev/null +++ b/util/test.js @@ -0,0 +1,19 @@ +const {Tag} = require('./tag'); +const {TagFilter} = require('./tagfilter'); + +let myATag = new Tag(["-name", "-n"], "name", "append"); +let myTTag = new Tag(["force"], "force", "toggle"); +myTTag.addTrigger('f'); + +console.log(myATag); +console.log(myTTag); + +let myFilter = new TagFilter([myATag, myTTag]); +console.log(myFilter); +console.log(myFilter.test("create -n jacob clark -f")); + +console.log(new TagFilter([ + new Tag(['-reason', '-r'], 'reason', 'append'), + new Tag(['-against', '-a'], 'against', 'append'), + new Tag(['-force', '-f'], 'force', 'toggle') +]).test('d6 d6 d10 -r to suffer -against myself -f')); \ No newline at end of file diff --git a/util/ts/tag.ts b/util/ts/tag.ts new file mode 100644 index 0000000..86c7ce2 --- /dev/null +++ b/util/ts/tag.ts @@ -0,0 +1,25 @@ +export class Tag { + triggers: string[] = []; + tagName: string; + filterType: TagFilterType; + + constructor(triggers: string[], tagName: string, filterType: TagFilterType) { + let trigger: string; for (trigger of triggers) { + this.triggers.push( + trigger.trim().startsWith("-") ? trigger.trim() : `-${trigger.trim()}` + ); + } + + this.tagName = tagName; + this.filterType = filterType; + }; + + public addTrigger(trigger: string): Tag { + this.triggers.push( + trigger.trim().startsWith("-") ? trigger.trim() : `-${trigger.trim()}` + ); + return this; + }; +} + +type TagFilterType = "append" | "toggle"; \ No newline at end of file diff --git a/util/ts/tagfilter.ts b/util/ts/tagfilter.ts new file mode 100644 index 0000000..fcf04f7 --- /dev/null +++ b/util/ts/tagfilter.ts @@ -0,0 +1,45 @@ +import {Tag} from "./tag"; + +export class TagFilter { + tags: Tag[]; + triggers: Map; + filterTypes: Map; + + constructor(tags: Tag[]) { + this.tags = tags; + this.triggers = new Map(); + this.filterTypes = new Map(); + let tag: Tag; + for (tag of this.tags) { + let trigger: string; for (trigger of tag.triggers) { + this.triggers.set(trigger, tag.tagName); + } + if (!this.filterTypes.has(tag.tagName)) {this.filterTypes.set(tag.tagName, tag.filterType);} + } + } + + public test(text: string): object { + var filtered: object = {}; + var reading: string = null; + + let words = text.trim().split(/\s+/g); + let word: string; for (word of words) { + if (word.startsWith('-') && word.length > 1 && this.triggers.has(word.trim())) { + reading = this.filterTypes.get(this.triggers.get(word.trim())) == "toggle" ? null : word.trim(); + if (!reading) {filtered[`${this.triggers.get(word.trim())}`] = true;} + else {filtered[`${this.triggers.get(reading)}`] = '';} + } + else if (reading) { + filtered[`${this.triggers.get(reading)}`] = `${filtered[`${this.triggers.get(reading)}`]} ${word}`; + } + } + + let key: string; for (key of Object.keys(filtered)) { + if (typeof filtered[key] == 'string') {filtered[key] = filtered[key].trim();} + } + + return filtered; + }; +} + +type TagFilterType = "append" | "toggle"; \ No newline at end of file diff --git a/util/ts/tsconfig.json b/util/ts/tsconfig.json new file mode 100644 index 0000000..990d7fa --- /dev/null +++ b/util/ts/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "module": "commonjs", + "lib": ["es2017", "es6", "dom"], + "target": "es2017", + "declaration": true, + "outDir": "../" + }, + "include": ["**/*"], + "exclude": [] +} \ No newline at end of file From 82d83a38eb2a83ba35e2b7b644d51a9ff72806a1 Mon Sep 17 00:00:00 2001 From: WubzyGD Date: Thu, 8 Oct 2020 10:14:09 -0600 Subject: [PATCH 2/6] Deathnote custom message, tags implementation --- commands/deathnote.js | 5 +++++ util/test.js | 19 ------------------- 2 files changed, 5 insertions(+), 19 deletions(-) delete mode 100644 util/test.js diff --git a/commands/deathnote.js b/commands/deathnote.js index fd79366..fba65e8 100644 --- a/commands/deathnote.js +++ b/commands/deathnote.js @@ -1,5 +1,7 @@ const Discord = require('discord.js'); const moment = require('moment'); +const {Tag} = require('../util/tag'); +const {TagFilter} = require('../util/tagfilter'); const deaths = [ "watching too much anime", "an overdose of waifus", "Hypotakunemia", "trying to self-isekai", @@ -66,6 +68,9 @@ module.exports = { let title = reptype.titles[Math.floor(Math.random() * reptype.titles.length)]; let pretext = before[Math.floor(Math.random() * before.length)]; + let options = new TagFilter([new Tag(['method', '-m', 'cause', '-c'], 'method', 'append')]).test(args.splice(0, 1).join(" ")); + if (options.method.length) {death = options.method;} + let victim = message.mentions.members.first(); let killer = message.member; diff --git a/util/test.js b/util/test.js deleted file mode 100644 index 6013ce5..0000000 --- a/util/test.js +++ /dev/null @@ -1,19 +0,0 @@ -const {Tag} = require('./tag'); -const {TagFilter} = require('./tagfilter'); - -let myATag = new Tag(["-name", "-n"], "name", "append"); -let myTTag = new Tag(["force"], "force", "toggle"); -myTTag.addTrigger('f'); - -console.log(myATag); -console.log(myTTag); - -let myFilter = new TagFilter([myATag, myTTag]); -console.log(myFilter); -console.log(myFilter.test("create -n jacob clark -f")); - -console.log(new TagFilter([ - new Tag(['-reason', '-r'], 'reason', 'append'), - new Tag(['-against', '-a'], 'against', 'append'), - new Tag(['-force', '-f'], 'force', 'toggle') -]).test('d6 d6 d10 -r to suffer -against myself -f')); \ No newline at end of file From 87be188c6495992e45f527d6a71e876ee9321425 Mon Sep 17 00:00:00 2001 From: WubzyGD Date: Thu, 8 Oct 2020 12:08:12 -0600 Subject: [PATCH 3/6] Deathnote custom victim text, victim-mention parsing --- commands/deathnote.js | 53 +++++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/commands/deathnote.js b/commands/deathnote.js index fba65e8..8daf6c0 100644 --- a/commands/deathnote.js +++ b/commands/deathnote.js @@ -57,23 +57,38 @@ module.exports = { if (!message.guild) {return message.reply("Unfortunately, this is a **guild-only** command!");} if (!args.length) {return message.channel.send(`Syntax: \`${prefix}deathnote <@member> [method of death]\``);} if (args[0] == "kill" || args[0] == "k") {args.shift();} // if someone adds in 'kill' it'll remove it and act like it wasn't there, proceeding as normal. - if (!mention) {return message.reply("You have to write their name down in order to kill them! (In other words, please mention the user whose name you wish to write.)");} - if (!args[0].trim().match(/^<@(?:\!?)\d+>$/)) {return message.reply("You have to mention someone!");} - if (mention.id == message.author.id) {return message.reply("Hehe I won't let you write your own name in the notebook! Just leave it somewhere for a few days and someone else will take it. Maybe they'll write your name...");} // users can't mention themselves - if (mention.id == client.user.id) {return message.reply("You can't kill me! Little did you know, I'm actually a death god!");} + //if (!args[0].trim().match(/^<@(?:\!?)\d+>$/)) {return message.reply("You have to mention someone!");} + if (mention && mention.id == message.author.id) {return message.reply("Hehe I won't let you write your own name in the notebook! Just leave it somewhere for a few days and someone else will take it. Maybe they'll write your name...");} // users can't mention themselves + if (mention && mention.id == client.user.id) {return message.reply("You can't kill me! Little did you know, I'm actually a death god!");} //TODO if bot is mentioned maybe let death = deaths[Math.floor(Math.random() * deaths.length)]; //kill method let reptype = responses[Object.keys(responses)[Math.floor(Math.random() * Object.keys(responses).length)]]; // report type let title = reptype.titles[Math.floor(Math.random() * reptype.titles.length)]; - let pretext = before[Math.floor(Math.random() * before.length)]; - let options = new TagFilter([new Tag(['method', '-m', 'cause', '-c'], 'method', 'append')]).test(args.splice(0, 1).join(" ")); - if (options.method.length) {death = options.method;} + let options = new TagFilter([ + new Tag(['method', '-m', 'cause', '-c'], 'method', 'append'), + new Tag(['victim', 'v', 'against', 'a', 'name', 'n'], 'victim', 'append') + ]).test(args.join(" ")); + if (options.method && options.method.length) {death = options.method;} - let victim = message.mentions.members.first(); + if (!mention && (!options.victim || !options.victim.length)) {return message.reply("You have to write their name down in order to kill them! (In other words, please mention the user whose name you wish to write.)");} + + if (options.victim && options.victim.length) { + let vargs = options.victim.trim().split(/\s+/g); + let nvargs = []; + let varg; for (varg of vargs) { + if (varg.match(/^<@(?:\!?)\d+>$/)) { + nvargs.push(message.guild.members.cache.has(varg.slice(varg.search(/\d/), varg.search('>'))) ? message.guild.members.cache.get(varg.slice(varg.search(/\d/), varg.search('>'))).displayName : varg); + } else {nvargs.push(varg);} + } + options.victim = nvargs.join(" ").trim(); + } + let victim = options.victim && options.victim.length ? options.victim : message.mentions.members.first().displayName; let killer = message.member; + let pretext = before[Math.floor(Math.random() * before.length)].replace(/{p}/g, victim); + let note = await message.channel.send(new Discord.MessageEmbed() .setDescription(pretext) .setColor('c375f0') @@ -84,22 +99,22 @@ module.exports = { await require('../util/wait')(2500); let text = reptype.texts[Math.floor(Math.random() * reptype.texts.length)] - .replace(/{p}/g, victim.displayName) //{p} = victim - .replace(/{pa}/g, victim.displayName.toLowerCase().endsWith('s') ? `${victim.displayName}'` : `${victim.displayName}'s`) //{pa} = victim but with a formatted apostrophe like "WubzyGD's" + .replace(/{p}/g, victim) //{p} = victim + .replace(/{pa}/g, victim.toLowerCase().endsWith('s') ? `${victim}'` : `${victim}'s`) //{pa} = victim but with a formatted apostrophe like "WubzyGD's" .replace(/{c}/g, death) // {c} = death method .replace(/{w}/g, killer.displayName) // {w} = killer or writer .replace(/{ds}/g, moment().format("h:mm a")); // {ds} = date small, basically just the time. // Create and format the kill text - //TODO message before sending then edit that message i.e. "A name is being written..." then wait 5s + let finalEmbed = new Discord.MessageEmbed() + .setAuthor(title, message.author.avatarURL()) + .setDescription(text) + .setColor('c375f0') + .setFooter("Natsuki") + .setTimestamp(); - return note.edit(new Discord.MessageEmbed() - .setAuthor(title, message.author.avatarURL()) - .setThumbnail(mention.avatarURL({size: 1024})) - .setDescription(text) - .setColor('c375f0') - .setFooter("Natsuki") - .setTimestamp() - ); + if (mention) {finalEmbed.setThumbnail(mention.avatarURL({size: 1024}));} + + return note.edit(finalEmbed); } }; \ No newline at end of file From eb7227392ca4d52224299aa83de2ad3e2e2869df Mon Sep 17 00:00:00 2001 From: WubzyGD Date: Thu, 8 Oct 2020 20:39:30 -0600 Subject: [PATCH 4/6] n?avatar --- commands/avatar.js | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 commands/avatar.js diff --git a/commands/avatar.js b/commands/avatar.js new file mode 100644 index 0000000..ddf32ca --- /dev/null +++ b/commands/avatar.js @@ -0,0 +1,20 @@ +const Discord = require('discord.js'); + +module.exports = { + name: "avatar", + aliases: ['av', 'a', 'pfp'], + help: "Use `{{p}}avatar` to get your own profile picture, or mention someone to get theirs!", + async execute(message, msg, args, cmd, prefix, mention, client) { + let member = !args.length ? message.author : mention ? mention : client.users.cache.has(args[0]) ? client.users.cache.get(args[0]) : message.author; + let name = !args.length ? message.member ? message.member.displayName : message.author.username : mention ? mention.username : client.users.cache.has(args[0]) ? client.users.cache.get(args[0]).username : message.author.username; + try { + return message.channel.send(new Discord.MessageEmbed() + .setTitle(`${name.endsWith('s') ? `${name}'` : `${name}'s`} Avatar`) + .setImage(member.avatarURL({size: 2048})) + .setColor('c375f0') + .setFooter("Natsuki", client.user.avatarURL()) + .setTimestamp() + ); + } catch {return message.reply("Hmm, there seems to have been an error while I tried to show you that user's avatar.");} + } +}; \ No newline at end of file From fdb6821d71d23c20b186414d3b8a6b752921faaa Mon Sep 17 00:00:00 2001 From: WubzyGD Date: Fri, 9 Oct 2020 14:58:42 -0600 Subject: [PATCH 5/6] Avatar -small and -verysmall flags --- commands/avatar.js | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/commands/avatar.js b/commands/avatar.js index ddf32ca..8f474cc 100644 --- a/commands/avatar.js +++ b/commands/avatar.js @@ -1,4 +1,6 @@ const Discord = require('discord.js'); +const {Tag} = require('../util/tag'); +const {TagFilter} = require('../util/tagfilter'); module.exports = { name: "avatar", @@ -7,14 +9,18 @@ module.exports = { async execute(message, msg, args, cmd, prefix, mention, client) { let member = !args.length ? message.author : mention ? mention : client.users.cache.has(args[0]) ? client.users.cache.get(args[0]) : message.author; let name = !args.length ? message.member ? message.member.displayName : message.author.username : mention ? mention.username : client.users.cache.has(args[0]) ? client.users.cache.get(args[0]).username : message.author.username; + let options = new TagFilter([ + new Tag(['small', 's', 'mini', 'm'], 'small', 'toggle'), + new Tag(['verysmall', 'vsmall', '-vs', 'xs'], 'vsmall', 'toggle') + ]).test(args.join(" ")); try { - return message.channel.send(new Discord.MessageEmbed() - .setTitle(`${name.endsWith('s') ? `${name}'` : `${name}'s`} Avatar`) - .setImage(member.avatarURL({size: 2048})) - .setColor('c375f0') - .setFooter("Natsuki", client.user.avatarURL()) - .setTimestamp() - ); + let avem = new Discord.MessageEmbed() + .setTitle(`${name.endsWith('s') ? `${name}'` : `${name}'s`} Avatar`) + .setImage(member.avatarURL({size: options.vsmall ? 128 : options.small ? 256 : 2048})) + .setColor('c375f0') + .setFooter("Natsuki", client.user.avatarURL()) + if (!options.vsmall) {avem.setTimestamp();} + return message.channel.send(avem); } catch {return message.reply("Hmm, there seems to have been an error while I tried to show you that user's avatar.");} } }; \ No newline at end of file From 043123c04a822aaff258724976caa994e04103c2 Mon Sep 17 00:00:00 2001 From: WubzyGD Date: Fri, 9 Oct 2020 21:29:08 -0600 Subject: [PATCH 6/6] n?staffrole --- .idea/Natsuki.iml | 12 +++++++++++ .idea/modules.xml | 8 ++++++++ commands/staffrole.js | 48 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+) create mode 100644 .idea/Natsuki.iml create mode 100644 .idea/modules.xml create mode 100644 commands/staffrole.js diff --git a/.idea/Natsuki.iml b/.idea/Natsuki.iml new file mode 100644 index 0000000..24643cc --- /dev/null +++ b/.idea/Natsuki.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..c4ee72c --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/commands/staffrole.js b/commands/staffrole.js new file mode 100644 index 0000000..7fd0acc --- /dev/null +++ b/commands/staffrole.js @@ -0,0 +1,48 @@ +const Discord = require('discord.js'); +const GuildSettings = require('../models/guild'); + +module.exports = { + name: "staffrole", + aliases: ['sr', 'setstaffrole'], + help: "Set your server's staff role, which allows users with that role to modify my settings in this server. You must be an admin in the server to change this setting.", + async execute(message, msg, args, cmd, prefix, mention, client) { + if (!message.guild) {return message.reply("This is a guild-only command!");} + if (!args.length) {return message.channel.send(`Syntax: \`${prefix}staffrole <@role|roleID|clear|view>\``);} + if (!message.member.permissions.has("ADMINISTRATOR")) {return message.reply("You must be an admin in this server in order to change this setting!");} + + let tguild = await GuildSettings.findOne({gid: message.guild.id}) + ? await GuildSettings.findOne({gid: message.guild.id}) + : new GuildSettings({gid: message.guild.id}); + + if (['view', 'v'].includes(args[0].trim().toLocaleLowerCase())) {return message.reply( + tguild.staffrole.length + ? message.guild.roles.cache.has(tguild.staffrole) + ? `\`People with the ${message.guild.roles.cache.get(tguild.staffrole).name}\` role can edit my setting here.` + : `I have a role stored for this server, but it doesn't seem to exist anymore, so only admins can edit my settings right now.` + : 'Only admins may edit settings in this server.' + );} + + let role = !['c', 'clear', 'n', 'none'].includes(args[0].trim().toLowerCase()) ? message.mentions.roles.size ? message.mentions.roles.first() : message.guild.roles.cache.has(args[0]) ? message.guild.roles.cache.get(args[0]) : null : 'c'; + + if (!role) {return message.reply("I couldn't find that role!");} + if (role === "c") { + tguild.staffrole = ''; + tguild.save(); + return message.reply("Got it, only admins can edit my settings in this server."); + } else { + tguild.staffrole = role.id; + tguild.save(); + let upm = message.reply("Sure thing!"); + await require('../util/wait')(1750); + return upm.edit(new Discord.MessageEmbed() + .setAuthor('Staff role updated!', message.author.avatarURL()) + .setDescription(`<@${tguild.staffrole}> can now edit my settings in this server.`) + .addField('Auditing Admin', message.member.displayName, true) + .addField('Role-Holders', `${message.guild.members.cache.filter(m => m.roles.cache.has(tguild.staffrole) && !client.users.cache.get(m.id).bot)}+ members have this role`) + .setColor('c375f0') + .setFooter('Natsuki', client.user.avatarURL()) + .setTimestamp() + ); + } + } +}; \ No newline at end of file