Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 71 additions & 43 deletions packages/server/src/services/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,13 @@ export const canPerformCreationService = async (
projectId: string,
organizationId: string,
) => {
const { accessedProjects, canCreateServices } = await findMemberById(
userId,
organizationId,
);
const member = await findMemberById(userId, organizationId);

if (member.role === "owner" || member.role === "admin") {
return true;
}

const { accessedProjects, canCreateServices } = member;
const haveAccessToProject = accessedProjects.includes(projectId);

if (canCreateServices && haveAccessToProject) {
Expand All @@ -79,7 +82,13 @@ export const canPerformAccessService = async (
serviceId: string,
organizationId: string,
) => {
const { accessedServices } = await findMemberById(userId, organizationId);
const member = await findMemberById(userId, organizationId);

if (member.role === "owner" || member.role === "admin") {
return true;
}

const { accessedServices } = member;
const haveAccessToService = accessedServices.includes(serviceId);

if (haveAccessToService) {
Expand All @@ -94,10 +103,13 @@ export const canPeformDeleteService = async (
serviceId: string,
organizationId: string,
) => {
const { accessedServices, canDeleteServices } = await findMemberById(
userId,
organizationId,
);
const member = await findMemberById(userId, organizationId);

if (member.role === "owner" || member.role === "admin") {
return true;
}

const { accessedServices, canDeleteServices } = member;
const haveAccessToService = accessedServices.includes(serviceId);

if (canDeleteServices && haveAccessToService) {
Expand All @@ -111,7 +123,13 @@ export const canPerformCreationProject = async (
userId: string,
organizationId: string,
) => {
const { canCreateProjects } = await findMemberById(userId, organizationId);
const member = await findMemberById(userId, organizationId);

if (member.role === "owner" || member.role === "admin") {
return true;
}

const { canCreateProjects } = member;

if (canCreateProjects) {
return true;
Expand All @@ -124,7 +142,13 @@ export const canPerformDeleteProject = async (
userId: string,
organizationId: string,
) => {
const { canDeleteProjects } = await findMemberById(userId, organizationId);
const member = await findMemberById(userId, organizationId);

if (member.role === "owner" || member.role === "admin") {
return true;
}

const { canDeleteProjects } = member;

if (canDeleteProjects) {
return true;
Expand All @@ -138,7 +162,13 @@ export const canPerformAccessProject = async (
projectId: string,
organizationId: string,
) => {
const { accessedProjects } = await findMemberById(userId, organizationId);
const member = await findMemberById(userId, organizationId);

if (member.role === "owner" || member.role === "admin") {
return true;
}

const { accessedProjects } = member;

const haveAccessToProject = accessedProjects.includes(projectId);

Expand All @@ -153,7 +183,13 @@ export const canPerformAccessEnvironment = async (
environmentId: string,
organizationId: string,
) => {
const { accessedEnvironments } = await findMemberById(userId, organizationId);
const member = await findMemberById(userId, organizationId);

if (member.role === "owner" || member.role === "admin") {
return true;
}

const { accessedEnvironments } = member;
const haveAccessToEnvironment = accessedEnvironments.includes(environmentId);

if (haveAccessToEnvironment) {
Expand All @@ -168,10 +204,13 @@ export const canPerformDeleteEnvironment = async (
projectId: string,
organizationId: string,
) => {
const { accessedProjects, canDeleteEnvironments } = await findMemberById(
userId,
organizationId,
);
const member = await findMemberById(userId, organizationId);

if (member.role === "owner" || member.role === "admin") {
return true;
}

const { accessedProjects, canDeleteEnvironments } = member;
const haveAccessToProject = accessedProjects.includes(projectId);

if (canDeleteEnvironments && haveAccessToProject) {
Expand All @@ -185,10 +224,13 @@ export const canAccessToTraefikFiles = async (
userId: string,
organizationId: string,
) => {
const { canAccessToTraefikFiles } = await findMemberById(
userId,
organizationId,
);
const member = await findMemberById(userId, organizationId);

if (member.role === "owner" || member.role === "admin") {
return true;
}

const { canAccessToTraefikFiles } = member;
return canAccessToTraefikFiles;
};

Expand Down Expand Up @@ -265,13 +307,6 @@ export const checkEnvironmentDeletionPermission = async (
) => {
const member = await findMemberById(userId, organizationId);

if (!member) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "User not found in organization",
});
}

if (member.role === "owner" || member.role === "admin") {
return true;
}
Expand Down Expand Up @@ -331,30 +366,19 @@ export const checkEnvironmentCreationPermission = async (
projectId: string,
organizationId: string,
) => {
// Get user's member record
const member = await findMemberById(userId, organizationId);

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;
}

// 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({
Expand Down Expand Up @@ -390,16 +414,20 @@ export const findMemberById = async (
};

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");
throw new TRPCError({
code: "BAD_REQUEST",
message: "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");
throw new TRPCError({
code: "BAD_REQUEST",
message: "Please enter a valid email address",
});
}
}

Expand Down