mirror of
https://github.com/yuzu-emu/Command-fix.git
synced 2024-12-23 04:45:29 +00:00
meta: enable stricter type checking
This commit is contained in:
parent
b42c3eaf88
commit
0ee8068198
|
@ -13,9 +13,14 @@ export function command (message: discord.Message) {
|
||||||
state.logChannel.send(`${message.author.toString()} has banned ${user} ${user.toString()} [${count}].`);
|
state.logChannel.send(`${message.author.toString()} has banned ${user} ${user.toString()} [${count}].`);
|
||||||
|
|
||||||
state.bans.push(new UserBan(user.id, user.username, message.author.id, message.author.username, count));
|
state.bans.push(new UserBan(user.id, user.username, message.author.id, message.author.username, count));
|
||||||
|
let member = message.guild?.member(user);
|
||||||
message.guild.member(user).ban().catch(function (error) {
|
if (!member) {
|
||||||
state.logChannel.send(`Error banning ${user} ${user.username}`);
|
state.logChannel.send(`Error banning ${user} ${user.username}: user not found.`);
|
||||||
|
logger.error(`User not found: ${user.toString()} ${user} ${user.username} when executing a ban`);
|
||||||
|
// we don't need a return here, because of the optional chaining below
|
||||||
|
}
|
||||||
|
member?.ban().catch(function (error) {
|
||||||
|
state.logChannel.send(`Error banning ${user.toString()} ${user.username}`);
|
||||||
logger.error(`Error banning ${user.toString()} ${user} ${user.username}.`, error);
|
logger.error(`Error banning ${user.toString()} ${user} ${user.username}.`, error);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,11 @@ const compatStrings: ICompatList = {
|
||||||
|
|
||||||
async function updateDatabase () {
|
async function updateDatabase () {
|
||||||
let body;
|
let body;
|
||||||
|
if (!targetServer) {
|
||||||
|
logger.error('Unable to download latest games list!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let response = await fetch(targetServer);
|
let response = await fetch(targetServer);
|
||||||
body = await response.json();
|
body = await response.json();
|
||||||
|
@ -50,7 +55,7 @@ export async function command (message: discord.Message) {
|
||||||
// Update remote list of games locally.
|
// Update remote list of games locally.
|
||||||
const waitMessage = message.channel.send('This will take a second...');
|
const waitMessage = message.channel.send('This will take a second...');
|
||||||
|
|
||||||
if (state.gameDBPromise == null) {
|
if (!state.gameDBPromise) {
|
||||||
state.gameDBPromise = updateDatabase();
|
state.gameDBPromise = updateDatabase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,16 +73,18 @@ export async function command (message: discord.Message) {
|
||||||
const game = message.content.substr(message.content.indexOf(' ') + 1);
|
const game = message.content.substr(message.content.indexOf(' ') + 1);
|
||||||
|
|
||||||
// Search all games. This is only linear time, so /shrug?
|
// Search all games. This is only linear time, so /shrug?
|
||||||
let bestGame: IGameDBEntry;
|
let bestGame: IGameDBEntry | null = null;
|
||||||
let bestScore = 0.5; // Game names must have at least a 50% similarity to be matched
|
let bestScore = 0.5; // Game names must have at least a 50% similarity to be matched
|
||||||
|
|
||||||
state.gameDB.forEach(testGame => {
|
// for is faster than forEach
|
||||||
|
for (let index = 0; index < state.gameDB.length; index++) {
|
||||||
|
const testGame = state.gameDB[index];
|
||||||
const newDistance = stringSimilarity.compareTwoStrings(game.toLowerCase(), testGame.title.toLowerCase());
|
const newDistance = stringSimilarity.compareTwoStrings(game.toLowerCase(), testGame.title.toLowerCase());
|
||||||
if (newDistance > bestScore) {
|
if (newDistance > bestScore) {
|
||||||
bestGame = testGame;
|
bestGame = testGame;
|
||||||
bestScore = newDistance;
|
bestScore = newDistance;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
if (!bestGame) {
|
if (!bestGame) {
|
||||||
message.channel.send('Game could not be found.');
|
message.channel.send('Game could not be found.');
|
||||||
|
|
|
@ -5,19 +5,30 @@ import discord = require('discord.js');
|
||||||
export const roles = ['Admins', 'Moderators', 'CitraBot'];
|
export const roles = ['Admins', 'Moderators', 'CitraBot'];
|
||||||
export function command (message: discord.Message) {
|
export function command (message: discord.Message) {
|
||||||
const role = process.env.DISCORD_DEVELOPER_ROLE;
|
const role = process.env.DISCORD_DEVELOPER_ROLE;
|
||||||
|
|
||||||
|
if (!role) {
|
||||||
|
logger.error('DISCORD_DEVELOPER_ROLE suddenly became undefined?!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
message.mentions.users.map((user) => {
|
message.mentions.users.map((user) => {
|
||||||
const member = message.guild.member(user);
|
const member = message.guild?.member(user);
|
||||||
const alreadyJoined = member.roles.cache.has(role);
|
const alreadyJoined = member?.roles.cache.has(role);
|
||||||
|
|
||||||
|
if (!member) {
|
||||||
|
message.channel.send(`User ${user.toString()} was not found in the channel.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (alreadyJoined) {
|
if (alreadyJoined) {
|
||||||
member.roles.remove(role).then(() => {
|
member?.roles.remove(role).then(() => {
|
||||||
message.channel.send(`${user.toString()}'s speech has been revoked in the #development channel.`);
|
message.channel.send(`${user.toString()}'s speech has been revoked in the #development channel.`);
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
state.logChannel.send(`Error revoking ${user.toString()}'s developer speech...`);
|
state.logChannel.send(`Error revoking ${user.toString()}'s developer speech...`);
|
||||||
logger.error(`Error revoking ${user} ${user.username}'s developer speech...`);
|
logger.error(`Error revoking ${user} ${user.username}'s developer speech...`);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
member.roles.add(role).then(() => {
|
member?.roles.add(role).then(() => {
|
||||||
message.channel.send(`${user.toString()} has been granted speech in the #development channel.`);
|
message.channel.send(`${user.toString()} has been granted speech in the #development channel.`);
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
state.logChannel.send(`Error granting ${user.toString()}'s developer speech...`);
|
state.logChannel.send(`Error granting ${user.toString()}'s developer speech...`);
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { Message } from 'discord.js';
|
||||||
|
|
||||||
export interface IGameDBEntry {
|
export interface IGameDBEntry {
|
||||||
directory: string;
|
directory: string;
|
||||||
title: string;
|
title: string;
|
||||||
|
@ -14,8 +16,13 @@ export interface ICompatList {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IResponses {
|
export interface IResponses {
|
||||||
pmReply: string,
|
readonly pmReply: string,
|
||||||
quotes: {
|
readonly quotes: {
|
||||||
[key: string]: { reply: string }
|
readonly [key: string]: { readonly reply: string }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IModule {
|
||||||
|
readonly roles?: string[],
|
||||||
|
command: (message: Message, args: string) => void | Promise<void>
|
||||||
|
}
|
||||||
|
|
|
@ -18,10 +18,17 @@ interface IModuleMap {
|
||||||
|
|
||||||
let cachedModules: IModuleMap = {};
|
let cachedModules: IModuleMap = {};
|
||||||
const client = new discord.Client();
|
const client = new discord.Client();
|
||||||
|
const rulesTrigger = process.env.DISCORD_RULES_TRIGGER;
|
||||||
|
const rluesRole = process.env.DISCORD_RULES_ROLE;
|
||||||
const mediaUsers = new Map();
|
const mediaUsers = new Map();
|
||||||
|
|
||||||
logger.info('Application startup. Configuring environment.');
|
logger.info('Application startup. Configuring environment.');
|
||||||
|
if (!rulesTrigger) {
|
||||||
|
throw new Error('DISCORD_RULES_TRIGGER somehow became undefined.');
|
||||||
|
}
|
||||||
|
if (!rluesRole) {
|
||||||
|
throw new Error('DISCORD_RULES_ROLE somehow became undefined.');
|
||||||
|
}
|
||||||
|
|
||||||
function findArray(haystack: string | any[], arr: any[]) {
|
function findArray(haystack: string | any[], arr: any[]) {
|
||||||
return arr.some(function (v: any) {
|
return arr.some(function (v: any) {
|
||||||
|
@ -36,6 +43,9 @@ function IsIgnoredCategory(categoryName: string) {
|
||||||
|
|
||||||
client.on('ready', async () => {
|
client.on('ready', async () => {
|
||||||
// Initialize app channels.
|
// Initialize app channels.
|
||||||
|
if (!process.env.DISCORD_LOG_CHANNEL || !process.env.DISCORD_MSGLOG_CHANNEL) {
|
||||||
|
throw new Error('DISCORD_LOG_CHANNEL or DISCORD_MSGLOG_CHANNEL not defined.');
|
||||||
|
}
|
||||||
let logChannel = await client.channels.fetch(process.env.DISCORD_LOG_CHANNEL) as discord.TextChannel;
|
let logChannel = await client.channels.fetch(process.env.DISCORD_LOG_CHANNEL) as discord.TextChannel;
|
||||||
let msglogChannel = await client.channels.fetch(process.env.DISCORD_MSGLOG_CHANNEL) as discord.TextChannel;
|
let msglogChannel = await client.channels.fetch(process.env.DISCORD_MSGLOG_CHANNEL) as discord.TextChannel;
|
||||||
if (!logChannel.send) throw new Error('DISCORD_LOG_CHANNEL is not a text channel!');
|
if (!logChannel.send) throw new Error('DISCORD_LOG_CHANNEL is not a text channel!');
|
||||||
|
@ -62,15 +72,16 @@ client.on('disconnect', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
client.on('guildMemberAdd', (member) => {
|
client.on('guildMemberAdd', (member) => {
|
||||||
|
if (process.env.DISCORD_RULES_ROLE)
|
||||||
member.roles.add(process.env.DISCORD_RULES_ROLE);
|
member.roles.add(process.env.DISCORD_RULES_ROLE);
|
||||||
});
|
});
|
||||||
|
|
||||||
client.on('messageDelete', message => {
|
client.on('messageDelete', message => {
|
||||||
let parent = (message.channel as discord.TextChannel).parent;
|
let parent = (message.channel as discord.TextChannel).parent;
|
||||||
if (parent && IsIgnoredCategory(parent.name) === false) {
|
if (parent && IsIgnoredCategory(parent.name) === false) {
|
||||||
if (message.content && message.content.startsWith('.') === false && message.author.bot === false) {
|
if (message.content && message.content.startsWith('.') === false && message.author?.bot === false) {
|
||||||
const deletionEmbed = new discord.MessageEmbed()
|
const deletionEmbed = new discord.MessageEmbed()
|
||||||
.setAuthor(message.author.tag, message.author.displayAvatarURL())
|
.setAuthor(message.author?.tag, message.author?.displayAvatarURL())
|
||||||
.setDescription(`Message deleted in ${message.channel.toString()}`)
|
.setDescription(`Message deleted in ${message.channel.toString()}`)
|
||||||
.addField('Content', message.cleanContent, false)
|
.addField('Content', message.cleanContent, false)
|
||||||
.setTimestamp()
|
.setTimestamp()
|
||||||
|
@ -84,14 +95,19 @@ client.on('messageDelete', message => {
|
||||||
|
|
||||||
client.on('messageUpdate', (oldMessage, newMessage) => {
|
client.on('messageUpdate', (oldMessage, newMessage) => {
|
||||||
const AllowedRoles = ['Administrators', 'Moderators', 'Team', 'VIP'];
|
const AllowedRoles = ['Administrators', 'Moderators', 'Team', 'VIP'];
|
||||||
if (!findArray(oldMessage.member.roles.cache.map(x => x.name), AllowedRoles)) {
|
let authorRoles = oldMessage.member?.roles?.cache?.map(x => x.name);
|
||||||
|
if (!authorRoles) {
|
||||||
|
logger.error(`Unable to get the roles for ${oldMessage.author}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!findArray(authorRoles, AllowedRoles)) {
|
||||||
let parent = (oldMessage.channel as discord.TextChannel).parent;
|
let parent = (oldMessage.channel as discord.TextChannel).parent;
|
||||||
if (parent && IsIgnoredCategory(parent.name) === false) {
|
if (parent && IsIgnoredCategory(parent.name) === false) {
|
||||||
const oldM = oldMessage.cleanContent;
|
const oldM = oldMessage.cleanContent;
|
||||||
const newM = newMessage.cleanContent;
|
const newM = newMessage.cleanContent;
|
||||||
if (oldMessage.content !== newMessage.content && oldM && newM) {
|
if (oldMessage.content !== newMessage.content && oldM && newM) {
|
||||||
const editedEmbed = new discord.MessageEmbed()
|
const editedEmbed = new discord.MessageEmbed()
|
||||||
.setAuthor(oldMessage.author.tag, oldMessage.author.displayAvatarURL())
|
.setAuthor(oldMessage.author?.tag, oldMessage.author?.displayAvatarURL())
|
||||||
.setDescription(`Message edited in ${oldMessage.channel.toString()} [Jump To Message](${newMessage.url})`)
|
.setDescription(`Message edited in ${oldMessage.channel.toString()} [Jump To Message](${newMessage.url})`)
|
||||||
.addField('Before', oldM, false)
|
.addField('Before', oldM, false)
|
||||||
.addField('After', newM, false)
|
.addField('After', newM, false)
|
||||||
|
@ -99,7 +115,7 @@ client.on('messageUpdate', (oldMessage, newMessage) => {
|
||||||
.setColor('GREEN');
|
.setColor('GREEN');
|
||||||
|
|
||||||
state.msglogChannel.send(editedEmbed);
|
state.msglogChannel.send(editedEmbed);
|
||||||
logger.info(`${oldMessage.author.username} ${oldMessage.author} edited message from: ${oldM} to: ${newM}.`);
|
logger.info(`${oldMessage.author?.username} ${oldMessage.author} edited message from: ${oldM} to: ${newM}.`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -118,9 +134,15 @@ client.on('message', message => {
|
||||||
|
|
||||||
logger.verbose(`${message.author.username} ${message.author} [Channel: ${(message.channel as discord.TextChannel).name} ${message.channel}]: ${message.content}`);
|
logger.verbose(`${message.author.username} ${message.author} [Channel: ${(message.channel as discord.TextChannel).name} ${message.channel}]: ${message.content}`);
|
||||||
|
|
||||||
|
let authorRoles = message.member?.roles?.cache?.map(x => x.name);
|
||||||
|
|
||||||
if (message.channel.id === process.env.DISCORD_MEDIA_CHANNEL && !message.author.bot) {
|
if (message.channel.id === process.env.DISCORD_MEDIA_CHANNEL && !message.author.bot) {
|
||||||
const AllowedMediaRoles = ['Administrators', 'Moderators', 'Team', 'VIP'];
|
const AllowedMediaRoles = ['Administrators', 'Moderators', 'Team', 'VIP'];
|
||||||
if (!findArray(message.member.roles.cache.map(x => x.name), AllowedMediaRoles)) {
|
if (!authorRoles) {
|
||||||
|
logger.error(`Unable to get the roles for ${message.author}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!findArray(authorRoles, AllowedMediaRoles)) {
|
||||||
const urlRegex = new RegExp(/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,4}\b([-a-zA-Z0-9@:%_+.~#?&//=]*)/gi);
|
const urlRegex = new RegExp(/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,4}\b([-a-zA-Z0-9@:%_+.~#?&//=]*)/gi);
|
||||||
if (message.attachments.size > 0 || message.content.match(urlRegex)) {
|
if (message.attachments.size > 0 || message.content.match(urlRegex)) {
|
||||||
mediaUsers.set(message.author.id, true);
|
mediaUsers.set(message.author.id, true);
|
||||||
|
@ -135,10 +157,10 @@ client.on('message', message => {
|
||||||
|
|
||||||
// Check if the channel is #rules, if so we want to follow a different logic flow.
|
// Check if the channel is #rules, if so we want to follow a different logic flow.
|
||||||
if (message.channel.id === process.env.DISCORD_RULES_CHANNEL) {
|
if (message.channel.id === process.env.DISCORD_RULES_CHANNEL) {
|
||||||
if (message.content.toLowerCase().includes(process.env.DISCORD_RULES_TRIGGER)) {
|
if (message.content.toLowerCase().includes(rulesTrigger)) {
|
||||||
// We want to remove the 'Unauthorized' role from them once they agree to the rules.
|
// We want to remove the 'Unauthorized' role from them once they agree to the rules.
|
||||||
logger.verbose(`${message.author.username} ${message.author} has accepted the rules, removing role ${process.env.DISCORD_RULES_ROLE}.`);
|
logger.verbose(`${message.author.username} ${message.author} has accepted the rules, removing role ${process.env.DISCORD_RULES_ROLE}.`);
|
||||||
message.member.roles.remove(process.env.DISCORD_RULES_ROLE, 'Accepted the rules.');
|
message.member?.roles.remove(rluesRole, 'Accepted the rules.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete the message in the channel to force a cleanup.
|
// Delete the message in the channel to force a cleanup.
|
||||||
|
@ -155,7 +177,11 @@ client.on('message', message => {
|
||||||
if (!cachedModule && !quoteResponse) return; // Not a valid command.
|
if (!cachedModule && !quoteResponse) return; // Not a valid command.
|
||||||
|
|
||||||
// Check access permissions.
|
// Check access permissions.
|
||||||
if (cachedModule && cachedModule.roles && !findArray(message.member.roles.cache.map(x => x.name), cachedModule.roles)) {
|
if (!authorRoles) {
|
||||||
|
logger.error(`Unable to get the roles for ${message.author}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (cachedModule && cachedModule.roles && !findArray(authorRoles, cachedModule.roles)) {
|
||||||
state.logChannel.send(`${message.author.toString()} attempted to use admin command: ${message.content}`);
|
state.logChannel.send(`${message.author.toString()} attempted to use admin command: ${message.content}`);
|
||||||
logger.info(`${message.author.username} ${message.author} attempted to use admin command: ${message.content}`);
|
logger.info(`${message.author.username} ${message.author} attempted to use admin command: ${message.content}`);
|
||||||
return;
|
return;
|
||||||
|
@ -168,7 +194,7 @@ client.on('message', message => {
|
||||||
if (!!cachedModule) {
|
if (!!cachedModule) {
|
||||||
cachedModule.command(message);
|
cachedModule.command(message);
|
||||||
} else if (cachedModules['quote']) {
|
} else if (cachedModules['quote']) {
|
||||||
cachedModules['quote'].command(message, quoteResponse.reply);
|
cachedModules['quote'].command(message, quoteResponse?.reply);
|
||||||
}
|
}
|
||||||
} catch (err) { logger.error(err); }
|
} catch (err) { logger.error(err); }
|
||||||
|
|
||||||
|
|
|
@ -13,13 +13,13 @@ class State {
|
||||||
stats: { joins: number; ruleAccepts: number; leaves: number; warnings: number; };
|
stats: { joins: number; ruleAccepts: number; leaves: number; warnings: number; };
|
||||||
lastGameDBUpdate: number;
|
lastGameDBUpdate: number;
|
||||||
gameDB: IGameDBEntry[];
|
gameDB: IGameDBEntry[];
|
||||||
gameDBPromise: Promise<void>;
|
gameDBPromise: Promise<void> | null;
|
||||||
|
|
||||||
constructor () {
|
constructor () {
|
||||||
this.logChannel = null;
|
this.logChannel;
|
||||||
this.msglogChannel = null;
|
this.msglogChannel;
|
||||||
this.warnings = [];
|
this.warnings = [];
|
||||||
this.responses = null;
|
this.responses;
|
||||||
this.bans = [];
|
this.bans = [];
|
||||||
this.stats = {
|
this.stats = {
|
||||||
joins: 0,
|
joins: 0,
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"module": "CommonJS",
|
"module": "CommonJS",
|
||||||
"noImplicitAny": true,
|
"noImplicitAny": true,
|
||||||
|
"strictNullChecks": true,
|
||||||
"removeComments": true,
|
"removeComments": true,
|
||||||
"preserveConstEnums": true,
|
"preserveConstEnums": true,
|
||||||
"outDir": "dist/",
|
"outDir": "dist/",
|
||||||
|
|
Loading…
Reference in a new issue