Skip to content

Commit

Permalink
Feat: Research Group & Center 언어포함 CRUD 생성 (#315)
Browse files Browse the repository at this point in the history
* refactor: deprecated v1 controller

* refactor: extract types in seperate package, remove unused attachment from research

* feat: make lab's research as nullable

* feat: add research language entity & repository

* feat: add language & sealed dtos

* feat: remove migrate methods & seperate update index methods

* feat: add CRUD language considered methods

* feat: add v2 reserach controller

* fix: fix test compiling

* test: fix professerservice test

* refactor: fix ktlint formatting

* review: research -> fetch lazy
  • Loading branch information
huGgW authored Sep 6, 2024
1 parent d2abb93 commit 7d970d4
Show file tree
Hide file tree
Showing 22 changed files with 881 additions and 686 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.wafflestudio.csereal.core.research.api.req

import com.fasterxml.jackson.annotation.JsonSubTypes
import com.fasterxml.jackson.annotation.JsonTypeInfo
import com.wafflestudio.csereal.core.research.type.ResearchType

data class CreateResearchLanguageReqBody(
val ko: CreateResearchSealedReqBody,
val en: CreateResearchSealedReqBody
) {
fun valid() = ko.type == en.type
fun valid(type: ResearchType) = ko.valid(type) && en.valid(type)
}

@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.EXISTING_PROPERTY,
property = "type"
)
@JsonSubTypes(
JsonSubTypes.Type(value = CreateResearchGroupReqBody::class, names = ["GROUPS", "groups"]),
JsonSubTypes.Type(value = CreateResearchCenterReqBody::class, names = ["CENTERS", "centers"])
)
sealed class CreateResearchSealedReqBody(
val type: ResearchType,
open val name: String,
open val description: String,
open val mainImageUrl: String?
) {
fun valid(type: ResearchType) = this.type == type
}

data class CreateResearchGroupReqBody(
override val name: String,
override val description: String,
override val mainImageUrl: String?
) : CreateResearchSealedReqBody(ResearchType.GROUPS, name, description, mainImageUrl)

data class CreateResearchCenterReqBody(
override val name: String,
override val description: String,
override val mainImageUrl: String?,
val websiteURL: String?
) : CreateResearchSealedReqBody(ResearchType.CENTERS, name, description, mainImageUrl)
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.wafflestudio.csereal.core.research.api.req

import com.fasterxml.jackson.annotation.JsonSubTypes
import com.fasterxml.jackson.annotation.JsonTypeInfo
import com.wafflestudio.csereal.core.research.type.ResearchType

data class ModifyResearchLanguageReqBody(
val ko: ModifyResearchSealedReqBody,
val en: ModifyResearchSealedReqBody
) {
fun valid() = ko.type == en.type
}

@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.EXISTING_PROPERTY,
property = "type"
)
@JsonSubTypes(
JsonSubTypes.Type(value = ModifyResearchGroupReqBody::class, names = ["GROUPS", "groups"]),
JsonSubTypes.Type(value = ModifyResearchCenterReqBody::class, names = ["CENTERS", "centers"])
)
sealed class ModifyResearchSealedReqBody(
val type: ResearchType,
open val name: String,
open val description: String,
open val removeImage: Boolean
)

data class ModifyResearchGroupReqBody(
override val name: String,
override val description: String,
override val removeImage: Boolean
) : ModifyResearchSealedReqBody(ResearchType.GROUPS, name, description, removeImage)

data class ModifyResearchCenterReqBody(
override val name: String,
override val description: String,
override val removeImage: Boolean,
val websiteURL: String?
) : ModifyResearchSealedReqBody(ResearchType.CENTERS, name, description, removeImage)
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@ package com.wafflestudio.csereal.core.research.api.res
import com.wafflestudio.csereal.common.CserealException
import com.wafflestudio.csereal.common.enums.LanguageType
import com.wafflestudio.csereal.common.utils.substringAroundKeyword
import com.wafflestudio.csereal.core.research.database.ResearchPostType
import com.wafflestudio.csereal.core.research.database.ResearchSearchEntity
import com.wafflestudio.csereal.core.research.database.ResearchSearchType
import com.wafflestudio.csereal.core.research.type.ResearchRelatedType

data class ResearchSearchResElement(
val id: Long,
val language: String,
val name: String,
val researchType: ResearchSearchType,
val researchType: ResearchRelatedType,
val partialDescription: String,
val boldStartIdx: Int,
val boldEndIdx: Int
Expand All @@ -36,10 +35,7 @@ data class ResearchSearchResElement(
id = it.id,
name = it.name,
language = it.language.let { ln -> LanguageType.makeLowercase(ln) },
researchType = when (it.postType) {
ResearchPostType.GROUPS -> ResearchSearchType.RESEARCH_GROUP
ResearchPostType.CENTERS -> ResearchSearchType.RESEARCH_CENTER
},
researchType = it.postType.ofResearchRelatedType(),
partialDescription = partialDesc,
boldStartIdx = startIdx ?: 0,
boldEndIdx = startIdx?.plus(keyword.length) ?: 0
Expand All @@ -59,7 +55,7 @@ data class ResearchSearchResElement(
id = it.id,
name = it.name,
language = it.language.let { ln -> LanguageType.makeLowercase(ln) },
researchType = ResearchSearchType.LAB,
researchType = ResearchRelatedType.LAB,
partialDescription = partialDesc,
boldStartIdx = startIdx ?: 0,
boldEndIdx = startIdx?.plus(keyword.length) ?: 0
Expand All @@ -79,7 +75,7 @@ data class ResearchSearchResElement(
id = it.id,
name = it.name,
language = it.language.let { ln -> LanguageType.makeLowercase(ln) },
researchType = ResearchSearchType.CONFERENCE,
researchType = ResearchRelatedType.CONFERENCE,
partialDescription = partialDesc,
boldStartIdx = startIdx ?: 0,
boldEndIdx = startIdx?.plus(keyword.length) ?: 0
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.wafflestudio.csereal.core.research.api
package com.wafflestudio.csereal.core.research.api.v1

import com.wafflestudio.csereal.common.aop.AuthenticatedStaff
import com.wafflestudio.csereal.common.enums.LanguageType
Expand All @@ -10,54 +10,29 @@ import com.wafflestudio.csereal.core.research.service.ResearchSearchService
import com.wafflestudio.csereal.core.research.service.ResearchService
import jakarta.validation.Valid
import jakarta.validation.constraints.Positive
import org.springframework.context.annotation.Profile
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*
import org.springframework.web.multipart.MultipartFile

@RequestMapping("/api/v1/research")
@RestController
@RestController("ResearchControllerV1")
@Deprecated(message = "Use V2 API")
class ResearchController(
private val researchService: ResearchService,
private val researchSearchService: ResearchSearchService
) {
@AuthenticatedStaff
@PostMapping
fun createResearchDetail(
@Valid
@RequestPart("request")
request: ResearchDto,
@RequestPart("mainImage") mainImage: MultipartFile?,
@RequestPart("attachments") attachments: List<MultipartFile>?
): ResponseEntity<ResearchDto> {
return ResponseEntity.ok(researchService.createResearchDetail(request, mainImage, attachments))
}

@GetMapping("/groups")
fun readAllResearchGroups(
@RequestParam(required = false, defaultValue = "ko") language: String
): ResponseEntity<ResearchGroupResponse> {
return ResponseEntity.ok(researchService.readAllResearchGroups(language))
return ResponseEntity.ok(researchService.readAllResearchGroupsDeprecated(language))
}

@GetMapping("/centers")
fun readAllResearchCenters(
@RequestParam(required = false, defaultValue = "ko") language: String
): ResponseEntity<List<ResearchDto>> {
return ResponseEntity.ok(researchService.readAllResearchCenters(language))
}

@AuthenticatedStaff
@PatchMapping("/{researchId}")
fun updateResearchDetail(
@PathVariable researchId: Long,
@Valid
@RequestPart("request")
request: ResearchDto,
@RequestPart("mainImage") mainImage: MultipartFile?,
@RequestPart("attachments") attachments: List<MultipartFile>?
): ResponseEntity<ResearchDto> {
return ResponseEntity.ok(researchService.updateResearchDetail(researchId, request, mainImage, attachments))
return ResponseEntity.ok(researchService.readAllResearchCentersDeprecated(language))
}

@AuthenticatedStaff
Expand Down Expand Up @@ -100,49 +75,6 @@ class ResearchController(
return ResponseEntity.ok(researchService.updateLab(labId, request, pdf))
}

@Profile("!prod")
@PostMapping("/migrate")
fun migrateResearchDetail(
@RequestBody requestList: List<ResearchDto>
): ResponseEntity<List<ResearchDto>> {
return ResponseEntity.ok(researchService.migrateResearchDetail(requestList))
}

@Profile("!prod")
@PostMapping("/lab/migrate")
fun migrateLabs(
@RequestBody requestList: List<LabDto>
): ResponseEntity<List<LabDto>> {
return ResponseEntity.ok(researchService.migrateLabs(requestList))
}

@Profile("!prod")
@PatchMapping("/migrateImageAndAttachments/{researchId}")
fun migrateResearchDetailImageAndAttachments(
@PathVariable researchId: Long,
@RequestPart("mainImage") mainImage: MultipartFile?,
@RequestPart("attachments") attachments: List<MultipartFile>?
): ResponseEntity<ResearchDto> {
return ResponseEntity.ok(
researchService.migrateResearchDetailImageAndAttachments(
researchId,
mainImage,
attachments
)
)
}

@Profile("!prod")
@PatchMapping("/lab/migratePdf/{labId}")
fun migrateLabPdf(
@PathVariable labId: Long,
@RequestPart("pdf") pdf: MultipartFile?
): ResponseEntity<LabDto> {
return ResponseEntity.ok(
researchService.migrateLabPdf(labId, pdf)
)
}

@GetMapping("/search/top")
fun searchTop(
@RequestParam(required = true) keyword: String,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
package com.wafflestudio.csereal.core.research.api.v2

import com.wafflestudio.csereal.common.aop.AuthenticatedStaff
import com.wafflestudio.csereal.common.enums.LanguageType
import com.wafflestudio.csereal.core.research.api.req.CreateResearchLanguageReqBody
import com.wafflestudio.csereal.core.research.api.req.ModifyResearchLanguageReqBody
import com.wafflestudio.csereal.core.research.dto.LabDto
import com.wafflestudio.csereal.core.research.dto.ResearchLanguageDto
import com.wafflestudio.csereal.core.research.dto.ResearchSealedDto
import com.wafflestudio.csereal.core.research.service.ResearchSearchService
import com.wafflestudio.csereal.core.research.service.ResearchService
import com.wafflestudio.csereal.core.research.type.ResearchType
import io.swagger.v3.oas.annotations.Parameter
import jakarta.validation.Valid
import jakarta.validation.constraints.Positive
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*
import org.springframework.web.multipart.MultipartFile

@RequestMapping("/api/v2/research")
@RestController
class ResearchController(
private val researchService: ResearchService,
private val researchSearchService: ResearchSearchService
) {
@GetMapping("/{researchId:[0-9]+}")
fun readResearch(
@Positive
@PathVariable(required = true)
researchId: Long
): ResearchLanguageDto {
return researchService.readResearchLanguage(researchId)
}

@GetMapping("/{researchType:[a-z A-Z]+}")
fun readAllResearch(
@PathVariable(required = true) researchType: String,
@RequestParam(required = false, defaultValue = "ko") language: String
): List<ResearchSealedDto> {
val researchTypeEnum = ResearchType.fromJsonValue(researchType)
val languageEnum = LanguageType.makeStringToLanguageType(language)
return researchService.readAllResearch(languageEnum, researchTypeEnum)
}

@AuthenticatedStaff
@PostMapping(consumes = ["multipart/form-data"])
fun createResearchGroup(
@RequestPart("request") request: CreateResearchLanguageReqBody,
@RequestPart("mainImage") mainImage: MultipartFile?
): ResearchLanguageDto = researchService.createResearchLanguage(request, mainImage)

@AuthenticatedStaff
@PutMapping("/{koreanId}/{englishId}", consumes = ["multipart/form-data"])
fun updateResearch(
@PathVariable @Positive
koreanId: Long,
@PathVariable @Positive
englishId: Long,
@RequestPart("request") request: ModifyResearchLanguageReqBody,

@Parameter(description = "image 교체할 경우 업로드. Request Body의 removeImage 관계없이 변경됨.")
@RequestPart("newImage")
newImage: MultipartFile?
): ResearchLanguageDto {
return researchService.updateResearchLanguage(koreanId, englishId, request, newImage)
}

@AuthenticatedStaff
@DeleteMapping("/{koreanId}/{englishId}")
fun deleteResearch(
@PathVariable @Positive
koreanId: Long,
@PathVariable @Positive
englishId: Long
) {
researchService.deleteResearchLanguage(koreanId, englishId)
}

// TODO: Change to Language Unified API
@GetMapping("/labs")
fun readAllLabs(
@RequestParam(required = false, defaultValue = "ko") language: String
): ResponseEntity<List<LabDto>> {
return ResponseEntity.ok(researchService.readAllLabs(language))
}

// TODO: Change to Language Unified API
@GetMapping("/lab/{labId}")
fun readLab(
@PathVariable labId: Long
): ResponseEntity<LabDto> {
return ResponseEntity.ok(researchService.readLab(labId))
}

// @AuthenticatedStaff
// @PostMapping("/lab")
// fun createLab(
// @Valid
// @RequestPart("request")
// request: LabDto,
// @RequestPart("pdf") pdf: MultipartFile?
// ): ResponseEntity<LabDto> {
// return ResponseEntity.ok(researchService.createLab(request, pdf))
// }
//
//
// // TODO: Change to Language Unified API
// @AuthenticatedStaff
// @PatchMapping("/lab/{labId}")
// fun updateLab(
// @PathVariable labId: Long,
// @Valid
// @RequestPart("request")
// request: LabUpdateRequest,
// @RequestPart("pdf") pdf: MultipartFile?
// ): ResponseEntity<LabDto> {
// return ResponseEntity.ok(researchService.updateLab(labId, request, pdf))
// }

@GetMapping("/search/top")
fun searchTop(
@RequestParam(required = true) keyword: String,
@RequestParam(required = true) @Valid @Positive number: Int,
@RequestParam(required = true, defaultValue = "ko") language: String,
@RequestParam(required = false, defaultValue = "30") @Valid @Positive amount: Int
) = researchSearchService.searchTopResearch(
keyword,
LanguageType.makeStringToLanguageType(language),
number,
amount
)

@GetMapping("/search")
fun searchPage(
@RequestParam(required = true) keyword: String,
@RequestParam(required = true) pageSize: Int,
@RequestParam(required = true) pageNum: Int,
@RequestParam(required = true, defaultValue = "ko") language: String,
@RequestParam(required = false, defaultValue = "30") @Valid @Positive amount: Int
) = researchSearchService.searchResearch(
keyword,
LanguageType.makeStringToLanguageType(language),
pageSize,
pageNum,
amount
)
}
Loading

0 comments on commit 7d970d4

Please sign in to comment.