Skip to content

Commit f3dde77

Browse files
authored
Merge pull request #119 from TwooTwoo/refactor/mentor-task
feat: 멘토 기준 할일 수정, 삭제 기능 구현
2 parents 1897ae0 + 8521864 commit f3dde77

7 files changed

Lines changed: 136 additions & 18 deletions

File tree

src/main/kotlin/goodspace/bllsoneshot/global/exception/ExceptionMessage.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,5 +38,6 @@ enum class ExceptionMessage(
3838
GENERAL_COMMENT_TOO_LONG("멘토의 총평은 200자를 초과할 수 없습니다."),
3939
GENERAL_COMMENT_REQUIRED("최종 저장 시 멘토의 총평은 필수입니다."),
4040
PROOF_SHOT_NOT_FOUND("해당 인증 사진을 찾을 수 없습니다."),
41-
FEEDBACK_CONTENT_BLANK("피드백 내용이 비어 있습니다.")
41+
FEEDBACK_CONTENT_BLANK("피드백 내용이 비어 있습니다."),
42+
TASK_NOT_CREATED_BY_MENTOR("멘토가 등록한 할 일이 아닙니다.")
4243
}

src/main/kotlin/goodspace/bllsoneshot/mentor/controller/MentorTaskController.kt

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,15 @@ import goodspace.bllsoneshot.global.security.userId
55
import goodspace.bllsoneshot.mentor.dto.request.MentorFeedbackRequest
66
import goodspace.bllsoneshot.mentor.dto.request.MentorTaskUpdateRequest
77
import goodspace.bllsoneshot.mentor.dto.response.MentorTaskDetailResponse
8+
import goodspace.bllsoneshot.mentor.dto.response.MentorTaskEditResponse
89
import goodspace.bllsoneshot.mentor.service.MentorTaskService
910
import io.swagger.v3.oas.annotations.Operation
1011
import io.swagger.v3.oas.annotations.tags.Tag
1112
import jakarta.validation.Valid
12-
import java.security.Principal
1313
import org.springframework.http.ResponseEntity
1414
import org.springframework.security.access.prepost.PreAuthorize
15-
import org.springframework.web.bind.annotation.GetMapping
16-
import org.springframework.web.bind.annotation.PathVariable
17-
import org.springframework.web.bind.annotation.DeleteMapping
18-
import org.springframework.web.bind.annotation.PutMapping
19-
import org.springframework.web.bind.annotation.RequestBody
20-
import org.springframework.web.bind.annotation.RequestMapping
21-
import org.springframework.web.bind.annotation.RestController
15+
import org.springframework.web.bind.annotation.*
16+
import java.security.Principal
2217

2318
@Tag(name = "Mentor Task", description = "멘토 - 할 일 관리")
2419
@RestController
@@ -123,19 +118,55 @@ class MentorTaskController(
123118
@Operation(
124119
summary = "멘토 할 일 수정",
125120
description = """
126-
멘토가 할 일의 이름과 목표 시간을 수정합니다.
121+
멘토가 담당 멘티의 할 일을 수정합니다.
122+
멘토가 등록한 할 일뿐 아니라 멘티가 등록한 할 일도 수정할 수 있습니다.
127123
128-
요청 필드:
129-
taskName: 할 일 이름 (필수)
124+
[요청]
125+
subject: 과목 (KOREAN, ENGLISH, MATH)
126+
taskName: 할 일 이름 (필수, 최대 50자)
130127
goalMinutes: 목표 시간 (분, 0 이상)
128+
worksheets: 학습 자료 목록 (기존 자료를 전체 교체합니다)
129+
columnLinks: 칼럼 링크 목록 (기존 링크를 전체 교체합니다)
130+
131+
[응답]
132+
subject: 과목
133+
date: 날짜
134+
taskName: 할 일 이름
135+
goalMinutes: 목표 시간 (분)
136+
worksheets: 학습 자료 PDF 파일
137+
columnLinks: 학습 자료 칼럼 링크
138+
completed: 멘티가 완료했는지 여부
131139
"""
132140
)
133141
fun updateTask(
134142
@PathVariable taskId: Long,
135143
@Valid @RequestBody request: MentorTaskUpdateRequest,
136144
principal: Principal
145+
): ResponseEntity<MentorTaskEditResponse> {
146+
val response = mentorTaskService.updateTask(principal.userId, taskId, request)
147+
return ResponseEntity.ok(response)
148+
}
149+
150+
@DeleteMapping("/{taskId}")
151+
@Operation(
152+
summary = "멘토 할 일 삭제",
153+
description = """
154+
멘토가 본인이 등록한 할 일을 삭제합니다.
155+
멘토가 등록한 할 일(createdBy = ROLE_MENTOR)만 삭제할 수 있습니다.
156+
멘티가 등록한 할 일은 삭제할 수 없습니다.
157+
158+
[요청]
159+
taskId
160+
161+
[응답]
162+
204 NO CONTENT
163+
"""
164+
)
165+
fun deleteTask(
166+
@PathVariable taskId: Long,
167+
principal: Principal
137168
): ResponseEntity<Void> {
138-
mentorTaskService.updateTask(principal.userId, taskId, request)
169+
mentorTaskService.deleteTask(principal.userId, taskId)
139170
return NO_CONTENT
140171
}
141172
}
Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,22 @@
11
package goodspace.bllsoneshot.mentor.dto.request
22

3+
import goodspace.bllsoneshot.entity.assignment.Subject
4+
import goodspace.bllsoneshot.task.dto.request.ColumnLinkCreateRequest
5+
import goodspace.bllsoneshot.task.dto.request.WorksheetCreateRequest
36
import jakarta.validation.constraints.NotBlank
47
import jakarta.validation.constraints.PositiveOrZero
58
import jakarta.validation.constraints.Size
69

710
data class MentorTaskUpdateRequest(
11+
val subject: Subject,
12+
813
@field:NotBlank(message = "할 일 이름이 비어 있습니다.")
914
@field:Size(max = 50, message = "할 일 이름은 50자를 초과할 수 없습니다.")
1015
val taskName: String,
1116

1217
@field:PositiveOrZero(message = "목표 시간은 0 이상이어야 합니다.")
13-
val goalMinutes: Int
18+
val goalMinutes: Int,
19+
20+
val worksheets: List<WorksheetCreateRequest> = emptyList(),
21+
val columnLinks: List<ColumnLinkCreateRequest> = emptyList()
1422
)
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package goodspace.bllsoneshot.mentor.dto.response
2+
3+
import goodspace.bllsoneshot.entity.assignment.Subject
4+
import goodspace.bllsoneshot.task.dto.response.feedback.ColumnLinkResponse
5+
import goodspace.bllsoneshot.task.dto.response.feedback.WorksheetResponse
6+
import java.time.LocalDate
7+
8+
data class MentorTaskEditResponse(
9+
val subject: Subject,
10+
val date: LocalDate?,
11+
val taskName: String,
12+
val goalMinutes: Int,
13+
val worksheets: List<WorksheetResponse>,
14+
val columnLinks: List<ColumnLinkResponse>,
15+
val completed: Boolean,
16+
)

src/main/kotlin/goodspace/bllsoneshot/mentor/mapper/MentorTaskMapper.kt

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,34 @@ package goodspace.bllsoneshot.mentor.mapper
33
import goodspace.bllsoneshot.entity.assignment.ProofShot
44
import goodspace.bllsoneshot.entity.assignment.Task
55
import goodspace.bllsoneshot.mentor.dto.response.MentorTaskDetailResponse
6+
import goodspace.bllsoneshot.mentor.dto.response.MentorTaskEditResponse
67
import goodspace.bllsoneshot.task.dto.response.feedback.ProofShotResponse
8+
import goodspace.bllsoneshot.task.mapper.ColumnLinkMapper
79
import goodspace.bllsoneshot.task.mapper.FeedbackMapper
810
import goodspace.bllsoneshot.task.mapper.QuestionMapper
11+
import goodspace.bllsoneshot.task.mapper.WorksheetMapper
912
import org.springframework.stereotype.Component
1013

1114
@Component
1215
class MentorTaskMapper(
1316
private val questionMapper: QuestionMapper,
14-
private val feedbackMapper: FeedbackMapper
17+
private val feedbackMapper: FeedbackMapper,
18+
private val worksheetMapper: WorksheetMapper,
19+
private val columnLinkMapper: ColumnLinkMapper
1520
) {
1621

22+
fun mapToEdit(task: Task): MentorTaskEditResponse {
23+
return MentorTaskEditResponse(
24+
subject = task.subject,
25+
date = task.date,
26+
taskName = task.name,
27+
goalMinutes = task.goalMinutes,
28+
completed = task.completed,
29+
worksheets = task.worksheets.map { worksheetMapper.map(it) },
30+
columnLinks = task.columnLinks.map { columnLinkMapper.map(it) }
31+
)
32+
}
33+
1734
fun mapToDetail(task: Task): MentorTaskDetailResponse {
1835
return MentorTaskDetailResponse(
1936
taskId = task.id!!,

src/main/kotlin/goodspace/bllsoneshot/mentor/service/MentorTaskService.kt

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
11
package goodspace.bllsoneshot.mentor.service
22

33
import goodspace.bllsoneshot.entity.assignment.*
4+
import goodspace.bllsoneshot.entity.user.UserRole
45
import goodspace.bllsoneshot.global.exception.ExceptionMessage.*
56
import goodspace.bllsoneshot.mentor.dto.request.MentorFeedbackRequest
67
import goodspace.bllsoneshot.mentor.dto.request.MentorTaskUpdateRequest
78
import goodspace.bllsoneshot.mentor.dto.response.MentorTaskDetailResponse
9+
import goodspace.bllsoneshot.mentor.dto.response.MentorTaskEditResponse
810
import goodspace.bllsoneshot.mentor.mapper.MentorTaskMapper
11+
import goodspace.bllsoneshot.repository.file.FileRepository
912
import goodspace.bllsoneshot.repository.task.TaskRepository
1013
import org.springframework.stereotype.Service
1114
import org.springframework.transaction.annotation.Transactional
1215

1316
@Service
1417
class MentorTaskService(
1518
private val taskRepository: TaskRepository,
19+
private val fileRepository: FileRepository,
1620
private val mentorTaskMapper: MentorTaskMapper
1721
) {
1822

@@ -54,12 +58,26 @@ class MentorTaskService(
5458
}
5559

5660
@Transactional
57-
fun updateTask(mentorId: Long, taskId: Long, request: MentorTaskUpdateRequest) {
61+
fun updateTask(mentorId: Long, taskId: Long, request: MentorTaskUpdateRequest): MentorTaskEditResponse {
5862
val task = findTaskWithDetails(taskId)
5963
validateMentorAccess(mentorId, task)
6064

65+
task.subject = request.subject
6166
task.name = request.taskName
6267
task.goalMinutes = request.goalMinutes
68+
replaceWorksheets(task, request)
69+
replaceColumnLinks(task, request)
70+
71+
return mentorTaskMapper.mapToEdit(task)
72+
}
73+
74+
@Transactional
75+
fun deleteTask(mentorId: Long, taskId: Long) {
76+
val task = findTaskWithDetails(taskId)
77+
validateMentorAccess(mentorId, task)
78+
validateCreatedByMentor(task)
79+
80+
taskRepository.delete(task)
6381
}
6482

6583
// ── 조회 ────────────────────────────────────────────
@@ -75,6 +93,33 @@ class MentorTaskService(
7593
check(task.mentee.mentor?.id == mentorId) { MENTEE_ACCESS_DENIED.message }
7694
}
7795

96+
private fun validateCreatedByMentor(task: Task) {
97+
check(task.createdBy == UserRole.ROLE_MENTOR) { TASK_NOT_CREATED_BY_MENTOR.message }
98+
}
99+
100+
// ── 학습 자료 · 칼럼 링크 교체 ──────────────────────
101+
102+
private fun replaceWorksheets(task: Task, request: MentorTaskUpdateRequest) {
103+
task.worksheets.clear()
104+
task.worksheets.addAll(
105+
request.worksheets
106+
.mapNotNull { it.fileId }
107+
.mapNotNull { fileId ->
108+
fileRepository.findById(fileId).orElse(null)
109+
?.let { file -> Worksheet(task, file) }
110+
}
111+
)
112+
}
113+
114+
private fun replaceColumnLinks(task: Task, request: MentorTaskUpdateRequest) {
115+
task.columnLinks.clear()
116+
task.columnLinks.addAll(
117+
request.columnLinks
118+
.mapNotNull { it.link?.takeIf { link -> link.isNotBlank() } }
119+
.map { link -> ColumnLink(task, link) }
120+
)
121+
}
122+
78123
private fun validateGeneralCommentLength(generalComment: String?) {
79124
if (generalComment != null) {
80125
require(generalComment.length <= MAX_GENERAL_COMMENT_LENGTH) {

src/main/kotlin/goodspace/bllsoneshot/task/service/TaskService.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -305,9 +305,9 @@ class TaskService(
305305

306306
private fun validateTaskOwnership(
307307
task: Task,
308-
menteeId: Long
308+
userId: Long
309309
) {
310-
check(task.mentee.id == menteeId) { TASK_ACCESS_DENIED.message }
310+
check(task.mentee.id == userId) { TASK_ACCESS_DENIED.message }
311311
}
312312

313313
private fun validateHasFeedback(task: Task) {

0 commit comments

Comments
 (0)