From 35657041f9f0242875493c6449f0ebb271e3dcdc Mon Sep 17 00:00:00 2001 From: Jo Seonggyu Date: Sat, 2 Sep 2023 14:24:14 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20research=20=ED=8C=A8=ED=82=A4=EC=A7=80?= =?UTF-8?q?=20=ED=94=84=EB=A1=A0=ED=8A=B8=EC=97=90=20=EB=A7=9E=EC=B6=B0=20?= =?UTF-8?q?=ED=98=91=EC=9D=98=20(#52)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: professor, staff에 uploadImage 추가 * fix: research에서 isPublic 제거, feat: lab에서 attachments 추가 * fix: attachments -> attachmentResponses 변경 * feat: LabProfessorResponse 추가 * fix: pdf를 list가 아닌 단일항목으로 수정 * feat: readLab 추가 * feat: ResearchLabReponse 추가 및 주석 삭제 * fix: researchDetail에 사진, 첨부파일 업로드 추가 * fix: pr 리뷰 수정 * fix: 오타 수정 --- ...yType.kt => MainImageContentEntityType.kt} | 2 +- .../core/about/database/AboutEntity.kt | 4 +- .../csereal/core/about/dto/AboutDto.kt | 4 +- .../core/about/service/AboutService.kt | 20 +-- .../core/academics/dto/AcademicsDto.kt | 4 +- .../academics/service/AcademicsService.kt | 22 +-- .../core/member/api/ProfessorController.kt | 5 +- .../core/member/api/StaffController.kt | 9 +- .../core/member/database/ProfessorEntity.kt | 4 +- .../core/member/database/StaffEntity.kt | 4 +- .../core/member/service/ProfessorService.kt | 9 +- .../core/member/service/StaffService.kt | 9 +- .../csereal/core/news/database/NewsEntity.kt | 4 +- .../csereal/core/news/dto/NewsDto.kt | 4 +- .../csereal/core/news/service/NewsService.kt | 20 +-- .../core/research/api/ResearchController.kt | 37 +++-- .../core/research/database/LabEntity.kt | 16 +- .../core/research/database/ResearchEntity.kt | 23 ++- .../csereal/core/research/dto/LabDto.kt | 15 +- .../core/research/dto/LabProfessorResponse.kt | 7 + .../csereal/core/research/dto/ResearchDto.kt | 15 +- .../core/research/dto/ResearchLabResponse.kt | 7 + .../core/research/service/ResearchService.kt | 140 +++++++++++++----- .../attachment/database/AttachmentEntity.kt | 10 ++ .../attachment/service/AttachmentService.kt | 50 ++++++- .../dto/introductionMaterialDto.kt | 8 - .../mainImage/service/MainImageService.kt | 13 +- .../core/seminar/database/SeminarEntity.kt | 4 +- .../csereal/core/seminar/dto/SeminarDto.kt | 4 +- .../core/seminar/service/SeminarService.kt | 19 ++- 30 files changed, 320 insertions(+), 172 deletions(-) rename src/main/kotlin/com/wafflestudio/csereal/common/controller/{ImageContentEntityType.kt => MainImageContentEntityType.kt} (82%) create mode 100644 src/main/kotlin/com/wafflestudio/csereal/core/research/dto/LabProfessorResponse.kt create mode 100644 src/main/kotlin/com/wafflestudio/csereal/core/research/dto/ResearchLabResponse.kt delete mode 100644 src/main/kotlin/com/wafflestudio/csereal/core/resource/introductionMaterial/dto/introductionMaterialDto.kt diff --git a/src/main/kotlin/com/wafflestudio/csereal/common/controller/ImageContentEntityType.kt b/src/main/kotlin/com/wafflestudio/csereal/common/controller/MainImageContentEntityType.kt similarity index 82% rename from src/main/kotlin/com/wafflestudio/csereal/common/controller/ImageContentEntityType.kt rename to src/main/kotlin/com/wafflestudio/csereal/common/controller/MainImageContentEntityType.kt index 8f58c860..eae7403c 100644 --- a/src/main/kotlin/com/wafflestudio/csereal/common/controller/ImageContentEntityType.kt +++ b/src/main/kotlin/com/wafflestudio/csereal/common/controller/MainImageContentEntityType.kt @@ -2,6 +2,6 @@ package com.wafflestudio.csereal.common.controller import com.wafflestudio.csereal.core.resource.mainImage.database.MainImageEntity -interface ImageContentEntityType { +interface MainImageContentEntityType { fun bringMainImage(): MainImageEntity? } \ No newline at end of file diff --git a/src/main/kotlin/com/wafflestudio/csereal/core/about/database/AboutEntity.kt b/src/main/kotlin/com/wafflestudio/csereal/core/about/database/AboutEntity.kt index 8dd8b967..a77058a7 100644 --- a/src/main/kotlin/com/wafflestudio/csereal/core/about/database/AboutEntity.kt +++ b/src/main/kotlin/com/wafflestudio/csereal/core/about/database/AboutEntity.kt @@ -2,7 +2,7 @@ package com.wafflestudio.csereal.core.about.database import com.wafflestudio.csereal.common.config.BaseTimeEntity import com.wafflestudio.csereal.common.controller.AttachmentContentEntityType -import com.wafflestudio.csereal.common.controller.ImageContentEntityType +import com.wafflestudio.csereal.common.controller.MainImageContentEntityType import com.wafflestudio.csereal.core.about.dto.AboutDto import com.wafflestudio.csereal.core.resource.attachment.database.AttachmentEntity import com.wafflestudio.csereal.core.resource.mainImage.database.MainImageEntity @@ -26,7 +26,7 @@ class AboutEntity( @OneToOne var mainImage: MainImageEntity? = null, - ) : BaseTimeEntity(), ImageContentEntityType, AttachmentContentEntityType { + ) : BaseTimeEntity(), MainImageContentEntityType, AttachmentContentEntityType { override fun bringMainImage(): MainImageEntity? = mainImage override fun bringAttachments(): List = attachments diff --git a/src/main/kotlin/com/wafflestudio/csereal/core/about/dto/AboutDto.kt b/src/main/kotlin/com/wafflestudio/csereal/core/about/dto/AboutDto.kt index 2d7c96e2..60233a13 100644 --- a/src/main/kotlin/com/wafflestudio/csereal/core/about/dto/AboutDto.kt +++ b/src/main/kotlin/com/wafflestudio/csereal/core/about/dto/AboutDto.kt @@ -18,7 +18,7 @@ data class AboutDto( val attachments: List?, ) { companion object { - fun of(entity: AboutEntity, imageURL: String?, attachments: List?) : AboutDto = entity.run { + fun of(entity: AboutEntity, imageURL: String?, attachmentResponses: List) : AboutDto = entity.run { AboutDto( id = this.id, name = this.name, @@ -29,7 +29,7 @@ data class AboutDto( modifiedAt = this.modifiedAt, locations = this.locations.map { it.name }, imageURL = imageURL, - attachments = attachments, + attachments = attachmentResponses, ) } } diff --git a/src/main/kotlin/com/wafflestudio/csereal/core/about/service/AboutService.kt b/src/main/kotlin/com/wafflestudio/csereal/core/about/service/AboutService.kt index 9a3af02b..f973a5c5 100644 --- a/src/main/kotlin/com/wafflestudio/csereal/core/about/service/AboutService.kt +++ b/src/main/kotlin/com/wafflestudio/csereal/core/about/service/AboutService.kt @@ -42,14 +42,14 @@ class AboutServiceImpl( } if(attachments != null) { - attachmentService.uploadAttachments(newAbout, attachments) + attachmentService.uploadAllAttachments(newAbout, attachments) } aboutRepository.save(newAbout) val imageURL = mainImageService.createImageURL(newAbout.mainImage) - val attachments = attachmentService.createAttachments(newAbout.attachments) + val attachmentResponses = attachmentService.createAttachmentResponses(newAbout.attachments) - return AboutDto.of(newAbout, imageURL, attachments) + return AboutDto.of(newAbout, imageURL, attachmentResponses) } @Transactional(readOnly = true) @@ -57,18 +57,18 @@ class AboutServiceImpl( val enumPostType = makeStringToEnum(postType) val about = aboutRepository.findByPostType(enumPostType) val imageURL = mainImageService.createImageURL(about.mainImage) - val attachments = attachmentService.createAttachments(about.attachments) + val attachmentResponses = attachmentService.createAttachmentResponses(about.attachments) - return AboutDto.of(about, imageURL, attachments) + return AboutDto.of(about, imageURL, attachmentResponses) } @Transactional(readOnly = true) override fun readAllClubs(): List { val clubs = aboutRepository.findAllByPostTypeOrderByName(AboutPostType.STUDENT_CLUBS).map { val imageURL = mainImageService.createImageURL(it.mainImage) - val attachments = attachmentService.createAttachments(it.attachments) - AboutDto.of(it, imageURL, attachments) + val attachmentResponses = attachmentService.createAttachmentResponses(it.attachments) + AboutDto.of(it, imageURL, attachmentResponses) } return clubs @@ -78,8 +78,8 @@ class AboutServiceImpl( override fun readAllFacilities(): List { val facilities = aboutRepository.findAllByPostTypeOrderByName(AboutPostType.FACILITIES).map { val imageURL = mainImageService.createImageURL(it.mainImage) - val attachments = attachmentService.createAttachments(it.attachments) - AboutDto.of(it, imageURL, attachments) + val attachmentResponses = attachmentService.createAttachmentResponses(it.attachments) + AboutDto.of(it, imageURL, attachmentResponses) } return facilities @@ -89,7 +89,7 @@ class AboutServiceImpl( override fun readAllDirections(): List { val directions = aboutRepository.findAllByPostTypeOrderByName(AboutPostType.DIRECTIONS).map { val imageURL = mainImageService.createImageURL(it.mainImage) - val attachments = attachmentService.createAttachments(it.attachments) + val attachments = attachmentService.createAttachmentResponses(it.attachments) AboutDto.of(it, imageURL, attachments) } diff --git a/src/main/kotlin/com/wafflestudio/csereal/core/academics/dto/AcademicsDto.kt b/src/main/kotlin/com/wafflestudio/csereal/core/academics/dto/AcademicsDto.kt index cc16ce4d..0df98fd5 100644 --- a/src/main/kotlin/com/wafflestudio/csereal/core/academics/dto/AcademicsDto.kt +++ b/src/main/kotlin/com/wafflestudio/csereal/core/academics/dto/AcademicsDto.kt @@ -14,7 +14,7 @@ data class AcademicsDto( val attachments: List?, ) { companion object { - fun of(entity: AcademicsEntity, attachments: List?) : AcademicsDto = entity.run { + fun of(entity: AcademicsEntity, attachmentResponses: List) : AcademicsDto = entity.run { AcademicsDto( id = this.id, name = this.name, @@ -22,7 +22,7 @@ data class AcademicsDto( year = this.year, createdAt = this.createdAt, modifiedAt = this.modifiedAt, - attachments = attachments, + attachments = attachmentResponses, ) } } diff --git a/src/main/kotlin/com/wafflestudio/csereal/core/academics/service/AcademicsService.kt b/src/main/kotlin/com/wafflestudio/csereal/core/academics/service/AcademicsService.kt index 4421c6f5..024565a3 100644 --- a/src/main/kotlin/com/wafflestudio/csereal/core/academics/service/AcademicsService.kt +++ b/src/main/kotlin/com/wafflestudio/csereal/core/academics/service/AcademicsService.kt @@ -37,15 +37,15 @@ class AcademicsServiceImpl( val newAcademics = AcademicsEntity.of(enumStudentType, enumPostType, request) if(attachments != null) { - attachmentService.uploadAttachments(newAcademics, attachments) + attachmentService.uploadAllAttachments(newAcademics, attachments) } academicsRepository.save(newAcademics) - val attachments = attachmentService.createAttachments(newAcademics.attachments) + val attachmentResponses = attachmentService.createAttachmentResponses(newAcademics.attachments) - return AcademicsDto.of(newAcademics, attachments) + return AcademicsDto.of(newAcademics, attachmentResponses) } @Transactional(readOnly = true) @@ -56,9 +56,9 @@ class AcademicsServiceImpl( val academics = academicsRepository.findByStudentTypeAndPostType(enumStudentType, enumPostType) - val attachments = attachmentService.createAttachments(academics.attachments) + val attachmentResponses = attachmentService.createAttachmentResponses(academics.attachments) - return AcademicsDto.of(academics, attachments) + return AcademicsDto.of(academics, attachmentResponses) } @Transactional @@ -68,9 +68,9 @@ class AcademicsServiceImpl( courseRepository.save(course) - val attachments = attachmentService.createAttachments(course.attachments) + val attachmentResponses = attachmentService.createAttachmentResponses(course.attachments) - return CourseDto.of(course, attachments) + return CourseDto.of(course, attachmentResponses) } @Transactional(readOnly = true) @@ -78,8 +78,8 @@ class AcademicsServiceImpl( val enumStudentType = makeStringToAcademicsStudentType(studentType) val courseDtoList = courseRepository.findAllByStudentTypeOrderByNameAsc(enumStudentType).map { - val attachments = attachmentService.createAttachments(it.attachments) - CourseDto.of(it, attachments) + val attachmentResponses = attachmentService.createAttachmentResponses(it.attachments) + CourseDto.of(it, attachmentResponses) } return courseDtoList } @@ -87,9 +87,9 @@ class AcademicsServiceImpl( @Transactional(readOnly = true) override fun readCourse(name: String): CourseDto { val course = courseRepository.findByName(name) - val attachments = attachmentService.createAttachments(course.attachments) + val attachmentResponses = attachmentService.createAttachmentResponses(course.attachments) - return CourseDto.of(course, attachments) + return CourseDto.of(course, attachmentResponses) } @Transactional(readOnly = true) diff --git a/src/main/kotlin/com/wafflestudio/csereal/core/member/api/ProfessorController.kt b/src/main/kotlin/com/wafflestudio/csereal/core/member/api/ProfessorController.kt index 6431351f..fa71dd42 100644 --- a/src/main/kotlin/com/wafflestudio/csereal/core/member/api/ProfessorController.kt +++ b/src/main/kotlin/com/wafflestudio/csereal/core/member/api/ProfessorController.kt @@ -40,9 +40,10 @@ class ProfessorController( @PatchMapping("/{professorId}") fun updateProfessor( @PathVariable professorId: Long, - @RequestBody updateProfessorRequest: ProfessorDto + @RequestPart("request") updateProfessorRequest: ProfessorDto, + @RequestPart("mainImage") mainImage: MultipartFile?, ): ResponseEntity { - return ResponseEntity.ok(professorService.updateProfessor(professorId, updateProfessorRequest)) + return ResponseEntity.ok(professorService.updateProfessor(professorId, updateProfessorRequest, mainImage)) } @DeleteMapping("/{professorId}") diff --git a/src/main/kotlin/com/wafflestudio/csereal/core/member/api/StaffController.kt b/src/main/kotlin/com/wafflestudio/csereal/core/member/api/StaffController.kt index 611d2afd..b9584fb0 100644 --- a/src/main/kotlin/com/wafflestudio/csereal/core/member/api/StaffController.kt +++ b/src/main/kotlin/com/wafflestudio/csereal/core/member/api/StaffController.kt @@ -31,9 +31,12 @@ class StaffController( return ResponseEntity.ok(staffService.getAllStaff()) } - @PatchMapping("/{staffId}") - fun updateStaff(@PathVariable staffId: Long, @RequestBody updateStaffRequest: StaffDto): ResponseEntity { - return ResponseEntity.ok(staffService.updateStaff(staffId, updateStaffRequest)) + fun updateStaff( + @PathVariable staffId: Long, + @RequestPart("request") updateStaffRequest: StaffDto, + @RequestPart("mainImage") mainImage: MultipartFile?, + ): ResponseEntity { + return ResponseEntity.ok(staffService.updateStaff(staffId, updateStaffRequest, mainImage)) } @DeleteMapping("/{staffId}") diff --git a/src/main/kotlin/com/wafflestudio/csereal/core/member/database/ProfessorEntity.kt b/src/main/kotlin/com/wafflestudio/csereal/core/member/database/ProfessorEntity.kt index 1414a0ae..4036a9dd 100644 --- a/src/main/kotlin/com/wafflestudio/csereal/core/member/database/ProfessorEntity.kt +++ b/src/main/kotlin/com/wafflestudio/csereal/core/member/database/ProfessorEntity.kt @@ -1,7 +1,7 @@ package com.wafflestudio.csereal.core.member.database import com.wafflestudio.csereal.common.config.BaseTimeEntity -import com.wafflestudio.csereal.common.controller.ImageContentEntityType +import com.wafflestudio.csereal.common.controller.MainImageContentEntityType import com.wafflestudio.csereal.core.member.dto.ProfessorDto import com.wafflestudio.csereal.core.research.database.LabEntity import com.wafflestudio.csereal.core.resource.mainImage.database.MainImageEntity @@ -44,7 +44,7 @@ class ProfessorEntity( @OneToOne var mainImage: MainImageEntity? = null, -) : BaseTimeEntity(), ImageContentEntityType { +) : BaseTimeEntity(), MainImageContentEntityType { override fun bringMainImage(): MainImageEntity? = mainImage companion object { diff --git a/src/main/kotlin/com/wafflestudio/csereal/core/member/database/StaffEntity.kt b/src/main/kotlin/com/wafflestudio/csereal/core/member/database/StaffEntity.kt index d4e5ec3a..355d4125 100644 --- a/src/main/kotlin/com/wafflestudio/csereal/core/member/database/StaffEntity.kt +++ b/src/main/kotlin/com/wafflestudio/csereal/core/member/database/StaffEntity.kt @@ -1,7 +1,7 @@ package com.wafflestudio.csereal.core.member.database import com.wafflestudio.csereal.common.config.BaseTimeEntity -import com.wafflestudio.csereal.common.controller.ImageContentEntityType +import com.wafflestudio.csereal.common.controller.MainImageContentEntityType import com.wafflestudio.csereal.core.member.dto.StaffDto import com.wafflestudio.csereal.core.resource.mainImage.database.MainImageEntity import jakarta.persistence.CascadeType @@ -24,7 +24,7 @@ class StaffEntity( @OneToOne var mainImage: MainImageEntity? = null, - ) : BaseTimeEntity(), ImageContentEntityType { + ) : BaseTimeEntity(), MainImageContentEntityType { override fun bringMainImage(): MainImageEntity? = mainImage companion object { diff --git a/src/main/kotlin/com/wafflestudio/csereal/core/member/service/ProfessorService.kt b/src/main/kotlin/com/wafflestudio/csereal/core/member/service/ProfessorService.kt index 86e6f8cf..4988369a 100644 --- a/src/main/kotlin/com/wafflestudio/csereal/core/member/service/ProfessorService.kt +++ b/src/main/kotlin/com/wafflestudio/csereal/core/member/service/ProfessorService.kt @@ -17,7 +17,7 @@ interface ProfessorService { fun getProfessor(professorId: Long): ProfessorDto fun getActiveProfessors(): ProfessorPageDto fun getInactiveProfessors(): List - fun updateProfessor(professorId: Long, updateProfessorRequest: ProfessorDto): ProfessorDto + fun updateProfessor(professorId: Long, updateProfessorRequest: ProfessorDto, mainImage: MultipartFile?): ProfessorDto fun deleteProfessor(professorId: Long) } @@ -94,8 +94,7 @@ class ProfessorServiceImpl( .sortedBy { it.name } } - override fun updateProfessor(professorId: Long, updateProfessorRequest: ProfessorDto): ProfessorDto { - + override fun updateProfessor(professorId: Long, updateProfessorRequest: ProfessorDto, mainImage: MultipartFile?): ProfessorDto { val professor = professorRepository.findByIdOrNull(professorId) ?: throw CserealException.Csereal404("해당 교수님을 찾을 수 없습니다. professorId: ${professorId}") @@ -107,6 +106,10 @@ class ProfessorServiceImpl( professor.update(updateProfessorRequest) + if(mainImage != null) { + mainImageService.uploadMainImage(professor, mainImage) + } + // 학력 업데이트 val oldEducations = professor.educations.map { it.name } diff --git a/src/main/kotlin/com/wafflestudio/csereal/core/member/service/StaffService.kt b/src/main/kotlin/com/wafflestudio/csereal/core/member/service/StaffService.kt index a68630d7..a08ca026 100644 --- a/src/main/kotlin/com/wafflestudio/csereal/core/member/service/StaffService.kt +++ b/src/main/kotlin/com/wafflestudio/csereal/core/member/service/StaffService.kt @@ -16,7 +16,7 @@ interface StaffService { fun createStaff(createStaffRequest: StaffDto, mainImage: MultipartFile?): StaffDto fun getStaff(staffId: Long): StaffDto fun getAllStaff(): List - fun updateStaff(staffId: Long, updateStaffRequest: StaffDto): StaffDto + fun updateStaff(staffId: Long, updateStaffRequest: StaffDto, mainImage: MultipartFile?): StaffDto fun deleteStaff(staffId: Long) } @@ -62,13 +62,16 @@ class StaffServiceImpl( }.sortedBy { it.name } } - override fun updateStaff(staffId: Long, updateStaffRequest: StaffDto): StaffDto { - + override fun updateStaff(staffId: Long, updateStaffRequest: StaffDto, mainImage: MultipartFile?): StaffDto { val staff = staffRepository.findByIdOrNull(staffId) ?: throw CserealException.Csereal404("해당 행정직원을 찾을 수 없습니다. staffId: ${staffId}") staff.update(updateStaffRequest) + if(mainImage != null) { + mainImageService.uploadMainImage(staff, mainImage) + } + // 주요 업무 업데이트 val oldTasks = staff.tasks.map { it.name } diff --git a/src/main/kotlin/com/wafflestudio/csereal/core/news/database/NewsEntity.kt b/src/main/kotlin/com/wafflestudio/csereal/core/news/database/NewsEntity.kt index 8349a433..327ebcd3 100644 --- a/src/main/kotlin/com/wafflestudio/csereal/core/news/database/NewsEntity.kt +++ b/src/main/kotlin/com/wafflestudio/csereal/core/news/database/NewsEntity.kt @@ -2,7 +2,7 @@ package com.wafflestudio.csereal.core.news.database import com.wafflestudio.csereal.common.config.BaseTimeEntity import com.wafflestudio.csereal.common.controller.AttachmentContentEntityType -import com.wafflestudio.csereal.common.controller.ImageContentEntityType +import com.wafflestudio.csereal.common.controller.MainImageContentEntityType import com.wafflestudio.csereal.core.news.dto.NewsDto import com.wafflestudio.csereal.core.resource.attachment.database.AttachmentEntity import com.wafflestudio.csereal.core.resource.mainImage.database.MainImageEntity @@ -30,7 +30,7 @@ class NewsEntity( @OneToMany(mappedBy = "news", cascade = [CascadeType.ALL]) var newsTags: MutableSet = mutableSetOf() -): BaseTimeEntity(), ImageContentEntityType, AttachmentContentEntityType { +): BaseTimeEntity(), MainImageContentEntityType, AttachmentContentEntityType { override fun bringMainImage() = mainImage override fun bringAttachments() = attachments diff --git a/src/main/kotlin/com/wafflestudio/csereal/core/news/dto/NewsDto.kt b/src/main/kotlin/com/wafflestudio/csereal/core/news/dto/NewsDto.kt index 240a9a87..3232d84f 100644 --- a/src/main/kotlin/com/wafflestudio/csereal/core/news/dto/NewsDto.kt +++ b/src/main/kotlin/com/wafflestudio/csereal/core/news/dto/NewsDto.kt @@ -21,7 +21,7 @@ data class NewsDto( val attachments: List?, ) { companion object { - fun of(entity: NewsEntity, imageURL: String?, attachments: List?, prevNext: Array?) : NewsDto = entity.run { + fun of(entity: NewsEntity, imageURL: String?, attachmentResponses: List, prevNext: Array?) : NewsDto = entity.run { NewsDto( id = this.id, title = this.title, @@ -36,7 +36,7 @@ data class NewsDto( nextId = prevNext?.get(1)?.id, nextTitle = prevNext?.get(1)?.title, imageURL = imageURL, - attachments = attachments, + attachments = attachmentResponses, ) } } diff --git a/src/main/kotlin/com/wafflestudio/csereal/core/news/service/NewsService.kt b/src/main/kotlin/com/wafflestudio/csereal/core/news/service/NewsService.kt index 38745afa..e2904321 100644 --- a/src/main/kotlin/com/wafflestudio/csereal/core/news/service/NewsService.kt +++ b/src/main/kotlin/com/wafflestudio/csereal/core/news/service/NewsService.kt @@ -49,12 +49,12 @@ class NewsServiceImpl( if (news.isDeleted) throw CserealException.Csereal404("삭제된 새소식입니다.(newsId: $newsId)") val imageURL = mainImageService.createImageURL(news.mainImage) - val attachments = attachmentService.createAttachments(news.attachments) + val attachmentResponses = attachmentService.createAttachmentResponses(news.attachments) val prevNext = newsRepository.findPrevNextId(newsId, tag, keyword) ?: throw CserealException.Csereal400("이전글 다음글이 존재하지 않습니다.(newsId=$newsId)") - return NewsDto.of(news, imageURL, attachments, prevNext) + return NewsDto.of(news, imageURL, attachmentResponses, prevNext) } @Transactional @@ -71,19 +71,15 @@ class NewsServiceImpl( } if(attachments != null) { - attachmentService.uploadAttachments(newNews, attachments) - } - - if(attachments != null) { - attachmentService.uploadAttachments(newNews, attachments) + attachmentService.uploadAllAttachments(newNews, attachments) } newsRepository.save(newNews) val imageURL = mainImageService.createImageURL(newNews.mainImage) - val attachments = attachmentService.createAttachments(newNews.attachments) + val attachmentResponses = attachmentService.createAttachmentResponses(newNews.attachments) - return NewsDto.of(newNews, imageURL, attachments, null) + return NewsDto.of(newNews, imageURL, attachmentResponses, null) } @Transactional @@ -99,7 +95,7 @@ class NewsServiceImpl( if(attachments != null) { news.attachments.clear() - attachmentService.uploadAttachments(news, attachments) + attachmentService.uploadAllAttachments(news, attachments) } val oldTags = news.newsTags.map { it.tag.name } @@ -119,9 +115,9 @@ class NewsServiceImpl( } val imageURL = mainImageService.createImageURL(news.mainImage) - val attachments = attachmentService.createAttachments(news.attachments) + val attachmentResponses = attachmentService.createAttachmentResponses(news.attachments) - return NewsDto.of(news, imageURL, attachments, null) + return NewsDto.of(news, imageURL, attachmentResponses, null) } @Transactional diff --git a/src/main/kotlin/com/wafflestudio/csereal/core/research/api/ResearchController.kt b/src/main/kotlin/com/wafflestudio/csereal/core/research/api/ResearchController.kt index 187623d6..af093051 100644 --- a/src/main/kotlin/com/wafflestudio/csereal/core/research/api/ResearchController.kt +++ b/src/main/kotlin/com/wafflestudio/csereal/core/research/api/ResearchController.kt @@ -7,6 +7,7 @@ import com.wafflestudio.csereal.core.research.service.ResearchService import jakarta.validation.Valid import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.* +import org.springframework.web.multipart.MultipartFile @RequestMapping("/api/v1/research") @RestController @@ -15,38 +16,50 @@ class ResearchController( ) { @PostMapping fun createResearchDetail( - @Valid @RequestBody request: ResearchDto - ) : ResponseEntity { - return ResponseEntity.ok(researchService.createResearchDetail(request)) + @Valid @RequestPart("request") request: ResearchDto, + @RequestPart("mainImage") mainImage: MultipartFile?, + @RequestPart("attachments") attachments: List? + ): ResponseEntity { + return ResponseEntity.ok(researchService.createResearchDetail(request, mainImage, attachments)) } @GetMapping("/groups") - fun readAllResearchGroups() : ResponseEntity { + fun readAllResearchGroups(): ResponseEntity { return ResponseEntity.ok(researchService.readAllResearchGroups()) } @GetMapping("/centers") - fun readAllResearchCenters() : ResponseEntity> { + fun readAllResearchCenters(): ResponseEntity> { return ResponseEntity.ok(researchService.readAllResearchCenters()) } @PatchMapping("/{researchId}") fun updateResearchDetail( @PathVariable researchId: Long, - @Valid @RequestBody request: ResearchDto - ) : ResponseEntity { - return ResponseEntity.ok(researchService.updateResearchDetail(researchId, request)) + @Valid @RequestPart("request") request: ResearchDto, + @RequestPart("mainImage") mainImage: MultipartFile?, + @RequestPart("attachments") attachments: List? + ): ResponseEntity { + return ResponseEntity.ok(researchService.updateResearchDetail(researchId, request, mainImage, attachments)) } @PostMapping("/lab") fun createLab( - @Valid @RequestBody request: LabDto - ) : ResponseEntity { - return ResponseEntity.ok(researchService.createLab(request)) + @Valid @RequestPart("request") request: LabDto, + @RequestPart("pdf") pdf: MultipartFile? + ): ResponseEntity { + return ResponseEntity.ok(researchService.createLab(request, pdf)) } @GetMapping("/labs") - fun readAllLabs() : ResponseEntity> { + fun readAllLabs(): ResponseEntity> { return ResponseEntity.ok(researchService.readAllLabs()) } + + @GetMapping("/lab/{labId}") + fun readLab( + @PathVariable labId: Long, + ): ResponseEntity { + return ResponseEntity.ok(researchService.readLab(labId)) + } } \ No newline at end of file diff --git a/src/main/kotlin/com/wafflestudio/csereal/core/research/database/LabEntity.kt b/src/main/kotlin/com/wafflestudio/csereal/core/research/database/LabEntity.kt index 3720f60e..63aaa866 100644 --- a/src/main/kotlin/com/wafflestudio/csereal/core/research/database/LabEntity.kt +++ b/src/main/kotlin/com/wafflestudio/csereal/core/research/database/LabEntity.kt @@ -1,13 +1,14 @@ package com.wafflestudio.csereal.core.research.database import com.wafflestudio.csereal.common.config.BaseTimeEntity +import com.wafflestudio.csereal.common.controller.AttachmentContentEntityType import com.wafflestudio.csereal.core.member.database.ProfessorEntity import com.wafflestudio.csereal.core.research.dto.LabDto +import com.wafflestudio.csereal.core.resource.attachment.database.AttachmentEntity import jakarta.persistence.* @Entity(name = "lab") class LabEntity( - val name: String, @OneToMany(mappedBy = "lab") @@ -16,7 +17,10 @@ class LabEntity( val location: String?, val tel: String?, val acronym: String?, - val pdf: String?, + + @OneToOne + var pdf: AttachmentEntity? = null, + val youtube: String?, @ManyToOne(fetch = FetchType.LAZY) @@ -24,24 +28,20 @@ class LabEntity( var research: ResearchEntity, val description: String?, - val websiteURL: String?, - val isPublic: Boolean, ) : BaseTimeEntity() { companion object { - fun of(researchGroup: ResearchEntity, labDto: LabDto) : LabEntity { + fun of(labDto: LabDto, researchGroup: ResearchEntity) : LabEntity { return LabEntity( name = labDto.name, location = labDto.location, tel = labDto.tel, acronym = labDto.acronym, - pdf = labDto.introductionMaterials?.pdf, - youtube = labDto.introductionMaterials?.youtube, + youtube = labDto.youtube, research = researchGroup, description = labDto.description, websiteURL = labDto.websiteURL, - isPublic = labDto.isPublic, ) } } diff --git a/src/main/kotlin/com/wafflestudio/csereal/core/research/database/ResearchEntity.kt b/src/main/kotlin/com/wafflestudio/csereal/core/research/database/ResearchEntity.kt index ad3d294f..70cbca2b 100644 --- a/src/main/kotlin/com/wafflestudio/csereal/core/research/database/ResearchEntity.kt +++ b/src/main/kotlin/com/wafflestudio/csereal/core/research/database/ResearchEntity.kt @@ -1,7 +1,11 @@ package com.wafflestudio.csereal.core.research.database import com.wafflestudio.csereal.common.config.BaseTimeEntity +import com.wafflestudio.csereal.common.controller.AttachmentContentEntityType +import com.wafflestudio.csereal.common.controller.MainImageContentEntityType import com.wafflestudio.csereal.core.research.dto.ResearchDto +import com.wafflestudio.csereal.core.resource.attachment.database.AttachmentEntity +import com.wafflestudio.csereal.core.resource.mainImage.database.MainImageEntity import jakarta.persistence.* @Entity(name = "research") @@ -10,24 +14,27 @@ class ResearchEntity( var postType: ResearchPostType, var name: String, - var description: String?, - var websiteURL: String?, + @OneToMany(mappedBy = "research", cascade = [CascadeType.ALL], orphanRemoval = true) + var labs: MutableList = mutableListOf(), - var isPublic: Boolean, + @OneToOne + var mainImage: MainImageEntity? = null, @OneToMany(mappedBy = "research", cascade = [CascadeType.ALL], orphanRemoval = true) - var labs: MutableList = mutableListOf() -): BaseTimeEntity() { + var attachments: MutableList = mutableListOf(), + + ) : BaseTimeEntity(), MainImageContentEntityType, AttachmentContentEntityType { + override fun bringMainImage() = mainImage + override fun bringAttachments() = attachments + companion object { - fun of(researchDto: ResearchDto) : ResearchEntity { + fun of(researchDto: ResearchDto): ResearchEntity { return ResearchEntity( postType = researchDto.postType, name = researchDto.name, description = researchDto.description, - websiteURL = researchDto.websiteURL, - isPublic = researchDto.isPublic ) } } diff --git a/src/main/kotlin/com/wafflestudio/csereal/core/research/dto/LabDto.kt b/src/main/kotlin/com/wafflestudio/csereal/core/research/dto/LabDto.kt index 82f95b23..55e19ea0 100644 --- a/src/main/kotlin/com/wafflestudio/csereal/core/research/dto/LabDto.kt +++ b/src/main/kotlin/com/wafflestudio/csereal/core/research/dto/LabDto.kt @@ -1,35 +1,34 @@ package com.wafflestudio.csereal.core.research.dto import com.wafflestudio.csereal.core.research.database.LabEntity -import com.wafflestudio.csereal.core.resource.introductionMaterial.dto.IntroductionMaterialDto data class LabDto( val id: Long, val name: String, - val professors: List?, + val professors: List?, val location: String?, val tel: String?, val acronym: String?, - val introductionMaterials: IntroductionMaterialDto?, + val pdf: String?, + val youtube: String?, val group: String, val description: String?, val websiteURL: String?, - val isPublic: Boolean, ) { companion object { - fun of(entity: LabEntity): LabDto = entity.run { + fun of(entity: LabEntity, pdfURL: String): LabDto = entity.run { LabDto( id = this.id, name = this.name, - professors = this.professors.map { it.name }, + professors = this.professors.map { LabProfessorResponse(id = it.id, name = it.name) }, location = this.location, tel = this.tel, acronym = this.acronym, - introductionMaterials = IntroductionMaterialDto(this.pdf, this.youtube), + pdf = pdfURL, + youtube = this.youtube, group = this.research.name, description = this.description, websiteURL = this.websiteURL, - isPublic = this.isPublic ) } } diff --git a/src/main/kotlin/com/wafflestudio/csereal/core/research/dto/LabProfessorResponse.kt b/src/main/kotlin/com/wafflestudio/csereal/core/research/dto/LabProfessorResponse.kt new file mode 100644 index 00000000..9ebbdd0a --- /dev/null +++ b/src/main/kotlin/com/wafflestudio/csereal/core/research/dto/LabProfessorResponse.kt @@ -0,0 +1,7 @@ +package com.wafflestudio.csereal.core.research.dto + +data class LabProfessorResponse( + val id: Long, + val name: String, +) { +} \ No newline at end of file diff --git a/src/main/kotlin/com/wafflestudio/csereal/core/research/dto/ResearchDto.kt b/src/main/kotlin/com/wafflestudio/csereal/core/research/dto/ResearchDto.kt index e81ba4fd..0f694e81 100644 --- a/src/main/kotlin/com/wafflestudio/csereal/core/research/dto/ResearchDto.kt +++ b/src/main/kotlin/com/wafflestudio/csereal/core/research/dto/ResearchDto.kt @@ -2,6 +2,7 @@ package com.wafflestudio.csereal.core.research.dto import com.wafflestudio.csereal.core.research.database.ResearchEntity import com.wafflestudio.csereal.core.research.database.ResearchPostType +import com.wafflestudio.csereal.core.resource.attachment.dto.AttachmentResponse import java.time.LocalDateTime data class ResearchDto( @@ -9,24 +10,24 @@ data class ResearchDto( val postType: ResearchPostType, val name: String, val description: String?, - val websiteURL: String?, val createdAt: LocalDateTime?, val modifiedAt: LocalDateTime?, - val isPublic: Boolean, - val labsId: List? + val labs: List?, + val imageURL: String?, + val attachments: List?, ) { companion object { - fun of(entity: ResearchEntity) = entity.run { + fun of(entity: ResearchEntity, imageURL: String?, attachmentResponse: List) = entity.run { ResearchDto( id = this.id, postType = this.postType, name = this.name, description = this.description, - websiteURL = this.websiteURL, createdAt = this.createdAt, modifiedAt = this.modifiedAt, - isPublic = this.isPublic, - labsId = this.labs.map { it.id } + labs = this.labs.map { ResearchLabResponse(id = it.id, name = it.name) }, + imageURL = imageURL, + attachments = attachmentResponse ) } } diff --git a/src/main/kotlin/com/wafflestudio/csereal/core/research/dto/ResearchLabResponse.kt b/src/main/kotlin/com/wafflestudio/csereal/core/research/dto/ResearchLabResponse.kt new file mode 100644 index 00000000..2761c2cb --- /dev/null +++ b/src/main/kotlin/com/wafflestudio/csereal/core/research/dto/ResearchLabResponse.kt @@ -0,0 +1,7 @@ +package com.wafflestudio.csereal.core.research.dto + +data class ResearchLabResponse( + val id: Long, + val name: String, +) { +} \ No newline at end of file diff --git a/src/main/kotlin/com/wafflestudio/csereal/core/research/service/ResearchService.kt b/src/main/kotlin/com/wafflestudio/csereal/core/research/service/ResearchService.kt index e42bc7c7..96c26303 100644 --- a/src/main/kotlin/com/wafflestudio/csereal/core/research/service/ResearchService.kt +++ b/src/main/kotlin/com/wafflestudio/csereal/core/research/service/ResearchService.kt @@ -1,47 +1,65 @@ package com.wafflestudio.csereal.core.research.service import com.wafflestudio.csereal.common.CserealException +import com.wafflestudio.csereal.common.properties.EndpointProperties import com.wafflestudio.csereal.core.member.database.ProfessorRepository import com.wafflestudio.csereal.core.research.database.* -import com.wafflestudio.csereal.core.research.dto.LabDto -import com.wafflestudio.csereal.core.research.dto.ResearchDto -import com.wafflestudio.csereal.core.research.dto.ResearchGroupResponse +import com.wafflestudio.csereal.core.research.dto.* +import com.wafflestudio.csereal.core.resource.attachment.database.AttachmentEntity +import com.wafflestudio.csereal.core.resource.attachment.service.AttachmentService +import com.wafflestudio.csereal.core.resource.mainImage.service.MainImageService import org.springframework.data.repository.findByIdOrNull import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional +import org.springframework.web.multipart.MultipartFile interface ResearchService { - fun createResearchDetail(request: ResearchDto): ResearchDto + fun createResearchDetail(request: ResearchDto, mainImage: MultipartFile?, attachments: List?): ResearchDto fun readAllResearchGroups(): ResearchGroupResponse fun readAllResearchCenters(): List - fun updateResearchDetail(researchId: Long, request: ResearchDto): ResearchDto - fun createLab(request: LabDto): LabDto - + fun updateResearchDetail(researchId: Long, request: ResearchDto, mainImage: MultipartFile?, attachments: List?): ResearchDto + fun createLab(request: LabDto, pdf: MultipartFile?): LabDto fun readAllLabs(): List + fun readLab(labId: Long): LabDto } @Service class ResearchServiceImpl( private val researchRepository: ResearchRepository, private val labRepository: LabRepository, - private val professorRepository: ProfessorRepository + private val professorRepository: ProfessorRepository, + private val mainImageService: MainImageService, + private val attachmentService: AttachmentService, + private val endpointProperties: EndpointProperties, ) : ResearchService { @Transactional - override fun createResearchDetail(request: ResearchDto): ResearchDto { + override fun createResearchDetail(request: ResearchDto, mainImage: MultipartFile?, attachments: List?): ResearchDto { val newResearch = ResearchEntity.of(request) - if(request.labsId != null) { - for(labId in request.labsId) { - val lab = labRepository.findByIdOrNull(labId) - ?: throw CserealException.Csereal404("해당 연구실을 찾을 수 없습니다.(labId=$labId)") - newResearch.labs.add(lab) - lab.research = newResearch + if(request.labs != null) { + + for(lab in request.labs) { + val labEntity = labRepository.findByIdOrNull(lab.id) + ?: throw CserealException.Csereal404("해당 연구실을 찾을 수 없습니다.(labId=${lab.id})") + newResearch.labs.add(labEntity) + labEntity.research = newResearch } } + if(mainImage != null) { + mainImageService.uploadMainImage(newResearch, mainImage) + } + + if(attachments != null) { + attachmentService.uploadAllAttachments(newResearch, attachments) + } + researchRepository.save(newResearch) - return ResearchDto.of(newResearch) + val imageURL = mainImageService.createImageURL(newResearch.mainImage) + val attachmentResponses = attachmentService.createAttachmentResponses(newResearch.attachments) + + return ResearchDto.of(newResearch, imageURL, attachmentResponses) } @Transactional(readOnly = true) @@ -53,7 +71,10 @@ class ResearchServiceImpl( "오늘도 인류가 꿈꾸는 행복하고 편리한 세상을 위해 변화와 혁신, 연구와 도전을 계속하고 있습니다." val researchGroups = researchRepository.findAllByPostTypeOrderByName(ResearchPostType.GROUPS).map { - ResearchDto.of(it) + val imageURL = mainImageService.createImageURL(it.mainImage) + val attachmentResponses = attachmentService.createAttachmentResponses(it.attachments) + + ResearchDto.of(it, imageURL, attachmentResponses) } return ResearchGroupResponse(description, researchGroups) @@ -62,27 +83,30 @@ class ResearchServiceImpl( @Transactional(readOnly = true) override fun readAllResearchCenters(): List { val researchCenters = researchRepository.findAllByPostTypeOrderByName(ResearchPostType.CENTERS).map { - ResearchDto.of(it) + val imageURL = mainImageService.createImageURL(it.mainImage) + val attachmentResponses = attachmentService.createAttachmentResponses(it.attachments) + + ResearchDto.of(it, imageURL, attachmentResponses) } return researchCenters } @Transactional - override fun updateResearchDetail(researchId: Long, request: ResearchDto): ResearchDto { + override fun updateResearchDetail(researchId: Long, request: ResearchDto, mainImage: MultipartFile?, attachments: List?): ResearchDto { val research = researchRepository.findByIdOrNull(researchId) ?: throw CserealException.Csereal404("해당 게시글을 찾을 수 없습니다.(researchId=$researchId)") - if(request.labsId != null) { - for(labId in request.labsId) { - val lab = labRepository.findByIdOrNull(labId) - ?: throw CserealException.Csereal404("해당 연구실을 찾을 수 없습니다.(labId=$labId)") + if(request.labs != null) { + for(lab in request.labs) { + val labEntity = labRepository.findByIdOrNull(lab.id) + ?: throw CserealException.Csereal404("해당 연구실을 찾을 수 없습니다.(labId=${lab.id})") } val oldLabs = research.labs.map { it.id } - val labsToRemove = oldLabs - request.labsId - val labsToAdd = request.labsId - oldLabs + val labsToRemove = oldLabs - request.labs.map { it.id } + val labsToAdd = request.labs.map { it.id } - oldLabs research.labs.removeIf { it.id in labsToRemove} @@ -94,40 +118,80 @@ class ResearchServiceImpl( } } - return ResearchDto.of(research) + if(mainImage != null) { + mainImageService.uploadMainImage(research, mainImage) + } + + if(attachments != null) { + research.attachments.clear() + attachmentService.uploadAllAttachments(research, attachments) + } + + val imageURL = mainImageService.createImageURL(research.mainImage) + val attachmentResponses = attachmentService.createAttachmentResponses(research.attachments) + + + return ResearchDto.of(research, imageURL, attachmentResponses) } @Transactional - override fun createLab(request: LabDto): LabDto { + override fun createLab(request: LabDto, pdf: MultipartFile?): LabDto { val researchGroup = researchRepository.findByName(request.group) - ?: throw CserealException.Csereal404("해당 연구그룹을 찾을 수 없습니다.(researchGroupId = ${request.group}") + ?: throw CserealException.Csereal404("해당 연구그룹을 찾을 수 없습니다.(researchGroupId = ${request.group})") if(researchGroup.postType != ResearchPostType.GROUPS) { throw CserealException.Csereal404("해당 게시글은 연구그룹이어야 합니다.") } - // get을 우선 구현하기 위해 빼겠습니다 - /* - if(request.professorsId != null) { - for(professorId in request.professorsId) { - val professor = professorRepository.findByIdOrNull(professorId) - ?: throw CserealException.Csereal404("해당 교수님을 찾을 수 없습니다.(professorId = $professorId") + val newLab = LabEntity.of(request, researchGroup) + + if(request.professors != null) { + for(professor in request.professors) { + val professorEntity = professorRepository.findByIdOrNull(professor.id) + ?: throw CserealException.Csereal404("해당 교수님을 찾을 수 없습니다.(professorId = ${professor.id}") + + newLab.professors.add(professorEntity) + professorEntity.lab = newLab } } - */ - val newLab = LabEntity.of(researchGroup, request) + var pdfURL = "" + if(pdf != null) { + val attachmentDto = attachmentService.uploadAttachmentInLabEntity(newLab, pdf) + pdfURL = "${endpointProperties.backend}/v1/attachment/${attachmentDto.filename}" + } labRepository.save(newLab) - return LabDto.of(newLab) + + return LabDto.of(newLab, pdfURL) } @Transactional(readOnly = true) override fun readAllLabs(): List { val labs = labRepository.findAllByOrderByName().map { - LabDto.of(it) + var pdfURL = "" + if(it.pdf != null) { + pdfURL = createPdfURL(it.pdf!!) + } + LabDto.of(it, pdfURL) } return labs } + + @Transactional + override fun readLab(labId: Long): LabDto { + val lab = labRepository.findByIdOrNull(labId) + ?: throw CserealException.Csereal404("해당 연구실을 찾을 수 없습니다.(labId=$labId)") + var pdfURL = "" + if(lab.pdf != null) { + pdfURL = createPdfURL(lab.pdf!!) + } + + return LabDto.of(lab, pdfURL) + } + + private fun createPdfURL(pdf: AttachmentEntity) : String{ + return "${endpointProperties.backend}/v1/attachment/${pdf.filename}" + } } \ No newline at end of file diff --git a/src/main/kotlin/com/wafflestudio/csereal/core/resource/attachment/database/AttachmentEntity.kt b/src/main/kotlin/com/wafflestudio/csereal/core/resource/attachment/database/AttachmentEntity.kt index afb4844b..1c79236a 100644 --- a/src/main/kotlin/com/wafflestudio/csereal/core/resource/attachment/database/AttachmentEntity.kt +++ b/src/main/kotlin/com/wafflestudio/csereal/core/resource/attachment/database/AttachmentEntity.kt @@ -5,6 +5,8 @@ import com.wafflestudio.csereal.core.about.database.AboutEntity import com.wafflestudio.csereal.core.academics.database.AcademicsEntity import com.wafflestudio.csereal.core.academics.database.CourseEntity import com.wafflestudio.csereal.core.news.database.NewsEntity +import com.wafflestudio.csereal.core.research.database.LabEntity +import com.wafflestudio.csereal.core.research.database.ResearchEntity import com.wafflestudio.csereal.core.seminar.database.SeminarEntity import jakarta.persistence.* @@ -37,6 +39,14 @@ class AttachmentEntity( @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "course_id") var course: CourseEntity? = null, + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "lab_id") + var lab: LabEntity? = null, + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "research_id") + var research: ResearchEntity? = null, ) : BaseTimeEntity() { } \ No newline at end of file diff --git a/src/main/kotlin/com/wafflestudio/csereal/core/resource/attachment/service/AttachmentService.kt b/src/main/kotlin/com/wafflestudio/csereal/core/resource/attachment/service/AttachmentService.kt index b70e17a0..d6654def 100644 --- a/src/main/kotlin/com/wafflestudio/csereal/core/resource/attachment/service/AttachmentService.kt +++ b/src/main/kotlin/com/wafflestudio/csereal/core/resource/attachment/service/AttachmentService.kt @@ -1,10 +1,13 @@ package com.wafflestudio.csereal.core.resource.attachment.service import com.wafflestudio.csereal.common.controller.AttachmentContentEntityType +import com.wafflestudio.csereal.common.properties.EndpointProperties import com.wafflestudio.csereal.core.about.database.AboutEntity import com.wafflestudio.csereal.core.academics.database.AcademicsEntity import com.wafflestudio.csereal.core.academics.database.CourseEntity import com.wafflestudio.csereal.core.news.database.NewsEntity +import com.wafflestudio.csereal.core.research.database.LabEntity +import com.wafflestudio.csereal.core.research.database.ResearchEntity import com.wafflestudio.csereal.core.resource.attachment.database.AttachmentEntity import com.wafflestudio.csereal.core.resource.attachment.database.AttachmentRepository import com.wafflestudio.csereal.core.resource.attachment.dto.AttachmentDto @@ -19,11 +22,15 @@ import java.nio.file.Files import java.nio.file.Paths interface AttachmentService { - fun uploadAttachments( + fun uploadAttachmentInLabEntity( + labEntity: LabEntity, + requestAttachment: MultipartFile + ): AttachmentDto + fun uploadAllAttachments( contentEntityType: AttachmentContentEntityType, requestAttachments: List, ): List - fun createAttachments(attachments: List?): List? + fun createAttachmentResponses(attachments: List?): List } @Service @@ -31,9 +38,38 @@ class AttachmentServiceImpl( private val attachmentRepository: AttachmentRepository, @Value("\${csereal_attachment.upload.path}") private val path: String, + private val endpointProperties: EndpointProperties, ) : AttachmentService { + override fun uploadAttachmentInLabEntity(labEntity: LabEntity, requestAttachment: MultipartFile): AttachmentDto { + Files.createDirectories(Paths.get(path)) + + val extension = FilenameUtils.getExtension(requestAttachment.originalFilename) + + val timeMillis = System.currentTimeMillis() + + val filename = "${timeMillis}_${requestAttachment.originalFilename}" + val totalFilename = path + filename + val saveFile = Paths.get("$totalFilename.$extension") + requestAttachment.transferTo(saveFile) + + val attachment = AttachmentEntity( + filename = filename, + attachmentsOrder = 1, + size = requestAttachment.size, + ) + + labEntity.pdf = attachment + attachmentRepository.save(attachment) + + return AttachmentDto( + filename = filename, + attachmentsOrder = 1, + size = requestAttachment.size + ) + + } @Transactional - override fun uploadAttachments( + override fun uploadAllAttachments( contentEntity: AttachmentContentEntityType, requestAttachments: List, ): List { @@ -72,13 +108,13 @@ class AttachmentServiceImpl( } @Transactional - override fun createAttachments(attachments: List?): List? { + override fun createAttachmentResponses(attachments: List?): List{ val list = mutableListOf() if (attachments != null) { for (attachment in attachments) { val attachmentDto = AttachmentResponse( name = attachment.filename, - url = "http://cse-dev-waffle.bacchus.io/attachment/${attachment.filename}", + url = "${endpointProperties.backend}/v1/attachment/${attachment.filename}", bytes = attachment.size, ) list.add(attachmentDto) @@ -109,6 +145,10 @@ class AttachmentServiceImpl( contentEntity.attachments.add(attachment) attachment.course = contentEntity } + is ResearchEntity -> { + contentEntity.attachments.add(attachment) + attachment.research = contentEntity + } } } } \ No newline at end of file diff --git a/src/main/kotlin/com/wafflestudio/csereal/core/resource/introductionMaterial/dto/introductionMaterialDto.kt b/src/main/kotlin/com/wafflestudio/csereal/core/resource/introductionMaterial/dto/introductionMaterialDto.kt deleted file mode 100644 index f4c9873c..00000000 --- a/src/main/kotlin/com/wafflestudio/csereal/core/resource/introductionMaterial/dto/introductionMaterialDto.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.wafflestudio.csereal.core.resource.introductionMaterial.dto - -// Todo: IntroductionMaterial이 연구실에만 쓰이는지 확인할 것 -data class IntroductionMaterialDto( - val pdf: String?, - val youtube: String?, -) { -} \ No newline at end of file diff --git a/src/main/kotlin/com/wafflestudio/csereal/core/resource/mainImage/service/MainImageService.kt b/src/main/kotlin/com/wafflestudio/csereal/core/resource/mainImage/service/MainImageService.kt index 0a5690f1..4a6e32eb 100644 --- a/src/main/kotlin/com/wafflestudio/csereal/core/resource/mainImage/service/MainImageService.kt +++ b/src/main/kotlin/com/wafflestudio/csereal/core/resource/mainImage/service/MainImageService.kt @@ -1,12 +1,13 @@ package com.wafflestudio.csereal.core.resource.mainImage.service import com.wafflestudio.csereal.common.CserealException -import com.wafflestudio.csereal.common.controller.ImageContentEntityType +import com.wafflestudio.csereal.common.controller.MainImageContentEntityType import com.wafflestudio.csereal.common.properties.EndpointProperties import com.wafflestudio.csereal.core.about.database.AboutEntity import com.wafflestudio.csereal.core.member.database.ProfessorEntity import com.wafflestudio.csereal.core.member.database.StaffEntity import com.wafflestudio.csereal.core.news.database.NewsEntity +import com.wafflestudio.csereal.core.research.database.ResearchEntity import com.wafflestudio.csereal.core.resource.mainImage.database.MainImageRepository import com.wafflestudio.csereal.core.resource.mainImage.database.MainImageEntity import com.wafflestudio.csereal.core.resource.mainImage.dto.MainImageDto @@ -25,10 +26,9 @@ import kotlin.io.path.name interface MainImageService { fun uploadMainImage( - contentEntityType: ImageContentEntityType, + contentEntityType: MainImageContentEntityType, requestImage: MultipartFile, ): MainImageDto - fun createImageURL(image: MainImageEntity?): String? } @@ -42,7 +42,7 @@ class MainImageServiceImpl( @Transactional override fun uploadMainImage( - contentEntityType: ImageContentEntityType, + contentEntityType: MainImageContentEntityType, requestImage: MultipartFile, ): MainImageDto { Files.createDirectories(Paths.get(path)) @@ -94,7 +94,7 @@ class MainImageServiceImpl( } else null } - private fun connectMainImageToEntity(contentEntity: ImageContentEntityType, mainImage: MainImageEntity) { + private fun connectMainImageToEntity(contentEntity: MainImageContentEntityType, mainImage: MainImageEntity) { when (contentEntity) { is NewsEntity -> { contentEntity.mainImage = mainImage @@ -116,6 +116,9 @@ class MainImageServiceImpl( contentEntity.mainImage = mainImage } + is ResearchEntity -> { + contentEntity.mainImage = mainImage + } else -> { throw WrongMethodTypeException("해당하는 엔티티가 없습니다") } diff --git a/src/main/kotlin/com/wafflestudio/csereal/core/seminar/database/SeminarEntity.kt b/src/main/kotlin/com/wafflestudio/csereal/core/seminar/database/SeminarEntity.kt index 04c6359d..9e2ba977 100644 --- a/src/main/kotlin/com/wafflestudio/csereal/core/seminar/database/SeminarEntity.kt +++ b/src/main/kotlin/com/wafflestudio/csereal/core/seminar/database/SeminarEntity.kt @@ -2,7 +2,7 @@ package com.wafflestudio.csereal.core.seminar.database import com.wafflestudio.csereal.common.config.BaseTimeEntity import com.wafflestudio.csereal.common.controller.AttachmentContentEntityType -import com.wafflestudio.csereal.common.controller.ImageContentEntityType +import com.wafflestudio.csereal.common.controller.MainImageContentEntityType import com.wafflestudio.csereal.core.resource.attachment.database.AttachmentEntity import com.wafflestudio.csereal.core.resource.mainImage.database.MainImageEntity import com.wafflestudio.csereal.core.seminar.dto.SeminarDto @@ -47,7 +47,7 @@ class SeminarEntity( @OneToMany(mappedBy = "seminar", cascade = [CascadeType.ALL], orphanRemoval = true) var attachments: MutableList = mutableListOf(), - ): BaseTimeEntity(), ImageContentEntityType, AttachmentContentEntityType { + ): BaseTimeEntity(), MainImageContentEntityType, AttachmentContentEntityType { override fun bringMainImage(): MainImageEntity? = mainImage override fun bringAttachments() = attachments diff --git a/src/main/kotlin/com/wafflestudio/csereal/core/seminar/dto/SeminarDto.kt b/src/main/kotlin/com/wafflestudio/csereal/core/seminar/dto/SeminarDto.kt index c0a20380..899a5b0d 100644 --- a/src/main/kotlin/com/wafflestudio/csereal/core/seminar/dto/SeminarDto.kt +++ b/src/main/kotlin/com/wafflestudio/csereal/core/seminar/dto/SeminarDto.kt @@ -34,7 +34,7 @@ data class SeminarDto( ) { companion object { - fun of(entity: SeminarEntity, imageURL: String?, attachments: List?, prevNext: Array?): SeminarDto = entity.run { + fun of(entity: SeminarEntity, imageURL: String?, attachmentResponses: List, prevNext: Array?): SeminarDto = entity.run { SeminarDto( id = this.id, title = this.title, @@ -60,7 +60,7 @@ data class SeminarDto( nextId = prevNext?.get(1)?.id, nextTitle = prevNext?.get(1)?.title, imageURL = imageURL, - attachments = attachments, + attachments = attachmentResponses, ) } diff --git a/src/main/kotlin/com/wafflestudio/csereal/core/seminar/service/SeminarService.kt b/src/main/kotlin/com/wafflestudio/csereal/core/seminar/service/SeminarService.kt index 2d28eef1..ebba6b47 100644 --- a/src/main/kotlin/com/wafflestudio/csereal/core/seminar/service/SeminarService.kt +++ b/src/main/kotlin/com/wafflestudio/csereal/core/seminar/service/SeminarService.kt @@ -40,14 +40,14 @@ class SeminarServiceImpl( } if(attachments != null) { - attachmentService.uploadAttachments(newSeminar, attachments) + attachmentService.uploadAllAttachments(newSeminar, attachments) } seminarRepository.save(newSeminar) val imageURL = mainImageService.createImageURL(newSeminar.mainImage) - val attachments = attachmentService.createAttachments(newSeminar.attachments) - return SeminarDto.of(newSeminar, imageURL, attachments, null) + val attachmentResponses = attachmentService.createAttachmentResponses(newSeminar.attachments) + return SeminarDto.of(newSeminar, imageURL, attachmentResponses, null) } @Transactional(readOnly = true) @@ -58,11 +58,11 @@ class SeminarServiceImpl( if (seminar.isDeleted) throw CserealException.Csereal400("삭제된 세미나입니다. (seminarId: $seminarId)") val imageURL = mainImageService.createImageURL(seminar.mainImage) - val attachments = attachmentService.createAttachments(seminar.attachments) + val attachmentResponses = attachmentService.createAttachmentResponses(seminar.attachments) val prevNext = seminarRepository.findPrevNextId(seminarId, keyword) - return SeminarDto.of(seminar, imageURL, attachments, prevNext) + return SeminarDto.of(seminar, imageURL, attachmentResponses, prevNext) } @Transactional @@ -79,14 +79,13 @@ class SeminarServiceImpl( if(attachments != null) { seminar.attachments.clear() - attachmentService.uploadAttachments(seminar, attachments) + attachmentService.uploadAllAttachments(seminar, attachments) } val imageURL = mainImageService.createImageURL(seminar.mainImage) - val attachments = attachmentService.createAttachments(seminar.attachments) - - - return SeminarDto.of(seminar, imageURL, attachments, null) + val attachmentResponses = attachmentService.createAttachmentResponses(seminar.attachments) + + return SeminarDto.of(seminar, imageURL, attachmentResponses, null) } @Transactional override fun deleteSeminar(seminarId: Long) {