mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-06-15 20:25:23 +02:00
[autofix.ci] apply automated fixes
This commit is contained in:
@@ -7,452 +7,452 @@ import { auth } from "../lib/auth";
|
||||
export type User = typeof user.$inferSelect;
|
||||
|
||||
export const addNewProject = async (
|
||||
userId: string,
|
||||
projectId: string,
|
||||
organizationId: string,
|
||||
userId: string,
|
||||
projectId: string,
|
||||
organizationId: string,
|
||||
) => {
|
||||
const userR = await findMemberById(userId, organizationId);
|
||||
const userR = await findMemberById(userId, organizationId);
|
||||
|
||||
await db
|
||||
.update(member)
|
||||
.set({
|
||||
accessedProjects: [...userR.accessedProjects, projectId],
|
||||
})
|
||||
.where(
|
||||
and(eq(member.id, userR.id), eq(member.organizationId, organizationId)),
|
||||
);
|
||||
await db
|
||||
.update(member)
|
||||
.set({
|
||||
accessedProjects: [...userR.accessedProjects, projectId],
|
||||
})
|
||||
.where(
|
||||
and(eq(member.id, userR.id), eq(member.organizationId, organizationId)),
|
||||
);
|
||||
};
|
||||
|
||||
export const addNewEnvironment = async (
|
||||
userId: string,
|
||||
environmentId: string,
|
||||
organizationId: string,
|
||||
userId: string,
|
||||
environmentId: string,
|
||||
organizationId: string,
|
||||
) => {
|
||||
const userR = await findMemberById(userId, organizationId);
|
||||
const userR = await findMemberById(userId, organizationId);
|
||||
|
||||
await db
|
||||
.update(member)
|
||||
.set({
|
||||
accessedEnvironments: [...userR.accessedEnvironments, environmentId],
|
||||
})
|
||||
.where(
|
||||
and(eq(member.id, userR.id), eq(member.organizationId, organizationId)),
|
||||
);
|
||||
await db
|
||||
.update(member)
|
||||
.set({
|
||||
accessedEnvironments: [...userR.accessedEnvironments, environmentId],
|
||||
})
|
||||
.where(
|
||||
and(eq(member.id, userR.id), eq(member.organizationId, organizationId)),
|
||||
);
|
||||
};
|
||||
|
||||
export const addNewService = async (
|
||||
userId: string,
|
||||
serviceId: string,
|
||||
organizationId: string,
|
||||
userId: string,
|
||||
serviceId: string,
|
||||
organizationId: string,
|
||||
) => {
|
||||
const userR = await findMemberById(userId, organizationId);
|
||||
await db
|
||||
.update(member)
|
||||
.set({
|
||||
accessedServices: [...userR.accessedServices, serviceId],
|
||||
})
|
||||
.where(
|
||||
and(eq(member.id, userR.id), eq(member.organizationId, organizationId)),
|
||||
);
|
||||
const userR = await findMemberById(userId, organizationId);
|
||||
await db
|
||||
.update(member)
|
||||
.set({
|
||||
accessedServices: [...userR.accessedServices, serviceId],
|
||||
})
|
||||
.where(
|
||||
and(eq(member.id, userR.id), eq(member.organizationId, organizationId)),
|
||||
);
|
||||
};
|
||||
|
||||
export const canPerformCreationService = async (
|
||||
userId: string,
|
||||
projectId: string,
|
||||
organizationId: string,
|
||||
userId: string,
|
||||
projectId: string,
|
||||
organizationId: string,
|
||||
) => {
|
||||
const { accessedProjects, canCreateServices } = await findMemberById(
|
||||
userId,
|
||||
organizationId,
|
||||
);
|
||||
const haveAccessToProject = accessedProjects.includes(projectId);
|
||||
const { accessedProjects, canCreateServices } = await findMemberById(
|
||||
userId,
|
||||
organizationId,
|
||||
);
|
||||
const haveAccessToProject = accessedProjects.includes(projectId);
|
||||
|
||||
if (canCreateServices && haveAccessToProject) {
|
||||
return true;
|
||||
}
|
||||
if (canCreateServices && haveAccessToProject) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
};
|
||||
|
||||
export const canPerformAccessService = async (
|
||||
userId: string,
|
||||
serviceId: string,
|
||||
organizationId: string,
|
||||
userId: string,
|
||||
serviceId: string,
|
||||
organizationId: string,
|
||||
) => {
|
||||
const { accessedServices } = await findMemberById(userId, organizationId);
|
||||
const haveAccessToService = accessedServices.includes(serviceId);
|
||||
const { accessedServices } = await findMemberById(userId, organizationId);
|
||||
const haveAccessToService = accessedServices.includes(serviceId);
|
||||
|
||||
if (haveAccessToService) {
|
||||
return true;
|
||||
}
|
||||
if (haveAccessToService) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
};
|
||||
|
||||
export const canPerformDeleteService = async (
|
||||
userId: string,
|
||||
serviceId: string,
|
||||
organizationId: string,
|
||||
userId: string,
|
||||
serviceId: string,
|
||||
organizationId: string,
|
||||
) => {
|
||||
const { accessedServices, canDeleteServices } = await findMemberById(
|
||||
userId,
|
||||
organizationId,
|
||||
);
|
||||
const haveAccessToService = accessedServices.includes(serviceId);
|
||||
const { accessedServices, canDeleteServices } = await findMemberById(
|
||||
userId,
|
||||
organizationId,
|
||||
);
|
||||
const haveAccessToService = accessedServices.includes(serviceId);
|
||||
|
||||
if (canDeleteServices && haveAccessToService) {
|
||||
return true;
|
||||
}
|
||||
if (canDeleteServices && haveAccessToService) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
};
|
||||
|
||||
export const canPerformCreationProject = async (
|
||||
userId: string,
|
||||
organizationId: string,
|
||||
userId: string,
|
||||
organizationId: string,
|
||||
) => {
|
||||
const { canCreateProjects } = await findMemberById(userId, organizationId);
|
||||
const { canCreateProjects } = await findMemberById(userId, organizationId);
|
||||
|
||||
if (canCreateProjects) {
|
||||
return true;
|
||||
}
|
||||
if (canCreateProjects) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
};
|
||||
|
||||
export const canPerformDeleteProject = async (
|
||||
userId: string,
|
||||
organizationId: string,
|
||||
userId: string,
|
||||
organizationId: string,
|
||||
) => {
|
||||
const { canDeleteProjects } = await findMemberById(userId, organizationId);
|
||||
const { canDeleteProjects } = await findMemberById(userId, organizationId);
|
||||
|
||||
if (canDeleteProjects) {
|
||||
return true;
|
||||
}
|
||||
if (canDeleteProjects) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
};
|
||||
|
||||
export const canPerformAccessProject = async (
|
||||
userId: string,
|
||||
projectId: string,
|
||||
organizationId: string,
|
||||
userId: string,
|
||||
projectId: string,
|
||||
organizationId: string,
|
||||
) => {
|
||||
const { accessedProjects } = await findMemberById(userId, organizationId);
|
||||
const { accessedProjects } = await findMemberById(userId, organizationId);
|
||||
|
||||
const haveAccessToProject = accessedProjects.includes(projectId);
|
||||
const haveAccessToProject = accessedProjects.includes(projectId);
|
||||
|
||||
if (haveAccessToProject) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
if (haveAccessToProject) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
export const canPerformAccessEnvironment = async (
|
||||
userId: string,
|
||||
environmentId: string,
|
||||
organizationId: string,
|
||||
userId: string,
|
||||
environmentId: string,
|
||||
organizationId: string,
|
||||
) => {
|
||||
const { accessedEnvironments } = await findMemberById(userId, organizationId);
|
||||
const haveAccessToEnvironment = accessedEnvironments.includes(environmentId);
|
||||
const { accessedEnvironments } = await findMemberById(userId, organizationId);
|
||||
const haveAccessToEnvironment = accessedEnvironments.includes(environmentId);
|
||||
|
||||
if (haveAccessToEnvironment) {
|
||||
return true;
|
||||
}
|
||||
if (haveAccessToEnvironment) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
};
|
||||
|
||||
export const canPerformDeleteEnvironment = async (
|
||||
userId: string,
|
||||
projectId: string,
|
||||
organizationId: string,
|
||||
userId: string,
|
||||
projectId: string,
|
||||
organizationId: string,
|
||||
) => {
|
||||
const { accessedProjects, canDeleteEnvironments } = await findMemberById(
|
||||
userId,
|
||||
organizationId,
|
||||
);
|
||||
const haveAccessToProject = accessedProjects.includes(projectId);
|
||||
const { accessedProjects, canDeleteEnvironments } = await findMemberById(
|
||||
userId,
|
||||
organizationId,
|
||||
);
|
||||
const haveAccessToProject = accessedProjects.includes(projectId);
|
||||
|
||||
if (canDeleteEnvironments && haveAccessToProject) {
|
||||
return true;
|
||||
}
|
||||
if (canDeleteEnvironments && haveAccessToProject) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
};
|
||||
|
||||
export const canAccessToTraefikFiles = async (
|
||||
userId: string,
|
||||
organizationId: string,
|
||||
userId: string,
|
||||
organizationId: string,
|
||||
) => {
|
||||
const { canAccessToTraefikFiles } = await findMemberById(
|
||||
userId,
|
||||
organizationId,
|
||||
);
|
||||
return canAccessToTraefikFiles;
|
||||
const { canAccessToTraefikFiles } = await findMemberById(
|
||||
userId,
|
||||
organizationId,
|
||||
);
|
||||
return canAccessToTraefikFiles;
|
||||
};
|
||||
|
||||
export const checkServiceAccess = async (
|
||||
userId: string,
|
||||
serviceId: string,
|
||||
organizationId: string,
|
||||
action = "access" as "access" | "create" | "delete",
|
||||
userId: string,
|
||||
serviceId: string,
|
||||
organizationId: string,
|
||||
action = "access" as "access" | "create" | "delete",
|
||||
) => {
|
||||
let hasPermission = false;
|
||||
switch (action) {
|
||||
case "create":
|
||||
hasPermission = await canPerformCreationService(
|
||||
userId,
|
||||
serviceId,
|
||||
organizationId,
|
||||
);
|
||||
break;
|
||||
case "access":
|
||||
hasPermission = await canPerformAccessService(
|
||||
userId,
|
||||
serviceId,
|
||||
organizationId,
|
||||
);
|
||||
break;
|
||||
case "delete":
|
||||
hasPermission = await canPerformDeleteService(
|
||||
userId,
|
||||
serviceId,
|
||||
organizationId,
|
||||
);
|
||||
break;
|
||||
default:
|
||||
hasPermission = false;
|
||||
}
|
||||
if (!hasPermission) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "Permission denied",
|
||||
});
|
||||
}
|
||||
let hasPermission = false;
|
||||
switch (action) {
|
||||
case "create":
|
||||
hasPermission = await canPerformCreationService(
|
||||
userId,
|
||||
serviceId,
|
||||
organizationId,
|
||||
);
|
||||
break;
|
||||
case "access":
|
||||
hasPermission = await canPerformAccessService(
|
||||
userId,
|
||||
serviceId,
|
||||
organizationId,
|
||||
);
|
||||
break;
|
||||
case "delete":
|
||||
hasPermission = await canPerformDeleteService(
|
||||
userId,
|
||||
serviceId,
|
||||
organizationId,
|
||||
);
|
||||
break;
|
||||
default:
|
||||
hasPermission = false;
|
||||
}
|
||||
if (!hasPermission) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "Permission denied",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const checkEnvironmentAccess = async (
|
||||
userId: string,
|
||||
environmentId: string,
|
||||
organizationId: string,
|
||||
action = "access" as const,
|
||||
userId: string,
|
||||
environmentId: string,
|
||||
organizationId: string,
|
||||
action = "access" as const,
|
||||
) => {
|
||||
let hasPermission = false;
|
||||
switch (action) {
|
||||
case "access":
|
||||
hasPermission = await canPerformAccessEnvironment(
|
||||
userId,
|
||||
environmentId,
|
||||
organizationId,
|
||||
);
|
||||
break;
|
||||
default:
|
||||
hasPermission = false;
|
||||
}
|
||||
if (!hasPermission) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "Permission denied",
|
||||
});
|
||||
}
|
||||
let hasPermission = false;
|
||||
switch (action) {
|
||||
case "access":
|
||||
hasPermission = await canPerformAccessEnvironment(
|
||||
userId,
|
||||
environmentId,
|
||||
organizationId,
|
||||
);
|
||||
break;
|
||||
default:
|
||||
hasPermission = false;
|
||||
}
|
||||
if (!hasPermission) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "Permission denied",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const checkEnvironmentDeletionPermission = async (
|
||||
userId: string,
|
||||
projectId: string,
|
||||
organizationId: string,
|
||||
userId: string,
|
||||
projectId: string,
|
||||
organizationId: string,
|
||||
) => {
|
||||
const member = await findMemberById(userId, organizationId);
|
||||
const member = await findMemberById(userId, organizationId);
|
||||
|
||||
if (!member) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "User not found in organization",
|
||||
});
|
||||
}
|
||||
if (!member) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "User not found in organization",
|
||||
});
|
||||
}
|
||||
|
||||
if (member.role === "owner" || member.role === "admin") {
|
||||
return true;
|
||||
}
|
||||
if (member.role === "owner" || member.role === "admin") {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!member.canDeleteEnvironments) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You don't have permission to delete environments",
|
||||
});
|
||||
}
|
||||
if (!member.canDeleteEnvironments) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You don't have permission to delete environments",
|
||||
});
|
||||
}
|
||||
|
||||
const hasProjectAccess = member.accessedProjects.includes(projectId);
|
||||
if (!hasProjectAccess) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You don't have access to this project",
|
||||
});
|
||||
}
|
||||
const hasProjectAccess = member.accessedProjects.includes(projectId);
|
||||
if (!hasProjectAccess) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You don't have access to this project",
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
};
|
||||
|
||||
export const checkProjectAccess = async (
|
||||
authId: string,
|
||||
action: "create" | "delete" | "access",
|
||||
organizationId: string,
|
||||
projectId?: string,
|
||||
authId: string,
|
||||
action: "create" | "delete" | "access",
|
||||
organizationId: string,
|
||||
projectId?: string,
|
||||
) => {
|
||||
let hasPermission = false;
|
||||
switch (action) {
|
||||
case "access":
|
||||
hasPermission = await canPerformAccessProject(
|
||||
authId,
|
||||
projectId as string,
|
||||
organizationId,
|
||||
);
|
||||
break;
|
||||
case "create":
|
||||
hasPermission = await canPerformCreationProject(authId, organizationId);
|
||||
break;
|
||||
case "delete":
|
||||
hasPermission = await canPerformDeleteProject(authId, organizationId);
|
||||
break;
|
||||
default:
|
||||
hasPermission = false;
|
||||
}
|
||||
if (!hasPermission) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "Permission denied",
|
||||
});
|
||||
}
|
||||
let hasPermission = false;
|
||||
switch (action) {
|
||||
case "access":
|
||||
hasPermission = await canPerformAccessProject(
|
||||
authId,
|
||||
projectId as string,
|
||||
organizationId,
|
||||
);
|
||||
break;
|
||||
case "create":
|
||||
hasPermission = await canPerformCreationProject(authId, organizationId);
|
||||
break;
|
||||
case "delete":
|
||||
hasPermission = await canPerformDeleteProject(authId, organizationId);
|
||||
break;
|
||||
default:
|
||||
hasPermission = false;
|
||||
}
|
||||
if (!hasPermission) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "Permission denied",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const checkEnvironmentCreationPermission = async (
|
||||
userId: string,
|
||||
projectId: string,
|
||||
organizationId: string,
|
||||
userId: string,
|
||||
projectId: string,
|
||||
organizationId: string,
|
||||
) => {
|
||||
// Get user's member record
|
||||
const member = await findMemberById(userId, organizationId);
|
||||
// Get user's member record
|
||||
const member = await findMemberById(userId, organizationId);
|
||||
|
||||
if (!member) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "User not found in organization",
|
||||
});
|
||||
}
|
||||
if (!member) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "User not found in organization",
|
||||
});
|
||||
}
|
||||
|
||||
// Owners and admins can always create environments
|
||||
if (member.role === "owner" || member.role === "admin") {
|
||||
return true;
|
||||
}
|
||||
// Owners and admins can always create environments
|
||||
if (member.role === "owner" || member.role === "admin") {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if user has canCreateEnvironments permission
|
||||
if (!member.canCreateEnvironments) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You don't have permission to create environments",
|
||||
});
|
||||
}
|
||||
// Check if user has canCreateEnvironments permission
|
||||
if (!member.canCreateEnvironments) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You don't have permission to create environments",
|
||||
});
|
||||
}
|
||||
|
||||
// Check if user has access to the project
|
||||
const hasProjectAccess = member.accessedProjects.includes(projectId);
|
||||
if (!hasProjectAccess) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You don't have access to this project",
|
||||
});
|
||||
}
|
||||
// Check if user has access to the project
|
||||
const hasProjectAccess = member.accessedProjects.includes(projectId);
|
||||
if (!hasProjectAccess) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You don't have access to this project",
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
};
|
||||
|
||||
export const findMemberById = async (
|
||||
userId: string,
|
||||
organizationId: string,
|
||||
userId: string,
|
||||
organizationId: string,
|
||||
) => {
|
||||
const result = await db.query.member.findFirst({
|
||||
where: and(
|
||||
eq(member.userId, userId),
|
||||
eq(member.organizationId, organizationId),
|
||||
),
|
||||
with: {
|
||||
user: true,
|
||||
},
|
||||
});
|
||||
const result = await db.query.member.findFirst({
|
||||
where: and(
|
||||
eq(member.userId, userId),
|
||||
eq(member.organizationId, organizationId),
|
||||
),
|
||||
with: {
|
||||
user: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!result) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "Permission denied",
|
||||
});
|
||||
}
|
||||
return result;
|
||||
if (!result) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "Permission denied",
|
||||
});
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
export const updateUser = async (userId: string, userData: Partial<User>) => {
|
||||
// Validate email if it's being updated
|
||||
if (userData.email !== undefined) {
|
||||
if (!userData.email || userData.email.trim() === "") {
|
||||
throw new Error("Email is required and cannot be empty");
|
||||
}
|
||||
// Validate email if it's being updated
|
||||
if (userData.email !== undefined) {
|
||||
if (!userData.email || userData.email.trim() === "") {
|
||||
throw new Error("Email is required and cannot be empty");
|
||||
}
|
||||
|
||||
// Basic email format validation
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
if (!emailRegex.test(userData.email)) {
|
||||
throw new Error("Please enter a valid email address");
|
||||
}
|
||||
}
|
||||
// Basic email format validation
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
if (!emailRegex.test(userData.email)) {
|
||||
throw new Error("Please enter a valid email address");
|
||||
}
|
||||
}
|
||||
|
||||
const userResult = await db
|
||||
.update(user)
|
||||
.set({
|
||||
...userData,
|
||||
})
|
||||
.where(eq(user.id, userId))
|
||||
.returning()
|
||||
.then((res) => res[0]);
|
||||
const userResult = await db
|
||||
.update(user)
|
||||
.set({
|
||||
...userData,
|
||||
})
|
||||
.where(eq(user.id, userId))
|
||||
.returning()
|
||||
.then((res) => res[0]);
|
||||
|
||||
return userResult;
|
||||
return userResult;
|
||||
};
|
||||
|
||||
export const createApiKey = async (
|
||||
userId: string,
|
||||
input: {
|
||||
name: string;
|
||||
prefix?: string;
|
||||
expiresIn?: number;
|
||||
metadata: {
|
||||
organizationId: string;
|
||||
};
|
||||
rateLimitEnabled?: boolean;
|
||||
rateLimitTimeWindow?: number;
|
||||
rateLimitMax?: number;
|
||||
remaining?: number;
|
||||
refillAmount?: number;
|
||||
refillInterval?: number;
|
||||
},
|
||||
userId: string,
|
||||
input: {
|
||||
name: string;
|
||||
prefix?: string;
|
||||
expiresIn?: number;
|
||||
metadata: {
|
||||
organizationId: string;
|
||||
};
|
||||
rateLimitEnabled?: boolean;
|
||||
rateLimitTimeWindow?: number;
|
||||
rateLimitMax?: number;
|
||||
remaining?: number;
|
||||
refillAmount?: number;
|
||||
refillInterval?: number;
|
||||
},
|
||||
) => {
|
||||
const result = await auth.createApiKey({
|
||||
body: {
|
||||
name: input.name,
|
||||
expiresIn: input.expiresIn,
|
||||
prefix: input.prefix,
|
||||
rateLimitEnabled: input.rateLimitEnabled,
|
||||
rateLimitTimeWindow: input.rateLimitTimeWindow,
|
||||
rateLimitMax: input.rateLimitMax,
|
||||
remaining: input.remaining,
|
||||
refillAmount: input.refillAmount,
|
||||
refillInterval: input.refillInterval,
|
||||
userId,
|
||||
},
|
||||
});
|
||||
const result = await auth.createApiKey({
|
||||
body: {
|
||||
name: input.name,
|
||||
expiresIn: input.expiresIn,
|
||||
prefix: input.prefix,
|
||||
rateLimitEnabled: input.rateLimitEnabled,
|
||||
rateLimitTimeWindow: input.rateLimitTimeWindow,
|
||||
rateLimitMax: input.rateLimitMax,
|
||||
remaining: input.remaining,
|
||||
refillAmount: input.refillAmount,
|
||||
refillInterval: input.refillInterval,
|
||||
userId,
|
||||
},
|
||||
});
|
||||
|
||||
if (input.metadata) {
|
||||
await db
|
||||
.update(apikey)
|
||||
.set({ metadata: JSON.stringify(input.metadata) })
|
||||
.where(eq(apikey.id, result.id));
|
||||
}
|
||||
if (input.metadata) {
|
||||
await db
|
||||
.update(apikey)
|
||||
.set({ metadata: JSON.stringify(input.metadata) })
|
||||
.where(eq(apikey.id, result.id));
|
||||
}
|
||||
|
||||
return result;
|
||||
return result;
|
||||
};
|
||||
|
||||
@@ -5,26 +5,26 @@ import boxen from "boxen";
|
||||
import { quote } from "shell-quote";
|
||||
import { writeDomainsToCompose } from "../docker/domain";
|
||||
import {
|
||||
encodeBase64,
|
||||
getEnvironmentVariablesObject,
|
||||
prepareEnvironmentVariables,
|
||||
encodeBase64,
|
||||
getEnvironmentVariablesObject,
|
||||
prepareEnvironmentVariables,
|
||||
} from "../docker/utils";
|
||||
|
||||
export type ComposeNested = InferResultType<
|
||||
"compose",
|
||||
{ environment: { with: { project: true } }; mounts: true; domains: true }
|
||||
"compose",
|
||||
{ environment: { with: { project: true } }; mounts: true; domains: true }
|
||||
>;
|
||||
|
||||
export const getBuildComposeCommand = async (compose: ComposeNested) => {
|
||||
const { COMPOSE_PATH } = paths(!!compose.serverId);
|
||||
const { sourceType, appName, mounts, composeType, domains } = compose;
|
||||
const command = createCommand(compose);
|
||||
const envCommand = getCreateEnvFileCommand(compose);
|
||||
const projectPath = join(COMPOSE_PATH, compose.appName, "code");
|
||||
const exportEnvCommand = getExportEnvCommand(compose);
|
||||
const { COMPOSE_PATH } = paths(!!compose.serverId);
|
||||
const { sourceType, appName, mounts, composeType, domains } = compose;
|
||||
const command = createCommand(compose);
|
||||
const envCommand = getCreateEnvFileCommand(compose);
|
||||
const projectPath = join(COMPOSE_PATH, compose.appName, "code");
|
||||
const exportEnvCommand = getExportEnvCommand(compose);
|
||||
|
||||
const newCompose = await writeDomainsToCompose(compose, domains);
|
||||
const logContent = `
|
||||
const newCompose = await writeDomainsToCompose(compose, domains);
|
||||
const logContent = `
|
||||
App Name: ${appName}
|
||||
Build Compose 🐳
|
||||
Detected: ${mounts.length} mounts 📂
|
||||
@@ -32,17 +32,17 @@ Command: docker ${command}
|
||||
Source Type: docker ${sourceType} ✅
|
||||
Compose Type: ${composeType} ✅`;
|
||||
|
||||
const logBox = boxen(logContent, {
|
||||
padding: {
|
||||
left: 1,
|
||||
right: 1,
|
||||
bottom: 1,
|
||||
},
|
||||
width: 80,
|
||||
borderStyle: "double",
|
||||
});
|
||||
const logBox = boxen(logContent, {
|
||||
padding: {
|
||||
left: 1,
|
||||
right: 1,
|
||||
bottom: 1,
|
||||
},
|
||||
width: 80,
|
||||
borderStyle: "double",
|
||||
});
|
||||
|
||||
const bashCommand = `
|
||||
const bashCommand = `
|
||||
set -e
|
||||
{
|
||||
echo "${logBox}";
|
||||
@@ -64,81 +64,81 @@ Compose Type: ${composeType} ✅`;
|
||||
}
|
||||
`;
|
||||
|
||||
return bashCommand;
|
||||
return bashCommand;
|
||||
};
|
||||
|
||||
const sanitizeCommand = (command: string) => {
|
||||
const sanitizedCommand = command.trim();
|
||||
const sanitizedCommand = command.trim();
|
||||
|
||||
const parts = sanitizedCommand.split(/\s+/);
|
||||
const parts = sanitizedCommand.split(/\s+/);
|
||||
|
||||
const restCommand = parts.map((arg) => arg.replace(/^"(.*)"$/, "$1"));
|
||||
const restCommand = parts.map((arg) => arg.replace(/^"(.*)"$/, "$1"));
|
||||
|
||||
return restCommand.join(" ");
|
||||
return restCommand.join(" ");
|
||||
};
|
||||
|
||||
export const createCommand = (compose: ComposeNested) => {
|
||||
const { composeType, appName, sourceType } = compose;
|
||||
if (compose.command) {
|
||||
return `${sanitizeCommand(compose.command)}`;
|
||||
}
|
||||
const { composeType, appName, sourceType } = compose;
|
||||
if (compose.command) {
|
||||
return `${sanitizeCommand(compose.command)}`;
|
||||
}
|
||||
|
||||
const path =
|
||||
sourceType === "raw" ? "docker-compose.yml" : compose.composePath;
|
||||
let command = "";
|
||||
const path =
|
||||
sourceType === "raw" ? "docker-compose.yml" : compose.composePath;
|
||||
let command = "";
|
||||
|
||||
if (composeType === "docker-compose") {
|
||||
command = `compose -p ${appName} -f ${path} up -d --build --remove-orphans`;
|
||||
} else if (composeType === "stack") {
|
||||
command = `stack deploy -c ${path} ${appName} --prune --with-registry-auth`;
|
||||
}
|
||||
if (composeType === "docker-compose") {
|
||||
command = `compose -p ${appName} -f ${path} up -d --build --remove-orphans`;
|
||||
} else if (composeType === "stack") {
|
||||
command = `stack deploy -c ${path} ${appName} --prune --with-registry-auth`;
|
||||
}
|
||||
|
||||
return command;
|
||||
return command;
|
||||
};
|
||||
|
||||
export const getCreateEnvFileCommand = (compose: ComposeNested) => {
|
||||
const { COMPOSE_PATH } = paths(!!compose.serverId);
|
||||
const { env, composePath, appName } = compose;
|
||||
const composeFilePath =
|
||||
join(COMPOSE_PATH, appName, "code", composePath) ||
|
||||
join(COMPOSE_PATH, appName, "code", "docker-compose.yml");
|
||||
const { COMPOSE_PATH } = paths(!!compose.serverId);
|
||||
const { env, composePath, appName } = compose;
|
||||
const composeFilePath =
|
||||
join(COMPOSE_PATH, appName, "code", composePath) ||
|
||||
join(COMPOSE_PATH, appName, "code", "docker-compose.yml");
|
||||
|
||||
const envFilePath = join(dirname(composeFilePath), ".env");
|
||||
const envFilePath = join(dirname(composeFilePath), ".env");
|
||||
|
||||
let envContent = `APP_NAME=${appName}\n`;
|
||||
envContent += env || "";
|
||||
if (!envContent.includes("DOCKER_CONFIG")) {
|
||||
envContent += "\nDOCKER_CONFIG=/root/.docker";
|
||||
}
|
||||
let envContent = `APP_NAME=${appName}\n`;
|
||||
envContent += env || "";
|
||||
if (!envContent.includes("DOCKER_CONFIG")) {
|
||||
envContent += "\nDOCKER_CONFIG=/root/.docker";
|
||||
}
|
||||
|
||||
if (compose.randomize) {
|
||||
envContent += `\nCOMPOSE_PREFIX=${compose.suffix}`;
|
||||
}
|
||||
if (compose.randomize) {
|
||||
envContent += `\nCOMPOSE_PREFIX=${compose.suffix}`;
|
||||
}
|
||||
|
||||
const envFileContent = prepareEnvironmentVariables(
|
||||
envContent,
|
||||
compose.environment.project.env,
|
||||
compose.environment.env,
|
||||
).join("\n");
|
||||
const envFileContent = prepareEnvironmentVariables(
|
||||
envContent,
|
||||
compose.environment.project.env,
|
||||
compose.environment.env,
|
||||
).join("\n");
|
||||
|
||||
const encodedContent = encodeBase64(envFileContent);
|
||||
return `
|
||||
const encodedContent = encodeBase64(envFileContent);
|
||||
return `
|
||||
touch ${envFilePath};
|
||||
echo "${encodedContent}" | base64 -d > "${envFilePath}";
|
||||
`;
|
||||
};
|
||||
|
||||
const getExportEnvCommand = (compose: ComposeNested) => {
|
||||
if (compose.composeType !== "stack") return "";
|
||||
if (compose.composeType !== "stack") return "";
|
||||
|
||||
const envVars = getEnvironmentVariablesObject(
|
||||
compose.env,
|
||||
compose.environment.project.env,
|
||||
compose.environment.env,
|
||||
);
|
||||
const exports = Object.entries(envVars)
|
||||
.map(([key, value]) => `${key}=${quote([value])}`)
|
||||
.join(" ");
|
||||
const envVars = getEnvironmentVariablesObject(
|
||||
compose.env,
|
||||
compose.environment.project.env,
|
||||
compose.environment.env,
|
||||
);
|
||||
const exports = Object.entries(envVars)
|
||||
.map(([key, value]) => `${key}=${quote([value])}`)
|
||||
.join(" ");
|
||||
|
||||
return exports ? `${exports}` : "";
|
||||
return exports ? `${exports}` : "";
|
||||
};
|
||||
|
||||
@@ -1,90 +1,90 @@
|
||||
import {
|
||||
getEnvironmentVariablesObject,
|
||||
prepareEnvironmentVariablesForShell,
|
||||
getEnvironmentVariablesObject,
|
||||
prepareEnvironmentVariablesForShell,
|
||||
} from "@dokploy/server/utils/docker/utils";
|
||||
import { quote } from "shell-quote";
|
||||
import {
|
||||
getBuildAppDirectory,
|
||||
getDockerContextPath,
|
||||
getBuildAppDirectory,
|
||||
getDockerContextPath,
|
||||
} from "../filesystem/directory";
|
||||
import type { ApplicationNested } from ".";
|
||||
import { createEnvFileCommand } from "./utils";
|
||||
|
||||
export const getDockerCommand = (application: ApplicationNested) => {
|
||||
const {
|
||||
appName,
|
||||
env,
|
||||
publishDirectory,
|
||||
buildArgs,
|
||||
buildSecrets,
|
||||
dockerBuildStage,
|
||||
cleanCache,
|
||||
createEnvFile,
|
||||
} = application;
|
||||
const dockerFilePath = getBuildAppDirectory(application);
|
||||
const {
|
||||
appName,
|
||||
env,
|
||||
publishDirectory,
|
||||
buildArgs,
|
||||
buildSecrets,
|
||||
dockerBuildStage,
|
||||
cleanCache,
|
||||
createEnvFile,
|
||||
} = application;
|
||||
const dockerFilePath = getBuildAppDirectory(application);
|
||||
|
||||
try {
|
||||
const image = `${appName}`;
|
||||
try {
|
||||
const image = `${appName}`;
|
||||
|
||||
const defaultContextPath =
|
||||
dockerFilePath.substring(0, dockerFilePath.lastIndexOf("/") + 1) || ".";
|
||||
const defaultContextPath =
|
||||
dockerFilePath.substring(0, dockerFilePath.lastIndexOf("/") + 1) || ".";
|
||||
|
||||
const dockerContextPath =
|
||||
getDockerContextPath(application) || defaultContextPath;
|
||||
const dockerContextPath =
|
||||
getDockerContextPath(application) || defaultContextPath;
|
||||
|
||||
const commandArgs = ["build", "-t", image, "-f", dockerFilePath, "."];
|
||||
const commandArgs = ["build", "-t", image, "-f", dockerFilePath, "."];
|
||||
|
||||
if (dockerBuildStage) {
|
||||
commandArgs.push("--target", dockerBuildStage);
|
||||
}
|
||||
if (dockerBuildStage) {
|
||||
commandArgs.push("--target", dockerBuildStage);
|
||||
}
|
||||
|
||||
if (cleanCache) {
|
||||
commandArgs.push("--no-cache");
|
||||
}
|
||||
if (cleanCache) {
|
||||
commandArgs.push("--no-cache");
|
||||
}
|
||||
|
||||
const args = prepareEnvironmentVariablesForShell(
|
||||
buildArgs,
|
||||
application.environment.project.env,
|
||||
application.environment.env,
|
||||
);
|
||||
const args = prepareEnvironmentVariablesForShell(
|
||||
buildArgs,
|
||||
application.environment.project.env,
|
||||
application.environment.env,
|
||||
);
|
||||
|
||||
for (const arg of args) {
|
||||
commandArgs.push("--build-arg", arg);
|
||||
}
|
||||
for (const arg of args) {
|
||||
commandArgs.push("--build-arg", arg);
|
||||
}
|
||||
|
||||
const secrets = getEnvironmentVariablesObject(
|
||||
buildSecrets,
|
||||
application.environment.project.env,
|
||||
application.environment.env,
|
||||
);
|
||||
const secrets = getEnvironmentVariablesObject(
|
||||
buildSecrets,
|
||||
application.environment.project.env,
|
||||
application.environment.env,
|
||||
);
|
||||
|
||||
const joinedSecrets = Object.entries(secrets)
|
||||
.map(([key, value]) => `${key}=${quote([value])}`)
|
||||
.join(" ");
|
||||
const joinedSecrets = Object.entries(secrets)
|
||||
.map(([key, value]) => `${key}=${quote([value])}`)
|
||||
.join(" ");
|
||||
|
||||
/*
|
||||
/*
|
||||
Do not generate an environment file when publishDirectory is specified,
|
||||
as it could be publicly exposed.
|
||||
Also respect the createEnvFile flag.
|
||||
*/
|
||||
let command = "";
|
||||
if (!publishDirectory && createEnvFile) {
|
||||
command += createEnvFileCommand(
|
||||
dockerFilePath,
|
||||
env,
|
||||
application.environment.project.env,
|
||||
application.environment.env,
|
||||
);
|
||||
}
|
||||
let command = "";
|
||||
if (!publishDirectory && createEnvFile) {
|
||||
command += createEnvFileCommand(
|
||||
dockerFilePath,
|
||||
env,
|
||||
application.environment.project.env,
|
||||
application.environment.env,
|
||||
);
|
||||
}
|
||||
|
||||
for (const key in secrets) {
|
||||
// Although buildx is smart enough to know we may be referring to an environment variable name,
|
||||
// we still make sure it doesn't fall back to `type=file`.
|
||||
// See: https://docs.docker.com/reference/cli/docker/buildx/build/#secret
|
||||
commandArgs.push("--secret", `type=env,id=${key}`);
|
||||
}
|
||||
for (const key in secrets) {
|
||||
// Although buildx is smart enough to know we may be referring to an environment variable name,
|
||||
// we still make sure it doesn't fall back to `type=file`.
|
||||
// See: https://docs.docker.com/reference/cli/docker/buildx/build/#secret
|
||||
commandArgs.push("--secret", `type=env,id=${key}`);
|
||||
}
|
||||
|
||||
command += `
|
||||
command += `
|
||||
echo "Building ${appName}" ;
|
||||
cd ${dockerContextPath} || {
|
||||
echo "❌ The path ${dockerContextPath} does not exist" ;
|
||||
@@ -98,8 +98,8 @@ ${joinedSecrets} docker ${commandArgs.join(" ")} || {
|
||||
echo "✅ Docker build completed." ;
|
||||
`;
|
||||
|
||||
return command;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
return command;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user