Skip to content

Commit

Permalink
feat: implement dwc command (#74)
Browse files Browse the repository at this point in the history
  • Loading branch information
HeadTriXz authored Sep 15, 2023
1 parent 65b0220 commit 65b7a91
Show file tree
Hide file tree
Showing 33 changed files with 2,358 additions and 115 deletions.
11 changes: 11 additions & 0 deletions apps/barry/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,10 @@ enum CaseType {
Mute @map("MUTE")
Kick @map("KICK")
Ban @map("BAN")
DWC
Unmute @map("UNMUTE")
Unban @map("UNBAN")
UnDWC @map("UNDWC")
}

model Case {
Expand Down Expand Up @@ -212,3 +214,12 @@ model TempBan {
@@id([guildID, userID])
@@map("temp_bans")
}

model DWCScheduledBan {
guildID String @map("guild_id")
userID String @map("user_id")
createdAt DateTime @map("created_at") @default(now())
@@id([guildID, userID])
@@map("dwc_scheduled_bans")
}
3 changes: 3 additions & 0 deletions apps/barry/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,12 @@ export default {
emotes: {
// Moderation
ban: new Emoji("ban", "1149399269531459616"),
dwc: new Emoji("dwc", "1151425609487106101"),
kick: new Emoji("kick", "1149399337412071484"),
mute: new Emoji("mute", "1149399536381477006"),
note: new Emoji("note", "1149399622398255188"),
unban: new Emoji("unban", "1149399596372607127"),
undwc: new Emoji("undwc", "1151870611203821628"),
unmute: new Emoji("unmute", "1149399568446914670"),
warn: new Emoji("warn", "1149399652504977508"),

Expand All @@ -76,5 +78,6 @@ export default {
previous: new Emoji("previous", "1124406936188768357")
},
defaultColor: 0xFFC331,
defaultDWCColor: 0xFFFF58,
embedColor: 0x2B2D31
};
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,38 @@ export class ProfileRepository {
});
}

/**
* Retrieves the profile record with the flaggable messages for the specified user.
*
* @param guildID The ID of the guild.
* @param userID The ID of the user.
* @param maxDays The amount of days to get profiles for.
* @returns The profile record with messages, or null if not found.
*/
async getWithFlaggableMessages(
guildID: string,
userID: string,
maxDays: number = 14
): Promise<ProfileWithMessages | null> {
const milliseconds = maxDays * 86400000;
const timestamp = BigInt(Date.now() - milliseconds - 1420070400000);
const minimumID = String(timestamp << 22n);

return this.#prisma.profile.findUnique({
include: {
messages: {
where: {
guildID: guildID,
messageID: {
gte: minimumID
}
}
}
},
where: { userID }
});
}

/**
* Retrieves the profile record with its messages for the specified user.
*
Expand Down
64 changes: 64 additions & 0 deletions apps/barry/src/modules/marketplace/dependencies/profiles/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
type APIEmbed,
type APIUser,
ButtonStyle,
ComponentType
Expand All @@ -11,7 +12,10 @@ import {
ProfileRepository,
ProfilesSettingsRepository
} from "./database.js";

import { DiscordAPIError } from "@discordjs/rest";
import { Module } from "@barry/core";
import { getDWCEmbed } from "../../utils.js";
import { getProfileContent } from "./editor/functions/content.js";
import { loadEvents } from "../../../../utils/loadFolder.js";

Expand Down Expand Up @@ -69,6 +73,18 @@ export default class ProfilesModule extends Module<Application> {
this.profilesSettings = new ProfilesSettingsRepository(client.prisma);
}

/**
* Flags all requests for the specified user.
*
* @param guildID The ID of the guild.
* @param channelID The ID of the channel.
* @param user The user to flag the requests of.
* @param reason The reason to flag the user.
*/
async flagUser(guildID: string, channelID: string, user: APIUser, reason: string): Promise<void> {
return this.#resetProfiles(guildID, channelID, user, 14, [getDWCEmbed(reason)]);
}

/**
* Checks if the guild has enabled this module.
*
Expand Down Expand Up @@ -148,4 +164,52 @@ export default class ProfilesModule extends Module<Application> {
}
}
}

/**
* Removes the flag from all profiles for the specified user.
*
* @param guildID The ID of the guild.
* @param channelID The ID of the channel.
* @param user The user to remove the flag of.
*/
async unflagUser(guildID: string, channelID: string, user: APIUser): Promise<void> {
return this.#resetProfiles(guildID, channelID, user, 21);
}

/**
* Resets flagged profiles for a user in a specific guild's channel.
*
* @param guildID The ID of the guild.
* @param channelID The ID of the channel.
* @param user The user for whom the profiles are being reset.
* @param maxDays The maximum number of days ago a request can be to be reset.
* @param embeds Optional array of embed objects to include in the updated messages.
*/
async #resetProfiles(
guildID: string,
channelID: string,
user: APIUser,
maxDays: number = 14,
embeds: APIEmbed[] = []
): Promise<void> {
const profile = await this.profiles.getWithFlaggableMessages(guildID, user.id, maxDays);
if (profile !== null) {
const content = getProfileContent(user, profile);
if (embeds.length > 0) {
content.embeds?.push(...embeds);
}

for (const message of profile.messages) {
try {
await this.client.api.channels.editMessage(channelID, message.messageID, content);
} catch (error: unknown) {
if (error instanceof DiscordAPIError && error.code === 10008) {
continue;
}

this.client.logger.error(error);
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ export interface RequestWithAttachments extends Request {
attachments: RequestAttachment[];
}

/**
* Represents a request with messages.
*/
export interface RequestWithMessages extends Request {
/**
* The messages for the request.
*/
messages: RequestMessage[];
}

/**
* Repository class for managing requests.
*/
Expand Down Expand Up @@ -123,6 +133,49 @@ export class RequestRepository {
});
}

/**
* Retrieves the requests that can be flagged for the specified user.
*
* @param guildID The ID of the guild.
* @param userID The ID of the user.
* @param maxDays The amount of days to get requests for.
* @returns The flaggable request records.
*/
async getFlaggableByUser(
guildID: string,
userID: string,
maxDays: number = 14
): Promise<Array<RequestWithAttachments & RequestWithMessages>> {
const milliseconds = maxDays * 86400000;
const timestamp = BigInt(Date.now() - milliseconds - 1420070400000);
const minimumID = String(timestamp << 22n);

return this.#prisma.request.findMany({
include: {
attachments: true,
messages: {
where: {
guildID: guildID,
messageID: {
gte: minimumID
}
}
}
},
where: {
messages: {
some: {
guildID: guildID,
messageID: {
gte: minimumID
}
}
},
userID: userID
}
});
}

/**
* Upserts a request record for the specified user.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { type APIUser, ButtonStyle, ComponentType } from "@discordjs/core";
import {
type APIEmbed,
type APIUser,
ButtonStyle,
ComponentType
} from "@discordjs/core";
import {
type RequestWithAttachments,
RequestMessageRepository,
Expand All @@ -8,7 +13,9 @@ import {
import type { Application } from "../../../../Application.js";
import type { RequestsSettings } from "@prisma/client";

import { DiscordAPIError } from "@discordjs/rest";
import { Module } from "@barry/core";
import { getDWCEmbed } from "../../utils.js";
import { getRequestContent } from "./editor/functions/content.js";
import { loadEvents } from "../../../../utils/loadFolder.js";

Expand Down Expand Up @@ -55,6 +62,18 @@ export default class RequestsModule extends Module<Application> {
this.requestsSettings = new RequestsSettingsRepository(client.prisma);
}

/**
* Flags all requests for the specified user.
*
* @param guildID The ID of the guild.
* @param channelID The ID of the channel.
* @param user The user to flag the requests of.
* @param reason The reason to flag the user.
*/
async flagUser(guildID: string, channelID: string, user: APIUser, reason: string): Promise<void> {
return this.#resetRequests(guildID, channelID, user, 14, [getDWCEmbed(reason)]);
}

/**
* Checks if the guild has enabled this module.
*
Expand Down Expand Up @@ -150,4 +169,52 @@ export default class RequestsModule extends Module<Application> {
}
}
}

/**
* Removes the flag from all requests for the specified user.
*
* @param guildID The ID of the guild.
* @param channelID The ID of the channel.
* @param user The user to remove the flag of.
*/
async unflagUser(guildID: string, channelID: string, user: APIUser): Promise<void> {
return this.#resetRequests(guildID, channelID, user, 21);
}

/**
* Resets flagged requests for a user in a specific guild's channel.
*
* @param guildID The ID of the guild.
* @param channelID The ID of the channel.
* @param user The user for whom the requests are being reset.
* @param maxDays The maximum number of days ago a request can be to be reset.
* @param embeds Optional array of embed objects to include in the updated messages.
*/
async #resetRequests(
guildID: string,
channelID: string,
user: APIUser,
maxDays: number = 14,
embeds: APIEmbed[] = []
): Promise<void> {
const requests = await this.requests.getFlaggableByUser(guildID, user.id, maxDays);
for (const request of requests) {
const content = getRequestContent(user, request);
if (embeds.length > 0) {
content.embeds?.push(...embeds);
}

for (const message of request.messages) {
try {
await this.client.api.channels.editMessage(channelID, message.messageID, content);
} catch (error: unknown) {
if (error instanceof DiscordAPIError && error.code === 10008) {
continue;
}

this.client.logger.error(error);
}
}
}
}
}
24 changes: 23 additions & 1 deletion apps/barry/src/modules/marketplace/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import type { ReplyableInteraction } from "@barry/core";
import { ButtonStyle, ComponentType, MessageFlags } from "@discordjs/core";
import {
type APIEmbed,
ButtonStyle,
ComponentType,
MessageFlags
} from "@discordjs/core";
import config from "../../config.js";

/**
* Represents a user that can be contacted.
Expand Down Expand Up @@ -83,3 +89,19 @@ export async function displayContact(interaction: ReplyableInteraction, contacta
flags: MessageFlags.Ephemeral
});
}

/**
* Returns the DWC embed for the user.
*
* @param reason The reason the user has been marked as DWC.
*/
export function getDWCEmbed(reason: string): APIEmbed {
return {
author: {
name: "Deal With Caution",
icon_url: config.emotes.error.imageURL
},
description: "This user has been marked as `Deal With Caution`. If you have a business relationship with this person, proceed with caution.\n\n**Reason:**\n" + reason,
color: config.embedColor
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -213,12 +213,14 @@ export default class extends SlashCommand<ModerationModule> {
});

const settings = await this.module.moderationSettings.getOrCreate(interaction.guildID);
await this.module.createLogMessage({
case: entity,
creator: interaction.user,
duration: duration,
reason: options.reason,
user: options.user
}, settings);
if (settings.channelID !== null) {
await this.module.createLogMessage(settings.channelID, {
case: entity,
creator: interaction.user,
duration: duration,
reason: options.reason,
user: options.user
});
}
}
}
Loading

0 comments on commit 65b7a91

Please # to comment.