|
|
const { v4 } = require("uuid");const prisma = require("../utils/prisma");const { VALID_CHAT_MODE } = require("../utils/chats/stream");
const EmbedConfig = { writable: [ // Used for generic updates so we can validate keys in request body
"enabled", "allowlist_domains", "allow_model_override", "allow_temperature_override", "allow_prompt_override", "max_chats_per_day", "max_chats_per_session", "chat_mode", "workspace_id", ],
new: async function (data, creatorId = null) { try { const embed = await prisma.embed_configs.create({ data: { uuid: v4(), enabled: true, chat_mode: validatedCreationData(data?.chat_mode, "chat_mode"), allowlist_domains: validatedCreationData( data?.allowlist_domains, "allowlist_domains" ), allow_model_override: validatedCreationData( data?.allow_model_override, "allow_model_override" ), allow_temperature_override: validatedCreationData( data?.allow_temperature_override, "allow_temperature_override" ), allow_prompt_override: validatedCreationData( data?.allow_prompt_override, "allow_prompt_override" ), max_chats_per_day: validatedCreationData( data?.max_chats_per_day, "max_chats_per_day" ), max_chats_per_session: validatedCreationData( data?.max_chats_per_session, "max_chats_per_session" ), createdBy: Number(creatorId) ?? null, workspace: { connect: { id: Number(data.workspace_id) }, }, }, }); return { embed, message: null }; } catch (error) { console.error(error.message); return { embed: null, message: error.message }; } },
update: async function (embedId = null, data = {}) { if (!embedId) throw new Error("No embed id provided for update"); const validKeys = Object.keys(data).filter((key) => this.writable.includes(key) ); if (validKeys.length === 0) return { embed: { id }, message: "No valid fields to update!" };
const updates = {}; validKeys.map((key) => { updates[key] = validatedCreationData(data[key], key); });
try { await prisma.embed_configs.update({ where: { id: Number(embedId) }, data: updates, }); return { success: true, error: null }; } catch (error) { console.error(error.message); return { success: false, error: error.message }; } },
get: async function (clause = {}) { try { const embedConfig = await prisma.embed_configs.findFirst({ where: clause, });
return embedConfig || null; } catch (error) { console.error(error.message); return null; } },
getWithWorkspace: async function (clause = {}) { try { const embedConfig = await prisma.embed_configs.findFirst({ where: clause, include: { workspace: true, }, });
return embedConfig || null; } catch (error) { console.error(error.message); return null; } },
delete: async function (clause = {}) { try { await prisma.embed_configs.delete({ where: clause, }); return true; } catch (error) { console.error(error.message); return false; } },
where: async function (clause = {}, limit = null, orderBy = null) { try { const results = await prisma.embed_configs.findMany({ where: clause, ...(limit !== null ? { take: limit } : {}), ...(orderBy !== null ? { orderBy } : {}), }); return results; } catch (error) { console.error(error.message); return []; } },
whereWithWorkspace: async function ( clause = {}, limit = null, orderBy = null ) { try { const results = await prisma.embed_configs.findMany({ where: clause, include: { workspace: true, _count: { select: { embed_chats: true }, }, }, ...(limit !== null ? { take: limit } : {}), ...(orderBy !== null ? { orderBy } : {}), }); return results; } catch (error) { console.error(error.message); return []; } },
// Will return null if process should be skipped
// an empty array means the system will check. This
// prevents a bad parse from allowing all requests
parseAllowedHosts: function (embed) { if (!embed.allowlist_domains) return null;
try { return JSON.parse(embed.allowlist_domains); } catch { console.error(`Failed to parse allowlist_domains for Embed ${embed.id}!`); return []; } },};
const BOOLEAN_KEYS = [ "allow_model_override", "allow_temperature_override", "allow_prompt_override", "enabled",];
const NUMBER_KEYS = [ "max_chats_per_day", "max_chats_per_session", "workspace_id",];
// Helper to validate a data object strictly into the proper format
function validatedCreationData(value, field) { if (field === "chat_mode") { if (!value || !VALID_CHAT_MODE.includes(value)) return "query"; return value; }
if (field === "allowlist_domains") { try { if (!value) return null; return JSON.stringify( // Iterate and force all domains to URL object
// and stringify the result.
value .split(",") .map((input) => { let url = input; if (!url.includes("http://") && !url.includes("https://")) url = `https://${url}`; try { new URL(url); return url; } catch { return null; } }) .filter((u) => !!u) ); } catch { return null; } }
if (BOOLEAN_KEYS.includes(field)) { return value === true || value === false ? value : false; }
if (NUMBER_KEYS.includes(field)) { return isNaN(value) || Number(value) <= 0 ? null : Number(value); }
return null;}
module.exports = { EmbedConfig };
|