Skip to content

Commit

Permalink
Feat: Staff 두 언어 묶어서 동작하는 V2 API 정의 (#301)
Browse files Browse the repository at this point in the history
  • Loading branch information
huGgW authored Aug 1, 2024
1 parent 88051c0 commit 14c5e5d
Show file tree
Hide file tree
Showing 16 changed files with 331 additions and 97 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.wafflestudio.csereal.core.member.api.req

data class CreateStaffLanguagesReqBody(
val ko: CreateStaffReqBody,
val en: CreateStaffReqBody
)
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.wafflestudio.csereal.core.member.api.req

data class CreateStaffReqBody(
val language: String,
val name: String,
val role: String,
val office: String,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.wafflestudio.csereal.core.member.api.req

data class ModifyStaffLanguagesReqBody(
val ko: ModifyStaffReqBody,
val en: ModifyStaffReqBody
)
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.wafflestudio.csereal.core.member.api.req

data class ModifyStaffReqBody(
val language: String,
val name: String,
val role: String,
val office: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package com.wafflestudio.csereal.core.member.api.res
import com.wafflestudio.csereal.common.CserealException
import com.wafflestudio.csereal.common.enums.LanguageType
import com.wafflestudio.csereal.core.member.database.MemberSearchEntity
import com.wafflestudio.csereal.core.member.database.MemberSearchType
import com.wafflestudio.csereal.core.member.type.MemberType
import com.wafflestudio.csereal.core.resource.mainImage.database.MainImageEntity

data class MemberSearchResponseElement(
Expand All @@ -12,7 +12,7 @@ data class MemberSearchResponseElement(
val name: String,
val academicRankOrRole: String,
val imageURL: String?,
val memberType: MemberSearchType
val memberType: MemberType
) {
companion object {
fun of(
Expand All @@ -27,7 +27,7 @@ data class MemberSearchResponseElement(
name = memberSearch.professor!!.name,
academicRankOrRole = memberSearch.professor!!.academicRank,
imageURL = imageURLMaker(memberSearch.professor!!.mainImage),
memberType = MemberSearchType.PROFESSOR
memberType = MemberType.PROFESSOR
)
memberSearch.professor == null && memberSearch.staff != null ->
MemberSearchResponseElement(
Expand All @@ -36,7 +36,7 @@ data class MemberSearchResponseElement(
name = memberSearch.staff!!.name,
academicRankOrRole = memberSearch.staff!!.role,
imageURL = imageURLMaker(memberSearch.staff!!.mainImage),
memberType = MemberSearchType.STAFF
memberType = MemberType.STAFF
)
else -> throw CserealException.Csereal401(
"MemberSearchEntity는 professor 혹은 staff 중 하나와만 연결되어있어야 합니다."
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.wafflestudio.csereal.core.member.api.v1

import com.wafflestudio.csereal.core.member.dto.SimpleStaffDto
import com.wafflestudio.csereal.core.member.dto.StaffDto
import com.wafflestudio.csereal.core.member.service.StaffService
import jakarta.validation.constraints.Positive
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*

@Deprecated(message = "Use v2 API")
@RequestMapping("/api/v1/staff")
@RestController("StaffControllerV1")
class StaffController(
private val staffService: StaffService
) {
@GetMapping("/{staffId}")
fun getStaff(
@PathVariable @Positive
staffId: Long
): ResponseEntity<StaffDto> {
return ResponseEntity.ok(staffService.getStaff(staffId))
}

@GetMapping
fun getAllStaff(
@RequestParam(required = false, defaultValue = "ko") language: String
): ResponseEntity<List<SimpleStaffDto>> {
return ResponseEntity.ok(staffService.getAllStaff(language))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.wafflestudio.csereal.core.member.api.v2

import com.wafflestudio.csereal.common.aop.AuthenticatedStaff
import com.wafflestudio.csereal.core.member.api.req.CreateStaffLanguagesReqBody
import com.wafflestudio.csereal.core.member.api.req.ModifyStaffLanguagesReqBody
import com.wafflestudio.csereal.core.member.dto.SimpleStaffDto
import com.wafflestudio.csereal.core.member.dto.StaffLanguagesDto
import com.wafflestudio.csereal.core.member.service.StaffService
import io.swagger.v3.oas.annotations.Parameter
import jakarta.validation.constraints.Positive
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.DeleteMapping
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.PutMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RequestPart
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.multipart.MultipartFile

@RequestMapping("/api/v2/staff")
@RestController
class StaffController(
private val staffService: StaffService
) {
@GetMapping("/{staffId}")
fun getStaff(
@PathVariable @Positive
staffId: Long
): StaffLanguagesDto = staffService.getStaffLanguages(staffId)

@GetMapping
fun getAllStaff(
@RequestParam(required = false, defaultValue = "ko") language: String
): ResponseEntity<List<SimpleStaffDto>> {
return ResponseEntity.ok(staffService.getAllStaff(language))
}

@AuthenticatedStaff
@PostMapping(consumes = ["multipart/form-data"])
fun createStaff(
@RequestPart("request") createStaffLanguagesReqBody: CreateStaffLanguagesReqBody,
@RequestPart("image") image: MultipartFile?
): StaffLanguagesDto = staffService.createStaffLanguages(createStaffLanguagesReqBody, image)

@AuthenticatedStaff
@PutMapping("/{koStaffId}/{enStaffId}", consumes = ["multipart/form-data"])
fun updateStaff(
@PathVariable @Positive
koStaffId: Long,
@PathVariable @Positive
enStaffId: Long,
@RequestPart("request") modifyStaffLanguageReq: ModifyStaffLanguagesReqBody,

@Parameter(description = "image 교체할 경우 업로드. Request Body의 removeImage 관계없이 변경됨.")
@RequestPart("newImage")
newImage: MultipartFile?
): StaffLanguagesDto =
staffService.updateStaffLanguages(koStaffId, enStaffId, modifyStaffLanguageReq, newImage)

@AuthenticatedStaff
@DeleteMapping("/{koStaffId}/{enStaffId}")
fun deleteStaff(
@PathVariable @Positive
koStaffId: Long,

@PathVariable @Positive
enStaffId: Long
) {
staffService.deleteStaffLanguages(koStaffId, enStaffId)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.wafflestudio.csereal.core.member.database

import com.wafflestudio.csereal.common.config.BaseTimeEntity
import com.wafflestudio.csereal.core.member.type.MemberType
import jakarta.persistence.*

@Entity(name = "member_language")
class MemberLanguageEntity(
@Column(nullable = false)
@Enumerated(EnumType.STRING)
val type: MemberType,

@Column(nullable = false)
val koreanId: Long,

@Column(nullable = false)
val englishId: Long
) : BaseTimeEntity() {
companion object {
fun of(
type: MemberType,
koreanId: Long,
englishId: Long
) = MemberLanguageEntity(type, koreanId, englishId)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.wafflestudio.csereal.core.member.database

import com.wafflestudio.csereal.core.member.type.MemberType
import org.springframework.data.jpa.repository.JpaRepository

interface MemberLanguageRepository : JpaRepository<MemberLanguageEntity, Long> {
fun existsByKoreanIdAndEnglishIdAndType(
koreanId: Long,
englishId: Long,
type: MemberType
): Boolean

fun findByKoreanIdAndEnglishIdAndType(
koreanId: Long,
englishId: Long,
type: MemberType
): MemberLanguageEntity?
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.wafflestudio.csereal.core.member.database

import com.wafflestudio.csereal.common.config.BaseTimeEntity
import com.wafflestudio.csereal.common.enums.LanguageType
import com.wafflestudio.csereal.core.member.type.MemberType
import jakarta.persistence.*

@Entity(name = "member_search")
Expand Down Expand Up @@ -80,11 +81,11 @@ class MemberSearchEntity(
}
}

fun ofType(): MemberSearchType {
fun ofType(): MemberType {
return if (professor != null) {
MemberSearchType.PROFESSOR
MemberType.PROFESSOR
} else if (staff != null) {
MemberSearchType.STAFF
MemberType.STAFF
} else {
throw RuntimeException("MemberSearchEntity must have either professor or staff")
}
Expand All @@ -100,8 +101,3 @@ class MemberSearchEntity(
this.content = createContent(staff)
}
}

enum class MemberSearchType {
PROFESSOR,
STAFF
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,47 @@
package com.wafflestudio.csereal.core.member.database

import com.querydsl.core.types.dsl.Expressions
import com.querydsl.jpa.JPAExpressions
import com.querydsl.jpa.impl.JPAQueryFactory
import com.wafflestudio.csereal.common.enums.LanguageType
import com.wafflestudio.csereal.core.member.database.QMemberLanguageEntity.memberLanguageEntity
import com.wafflestudio.csereal.core.member.database.QStaffEntity.staffEntity
import com.wafflestudio.csereal.core.member.type.MemberType
import com.wafflestudio.csereal.core.resource.mainImage.database.QMainImageEntity.mainImageEntity
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.Repository

interface StaffRepository : JpaRepository<StaffEntity, Long> {
interface StaffRepository : JpaRepository<StaffEntity, Long>, StaffRepositoryCustom {
fun findAllByLanguage(languageType: LanguageType): List<StaffEntity>
}

interface StaffRepositoryCustom {
fun findStaffAllLanguages(id: Long): Map<LanguageType, List<StaffEntity>>
}

@Repository
class StaffRepositoryCustomImpl(
private val queryFactory: JPAQueryFactory
) : StaffRepositoryCustom {
override fun findStaffAllLanguages(id: Long): Map<LanguageType, List<StaffEntity>> {
val staffs = queryFactory.selectFrom(staffEntity)
.where(
staffEntity.id.`in`(
JPAExpressions.select(
memberLanguageEntity.koreanId
).from(memberLanguageEntity)
.where(memberLanguageEntity.englishId.eq(id), memberLanguageEntity.type.eq(MemberType.STAFF)),
JPAExpressions.select(
memberLanguageEntity.englishId
).from(memberLanguageEntity)
.where(memberLanguageEntity.koreanId.eq(id), memberLanguageEntity.type.eq(MemberType.STAFF)),
Expressions.constant(id)
)
).leftJoin(mainImageEntity).on(mainImageEntity.id.eq(staffEntity.id))
.fetch()

return staffs.groupBy {
it.language
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.wafflestudio.csereal.core.member.dto

data class StaffLanguagesDto(
val ko: StaffDto?,
val en: StaffDto?
)
Loading

0 comments on commit 14c5e5d

Please sign in to comment.