push time
This commit is contained in:
parent
07029ffc52
commit
c7b55b1aae
41 changed files with 1150 additions and 96 deletions
157
package-lock.json
generated
157
package-lock.json
generated
|
@ -232,6 +232,21 @@
|
|||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
|
||||
"dev": true
|
||||
},
|
||||
"base64-js": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
|
||||
"integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==",
|
||||
"dev": true
|
||||
},
|
||||
"bl": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/bl/-/bl-2.2.0.tgz",
|
||||
"integrity": "sha512-wbgvOpqopSr7uq6fJrLH8EsvYMJf9gzfo2jCsL2eTy75qXPukA4pCgHamOQkZtY5vmfVtjB+P3LNlMHW5CEZXA==",
|
||||
"requires": {
|
||||
"readable-stream": "^2.3.5",
|
||||
"safe-buffer": "^5.1.1"
|
||||
}
|
||||
},
|
||||
"boxen": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/boxen/-/boxen-3.2.0.tgz",
|
||||
|
@ -346,9 +361,24 @@
|
|||
}
|
||||
},
|
||||
"bson": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/bson/-/bson-1.1.3.tgz",
|
||||
"integrity": "sha512-TdiJxMVnodVS7r0BdL42y/pqC9cL2iKynVwA0Ho3qbsQYr428veL3l7BQyuqiw+Q5SqqoT0m4srSY/BlZ9AxXg=="
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/bson/-/bson-4.0.3.tgz",
|
||||
"integrity": "sha512-7uBjjxwOSuGLmoqGI1UXWpDGc0K2WjR7dC6iaOg4iriNZo6M2EEBb8co4dEPJ5ArYCebPMie0ecgX0TWF+ZUrQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"buffer": "^5.1.0",
|
||||
"long": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"buffer": {
|
||||
"version": "5.4.3",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.4.3.tgz",
|
||||
"integrity": "sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"base64-js": "^1.0.2",
|
||||
"ieee754": "^1.1.4"
|
||||
}
|
||||
},
|
||||
"builtin-modules": {
|
||||
"version": "1.1.1",
|
||||
|
@ -519,6 +549,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
|
||||
},
|
||||
"cross-spawn": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
|
||||
|
@ -595,6 +630,11 @@
|
|||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
|
||||
},
|
||||
"denque": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/denque/-/denque-1.4.1.tgz",
|
||||
"integrity": "sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ=="
|
||||
},
|
||||
"diff": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz",
|
||||
|
@ -602,7 +642,7 @@
|
|||
"dev": true
|
||||
},
|
||||
"discord.js": {
|
||||
"version": "github:discordjs/discord.js#ee0b7c155a1767ed42e2756e53d56368e8b69929",
|
||||
"version": "github:discordjs/discord.js#030d263a9e018a766c5f399624fe4f8ec2b7349c",
|
||||
"from": "github:discordjs/discord.js",
|
||||
"requires": {
|
||||
"@discordjs/collection": "^0.1.1",
|
||||
|
@ -854,6 +894,12 @@
|
|||
"safer-buffer": ">= 2.1.2 < 3"
|
||||
}
|
||||
},
|
||||
"ieee754": {
|
||||
"version": "1.1.13",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz",
|
||||
"integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==",
|
||||
"dev": true
|
||||
},
|
||||
"import-lazy": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz",
|
||||
|
@ -885,8 +931,7 @@
|
|||
"inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
|
@ -1049,6 +1094,11 @@
|
|||
"integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==",
|
||||
"dev": true
|
||||
},
|
||||
"isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
|
||||
},
|
||||
"isexe": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||
|
@ -1129,6 +1179,12 @@
|
|||
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
|
||||
"dev": true
|
||||
},
|
||||
"long": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
|
||||
"integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==",
|
||||
"dev": true
|
||||
},
|
||||
"loud-rejection": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz",
|
||||
|
@ -1252,15 +1308,29 @@
|
|||
"minimist": "0.0.8"
|
||||
}
|
||||
},
|
||||
"module-alias": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/module-alias/-/module-alias-2.2.2.tgz",
|
||||
"integrity": "sha512-A/78XjoX2EmNvppVWEhM2oGk3x4lLxnkEA4jTbaK97QKSDjkIoOsKQlfylt/d3kKKi596Qy3NP5XrXJ6fZIC9Q=="
|
||||
},
|
||||
"mongodb": {
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.4.1.tgz",
|
||||
"integrity": "sha512-juqt5/Z42J4DcE7tG7UdVaTKmUC6zinF4yioPfpeOSNBieWSK6qCY+0tfGQcHLKrauWPDdMZVROHJOa8q2pWsA==",
|
||||
"version": "3.5.2",
|
||||
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.5.2.tgz",
|
||||
"integrity": "sha512-Lxt4th2tK2MxmkDBR5cMik+xEnkvhwg0BC5kGcHm9RBwaNEsrIryvV5istGXOHbnif5KslMpY1FbX6YbGJ/Trg==",
|
||||
"requires": {
|
||||
"bl": "^2.2.0",
|
||||
"bson": "^1.1.1",
|
||||
"denque": "^1.4.1",
|
||||
"require_optional": "^1.0.1",
|
||||
"safe-buffer": "^5.1.2",
|
||||
"saslprep": "^1.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"bson": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/bson/-/bson-1.1.3.tgz",
|
||||
"integrity": "sha512-TdiJxMVnodVS7r0BdL42y/pqC9cL2iKynVwA0Ho3qbsQYr428veL3l7BQyuqiw+Q5SqqoT0m4srSY/BlZ9AxXg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"mute-stream": {
|
||||
|
@ -1455,9 +1525,14 @@
|
|||
"dev": true
|
||||
},
|
||||
"prism-media": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/prism-media/-/prism-media-1.1.0.tgz",
|
||||
"integrity": "sha512-W+oxjRyjtd7hw3pefNZuc7YEZ6VICORJvVNfCPs0+7CsJ43CqMjGAYGjPL3hQ82vw03EVra+CiX4zisqOBUUGw=="
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/prism-media/-/prism-media-1.2.0.tgz",
|
||||
"integrity": "sha512-zjcO/BLVlfxWqFpEUlDyL1R9XXMquasNP4xpeYDPPZi/Zcz0i6OXoqcvxOLgbRVPsJXVd29vlYmRx2bts+hzEw=="
|
||||
},
|
||||
"process-nextick-args": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
|
||||
},
|
||||
"pseudomap": {
|
||||
"version": "1.0.2",
|
||||
|
@ -1522,6 +1597,27 @@
|
|||
"read-pkg": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "2.3.7",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
|
||||
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
|
||||
"requires": {
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.3",
|
||||
"isarray": "~1.0.0",
|
||||
"process-nextick-args": "~2.0.0",
|
||||
"safe-buffer": "~5.1.1",
|
||||
"string_decoder": "~1.1.1",
|
||||
"util-deprecate": "~1.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"redent": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/redent/-/redent-2.0.0.tgz",
|
||||
|
@ -1749,6 +1845,21 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"requires": {
|
||||
"safe-buffer": "~5.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
|
||||
|
@ -1930,9 +2041,9 @@
|
|||
}
|
||||
},
|
||||
"tweetnacl": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.1.tgz",
|
||||
"integrity": "sha512-kcoMoKTPYnoeS50tzoqjPY3Uv9axeuuFAZY9M/9zFnhoVvRfxz9K29IMPD7jGmt2c8SW7i3gT9WqDl2+nV7p4A=="
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.2.tgz",
|
||||
"integrity": "sha512-+8aPRjmXgf1VqvyxSlBUzKzeYqVS9Ai8vZ28g+mL7dNQl1jlUTCMDZnvNQdAS1xTywMkIXwJsfipsR/6s2+syw=="
|
||||
},
|
||||
"type-fest": {
|
||||
"version": "0.8.1",
|
||||
|
@ -1950,11 +2061,16 @@
|
|||
}
|
||||
},
|
||||
"typescript": {
|
||||
"version": "3.7.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.4.tgz",
|
||||
"integrity": "sha512-A25xv5XCtarLwXpcDNZzCGvW2D1S3/bACratYBx2sax8PefsFhlYmkQicKHvpYflFS8if4zne5zT5kpJ7pzuvw==",
|
||||
"version": "3.7.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.5.tgz",
|
||||
"integrity": "sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw==",
|
||||
"dev": true
|
||||
},
|
||||
"typy": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/typy/-/typy-3.3.0.tgz",
|
||||
"integrity": "sha512-Du53deMF9X9pSM3gVXDjLBq14BUfZWSGKfmmR1kTlg953RaIZehfc8fQuoAiW+SRO6bJsP+59mv1tsH8vwKghg=="
|
||||
},
|
||||
"unique-string": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz",
|
||||
|
@ -2045,6 +2161,11 @@
|
|||
"prepend-http": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
|
||||
},
|
||||
"validate-npm-package-license": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
|
||||
|
|
23
package.json
23
package.json
|
@ -7,10 +7,12 @@
|
|||
"author": "Rauf",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/bson": "^4.0.1",
|
||||
"@types/node": "^10.17.13",
|
||||
"@types/ws": "^6.0.4",
|
||||
"bson": "^4.0.3",
|
||||
"gts": "^1.1.2",
|
||||
"typescript": "~3.7.0",
|
||||
"@types/node": "^10.0.3",
|
||||
"@types/ws": "^6.0.4"
|
||||
"typescript": "^3.7.5"
|
||||
},
|
||||
"scripts": {
|
||||
"check": "gts check",
|
||||
|
@ -25,6 +27,19 @@
|
|||
"dependencies": {
|
||||
"@types/mongodb": "^3.3.14",
|
||||
"discord.js": "github:discordjs/discord.js",
|
||||
"mongodb": "^3.4.1"
|
||||
"module-alias": "^2.2.2",
|
||||
"mongodb": "^3.5.2",
|
||||
"typy": "^3.3.0"
|
||||
},
|
||||
"_moduleAliases": {
|
||||
"@lifeguard": "./build/src",
|
||||
"@lifeguard/base": "./",
|
||||
"@assertions": "./build/src/assertions",
|
||||
"@config": "./build/src/config",
|
||||
"@events": "./build/src/events",
|
||||
"@models": "./build/src/models",
|
||||
"@plugins": "./build/src/plugins",
|
||||
"@structures": "./build/src/structures",
|
||||
"@util": "./build/src/util"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { name, url } from '@config/mongodb';
|
||||
import { Plugin } from '@plugins/Plugin';
|
||||
import { Database } from '@util/Database';
|
||||
import { Client, ClientOptions, Collection } from 'discord.js';
|
||||
import { Plugin } from './plugins/Plugin';
|
||||
import { Database } from './util/Database';
|
||||
import { name, url } from './config/mongodb';
|
||||
|
||||
export class PluginClient extends Client {
|
||||
plugins!: Collection<string, Plugin>;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { GuildMember, Guild } from 'discord.js';
|
||||
import { developers } from '../config/bot';
|
||||
import { developers } from '@config/bot';
|
||||
|
||||
export function calcUserLevel(user: GuildMember, guild: Guild) {
|
||||
if (developers.includes(user.id)) {
|
||||
|
|
35
src/events/channelCreate.ts
Normal file
35
src/events/channelCreate.ts
Normal file
|
@ -0,0 +1,35 @@
|
|||
import { Event } from '@events/Event';
|
||||
import { GuildStructure } from '@structures/GuildStructure';
|
||||
import { defaultEmbed } from '@util/DefaultEmbed';
|
||||
import { GuildChannel, TextChannel } from 'discord.js';
|
||||
|
||||
export const event = new Event(
|
||||
'channelCreate',
|
||||
async (lifeguard, channel: GuildChannel) => {
|
||||
const dbGuild = await (channel.guild as GuildStructure).db;
|
||||
if (dbGuild?.config.channels?.logging) {
|
||||
const modlog = channel.guild.channels.get(
|
||||
dbGuild.config.channels.logging
|
||||
) as TextChannel;
|
||||
|
||||
const auditLog = await channel.guild.fetchAuditLogs({
|
||||
type: 'CHANNEL_CREATE',
|
||||
});
|
||||
const auditLogEntry = auditLog.entries.last();
|
||||
|
||||
// const embed = defaultEmbed()
|
||||
// .setDescription(
|
||||
// `:pencil: Channel ${channel.toString()} (${channel.id}) was created`
|
||||
// )
|
||||
// .setTitle('Channel Create');
|
||||
|
||||
// if (auditLogEntry) {
|
||||
// embed.setAuthor(`${auditLogEntry.executor.tag}`);
|
||||
// }
|
||||
|
||||
const embed = defaultEmbed();
|
||||
|
||||
modlog.send(embed);
|
||||
}
|
||||
}
|
||||
);
|
|
@ -1,7 +1,7 @@
|
|||
import { Event } from '@events/Event';
|
||||
import { PluginClient } from '@lifeguard/PluginClient';
|
||||
import { readdir } from 'fs';
|
||||
import { promisify } from 'util';
|
||||
import { Event } from './Event';
|
||||
import { PluginClient } from '../PluginClient';
|
||||
|
||||
const readDir = promisify(readdir);
|
||||
|
||||
|
|
|
@ -1,13 +1,18 @@
|
|||
import { Event } from './Event';
|
||||
import { Event } from '@events/Event';
|
||||
import { Guild } from 'discord.js';
|
||||
|
||||
export const event = new Event('guildCreate', lifeguard => {
|
||||
if (lifeguard.user) {
|
||||
lifeguard.user.setPresence({
|
||||
activity: {
|
||||
name: `${lifeguard.users.size} people in the pool`,
|
||||
type: 'WATCHING',
|
||||
},
|
||||
status: 'online',
|
||||
});
|
||||
export const event = new Event(
|
||||
'guildCreate',
|
||||
async (lifeguard, guild: Guild) => {
|
||||
await lifeguard.db.guilds.insertOne({ id: guild.id, config: {} });
|
||||
if (lifeguard.user) {
|
||||
lifeguard.user.setPresence({
|
||||
activity: {
|
||||
name: `${lifeguard.users.size} people in the pool`,
|
||||
type: 'WATCHING',
|
||||
},
|
||||
status: 'online',
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { Event } from './Event';
|
||||
import { calcUserLevel } from '@assertions/userLevel';
|
||||
import { prefix } from '@config/bot';
|
||||
import { Event } from '@events/Event';
|
||||
import { PluginClient } from '@lifeguard/PluginClient';
|
||||
import { UserDoc } from '@models/User';
|
||||
import { Message } from 'discord.js';
|
||||
import { prefix } from '../config/bot';
|
||||
import { PluginClient } from '../PluginClient';
|
||||
import { calcUserLevel } from '../assertions/userLevel';
|
||||
import { UserDoc } from '../models/User';
|
||||
|
||||
function parseContent(content: string) {
|
||||
const split = content.split(' ');
|
||||
|
@ -14,8 +14,15 @@ function parseContent(content: string) {
|
|||
|
||||
function getCommandFromPlugin(lifeguard: PluginClient, cmdName: string) {
|
||||
const plugin = lifeguard.plugins.find(p => p.has(cmdName));
|
||||
const command = plugin?.get(cmdName);
|
||||
return command;
|
||||
if (plugin) {
|
||||
return plugin?.get(cmdName);
|
||||
} else {
|
||||
const plugins = [...lifeguard.plugins.values()];
|
||||
const cmds = plugins
|
||||
.map(p => [...p.values()])
|
||||
.reduce((acc, val) => acc.concat(val), []);
|
||||
return cmds.find(cmd => cmd.options.alias?.includes(cmdName));
|
||||
}
|
||||
}
|
||||
|
||||
export const event = new Event(
|
||||
|
|
|
@ -1,20 +1,42 @@
|
|||
import { Event } from './Event';
|
||||
import { prefix } from '@config/bot';
|
||||
import { Event } from '@events/Event';
|
||||
import { Guild } from '@models/Guild';
|
||||
import { User } from '@models/User';
|
||||
import { GuildStructure } from '@structures/GuildStructure';
|
||||
import { Message } from 'discord.js';
|
||||
import { prefix } from '../config/bot';
|
||||
import { User, UserDoc } from '../models/User';
|
||||
|
||||
export const event = new Event('message', async (lifeguard, msg: Message) => {
|
||||
let dbUser = (await lifeguard.db.users.findOne({
|
||||
let dbUser = await lifeguard.db.users.findOne({
|
||||
id: msg.author.id,
|
||||
})) as UserDoc;
|
||||
});
|
||||
if (!dbUser) {
|
||||
await lifeguard.db.users.insertOne(
|
||||
new User({ id: msg.author.id, infractions: [] })
|
||||
);
|
||||
dbUser = (await lifeguard.db.users.findOne({
|
||||
await lifeguard.db.users.insertOne(new User({ id: msg.author.id }));
|
||||
dbUser = await lifeguard.db.users.findOne({
|
||||
id: msg.author.id,
|
||||
})) as UserDoc;
|
||||
});
|
||||
}
|
||||
|
||||
if (msg.guild) {
|
||||
const dbGuild = await (msg.guild as GuildStructure).db;
|
||||
if (!dbGuild) {
|
||||
await lifeguard.db.guilds.insertOne(new Guild({ id: msg.guild.id }));
|
||||
}
|
||||
}
|
||||
|
||||
if (dbUser) {
|
||||
dbUser.stats.totalSentMessages++;
|
||||
dbUser.stats.totalSentCharacters += msg.content.length;
|
||||
dbUser.stats.totalCustomEmojisUsed +=
|
||||
msg.content.match(/<.[^ ]*>/)?.length ?? 0;
|
||||
dbUser.stats.totalTimesMentionedAUser += msg.mentions.users.size;
|
||||
dbUser.stats.totalSentAttachments += msg.attachments.size;
|
||||
|
||||
await lifeguard.db.users.updateOne(
|
||||
{ id: dbUser.id },
|
||||
{ $set: { stats: dbUser.stats } }
|
||||
);
|
||||
}
|
||||
|
||||
if (msg.content.startsWith(prefix)) {
|
||||
lifeguard.emit('lifeguardCommandUsed', msg, dbUser);
|
||||
}
|
||||
|
|
20
src/events/messageReactionAdd.ts
Normal file
20
src/events/messageReactionAdd.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { Event } from '@events/Event';
|
||||
import { GuildStructure } from '@structures/GuildStructure';
|
||||
import { MessageReaction, User } from 'discord.js';
|
||||
|
||||
export const event = new Event(
|
||||
'messageReactionAdd',
|
||||
async (lifeguard, reaction: MessageReaction, user: User) => {
|
||||
await lifeguard.db.users.updateOne(
|
||||
{ id: user.id },
|
||||
{ $inc: { 'stats.totalTimesReacted': 1 } }
|
||||
);
|
||||
const dbGuild = await (reaction.message.guild as GuildStructure).db;
|
||||
if (
|
||||
dbGuild?.config.channels?.starboard &&
|
||||
reaction.emoji.name === dbGuild?.config.starboard?.emoji
|
||||
) {
|
||||
lifeguard.emit('starboardReactionAdd', reaction);
|
||||
}
|
||||
}
|
||||
);
|
|
@ -1,4 +1,4 @@
|
|||
import { Event } from './Event';
|
||||
import { Event } from '@events/Event';
|
||||
|
||||
export const event = new Event('ready', lifeguard => {
|
||||
console.log('Connected to Discord');
|
||||
|
|
64
src/events/starboardReactionAdd.ts
Normal file
64
src/events/starboardReactionAdd.ts
Normal file
|
@ -0,0 +1,64 @@
|
|||
import { Event } from '@events/Event';
|
||||
import { GuildStructure } from '@structures/GuildStructure';
|
||||
import { defaultEmbed } from '@util/DefaultEmbed';
|
||||
import { TextChannel, MessageReaction } from 'discord.js';
|
||||
|
||||
export const event = new Event(
|
||||
'starboardReactionAdd',
|
||||
async (lifeguard, reaction: MessageReaction) => {
|
||||
const dbGuild = await (reaction.message.guild as GuildStructure).db;
|
||||
if (dbGuild?.config.starboard && dbGuild.config.channels?.starboard) {
|
||||
const starboardChannel = reaction.message.guild?.channels.get(
|
||||
dbGuild.config.channels.starboard
|
||||
) as TextChannel;
|
||||
const starboard = dbGuild.config.starboard;
|
||||
if (
|
||||
starboardChannel &&
|
||||
!starboard.ignoredChannels.includes(reaction.message.channel.id)
|
||||
) {
|
||||
if (reaction.count ?? 0 >= starboard.minCount) {
|
||||
const starboardMessage = starboard.messages.find(
|
||||
m => m.id === reaction.message.id
|
||||
);
|
||||
if (starboardMessage) {
|
||||
const starboardMessageInChannel = starboardChannel.messages.get(
|
||||
starboardMessage.starboardID
|
||||
);
|
||||
starboardMessage.count = reaction.count ?? starboardMessage.count;
|
||||
const embed = defaultEmbed()
|
||||
.setAuthor(
|
||||
starboardMessageInChannel?.author.tag,
|
||||
starboardMessageInChannel?.author.avatarURL() ?? ''
|
||||
)
|
||||
.setDescription(reaction.message.content);
|
||||
starboardMessageInChannel?.edit(
|
||||
`${starboard.emoji} ${reaction.count} ${reaction.message.channel} (${reaction.message.id})`,
|
||||
embed
|
||||
);
|
||||
} else {
|
||||
const embed = defaultEmbed()
|
||||
.setAuthor(
|
||||
reaction.message.author.tag,
|
||||
reaction.message.author.avatarURL() ?? ''
|
||||
)
|
||||
.setDescription(reaction.message.content);
|
||||
const starboardMessage = await starboardChannel.send(
|
||||
`${starboard.emoji} ${reaction.count} ${reaction.message.channel} (${reaction.message.id})`,
|
||||
embed
|
||||
);
|
||||
starboard.messages.push({
|
||||
id: reaction.message.id,
|
||||
starboardID: starboardMessage.id,
|
||||
content: reaction.message.content,
|
||||
count: reaction.count ?? 0,
|
||||
});
|
||||
}
|
||||
await lifeguard.db.guilds.updateOne(
|
||||
{ id: dbGuild.id },
|
||||
{ $set: { 'config.starboard': starboard } }
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
13
src/index.ts
13
src/index.ts
|
@ -1,7 +1,12 @@
|
|||
import { token } from './config/bot';
|
||||
import { EventLoader } from './events/eventLoader';
|
||||
import { PluginLoader } from './plugins/pluginLoader';
|
||||
import { PluginClient } from './PluginClient';
|
||||
import 'module-alias/register';
|
||||
|
||||
import { token } from '@config/bot';
|
||||
import { EventLoader } from '@events/eventLoader';
|
||||
import { PluginClient } from '@lifeguard/PluginClient';
|
||||
import { PluginLoader } from '@plugins/pluginLoader';
|
||||
import { StructureLoader } from '@structures/structureLoader';
|
||||
|
||||
StructureLoader();
|
||||
|
||||
const lifeguard = new PluginClient();
|
||||
|
||||
|
|
52
src/models/Guild.ts
Normal file
52
src/models/Guild.ts
Normal file
|
@ -0,0 +1,52 @@
|
|||
import { ObjectId } from 'bson';
|
||||
|
||||
export interface GuildChannels {
|
||||
logging?: string;
|
||||
starboard?: string;
|
||||
}
|
||||
|
||||
export interface GuildRoles {
|
||||
[key: string]: string | string[] | undefined;
|
||||
muted?: string;
|
||||
moderator?: string;
|
||||
groupRoles?: string[];
|
||||
lockedRoles?: string[];
|
||||
}
|
||||
|
||||
export interface GuildStarboardMessage {
|
||||
id: string;
|
||||
starboardID: string;
|
||||
count: number;
|
||||
content: string;
|
||||
}
|
||||
|
||||
export interface GuildStarboard {
|
||||
emoji: string;
|
||||
minCount: number;
|
||||
ignoredChannels: string[];
|
||||
messages: GuildStarboardMessage[];
|
||||
}
|
||||
|
||||
export interface GuildConfig {
|
||||
blacklisted?: boolean;
|
||||
channels?: GuildChannels;
|
||||
roles?: GuildRoles;
|
||||
starboard?: GuildStarboard;
|
||||
}
|
||||
|
||||
export interface GuildDoc {
|
||||
id: string;
|
||||
config?: GuildConfig;
|
||||
}
|
||||
|
||||
export class Guild implements GuildDoc {
|
||||
_id: ObjectId;
|
||||
id: string;
|
||||
config: GuildConfig;
|
||||
constructor(data: GuildDoc) {
|
||||
this._id = new ObjectId();
|
||||
this.id = data.id;
|
||||
this.config = data.config ?? {};
|
||||
this.config.blacklisted = data.config?.blacklisted ?? false;
|
||||
}
|
||||
}
|
|
@ -1,5 +1,8 @@
|
|||
interface UserInfraction {
|
||||
action: 'Warn' | 'Mute' | 'Tempban' | 'Ban';
|
||||
import { ObjectId } from 'bson';
|
||||
import { PermissionOverwriteOption } from 'discord.js';
|
||||
|
||||
export interface UserInfraction {
|
||||
action: 'Warn' | 'Kick' | 'Mute' | 'Ban';
|
||||
active: boolean;
|
||||
guild: string;
|
||||
id: number;
|
||||
|
@ -8,19 +11,68 @@ interface UserInfraction {
|
|||
time: Date;
|
||||
}
|
||||
|
||||
export interface UserBackup {
|
||||
guild: string;
|
||||
id: number;
|
||||
roles: string[];
|
||||
nickname: string;
|
||||
channelOverrides: UserBackupChannelOverride[];
|
||||
deafened: boolean;
|
||||
muted: boolean;
|
||||
createdAt: Date;
|
||||
}
|
||||
|
||||
export interface UserBackupChannelOverride {
|
||||
channelId: number;
|
||||
overrides: PermissionOverwriteOption;
|
||||
}
|
||||
|
||||
export interface UserStats {
|
||||
totalSentMessages: number;
|
||||
totalSentCharacters: number;
|
||||
totalDeletedMessages: number;
|
||||
totalCustomEmojisUsed: number;
|
||||
totalTimesMentionedAUser: number;
|
||||
totalSentAttachments: number;
|
||||
totalTimesReacted: number;
|
||||
mostUsedReaction: string;
|
||||
}
|
||||
|
||||
export interface UserReactions {
|
||||
[name: string]: number;
|
||||
}
|
||||
|
||||
export interface UserDoc {
|
||||
blacklisted?: boolean;
|
||||
id: string;
|
||||
infractions: UserInfraction[];
|
||||
infractions?: UserInfraction[];
|
||||
backups?: UserBackup[];
|
||||
stats?: UserStats;
|
||||
reactions?: UserReactions;
|
||||
}
|
||||
|
||||
export class User implements UserDoc {
|
||||
_id: ObjectId;
|
||||
blacklisted: boolean;
|
||||
id: string;
|
||||
infractions: UserInfraction[];
|
||||
backups: UserBackup[];
|
||||
stats: UserStats;
|
||||
constructor(data: UserDoc) {
|
||||
this._id = new ObjectId();
|
||||
this.blacklisted = data.blacklisted ?? false;
|
||||
this.id = data.id;
|
||||
this.infractions = data.infractions;
|
||||
this.infractions = data.infractions ?? [];
|
||||
this.backups = data.backups ?? [];
|
||||
this.stats = data.stats ?? {
|
||||
totalSentMessages: 0,
|
||||
totalSentCharacters: 0,
|
||||
totalDeletedMessages: 0,
|
||||
totalCustomEmojisUsed: 0,
|
||||
totalTimesMentionedAUser: 0,
|
||||
totalSentAttachments: 0,
|
||||
totalTimesReacted: 0,
|
||||
mostUsedReaction: '',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import { Message, PermissionString } from 'discord.js';
|
||||
import { PluginClient } from '../PluginClient';
|
||||
import { UserDoc } from '../models/User';
|
||||
import { PluginClient } from '@lifeguard/PluginClient';
|
||||
import { UserDoc } from '@models/User';
|
||||
|
||||
type CommandFunction = (
|
||||
lifeguard: PluginClient,
|
||||
msg: Message,
|
||||
args: string[],
|
||||
dbUser: UserDoc
|
||||
dbUser?: UserDoc
|
||||
) => void;
|
||||
|
||||
interface CommandOptions {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Collection } from 'discord.js';
|
||||
import { Command } from './Command';
|
||||
import { Command } from '@plugins/Command';
|
||||
|
||||
export class Plugin extends Collection<string, Command> {
|
||||
constructor() {
|
||||
|
|
46
src/plugins/admin/config.ts
Normal file
46
src/plugins/admin/config.ts
Normal file
|
@ -0,0 +1,46 @@
|
|||
import { Command } from '@plugins/Command';
|
||||
import { t as typy } from 'typy';
|
||||
|
||||
export const command = new Command(
|
||||
'config',
|
||||
async (lifeguard, msg, [cmd, ...args]) => {
|
||||
const path = args[0];
|
||||
switch (cmd) {
|
||||
case 'get':
|
||||
const guild = await lifeguard.db.guilds.findOne({ id: msg.guild?.id });
|
||||
if (guild) {
|
||||
const config = guild['config'];
|
||||
if (path) {
|
||||
msg.channel.send(`${path} - ${typy(config, path).safeObject}`);
|
||||
} else {
|
||||
msg.channel.send(
|
||||
`\`\`\`json\n${JSON.stringify(config, null, 2)}\`\`\``
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'set':
|
||||
const res = await lifeguard.db.guilds.findOneAndUpdate(
|
||||
{
|
||||
id: msg.guild?.id,
|
||||
},
|
||||
{
|
||||
$set: { [`config.${path}`]: JSON.parse(args[1]) },
|
||||
}
|
||||
);
|
||||
if (res.ok) {
|
||||
msg.channel.send('Value has been set successfully');
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
{
|
||||
level: 3,
|
||||
usage: ['config get', 'config get {key}', 'config set {key} {value}'],
|
||||
hidden: true,
|
||||
}
|
||||
);
|
|
@ -1,5 +1,5 @@
|
|||
import { Command } from '../Command';
|
||||
import { parseUser } from '../../util/parseUser';
|
||||
import { Command } from '@plugins/Command';
|
||||
import { parseUser } from '@util/parseUser';
|
||||
|
||||
export const command = new Command(
|
||||
'role',
|
31
src/plugins/admin/roles.ts
Normal file
31
src/plugins/admin/roles.ts
Normal file
|
@ -0,0 +1,31 @@
|
|||
import { Command } from '@plugins/Command';
|
||||
|
||||
export const command = new Command(
|
||||
'roles',
|
||||
async (lifeguard, msg) => {
|
||||
const roleList = msg.guild?.roles
|
||||
?.sort((ra, rb) => rb.position - ra.position)
|
||||
.map(r => `${r.id} - ${r.name} (${r.members.size} members)`);
|
||||
const blocks: string[] = [''];
|
||||
|
||||
roleList?.forEach(r => {
|
||||
let currentBlockIndex: number = blocks.length - 1;
|
||||
|
||||
if (
|
||||
blocks[currentBlockIndex].length > 1990 ||
|
||||
blocks[currentBlockIndex].concat(`\n${r}`).length > 1990
|
||||
) {
|
||||
blocks.push('');
|
||||
currentBlockIndex++;
|
||||
}
|
||||
|
||||
blocks[currentBlockIndex] += `\n${r}`;
|
||||
});
|
||||
|
||||
blocks.forEach(b => msg.channel.send(`\`\`\`dns${b}\`\`\``));
|
||||
},
|
||||
{
|
||||
level: 1,
|
||||
usage: ['roles'],
|
||||
}
|
||||
);
|
33
src/plugins/admin/slowmode.ts
Normal file
33
src/plugins/admin/slowmode.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
import { Command } from '@plugins/Command';
|
||||
import { TextChannel } from 'discord.js';
|
||||
|
||||
export const command = new Command(
|
||||
'slowmode',
|
||||
async (lifeguard, msg, args) => {
|
||||
const [cmd, time] = args;
|
||||
switch (cmd) {
|
||||
case 'set':
|
||||
if (msg.guild) {
|
||||
(msg.channel as TextChannel).setRateLimitPerUser(+time);
|
||||
msg.channel.send(
|
||||
`Slowmode has been set to 1 message every ${time} seconds`
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'off':
|
||||
if (msg.guild) {
|
||||
(msg.channel as TextChannel).setRateLimitPerUser(0);
|
||||
msg.channel.send(`Slowmode has been turned off`);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
{
|
||||
level: 1,
|
||||
usage: ['slowmode set {time}', 'slowmode off'],
|
||||
}
|
||||
);
|
|
@ -1,5 +1,5 @@
|
|||
import { Command } from '../Command';
|
||||
import { defaultEmbed } from '../../util/DefaultEmbed';
|
||||
import { Command } from '@plugins/Command';
|
||||
import { defaultEmbed } from '@util/DefaultEmbed';
|
||||
|
||||
export const command = new Command(
|
||||
'ping',
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Command } from '../Command';
|
||||
import { Command } from '@plugins/Command';
|
||||
import { defaultEmbed } from '@util/DefaultEmbed';
|
||||
import { inspect } from 'util';
|
||||
import { runInNewContext } from 'vm';
|
||||
import { defaultEmbed } from '../../util/DefaultEmbed';
|
||||
|
||||
function parseBlock(script: string) {
|
||||
const cbr = /^(([ \t]*`{3,4})([^\n]*)([\s\S]+?)(^[ \t]*\2))/gm;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Command } from '../Command';
|
||||
import { parseUser } from '../../util/parseUser';
|
||||
import { Command } from '@plugins/Command';
|
||||
import { parseUser } from '@util/parseUser';
|
||||
|
||||
export const command = new Command(
|
||||
'blacklist',
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { Command } from '../Command';
|
||||
import { promisify } from 'util';
|
||||
import { Command } from '@plugins/Command';
|
||||
import { exec } from 'child_process';
|
||||
import { resolve } from 'path';
|
||||
import { MessageEmbed } from 'discord.js';
|
||||
import { resolve } from 'path';
|
||||
import { promisify } from 'util';
|
||||
|
||||
export const command = new Command(
|
||||
'about',
|
||||
|
@ -23,7 +23,9 @@ export const command = new Command(
|
|||
const { version: discordjsVersion } = require('discord.js/package.json');
|
||||
|
||||
// Get Lifeguard Version
|
||||
const { version: lifeguardVersion } = require('../../../../package.json');
|
||||
const {
|
||||
version: lifeguardVersion,
|
||||
} = require('@lifeguard/base/package.json');
|
||||
|
||||
const embed = new MessageEmbed()
|
||||
.setTitle('About Lifeguard')
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { Command } from '../Command';
|
||||
import { MessageEmbed, Collection, GuildMember, Guild } from 'discord.js';
|
||||
import { Plugin } from '../Plugin';
|
||||
import { calcUserLevel } from '../../assertions/userLevel';
|
||||
import { defaultEmbed } from '../../util/DefaultEmbed';
|
||||
import { calcUserLevel } from '@assertions/userLevel';
|
||||
import { Command } from '@plugins/Command';
|
||||
import { Plugin } from '@plugins/Plugin';
|
||||
import { defaultEmbed } from '@util/DefaultEmbed';
|
||||
import { Collection, Guild, GuildMember } from 'discord.js';
|
||||
|
||||
function convertPlugins(
|
||||
plugins: Collection<string, Plugin>,
|
||||
|
@ -39,8 +39,6 @@ export const command = new Command(
|
|||
);
|
||||
|
||||
for (const plugin of plugins) {
|
||||
// console.log(plugin)
|
||||
// embed.addField(plugin.name, plugin.cmds.join('\n'));
|
||||
if (plugin.cmds.length > 0) {
|
||||
embed.addField(plugin.name, plugin.cmds.join('\n'));
|
||||
}
|
||||
|
|
55
src/plugins/moderation/ban.ts
Normal file
55
src/plugins/moderation/ban.ts
Normal file
|
@ -0,0 +1,55 @@
|
|||
import { UserInfraction } from '@models/User';
|
||||
import { Command } from '@plugins/Command';
|
||||
import { parseUser } from '@util/parseUser';
|
||||
|
||||
export const command = new Command(
|
||||
'ban',
|
||||
async (lifeguard, msg, [uid, ...reason]) => {
|
||||
// Parse user id from mention
|
||||
const u = parseUser(uid);
|
||||
try {
|
||||
// Create Infraction
|
||||
const inf: UserInfraction = {
|
||||
action: 'Ban',
|
||||
active: true,
|
||||
guild: msg.guild?.id as string,
|
||||
id: (await lifeguard.db.users.findOne({ id: u }))?.infractions
|
||||
.length as number,
|
||||
moderator: msg.author.id,
|
||||
reason: reason.join(' '),
|
||||
time: new Date(),
|
||||
};
|
||||
|
||||
// Update User in Database
|
||||
await lifeguard.db.users.findOneAndUpdate(
|
||||
{ id: u },
|
||||
{ $push: { infractions: inf } },
|
||||
{ returnOriginal: false }
|
||||
);
|
||||
|
||||
// Get User
|
||||
const member = await msg.guild?.members.get(u);
|
||||
// Notify User about Action
|
||||
member?.send(
|
||||
`You have been banned from **${msg.guild?.name}** for \`${
|
||||
reason.length > 0 ? reason.join(' ') : 'No Reason Specified'
|
||||
}\``
|
||||
);
|
||||
// Ban User
|
||||
member?.ban({ reason: reason.join(' ') });
|
||||
|
||||
// Tell moderator action was successful
|
||||
msg.channel.send(
|
||||
`${member?.user.tag} was banned by ${msg.author.tag} for \`${
|
||||
reason.length > 0 ? reason.join(' ') : 'No Reason Specified'
|
||||
}\``
|
||||
);
|
||||
} catch (err) {
|
||||
msg.channel.send(err.message);
|
||||
}
|
||||
},
|
||||
{
|
||||
level: 1,
|
||||
usage: ['ban {user} [reason]'],
|
||||
}
|
||||
);
|
60
src/plugins/moderation/forceban.ts
Normal file
60
src/plugins/moderation/forceban.ts
Normal file
|
@ -0,0 +1,60 @@
|
|||
import { UserInfraction } from '@models/User';
|
||||
import { Command } from '@plugins/Command';
|
||||
import { parseUser } from '@util/parseUser';
|
||||
import { GuildMember, User } from 'discord.js';
|
||||
|
||||
export const command = new Command(
|
||||
'forceban',
|
||||
async (lifeguard, msg, [uid, ...reason]) => {
|
||||
// Parse user id from mention
|
||||
const u = parseUser(uid);
|
||||
try {
|
||||
// Create Infraction
|
||||
const inf: UserInfraction = {
|
||||
action: 'Ban',
|
||||
active: true,
|
||||
guild: msg.guild?.id as string,
|
||||
id: (await lifeguard.db.users.findOne({ id: u }))?.infractions
|
||||
.length as number,
|
||||
moderator: msg.author.id,
|
||||
reason: reason.join(' '),
|
||||
time: new Date(),
|
||||
};
|
||||
|
||||
// Update User in Database
|
||||
await lifeguard.db.users.findOneAndUpdate(
|
||||
{ id: u },
|
||||
{ $push: { infractions: inf } },
|
||||
{ returnOriginal: false }
|
||||
);
|
||||
|
||||
// Ban user from guild
|
||||
const member = await msg.guild?.members.ban(u, {
|
||||
reason: reason.join(' '),
|
||||
});
|
||||
|
||||
// Retreive user tag
|
||||
let tag;
|
||||
if (member instanceof GuildMember) {
|
||||
tag = member.user.tag;
|
||||
} else if (member instanceof User) {
|
||||
tag = member.tag;
|
||||
} else {
|
||||
tag = member;
|
||||
}
|
||||
|
||||
// Tell moderator ban was successful
|
||||
msg.channel.send(
|
||||
`${tag} was force-banned by ${msg.author.toString()} for \`${
|
||||
reason.length > 0 ? reason.join(' ') : 'No Reason Specified'
|
||||
}\``
|
||||
);
|
||||
} catch (err) {
|
||||
msg.channel.send(err.message);
|
||||
}
|
||||
},
|
||||
{
|
||||
level: 1,
|
||||
usage: ['forceban {user} [reason]'],
|
||||
}
|
||||
);
|
54
src/plugins/moderation/infractions.ts
Normal file
54
src/plugins/moderation/infractions.ts
Normal file
|
@ -0,0 +1,54 @@
|
|||
import { Command } from '@plugins/Command';
|
||||
import { parseUser } from '@util/parseUser';
|
||||
import { MessageAttachment } from 'discord.js';
|
||||
|
||||
export const command = new Command(
|
||||
'infractions',
|
||||
async (lifeguard, msg, [cmd, ...args], dbUser) => {
|
||||
switch (cmd) {
|
||||
case 'archive':
|
||||
// Get users from Database that have infractions
|
||||
const dbUsers = lifeguard.db.users.find({
|
||||
infractions: { $elemMatch: { guild: msg.guild?.id } },
|
||||
});
|
||||
|
||||
const guildInfractions = (
|
||||
await dbUsers
|
||||
// Filter out infractions not from current guild
|
||||
.map(u => u.infractions.filter(inf => inf.guild === msg.guild?.id))
|
||||
.toArray()
|
||||
)
|
||||
// Flatten Array
|
||||
.reduce((acc, val) => acc.concat(val), []);
|
||||
|
||||
// Send archive as JSON file
|
||||
msg.channel.send(
|
||||
new MessageAttachment(
|
||||
Buffer.from(JSON.stringify(guildInfractions, null, 2)),
|
||||
`${msg.guild?.id}.infractions.json`
|
||||
)
|
||||
);
|
||||
break;
|
||||
|
||||
case 'info':
|
||||
const [user, infID] = args;
|
||||
const u = parseUser(user);
|
||||
const dbUser = await lifeguard.db.users.findOne({ id: u });
|
||||
const inf = dbUser?.infractions.find(inf => inf.id === +infID);
|
||||
msg.channel.send(`\`\`\`json\n${JSON.stringify(inf, null, 2)}\n\`\`\``);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
{
|
||||
level: 1,
|
||||
usage: [
|
||||
'infractions archive',
|
||||
'infractions search {user}',
|
||||
'infractions info {user} {id}',
|
||||
],
|
||||
alias: ['inf'],
|
||||
}
|
||||
);
|
55
src/plugins/moderation/kick.ts
Normal file
55
src/plugins/moderation/kick.ts
Normal file
|
@ -0,0 +1,55 @@
|
|||
import { UserInfraction } from '@models/User';
|
||||
import { Command } from '@plugins/Command';
|
||||
import { parseUser } from '@util/parseUser';
|
||||
|
||||
export const command = new Command(
|
||||
'kick',
|
||||
async (lifeguard, msg, [uid, ...reason]) => {
|
||||
// Parse user id from mention
|
||||
const u = parseUser(uid);
|
||||
try {
|
||||
// Create Infraction
|
||||
const inf: UserInfraction = {
|
||||
action: 'Kick',
|
||||
active: true,
|
||||
guild: msg.guild?.id as string,
|
||||
id: (await lifeguard.db.users.findOne({ id: u }))?.infractions
|
||||
.length as number,
|
||||
moderator: msg.author.id,
|
||||
reason: reason.join(' '),
|
||||
time: new Date(),
|
||||
};
|
||||
|
||||
// Update User in Database
|
||||
await lifeguard.db.users.findOneAndUpdate(
|
||||
{ id: u },
|
||||
{ $push: { infractions: inf } },
|
||||
{ returnOriginal: false }
|
||||
);
|
||||
|
||||
// Get User
|
||||
const member = await msg.guild?.members.get(u);
|
||||
// Notify User about Action
|
||||
member?.send(
|
||||
`You have been kicked from **${msg.guild?.name}** for \`${reason.join(
|
||||
' '
|
||||
)}\``
|
||||
);
|
||||
// Ban the User
|
||||
member?.kick(reason.join(' '));
|
||||
|
||||
// Tell moderator action was successful
|
||||
msg.channel.send(
|
||||
`${member?.user.tag} was kicked by ${msg.author.tag} for \`${
|
||||
reason.length > 0 ? reason.join(' ') : 'No Reason Specified'
|
||||
}\``
|
||||
);
|
||||
} catch (err) {
|
||||
msg.channel.send(err.message);
|
||||
}
|
||||
},
|
||||
{
|
||||
level: 1,
|
||||
usage: ['kick {user} [reason]'],
|
||||
}
|
||||
);
|
20
src/plugins/moderation/mban.ts
Normal file
20
src/plugins/moderation/mban.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { Command } from '@plugins/Command';
|
||||
import { command as ban } from '@plugins/moderation/ban';
|
||||
|
||||
export const command = new Command(
|
||||
'mban',
|
||||
async (lifeguard, msg, args) => {
|
||||
// Find where '-r' is in the args
|
||||
const reasonFlagIndex = args.indexOf('-r') || args.length;
|
||||
// Get users from args
|
||||
const users = args.slice(0, reasonFlagIndex);
|
||||
// Get reason from args
|
||||
const reason = args.slice(reasonFlagIndex + 1).join(' ');
|
||||
// Run ban command for each user
|
||||
users.forEach(user => ban.func(lifeguard, msg, [user, reason]));
|
||||
},
|
||||
{
|
||||
level: 1,
|
||||
usage: ['mban {users} -r [reason]'],
|
||||
}
|
||||
);
|
20
src/plugins/moderation/mkick.ts
Normal file
20
src/plugins/moderation/mkick.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { Command } from '@plugins/Command';
|
||||
import { command as kick } from '@plugins/moderation/kick';
|
||||
|
||||
export const command = new Command(
|
||||
'mkick',
|
||||
async (lifeguard, msg, args) => {
|
||||
// Find where '-r' is in the args
|
||||
const reasonFlagIndex = args.indexOf('-r');
|
||||
// Get users from args
|
||||
const uids = args.slice(0, reasonFlagIndex);
|
||||
// Get reason from args
|
||||
const reason = args.slice(reasonFlagIndex + 1).join(' ');
|
||||
// Run ban command for each user
|
||||
uids.forEach(uid => kick.func(lifeguard, msg, [uid, reason]));
|
||||
},
|
||||
{
|
||||
level: 1,
|
||||
usage: ['mkick {users} -r [reason]'],
|
||||
}
|
||||
);
|
59
src/plugins/moderation/mute.ts
Normal file
59
src/plugins/moderation/mute.ts
Normal file
|
@ -0,0 +1,59 @@
|
|||
import { UserInfraction } from '@models/User';
|
||||
import { Command } from '@plugins/Command';
|
||||
import { defaultEmbed } from '@util/DefaultEmbed';
|
||||
import { parseUser } from '@util/parseUser';
|
||||
|
||||
export const command = new Command(
|
||||
'mute',
|
||||
async (lifeguard, msg, [uid, ...reason]) => {
|
||||
// Get guild from db
|
||||
const guild = await lifeguard.db.guilds.findOne({ id: msg.guild?.id });
|
||||
// Check if muted role exists
|
||||
if (guild?.config.roles?.muted) {
|
||||
// Parse user id from mention
|
||||
const u = parseUser(uid);
|
||||
try {
|
||||
// Create Infracrion
|
||||
const inf: UserInfraction = {
|
||||
action: 'Mute',
|
||||
active: true,
|
||||
guild: msg.guild?.id as string,
|
||||
id: (await lifeguard.db.users.findOne({ id: u }))?.infractions
|
||||
.length as number,
|
||||
moderator: msg.author.id,
|
||||
reason: reason.join(' '),
|
||||
time: new Date(),
|
||||
};
|
||||
// Update User in Database
|
||||
await lifeguard.db.users.findOneAndUpdate(
|
||||
{ id: u },
|
||||
{ $push: { infractions: inf } },
|
||||
{ returnOriginal: false }
|
||||
);
|
||||
|
||||
// Get User
|
||||
const member = msg.guild?.members.get(u);
|
||||
// Add role to user
|
||||
await member?.roles.add(guild.config.roles.muted);
|
||||
|
||||
// Tell moderator action was successfull
|
||||
msg.channel.send(
|
||||
`${member?.user.tag} was muted by ${msg.author.tag} for \`${
|
||||
reason.length > 0 ? reason.join(' ') : 'No Reason Specified'
|
||||
}\``
|
||||
);
|
||||
} catch (err) {
|
||||
msg.channel.send(err.message);
|
||||
}
|
||||
} else {
|
||||
const embed = defaultEmbed()
|
||||
.setTitle(':rotating_light: Error! :rotating_light:')
|
||||
.setDescription('No mute role configured!');
|
||||
msg.channel.send(embed);
|
||||
}
|
||||
},
|
||||
{
|
||||
level: 1,
|
||||
usage: ['mute {user} [reason]'],
|
||||
}
|
||||
);
|
57
src/plugins/moderation/softban.ts
Normal file
57
src/plugins/moderation/softban.ts
Normal file
|
@ -0,0 +1,57 @@
|
|||
import { UserInfraction } from '@models/User';
|
||||
import { Command } from '@plugins/Command';
|
||||
import { parseUser } from '@util/parseUser';
|
||||
|
||||
export const command = new Command(
|
||||
'softban',
|
||||
async (lifeguard, msg, [uid, ...reason]) => {
|
||||
// Parse user id from mention
|
||||
const u = parseUser(uid);
|
||||
try {
|
||||
// Create Infraction
|
||||
const inf: UserInfraction = {
|
||||
action: 'Ban',
|
||||
active: true,
|
||||
guild: msg.guild?.id as string,
|
||||
id: (await lifeguard.db.users.findOne({ id: u }))?.infractions
|
||||
.length as number,
|
||||
moderator: msg.author.id,
|
||||
reason: reason.join(' '),
|
||||
time: new Date(),
|
||||
};
|
||||
|
||||
// Update User in Database
|
||||
await lifeguard.db.users.findOneAndUpdate(
|
||||
{ id: u },
|
||||
{ $push: { infractions: inf } },
|
||||
{ returnOriginal: false }
|
||||
);
|
||||
|
||||
// Get User
|
||||
const member = await msg.guild?.members.get(u);
|
||||
// Notify user of action
|
||||
member?.send(
|
||||
`You have been soft-banned from **${msg.guild?.name}** for \`${
|
||||
reason.length > 0 ? reason.join(' ') : 'No Reason Specified'
|
||||
}`
|
||||
);
|
||||
// Ban User
|
||||
member?.ban({ reason: reason.join(' '), days: 7 });
|
||||
// Unban User
|
||||
await msg.guild?.members.unban(u, reason.join(' '));
|
||||
|
||||
// Tell moderator action was successfull
|
||||
msg.channel.send(
|
||||
`${member?.user.tag} was soft-banned by ${msg.author.tag} for \`${
|
||||
reason.length > 0 ? reason.join(' ') : 'No Reason Specified'
|
||||
}`
|
||||
);
|
||||
} catch (err) {
|
||||
msg.channel.send(err.message);
|
||||
}
|
||||
},
|
||||
{
|
||||
level: 1,
|
||||
usage: ['softban {user} [reason]'],
|
||||
}
|
||||
);
|
39
src/plugins/moderation/unmute.ts
Normal file
39
src/plugins/moderation/unmute.ts
Normal file
|
@ -0,0 +1,39 @@
|
|||
import { Command } from '@plugins/Command';
|
||||
import { defaultEmbed } from '@util/DefaultEmbed';
|
||||
import { parseUser } from '@util/parseUser';
|
||||
|
||||
export const command = new Command(
|
||||
'unmute',
|
||||
async (lifeguard, msg, [uid, ...reason]) => {
|
||||
// Get guild from database
|
||||
const guild = await lifeguard.db.guilds.findOne({ id: msg.guild?.id });
|
||||
// Check if muted role exists
|
||||
if (guild?.config.roles?.muted) {
|
||||
// Parse user id from mention
|
||||
const u = parseUser(uid);
|
||||
try {
|
||||
// Get User
|
||||
const member = msg.guild?.members.get(u);
|
||||
// Remove Role
|
||||
await member?.roles.remove(guild.config.roles.muted);
|
||||
// Tell moderator action was successfull
|
||||
msg.channel.send(
|
||||
`${member?.user.tag} was unmuted by ${msg.author.tag} for \`${
|
||||
reason.length > 0 ? reason.join(' ') : 'No Reason Specified'
|
||||
}\``
|
||||
);
|
||||
} catch (err) {
|
||||
msg.channel.send(err.message);
|
||||
}
|
||||
} else {
|
||||
const embed = defaultEmbed()
|
||||
.setTitle(':rotating_light: Error! :rotating_light:')
|
||||
.setDescription('No mute role configured!');
|
||||
msg.channel.send(embed);
|
||||
}
|
||||
},
|
||||
{
|
||||
level: 1,
|
||||
usage: ['unmute {user} [reason]'],
|
||||
}
|
||||
);
|
47
src/plugins/moderation/warn.ts
Normal file
47
src/plugins/moderation/warn.ts
Normal file
|
@ -0,0 +1,47 @@
|
|||
import { UserInfraction } from '@models/User';
|
||||
import { Command } from '@plugins/Command';
|
||||
import { parseUser } from '@util/parseUser';
|
||||
|
||||
export const command = new Command(
|
||||
'warn',
|
||||
async (lifeguard, msg, [uid, ...reason]) => {
|
||||
// Parse user id from mention
|
||||
const u = parseUser(uid);
|
||||
try {
|
||||
// Create Infracion
|
||||
const inf: UserInfraction = {
|
||||
action: 'Warn',
|
||||
active: true,
|
||||
guild: msg.guild?.id as string,
|
||||
id: (await lifeguard.db.users.findOne({ id: u }))?.infractions
|
||||
.length as number,
|
||||
moderator: msg.author.id,
|
||||
reason: reason.join(' '),
|
||||
time: new Date(),
|
||||
};
|
||||
|
||||
// Update User in Database
|
||||
await lifeguard.db.users.findOneAndUpdate(
|
||||
{ id: u },
|
||||
{ $push: { infractions: inf } },
|
||||
{ returnOriginal: false }
|
||||
);
|
||||
|
||||
// Get User
|
||||
const member = msg.guild?.members.get(u);
|
||||
|
||||
// Tell moderator action was sucessfull
|
||||
msg.channel.send(
|
||||
`${member?.user.tag} was warned by ${msg.author.tag} for \`${
|
||||
reason.length > 0 ? reason.join(' ') : 'No Reason Specified'
|
||||
}\``
|
||||
);
|
||||
} catch (err) {
|
||||
msg.channel.send(err.message);
|
||||
}
|
||||
},
|
||||
{
|
||||
level: 1,
|
||||
usage: ['warn {user} [reason]'],
|
||||
}
|
||||
);
|
29
src/structures/GuildMember.ts
Normal file
29
src/structures/GuildMember.ts
Normal file
|
@ -0,0 +1,29 @@
|
|||
import { Structures, Guild, GuildMember } from 'discord.js';
|
||||
import { PluginClient } from 'PluginClient';
|
||||
import { inspect } from 'util';
|
||||
|
||||
Structures.extend('GuildMember', guildMember => {
|
||||
return class extends guildMember {
|
||||
_client: PluginClient;
|
||||
constructor(client: PluginClient, data: object, guild: Guild) {
|
||||
super(client, data, guild);
|
||||
this._client = client;
|
||||
}
|
||||
|
||||
get db() {
|
||||
return this._client.db.users.findOne({ id: this.user.id });
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
export class GuildMemberStructure extends GuildMember {
|
||||
_client: PluginClient;
|
||||
constructor(client: PluginClient, data: object, guild: Guild) {
|
||||
super(client, data, guild);
|
||||
this._client = client;
|
||||
}
|
||||
|
||||
get db() {
|
||||
return this._client.db.users.findOne({ id: this.user.id });
|
||||
}
|
||||
}
|
29
src/structures/GuildStructure.ts
Normal file
29
src/structures/GuildStructure.ts
Normal file
|
@ -0,0 +1,29 @@
|
|||
import { Structures, Guild } from 'discord.js';
|
||||
import { PluginClient } from 'PluginClient';
|
||||
import { inspect } from 'util';
|
||||
|
||||
Structures.extend('Guild', guildClass => {
|
||||
return class extends guildClass {
|
||||
_client: PluginClient;
|
||||
constructor(client: PluginClient, data: object) {
|
||||
super(client, data);
|
||||
this._client = client;
|
||||
}
|
||||
|
||||
get db() {
|
||||
return this._client.db.guilds.findOne({ id: this.id });
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
export class GuildStructure extends Guild {
|
||||
_client: PluginClient;
|
||||
constructor(client: PluginClient, data: object) {
|
||||
super(client, data);
|
||||
this._client = client;
|
||||
}
|
||||
|
||||
get db() {
|
||||
return this._client.db.guilds.findOne({ id: this.id });
|
||||
}
|
||||
}
|
11
src/structures/structureLoader.ts
Normal file
11
src/structures/structureLoader.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { readdirSync } from 'fs';
|
||||
|
||||
export function StructureLoader() {
|
||||
const structureFiles = readdirSync('./build/src/structures');
|
||||
|
||||
for (const file of structureFiles) {
|
||||
if (file !== 'structureLoader.js' && file.endsWith('js')) {
|
||||
require(`./${file}`);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
import { connect, Db, MongoClientOptions } from 'mongodb';
|
||||
import { connect, Db, MongoClientOptions, Collection } from 'mongodb';
|
||||
import { User } from '../models/User';
|
||||
import { Guild } from '../models/Guild';
|
||||
|
||||
interface DatabaseConfig {
|
||||
url: string;
|
||||
|
@ -20,11 +22,11 @@ export class Database {
|
|||
this.db = client.db(this.config.name);
|
||||
}
|
||||
|
||||
get guilds() {
|
||||
get guilds(): Collection<Guild> {
|
||||
return this.db.collection('guilds');
|
||||
}
|
||||
|
||||
get users() {
|
||||
get users(): Collection<User> {
|
||||
return this.db.collection('users');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,10 +2,19 @@
|
|||
"extends": "./node_modules/gts/tsconfig-google.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": ".",
|
||||
"outDir": "build"
|
||||
"outDir": "build",
|
||||
"baseUrl": "./src",
|
||||
"paths": {
|
||||
"@lifeguard/*": ["./*"],
|
||||
"@lifegaurd/base/*": ["../*"],
|
||||
"@assertions/*": ["./assertions/*"],
|
||||
"@config/*": ["./config/*"],
|
||||
"@events/*": ["./events/*"],
|
||||
"@models/*": ["./models/*"],
|
||||
"@plugins/*": ["./plugins/*"],
|
||||
"@structures/*": ["./structures/*"],
|
||||
"@util/*": ["./util/*"]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"test/**/*.ts"
|
||||
]
|
||||
"include": ["src/**/*.ts", "test/**/*.ts"]
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue