248 lines
6.5 KiB
JavaScript
248 lines
6.5 KiB
JavaScript
// SupportBot | JSON fallback adapter for environments without native addons (Pterodactyl)
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
|
|
const DB_PATH = path.join(__dirname, "../Data/supportbot.json");
|
|
|
|
function load() {
|
|
try {
|
|
const raw = fs.readFileSync(DB_PATH, "utf8");
|
|
return JSON.parse(raw);
|
|
} catch (e) {
|
|
return {
|
|
suggestions: {},
|
|
profiles: {},
|
|
tickets: {},
|
|
ticket_panel: [],
|
|
ticket_users: {},
|
|
settings: {},
|
|
};
|
|
}
|
|
}
|
|
|
|
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();
|
|
|
|
function ensureProfile(userId) {
|
|
if (!state.profiles[userId]) {
|
|
state.profiles[userId] = { user_id: userId, bio: "", timezone: "", clockedIn: 0 };
|
|
save(state);
|
|
}
|
|
}
|
|
|
|
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),
|
|
clockedIn: row.clockedIn !== undefined ? Boolean(row.clockedIn) : row.clockedIn,
|
|
questionAnswers,
|
|
};
|
|
}
|
|
|
|
module.exports = {
|
|
addTicket(ticket) {
|
|
const now = Date.now();
|
|
const id = ticket.id;
|
|
state.tickets[id] = state.tickets[id] || {};
|
|
const existing = state.tickets[id];
|
|
|
|
state.tickets[id] = {
|
|
ticket_id: id,
|
|
user_id: ticket.user,
|
|
subject: ticket.reason || "",
|
|
description: ticket.description || "",
|
|
created_at: existing.created_at || now,
|
|
updated_at: now,
|
|
department: ticket.department || "general",
|
|
priority: ticket.priority || "medium",
|
|
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,
|
|
status: existing.status || "open",
|
|
};
|
|
|
|
save(state);
|
|
|
|
if (global.apiServer) {
|
|
global.apiServer.broadcast("ticket_created", {
|
|
ticket_id: id,
|
|
user_id: ticket.user,
|
|
subject: ticket.reason || "",
|
|
description: ticket.description || "",
|
|
department: ticket.department || "general",
|
|
priority: ticket.priority || "medium",
|
|
created_at: now,
|
|
});
|
|
}
|
|
},
|
|
|
|
updateTicketQuestionAnswers(ticketId, questionAnswers = []) {
|
|
const t = state.tickets[ticketId];
|
|
if (!t) return;
|
|
t.questionAnswers = JSON.stringify(questionAnswers);
|
|
t.updated_at = Date.now();
|
|
save(state);
|
|
},
|
|
|
|
updateTicketVoice(ticketId, voiceChannelId) {
|
|
const t = state.tickets[ticketId];
|
|
if (!t) return;
|
|
t.voiceChannelId = voiceChannelId;
|
|
t.updated_at = Date.now();
|
|
save(state);
|
|
},
|
|
|
|
updateTicketStatus(ticketId, status) {
|
|
const t = state.tickets[ticketId];
|
|
if (!t) return;
|
|
t.status = status;
|
|
t.updated_at = Date.now();
|
|
save(state);
|
|
|
|
if (global.apiServer && status === "closed") {
|
|
global.apiServer.broadcast("ticket_closed", { ticket_id: ticketId });
|
|
}
|
|
},
|
|
|
|
updateTicketDepartment(ticketId, department) {
|
|
const t = state.tickets[ticketId];
|
|
if (!t) return;
|
|
t.department = department;
|
|
t.updated_at = Date.now();
|
|
save(state);
|
|
},
|
|
|
|
updateTicketPriority(ticketId, priority) {
|
|
const t = state.tickets[ticketId];
|
|
if (!t) return;
|
|
t.priority = priority;
|
|
t.updated_at = Date.now();
|
|
save(state);
|
|
},
|
|
|
|
setTicketAIState(ticketId, aiState = {}) {
|
|
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);
|
|
},
|
|
|
|
disableTicketAI(ticketId) {
|
|
const t = state.tickets[ticketId];
|
|
if (!t) return;
|
|
t.aiModeEnabled = 0;
|
|
t.updated_at = Date.now();
|
|
save(state);
|
|
},
|
|
|
|
getTicket(ticketId) {
|
|
return normaliseTicketRow(state.tickets[ticketId]);
|
|
},
|
|
|
|
getTicketByAIChannel(aiChannelId) {
|
|
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;
|
|
},
|
|
|
|
getAllTickets() {
|
|
return Object.values(state.tickets).map(normaliseTicketRow);
|
|
},
|
|
|
|
saveTicketPanel(messageId, channelId) {
|
|
state.ticket_panel.push({ id: Date.now(), message_id: messageId, channel_id: channelId, created_at: Date.now() });
|
|
save(state);
|
|
},
|
|
|
|
getTicketPanel() {
|
|
const arr = state.ticket_panel;
|
|
if (!arr || arr.length === 0) return null;
|
|
return arr[arr.length - 1];
|
|
},
|
|
|
|
addUserToTicket(ticketId, userId) {
|
|
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);
|
|
},
|
|
|
|
removeUserFromTicket(ticketId, userId) {
|
|
const arr = new Set(state.ticket_users[ticketId] || []);
|
|
arr.delete(userId);
|
|
state.ticket_users[ticketId] = Array.from(arr);
|
|
save(state);
|
|
},
|
|
|
|
getTicketUsers(ticketId) {
|
|
return (state.ticket_users[ticketId] || []).slice();
|
|
},
|
|
|
|
getSettings() {
|
|
return state.settings || {};
|
|
},
|
|
|
|
getProfile(userId) {
|
|
ensureProfile(userId);
|
|
const row = state.profiles[userId];
|
|
if (!row) return { user_id: userId, bio: "", timezone: "", clockedIn: false };
|
|
return { ...row, clockedIn: Boolean(row.clockedIn) };
|
|
},
|
|
|
|
setClockedIn(userId, clockedIn) {
|
|
ensureProfile(userId);
|
|
state.profiles[userId].clockedIn = clockedIn ? 1 : 0;
|
|
save(state);
|
|
},
|
|
|
|
saveSettings(obj) {
|
|
state.settings = obj || {};
|
|
save(state);
|
|
},
|
|
};
|