Skip to content

Commit 8f53fc6

Browse files
authored
Feat: Professor API 언어 통합 업데이트 (#304)
* refactor: move member search controller to v1 * feat: make a bit more query efficient * feat: change to language merged apis * fix: ktlint issue * fix: fix index columnlist
1 parent 1f02726 commit 8f53fc6

File tree

15 files changed

+338
-124
lines changed

15 files changed

+338
-124
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.wafflestudio.csereal.core.member.api.req
2+
3+
data class CreateProfessorLanguagesReqBody(
4+
val ko: CreateProfessorReqBody,
5+
val en: CreateProfessorReqBody
6+
)

src/main/kotlin/com/wafflestudio/csereal/core/member/api/req/CreateProfessorReqBody.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import com.wafflestudio.csereal.core.member.database.ProfessorStatus
44
import java.time.LocalDate
55

66
data class CreateProfessorReqBody(
7-
val language: String,
87
val name: String,
98
val status: ProfessorStatus,
109
val academicRank: String,
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.wafflestudio.csereal.core.member.api.req
2+
3+
data class ModifyProfessorLanguagesReqBody(
4+
val ko: ModifyProfessorReqBody,
5+
val en: ModifyProfessorReqBody
6+
)

src/main/kotlin/com/wafflestudio/csereal/core/member/api/req/ModifyProfessorReqBody.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import com.wafflestudio.csereal.core.member.database.ProfessorStatus
44
import java.time.LocalDate
55

66
data class ModifyProfessorReqBody(
7-
val language: String,
87
val name: String,
98
val status: ProfessorStatus,
109
val academicRank: String,

src/main/kotlin/com/wafflestudio/csereal/core/member/api/MemberSearchController.kt renamed to src/main/kotlin/com/wafflestudio/csereal/core/member/api/v1/MemberSearchController.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.wafflestudio.csereal.core.member.api
1+
package com.wafflestudio.csereal.core.member.api.v1
22

33
import com.wafflestudio.csereal.common.enums.LanguageType
44
import com.wafflestudio.csereal.core.member.service.MemberSearchService
@@ -8,6 +8,7 @@ import org.springframework.web.bind.annotation.GetMapping
88
import org.springframework.web.bind.annotation.RequestMapping
99
import org.springframework.web.bind.annotation.RequestParam
1010
import org.springframework.web.bind.annotation.RestController
11+
import kotlin.let
1112

1213
@RestController
1314
@RequestMapping("/api/v1/member/search")
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.wafflestudio.csereal.core.member.api.v1
2+
3+
import com.wafflestudio.csereal.core.member.dto.ProfessorDto
4+
import com.wafflestudio.csereal.core.member.dto.ProfessorPageDto
5+
import com.wafflestudio.csereal.core.member.dto.SimpleProfessorDto
6+
import com.wafflestudio.csereal.core.member.service.ProfessorService
7+
import org.springframework.http.ResponseEntity
8+
import org.springframework.web.bind.annotation.*
9+
10+
@Deprecated(message = "Use V2 API")
11+
@RequestMapping("/api/v1/professor")
12+
@RestController("ProfessorControllerV1")
13+
class ProfessorController(
14+
private val professorService: ProfessorService
15+
) {
16+
@GetMapping("/{professorId}")
17+
fun getProfessor(@PathVariable professorId: Long): ResponseEntity<ProfessorDto> {
18+
return ResponseEntity.ok(professorService.getProfessor(professorId))
19+
}
20+
21+
@GetMapping("/active")
22+
fun getActiveProfessors(
23+
@RequestParam(required = false, defaultValue = "ko") language: String
24+
): ResponseEntity<ProfessorPageDto> {
25+
return ResponseEntity.ok(professorService.getActiveProfessors(language))
26+
}
27+
28+
@GetMapping("/inactive")
29+
fun getInactiveProfessors(
30+
@RequestParam(required = false, defaultValue = "ko") language: String
31+
): ResponseEntity<List<SimpleProfessorDto>> {
32+
return ResponseEntity.ok(professorService.getInactiveProfessors(language))
33+
}
34+
}
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,29 @@
1-
package com.wafflestudio.csereal.core.member.api
1+
package com.wafflestudio.csereal.core.member.api.v2
22

33
import com.wafflestudio.csereal.common.aop.AuthenticatedStaff
4-
import com.wafflestudio.csereal.core.member.api.req.CreateProfessorReqBody
5-
import com.wafflestudio.csereal.core.member.api.req.ModifyProfessorReqBody
6-
import com.wafflestudio.csereal.core.member.dto.ProfessorDto
4+
import com.wafflestudio.csereal.core.member.api.req.CreateProfessorLanguagesReqBody
5+
import com.wafflestudio.csereal.core.member.api.req.ModifyProfessorLanguagesReqBody
6+
import com.wafflestudio.csereal.core.member.dto.ProfessorLanguagesDto
77
import com.wafflestudio.csereal.core.member.dto.ProfessorPageDto
88
import com.wafflestudio.csereal.core.member.dto.SimpleProfessorDto
99
import com.wafflestudio.csereal.core.member.service.ProfessorService
1010
import io.swagger.v3.oas.annotations.Parameter
11+
import jakarta.validation.constraints.Positive
1112
import org.springframework.http.ResponseEntity
1213
import org.springframework.web.bind.annotation.*
1314
import org.springframework.web.multipart.MultipartFile
1415

15-
@RequestMapping("/api/v1/professor")
16+
@RequestMapping("/api/v2/professor")
1617
@RestController
1718
class ProfessorController(
1819
private val professorService: ProfessorService
1920
) {
20-
21-
@AuthenticatedStaff
22-
@PostMapping
23-
fun createProfessor(
24-
@RequestPart("request") createProfessorRequest: CreateProfessorReqBody,
25-
@RequestPart("mainImage") mainImage: MultipartFile?
26-
): ProfessorDto {
27-
return professorService.createProfessor(createProfessorRequest, mainImage)
28-
}
29-
3021
@GetMapping("/{professorId}")
31-
fun getProfessor(@PathVariable professorId: Long): ResponseEntity<ProfessorDto> {
32-
return ResponseEntity.ok(professorService.getProfessor(professorId))
33-
}
22+
fun getProfessor(
23+
@PathVariable @Positive
24+
professorId: Long
25+
): ProfessorLanguagesDto =
26+
professorService.getProfessorLanguages(professorId)
3427

3528
@GetMapping("/active")
3629
fun getActiveProfessors(
@@ -47,24 +40,34 @@ class ProfessorController(
4740
}
4841

4942
@AuthenticatedStaff
50-
@PutMapping("/{professorId}")
43+
@PostMapping(consumes = ["multipart/form-data"])
44+
fun createProfessor(
45+
@RequestPart("request") requestBody: CreateProfessorLanguagesReqBody,
46+
@RequestPart("image") image: MultipartFile?
47+
): ProfessorLanguagesDto =
48+
professorService.createProfessorLanguages(requestBody, image)
49+
50+
@AuthenticatedStaff
51+
@PutMapping("/{koProfessorId}/{enProfessorId}", consumes = ["multipart/form-data"])
5152
fun updateProfessor(
52-
@PathVariable professorId: Long,
53-
@RequestPart("request") updateProfessorRequest: ModifyProfessorReqBody,
53+
@PathVariable @Positive
54+
koProfessorId: Long,
55+
@PathVariable @Positive
56+
enProfessorId: Long,
57+
@RequestPart("request") requestBody: ModifyProfessorLanguagesReqBody,
5458

5559
@Parameter(description = "image 교체할 경우 업로드. Request Body의 removeImage 관계없이 변경됨.")
5660
@RequestPart("newImage")
5761
newImage: MultipartFile?
58-
): ResponseEntity<ProfessorDto> {
59-
return ResponseEntity.ok(
60-
professorService.updateProfessor(professorId, updateProfessorRequest, newImage)
61-
)
62-
}
62+
): ProfessorLanguagesDto =
63+
professorService.updateProfessorLanguages(koProfessorId, enProfessorId, requestBody, newImage)
6364

6465
@AuthenticatedStaff
65-
@DeleteMapping("/{professorId}")
66-
fun deleteProfessor(@PathVariable professorId: Long): ResponseEntity<Any> {
67-
professorService.deleteProfessor(professorId)
68-
return ResponseEntity.ok().build()
69-
}
66+
@DeleteMapping("/{koProfessorId}/{enProfessorId}", consumes = ["multipart/form-data"])
67+
fun deleteProfessor(
68+
@PathVariable @Positive
69+
koProfessorId: Long,
70+
@PathVariable @Positive
71+
enProfessorId: Long
72+
) = professorService.deleteProfessorLanguages(koProfessorId, enProfessorId)
7073
}

src/main/kotlin/com/wafflestudio/csereal/core/member/database/MemberLanguageEntity.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@ import com.wafflestudio.csereal.core.member.type.MemberType
55
import jakarta.persistence.*
66

77
@Entity(name = "member_language")
8+
@Table(
9+
indexes = [
10+
Index(columnList = "type"),
11+
Index(columnList = "korean_id"),
12+
Index(columnList = "english_id")
13+
]
14+
)
815
class MemberLanguageEntity(
916
@Column(nullable = false)
1017
@Enumerated(EnumType.STRING)
Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,69 @@
11
package com.wafflestudio.csereal.core.member.database
22

3+
import com.querydsl.core.types.dsl.Expressions
4+
import com.querydsl.jpa.JPAExpressions
5+
import com.querydsl.jpa.impl.JPAQueryFactory
36
import com.wafflestudio.csereal.common.enums.LanguageType
7+
import com.wafflestudio.csereal.core.member.database.QCareerEntity.careerEntity
8+
import com.wafflestudio.csereal.core.member.database.QEducationEntity.educationEntity
9+
import com.wafflestudio.csereal.core.member.database.QMemberLanguageEntity.memberLanguageEntity
10+
import com.wafflestudio.csereal.core.member.database.QProfessorEntity.professorEntity
11+
import com.wafflestudio.csereal.core.member.database.QResearchAreaEntity.researchAreaEntity
12+
import com.wafflestudio.csereal.core.member.type.MemberType
13+
import com.wafflestudio.csereal.core.research.database.QLabEntity.labEntity
14+
import com.wafflestudio.csereal.core.resource.mainImage.database.QMainImageEntity.mainImageEntity
415
import org.springframework.data.jpa.repository.JpaRepository
16+
import org.springframework.stereotype.Repository
517

6-
interface ProfessorRepository : JpaRepository<ProfessorEntity, Long> {
18+
interface ProfessorRepository : JpaRepository<ProfessorEntity, Long>, ProfessorRepositoryCustom {
719
fun findByLanguageAndStatus(
820
languageType: LanguageType,
921
status: ProfessorStatus
1022
): List<ProfessorEntity>
23+
1124
fun findByLanguageAndStatusNot(
1225
languageType: LanguageType,
1326
status: ProfessorStatus
1427
): List<ProfessorEntity>
1528
}
29+
30+
interface ProfessorRepositoryCustom {
31+
fun findProfessorAllLanguages(id: Long): Map<LanguageType, List<ProfessorEntity>>
32+
}
33+
34+
@Repository
35+
class ProfessorRepositoryCustomImpl(
36+
private val queryFactory: JPAQueryFactory
37+
) : ProfessorRepositoryCustom {
38+
override fun findProfessorAllLanguages(id: Long): Map<LanguageType, List<ProfessorEntity>> {
39+
val professors = queryFactory.selectFrom(professorEntity)
40+
.where(
41+
professorEntity.id.`in`(
42+
JPAExpressions.select(
43+
memberLanguageEntity.koreanId
44+
).from(memberLanguageEntity)
45+
.where(
46+
memberLanguageEntity.englishId.eq(id),
47+
memberLanguageEntity.type.eq(MemberType.PROFESSOR)
48+
),
49+
JPAExpressions.select(
50+
memberLanguageEntity.englishId
51+
).from(memberLanguageEntity)
52+
.where(
53+
memberLanguageEntity.koreanId.eq(id),
54+
memberLanguageEntity.type.eq(MemberType.PROFESSOR)
55+
),
56+
Expressions.constant(id)
57+
)
58+
).leftJoin(mainImageEntity).fetchJoin()
59+
.leftJoin(labEntity).fetchJoin()
60+
.leftJoin(careerEntity).on(careerEntity.professor.eq(professorEntity))
61+
.leftJoin(researchAreaEntity).on(researchAreaEntity.professor.eq(professorEntity))
62+
.leftJoin(educationEntity).on(educationEntity.professor.eq(professorEntity))
63+
.fetch()
64+
65+
return professors.groupBy {
66+
it.language
67+
}
68+
}
69+
}

src/main/kotlin/com/wafflestudio/csereal/core/member/database/StaffRepository.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import com.querydsl.jpa.impl.JPAQueryFactory
66
import com.wafflestudio.csereal.common.enums.LanguageType
77
import com.wafflestudio.csereal.core.member.database.QMemberLanguageEntity.memberLanguageEntity
88
import com.wafflestudio.csereal.core.member.database.QStaffEntity.staffEntity
9+
import com.wafflestudio.csereal.core.member.database.QTaskEntity.taskEntity
910
import com.wafflestudio.csereal.core.member.type.MemberType
1011
import com.wafflestudio.csereal.core.resource.mainImage.database.QMainImageEntity.mainImageEntity
1112
import org.springframework.data.jpa.repository.JpaRepository
@@ -37,7 +38,8 @@ class StaffRepositoryCustomImpl(
3738
.where(memberLanguageEntity.koreanId.eq(id), memberLanguageEntity.type.eq(MemberType.STAFF)),
3839
Expressions.constant(id)
3940
)
40-
).leftJoin(mainImageEntity).on(mainImageEntity.id.eq(staffEntity.id))
41+
).leftJoin(mainImageEntity).fetchJoin()
42+
.leftJoin(taskEntity).on(taskEntity.staff.eq(staffEntity))
4143
.fetch()
4244

4345
return staffs.groupBy {

0 commit comments

Comments
 (0)