diff --git a/apps/server/src/core/auth/guards/jwt.guard.ts b/apps/server/src/core/auth/guards/jwt.guard.ts index f849077f..12775572 100644 --- a/apps/server/src/core/auth/guards/jwt.guard.ts +++ b/apps/server/src/core/auth/guards/jwt.guard.ts @@ -47,7 +47,7 @@ export class JwtGuard implements CanActivate { //fetch user and current workspace data from db request['user'] = await this.userService.getUserInstance(payload.sub); } catch (error) { - throw new UnauthorizedException(error.message); + throw new UnauthorizedException('Failed to fetch auth user'); } return true; diff --git a/apps/server/src/core/user/user.service.ts b/apps/server/src/core/user/user.service.ts index 03fabe9a..ec73bd18 100644 --- a/apps/server/src/core/user/user.service.ts +++ b/apps/server/src/core/user/user.service.ts @@ -10,7 +10,6 @@ import { UserRepository } from './repositories/user.repository'; import { plainToInstance } from 'class-transformer'; import * as bcrypt from 'bcrypt'; import { WorkspaceService } from '../workspace/services/workspace.service'; -import { Workspace } from '../workspace/entities/workspace.entity'; import { DataSource, EntityManager } from 'typeorm'; import { transactionWrapper } from '../../helpers/db.helper'; import { CreateWorkspaceDto } from '../workspace/dto/create-workspace.dto'; @@ -61,7 +60,10 @@ export class UserService { } async getUserInstance(userId: string) { + console.log('what is') + const user: User = await this.findById(userId); + console.log('what one') if (!user) { throw new NotFoundException('User not found'); diff --git a/apps/server/src/core/workspace/controllers/workspace.controller.ts b/apps/server/src/core/workspace/controllers/workspace.controller.ts index 97c13588..2da846a2 100644 --- a/apps/server/src/core/workspace/controllers/workspace.controller.ts +++ b/apps/server/src/core/workspace/controllers/workspace.controller.ts @@ -18,11 +18,15 @@ import { User } from '../../user/entities/user.entity'; import { CurrentWorkspace } from '../../../decorators/current-workspace.decorator'; import { Workspace } from '../entities/workspace.entity'; import { PaginationOptions } from '../../../helpers/pagination/pagination-options'; +import { WorkspaceUserService } from '../services/workspace-user.service'; @UseGuards(JwtGuard) @Controller('workspaces') export class WorkspaceController { - constructor(private readonly workspaceService: WorkspaceService) {} + constructor( + private readonly workspaceService: WorkspaceService, + private readonly workspaceUserService: WorkspaceUserService, + ) {} @HttpCode(HttpStatus.OK) @Post('/') @@ -67,7 +71,10 @@ export class WorkspaceController { pagination: PaginationOptions, @CurrentWorkspace() workspace: Workspace, ) { - return this.workspaceService.getWorkspaceUsers(workspace.id, pagination); + return this.workspaceUserService.getWorkspaceUsers( + workspace.id, + pagination, + ); } @HttpCode(HttpStatus.OK) @@ -76,7 +83,7 @@ export class WorkspaceController { @Body() addWorkspaceUserDto: AddWorkspaceUserDto, @CurrentWorkspace() workspace: Workspace, ) { - return this.workspaceService.addUserToWorkspace( + return this.workspaceUserService.addUserToWorkspace( addWorkspaceUserDto.userId, workspace.id, addWorkspaceUserDto.role, @@ -89,7 +96,7 @@ export class WorkspaceController { @Body() removeWorkspaceUserDto: RemoveWorkspaceUserDto, @CurrentWorkspace() workspace: Workspace, ) { - return this.workspaceService.removeUserFromWorkspace( + return this.workspaceUserService.removeUserFromWorkspace( removeWorkspaceUserDto.userId, workspace.id, ); @@ -102,7 +109,7 @@ export class WorkspaceController { @AuthUser() authUser: User, @CurrentWorkspace() workspace: Workspace, ) { - return this.workspaceService.updateWorkspaceUserRole( + return this.workspaceUserService.updateWorkspaceUserRole( authUser, workspaceUserRoleDto, workspace.id, diff --git a/apps/server/src/core/workspace/services/workspace-user.service.ts b/apps/server/src/core/workspace/services/workspace-user.service.ts new file mode 100644 index 00000000..34e7249e --- /dev/null +++ b/apps/server/src/core/workspace/services/workspace-user.service.ts @@ -0,0 +1,204 @@ +import { + BadRequestException, + Injectable, + NotFoundException, +} from '@nestjs/common'; +import { WorkspaceUserRepository } from '../repositories/workspace-user.repository'; +import { + WorkspaceUser, + WorkspaceUserRole, +} from '../entities/workspace-user.entity'; +import { Workspace } from '../entities/workspace.entity'; +import { UpdateWorkspaceUserRoleDto } from '../dto/update-workspace-user-role.dto'; +import { SpaceService } from '../../space/space.service'; +import { PaginationOptions } from '../../../helpers/pagination/pagination-options'; +import { PaginationMetaDto } from '../../../helpers/pagination/pagination-meta-dto'; +import { PaginatedResult } from '../../../helpers/pagination/paginated-result'; +import { User } from '../../user/entities/user.entity'; +import { DataSource, EntityManager } from 'typeorm'; +import { transactionWrapper } from '../../../helpers/db.helper'; + +@Injectable() +export class WorkspaceUserService { + constructor( + private workspaceUserRepository: WorkspaceUserRepository, + private spaceService: SpaceService, + private dataSource: DataSource, + ) {} + + async addUserToWorkspace( + userId: string, + workspaceId: string, + role: string, + manager?: EntityManager, + ): Promise { + let addedUser; + + await transactionWrapper( + async (manager) => { + const existingWorkspaceUser = await manager.findOne(WorkspaceUser, { + where: { userId: userId, workspaceId: workspaceId }, + }); + + const userExists = await manager.exists(User, { + where: { id: userId }, + }); + if (!userExists) { + throw new NotFoundException('User not found'); + } + + if (existingWorkspaceUser) { + throw new BadRequestException( + 'User is already a member of this workspace', + ); + } + + const workspaceUser = new WorkspaceUser(); + workspaceUser.userId = userId; + workspaceUser.workspaceId = workspaceId; + workspaceUser.role = role; + + addedUser = await manager.save(workspaceUser); + }, + this.dataSource, + manager, + ); + + return addedUser; + } + + async updateWorkspaceUserRole( + authUser: User, + workspaceUserRoleDto: UpdateWorkspaceUserRoleDto, + workspaceId: string, + ) { + const workspaceUser = await this.getWorkspaceUser( + workspaceUserRoleDto.userId, + workspaceId, + ); + + if (workspaceUser.role === workspaceUserRoleDto.role) { + return workspaceUser; + } + + const workspaceOwnerCount = await this.workspaceUserRepository.count({ + where: { + role: WorkspaceUserRole.OWNER, + }, + }); + + if ( + workspaceUser.role === WorkspaceUserRole.OWNER && + workspaceOwnerCount === 1 + ) { + throw new BadRequestException( + 'There must be at least one workspace owner', + ); + } + + workspaceUser.role = workspaceUserRoleDto.role; + + return this.workspaceUserRepository.save(workspaceUser); + } + + async removeUserFromWorkspace( + userId: string, + workspaceId: string, + ): Promise { + await this.getWorkspaceUser(userId, workspaceId); + + const workspaceUser = await this.getWorkspaceUser(userId, workspaceId); + + const workspaceOwnerCount = await this.workspaceUserRepository.count({ + where: { + role: WorkspaceUserRole.OWNER, + }, + }); + + if ( + workspaceUser.role === WorkspaceUserRole.OWNER && + workspaceOwnerCount === 1 + ) { + throw new BadRequestException( + 'There must be at least one workspace owner', + ); + } + + await this.workspaceUserRepository.delete({ + userId, + workspaceId, + }); + } + + async getUserWorkspaces( + userId: string, + paginationOptions: PaginationOptions, + ): Promise> { + const [workspaces, count] = await this.workspaceUserRepository.findAndCount( + { + where: { userId: userId }, + relations: ['workspace'], + take: paginationOptions.limit, + skip: paginationOptions.skip, + }, + ); + + const userWorkspaces = workspaces.map( + (userWorkspace: WorkspaceUser) => userWorkspace.workspace, + ); + + const paginationMeta = new PaginationMetaDto({ count, paginationOptions }); + return new PaginatedResult(userWorkspaces, paginationMeta); + } + + async getWorkspaceUsers( + workspaceId: string, + paginationOptions: PaginationOptions, + ): Promise> { + const [workspaceUsers, count] = + await this.workspaceUserRepository.findAndCount({ + relations: ['user'], + where: { + workspace: { + id: workspaceId, + }, + }, + take: paginationOptions.limit, + skip: paginationOptions.skip, + }); + + const users = workspaceUsers.map((workspaceUser) => { + workspaceUser.user.password = ''; + return { + ...workspaceUser.user, + role: workspaceUser.role, + }; + }); + + const paginationMeta = new PaginationMetaDto({ count, paginationOptions }); + return new PaginatedResult(users, paginationMeta); + } + + async getUserRoleInWorkspace( + userId: string, + workspaceId: string, + ): Promise { + const workspaceUser = await this.getWorkspaceUser(userId, workspaceId); + return workspaceUser.role ? workspaceUser.role : null; + } + + async getWorkspaceUser( + userId: string, + workspaceId: string, + ): Promise { + const workspaceUser = await this.workspaceUserRepository.findOne({ + where: { userId, workspaceId }, + }); + + if (!workspaceUser) { + throw new BadRequestException('Workspace member not found'); + } + + return workspaceUser; + } +} diff --git a/apps/server/src/core/workspace/services/workspace.service.ts b/apps/server/src/core/workspace/services/workspace.service.ts index 5891b0c3..b7f63878 100644 --- a/apps/server/src/core/workspace/services/workspace.service.ts +++ b/apps/server/src/core/workspace/services/workspace.service.ts @@ -24,6 +24,7 @@ import { User } from '../../user/entities/user.entity'; import { DataSource, EntityManager } from 'typeorm'; import { transactionWrapper } from '../../../helpers/db.helper'; import { CreateSpaceDto } from '../../space/dto/create-space.dto'; +import { WorkspaceUserService } from './workspace-user.service'; @Injectable() export class WorkspaceService { @@ -31,6 +32,8 @@ export class WorkspaceService { private workspaceRepository: WorkspaceRepository, private workspaceUserRepository: WorkspaceUserRepository, private spaceService: SpaceService, + private workspaceUserService: WorkspaceUserService, + private dataSource: DataSource, ) {} @@ -60,7 +63,7 @@ export class WorkspaceService { createWorkspaceDto ?? null, manager, ); - await this.addUserToWorkspace( + await this.workspaceUserService.addUserToWorkspace( userId, createdWorkspace.id, WorkspaceUserRole.OWNER, @@ -96,7 +99,7 @@ export class WorkspaceService { // add user to workspace and default space - await this.addUserToWorkspace( + await this.workspaceUserService.addUserToWorkspace( userId, firstWorkspace[0].id, WorkspaceUserRole.MEMBER, @@ -180,110 +183,6 @@ export class WorkspaceService { // delete workspace } - async addUserToWorkspace( - userId: string, - workspaceId: string, - role: string, - manager?: EntityManager, - ): Promise { - let addedUser; - - await transactionWrapper( - async (manager) => { - const existingWorkspaceUser = await manager.findOne(WorkspaceUser, { - where: { userId: userId, workspaceId: workspaceId }, - }); - - const userExists = await manager.exists(User, { - where: { id: userId }, - }); - if (!userExists) { - throw new NotFoundException('User not found'); - } - - if (existingWorkspaceUser) { - throw new BadRequestException( - 'User is already a member of this workspace', - ); - } - - const workspaceUser = new WorkspaceUser(); - workspaceUser.userId = userId; - workspaceUser.workspaceId = workspaceId; - workspaceUser.role = role; - - addedUser = await manager.save(workspaceUser); - }, - this.dataSource, - manager, - ); - - return addedUser; - } - - async updateWorkspaceUserRole( - authUser: User, - workspaceUserRoleDto: UpdateWorkspaceUserRoleDto, - workspaceId: string, - ) { - const workspaceUser = await this.getWorkspaceUser( - workspaceUserRoleDto.userId, - workspaceId, - ); - - if (workspaceUser.role === workspaceUserRoleDto.role) { - return workspaceUser; - } - - const workspaceOwnerCount = await this.workspaceUserRepository.count({ - where: { - role: WorkspaceUserRole.OWNER, - }, - }); - - if ( - workspaceUser.role === WorkspaceUserRole.OWNER && - workspaceOwnerCount === 1 - ) { - throw new BadRequestException( - 'There must be at least one workspace owner', - ); - } - - workspaceUser.role = workspaceUserRoleDto.role; - - return this.workspaceUserRepository.save(workspaceUser); - } - - async removeUserFromWorkspace( - userId: string, - workspaceId: string, - ): Promise { - await this.getWorkspaceUser(userId, workspaceId); - - const workspaceUser = await this.getWorkspaceUser(userId, workspaceId); - - const workspaceOwnerCount = await this.workspaceUserRepository.count({ - where: { - role: WorkspaceUserRole.OWNER, - }, - }); - - if ( - workspaceUser.role === WorkspaceUserRole.OWNER && - workspaceOwnerCount === 1 - ) { - throw new BadRequestException( - 'There must be at least one workspace owner', - ); - } - - await this.workspaceUserRepository.delete({ - userId, - workspaceId, - }); - } - async getUserCurrentWorkspace(userId: string): Promise { const userWorkspace = await this.workspaceUserRepository.findOne({ where: { userId: userId }, @@ -320,55 +219,4 @@ export class WorkspaceService { const paginationMeta = new PaginationMetaDto({ count, paginationOptions }); return new PaginatedResult(userWorkspaces, paginationMeta); } - - async getWorkspaceUsers( - workspaceId: string, - paginationOptions: PaginationOptions, - ): Promise> { - const [workspaceUsers, count] = - await this.workspaceUserRepository.findAndCount({ - relations: ['user'], - where: { - workspace: { - id: workspaceId, - }, - }, - take: paginationOptions.limit, - skip: paginationOptions.skip, - }); - - const users = workspaceUsers.map((workspaceUser) => { - workspaceUser.user.password = ''; - return { - ...workspaceUser.user, - role: workspaceUser.role, - }; - }); - - const paginationMeta = new PaginationMetaDto({ count, paginationOptions }); - return new PaginatedResult(users, paginationMeta); - } - - async getUserRoleInWorkspace( - userId: string, - workspaceId: string, - ): Promise { - const workspaceUser = await this.getWorkspaceUser(userId, workspaceId); - return workspaceUser.role ? workspaceUser.role : null; - } - - async getWorkspaceUser( - userId: string, - workspaceId: string, - ): Promise { - const workspaceUser = await this.workspaceUserRepository.findOne({ - where: { userId, workspaceId }, - }); - - if (!workspaceUser) { - throw new BadRequestException('Workspace member not found'); - } - - return workspaceUser; - } } diff --git a/apps/server/src/core/workspace/workspace.module.ts b/apps/server/src/core/workspace/workspace.module.ts index af16e873..7507afd5 100644 --- a/apps/server/src/core/workspace/workspace.module.ts +++ b/apps/server/src/core/workspace/workspace.module.ts @@ -9,6 +9,7 @@ import { WorkspaceInvitation } from './entities/workspace-invitation.entity'; import { WorkspaceUserRepository } from './repositories/workspace-user.repository'; import { AuthModule } from '../auth/auth.module'; import { SpaceModule } from '../space/space.module'; +import { WorkspaceUserService } from './services/workspace-user.service'; @Module({ imports: [ @@ -17,7 +18,12 @@ import { SpaceModule } from '../space/space.module'; SpaceModule, ], controllers: [WorkspaceController], - providers: [WorkspaceService, WorkspaceRepository, WorkspaceUserRepository], + providers: [ + WorkspaceService, + WorkspaceUserService, + WorkspaceRepository, + WorkspaceUserRepository, + ], exports: [WorkspaceService, WorkspaceRepository, WorkspaceUserRepository], }) export class WorkspaceModule {}