diff --git a/src/domain/vr-resource/dto/response/get-vr-resources.response.dto.ts b/src/domain/vr-resource/dto/response/get-vr-resources.response.dto.ts index 4c4b9b1..05a8e25 100644 --- a/src/domain/vr-resource/dto/response/get-vr-resources.response.dto.ts +++ b/src/domain/vr-resource/dto/response/get-vr-resources.response.dto.ts @@ -30,6 +30,8 @@ export class VrResourceDto extends PickType(VrResource, [ } } +export class GetVrResourceByIdResponseDto extends VrResourceDto {} + export class GetVrResourcesResponseDto { @ApiProperty({ description: 'VR 자원(아바타, 배경) 목록', diff --git a/src/domain/vr-resource/repository/vr-resource.repository.ts b/src/domain/vr-resource/repository/vr-resource.repository.ts index 9d94937..bb198e6 100644 --- a/src/domain/vr-resource/repository/vr-resource.repository.ts +++ b/src/domain/vr-resource/repository/vr-resource.repository.ts @@ -27,4 +27,10 @@ export class VrResourceRepository extends Repository { async findById(id: string): Promise { return this.repository.findOne({ where: { id }, relations: ['group'] }); } + + async findByIdAndGroupId(id: string, groupId: string): Promise { + return this.repository.findOne({ + where: { id, group: { id: groupId } }, + }); + } } diff --git a/src/domain/vr-resource/service/vr-resource.service.ts b/src/domain/vr-resource/service/vr-resource.service.ts index 265eb5a..f601f6c 100644 --- a/src/domain/vr-resource/service/vr-resource.service.ts +++ b/src/domain/vr-resource/service/vr-resource.service.ts @@ -1,4 +1,8 @@ -import { Injectable } from '@nestjs/common'; +import { + ForbiddenException, + Injectable, + NotFoundException, +} from '@nestjs/common'; import { GroupService } from 'src/domain/group/service/group.service'; import { VrResourceRepository } from '../repository/vr-resource.repository'; import { User } from 'src/domain/user/entity/user.entity'; @@ -36,6 +40,24 @@ export class VrResourceService { return vrResourceDtos; } + async getVrResourceById(id: string, user: User): Promise { + // 1. Get VR resource by id + const vrResource = await this.vrResourceRepository.findById(id); + if (!vrResource) { + throw new NotFoundException('Not found'); + } + // 2. Check if the user has access to the resource + const isOwner = + vrResource?.group?.id !== (await this.groupService.getMyGroup(user)).id; + if (!(isOwner || vrResource.isSample)) { + throw new ForbiddenException('Forbidden'); + } + + // 3. make as dto + const vrResourceDto = await this.makeVrResourceDto([vrResource]); + return vrResourceDto[0]; + } + /* -------------------------------------------------------------------------- */ private makeVrResourceDto( vrResources: VrResource[], diff --git a/src/domain/vr-resource/vr-resource.controller.ts b/src/domain/vr-resource/vr-resource.controller.ts index 4a71c9f..9ce7f7e 100644 --- a/src/domain/vr-resource/vr-resource.controller.ts +++ b/src/domain/vr-resource/vr-resource.controller.ts @@ -7,6 +7,7 @@ import { UploadedFile, Get, UploadedFiles, + Param, } from '@nestjs/common'; import { ApiBearerAuth, @@ -29,7 +30,10 @@ import { InitEnrollGuard } from 'src/common/auth/guard/init-enroll.guard'; import { CareGiverGuard } from 'src/common/auth/guard/role.guard'; import { GetAiTaskQueueResponseDto } from './dto/response/get-ai-task-queue.response.dto'; import { VrResourceService } from './service/vr-resource.service'; -import { GetVrResourcesResponseDto } from './dto/response/get-vr-resources.response.dto'; +import { + GetVrResourceByIdResponseDto, + GetVrResourcesResponseDto, +} from './dto/response/get-vr-resources.response.dto'; import { GenerateAvatarRequestDto } from './dto/request/generate-avatar.request.dto'; @ApiTags('VR-resource') @@ -87,6 +91,20 @@ export class VrResourceController { ); } + @ApiOperation({ + summary: 'ID로 특정 VR 자원 불러오기 (샘플 포함)', + }) + @ApiBearerAuth() + @ApiResponse({ type: GetVrResourcesResponseDto }) + @UseGuards(JwtAuthGuard, InitEnrollGuard) + @Get('/:id') + async getVrResourceById( + @Param('id') resourceId: string, + @AuthUser() user: User, + ): Promise { + return await this.vrResourceService.getVrResourceById(resourceId, user); + } + @ApiOperation({ summary: '완성된 VR 자원 불러오기 (샘플 포함)', }) diff --git a/src/domain/vr-video/repository/vr-video.repository.ts b/src/domain/vr-video/repository/vr-video.repository.ts index 4617411..e14a54b 100644 --- a/src/domain/vr-video/repository/vr-video.repository.ts +++ b/src/domain/vr-video/repository/vr-video.repository.ts @@ -42,7 +42,7 @@ export class VrVideoRepository extends Repository { async findById(videoId: string): Promise { return this.repository.findOne({ where: { id: videoId }, - relations: ['scene', 'avatars'], + relations: ['scene', 'avatars', 'group'], }); } diff --git a/src/domain/vr-video/service/vr-video.service.ts b/src/domain/vr-video/service/vr-video.service.ts index cba2594..acc6de6 100644 --- a/src/domain/vr-video/service/vr-video.service.ts +++ b/src/domain/vr-video/service/vr-video.service.ts @@ -64,6 +64,34 @@ export class VrVideoService { return await this.makeVrVideoDto(sampleVrVideos); } + // /* ---------------------------- GET /vr-video/:id --------------------------- */ + /** + * videoID를 통해 특정 video만 가져옴 + * @param user UserID + * @param videoId videoID + */ + async getVrVideo( + user: User, + videoId: string, + ): Promise { + const vrVideo = await this.vrVideoRepository.findById(videoId); + // 1. validation logic + if (!vrVideo) { + throw new NotFoundException('VrVideo not found'); + } + const isUserInGroup = await this.groupRepository.isUserInGroup( + user.id, + vrVideo.group.id, + ); + const isSample = vrVideo.isSample; + if (!(isUserInGroup || isSample)) { + throw new NotFoundException('User is not in the group'); + } + + // 2. return DTO from DB. + return (await this.makeVrVideoDto([vrVideo]))[0]; + } + /* ----------------------------- POST /vr-video ----------------------------- */ /** @@ -267,58 +295,3 @@ export class VrVideoService { ); } } - -// // deprecated -// // /* ---------------------------- GET /vr-video/:id --------------------------- */ - -// // /** -// // * videoID를 통해 특정 video만 가져옴 -// // * @param user UserID -// // * @param videoId videoID -// // */ -// // async getVrVideo( -// // user: User, -// // videoId: string, -// // ): Promise { -// // const vrVideo = await this.vrVideoRepository.findById(videoId); -// // // 1. validation logic -// // if (!vrVideo) { -// // throw new NotFoundException('VrVideo not found'); -// // } -// // const isUserInGroup = await this.groupRepository.isUserInGroup( -// // user.id, -// // vrVideo.group.id, -// // ); -// // if (!isUserInGroup) { -// // throw new NotFoundException('User is not in the group'); -// // } - -// // // 2. return DTO from DB. -// // const sceneDto = VrResourceDtoForVideo.of( -// // vrVideo.scene, -// // await this.vrResourceStorageRepository.generateSignedUrlList( -// // vrVideo.scene.filePath, -// // ), -// // await this.getResourcePositionFileURL( -// // vrVideo.id, -// // vrVideo.scene.id, -// // 'scene', -// // ), -// // ); -// // const avatarDtos = await Promise.all( -// // vrVideo.avatars.map(async (avatar) => { -// // return VrResourceDtoForVideo.of( -// // avatar, -// // await this.vrResourceStorageRepository.generateSignedUrlList( -// // avatar.filePath, -// // ), -// // await this.getResourcePositionFileURL( -// // vrVideo.id, -// // avatar.id, -// // 'avatar', -// // ), -// // ); -// // }), -// // ); -// // return new GetVrVideosResponseDto(vrVideo, sceneDto, avatarDtos); -// // } diff --git a/src/domain/vr-video/vr-video.controller.ts b/src/domain/vr-video/vr-video.controller.ts index 5eb520d..131bf55 100644 --- a/src/domain/vr-video/vr-video.controller.ts +++ b/src/domain/vr-video/vr-video.controller.ts @@ -35,6 +35,18 @@ export class VrVideoController { return await this.vrVideoService.generateVrVideo(user, requestDto, true); } + @ApiOperation({ summary: '특정 VR 비디오 정보 불러오기 (샘플 포함)' }) + @ApiBearerAuth() + @ApiResponse({ type: GetVrVideosResponseDto }) + @UseGuards(JwtAuthGuard, InitEnrollGuard) + @Get('/:id') + async getVrVideo( + @AuthUser() user: User, + @Param('id') videoId: string, + ): Promise { + return await this.vrVideoService.getVrVideo(user, videoId); + } + @ApiOperation({ summary: 'VR 비디오 정보 불러오기' }) @ApiBearerAuth() @ApiResponse({ type: [GetVrVideosResponseDto] }) @@ -44,17 +56,3 @@ export class VrVideoController { return await this.vrVideoService.getVrVideos(user); } } - -// deprecated -// // 특정 VR 비디오 id를 통해서 특정한 VR비디오 정보를 불러오는 API를 작성할것. -// @ApiOperation({ summary: 'VR 비디오 정보 불러오기' }) -// @ApiBearerAuth() -// @ApiResponse({ type: GetVrVideosResponseDto }) -// @UseGuards(JwtAuthGuard, InitEnrollGuard) -// @Get('/:id') -// async getVrVideo( -// @AuthUser() user: User, -// @Param('id') videoId: string, -// ): Promise { -// return await this.vrVideoService.getVrVideo(user, videoId); -// }