|
|
import { Elysia } from "elysia"; |
|
|
import { authPlugin } from "$api/authPlugin"; |
|
|
import { defaultModel } from "$lib/server/models"; |
|
|
import { collections } from "$lib/server/database"; |
|
|
import { authCondition } from "$lib/server/auth"; |
|
|
import { models, validateModel } from "$lib/server/models"; |
|
|
import { DEFAULT_SETTINGS, type SettingsEditable } from "$lib/types/Settings"; |
|
|
import { z } from "zod"; |
|
|
import { config } from "$lib/server/config"; |
|
|
import { logger } from "$lib/server/logger"; |
|
|
|
|
|
export const userGroup = new Elysia() |
|
|
.use(authPlugin) |
|
|
.get("/login", () => { |
|
|
|
|
|
throw new Error("Not implemented"); |
|
|
}) |
|
|
.get("/login/callback", () => { |
|
|
|
|
|
throw new Error("Not implemented"); |
|
|
}) |
|
|
.post("/logout", () => { |
|
|
|
|
|
throw new Error("Not implemented"); |
|
|
}) |
|
|
.group("/user", (app) => { |
|
|
return app |
|
|
.get("/", ({ locals }) => { |
|
|
return locals.user |
|
|
? { |
|
|
id: locals.user._id.toString(), |
|
|
username: locals.user.username, |
|
|
avatarUrl: locals.user.avatarUrl, |
|
|
email: locals.user.email, |
|
|
isAdmin: locals.user.isAdmin ?? false, |
|
|
isEarlyAccess: locals.user.isEarlyAccess ?? false, |
|
|
} |
|
|
: null; |
|
|
}) |
|
|
.get("/settings", async ({ locals }) => { |
|
|
const settings = await collections.settings.findOne(authCondition(locals)); |
|
|
|
|
|
if (settings && !validateModel(models).safeParse(settings?.activeModel).success) { |
|
|
settings.activeModel = defaultModel.id; |
|
|
await collections.settings.updateOne(authCondition(locals), { |
|
|
$set: { activeModel: defaultModel.id }, |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
if ( |
|
|
settings?.activeModel && |
|
|
models.find((m) => m.id === settings?.activeModel)?.unlisted === true |
|
|
) { |
|
|
settings.activeModel = defaultModel.id; |
|
|
await collections.settings.updateOne(authCondition(locals), { |
|
|
$set: { activeModel: defaultModel.id }, |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
return { |
|
|
welcomeModalSeen: !!settings?.welcomeModalSeenAt, |
|
|
welcomeModalSeenAt: settings?.welcomeModalSeenAt ?? null, |
|
|
|
|
|
activeModel: settings?.activeModel ?? DEFAULT_SETTINGS.activeModel, |
|
|
disableStream: settings?.disableStream ?? DEFAULT_SETTINGS.disableStream, |
|
|
directPaste: settings?.directPaste ?? DEFAULT_SETTINGS.directPaste, |
|
|
hidePromptExamples: settings?.hidePromptExamples ?? DEFAULT_SETTINGS.hidePromptExamples, |
|
|
shareConversationsWithModelAuthors: |
|
|
settings?.shareConversationsWithModelAuthors ?? |
|
|
DEFAULT_SETTINGS.shareConversationsWithModelAuthors, |
|
|
|
|
|
customPrompts: settings?.customPrompts ?? {}, |
|
|
multimodalOverrides: settings?.multimodalOverrides ?? {}, |
|
|
toolsOverrides: settings?.toolsOverrides ?? {}, |
|
|
billingOrganization: settings?.billingOrganization ?? undefined, |
|
|
}; |
|
|
}) |
|
|
.post("/settings", async ({ locals, request }) => { |
|
|
const body = await request.json(); |
|
|
|
|
|
const { welcomeModalSeen, ...settings } = z |
|
|
.object({ |
|
|
shareConversationsWithModelAuthors: z |
|
|
.boolean() |
|
|
.default(DEFAULT_SETTINGS.shareConversationsWithModelAuthors), |
|
|
welcomeModalSeen: z.boolean().optional(), |
|
|
activeModel: z.string().default(DEFAULT_SETTINGS.activeModel), |
|
|
customPrompts: z.record(z.string()).default({}), |
|
|
multimodalOverrides: z.record(z.boolean()).default({}), |
|
|
toolsOverrides: z.record(z.boolean()).default({}), |
|
|
disableStream: z.boolean().default(false), |
|
|
directPaste: z.boolean().default(false), |
|
|
hidePromptExamples: z.record(z.boolean()).default({}), |
|
|
billingOrganization: z.string().optional(), |
|
|
}) |
|
|
.parse(body) satisfies SettingsEditable; |
|
|
|
|
|
await collections.settings.updateOne( |
|
|
authCondition(locals), |
|
|
{ |
|
|
$set: { |
|
|
...settings, |
|
|
...(welcomeModalSeen && { welcomeModalSeenAt: new Date() }), |
|
|
updatedAt: new Date(), |
|
|
}, |
|
|
$setOnInsert: { |
|
|
createdAt: new Date(), |
|
|
}, |
|
|
}, |
|
|
{ |
|
|
upsert: true, |
|
|
} |
|
|
); |
|
|
|
|
|
return new Response(); |
|
|
}) |
|
|
.get("/reports", async ({ locals }) => { |
|
|
if (!locals.user || !locals.sessionId) { |
|
|
return []; |
|
|
} |
|
|
|
|
|
const reports = await collections.reports |
|
|
.find({ |
|
|
createdBy: locals.user?._id ?? locals.sessionId, |
|
|
}) |
|
|
.toArray(); |
|
|
return reports; |
|
|
}) |
|
|
.get("/billing-orgs", async ({ locals, set }) => { |
|
|
|
|
|
if (!config.isHuggingChat) { |
|
|
set.status = 404; |
|
|
return { error: "Not available" }; |
|
|
} |
|
|
|
|
|
|
|
|
if (!locals.user) { |
|
|
set.status = 401; |
|
|
return { error: "Login required" }; |
|
|
} |
|
|
|
|
|
if (!locals.token) { |
|
|
set.status = 401; |
|
|
return { error: "OAuth token not available. Please log out and log back in." }; |
|
|
} |
|
|
|
|
|
try { |
|
|
|
|
|
const response = await fetch("https://huggingface.co/oauth/userinfo", { |
|
|
headers: { Authorization: `Bearer ${locals.token}` }, |
|
|
}); |
|
|
|
|
|
if (!response.ok) { |
|
|
logger.error(`Failed to fetch billing orgs: ${response.status}`); |
|
|
set.status = 502; |
|
|
return { error: "Failed to fetch billing information" }; |
|
|
} |
|
|
|
|
|
const data = await response.json(); |
|
|
|
|
|
|
|
|
const settings = await collections.settings.findOne(authCondition(locals)); |
|
|
const currentBillingOrg = settings?.billingOrganization; |
|
|
|
|
|
|
|
|
const billingOrgs = (data.orgs ?? []) |
|
|
.filter((org: { canPay?: boolean }) => org.canPay === true) |
|
|
.map((org: { sub: string; name: string; preferred_username: string }) => ({ |
|
|
sub: org.sub, |
|
|
name: org.name, |
|
|
preferred_username: org.preferred_username, |
|
|
})); |
|
|
|
|
|
|
|
|
const isCurrentOrgValid = |
|
|
!currentBillingOrg || |
|
|
billingOrgs.some( |
|
|
(org: { preferred_username: string }) => org.preferred_username === currentBillingOrg |
|
|
); |
|
|
|
|
|
|
|
|
if (!isCurrentOrgValid && currentBillingOrg) { |
|
|
logger.info( |
|
|
`Clearing invalid billingOrganization '${currentBillingOrg}' for user ${locals.user._id}` |
|
|
); |
|
|
await collections.settings.updateOne(authCondition(locals), { |
|
|
$unset: { billingOrganization: "" }, |
|
|
$set: { updatedAt: new Date() }, |
|
|
}); |
|
|
} |
|
|
|
|
|
return { |
|
|
userCanPay: data.canPay ?? false, |
|
|
organizations: billingOrgs, |
|
|
currentBillingOrg: isCurrentOrgValid ? currentBillingOrg : undefined, |
|
|
}; |
|
|
} catch (err) { |
|
|
logger.error(err, "Error fetching billing orgs:"); |
|
|
set.status = 500; |
|
|
return { error: "Internal server error" }; |
|
|
} |
|
|
}); |
|
|
}); |
|
|
|