Rewrite how modpoints are handled
This commit is contained in:
parent
bc787738ac
commit
0a2a37f23e
@ -23,7 +23,7 @@ import {
|
||||
Warn
|
||||
} from '../infractions/index.js';
|
||||
import { CommandOption, Infraction as InfractionClass, Initialisable } from '../interfaces/index.js';
|
||||
import { InvokerWrapper, MemberWrapper, UserWrapper } from './wrappers/index.js';
|
||||
import { GuildWrapper, InvokerWrapper, MemberWrapper, UserWrapper } from './wrappers/index.js';
|
||||
import { InfractionFail, InfractionSuccess } from '../../../@types/Infractions.js';
|
||||
|
||||
|
||||
@ -393,7 +393,7 @@ class ModerationManager implements Initialisable
|
||||
if (infraction.targetType === 'CHANNEL')
|
||||
return verification;
|
||||
|
||||
const oldPoints = await targetUser!.totalPoints(guild);
|
||||
const oldPoints = await this.calculatePoints(targetUser!, guild);
|
||||
if (infraction.points === null)
|
||||
throw new Error('Null points when they should be defined');
|
||||
const newPoints = oldPoints + infraction.points;
|
||||
@ -498,16 +498,16 @@ class ModerationManager implements Initialisable
|
||||
{
|
||||
if (!targetUser)
|
||||
throw new Error('Missing target user for a user type infraction');
|
||||
response.infraction.totalPoints = await targetUser.totalPoints(guild);
|
||||
response.infraction.totalPoints = await this.calculatePoints(targetUser, guild);
|
||||
response.infraction.totalPoints += points;
|
||||
}
|
||||
const result = await response.infraction.execute();
|
||||
|
||||
// Infraction doesn't have an ID until it is executed, hence this after execute
|
||||
if (response.infraction.targetType === 'USER')
|
||||
await targetUser!.totalPoints(guild, {
|
||||
points, expiration, timestamp: response.infraction.timestamp, id: response.infraction.id
|
||||
});
|
||||
// if (response.infraction.targetType === 'USER')
|
||||
// await targetUser!.totalPoints(guild, {
|
||||
// points, expiration, timestamp: response.infraction.timestamp, id: response.infraction.id
|
||||
// });
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -537,7 +537,7 @@ class ModerationManager implements Initialisable
|
||||
if (!undoClass)
|
||||
return false;
|
||||
|
||||
const guild = this.#client.getGuildWrapper(i.guild!);
|
||||
const guild = await this.#client.getGuildWrapper(i.guild!);
|
||||
if (!guild)
|
||||
throw new Error('Missing guild');
|
||||
// await guild.settings(); //just incase
|
||||
@ -636,7 +636,7 @@ class ModerationManager implements Initialisable
|
||||
{ $set: { _callbacked: true } }
|
||||
).catch((e) =>
|
||||
{
|
||||
this.#logger.error(`Error during update of infraction ${infraction.id}:\n${e.stack || e}\n${e.errInfo}`);
|
||||
this.#logger.error(`Error during update of infraction ${infraction.id}:\n${e.stack || e}\n${inspect(e.errInfo)}`);
|
||||
});
|
||||
const cb = this.#callbacks.get(infraction.id);
|
||||
if (cb)
|
||||
@ -691,6 +691,29 @@ class ModerationManager implements Initialisable
|
||||
return result || null;
|
||||
}
|
||||
|
||||
async calculatePoints (user: UserWrapper, guild: GuildWrapper)
|
||||
{
|
||||
const [ result ] = await this.#client.mongodb.infractions.aggregate([{
|
||||
$match: {
|
||||
target: user.id,
|
||||
guild: guild.id,
|
||||
resolved: false,
|
||||
$or: [{ expiration: { $gt: Date.now() } }, { expiration: 0 }, { expiration: null }],
|
||||
}
|
||||
}, {
|
||||
$group: {
|
||||
_id: null,
|
||||
points: {
|
||||
$sum: '$points'
|
||||
}
|
||||
}
|
||||
}]);
|
||||
let points = 0;
|
||||
if (result)
|
||||
({ points } = result);
|
||||
return points;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ModerationManager;
|
@ -23,7 +23,7 @@ class CaseCommand extends SlashCommand
|
||||
minimum: 0,
|
||||
required: true
|
||||
}, {
|
||||
name: [ 'export', 'verbose', 'changes', 'delete' ], //
|
||||
name: [ 'raw', 'verbose', 'changes', 'delete' ], //
|
||||
type: CommandOptionType.BOOLEAN,
|
||||
description: [
|
||||
'Print out raw infraction data in JSON form',
|
||||
@ -45,7 +45,7 @@ class CaseCommand extends SlashCommand
|
||||
|
||||
async execute (invoker: InvokerWrapper<true>, opts: CommandParams)
|
||||
{
|
||||
const { id, verbose, export: exp, changes, delete: remove } = opts;
|
||||
const { id, verbose, raw, changes, delete: remove } = opts;
|
||||
const guild = invoker.guild!;
|
||||
|
||||
const infraction = await new Infraction(this.client, this.logger, { guild, case: id!.asNumber }).fetch(true).catch(() => null);
|
||||
@ -62,9 +62,9 @@ class CaseCommand extends SlashCommand
|
||||
});
|
||||
return { emoji: 'success', index: 'COMMAND_CASE_DELETED', params: { caseID: id!.asNumber } };
|
||||
}
|
||||
if (exp?.asString)
|
||||
return `\`\`\`js\n${inspect(infraction)}\`\`\``;
|
||||
if (changes?.asString)
|
||||
if (raw?.asBool)
|
||||
return `\`\`\`js\n${inspect(infraction.json)}\`\`\``;
|
||||
if (changes?.asBool)
|
||||
return { embed: await this._listChanges(invoker, infraction.json) };
|
||||
|
||||
const target = infraction.targetType === 'USER' ? await this.client.resolver.resolveUser(infraction.targetId!) : await guild.resolveChannel(infraction.targetId);
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { ImageURLOptions, MessageCreateOptions, MessagePayload, User } from 'discord.js';
|
||||
import DiscordClient from '../../DiscordClient.js';
|
||||
import { UserSettings } from '../../../../@types/Settings.js';
|
||||
import GuildWrapper from './GuildWrapper.js';
|
||||
// import GuildWrapper from './GuildWrapper.js';
|
||||
import { LoggerClient } from '@navy.gif/logger';
|
||||
|
||||
type Expiry = {points: number, expiration: number, id: string}
|
||||
// type Expiry = {points: number, expiration: number, id: string}
|
||||
|
||||
class UserWrapper
|
||||
{
|
||||
@ -12,12 +12,12 @@ class UserWrapper
|
||||
#user: User;
|
||||
|
||||
#settings: UserSettings;
|
||||
#points: {
|
||||
[key: string]: {
|
||||
expirations: Expiry[],
|
||||
points: number
|
||||
}
|
||||
};
|
||||
// #points: {
|
||||
// [key: string]: {
|
||||
// expirations: Expiry[],
|
||||
// points: number
|
||||
// }
|
||||
// };
|
||||
|
||||
#logger: LoggerClient;
|
||||
|
||||
@ -28,7 +28,7 @@ class UserWrapper
|
||||
this.#logger = client.createLogger({ name: `User: ${user.id}` });
|
||||
|
||||
this.#settings = {};
|
||||
this.#points = {};
|
||||
// this.#points = {};
|
||||
}
|
||||
|
||||
async settings (forceFetch = false)
|
||||
@ -44,105 +44,105 @@ class UserWrapper
|
||||
return this.#settings;
|
||||
}
|
||||
|
||||
async fetchPoints (guild: GuildWrapper)
|
||||
{
|
||||
let index = this.#points[guild.id];
|
||||
if (index)
|
||||
return Promise.resolve(index);
|
||||
this.#points[guild.id] = {
|
||||
expirations: [],
|
||||
points: 0
|
||||
};
|
||||
index = this.#points[guild.id];
|
||||
// async fetchPoints (guild: GuildWrapper)
|
||||
// {
|
||||
// let index = this.#points[guild.id];
|
||||
// if (index)
|
||||
// return Promise.resolve(index);
|
||||
// this.#points[guild.id] = {
|
||||
// expirations: [],
|
||||
// points: 0
|
||||
// };
|
||||
// index = this.#points[guild.id];
|
||||
|
||||
const filter = {
|
||||
guild: guild.id,
|
||||
target: this.id,
|
||||
resolved: false,
|
||||
// points: { $gte: 0 },
|
||||
// $or: [{ expiration: 0 }, { expiration: { $gte: now } }]
|
||||
};
|
||||
const find = await this.#client.mongodb.infractions.find(
|
||||
filter,
|
||||
{ projection: { id: 1, points: 1, expiration: 1 } }
|
||||
);
|
||||
// const filter = {
|
||||
// guild: guild.id,
|
||||
// target: this.id,
|
||||
// resolved: false,
|
||||
// // points: { $gte: 0 },
|
||||
// // $or: [{ expiration: 0 }, { expiration: { $gte: now } }]
|
||||
// };
|
||||
// const find = await this.#client.mongodb.infractions.find(
|
||||
// filter,
|
||||
// { projection: { id: 1, points: 1, expiration: 1 } }
|
||||
// );
|
||||
|
||||
if (find.length)
|
||||
{
|
||||
for (const { points: p, expiration, id } of find)
|
||||
{
|
||||
let points = p;
|
||||
// Imported cases may have false or null
|
||||
if (typeof points !== 'number')
|
||||
points = 0;
|
||||
if (expiration > 0)
|
||||
{
|
||||
index.expirations.push({ points, expiration, id });
|
||||
}
|
||||
else
|
||||
{
|
||||
index.points += points;
|
||||
}
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
// if (find.length)
|
||||
// {
|
||||
// for (const { points: p, expiration, id } of find)
|
||||
// {
|
||||
// let points = p;
|
||||
// // Imported cases may have false or null
|
||||
// if (typeof points !== 'number')
|
||||
// points = 0;
|
||||
// if (expiration > 0)
|
||||
// {
|
||||
// index.expirations.push({ points, expiration, id });
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// index.points += points;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return index;
|
||||
// }
|
||||
|
||||
async editPoints (guild: GuildWrapper, { id, diff, expiration }: {id: string, diff: number, expiration: unknown })
|
||||
{
|
||||
const points = await this.fetchPoints(guild);
|
||||
if (expiration)
|
||||
{
|
||||
const expiry = points.expirations.find((exp) => exp.id === id) as Expiry;
|
||||
expiry.points += diff;
|
||||
}
|
||||
else
|
||||
points.points += diff;
|
||||
return this.totalPoints(guild);
|
||||
}
|
||||
// async editPoints (guild: GuildWrapper, { id, diff, expiration }: {id: string, diff: number, expiration: unknown })
|
||||
// {
|
||||
// const points = await this.fetchPoints(guild);
|
||||
// if (expiration)
|
||||
// {
|
||||
// const expiry = points.expirations.find((exp) => exp.id === id) as Expiry;
|
||||
// expiry.points += diff;
|
||||
// }
|
||||
// else
|
||||
// points.points += diff;
|
||||
// return this.totalPoints(guild);
|
||||
// }
|
||||
|
||||
async editExpiration (guild: GuildWrapper, { id, expiration, points }: { id: string, expiration: number, points: number })
|
||||
{
|
||||
const index = await this.fetchPoints(guild);
|
||||
const i = index.expirations.findIndex((exp) => exp.id === id);
|
||||
if (i > -1)
|
||||
index.expirations[i].expiration = expiration;
|
||||
else
|
||||
{
|
||||
index.points -= points;
|
||||
index.expirations.push({ id, points, expiration });
|
||||
}
|
||||
return this.totalPoints(guild);
|
||||
}
|
||||
// async editExpiration (guild: GuildWrapper, { id, expiration, points }: { id: string, expiration: number, points: number })
|
||||
// {
|
||||
// const index = await this.fetchPoints(guild);
|
||||
// const i = index.expirations.findIndex((exp) => exp.id === id);
|
||||
// if (i > -1)
|
||||
// index.expirations[i].expiration = expiration;
|
||||
// else
|
||||
// {
|
||||
// index.points -= points;
|
||||
// index.expirations.push({ id, points, expiration });
|
||||
// }
|
||||
// return this.totalPoints(guild);
|
||||
// }
|
||||
|
||||
async totalPoints (guild: GuildWrapper, point?: { id: string, points: number, expiration: number, timestamp: number })
|
||||
{ // point = { points: x, expiration: x, timestamp: x}
|
||||
const index = await this.fetchPoints(guild);
|
||||
const now = Date.now();
|
||||
// async totalPoints (guild: GuildWrapper, point?: { id: string, points: number, expiration: number, timestamp: number })
|
||||
// { // point = { points: x, expiration: x, timestamp: x}
|
||||
// const index = await this.fetchPoints(guild);
|
||||
// const now = Date.now();
|
||||
|
||||
if (point)
|
||||
{
|
||||
if (point.expiration > 0)
|
||||
{
|
||||
index.expirations.push({ id: point.id, points: point.points, expiration: point.expiration + point.timestamp });
|
||||
}
|
||||
else
|
||||
{
|
||||
index.points += point.points;
|
||||
}
|
||||
}
|
||||
// if (point)
|
||||
// {
|
||||
// if (point.expiration > 0)
|
||||
// {
|
||||
// index.expirations.push({ id: point.id, points: point.points, expiration: point.expiration + point.timestamp });
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// index.points += point.points;
|
||||
// }
|
||||
// }
|
||||
|
||||
let expirationPoints = index.expirations.map((e) =>
|
||||
{
|
||||
if (e.expiration >= now)
|
||||
return e.points;
|
||||
return 0;
|
||||
});
|
||||
// let expirationPoints = index.expirations.map((e) =>
|
||||
// {
|
||||
// if (e.expiration >= now)
|
||||
// return e.points;
|
||||
// return 0;
|
||||
// });
|
||||
|
||||
if (expirationPoints.length === 0)
|
||||
expirationPoints = [ 0 ];
|
||||
return expirationPoints.reduce((p, v) => p + v) + index.points;
|
||||
}
|
||||
// if (expirationPoints.length === 0)
|
||||
// expirationPoints = [ 0 ];
|
||||
// return expirationPoints.reduce((p, v) => p + v) + index.points;
|
||||
// }
|
||||
|
||||
async updateSettings (data: UserSettings)
|
||||
{ // Update property (upsert true) - updateOne
|
||||
|
@ -60,8 +60,6 @@ class UnmuteInfraction extends Infraction
|
||||
now = Date.now();
|
||||
|
||||
let callback = null;
|
||||
// TODO: Make this not rely on a member wrapper
|
||||
const memberWrapper = await this.guild.memberWrapper(this.member!).catch(() => null);
|
||||
if (Object.keys(this.data).length)
|
||||
{
|
||||
removedRoles = this.data.removedRoles!;
|
||||
@ -70,6 +68,8 @@ class UnmuteInfraction extends Infraction
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Make this not rely on a member wrapper
|
||||
const memberWrapper = await this.guild.memberWrapper(this.member!).catch(() => null);
|
||||
callback = await memberWrapper?.getCallback('MUTE');
|
||||
if (callback)
|
||||
{
|
||||
|
@ -143,7 +143,15 @@ class Infraction
|
||||
|
||||
this.#silent = data.silent || false;
|
||||
this.#points = data.points || 0;
|
||||
this.#expiration = typeof data.expiration !== 'undefined' && data.expiration > 0 ? Date.now() + data.expiration : null; // Time when the points expire in milliseconds
|
||||
|
||||
// Null, not set, 0 never expires, otherwise timestamp of when it expires
|
||||
if (typeof data.expiration === 'undefined')
|
||||
this.#expiration = null;
|
||||
else if (data.expiration > 0)
|
||||
this.#expiration = Date.now() + data.expiration;
|
||||
else
|
||||
this.#expiration = 0;
|
||||
// this.#expiration = typeof data.expiration !== 'undefined' && data.expiration > 0 ? Date.now() + data.expiration : null; // Time when the points expire in milliseconds
|
||||
this.#totalPoints = 0;
|
||||
|
||||
this.#data = data.data || {}; // Miscellaneous data that may need to be saved for future use.
|
||||
@ -652,7 +660,7 @@ class Infraction
|
||||
return this._succeed();
|
||||
}
|
||||
|
||||
#error (reason?: string)
|
||||
#errorCheck (reason?: string)
|
||||
{
|
||||
if (!this.#fetched)
|
||||
throw new Error(reason || 'Cannot edit an unfetched infraction');
|
||||
@ -660,7 +668,7 @@ class Infraction
|
||||
|
||||
async updateMessages ()
|
||||
{
|
||||
this.#error('Cannot update messages for unfetched infractions');
|
||||
this.#errorCheck('Cannot update messages for unfetched infractions');
|
||||
// console.log(this._dmLogMessage, this.dmLogMessageId, this.dmLogMessage);
|
||||
if (this.#dmLogMessage)
|
||||
await this.#dmLogMessage.edit({ embeds: [ await this.#embed(true) ] });
|
||||
@ -670,7 +678,7 @@ class Infraction
|
||||
|
||||
async editReason (staff: UserResolveable, reason: string): Promise<InfractionEditResult>
|
||||
{
|
||||
this.#error();
|
||||
this.#errorCheck();
|
||||
const log: InfractionChange = {
|
||||
reason: this.#reason,
|
||||
staff: typeof staff === 'string' ? staff : staff.id,
|
||||
@ -683,7 +691,7 @@ class Infraction
|
||||
|
||||
async editPoints (staff: UserResolveable, points: number): Promise<InfractionEditResult>
|
||||
{
|
||||
this.#error();
|
||||
this.#errorCheck();
|
||||
const settings = await this.#guild.settings();
|
||||
if (this.#targetType !== 'USER')
|
||||
return { error: true, index: 'INFRACTION_EDIT_INVALID_TARGETTYPE' };
|
||||
@ -697,18 +705,19 @@ class Infraction
|
||||
};
|
||||
const diff = points - (this.#points ?? 0);
|
||||
this.#points = points;
|
||||
if (!this.#target)
|
||||
throw new Error('Missing target?');
|
||||
const userWrapper = await this.#client.getUserWrapper(this.#target.id);
|
||||
if (!userWrapper)
|
||||
throw new Error('Missing user wrapper');
|
||||
this.#totalPoints = await userWrapper.editPoints(this.#guild, { diff, id: this.id, expiration: this.#expiration });
|
||||
// if (!this.#target)
|
||||
// throw new Error('Missing target?');
|
||||
// const userWrapper = await this.#client.getUserWrapper(this.#target.id);
|
||||
// if (!userWrapper)
|
||||
// throw new Error('Missing user wrapper');
|
||||
// this.#totalPoints = await userWrapper.editPoints(this.#guild, { diff, id: this.id, expiration: this.#expiration });
|
||||
this.#totalPoints += diff;
|
||||
this.#changes.push(log);
|
||||
}
|
||||
|
||||
async editExpiration (staff: UserResolveable, expiration: number): Promise<InfractionEditResult>
|
||||
{
|
||||
this.#error();
|
||||
this.#errorCheck();
|
||||
const settings = await this.#guild.settings();
|
||||
if (this.#targetType !== 'USER')
|
||||
return { error: true, index: 'INFRACTION_EDIT_INVALID_TARGETTYPE' };
|
||||
@ -724,22 +733,22 @@ class Infraction
|
||||
expiration: this.#expiration ? this.#expiration - this.#timestamp : null
|
||||
};
|
||||
this.#expiration = expiration + this.#timestamp;
|
||||
if (!this.#target)
|
||||
throw new Error('Missing target?');
|
||||
const userWrapper = await this.#client.getUserWrapper(this.#target.id);
|
||||
if (!userWrapper)
|
||||
throw new Error('Missing user wrapper');
|
||||
this.#totalPoints = await userWrapper.editExpiration(this.#guild, {
|
||||
id: this.id,
|
||||
expiration: this.#expiration,
|
||||
points: this.#points
|
||||
});
|
||||
// if (!this.#target)
|
||||
// throw new Error('Missing target?');
|
||||
// const userWrapper = await this.#client.getUserWrapper(this.#target.id);
|
||||
// if (!userWrapper)
|
||||
// throw new Error('Missing user wrapper');
|
||||
// this.#totalPoints = await userWrapper.editExpiration(this.#guild, {
|
||||
// id: this.id,
|
||||
// expiration: this.#expiration,
|
||||
// points: this.#points
|
||||
// });
|
||||
this.#changes.push(log);
|
||||
}
|
||||
|
||||
async editDuration (staff: UserResolveable, duration: number): Promise<InfractionEditResult>
|
||||
{
|
||||
this.#error();
|
||||
this.#errorCheck();
|
||||
if (this.#resolved)
|
||||
return { error: true, index: 'INFRACTION_EDIT_DURATION_RESOLVED' };
|
||||
if (this.#callbacked)
|
||||
|
@ -228,6 +228,7 @@ const FilterPresets: {
|
||||
"restarts",
|
||||
"restarted",
|
||||
"reskin",
|
||||
"refraction",
|
||||
"rated",
|
||||
"suspicious",
|
||||
"racoon",
|
||||
|
Loading…
Reference in New Issue
Block a user