import { getRepository, In, InsertResult, Repository } from "typeorm"; import { BaseGuildRepository } from "./BaseGuildRepository"; import { CaseTypes } from "./CaseTypes"; import { connection } from "./db"; import { Case } from "./entities/Case"; import { CaseNote } from "./entities/CaseNote"; import moment = require("moment-timezone"); import { Queue } from "../Queue"; const CASE_SUMMARY_REASON_MAX_LENGTH = 300; export class GuildCases extends BaseGuildRepository { private cases: Repository<Case>; private caseNotes: Repository<CaseNote>; protected createQueue: Queue; constructor(guildId) { super(guildId); this.cases = getRepository(Case); this.caseNotes = getRepository(CaseNote); this.createQueue = new Queue(); } async get(ids: number[]): Promise<Case[]> { return this.cases.find({ relations: this.getRelations(), where: { guild_id: this.guildId, id: In(ids), }, }); } async find(id: number): Promise<Case | undefined> { return this.cases.findOne({ relations: this.getRelations(), where: { guild_id: this.guildId, id, }, }); } async findByCaseNumber(caseNumber: number): Promise<Case | undefined> { return this.cases.findOne({ relations: this.getRelations(), where: { guild_id: this.guildId, case_number: caseNumber, }, }); } async findLatestByModId(modId: string): Promise<Case | undefined> { return this.cases.findOne({ relations: this.getRelations(), where: { guild_id: this.guildId, mod_id: modId, }, order: { case_number: "DESC", }, }); } async findByAuditLogId(auditLogId: string): Promise<Case | undefined> { return this.cases.findOne({ relations: this.getRelations(), where: { guild_id: this.guildId, audit_log_id: auditLogId, }, }); } async getByUserId(userId: string): Promise<Case[]> { return this.cases.find({ relations: this.getRelations(), where: { guild_id: this.guildId, user_id: userId, }, }); } async getTotalCasesByModId(modId: string): Promise<number> { return this.cases.count({ where: { guild_id: this.guildId, mod_id: modId, is_hidden: 0, }, }); } async getRecentByModId(modId: string, count: number, skip = 0): Promise<Case[]> { return this.cases.find({ relations: this.getRelations(), where: { guild_id: this.guildId, mod_id: modId, is_hidden: 0, }, skip, take: count, order: { case_number: "DESC", }, }); } async setHidden(id: number, hidden: boolean): Promise<void> { await this.cases.update( { id }, { is_hidden: hidden, }, ); } async createInternal(data): Promise<InsertResult> { return this.createQueue.add(async () => { const lastCaseNumberRow = await this.cases .createQueryBuilder() .select(["MAX(case_number) AS last_case_number"]) .where("guild_id = :guildId", { guildId: this.guildId }) .getRawOne(); const lastCaseNumber = lastCaseNumberRow?.last_case_number || 0; return this.cases .insert({ case_number: lastCaseNumber + 1, ...data, guild_id: this.guildId, }) .catch((err) => { if (err?.code === "ER_DUP_ENTRY") { if (data.audit_log_id) { console.trace(`Tried to insert case with duplicate audit_log_id`); return this.createInternal({ ...data, audit_log_id: undefined, }); } } throw err; }); }); } async create(data): Promise<Case> { const result = await this.createInternal(data); return (await this.find(result.identifiers[0].id))!; } update(id, data) { return this.cases.update(id, data); } async softDelete(id: number, deletedById: string, deletedByName: string, deletedByText: string) { return connection.transaction(async (entityManager) => { const cases = entityManager.getRepository(Case); const caseNotes = entityManager.getRepository(CaseNote); await Promise.all([ caseNotes.delete({ case_id: id, }), cases.update(id, { user_id: "0", user_name: "Unknown#0000", mod_id: null, mod_name: "Unknown#0000", type: CaseTypes.Deleted, audit_log_id: null, is_hidden: false, pp_id: null, pp_name: null, }), ]); await caseNotes.insert({ case_id: id, mod_id: deletedById, mod_name: deletedByName, body: deletedByText, }); }); } async createNote(caseId: number, data: any): Promise<void> { await this.caseNotes.insert({ ...data, case_id: caseId, }); } }