diff --git a/libs/common/src/constants/controller-route.ts b/libs/common/src/constants/controller-route.ts index 7ef8808..80088aa 100644 --- a/libs/common/src/constants/controller-route.ts +++ b/libs/common/src/constants/controller-route.ts @@ -21,6 +21,11 @@ export class ControllerRoute { public static readonly DELETE_PROJECT_SUMMARY = 'Delete a project'; public static readonly DELETE_PROJECT_DESCRIPTION = 'This endpoint deletes an existing project by its unique identifier (UUID).'; + + public static readonly GET_USERS_BY_PROJECT_SUMMARY = + 'Get users by project'; + public static readonly GET_USERS_BY_PROJECT_DESCRIPTION = + 'This endpoint retrieves all users associated with a specific project.'; }; }; @@ -733,6 +738,7 @@ export class ControllerRoute { public static readonly CREATE_USER_INVITATION_DESCRIPTION = 'This endpoint creates an invitation for a user to assign to role and spaces.'; + public static readonly CHECK_EMAIL_SUMMARY = 'Check email'; public static readonly CHECK_EMAIL_DESCRIPTION = diff --git a/src/project/controllers/project.controller.ts b/src/project/controllers/project.controller.ts index a39ced1..c888acb 100644 --- a/src/project/controllers/project.controller.ts +++ b/src/project/controllers/project.controller.ts @@ -86,4 +86,18 @@ export class ProjectController { async findOne(@Param() params: GetProjectParam): Promise { return this.projectService.getProject(params.projectUuid); } + + @ApiBearerAuth() + @UseGuards(JwtAuthGuard) + @ApiOperation({ + summary: ControllerRoute.PROJECT.ACTIONS.GET_USERS_BY_PROJECT_SUMMARY, + description: + ControllerRoute.PROJECT.ACTIONS.GET_USERS_BY_PROJECT_DESCRIPTION, + }) + @Get(':projectUuid/users') + async findUsersByProject( + @Param() params: GetProjectParam, + ): Promise { + return this.projectService.getUsersByProject(params.projectUuid); + } } diff --git a/src/project/project.module.ts b/src/project/project.module.ts index 8711499..0afbd1c 100644 --- a/src/project/project.module.ts +++ b/src/project/project.module.ts @@ -6,6 +6,8 @@ import { ProjectRepository } from '@app/common/modules/project/repositiories'; import { CreateOrphanSpaceHandler } from './handler'; import { SpaceRepository } from '@app/common/modules/space'; import { CommunityRepository } from '@app/common/modules/community/repositories'; +import { InviteUserRepository } from '@app/common/modules/Invite-user/repositiories'; +import { UserRepository } from '@app/common/modules/user/repositories'; const CommandHandlers = [CreateOrphanSpaceHandler]; @@ -19,6 +21,8 @@ const CommandHandlers = [CreateOrphanSpaceHandler]; CommunityRepository, ProjectService, ProjectRepository, + InviteUserRepository, + UserRepository, ], exports: [ProjectService, CqrsModule], }) diff --git a/src/project/services/project.service.ts b/src/project/services/project.service.ts index 75aa67a..1d5e609 100644 --- a/src/project/services/project.service.ts +++ b/src/project/services/project.service.ts @@ -12,11 +12,17 @@ import { ProjectDto } from '@app/common/modules/project/dtos'; import { PageResponse } from '@app/common/dto/pagination.response.dto'; import { CommandBus } from '@nestjs/cqrs'; import { CreateOrphanSpaceCommand } from '../command/create-orphan-space-command'; +import { InviteUserRepository } from '@app/common/modules/Invite-user/repositiories'; +import { UserRepository } from '@app/common/modules/user/repositories'; +import { UserStatusEnum } from '@app/common/constants/user-status.enum'; +import { RoleType } from '@app/common/constants/role.type.enum'; @Injectable() export class ProjectService { constructor( private readonly projectRepository: ProjectRepository, + private readonly inviteUserRepository: InviteUserRepository, + private readonly userRepository: UserRepository, private commandBus: CommandBus, ) {} @@ -181,6 +187,78 @@ export class ProjectService { } } + async getUsersByProject(uuid: string): Promise { + try { + // Fetch invited users + const invitedUsers = await this.inviteUserRepository.find({ + where: { project: { uuid }, isActive: true }, + select: [ + 'firstName', + 'lastName', + 'email', + 'createdAt', + 'status', + 'phoneNumber', + 'jobTitle', + 'invitedBy', + 'isEnabled', + ], + relations: ['roleType'], + }); + + // Fetch project users + const users = await this.userRepository.find({ + where: { project: { uuid }, isActive: true }, + select: ['firstName', 'lastName', 'email', 'createdAt'], + relations: ['roleType'], + }); + + // Combine both arrays + const allUsers = [...users, ...invitedUsers]; + + const normalizedUsers = allUsers.map((user) => { + const createdAt = new Date(user.createdAt); + const createdDate = createdAt.toLocaleDateString(); + const createdTime = createdAt.toLocaleTimeString(); + + // Normalize user properties + const normalizedProps = this.normalizeUserProperties(user); + + // Return the normalized user object + return { + ...user, + createdDate, + createdTime, + ...normalizedProps, + }; + }); + + return new SuccessResponseDto({ + message: `Users in project with ID ${uuid} retrieved successfully`, + data: normalizedUsers, + statusCode: HttpStatus.OK, + }); + } catch (error) { + if (error instanceof HttpException) { + throw error; + } + + throw new HttpException( + `An error occurred while retrieving users in the project with id ${uuid}`, + HttpStatus.INTERNAL_SERVER_ERROR, + ); + } + } + normalizeUserProperties(user: any) { + return { + status: user.status ?? UserStatusEnum.ACTIVE, + invitedBy: user.invitedBy ?? RoleType.SPACE_MEMBER, + isEnabled: user.isEnabled ?? true, + phoneNumber: user.phoneNumber ?? null, + jobTitle: user.jobTitle ?? null, + roleType: user.roleType?.type ?? null, + }; + } async findOne(uuid: string): Promise { const project = await this.projectRepository.findOne({ where: { uuid } }); return project;