feat: add collaborator management to projects module

Added endpoints to manage collaborators in `ProjectsController`:
- Add collaborator
- Remove collaborator
- Get project collaborators

Updated `ProjectsService` with corresponding methods and enhanced `checkUserAccess` to validate user access as owner or collaborator. Included unit tests for new functionality in controllers and services.
This commit is contained in:
2025-05-15 20:56:43 +02:00
parent 576d063e52
commit c16c8d51d2
4 changed files with 367 additions and 17 deletions

View File

@@ -45,11 +45,11 @@ export class ProjectsService {
.select()
.from(schema.projects)
.where(eq(schema.projects.id, id));
if (!project) {
throw new NotFoundException(`Project with ID ${id} not found`);
}
return project;
}
@@ -65,11 +65,11 @@ export class ProjectsService {
})
.where(eq(schema.projects.id, id))
.returning();
if (!project) {
throw new NotFoundException(`Project with ID ${id} not found`);
}
return project;
}
@@ -81,11 +81,11 @@ export class ProjectsService {
.delete(schema.projects)
.where(eq(schema.projects.id, id))
.returning();
if (!project) {
throw new NotFoundException(`Project with ID ${id} not found`);
}
return project;
}
@@ -93,6 +93,7 @@ export class ProjectsService {
* Check if a user has access to a project
*/
async checkUserAccess(projectId: string, userId: string) {
// Check if the user is the owner of the project
const [project] = await this.db
.select()
.from(schema.projects)
@@ -102,7 +103,104 @@ export class ProjectsService {
eq(schema.projects.ownerId, userId)
)
);
return !!project;
if (project) {
return true;
}
// Check if the user is a collaborator on the project
const [collaboration] = await this.db
.select()
.from(schema.projectCollaborators)
.where(
and(
eq(schema.projectCollaborators.projectId, projectId),
eq(schema.projectCollaborators.userId, userId)
)
);
return !!collaboration;
}
}
/**
* Add a collaborator to a project
*/
async addCollaborator(projectId: string, userId: string) {
// Check if the project exists
await this.findById(projectId);
// Check if the user exists
const [user] = await this.db
.select()
.from(schema.users)
.where(eq(schema.users.id, userId));
if (!user) {
throw new NotFoundException(`User with ID ${userId} not found`);
}
// Check if the user is already a collaborator on the project
const [existingCollaboration] = await this.db
.select()
.from(schema.projectCollaborators)
.where(
and(
eq(schema.projectCollaborators.projectId, projectId),
eq(schema.projectCollaborators.userId, userId)
)
);
if (existingCollaboration) {
return existingCollaboration;
}
// Add the user as a collaborator on the project
const [collaboration] = await this.db
.insert(schema.projectCollaborators)
.values({
projectId,
userId,
})
.returning();
return collaboration;
}
/**
* Remove a collaborator from a project
*/
async removeCollaborator(projectId: string, userId: string) {
const [collaboration] = await this.db
.delete(schema.projectCollaborators)
.where(
and(
eq(schema.projectCollaborators.projectId, projectId),
eq(schema.projectCollaborators.userId, userId)
)
)
.returning();
if (!collaboration) {
throw new NotFoundException(`User with ID ${userId} is not a collaborator on project with ID ${projectId}`);
}
return collaboration;
}
/**
* Get all collaborators for a project
*/
async getCollaborators(projectId: string) {
// Check if the project exists
await this.findById(projectId);
// Get all collaborators for the project
return this.db
.select({
user: schema.users,
})
.from(schema.projectCollaborators)
.innerJoin(schema.users, eq(schema.projectCollaborators.userId, schema.users.id))
.where(eq(schema.projectCollaborators.projectId, projectId));
}
}