Skip to content

Commit

Permalink
feat: course CR v2 api (#302)
Browse files Browse the repository at this point in the history
* feat: create, readAll course

* 리뷰 반영, formatting
  • Loading branch information
leeeryboy committed Aug 5, 2024
1 parent 14c5e5d commit 48389d5
Show file tree
Hide file tree
Showing 8 changed files with 163 additions and 86 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.wafflestudio.csereal.core.academics.api
package com.wafflestudio.csereal.core.academics.api.v1

import com.wafflestudio.csereal.common.aop.AuthenticatedStaff
import com.wafflestudio.csereal.common.enums.LanguageType
Expand All @@ -16,7 +16,7 @@ import org.springframework.web.bind.annotation.*
import org.springframework.web.multipart.MultipartFile

@RequestMapping("/api/v1/academics")
@RestController
@RestController("AcademicsControllerV1")
class AcademicsController(
private val academicsService: AcademicsService,
private val academicsSearchService: AcademicsSearchService
Expand Down Expand Up @@ -86,17 +86,6 @@ class AcademicsController(
) = academicsService.deleteAcademicsYearResponse(language, studentType, postType, year)

//교과목 정보
@AuthenticatedStaff
@PostMapping("/{studentType}/course")
fun createCourse(
@PathVariable studentType: String,
@Valid
@RequestPart("request")
request: CourseDto,
@RequestPart("attachments") attachments: List<MultipartFile>?
): ResponseEntity<CourseDto> {
return ResponseEntity.ok(academicsService.createCourse(studentType, request, attachments))
}

@GetMapping("/{studentType}/courses")
fun readAllCourses(
Expand All @@ -106,14 +95,6 @@ class AcademicsController(
return ResponseEntity.ok(academicsService.readAllCourses(language, studentType))
}

@GetMapping("/course")
fun readCourse(
@RequestParam(required = false, defaultValue = "ko") language: String,
@RequestParam name: String
): ResponseEntity<CourseDto> {
return ResponseEntity.ok(academicsService.readCourse(language, name))
}

@GetMapping("/undergraduate/degree-requirements")
fun readDegreeRequirements(
@RequestParam(required = false, defaultValue = "ko") language: String
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.wafflestudio.csereal.core.academics.api.v2

import com.wafflestudio.csereal.common.aop.AuthenticatedStaff
import com.wafflestudio.csereal.core.academics.dto.GroupedCourseDto
import com.wafflestudio.csereal.core.academics.service.AcademicsService
import jakarta.validation.Valid
import org.springframework.web.bind.annotation.*

@RequestMapping("/api/v2/academics")
@RestController
class AcademicsController(
private val academicsService: AcademicsService
) {
@AuthenticatedStaff
@PostMapping("/{studentType}/course")
fun createCourse(
@PathVariable studentType: String,
@Valid
@RequestBody
request: GroupedCourseDto
) = academicsService.createCourse(studentType, request)

@GetMapping("/{studentType}/courses")
fun readAllGroupedCourses(@PathVariable studentType: String): List<GroupedCourseDto> =
academicsService.readAllGroupedCourses(studentType)
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
package com.wafflestudio.csereal.core.academics.database

import com.wafflestudio.csereal.common.config.BaseTimeEntity
import com.wafflestudio.csereal.common.controller.AttachmentContentEntityType
import com.wafflestudio.csereal.common.enums.LanguageType
import com.wafflestudio.csereal.core.academics.dto.CourseDto
import com.wafflestudio.csereal.core.resource.attachment.database.AttachmentEntity
import jakarta.persistence.*

@Entity(name = "course")
class CourseEntity(
var isDeleted: Boolean = false,

@Enumerated(EnumType.STRING)
var studentType: AcademicsStudentType,

@Enumerated(EnumType.STRING)
Expand All @@ -20,30 +16,36 @@ class CourseEntity(
var code: String,
var name: String,
var credit: Int,
var grade: String,
var grade: Int,

@Column(columnDefinition = "mediumText")
var description: String?,

@OneToMany(mappedBy = "course", cascade = [CascadeType.ALL], orphanRemoval = true)
var attachments: MutableList<AttachmentEntity> = mutableListOf(),

@OneToOne(mappedBy = "course", cascade = [CascadeType.ALL], orphanRemoval = true)
var academicsSearch: AcademicsSearchEntity? = null

) : BaseTimeEntity(), AttachmentContentEntityType {
override fun bringAttachments() = attachments
) : BaseTimeEntity() {

companion object {
fun of(studentType: AcademicsStudentType, languageType: LanguageType, courseDto: CourseDto): CourseEntity {
fun of(
studentType: AcademicsStudentType,
languageType: LanguageType,
classification: String,
code: String,
name: String,
credit: Int,
grade: Int,
description: String?
): CourseEntity {
return CourseEntity(
studentType = studentType,
language = languageType,
classification = courseDto.classification,
code = courseDto.code,
name = courseDto.name,
credit = courseDto.credit,
grade = courseDto.grade,
description = courseDto.description
classification = classification,
code = code,
name = name,
credit = credit,
grade = grade,
description = description
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,45 @@ package com.wafflestudio.csereal.core.academics.database

import com.wafflestudio.csereal.common.enums.LanguageType
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.Query
import org.springframework.data.repository.query.Param

interface CourseRepository : JpaRepository<CourseEntity, Long> {
interface CourseProjection {
val code: String
val credit: Int
val grade: Int
val koName: String
val koDescription: String
val koClassification: String
val enName: String
val enDescription: String
val enClassification: String
}

fun findAllByLanguageAndStudentTypeOrderByNameAsc(
languageType: LanguageType,
studentType: AcademicsStudentType
): List<CourseEntity>
fun findByLanguageAndName(
languageType: LanguageType,
name: String
): CourseEntity

@Query(
"""
SELECT
c.code as code,
MAX(c.credit) as credit,
MAX(c.grade) as grade,
MAX(CASE WHEN c.language = 'KO' THEN c.name ELSE '' END) as koName,
MAX(CASE WHEN c.language = 'KO' THEN c.description ELSE '' END) as koDescription,
MAX(CASE WHEN c.language = 'KO' THEN c.classification ELSE '' END) as koClassification,
MAX(CASE WHEN c.language = 'EN' THEN c.name ELSE '' END) as enName,
MAX(CASE WHEN c.language = 'EN' THEN c.description ELSE '' END) as enDescription,
MAX(CASE WHEN c.language = 'EN' THEN c.classification ELSE '' END) as enClassification
FROM course c
WHERE c.studentType = :studentType
GROUP BY c.code
"""
)
fun findGroupedCourses(@Param("studentType") studentType: AcademicsStudentType): List<CourseProjection>

fun existsByCode(code: String): Boolean
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package com.wafflestudio.csereal.core.academics.dto

import com.wafflestudio.csereal.common.enums.LanguageType
import com.wafflestudio.csereal.core.academics.database.CourseEntity
import com.wafflestudio.csereal.core.resource.attachment.dto.AttachmentResponse

data class CourseDto(
val id: Long,
Expand All @@ -11,12 +10,11 @@ data class CourseDto(
val code: String,
val name: String,
val credit: Int,
val grade: String,
val description: String?,
val attachments: List<AttachmentResponse>?
val grade: Int,
val description: String?
) {
companion object {
fun of(entity: CourseEntity, attachmentResponses: List<AttachmentResponse>): CourseDto = entity.run {
fun of(entity: CourseEntity): CourseDto = entity.run {
CourseDto(
id = this.id,
language = LanguageType.makeLowercase(this.language),
Expand All @@ -25,8 +23,7 @@ data class CourseDto(
name = this.name,
credit = this.credit,
grade = this.grade,
description = this.description,
attachments = attachmentResponses
description = this.description
)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.wafflestudio.csereal.core.academics.dto

import com.wafflestudio.csereal.core.academics.database.CourseRepository

data class GroupedCourseDto(
val code: String,
val credit: Int,
val grade: Int,
val ko: SingleCourseDto,
val en: SingleCourseDto
)

data class SingleCourseDto(
val name: String,
val description: String,
val classification: String
)

object CourseMapper {
fun toGroupedCourseDTO(projection: CourseRepository.CourseProjection): GroupedCourseDto {
return GroupedCourseDto(
code = projection.code,
credit = projection.credit,
grade = projection.grade,
ko = SingleCourseDto(
name = projection.koName,
description = projection.koDescription,
classification = projection.koClassification
),
en = SingleCourseDto(
name = projection.enName,
description = projection.enDescription,
classification = projection.enClassification
)
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,11 @@ interface AcademicsService {
fun updateDegreeRequirements(language: String, request: UpdateSingleReq, newAttachments: List<MultipartFile>?)
fun createCourse(
studentType: String,
request: CourseDto,
attachments: List<MultipartFile>?
): CourseDto
request: GroupedCourseDto
)

fun readAllCourses(language: String, studentType: String): List<CourseDto>
fun readCourse(language: String, name: String): CourseDto
fun readAllGroupedCourses(studentType: String): List<GroupedCourseDto>
fun createScholarshipDetail(
studentType: String,
request: ScholarshipDto
Expand Down Expand Up @@ -275,28 +274,44 @@ class AcademicsServiceImpl(
@Transactional
override fun createCourse(
studentType: String,
request: CourseDto,
attachments: List<MultipartFile>?
): CourseDto {
val enumStudentType = makeStringToAcademicsStudentType(studentType)
val enumLanguageType = LanguageType.makeStringToLanguageType(request.language)
request: GroupedCourseDto
) {
if (courseRepository.existsByCode(request.code)) {
throw CserealException.Csereal409("해당 교과목 번호를 가지고 있는 엔티티가 이미 있습니다")
}

val newCourse = CourseEntity.of(enumStudentType, enumLanguageType, request)
val enumStudentType = makeStringToAcademicsStudentType(studentType)

if (attachments != null) {
attachmentService.uploadAllAttachments(newCourse, attachments)
}
val koCourse = CourseEntity.of(
enumStudentType,
LanguageType.KO,
request.ko.classification,
request.code,
request.ko.name,
request.credit,
request.grade,
request.ko.description
)
val enCourse = CourseEntity.of(
enumStudentType,
LanguageType.EN,
request.en.classification,
request.code,
request.en.name,
request.credit,
request.grade,
request.en.description
)

// create search data
newCourse.apply {
koCourse.apply {
academicsSearch = AcademicsSearchEntity.create(this)
}
courseRepository.save(newCourse)

val attachmentResponses =
attachmentService.createAttachmentResponses(newCourse.attachments)

return CourseDto.of(newCourse, attachmentResponses)
enCourse.apply {
academicsSearch = AcademicsSearchEntity.create(this)
}
courseRepository.save(koCourse)
courseRepository.save(enCourse)
}

@Transactional(readOnly = true)
Expand All @@ -308,21 +323,15 @@ class AcademicsServiceImpl(
enumLanguageType,
enumStudentType
).map {
val attachmentResponses =
attachmentService.createAttachmentResponses(it.attachments)

CourseDto.of(it, attachmentResponses)
CourseDto.of(it)
}
return courseDtoList
}

@Transactional(readOnly = true)
override fun readCourse(language: String, name: String): CourseDto {
val enumLanguageType = LanguageType.makeStringToLanguageType(language)
val course = courseRepository.findByLanguageAndName(enumLanguageType, name)
val attachmentResponses = attachmentService.createAttachmentResponses(course.attachments)

return CourseDto.of(course, attachmentResponses)
override fun readAllGroupedCourses(studentType: String): List<GroupedCourseDto> {
val enumStudentType = makeStringToAcademicsStudentType(studentType)
return courseRepository.findGroupedCourses(enumStudentType).map(CourseMapper::toGroupedCourseDTO)
}

@Transactional
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ 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.notice.database.NoticeEntity
import com.wafflestudio.csereal.core.research.database.LabEntity
Expand Down Expand Up @@ -214,11 +213,6 @@ class AttachmentServiceImpl(
attachment.academics = contentEntity
}

is CourseEntity -> {
contentEntity.attachments.add(attachment)
attachment.course = contentEntity
}

is ResearchEntity -> {
contentEntity.attachments.add(attachment)
attachment.research = contentEntity
Expand Down

0 comments on commit 48389d5

Please sign in to comment.