diff --git a/src/app.module.ts b/src/app.module.ts index 4637972..d90331a 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -24,6 +24,7 @@ import S3Module from './providers/storage/s3/s3.module'; import PointLogModule from './modules/pointLog/pointLog.module'; import { LoggerModule } from './common/logger/winston/logger.module'; import TransactionModule from './providers/database/transaction/transaction.module'; +import ProfileModule from './modules/profile/profile.module'; @Module({ imports: [ @@ -39,6 +40,7 @@ import TransactionModule from './providers/database/transaction/transaction.modu PrismaModule, AuthModule, UserModule, + ProfileModule, NotificationModule, FollowModule, PlanModule, diff --git a/src/modules/auth/auth.controller.ts b/src/modules/auth/auth.controller.ts index 691723f..2a6da1b 100644 --- a/src/modules/auth/auth.controller.ts +++ b/src/modules/auth/auth.controller.ts @@ -50,7 +50,7 @@ export default class AuthController { const { accessToken, refreshToken } = this.service.createTokens(tokenPayload); res.cookie('refreshToken', refreshToken, { - path: '/user/token/refresh', + path: '/auth/refresh/token', httpOnly: true, sameSite: 'lax', secure: true, @@ -80,7 +80,7 @@ export default class AuthController { // 기존 회원의 경우 토큰 반환 res.cookie('refreshToken', tokens.refreshToken, { - path: '/user/token/refresh', + path: '/auth/refresh/token', httpOnly: true, sameSite: 'lax', secure: true, @@ -108,7 +108,7 @@ export default class AuthController { } res.cookie('refreshToken', tokens.refreshToken, { - path: '/user/token/refresh', + path: '/auth/refresh/token', httpOnly: true, sameSite: 'lax', secure: true, @@ -138,7 +138,7 @@ export default class AuthController { } res.cookie('refreshToken', tokens.refreshToken, { - path: '/user/token/refresh', + path: '/auth/refresh/token', httpOnly: true, sameSite: 'lax', secure: true, @@ -162,7 +162,7 @@ export default class AuthController { const { accessToken, refreshToken: newRefreshToken } = this.service.createNewToken(refreshToken); res.cookie('refreshToken', newRefreshToken, { - path: '/user/token/refresh', + path: '/auth/refresh/token', httpOnly: true, sameSite: 'lax', secure: true, diff --git a/src/modules/auth/auth.module.ts b/src/modules/auth/auth.module.ts index 44b9f68..86fb411 100644 --- a/src/modules/auth/auth.module.ts +++ b/src/modules/auth/auth.module.ts @@ -9,6 +9,7 @@ import { GoogleStrategy } from './strategy/google.strategy'; import AuthController from './auth.controller'; import { KakaoStrategy } from './strategy/kakao.strategy'; import { NaverStrategy } from './strategy/naver.strategy'; +import ProfileModule from '../profile/profile.module'; @Module({ imports: [ @@ -16,6 +17,7 @@ import { NaverStrategy } from './strategy/naver.strategy'; JwtModule.register({ secret: process.env.JWT_SECRET }), + ProfileModule, UserStatsModule ], controllers: [AuthController], diff --git a/src/modules/auth/auth.repository.ts b/src/modules/auth/auth.repository.ts index 5ed0be9..5716aec 100644 --- a/src/modules/auth/auth.repository.ts +++ b/src/modules/auth/auth.repository.ts @@ -1,9 +1,6 @@ import { Injectable } from '@nestjs/common'; -import { IDreamerProfile, IMakerProfile } from 'src/modules/user/domain/profile.interface'; -import { DreamerProfileMapper, MakerProfileMapper } from 'src/modules/user/domain/profile.mapper'; import { IUser } from 'src/modules/user/domain/user.interface'; import UserMapper from 'src/modules/user/domain/user.mapper'; -import { DreamerProfileProperties, MakerProfileProperties } from 'src/modules/user/types/profile.types'; import { OAuthProperties, SignupProperties } from 'src/modules/user/types/user.types'; import DBClient from 'src/providers/database/prisma/DB.client'; @@ -40,33 +37,4 @@ export default class AuthRepository { return new UserMapper(data).toDomain(); } - - async createDreamer(user: Partial): Promise { - const profile = await this.db.dreamerProfile.create({ - data: { - user: { connect: { id: user.userId } }, - tripTypes: user.tripTypes, - serviceArea: user.serviceArea, - image: user.image - } - }); - - return new DreamerProfileMapper(profile).toDomain(); - } - - async createMaker(user: Partial): Promise { - const profile = await this.db.makerProfile.create({ - data: { - user: { connect: { id: user.userId } }, - serviceArea: user.serviceArea, - serviceTypes: user.serviceTypes, - gallery: user.gallery, - description: user.description, - detailDescription: user.detailDescription, - image: user.image - } - }); - - return new MakerProfileMapper(profile).toDomain(); - } } diff --git a/src/modules/auth/auth.service.ts b/src/modules/auth/auth.service.ts index 08e0a6d..b7ecc9f 100644 --- a/src/modules/auth/auth.service.ts +++ b/src/modules/auth/auth.service.ts @@ -3,20 +3,22 @@ import BadRequestError from 'src/common/errors/badRequestError'; import { JwtService } from '@nestjs/jwt'; import { Injectable } from '@nestjs/common'; import User from 'src/modules/user/domain/user.domain'; -import { DreamerProfile, MakerProfile } from 'src/modules/user/domain/profile.domain'; +import { DreamerProfile, MakerProfile } from 'src/modules/profile/domain/profile.domain'; import UserStatsService from '../userStats/userStats.service'; import { FilteredUserProperties, OAuthProperties, UserProperties } from 'src/modules/user/types/user.types'; import AuthRepository from './auth.repository'; import { Role, RoleValues } from 'src/common/constants/role.type'; -import { DreamerProfileProperties, MakerProfileProperties } from 'src/modules/user/types/profile.types'; +import { DreamerProfileProperties, MakerProfileProperties } from 'src/modules/profile/types/profile.types'; import { OAuthProvider } from 'src/common/constants/oauth.type'; import UnauthorizedError from 'src/common/errors/unauthorizedError'; +import ProfileService from '../profile/profile.service'; @Injectable() export default class AuthService { constructor( private readonly repository: AuthRepository, private readonly jwt: JwtService, + private readonly profile: ProfileService, private readonly userStats: UserStatsService ) {} @@ -44,14 +46,7 @@ export default class AuthService { const userData = await User.create(user); const savedUser = await this.repository.create(userData.signupData()); - // 역할에 따라 프로필 등록 - if (savedUser.getRole() === RoleValues.DREAMER) { - const profileData = DreamerProfile.create({ ...profile, userId: savedUser.getId() }); - await this.repository.createDreamer(profileData); - } else { - const profileData = MakerProfile.create({ ...profile, userId: savedUser.getId() }); - await this.repository.createMaker(profileData.get()); - } + await this.profile.createProfile(savedUser.getId(), savedUser.getRole(), profile); // 유저 생성시 기본값으로 UserStats 생성 await this.userStats.create(savedUser.getId(), {}); diff --git a/src/modules/chatRoom/chatRoom.module.ts b/src/modules/chatRoom/chatRoom.module.ts index c4d2019..f2e67f5 100644 --- a/src/modules/chatRoom/chatRoom.module.ts +++ b/src/modules/chatRoom/chatRoom.module.ts @@ -9,6 +9,7 @@ import ChatModule from '../chat/chat.module'; import ChatRoomGateway from './chatRoom.gateway'; import WebSocketJwtGuard from 'src/common/guards/webSocket.guard'; import UserModule from '../user/user.module'; +import ProfileModule from '../profile/profile.module'; @Module({ imports: [ @@ -17,7 +18,8 @@ import UserModule from '../user/user.module'; }), MongooseModule.forFeature([{ name: ChatRoom.name, schema: ChatRoomSchema }]), ChatModule, - UserModule + UserModule, + ProfileModule ], controllers: [ChatRoomController], diff --git a/src/modules/chatRoom/chatRoom.service.ts b/src/modules/chatRoom/chatRoom.service.ts index ff3c4b2..2148f6d 100644 --- a/src/modules/chatRoom/chatRoom.service.ts +++ b/src/modules/chatRoom/chatRoom.service.ts @@ -13,6 +13,7 @@ import { ChatReference, FileUploadData, FindChatRoomByIdOptions } from 'src/modu import NotFoundError from 'src/common/errors/notFoundError'; import IChatRoom from './domain/chatRoom.interface'; import BadRequestError from 'src/common/errors/badRequestError'; +import ProfileService from '../profile/profile.service'; import TransactionManager from 'src/providers/database/transaction/transaction.manager'; import Transactional from 'src/common/decorators/transaction.decorator'; @@ -23,6 +24,7 @@ export default class ChatRoomService { private readonly repository: ChatRoomRepository, private readonly chatService: ChatService, private readonly userService: UserService, + private readonly profileService: ProfileService, private readonly transactionManager: TransactionManager ) {} @@ -153,7 +155,7 @@ export default class ChatRoomService { const users = await Promise.all( userIds?.map(async (userId) => { const userData = await this.userService.getUser(userId); - const userProfile = await this.userService.getProfile(userData.role, userId); + const userProfile = await this.profileService.getProfile(userData.role, userId); const user = { id: userId, diff --git a/src/modules/plan/plan.module.ts b/src/modules/plan/plan.module.ts index 9045a54..06c0367 100644 --- a/src/modules/plan/plan.module.ts +++ b/src/modules/plan/plan.module.ts @@ -6,9 +6,10 @@ import PlanRepository from './plan.repository'; import PlanService from './plan.service'; import ChatRoomModule from '../chatRoom/chatRoom.module'; import { BullModule } from '@nestjs/bullmq'; +import ProfileModule from '../profile/profile.module'; @Module({ - imports: [BullModule.registerQueue({ name: 'points' }), UserModule, QuoteModule, ChatRoomModule], + imports: [BullModule.registerQueue({ name: 'points' }), UserModule, ProfileModule, QuoteModule, ChatRoomModule], controllers: [PlanController], providers: [PlanRepository, PlanService], exports: [PlanRepository, PlanService] diff --git a/src/modules/plan/plan.service.ts b/src/modules/plan/plan.service.ts index 7b419f3..acc2c03 100644 --- a/src/modules/plan/plan.service.ts +++ b/src/modules/plan/plan.service.ts @@ -24,6 +24,7 @@ import { Queue } from 'bullmq'; import { PointEventEnum } from 'src/common/constants/pointEvent.type'; import TransactionManager from 'src/providers/database/transaction/transaction.manager'; import Transactional from 'src/common/decorators/transaction.decorator'; +import ProfileService from '../profile/profile.service'; @Injectable() export default class PlanService { @@ -32,6 +33,7 @@ export default class PlanService { private readonly repository: PlanRepository, private readonly quoteService: QuoteService, private readonly userService: UserService, + private readonly profileService: ProfileService, private readonly chatRoomService: ChatRoomService, private readonly transactionManager: TransactionManager, private readonly eventEmitter: EventEmitter2 @@ -54,7 +56,7 @@ export default class PlanService { userId: string, options: PlanQueryOptions ): Promise<{ totalCount: number; groupByCount: GroupByCount; list: PlanToClientProperties[] }> { - const makerProfile = await this.userService.getProfile(RoleValues.MAKER, userId); + const makerProfile = await this.profileService.getProfile(RoleValues.MAKER, userId); const serviceArea: ServiceArea[] = options.isAssigned === true ? undefined : makerProfile.serviceArea; options.serviceArea = serviceArea; //NOTE. 메이커의 서비스지역 필터링 @@ -181,7 +183,7 @@ export default class PlanService { throw new BadRequestError(ErrorMessage.PLAN_ASSIGN_NOT_MAKER); } - const assigneeServiceArea = (await this.userService.getProfile(RoleValues.MAKER, assigneeId)).serviceArea; + const assigneeServiceArea = (await this.profileService.getProfile(RoleValues.MAKER, assigneeId)).serviceArea; if (!assigneeServiceArea.includes(plan.getServiceArea())) { throw new BadRequestError(ErrorMessage.PLAN_MAKER_NOT_IN_SERVICE_AREA); } diff --git a/src/modules/user/domain/profile.domain.ts b/src/modules/profile/domain/profile.domain.ts similarity index 100% rename from src/modules/user/domain/profile.domain.ts rename to src/modules/profile/domain/profile.domain.ts diff --git a/src/modules/user/domain/profile.interface.ts b/src/modules/profile/domain/profile.interface.ts similarity index 89% rename from src/modules/user/domain/profile.interface.ts rename to src/modules/profile/domain/profile.interface.ts index bef8524..ab7d6a4 100644 --- a/src/modules/user/domain/profile.interface.ts +++ b/src/modules/profile/domain/profile.interface.ts @@ -1,4 +1,4 @@ -import { DreamerProfileProperties, MakerProfileProperties } from 'src/modules/user/types/profile.types'; +import { DreamerProfileProperties, MakerProfileProperties } from 'src/modules/profile/types/profile.types'; export interface IDreamerProfile { update(data: Partial): DreamerProfileProperties; diff --git a/src/modules/user/domain/profile.mapper.ts b/src/modules/profile/domain/profile.mapper.ts similarity index 89% rename from src/modules/user/domain/profile.mapper.ts rename to src/modules/profile/domain/profile.mapper.ts index 30bd9ef..6f430dd 100644 --- a/src/modules/user/domain/profile.mapper.ts +++ b/src/modules/profile/domain/profile.mapper.ts @@ -1,5 +1,5 @@ import { DreamerProfileProperties, MakerProfileProperties } from '../types/profile.types'; -import { DreamerProfile, MakerProfile } from './profile.domain'; +import { DreamerProfile, MakerProfile } from '../../profile/domain/profile.domain'; export class DreamerProfileMapper { constructor(private readonly dreamer: DreamerProfileProperties) {} @@ -21,6 +21,7 @@ export class MakerProfileMapper { constructor(private readonly maker: MakerProfileProperties) {} toDomain() { + if (!this.maker) return null; return new MakerProfile({ userId: this.maker.userId, image: this.maker.image, diff --git a/src/modules/profile/profile.controller.ts b/src/modules/profile/profile.controller.ts new file mode 100644 index 0000000..fb15be7 --- /dev/null +++ b/src/modules/profile/profile.controller.ts @@ -0,0 +1,49 @@ +import { Body, Controller, Get, Patch } from '@nestjs/common'; +import ProfileService from './profile.service'; +import { + ApiBearerAuth, + ApiBody, + ApiOkResponse, + ApiOperation, + ApiResponse, + ApiUnauthorizedResponse +} from '@nestjs/swagger'; +import { DreamerProfileResponseDTO, MakerProfileResponseDTO } from '../user/types/user.response.dto'; +import { UserRole } from 'src/common/decorators/role.decorator'; +import { UserId } from 'src/common/decorators/user.decorator'; +import { DreamerProfileProperties, MakerProfileProperties } from './types/profile.types'; +import UpdateProfileDTO from './types/updateProfile.dto'; + +@Controller('profile') +export default class ProfileController { + constructor(private readonly service: ProfileService) {} + + @Get() + @ApiBearerAuth('accessToken') + @ApiOperation({ summary: '프로필 정보 조회', description: '로그인한 유저의 프로필을 조회합니다' }) + @ApiOkResponse({ type: MakerProfileResponseDTO || DreamerProfileResponseDTO }) + @ApiUnauthorizedResponse({ description: 'Access Token이 없거나 만료되었습니다' }) + async getProfile( + @UserRole() role: string, + @UserId() userId: string + ): Promise { + return await this.service.getProfile(role, userId); + } + + @Patch('update') + @ApiBearerAuth('accessToken') + @ApiOperation({ summary: '프로필 수정', description: '로그인한 유저의 프로필을 수정합니다' }) + @ApiBody({ type: UpdateProfileDTO }) + @ApiResponse({ type: MakerProfileResponseDTO || DreamerProfileResponseDTO }) + @ApiUnauthorizedResponse({ description: 'Access Token이 없거나 만료되었습니다' }) + async updateProfile( + @UserRole() role: string, + @Body() data: Partial, + @UserId() userId: string + ) { + if (role === 'DREAMER') { + return await this.service.updateDreamerProfile(userId, data); + } + return await this.service.updateMakerProfile(userId, data); + } +} diff --git a/src/modules/profile/profile.module.ts b/src/modules/profile/profile.module.ts new file mode 100644 index 0000000..85ae424 --- /dev/null +++ b/src/modules/profile/profile.module.ts @@ -0,0 +1,12 @@ +import { Module } from '@nestjs/common'; +import ProfileController from './profile.controller'; +import ProfileService from './profile.service'; +import ProfileRepository from './profile.repository'; + +@Module({ + imports: [], + controllers: [ProfileController], + providers: [ProfileService, ProfileRepository], + exports: [ProfileService] +}) +export default class ProfileModule {} diff --git a/src/modules/profile/profile.repository.ts b/src/modules/profile/profile.repository.ts new file mode 100644 index 0000000..53dc285 --- /dev/null +++ b/src/modules/profile/profile.repository.ts @@ -0,0 +1,81 @@ +import { Injectable } from '@nestjs/common'; +import DBClient from 'src/providers/database/prisma/DB.client'; +import { IDreamerProfile, IMakerProfile } from './domain/profile.interface'; +import { DreamerProfileMapper, MakerProfileMapper } from './domain/profile.mapper'; +import { DreamerProfileProperties, MakerProfileProperties } from './types/profile.types'; + +@Injectable() +export default class ProfileRepository { + constructor(private readonly db: DBClient) {} + + async findDreamerProfile(userId: string): Promise { + const data = await this.db.dreamerProfile.findUnique({ + where: { + userId + } + }); + + return new DreamerProfileMapper(data).toDomain(); + } + + async findMakerProfile(userId: string): Promise { + const data = await this.db.makerProfile.findUnique({ + where: { + userId + } + }); + + return new MakerProfileMapper(data).toDomain(); + } + + async createDreamer(user: Partial): Promise { + const profile = await this.db.dreamerProfile.create({ + data: { + user: { connect: { id: user.userId } }, + tripTypes: user.tripTypes, + serviceArea: user.serviceArea, + image: user.image + } + }); + + return new DreamerProfileMapper(profile).toDomain(); + } + + async createMaker(user: Partial): Promise { + const profile = await this.db.makerProfile.create({ + data: { + user: { connect: { id: user.userId } }, + serviceArea: user.serviceArea, + serviceTypes: user.serviceTypes, + gallery: user.gallery, + description: user.description, + detailDescription: user.detailDescription, + image: user.image + } + }); + + return new MakerProfileMapper(profile).toDomain(); + } + + async updateDreamerProfile(userId: string, data: Partial): Promise { + const profile = await this.db.dreamerProfile.update({ + where: { + userId + }, + data + }); + + return new DreamerProfileMapper(profile).toDomain(); + } + + async updateMakerProfile(userId: string, data: Partial): Promise { + const profile = await this.db.makerProfile.update({ + where: { + userId + }, + data + }); + + return new MakerProfileMapper(profile).toDomain(); + } +} diff --git a/src/modules/profile/profile.service.ts b/src/modules/profile/profile.service.ts new file mode 100644 index 0000000..7513314 --- /dev/null +++ b/src/modules/profile/profile.service.ts @@ -0,0 +1,62 @@ +import { Injectable } from '@nestjs/common'; +import ProfileRepository from './profile.repository'; +import { DreamerProfileProperties, MakerProfileProperties } from './types/profile.types'; +import BadRequestError from 'src/common/errors/badRequestError'; +import ErrorMessage from 'src/common/constants/errorMessage.enum'; +import { Role, RoleValues } from 'src/common/constants/role.type'; +import { DreamerProfile, MakerProfile } from './domain/profile.domain'; + +@Injectable() +export default class ProfileService { + constructor(private readonly repository: ProfileRepository) {} + + async getProfile(role: string, userId: string): Promise { + if (role === RoleValues.DREAMER) { + const profile = await this.repository.findDreamerProfile(userId); + return profile.get(); + } + + const profile = await this.repository.findMakerProfile(userId); + return profile.get(); + } + + async createProfile( + userId: string, + role: Role, + data: DreamerProfileProperties | MakerProfileProperties + ): Promise { + // 역할에 따라 프로필 등록 + if (role === RoleValues.DREAMER) { + const profileData = DreamerProfile.create({ ...data, userId }); + await this.repository.createDreamer(profileData); + } else { + const profileData = MakerProfile.create({ ...data, userId }); + await this.repository.createMaker(profileData.get()); + } + + return; + } + + async updateDreamerProfile( + userId: string, + data: Partial + ): Promise { + const profile = await this.repository.findDreamerProfile(userId); + if (!profile) { + throw new BadRequestError(ErrorMessage.USER_NOT_FOUND); + } + + const newProfile = await this.repository.updateDreamerProfile(userId, profile.update(data)); + return newProfile.get(); + } + + async updateMakerProfile(userId: string, data: Partial): Promise { + const profile = await this.repository.findMakerProfile(userId); + if (!profile) { + throw new BadRequestError(ErrorMessage.USER_NOT_FOUND); + } + + const newProfile = await this.repository.updateMakerProfile(userId, profile.update(data)); + return newProfile.get(); + } +} diff --git a/src/modules/profile/types/profile.response.dto.ts b/src/modules/profile/types/profile.response.dto.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/modules/user/types/profile.types.ts b/src/modules/profile/types/profile.types.ts similarity index 100% rename from src/modules/user/types/profile.types.ts rename to src/modules/profile/types/profile.types.ts diff --git a/src/modules/user/types/updateProfile.dto.ts b/src/modules/profile/types/updateProfile.dto.ts similarity index 64% rename from src/modules/user/types/updateProfile.dto.ts rename to src/modules/profile/types/updateProfile.dto.ts index 9647686..c8fd63a 100644 --- a/src/modules/user/types/updateProfile.dto.ts +++ b/src/modules/profile/types/updateProfile.dto.ts @@ -1,4 +1,4 @@ import { PartialType } from '@nestjs/swagger'; -import { SignupProfileDTO } from './signup.dto'; +import { SignupProfileDTO } from 'src/modules/user/types/signup.dto'; export default class UpdateProfileDTO extends PartialType(SignupProfileDTO) {} diff --git a/src/modules/user/domain/user.domain.ts b/src/modules/user/domain/user.domain.ts index 7d5c6d0..88063bd 100644 --- a/src/modules/user/domain/user.domain.ts +++ b/src/modules/user/domain/user.domain.ts @@ -11,7 +11,7 @@ import { ComparePassword, HashingPassword } from '../../../common/utilities/hash import { IUser } from './user.interface'; import BadRequestError from 'src/common/errors/badRequestError'; import ErrorMessage from 'src/common/constants/errorMessage.enum'; -import { MakerInfoAndProfileProperties, MakerProfileProperties } from 'src/modules/user/types/profile.types'; +import { MakerInfoAndProfileProperties, MakerProfileProperties } from 'src/modules/profile/types/profile.types'; import { UserStatsProperties, UserStatsToClientProperties } from 'src/modules/userStats/types/userStats.types'; import { OAuthProvider } from 'src/common/constants/oauth.type'; diff --git a/src/modules/user/domain/user.interface.ts b/src/modules/user/domain/user.interface.ts index 3d55e7f..b2aa1be 100644 --- a/src/modules/user/domain/user.interface.ts +++ b/src/modules/user/domain/user.interface.ts @@ -1,5 +1,5 @@ import { Role } from 'src/common/constants/role.type'; -import { MakerInfoAndProfileProperties } from 'src/modules/user/types/profile.types'; +import { MakerInfoAndProfileProperties } from 'src/modules/profile/types/profile.types'; import { FilteredUserProperties, OAuthProperties, diff --git a/src/modules/user/types/user.types.ts b/src/modules/user/types/user.types.ts index 5e77fcb..dbd2e1f 100644 --- a/src/modules/user/types/user.types.ts +++ b/src/modules/user/types/user.types.ts @@ -1,7 +1,7 @@ import { ProfileImage } from 'src/common/constants/image.type'; import { Role } from 'src/common/constants/role.type'; import { TripType } from 'src/common/constants/tripType.type'; -import { MakerProfileProperties } from './profile.types'; +import { MakerProfileProperties } from '../../profile/types/profile.types'; import SortOrder from 'src/common/constants/sortOrder.enum'; import { UserStatsProperties } from '../../userStats/types/userStats.types'; import { OAuthProvider } from 'src/common/constants/oauth.type'; diff --git a/src/modules/user/user.controller.ts b/src/modules/user/user.controller.ts index d7066d8..5b5a9e2 100644 --- a/src/modules/user/user.controller.ts +++ b/src/modules/user/user.controller.ts @@ -2,26 +2,10 @@ import { Body, Controller, Get, Param, Patch, Query } from '@nestjs/common'; import UserService from './user.service'; import { Public } from 'src/common/decorators/public.decorator'; import { UserId } from 'src/common/decorators/user.decorator'; -import { - ApiBearerAuth, - ApiBody, - ApiOkResponse, - ApiOperation, - ApiResponse, - ApiUnauthorizedResponse -} from '@nestjs/swagger'; -import { - DreamerProfileResponseDTO, - FilteredUserResponseDTO, - followResponseDTO, - MakerProfileResponseDTO, - UserResponseDTO -} from './types/user.response.dto'; -import UpdateProfileDTO from './types/updateProfile.dto'; -import { DreamerProfileProperties, MakerProfileProperties } from './types/profile.types'; +import { ApiBearerAuth, ApiBody, ApiOkResponse, ApiOperation, ApiUnauthorizedResponse } from '@nestjs/swagger'; +import { FilteredUserResponseDTO, followResponseDTO, UserResponseDTO } from './types/user.response.dto'; import { FilteredUserProperties, UserProperties } from './types/user.types'; import UpdateUserDTO from './types/updateUser.dto'; -import { UserRole } from 'src/common/decorators/role.decorator'; import { Role } from 'src/common/decorators/roleGuard.decorator'; import { GetMakerListQueryDTO, PaginationQueryDTO } from 'src/modules/user/types/query.dto'; @@ -38,20 +22,8 @@ export default class UserController { return await this.service.getUser(userId); } - @Get('profile') - @ApiBearerAuth('accessToken') - @ApiOperation({ summary: '프로필 정보 조회', description: '로그인한 유저의 프로필을 조회합니다' }) - @ApiOkResponse({ type: MakerProfileResponseDTO || DreamerProfileResponseDTO }) - @ApiUnauthorizedResponse({ description: 'Access Token이 없거나 만료되었습니다' }) - async getProfile( - @UserRole() role: string, - @UserId() userId: string - ): Promise { - return await this.service.getProfile(role, userId); - } - @Public() - @Get('profile/:makerId') + @Get('maker/:makerId') async getProfileById(@Param('makerId') makerId: string, @UserId() dreamerId: string) { return await this.service.getProfileCardData(makerId, dreamerId, true); } @@ -80,21 +52,4 @@ export default class UserController { async updateUser(@Body() data: UpdateUserDTO, @UserId() userId: string): Promise { return await this.service.updateUser(userId, data); } - - @Patch('update/profile') - @ApiBearerAuth('accessToken') - @ApiOperation({ summary: '프로필 수정', description: '로그인한 유저의 프로필을 수정합니다' }) - @ApiBody({ type: UpdateProfileDTO }) - @ApiResponse({ type: MakerProfileResponseDTO || DreamerProfileResponseDTO }) - @ApiUnauthorizedResponse({ description: 'Access Token이 없거나 만료되었습니다' }) - async updateProfile( - @UserRole() role: string, - @Body() data: Partial, - @UserId() userId: string - ) { - if (role === 'DREAMER') { - return await this.service.updateDreamerProfile(userId, data); - } - return await this.service.updateMakerProfile(userId, data); - } } diff --git a/src/modules/user/user.e2e.spec.ts b/src/modules/user/user.e2e.spec.ts index 1becbea..3dd2267 100644 --- a/src/modules/user/user.e2e.spec.ts +++ b/src/modules/user/user.e2e.spec.ts @@ -61,10 +61,10 @@ describe('Review Test (e2e)', () => { }); }); - describe('[GET /users/profile]', () => { + describe('[GET /profile]', () => { it('DREAMER의 프로필 조회', async () => { const { body, statusCode } = await request(app.getHttpServer()) - .get('/users/profile') + .get('/profile') .set('authorization', `Bearer ${dreamerToken}`); expect(statusCode).toBe(HttpStatus.OK); @@ -73,7 +73,7 @@ describe('Review Test (e2e)', () => { it('MAKER의 프로필 조회', async () => { const { body, statusCode } = await request(app.getHttpServer()) - .get('/users/profile') + .get('/profile') .set('authorization', `Bearer ${makerToken}`); expect(statusCode).toBe(HttpStatus.OK); @@ -81,10 +81,10 @@ describe('Review Test (e2e)', () => { }); }); - describe('[GET /users/profile/{makerId}]', () => { + describe('[GET /users/maker/{makerId}]', () => { it('메이커 정보 조회', async () => { const { body, statusCode } = await request(app.getHttpServer()) - .get(`/users/profile/${makerId}`) + .get(`/users/maker/${makerId}`) .set('authorization', `Bearer ${dreamerToken}`); expect(statusCode).toBe(HttpStatus.OK); @@ -92,7 +92,7 @@ describe('Review Test (e2e)', () => { }); it('메이커 정보 조회, 존재하지 않는 MAKER인 경우 400에러', async () => { - const { statusCode } = await request(app.getHttpServer()).get(`/users/profile/1`); + const { statusCode } = await request(app.getHttpServer()).get(`/users/maker/1`); expect(statusCode).toBe(HttpStatus.BAD_REQUEST); }); @@ -186,12 +186,12 @@ describe('Review Test (e2e)', () => { }); }); - describe('[PATCH /users/update/profile]', () => { + describe('[PATCH /profile/update]', () => { const dto = { image: ProfileImageValues.DEFAULT_4 }; it('나의 프로필 수정-DREAMER', async () => { const { body, statusCode } = await request(app.getHttpServer()) - .patch('/users/update/profile') + .patch('/profile/update') .set('authorization', `Bearer ${dreamerToken}`) .send(dto); @@ -201,7 +201,7 @@ describe('Review Test (e2e)', () => { it('나의 프로필 수정-MAKER', async () => { const { body, statusCode } = await request(app.getHttpServer()) - .patch('/users/update/profile') + .patch('/profile/update') .set('authorization', `Bearer ${makerToken}`) .send(dto); @@ -211,7 +211,7 @@ describe('Review Test (e2e)', () => { it('나의 프로필 수정-DREAMER, 유저 프로필이 없는 경우 400에러', async () => { const { body, statusCode } = await request(app.getHttpServer()) - .patch('/users/update/profile') + .patch('/profile/update') .set('authorization', `Bearer ${noUserToken}`) .send(dto); diff --git a/src/modules/user/user.repository.ts b/src/modules/user/user.repository.ts index 7283edb..c5d2724 100644 --- a/src/modules/user/user.repository.ts +++ b/src/modules/user/user.repository.ts @@ -1,11 +1,8 @@ import { Injectable } from '@nestjs/common'; import DBClient from 'src/providers/database/prisma/DB.client'; import UserMapper from './domain/user.mapper'; -import { MakerOrderBy, MakerOrderByField, UserProperties } from './types/user.types'; -import { DreamerProfileProperties, MakerProfileProperties } from './types/profile.types'; -import { DreamerProfileMapper, MakerProfileMapper } from './domain/profile.mapper'; +import { MakerOrderBy, MakerOrderByField } from './types/user.types'; import { IUser } from './domain/user.interface'; -import { IDreamerProfile, IMakerProfile } from './domain/profile.interface'; import { RoleValues } from 'src/common/constants/role.type'; import SortOrder from 'src/common/constants/sortOrder.enum'; import { GetMakerListQueryDTO } from 'src/modules/user/types/query.dto'; @@ -104,50 +101,4 @@ export default class UserRepository { return new UserMapper(user).toDomain(); } - - async findDreamerProfile(userId: string): Promise { - const data = await this.db.dreamerProfile.findUnique({ - where: { - userId - } - }); - - if (data) { - return new DreamerProfileMapper(data).toDomain(); - } - } - - async findMakerProfile(userId: string): Promise { - const data = await this.db.makerProfile.findUnique({ - where: { - userId - } - }); - - if (data) { - return new MakerProfileMapper(data).toDomain(); - } - } - - async updateDreamerProfile(userId: string, data: Partial): Promise { - const profile = await this.db.dreamerProfile.update({ - where: { - userId - }, - data - }); - - return new DreamerProfileMapper(profile).toDomain(); - } - - async updateMakerProfile(userId: string, data: Partial): Promise { - const profile = await this.db.makerProfile.update({ - where: { - userId - }, - data - }); - - return new MakerProfileMapper(profile).toDomain(); - } } diff --git a/src/modules/user/user.service.ts b/src/modules/user/user.service.ts index 7947270..71183db 100644 --- a/src/modules/user/user.service.ts +++ b/src/modules/user/user.service.ts @@ -3,7 +3,7 @@ import UserRepository from './user.repository'; import BadRequestError from 'src/common/errors/badRequestError'; import ErrorMessage from 'src/common/constants/errorMessage.enum'; import { FilteredUserProperties, PasswordProperties, UserProperties } from './types/user.types'; -import { DreamerProfileProperties, MakerInfoAndProfileProperties, MakerProfileProperties } from './types/profile.types'; +import { MakerInfoAndProfileProperties } from '../profile/types/profile.types'; import UserStatsService from '../userStats/userStats.service'; import FollowService from '../follow/follow.service'; import { GetMakerListQueryDTO, PaginationQueryDTO } from 'src/modules/user/types/query.dto'; @@ -23,16 +23,6 @@ export default class UserService { return user?.toClientAll(); } - async getProfile(role: string, userId: string): Promise { - if (role === 'DREAMER') { - const profile = await this.repository.findDreamerProfile(userId); - return profile.get(); - } - - const profile = await this.repository.findMakerProfile(userId); - return profile.get(); - } - async getMakers( options: GetMakerListQueryDTO, userId?: string @@ -70,29 +60,6 @@ export default class UserService { return newUser.toClient(); } - async updateDreamerProfile( - userId: string, - data: Partial - ): Promise { - const profile = await this.repository.findDreamerProfile(userId); - if (!profile) { - throw new BadRequestError(ErrorMessage.USER_NOT_FOUND); - } - - const newProfile = await this.repository.updateDreamerProfile(userId, profile.update(data)); - return newProfile.get(); - } - - async updateMakerProfile(userId: string, data: Partial): Promise { - const profile = await this.repository.findMakerProfile(userId); - if (!profile) { - throw new BadRequestError(ErrorMessage.USER_NOT_FOUND); - } - - const newProfile = await this.repository.updateMakerProfile(userId, profile.update(data)); - return newProfile.get(); - } - async getProfileCardData(makerId: string, dreamerId: string, withDetails?: boolean): Promise { const user = await this.repository.findByIdWithProfileAndFollow(makerId);