mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-07-07 15:05:23 +02:00
- Updated the user role property from `rol` to `role` across multiple TRPC context and router files to ensure consistency and clarity in role management. - Adjusted conditional checks for user roles in various procedures to reflect the updated property name, enhancing code readability and maintainability.
230 lines
6.0 KiB
TypeScript
230 lines
6.0 KiB
TypeScript
import { slugify } from "@/lib/slug";
|
|
import {
|
|
adminProcedure,
|
|
createTRPCRouter,
|
|
protectedProcedure,
|
|
} from "@/server/api/trpc";
|
|
import { generatePassword } from "@/templates/utils";
|
|
import { IS_CLOUD } from "@dokploy/server/constants";
|
|
import {
|
|
apiCreateAi,
|
|
apiUpdateAi,
|
|
deploySuggestionSchema,
|
|
} from "@dokploy/server/db/schema/ai";
|
|
import { createDomain, createMount } from "@dokploy/server/index";
|
|
import {
|
|
deleteAiSettings,
|
|
getAiSettingById,
|
|
getAiSettingsByOrganizationId,
|
|
saveAiSettings,
|
|
suggestVariants,
|
|
} from "@dokploy/server/services/ai";
|
|
import { createComposeByTemplate } from "@dokploy/server/services/compose";
|
|
import { findProjectById } from "@dokploy/server/services/project";
|
|
import {
|
|
addNewService,
|
|
checkServiceAccess,
|
|
} from "@dokploy/server/services/user";
|
|
import {
|
|
type Model,
|
|
getProviderHeaders,
|
|
} from "@dokploy/server/utils/ai/select-ai-provider";
|
|
import { TRPCError } from "@trpc/server";
|
|
import { z } from "zod";
|
|
|
|
export const aiRouter = createTRPCRouter({
|
|
one: protectedProcedure
|
|
.input(z.object({ aiId: z.string() }))
|
|
.query(async ({ ctx, input }) => {
|
|
const aiSetting = await getAiSettingById(input.aiId);
|
|
if (aiSetting.organizationId !== ctx.session.activeOrganizationId) {
|
|
throw new TRPCError({
|
|
code: "UNAUTHORIZED",
|
|
message: "You don't have access to this AI configuration",
|
|
});
|
|
}
|
|
return aiSetting;
|
|
}),
|
|
|
|
getModels: protectedProcedure
|
|
.input(z.object({ apiUrl: z.string().min(1), apiKey: z.string().min(1) }))
|
|
.query(async ({ input }) => {
|
|
try {
|
|
const headers = getProviderHeaders(input.apiUrl, input.apiKey);
|
|
const response = await fetch(`${input.apiUrl}/models`, { headers });
|
|
|
|
if (!response.ok) {
|
|
const errorText = await response.text();
|
|
throw new Error(`Failed to fetch models: ${errorText}`);
|
|
}
|
|
|
|
const res = await response.json();
|
|
|
|
if (Array.isArray(res)) {
|
|
return res.map((model) => ({
|
|
id: model.id || model.name,
|
|
object: "model",
|
|
created: Date.now(),
|
|
owned_by: "provider",
|
|
}));
|
|
}
|
|
|
|
if (res.models) {
|
|
return res.models.map((model: any) => ({
|
|
id: model.id || model.name,
|
|
object: "model",
|
|
created: Date.now(),
|
|
owned_by: "provider",
|
|
})) as Model[];
|
|
}
|
|
|
|
if (res.data) {
|
|
return res.data as Model[];
|
|
}
|
|
|
|
const possibleModels =
|
|
(Object.values(res).find(Array.isArray) as any[]) || [];
|
|
return possibleModels.map((model) => ({
|
|
id: model.id || model.name,
|
|
object: "model",
|
|
created: Date.now(),
|
|
owned_by: "provider",
|
|
})) as Model[];
|
|
} catch (error) {
|
|
throw new TRPCError({
|
|
code: "BAD_REQUEST",
|
|
message: error instanceof Error ? error?.message : `Error: ${error}`,
|
|
});
|
|
}
|
|
}),
|
|
create: adminProcedure.input(apiCreateAi).mutation(async ({ ctx, input }) => {
|
|
return await saveAiSettings(ctx.session.activeOrganizationId, input);
|
|
}),
|
|
|
|
update: protectedProcedure
|
|
.input(apiUpdateAi)
|
|
.mutation(async ({ ctx, input }) => {
|
|
return await saveAiSettings(ctx.session.activeOrganizationId, input);
|
|
}),
|
|
|
|
getAll: adminProcedure.query(async ({ ctx }) => {
|
|
return await getAiSettingsByOrganizationId(
|
|
ctx.session.activeOrganizationId,
|
|
);
|
|
}),
|
|
|
|
get: protectedProcedure
|
|
.input(z.object({ aiId: z.string() }))
|
|
.query(async ({ ctx, input }) => {
|
|
const aiSetting = await getAiSettingById(input.aiId);
|
|
if (aiSetting.organizationId !== ctx.session.activeOrganizationId) {
|
|
throw new TRPCError({
|
|
code: "UNAUTHORIZED",
|
|
message: "You don't have access to this AI configuration",
|
|
});
|
|
}
|
|
return aiSetting;
|
|
}),
|
|
|
|
delete: protectedProcedure
|
|
.input(z.object({ aiId: z.string() }))
|
|
.mutation(async ({ ctx, input }) => {
|
|
const aiSetting = await getAiSettingById(input.aiId);
|
|
if (aiSetting.organizationId !== ctx.session.activeOrganizationId) {
|
|
throw new TRPCError({
|
|
code: "UNAUTHORIZED",
|
|
message: "You don't have access to this AI configuration",
|
|
});
|
|
}
|
|
return await deleteAiSettings(input.aiId);
|
|
}),
|
|
|
|
suggest: protectedProcedure
|
|
.input(
|
|
z.object({
|
|
aiId: z.string(),
|
|
input: z.string(),
|
|
serverId: z.string().optional(),
|
|
}),
|
|
)
|
|
.mutation(async ({ ctx, input }) => {
|
|
try {
|
|
return await suggestVariants({
|
|
...input,
|
|
organizationId: ctx.session.activeOrganizationId,
|
|
});
|
|
} catch (error) {
|
|
throw new TRPCError({
|
|
code: "BAD_REQUEST",
|
|
message: error instanceof Error ? error?.message : `Error: ${error}`,
|
|
});
|
|
}
|
|
}),
|
|
deploy: protectedProcedure
|
|
.input(deploySuggestionSchema)
|
|
.mutation(async ({ ctx, input }) => {
|
|
if (ctx.user.role === "member") {
|
|
await checkServiceAccess(
|
|
ctx.session.activeOrganizationId,
|
|
input.projectId,
|
|
"create",
|
|
);
|
|
}
|
|
|
|
if (IS_CLOUD && !input.serverId) {
|
|
throw new TRPCError({
|
|
code: "UNAUTHORIZED",
|
|
message: "You need to use a server to create a compose",
|
|
});
|
|
}
|
|
|
|
const project = await findProjectById(input.projectId);
|
|
|
|
const projectName = slugify(`${project.name} ${input.id}`);
|
|
|
|
const compose = await createComposeByTemplate({
|
|
...input,
|
|
composeFile: input.dockerCompose,
|
|
env: input.envVariables,
|
|
serverId: input.serverId,
|
|
name: input.name,
|
|
sourceType: "raw",
|
|
appName: `${projectName}-${generatePassword(6)}`,
|
|
isolatedDeployment: true,
|
|
});
|
|
|
|
if (input.domains && input.domains?.length > 0) {
|
|
for (const domain of input.domains) {
|
|
await createDomain({
|
|
...domain,
|
|
domainType: "compose",
|
|
certificateType: "none",
|
|
composeId: compose.composeId,
|
|
});
|
|
}
|
|
}
|
|
if (input.configFiles && input.configFiles?.length > 0) {
|
|
for (const mount of input.configFiles) {
|
|
await createMount({
|
|
filePath: mount.filePath,
|
|
mountPath: "",
|
|
content: mount.content,
|
|
serviceId: compose.composeId,
|
|
serviceType: "compose",
|
|
type: "file",
|
|
});
|
|
}
|
|
}
|
|
|
|
if (ctx.user.role === "member") {
|
|
await addNewService(
|
|
ctx.session.activeOrganizationId,
|
|
ctx.user.ownerId,
|
|
compose.composeId,
|
|
);
|
|
}
|
|
|
|
return null;
|
|
}),
|
|
});
|