[deploy] add ticket sla, pipeline, automations, kb
All checks were successful
Deploy Discord Bot / deploy (push) Successful in 36s
All checks were successful
Deploy Discord Bot / deploy (push) Successful in 36s
This commit is contained in:
103
src/services/ticketAutomationService.ts
Normal file
103
src/services/ticketAutomationService.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
import { prisma } from '../database';
|
||||
import { context } from '../config/context';
|
||||
import { TextChannel } from 'discord.js';
|
||||
|
||||
type AutomationCondition = {
|
||||
category?: string;
|
||||
status?: string;
|
||||
minHours?: number;
|
||||
};
|
||||
|
||||
type AutomationAction = {
|
||||
type: 'pingRole' | 'reminder' | 'flag';
|
||||
roleId?: string;
|
||||
message?: string;
|
||||
status?: string;
|
||||
};
|
||||
|
||||
export class TicketAutomationService {
|
||||
public async list(guildId: string) {
|
||||
return prisma.ticketAutomationRule.findMany({ where: { guildId }, orderBy: { createdAt: 'asc' } });
|
||||
}
|
||||
|
||||
public async save(rule: {
|
||||
id?: string;
|
||||
guildId: string;
|
||||
name: string;
|
||||
condition: AutomationCondition;
|
||||
action: AutomationAction;
|
||||
active?: boolean;
|
||||
}) {
|
||||
if (rule.id) {
|
||||
return prisma.ticketAutomationRule.update({
|
||||
where: { id: rule.id },
|
||||
data: {
|
||||
name: rule.name,
|
||||
condition: rule.condition,
|
||||
action: rule.action,
|
||||
active: rule.active ?? true
|
||||
}
|
||||
});
|
||||
}
|
||||
return prisma.ticketAutomationRule.create({
|
||||
data: {
|
||||
guildId: rule.guildId,
|
||||
name: rule.name,
|
||||
condition: rule.condition,
|
||||
action: rule.action,
|
||||
active: rule.active ?? true
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public async remove(guildId: string, id: string) {
|
||||
const found = await prisma.ticketAutomationRule.findFirst({ where: { id, guildId } });
|
||||
if (!found) return false;
|
||||
await prisma.ticketAutomationRule.delete({ where: { id } });
|
||||
return true;
|
||||
}
|
||||
|
||||
public async checkTicket(ticket: any, isScheduled = false) {
|
||||
const rules = await prisma.ticketAutomationRule.findMany({ where: { guildId: ticket.guildId, active: true }, take: 50 });
|
||||
if (!rules.length) return;
|
||||
const guild = context.client?.guilds.cache.get(ticket.guildId) ?? (await context.client?.guilds.fetch(ticket.guildId).catch(() => null));
|
||||
if (!guild) return;
|
||||
const channel = ticket.channelId ? await guild.channels.fetch(ticket.channelId).catch(() => null) : null;
|
||||
for (const rule of rules) {
|
||||
const cond = (rule.condition as any) || {};
|
||||
const act = (rule.action as any) || {};
|
||||
const matchesCategory =
|
||||
!cond.category || (ticket.topic || '').toLowerCase().includes(String(cond.category).toLowerCase());
|
||||
const matchesStatus = !cond.status || ticket.status === cond.status;
|
||||
const matchesAge =
|
||||
!cond.minHours ||
|
||||
(ticket.createdAt &&
|
||||
Date.now() - new Date(ticket.createdAt).getTime() >= Number(cond.minHours) * 3600 * 1000);
|
||||
if (!matchesCategory || !matchesStatus || !matchesAge) continue;
|
||||
if (act.type === 'pingRole' && channel?.isTextBased() && act.roleId) {
|
||||
await (channel as TextChannel).send({ content: `<@&${act.roleId}> Bitte Ticket pruefen.` }).catch(() => undefined);
|
||||
}
|
||||
if (act.type === 'reminder' && channel?.isTextBased()) {
|
||||
await (channel as TextChannel)
|
||||
.send({ content: act.message || 'Reminder: Ticket ist noch offen.' })
|
||||
.catch(() => undefined);
|
||||
}
|
||||
if (act.type === 'flag' && act.status && ticket.status !== act.status) {
|
||||
await prisma.ticket.update({ where: { id: ticket.id }, data: { status: act.status } }).catch(() => undefined);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public startLoop() {
|
||||
setInterval(() => {
|
||||
const since = new Date(Date.now() - 24 * 60 * 60 * 1000);
|
||||
prisma.ticket
|
||||
.findMany({
|
||||
where: { status: { notIn: ['erledigt', 'closed'] }, createdAt: { lte: since } },
|
||||
take: 50
|
||||
})
|
||||
.then((tickets) => tickets.forEach((t) => this.checkTicket(t, true)))
|
||||
.catch(() => undefined);
|
||||
}, 60_000);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user