From 3e7c2de9a4396454744238e0b5723099bbdfbf93 Mon Sep 17 00:00:00 2001 From: Philipinho <16838612+Philipinho@users.noreply.github.com> Date: Sat, 26 Aug 2023 23:38:14 +0100 Subject: [PATCH] Return user and with current workspace * Create endpoint to return user and their workspace * Only return auth tokens on login/signup * Allow nullable workspace name --- server/src/core/auth/dto/tokens.dto.ts | 4 ++ server/src/core/auth/services/auth.service.ts | 15 +++---- .../src/core/auth/services/token.service.ts | 8 ++++ server/src/core/user/user.controller.ts | 19 +++++---- server/src/core/user/user.service.ts | 20 +++++---- .../workspace/entities/workspace.entity.ts | 2 +- .../repositories/workspace.repository.ts | 4 ++ .../workspace/services/workspace.service.ts | 41 +++++++++++++++++-- 8 files changed, 85 insertions(+), 28 deletions(-) create mode 100644 server/src/core/auth/dto/tokens.dto.ts diff --git a/server/src/core/auth/dto/tokens.dto.ts b/server/src/core/auth/dto/tokens.dto.ts new file mode 100644 index 0000000..a162be3 --- /dev/null +++ b/server/src/core/auth/dto/tokens.dto.ts @@ -0,0 +1,4 @@ +export interface TokensDto { + accessToken: string; + refreshToken: string; +} diff --git a/server/src/core/auth/services/auth.service.ts b/server/src/core/auth/services/auth.service.ts index 6f85b60..0471920 100644 --- a/server/src/core/auth/services/auth.service.ts +++ b/server/src/core/auth/services/auth.service.ts @@ -1,13 +1,10 @@ -import { - BadRequestException, - Injectable, - UnauthorizedException, -} from '@nestjs/common'; +import { Injectable, UnauthorizedException } from '@nestjs/common'; import { LoginDto } from '../dto/login.dto'; import { User } from '../../user/entities/user.entity'; import { CreateUserDto } from '../../user/dto/create-user.dto'; import { UserService } from '../../user/user.service'; import { TokenService } from './token.service'; +import { TokensDto } from '../dto/tokens.dto'; @Injectable() export class AuthService { @@ -29,16 +26,16 @@ export class AuthService { user.lastLoginAt = new Date(); - const token: string = await this.tokenService.generateJwt(user); + const tokens: TokensDto = await this.tokenService.generateTokens(user); - return { user, token }; + return { tokens }; } async register(createUserDto: CreateUserDto) { const user: User = await this.userService.create(createUserDto); - const token: string = await this.tokenService.generateJwt(user); + const tokens: TokensDto = await this.tokenService.generateTokens(user); - return { user, token }; + return { tokens }; } } diff --git a/server/src/core/auth/services/token.service.ts b/server/src/core/auth/services/token.service.ts index a7e8317..d5ca91c 100644 --- a/server/src/core/auth/services/token.service.ts +++ b/server/src/core/auth/services/token.service.ts @@ -3,6 +3,7 @@ import { JwtService } from '@nestjs/jwt'; import { EnvironmentService } from '../../../environment/environment.service'; import { User } from '../../user/entities/user.entity'; import { FastifyRequest } from 'fastify'; +import { TokensDto } from "../dto/tokens.dto"; @Injectable() export class TokenService { @@ -18,6 +19,13 @@ export class TokenService { return await this.jwtService.signAsync(payload); } + async generateTokens(user: User): Promise { + return { + accessToken: await this.generateJwt(user), + refreshToken: null, + }; + } + async verifyJwt(token: string) { return await this.jwtService.verifyAsync(token, { secret: this.environmentService.getJwtSecret(), diff --git a/server/src/core/user/user.controller.ts b/server/src/core/user/user.controller.ts index d6d4728..1fa6f22 100644 --- a/server/src/core/user/user.controller.ts +++ b/server/src/core/user/user.controller.ts @@ -1,11 +1,6 @@ import { Controller, Get, - Post, - Body, - Patch, - Param, - Delete, UseGuards, HttpCode, HttpStatus, @@ -13,11 +8,10 @@ import { UnauthorizedException, } from '@nestjs/common'; import { UserService } from './user.service'; -import { CreateUserDto } from './dto/create-user.dto'; -import { UpdateUserDto } from './dto/update-user.dto'; import { JwtGuard } from '../auth/guards/JwtGuard'; import { FastifyRequest } from 'fastify'; import { User } from './entities/user.entity'; +import { Workspace } from '../workspace/entities/workspace.entity'; @UseGuards(JwtGuard) @Controller('user') @@ -36,4 +30,15 @@ export class UserController { return { user }; } + + @HttpCode(HttpStatus.OK) + @Get('info') + async getUserInfo(@Req() req: FastifyRequest) { + const jwtPayload = req['user']; + + const data: { workspace: Workspace; user: User } = + await this.userService.getUserInstance(jwtPayload.sub); + + return data; + } } diff --git a/server/src/core/user/user.service.ts b/server/src/core/user/user.service.ts index 35c1c81..3690253 100644 --- a/server/src/core/user/user.service.ts +++ b/server/src/core/user/user.service.ts @@ -7,6 +7,7 @@ import { plainToInstance } from 'class-transformer'; import * as bcrypt from 'bcrypt'; import { WorkspaceService } from '../workspace/services/workspace.service'; import { CreateWorkspaceDto } from '../workspace/dto/create-workspace.dto'; +import { Workspace } from "../workspace/entities/workspace.entity"; @Injectable() export class UserService { @@ -27,17 +28,20 @@ export class UserService { user = await this.userRepository.save(user); - //TODO: create workspace if it is not a signup to an existing workspace - const workspaceDto: CreateWorkspaceDto = { - name: user.name, // will be better handled - }; - - await this.workspaceService.create(workspaceDto, user.id); + //TODO: only create workspace if it is not a signup to an existing workspace + await this.workspaceService.create(user.id); return user; } - findById(userId: string) { + async getUserInstance(userId: string) { + const user: User = await this.findById(userId); + const workspace: Workspace = + await this.workspaceService.getUserCurrentWorkspace(userId); + return { user, workspace }; + } + + async findById(userId: string) { return this.userRepository.findById(userId); } @@ -45,7 +49,7 @@ export class UserService { return this.userRepository.findByEmail(email); } - update(id: number, updateUserDto: UpdateUserDto) { + async update(id: number, updateUserDto: UpdateUserDto) { return `This action updates a #${id} user`; } diff --git a/server/src/core/workspace/entities/workspace.entity.ts b/server/src/core/workspace/entities/workspace.entity.ts index 88d17b2..10d8def 100644 --- a/server/src/core/workspace/entities/workspace.entity.ts +++ b/server/src/core/workspace/entities/workspace.entity.ts @@ -27,7 +27,7 @@ export class Workspace { @Column({ length: 255, nullable: true }) logo: string; - @Column({ length: 255, unique: true }) + @Column({ length: 255, nullable: true, unique: true }) hostname: string; @Column({ length: 255, nullable: true }) diff --git a/server/src/core/workspace/repositories/workspace.repository.ts b/server/src/core/workspace/repositories/workspace.repository.ts index f4bf70b..f833e7c 100644 --- a/server/src/core/workspace/repositories/workspace.repository.ts +++ b/server/src/core/workspace/repositories/workspace.repository.ts @@ -7,4 +7,8 @@ export class WorkspaceRepository extends Repository { constructor(private dataSource: DataSource) { super(Workspace, dataSource.createEntityManager()); } + + async findById(workspaceId: string) { + return this.findOneBy({ id: workspaceId }); + } } diff --git a/server/src/core/workspace/services/workspace.service.ts b/server/src/core/workspace/services/workspace.service.ts index 4fdce8d..0be59be 100644 --- a/server/src/core/workspace/services/workspace.service.ts +++ b/server/src/core/workspace/services/workspace.service.ts @@ -16,15 +16,21 @@ export class WorkspaceService { ) {} async create( - createWorkspaceDto: CreateWorkspaceDto, userId: string, + createWorkspaceDto?: CreateWorkspaceDto, ): Promise { - let workspace: Workspace = plainToInstance(Workspace, createWorkspaceDto); + let workspace: Workspace; + + if (createWorkspaceDto) { + workspace = plainToInstance(Workspace, createWorkspaceDto); + } else { + workspace = new Workspace(); + } workspace.inviteCode = uuid(); workspace.creatorId = userId; - if (!workspace.hostname?.trim()) { + if (workspace.name && !workspace.hostname?.trim()) { workspace.hostname = generateHostname(createWorkspaceDto.name); } @@ -46,4 +52,33 @@ export class WorkspaceService { return this.workspaceUserRepository.save(workspaceUser); } + + async findById(workspaceId: string): Promise { + return await this.workspaceRepository.findById(workspaceId); + } + + async getUserCurrentWorkspace( + userId: string, + workspaceId?: string, + ): Promise { + // TODO: use workspaceId and fetch workspace based on the id + // we currently assume the user belongs to one workspace + const userWorkspace = await this.workspaceUserRepository.findOne({ + where: { userId: userId }, + relations: ['workspace'], + }); + + return userWorkspace.workspace; + } + + async userWorkspaces(userId: string): Promise { + const workspaces = await this.workspaceUserRepository.find({ + where: { userId: userId }, + relations: ['workspace'], + }); + + return workspaces.map( + (userWorkspace: WorkspaceUser) => userWorkspace.workspace, + ); + } }