Files
SupportBot/Structures/Database.js
T

247 lines
6.5 KiB
JavaScript
Raw Normal View History

2026-08-06 17:29:37 +01:00
// SupportBot | JSON fallback adapter for environments without native addons (Pterodactyl)
const fs = require("fs");
2025-09-20 23:09:22 +01:00
const path = require("path");
2026-08-06 17:29:37 +01:00
const DB_PATH = path.join(__dirname, "../Data/supportbot.json");
function load() {
2026-03-10 20:02:43 +00:00
try {
2026-08-06 17:29:37 +01:00
const raw = fs.readFileSync(DB_PATH, "utf8");
return JSON.parse(raw);
2026-03-10 20:02:43 +00:00
} catch (e) {
2026-08-06 17:29:37 +01:00
return {
suggestions: {},
profiles: {},
tickets: {},
ticket_panel: [],
ticket_users: {},
settings: {},
};
2025-09-20 23:09:22 +01:00
}
2026-08-06 17:29:37 +01:00
}
2026-03-10 20:02:43 +00:00
2026-08-06 17:29:37 +01:00
function save(state) {
try {
fs.mkdirSync(path.dirname(DB_PATH), { recursive: true });
fs.writeFileSync(DB_PATH, JSON.stringify(state, null, 2), "utf8");
} catch (e) {
console.error("Failed to persist database:", e);
}
}
const state = load();
2025-09-20 23:09:22 +01:00
2026-03-10 20:02:43 +00:00
function ensureProfile(userId) {
2026-08-06 17:29:37 +01:00
if (!state.profiles[userId]) {
state.profiles[userId] = { user_id: userId, bio: "", timezone: "", clockedIn: 0 };
save(state);
2026-03-10 20:02:43 +00:00
}
}
2025-09-20 23:09:22 +01:00
2026-03-11 18:58:15 +00:00
function normaliseTicketRow(row) {
if (!row) return null;
let questionAnswers = [];
if (row.questionAnswers) {
try {
questionAnswers = JSON.parse(row.questionAnswers);
} catch {
questionAnswers = [];
}
}
return {
...row,
aiModeEnabled: Boolean(row.aiModeEnabled),
2026-08-06 17:29:37 +01:00
clockedIn: row.clockedIn !== undefined ? Boolean(row.clockedIn) : row.clockedIn,
2026-03-11 18:58:15 +00:00
questionAnswers,
};
}
2026-03-10 20:02:43 +00:00
module.exports = {
2025-09-20 23:09:22 +01:00
addTicket(ticket) {
const now = Date.now();
2026-08-06 17:29:37 +01:00
const id = ticket.id;
state.tickets[id] = state.tickets[id] || {};
const existing = state.tickets[id];
2026-03-10 20:02:43 +00:00
2026-08-06 17:29:37 +01:00
state.tickets[id] = {
ticket_id: id,
2025-09-20 23:09:22 +01:00
user_id: ticket.user,
subject: ticket.reason || "",
description: ticket.description || "",
2026-08-06 17:29:37 +01:00
created_at: existing.created_at || now,
2026-03-10 20:02:43 +00:00
updated_at: now,
department: ticket.department || "general",
priority: ticket.priority || "medium",
2026-03-11 18:58:15 +00:00
aiModeEnabled: ticket.aiModeEnabled ? 1 : 0,
aiChannelId: ticket.aiChannelId || null,
aiType: ticket.aiType || null,
aiEnabledBy: ticket.aiEnabledBy || null,
aiEnabledAt: ticket.aiEnabledAt || null,
questionAnswers: JSON.stringify(ticket.questionAnswers || []),
ticketName: ticket.name || null,
ticketNumber: ticket.number || null,
2026-08-06 17:29:37 +01:00
status: existing.status || "open",
};
save(state);
2026-08-06 16:30:04 +01:00
if (global.apiServer) {
global.apiServer.broadcast("ticket_created", {
2026-08-06 17:29:37 +01:00
ticket_id: id,
2026-08-06 16:30:04 +01:00
user_id: ticket.user,
subject: ticket.reason || "",
description: ticket.description || "",
department: ticket.department || "general",
priority: ticket.priority || "medium",
2026-08-06 17:29:37 +01:00
created_at: now,
2026-08-06 16:30:04 +01:00
});
}
2026-03-11 18:58:15 +00:00
},
updateTicketQuestionAnswers(ticketId, questionAnswers = []) {
2026-08-06 17:29:37 +01:00
const t = state.tickets[ticketId];
if (!t) return;
t.questionAnswers = JSON.stringify(questionAnswers);
t.updated_at = Date.now();
save(state);
2025-09-20 23:09:22 +01:00
},
updateTicketVoice(ticketId, voiceChannelId) {
2026-08-06 17:29:37 +01:00
const t = state.tickets[ticketId];
if (!t) return;
t.voiceChannelId = voiceChannelId;
t.updated_at = Date.now();
save(state);
2025-09-20 23:09:22 +01:00
},
2026-03-10 20:02:43 +00:00
updateTicketStatus(ticketId, status) {
2026-08-06 17:29:37 +01:00
const t = state.tickets[ticketId];
if (!t) return;
t.status = status;
t.updated_at = Date.now();
save(state);
2026-08-06 16:30:04 +01:00
if (global.apiServer && status === "closed") {
global.apiServer.broadcast("ticket_closed", { ticket_id: ticketId });
}
2025-09-20 23:09:22 +01:00
},
2026-03-10 20:02:43 +00:00
updateTicketDepartment(ticketId, department) {
2026-08-06 17:29:37 +01:00
const t = state.tickets[ticketId];
if (!t) return;
t.department = department;
t.updated_at = Date.now();
save(state);
2025-09-20 23:09:22 +01:00
},
2026-03-10 20:02:43 +00:00
updateTicketPriority(ticketId, priority) {
2026-08-06 17:29:37 +01:00
const t = state.tickets[ticketId];
if (!t) return;
t.priority = priority;
t.updated_at = Date.now();
save(state);
2025-09-20 23:09:22 +01:00
},
2026-03-11 18:58:15 +00:00
setTicketAIState(ticketId, aiState = {}) {
2026-08-06 17:29:37 +01:00
const t = state.tickets[ticketId];
if (!t) return;
t.aiModeEnabled = aiState.enabled ? 1 : 0;
t.aiChannelId = aiState.aiChannelId || null;
t.aiType = aiState.aiType || null;
t.aiEnabledBy = aiState.enabledBy || null;
t.aiEnabledAt = aiState.enabledAt ? new Date(aiState.enabledAt).getTime() : aiState.enabled ? Date.now() : null;
t.updated_at = Date.now();
save(state);
},
enableTicketAI(ticketId, aiChannelId = null, aiType = null, enabledBy = null) {
const t = state.tickets[ticketId];
if (!t) return;
t.aiModeEnabled = 1;
t.aiChannelId = aiChannelId;
t.aiType = aiType;
t.aiEnabledBy = enabledBy;
t.aiEnabledAt = Date.now();
t.updated_at = Date.now();
save(state);
2026-03-11 18:58:15 +00:00
},
disableTicketAI(ticketId) {
2026-08-06 17:29:37 +01:00
const t = state.tickets[ticketId];
if (!t) return;
t.aiModeEnabled = 0;
t.updated_at = Date.now();
save(state);
2026-03-11 18:58:15 +00:00
},
2025-09-20 23:09:22 +01:00
getTicket(ticketId) {
2026-08-06 17:29:37 +01:00
return normaliseTicketRow(state.tickets[ticketId]);
2026-03-11 18:58:15 +00:00
},
getTicketByAIChannel(aiChannelId) {
2026-08-06 17:29:37 +01:00
const keys = Object.keys(state.tickets);
for (const k of keys) {
const t = state.tickets[k];
if (t && t.aiChannelId === aiChannelId) return normaliseTicketRow(t);
}
return null;
2025-09-20 23:09:22 +01:00
},
getAllTickets() {
2026-08-06 17:29:37 +01:00
return Object.values(state.tickets).map(normaliseTicketRow);
2025-09-20 23:09:22 +01:00
},
saveTicketPanel(messageId, channelId) {
2026-08-06 17:29:37 +01:00
state.ticket_panel.push({ id: Date.now(), message_id: messageId, channel_id: channelId, created_at: Date.now() });
save(state);
2025-09-20 23:09:22 +01:00
},
getTicketPanel() {
2026-08-06 17:29:37 +01:00
const arr = state.ticket_panel;
if (!arr || arr.length === 0) return null;
return arr[arr.length - 1];
2025-09-20 23:09:22 +01:00
},
addUserToTicket(ticketId, userId) {
2026-08-06 17:29:37 +01:00
state.ticket_users[ticketId] = state.ticket_users[ticketId] || new Set();
// Sets cannot be serialized directly; store as array
const arr = new Set(state.ticket_users[ticketId]);
arr.add(userId);
state.ticket_users[ticketId] = Array.from(arr);
save(state);
2025-09-20 23:09:22 +01:00
},
removeUserFromTicket(ticketId, userId) {
2026-08-06 17:29:37 +01:00
const arr = new Set(state.ticket_users[ticketId] || []);
arr.delete(userId);
state.ticket_users[ticketId] = Array.from(arr);
save(state);
2025-09-20 23:09:22 +01:00
},
getTicketUsers(ticketId) {
2026-08-06 17:29:37 +01:00
return (state.ticket_users[ticketId] || []).slice();
2025-09-20 23:09:22 +01:00
},
getSettings() {
2026-08-06 17:29:37 +01:00
return state.settings || {};
2025-09-20 23:09:22 +01:00
},
2026-03-10 20:02:43 +00:00
getProfile(userId) {
ensureProfile(userId);
2026-08-06 17:29:37 +01:00
const row = state.profiles[userId];
if (!row) return { user_id: userId, bio: "", timezone: "", clockedIn: false };
return { ...row, clockedIn: Boolean(row.clockedIn) };
2026-03-10 20:02:43 +00:00
},
setClockedIn(userId, clockedIn) {
ensureProfile(userId);
2026-08-06 17:29:37 +01:00
state.profiles[userId].clockedIn = clockedIn ? 1 : 0;
save(state);
2026-03-10 20:02:43 +00:00
},
2025-09-20 23:09:22 +01:00
saveSettings(obj) {
2026-08-06 17:29:37 +01:00
state.settings = obj || {};
save(state);
2026-03-10 20:02:43 +00:00
},
2025-09-20 23:09:22 +01:00
};