diff --git a/build.gradle b/build.gradle index 1abce634..d56a53eb 100644 --- a/build.gradle +++ b/build.gradle @@ -50,18 +50,20 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' - implementation("io.jsonwebtoken:jjwt-api:0.11.5") + implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.2.0' + implementation 'io.jsonwebtoken:jjwt-api:0.11.5' compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' runtimeOnly 'com.h2database:h2' - runtimeOnly("io.jsonwebtoken:jjwt-impl:0.11.5") - runtimeOnly("io.jsonwebtoken:jjwt-jackson:0.11.5") + runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5' + runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5' testImplementation 'com.h2database:h2:2.1.214' testImplementation 'org.springframework.security:spring-security-test' testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc' testImplementation 'org.springframework.boot:spring-boot-starter-test' + testImplementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter-test:2.2.0' testImplementation 'com.h2database:h2' asciidoctorExtensions 'org.springframework.restdocs:spring-restdocs-asciidoctor' } diff --git a/src/docs/asciidoc/ohdab.adoc b/src/docs/asciidoc/ohdab.adoc index 35ec9a0f..f474782e 100644 --- a/src/docs/asciidoc/ohdab.adoc +++ b/src/docs/asciidoc/ohdab.adoc @@ -17,6 +17,16 @@ include::{snippets}/members/join/http-request.adoc[] include::{snippets}/members/join/http-response.adoc[] +=== 회원탈퇴 + +==== Request + +include::{snippets}/members/withdrawl/http-request.adoc[] + +==== Response + +include::{snippets}/members/withdrawl/http-response.adoc[] + === 로그인 ==== Request @@ -25,7 +35,7 @@ include::{snippets}/members/login/http-request.adoc[] ==== Response -include::{snippets}/members/login/http-response.adoc +include::{snippets}/members/login/http-response.adoc[] === 선생님 목록 조회 @@ -57,3 +67,148 @@ include::{snippets}/members/teachers/expulsion/{teacher-id}/http-request.adoc[] include::{snippets}/members/teachers/expulsion/{teacher-id}/http-response.adoc[] +== MistakeNote + +=== 교재 상세조회(전체 학생에 대한 오답노트 조회) + +==== Request + +include::{snippets}/mistake_note/getAllMistakeNoteInfo/http-request.adoc[] + +==== Response + +include::{snippets}/mistake_note/getAllMistakeNoteInfo/http-response.adoc[] + +=== 학생별 N번 틀린 문제 문자열 출력 + +==== Request + +include::{snippets}/mistake_note/getNumberWrongNTimes/http-request.adoc[] + +==== Response + +include::{snippets}/mistake_note/getNumberWrongNTimes/http-response.adoc[] + +=== 학생별 오답노트 조회 + +==== Request + +include::{snippets}/mistake_note/getMistakeNoteInfoByStudent/http-request.adoc[] + +==== Response + +include::{snippets}/mistake_note/getMistakeNoteInfoByStudent/http-response.adoc[] + +=== 오답 기록하기 + +==== Request + +include::{snippets}/mistake_note/saveMistakeNoteInfo/http-request.adoc[] + +==== Response + +include::{snippets}/mistake_note/saveMistakeNoteInfo/http-response.adoc[] + +== Classroom + +=== 반 추가 + +==== Request + +include::{snippets}/classrooms/enrollment/http-request.adoc[] + +==== Response + +include::{snippets}/classrooms/enrollment/http-response.adoc[] + +=== 반 목록 조회 + +==== Request + +include::{snippets}/classrooms/http-request.adoc[] + +==== Response + +include::{snippets}/classrooms/http-response.adoc[] + +=== 반 상세 조회 + +==== Request + +include::{snippets}/classrooms/{classroom-id}/http-request.adoc[] + +==== Response + +include::{snippets}/classrooms/{classroom-id}/http-response.adoc[] + +=== 반 정보 수정 + +==== Request + +include::{snippets}/classrooms/info/{classroom-id}/http-request.adoc[] + +==== Response + +include::{snippets}/classrooms/info/{classroom-id}/http-response.adoc[] + +=== 반 삭제 + +==== Request + +include::{snippets}/classrooms/expulsion/{classroom-id}/http-request.adoc[] + +==== Response + +include::{snippets}/classrooms/expulsion/{classroom-id}/http-response.adoc[] + +=== 학생 추가 + +==== Request + +include::{snippets}/classrooms/addStudent/http-request.adoc[] + +==== Response + +include::{snippets}/classrooms/addStudent/http-response.adoc[] + +=== 학생 삭제 + +==== Request + +include::{snippets}/classrooms/deleteStudent/http-request.adoc[] + +==== Response + +include::{snippets}/classrooms/deleteStudent/http-response.adoc[] + +=== 교재 목록 조회 + +==== Request + +include::{snippets}/classrooms/{classroom-id}/workbooks/http-request.adoc[] + +==== Response + +include::{snippets}/classrooms/{classroom-id}/workbooks/http-response.adoc[] + +=== 교재 추가 + +==== Request + +include::{snippets}/classrooms/{classroom-id}/addWorkbooks/http-request.adoc[] + +==== Response + +include::{snippets}/classrooms/{classroom-id}/addWorkbooks/http-response.adoc[] + +=== 교재 정보 수정 + +==== Request + +include::{snippets}/classrooms/workbooks/info/{workbook-id}/http-request.adoc[] + +==== Response + +include::{snippets}/classrooms/workbooks/info/{workbook-id}/http-response.adoc[] + + diff --git a/src/main/java/com/ohdab/classroom/controller/ClassroomController.java b/src/main/java/com/ohdab/classroom/controller/ClassroomController.java new file mode 100644 index 00000000..926e278c --- /dev/null +++ b/src/main/java/com/ohdab/classroom/controller/ClassroomController.java @@ -0,0 +1,133 @@ +package com.ohdab.classroom.controller; + +import static com.ohdab.classroom.service.dto.ClassroomDetailDto.ClassroomDetailDtoResponse; +import static com.ohdab.classroom.service.dto.ClassroomUpdateDto.ClassroomUpdateDtoRequest; + +import com.ohdab.classroom.controller.mapper.ClassroomMapper; +import com.ohdab.classroom.controller.request.AddClassroomReq; +import com.ohdab.classroom.controller.request.AddStudentReq; +import com.ohdab.classroom.controller.request.AddWorkbookReq; +import com.ohdab.classroom.controller.request.UpdateClassroomReq; +import com.ohdab.classroom.controller.request.UpdateWorkbookInfoReq; +import com.ohdab.classroom.controller.response.*; +import com.ohdab.classroom.service.dto.ClassroomAddWorkbookDto; +import com.ohdab.classroom.service.dto.ClassroomDto; +import com.ohdab.classroom.service.dto.ClassroomWorkbookDto; +import com.ohdab.classroom.service.dto.ClassroomWorkbookUpdateDto; +import com.ohdab.classroom.service.usecase.*; +import com.ohdab.member.controller.response.DeleteStudentRes; +import java.util.List; +import javax.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/classrooms") +public class ClassroomController { + + private final AddClassroomUsecase addClassroomUsecase; + private final FindClassroomListUsecase findClassroomListUsecase; + private final FindClassroomDetailUsecase findClassroomDetailUsecase; + private final UpdateClassroomInfoUsecase updateClassroomInfoUsecase; + private final DeleteClassroomUsecase deleteClassroomUsecase; + private final DeleteStudentUsecase deleteStudentUsecase; + private final GetWorkbookListUsecase getWorkbookListUsecase; + private final AddWorkbookUsecase addWorkbookUsecase; + private final UpdateWorkbookInfoUsecase updateWorkbookInfoUsecase; + private final AddStudentUsecase addStudentUsecase; + + @PostMapping("/enrollment") + public ResponseEntity addClassroom( + @Valid @RequestBody AddClassroomReq addClassroomReq) { + ClassroomDto.Request classroomReqDto = + ClassroomMapper.classroomReqToClassroomDtoRequest(addClassroomReq); + addClassroomUsecase.addClassroom(classroomReqDto); + return ResponseEntity.ok(ClassroomMapper.createClassRoomRes()); + } + + @GetMapping("") + public ResponseEntity getClassroomListByTeacherId( + @RequestParam(name = "teacherId") long teacherId) { + List responses = + findClassroomListUsecase.findClassroomListByTeacherId(teacherId); + return ResponseEntity.ok(ClassroomMapper.classroomDtoListToClassroomResList(responses)); + } + + @GetMapping("/{classroom-id}") + public ResponseEntity getClassroomDetailById( + @PathVariable("classroom-id") long id) { + ClassroomDetailDtoResponse classroomDetail = + findClassroomDetailUsecase.getClassroomDetailById(id); + ClassroomDetailRes classroomDetailRes = + ClassroomMapper.ClassroomDetailToClassroomDetailRes(classroomDetail); + return ResponseEntity.ok(classroomDetailRes); + } + + @PatchMapping("/info/{classroom-id}") + public ResponseEntity updateClassroom( + @PathVariable(name = "classroom-id") long classroomId, + @RequestBody @Valid UpdateClassroomReq request) { + ClassroomUpdateDtoRequest classroomUpdateDto = + ClassroomMapper.classroomUpdateDtoReqToClassroomUpdateDtoRequest( + classroomId, request); + updateClassroomInfoUsecase.updateClassroomInfo(classroomUpdateDto); + return ResponseEntity.ok(UpdateClassroomRes.builder().message("반 정보 수정 성공").build()); + } + + @DeleteMapping("/expulsion/{classroom-id}") + public ResponseEntity deleteClassroom( + @PathVariable(name = "classroom-id") long classroomId) { + deleteClassroomUsecase.deleteClassroomById(classroomId); + return ResponseEntity.ok(DeleteClassroomRes.builder().message("반 삭제 성공").build()); + } + + @PatchMapping("/{classroom-id}/expulsion/students/{student-id}") + public ResponseEntity deleteStudent( + @PathVariable("classroom-id") long classroomId, + @PathVariable("student-id") long studentId) { + deleteStudentUsecase.deleteStudent(classroomId, studentId); + return ResponseEntity.ok(DeleteStudentRes.builder().message("학생을 삭제하였습니다.").build()); + } + + @GetMapping("/{classroom-id}/workbooks") + public ResponseEntity getWorkbookListByClassroomId( + @PathVariable(name = "classroom-id") long classroomId) { + List classroomWorkbookDtoList = + getWorkbookListUsecase.getWorkbookListByClassroomId(classroomId); + return ResponseEntity.ok( + ClassroomMapper.classroomWorkbookDtoListToResponseList(classroomWorkbookDtoList)); + } + + @PostMapping("/{classroom-id}/workbooks") + public ResponseEntity getWorkbookListByClassroomId( + @PathVariable(name = "classroom-id") long classroomId, + @RequestBody @Valid AddWorkbookReq addWorkbookReq) { + ClassroomAddWorkbookDto.Request addWorkbookDto = + ClassroomMapper.addWorkbookRequestToDto(addWorkbookReq); + addWorkbookUsecase.addWorkbookByClassroomId(classroomId, addWorkbookDto); + return ResponseEntity.ok( + AddWorkbookRes.builder().message("해당 반에 교재 및 오답노트가 추가되었습니다.").build()); + } + + @PatchMapping("/workbooks/info/{workbook-id}") + public ResponseEntity updateWorkInfobook( + @PathVariable(name = "workbook-id") long workbookId, + UpdateWorkbookInfoReq updateWorkbookInfoReq) { + ClassroomWorkbookUpdateDto.Request workbookUpdateDtoReq = + ClassroomMapper.updateWorkbookRequestToDto(workbookId, updateWorkbookInfoReq); + updateWorkbookInfoUsecase.updateWorkbookInfo(workbookUpdateDtoReq); + return ResponseEntity.ok( + UpdateWorkbookInfoRes.builder().message("교재 정보가 수정 되었습니다.").build()); + } + + @PostMapping("/{classroom-id}/students/enrollment") + public ResponseEntity addStudent( + @PathVariable(name = "classroom-id") long classroomId, + @RequestBody @Valid AddStudentReq addStudentReq) { + addStudentUsecase.addStudent( + ClassroomMapper.toAddStudentDtoRequest(classroomId, addStudentReq)); + return ResponseEntity.ok(AddStudentRes.builder().message("해당 반에 학생이 추가되었습니다.").build()); + } +} diff --git a/src/main/java/com/ohdab/classroom/controller/mapper/ClassroomMapper.java b/src/main/java/com/ohdab/classroom/controller/mapper/ClassroomMapper.java new file mode 100644 index 00000000..e954e25d --- /dev/null +++ b/src/main/java/com/ohdab/classroom/controller/mapper/ClassroomMapper.java @@ -0,0 +1,130 @@ +package com.ohdab.classroom.controller.mapper; + +import static com.ohdab.classroom.service.dto.ClassroomDetailDto.ClassroomDetailDtoResponse; +import static com.ohdab.classroom.service.dto.ClassroomUpdateDto.ClassroomUpdateDtoRequest; + +import com.ohdab.classroom.controller.request.AddClassroomReq; +import com.ohdab.classroom.controller.request.AddStudentReq; +import com.ohdab.classroom.controller.request.AddWorkbookReq; +import com.ohdab.classroom.controller.request.UpdateClassroomReq; +import com.ohdab.classroom.controller.request.UpdateWorkbookInfoReq; +import com.ohdab.classroom.controller.response.AddClassroomRes; +import com.ohdab.classroom.controller.response.ClassroomDetailRes; +import com.ohdab.classroom.controller.response.ClassroomResList; +import com.ohdab.classroom.controller.response.ClassroomWorkbookListRes; +import com.ohdab.classroom.service.dto.AddStudentDto; +import com.ohdab.classroom.service.dto.ClassroomAddWorkbookDto; +import com.ohdab.classroom.service.dto.ClassroomAddWorkbookDto.Request; +import com.ohdab.classroom.service.dto.ClassroomDto; +import com.ohdab.classroom.service.dto.ClassroomWorkbookDto.Response; +import com.ohdab.classroom.service.dto.ClassroomWorkbookUpdateDto; +import java.util.List; +import java.util.stream.Collectors; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class ClassroomMapper { + public static ClassroomDto.Request classroomReqToClassroomDtoRequest( + AddClassroomReq addClassroomReq) { + + return ClassroomDto.Request.builder() + .info( + ClassroomDto.Info.builder() + .name(addClassroomReq.getName()) + .description(addClassroomReq.getDescription()) + .grade(addClassroomReq.getGrade()) + .build()) + .teacherId(addClassroomReq.getTeacherId()) + .build(); + } + + public static AddClassroomRes createClassRoomRes() { + return AddClassroomRes.builder().message("반이 추가되었습니다.").build(); + } + + public static ClassroomResList classroomDtoListToClassroomResList( + List classroomDtoList) { + return ClassroomResList.builder() + .classroomInfoList( + classroomDtoList.stream() + .map( + classroomDto -> + ClassroomResList.ClassroomInfo.builder() + .id(classroomDto.getId()) + .name(classroomDto.getInfo().getName()) + .description( + classroomDto + .getInfo() + .getDescription()) + .grade(classroomDto.getInfo().getGrade()) + .build()) + .collect(Collectors.toList())) + .build(); + } + + public static ClassroomDetailRes ClassroomDetailToClassroomDetailRes( + ClassroomDetailDtoResponse detailDto) { + return ClassroomDetailRes.builder() + .id(detailDto.getClassroomId()) + .teacherId(detailDto.getTeacherId()) + .name(detailDto.getInfo().getName()) + .description(detailDto.getInfo().getDescription()) + .grade(detailDto.getInfo().getGrade()) + .studentIds(detailDto.getStudentIds()) + .workbookIds(detailDto.getWorkbookIds()) + .build(); + } + + public static ClassroomUpdateDtoRequest classroomUpdateDtoReqToClassroomUpdateDtoRequest( + long classroomId, UpdateClassroomReq request) { + return ClassroomUpdateDtoRequest.builder() + .classroomId(classroomId) + .name(request.getName()) + .description(request.getDescription()) + .grade(request.getGrade()) + .build(); + } + + public static ClassroomWorkbookListRes classroomWorkbookDtoListToResponseList( + List classroomWorkbookDtoList) { + return ClassroomWorkbookListRes.builder() + .workbookList( + classroomWorkbookDtoList.stream() + .map( + w -> + ClassroomWorkbookListRes.WorkbookInfo.builder() + .id(w.getId()) + .name(w.getName()) + .createdAt(w.getCreatedAt().toLocalDate()) + .build()) + .collect(Collectors.toList())) + .build(); + } + + public static Request addWorkbookRequestToDto(AddWorkbookReq addWorkbookReq) { + return ClassroomAddWorkbookDto.Request.builder() + .name(addWorkbookReq.getName()) + .description(addWorkbookReq.getDescription()) + .startingNumber(addWorkbookReq.getStartingNumber()) + .endingNumber(addWorkbookReq.getEndingNumber()) + .build(); + } + + public static ClassroomWorkbookUpdateDto.Request updateWorkbookRequestToDto( + long workbookId, UpdateWorkbookInfoReq updateWorkbookInfoReq) { + return ClassroomWorkbookUpdateDto.Request.builder() + .id(workbookId) + .name(updateWorkbookInfoReq.getName()) + .description(updateWorkbookInfoReq.getDescription()) + .build(); + } + + public static AddStudentDto.Request toAddStudentDtoRequest( + long classroomId, AddStudentReq addStudentReq) { + return AddStudentDto.Request.builder() + .classroomId(classroomId) + .studentName(addStudentReq.getStudentName()) + .build(); + } +} diff --git a/src/main/java/com/ohdab/classroom/controller/request/AddClassroomReq.java b/src/main/java/com/ohdab/classroom/controller/request/AddClassroomReq.java new file mode 100644 index 00000000..8e37aacf --- /dev/null +++ b/src/main/java/com/ohdab/classroom/controller/request/AddClassroomReq.java @@ -0,0 +1,22 @@ +package com.ohdab.classroom.controller.request; + +import javax.validation.constraints.NotNull; +import lombok.*; + +@Getter +@Builder +@AllArgsConstructor +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class AddClassroomReq { + + @NotNull(message = "반 이름은 필수 입력 값입니다.") + private String name; + + @NotNull(message = "반 설명은 필수 입력값 입니다.") + private String description; + + private String grade; + + @NotNull(message = "선생님 아이디는 필수 입력값 입니다.") + private long teacherId; +} diff --git a/src/main/java/com/ohdab/classroom/controller/request/AddStudentReq.java b/src/main/java/com/ohdab/classroom/controller/request/AddStudentReq.java new file mode 100644 index 00000000..005c3be9 --- /dev/null +++ b/src/main/java/com/ohdab/classroom/controller/request/AddStudentReq.java @@ -0,0 +1,14 @@ +package com.ohdab.classroom.controller.request; + +import javax.validation.constraints.NotNull; +import lombok.*; + +@Getter +@Builder +@AllArgsConstructor +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class AddStudentReq { + + @NotNull(message = "학생 이름은 필수 입력 값입니다.") + private String studentName; +} diff --git a/src/main/java/com/ohdab/classroom/controller/request/AddWorkbookReq.java b/src/main/java/com/ohdab/classroom/controller/request/AddWorkbookReq.java new file mode 100644 index 00000000..c9a4bc74 --- /dev/null +++ b/src/main/java/com/ohdab/classroom/controller/request/AddWorkbookReq.java @@ -0,0 +1,27 @@ +package com.ohdab.classroom.controller.request; + +import javax.validation.constraints.NotNull; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Builder +@AllArgsConstructor +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class AddWorkbookReq { + + @NotNull(message = "교재 이름은 필수 입력 값입니다.") + private String name; + + @NotNull(message = "교재 설명은 필수 입력값 입니다.") + private String description; + + @NotNull(message = "교재 문제의 시작 번호는 필수 입력값 입니다.") + private int startingNumber; + + @NotNull(message = "교재 문제의 끝 번호는 필수 입력값 입니다.") + private int endingNumber; +} diff --git a/src/main/java/com/ohdab/classroom/controller/request/UpdateClassroomReq.java b/src/main/java/com/ohdab/classroom/controller/request/UpdateClassroomReq.java new file mode 100644 index 00000000..2c8a10d2 --- /dev/null +++ b/src/main/java/com/ohdab/classroom/controller/request/UpdateClassroomReq.java @@ -0,0 +1,19 @@ +package com.ohdab.classroom.controller.request; + +import javax.validation.constraints.NotNull; +import lombok.*; + +@Getter +@Builder +@AllArgsConstructor +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class UpdateClassroomReq { + + @NotNull(message = "반 이름은 필수 입력 값입니다.") + private String name; + + @NotNull(message = "반 설명은 필수 입력값 입니다.") + private String description; + + private String grade; +} diff --git a/src/main/java/com/ohdab/classroom/controller/request/UpdateWorkbookInfoReq.java b/src/main/java/com/ohdab/classroom/controller/request/UpdateWorkbookInfoReq.java new file mode 100644 index 00000000..704e61f8 --- /dev/null +++ b/src/main/java/com/ohdab/classroom/controller/request/UpdateWorkbookInfoReq.java @@ -0,0 +1,21 @@ +package com.ohdab.classroom.controller.request; + +import javax.validation.constraints.NotNull; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Builder +@AllArgsConstructor +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class UpdateWorkbookInfoReq { + + @NotNull(message = "교재 이름은 필수 입력 값입니다.") + private String name; + + @NotNull(message = "교재 설명은 필수 입력값 입니다.") + private String description; +} diff --git a/src/main/java/com/ohdab/classroom/controller/response/AddClassroomRes.java b/src/main/java/com/ohdab/classroom/controller/response/AddClassroomRes.java new file mode 100644 index 00000000..e4ba2e04 --- /dev/null +++ b/src/main/java/com/ohdab/classroom/controller/response/AddClassroomRes.java @@ -0,0 +1,10 @@ +package com.ohdab.classroom.controller.response; + +import lombok.Builder; +import lombok.Getter; + +@Builder +@Getter +public class AddClassroomRes { + String message; +} diff --git a/src/main/java/com/ohdab/classroom/controller/response/AddStudentRes.java b/src/main/java/com/ohdab/classroom/controller/response/AddStudentRes.java new file mode 100644 index 00000000..2a5d607c --- /dev/null +++ b/src/main/java/com/ohdab/classroom/controller/response/AddStudentRes.java @@ -0,0 +1,11 @@ +package com.ohdab.classroom.controller.response; + +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class AddStudentRes { + + private String message; +} diff --git a/src/main/java/com/ohdab/classroom/controller/response/AddWorkbookRes.java b/src/main/java/com/ohdab/classroom/controller/response/AddWorkbookRes.java new file mode 100644 index 00000000..0d4afe73 --- /dev/null +++ b/src/main/java/com/ohdab/classroom/controller/response/AddWorkbookRes.java @@ -0,0 +1,10 @@ +package com.ohdab.classroom.controller.response; + +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class AddWorkbookRes { + String message; +} diff --git a/src/main/java/com/ohdab/classroom/controller/response/ClassroomDetailRes.java b/src/main/java/com/ohdab/classroom/controller/response/ClassroomDetailRes.java new file mode 100644 index 00000000..6859f217 --- /dev/null +++ b/src/main/java/com/ohdab/classroom/controller/response/ClassroomDetailRes.java @@ -0,0 +1,20 @@ +package com.ohdab.classroom.controller.response; + +import java.util.List; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class ClassroomDetailRes { + + private long id; + + private String name; + private String description; + private String grade; + + private long teacherId; + private List studentIds; + private List workbookIds; +} diff --git a/src/main/java/com/ohdab/classroom/controller/response/ClassroomResList.java b/src/main/java/com/ohdab/classroom/controller/response/ClassroomResList.java new file mode 100644 index 00000000..05189e6e --- /dev/null +++ b/src/main/java/com/ohdab/classroom/controller/response/ClassroomResList.java @@ -0,0 +1,21 @@ +package com.ohdab.classroom.controller.response; + +import java.util.List; +import lombok.Builder; +import lombok.Getter; + +@Builder +@Getter +public class ClassroomResList { + + List classroomInfoList; + + @Getter + @Builder + public static class ClassroomInfo { + private long id; + private String name; + private String description; + private String grade; + } +} diff --git a/src/main/java/com/ohdab/classroom/controller/response/ClassroomWorkbookListRes.java b/src/main/java/com/ohdab/classroom/controller/response/ClassroomWorkbookListRes.java new file mode 100644 index 00000000..56dbcdd3 --- /dev/null +++ b/src/main/java/com/ohdab/classroom/controller/response/ClassroomWorkbookListRes.java @@ -0,0 +1,23 @@ +package com.ohdab.classroom.controller.response; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.time.LocalDate; +import java.util.List; +import lombok.Builder; +import lombok.Getter; + +@Builder +@Getter +public class ClassroomWorkbookListRes { + + @JsonProperty("workbooks") + List workbookList; + + @Getter + @Builder + public static class WorkbookInfo { + long id; + String name; + LocalDate createdAt; + } +} diff --git a/src/main/java/com/ohdab/classroom/controller/response/DeleteClassroomRes.java b/src/main/java/com/ohdab/classroom/controller/response/DeleteClassroomRes.java new file mode 100644 index 00000000..0a6a9773 --- /dev/null +++ b/src/main/java/com/ohdab/classroom/controller/response/DeleteClassroomRes.java @@ -0,0 +1,10 @@ +package com.ohdab.classroom.controller.response; + +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class DeleteClassroomRes { + String message; +} diff --git a/src/main/java/com/ohdab/classroom/controller/response/UpdateClassroomRes.java b/src/main/java/com/ohdab/classroom/controller/response/UpdateClassroomRes.java new file mode 100644 index 00000000..d8fe7759 --- /dev/null +++ b/src/main/java/com/ohdab/classroom/controller/response/UpdateClassroomRes.java @@ -0,0 +1,10 @@ +package com.ohdab.classroom.controller.response; + +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class UpdateClassroomRes { + String message; +} diff --git a/src/main/java/com/ohdab/classroom/controller/response/UpdateWorkbookInfoRes.java b/src/main/java/com/ohdab/classroom/controller/response/UpdateWorkbookInfoRes.java new file mode 100644 index 00000000..3e3a18b0 --- /dev/null +++ b/src/main/java/com/ohdab/classroom/controller/response/UpdateWorkbookInfoRes.java @@ -0,0 +1,10 @@ +package com.ohdab.classroom.controller.response; + +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class UpdateWorkbookInfoRes { + String message; +} diff --git a/src/main/java/com/ohdab/classroom/domain/Classroom.java b/src/main/java/com/ohdab/classroom/domain/Classroom.java index 2b6b3785..fde41409 100644 --- a/src/main/java/com/ohdab/classroom/domain/Classroom.java +++ b/src/main/java/com/ohdab/classroom/domain/Classroom.java @@ -1,10 +1,14 @@ package com.ohdab.classroom.domain; import com.ohdab.classroom.domain.classroomInfo.ClassroomInfo; +import com.ohdab.classroom.exception.NoStudentException; import com.ohdab.core.baseentity.BaseEntity; +import com.ohdab.core.exception.ExceptionEnum; import com.ohdab.member.domain.student.studentid.StudentId; import com.ohdab.member.domain.teacher.teacherid.TeacherId; import com.ohdab.workbook.domain.workbookid.WorkbookId; +import io.jsonwebtoken.lang.Assert; +import java.util.ArrayList; import java.util.List; import javax.persistence.*; import lombok.AccessLevel; @@ -31,43 +35,38 @@ public class Classroom extends BaseEntity { @ElementCollection @CollectionTable(name = "STUDENT_LIST", joinColumns = @JoinColumn(name = "classroom_id")) - private List students; + private List students = new ArrayList<>(); @ElementCollection @CollectionTable(name = "WORKBOOK_LIST", joinColumns = @JoinColumn(name = "classroom_id")) - private List workbooks; + private List workbooks = new ArrayList<>(); @Builder public Classroom(ClassroomInfo classroomInfo, TeacherId teacher) { - if (classroomInfo == null) { - throw new IllegalStateException("ClassroomInfo cannot be null"); - } - if (teacher == null) { - throw new IllegalStateException("Teacher cannot be null"); - } - setClassroomInfo(classroomInfo); - setTeacher(teacher); - } - - private void setClassroomInfo(ClassroomInfo classroomInfo) { + Assert.notNull(classroomInfo, ExceptionEnum.IS_NULL.getMessage()); + Assert.notNull(teacher, ExceptionEnum.IS_NULL.getMessage()); this.classroomInfo = classroomInfo; - } - - private void setTeacher(TeacherId teacher) { this.teacher = teacher; } public void addStudent(StudentId student) { - if (student == null) { - throw new IllegalStateException("Student cannot be null."); - } + Assert.notNull(student, ExceptionEnum.IS_NULL.getMessage()); this.students.add(student); } public void addWorkbook(WorkbookId workbook) { - if (workbook == null) { - throw new IllegalStateException("Workbook cannot be null."); - } + Assert.notNull(workbook, ExceptionEnum.IS_NULL.getMessage()); this.workbooks.add(workbook); } + + public void deleteStudent(long studentId) { + if (!students.removeIf(student -> student.getId() == studentId)) { + throw new NoStudentException(ExceptionEnum.NO_STUDENT.getMessage()); + } + } + + public void updateClassroomInfo(ClassroomInfo classroomInfo) { + Assert.notNull(classroomInfo, ExceptionEnum.IS_NULL.getMessage()); + this.classroomInfo = classroomInfo; + } } diff --git a/src/main/java/com/ohdab/classroom/domain/classroomInfo/ClassroomInfo.java b/src/main/java/com/ohdab/classroom/domain/classroomInfo/ClassroomInfo.java index 411febaa..0739f6c0 100644 --- a/src/main/java/com/ohdab/classroom/domain/classroomInfo/ClassroomInfo.java +++ b/src/main/java/com/ohdab/classroom/domain/classroomInfo/ClassroomInfo.java @@ -28,6 +28,7 @@ private void setName(String name) { throw new IllegalStateException( "Name length cannot exceed 20 : current length \"" + name.length() + "\""); } + this.name = name; } private void setDescription(String description) { @@ -37,6 +38,7 @@ private void setDescription(String description) { + name.length() + "\""); } + this.description = description; } private void setGrade(Grade grade) { diff --git a/src/main/java/com/ohdab/classroom/domain/classroomInfo/Grade.java b/src/main/java/com/ohdab/classroom/domain/classroomInfo/Grade.java index e6167f8b..a7207840 100644 --- a/src/main/java/com/ohdab/classroom/domain/classroomInfo/Grade.java +++ b/src/main/java/com/ohdab/classroom/domain/classroomInfo/Grade.java @@ -1,13 +1,33 @@ package com.ohdab.classroom.domain.classroomInfo; +import java.util.HashMap; +import java.util.Map; import lombok.Getter; @Getter public enum Grade { - MID_1, - MID_2, - MID_3, - HIGH_1, - HIGH_2, - HIGH_3; + MID_1("mid1"), + MID_2("mid2"), + MID_3("mid3"), + HIGH_1("high1"), + HIGH_2("high2"), + HIGH_3("high3"); + + public final String label; + + private Grade(String label) { + this.label = label; + } + + private static final Map BY_LABEL = new HashMap<>(); + + static { + for (Grade e : values()) { + BY_LABEL.put(e.label, e); + } + } + + public static Grade valueOfLabel(String label) { + return BY_LABEL.get(label); + } } diff --git a/src/main/java/com/ohdab/classroom/event/StudentAddedEvent.java b/src/main/java/com/ohdab/classroom/event/StudentAddedEvent.java new file mode 100644 index 00000000..26449043 --- /dev/null +++ b/src/main/java/com/ohdab/classroom/event/StudentAddedEvent.java @@ -0,0 +1,20 @@ +package com.ohdab.classroom.event; + +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class StudentAddedEvent { + + private String studentName; + private String password; + + @Builder + public StudentAddedEvent(String studentName) { + this.studentName = studentName; + this.password = "1234"; + } +} diff --git a/src/main/java/com/ohdab/classroom/exception/NoClassroomException.java b/src/main/java/com/ohdab/classroom/exception/NoClassroomException.java new file mode 100644 index 00000000..6ca31249 --- /dev/null +++ b/src/main/java/com/ohdab/classroom/exception/NoClassroomException.java @@ -0,0 +1,18 @@ +package com.ohdab.classroom.exception; + +public class NoClassroomException extends RuntimeException { + + public NoClassroomException() {} + + public NoClassroomException(String message) { + super(message); + } + + public NoClassroomException(String message, Throwable cause) { + super(message, cause); + } + + public NoClassroomException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/com/ohdab/classroom/exception/NoGradeException.java b/src/main/java/com/ohdab/classroom/exception/NoGradeException.java new file mode 100644 index 00000000..e178b827 --- /dev/null +++ b/src/main/java/com/ohdab/classroom/exception/NoGradeException.java @@ -0,0 +1,18 @@ +package com.ohdab.classroom.exception; + +public class NoGradeException extends RuntimeException { + + public NoGradeException() {} + + public NoGradeException(String message) { + super(message); + } + + public NoGradeException(String message, Throwable cause) { + super(message, cause); + } + + public NoGradeException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/com/ohdab/classroom/exception/NoStudentException.java b/src/main/java/com/ohdab/classroom/exception/NoStudentException.java new file mode 100644 index 00000000..9b75564a --- /dev/null +++ b/src/main/java/com/ohdab/classroom/exception/NoStudentException.java @@ -0,0 +1,18 @@ +package com.ohdab.classroom.exception; + +public class NoStudentException extends RuntimeException { + + public NoStudentException() {} + + public NoStudentException(String message) { + super(message); + } + + public NoStudentException(String message, Throwable cause) { + super(message, cause); + } + + public NoStudentException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/com/ohdab/classroom/exception/NoTeacherException.java b/src/main/java/com/ohdab/classroom/exception/NoTeacherException.java new file mode 100644 index 00000000..85aa5bbc --- /dev/null +++ b/src/main/java/com/ohdab/classroom/exception/NoTeacherException.java @@ -0,0 +1,18 @@ +package com.ohdab.classroom.exception; + +public class NoTeacherException extends RuntimeException { + + public NoTeacherException() {} + + public NoTeacherException(String message) { + super(message); + } + + public NoTeacherException(String message, Throwable cause) { + super(message, cause); + } + + public NoTeacherException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/com/ohdab/classroom/repository/ClassroomRepository.java b/src/main/java/com/ohdab/classroom/repository/ClassroomRepository.java new file mode 100644 index 00000000..dfdebca6 --- /dev/null +++ b/src/main/java/com/ohdab/classroom/repository/ClassroomRepository.java @@ -0,0 +1,13 @@ +package com.ohdab.classroom.repository; + +import com.ohdab.classroom.domain.Classroom; +import com.ohdab.member.domain.student.studentid.StudentId; +import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ClassroomRepository extends JpaRepository { + + List findAllByTeacherId(long teacherId); + + List findStudentsById(long classroomId); +} diff --git a/src/main/java/com/ohdab/classroom/service/AddClassroomService.java b/src/main/java/com/ohdab/classroom/service/AddClassroomService.java new file mode 100644 index 00000000..c980445b --- /dev/null +++ b/src/main/java/com/ohdab/classroom/service/AddClassroomService.java @@ -0,0 +1,52 @@ +package com.ohdab.classroom.service; + +import static com.ohdab.classroom.service.helper.ClassroomHelperService.findGradeByString; + +import com.ohdab.classroom.domain.Classroom; +import com.ohdab.classroom.domain.classroomInfo.ClassroomInfo; +import com.ohdab.classroom.exception.NoTeacherException; +import com.ohdab.classroom.repository.ClassroomRepository; +import com.ohdab.classroom.service.dto.ClassroomDto; +import com.ohdab.classroom.service.usecase.AddClassroomUsecase; +import com.ohdab.core.exception.ExceptionEnum; +import com.ohdab.member.domain.teacher.teacherid.TeacherId; +import com.ohdab.member.repository.MemberRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class AddClassroomService implements AddClassroomUsecase { + + private final MemberRepository memberRepository; + private final ClassroomRepository classroomRepository; + + @Override + public void addClassroom(ClassroomDto.Request classroomReqDto) { + long teacherId = classroomReqDto.getTeacherId(); + throwIfTeacherDoesNotExist(teacherId); + + ClassroomInfo classroomInfo = + ClassroomInfo.builder() + .name(classroomReqDto.getInfo().getName()) + .description(classroomReqDto.getInfo().getDescription()) + .grade(findGradeByString(classroomReqDto.getInfo().getGrade())) + .build(); + + Classroom classroom = + Classroom.builder() + .teacher(TeacherId.builder().id(teacherId).build()) + .classroomInfo(classroomInfo) + .build(); + + classroomRepository.save(classroom); + } + + private void throwIfTeacherDoesNotExist(long teacherId) { + if (!memberRepository.existsById(teacherId)) { + throw new NoTeacherException(ExceptionEnum.NO_TEACHER.getMessage()); + } + } +} diff --git a/src/main/java/com/ohdab/classroom/service/AddStudentService.java b/src/main/java/com/ohdab/classroom/service/AddStudentService.java new file mode 100644 index 00000000..b1a0155c --- /dev/null +++ b/src/main/java/com/ohdab/classroom/service/AddStudentService.java @@ -0,0 +1,74 @@ +package com.ohdab.classroom.service; + +import com.ohdab.classroom.domain.Classroom; +import com.ohdab.classroom.event.StudentAddedEvent; +import com.ohdab.classroom.exception.NoClassroomException; +import com.ohdab.classroom.repository.ClassroomRepository; +import com.ohdab.classroom.service.dto.AddStudentDto; +import com.ohdab.classroom.service.usecase.AddStudentUsecase; +import com.ohdab.core.exception.ExceptionEnum; +import com.ohdab.member.domain.Member; +import com.ohdab.member.domain.student.studentid.StudentId; +import com.ohdab.member.exception.NoMemberException; +import com.ohdab.member.repository.MemberRepository; +import com.ohdab.mistakenote.domain.MistakeNote; +import com.ohdab.mistakenote.repository.MistakeNoteRepository; +import com.ohdab.workbook.domain.workbookid.WorkbookId; +import java.util.List; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional +public class AddStudentService implements AddStudentUsecase { + + private final ApplicationEventPublisher publisher; + private final ClassroomRepository classroomRepository; + private final MemberRepository memberRepository; + private final MistakeNoteRepository mistakeNoteRepository; + + @Override + public void addStudent(AddStudentDto.Request addStudentReq) { + Classroom classroom = findClassroomById(addStudentReq.getClassroomId()); + publishStudentAddedEvent(addStudentReq.getStudentName()); + Member student = findMemberByName(addStudentReq.getStudentName()); + createMistakeNoteForAddedStudent(classroom, student); + classroom.addStudent(new StudentId(student.getId())); + } + + private Classroom findClassroomById(long classroomId) { + return classroomRepository + .findById(classroomId) + .orElseThrow( + () -> new NoClassroomException(ExceptionEnum.NO_CLASSROOM.getMessage())); + } + + private void publishStudentAddedEvent(String studentName) { + publisher.publishEvent(StudentAddedEvent.builder().studentName(studentName).build()); + } + + private Member findMemberByName(String studentName) { + return memberRepository + .findByMemberInfoName(studentName) + .orElseThrow(() -> new NoMemberException(ExceptionEnum.NO_MEMBER.getMessage())); + } + + private void createMistakeNoteForAddedStudent(Classroom classroom, Member student) { + long studentId = student.getId(); + List workbooks = classroom.getWorkbooks(); + List mistakeNotes = + workbooks.stream() + .map( + workbookId -> + MistakeNote.builder() + .workbookId(workbookId) + .studentId(new StudentId(studentId)) + .build()) + .collect(Collectors.toList()); + mistakeNoteRepository.saveAll(mistakeNotes); + } +} diff --git a/src/main/java/com/ohdab/classroom/service/AddWorkbookService.java b/src/main/java/com/ohdab/classroom/service/AddWorkbookService.java new file mode 100644 index 00000000..17a6d17d --- /dev/null +++ b/src/main/java/com/ohdab/classroom/service/AddWorkbookService.java @@ -0,0 +1,74 @@ +package com.ohdab.classroom.service; + +import com.ohdab.classroom.domain.Classroom; +import com.ohdab.classroom.domain.classroomid.ClassroomId; +import com.ohdab.classroom.repository.ClassroomRepository; +import com.ohdab.classroom.service.dto.ClassroomAddWorkbookDto; +import com.ohdab.classroom.service.dto.ClassroomAddWorkbookDto.Request; +import com.ohdab.classroom.service.helper.ClassroomHelperService; +import com.ohdab.classroom.service.usecase.AddWorkbookUsecase; +import com.ohdab.member.domain.student.studentid.StudentId; +import com.ohdab.mistakenote.domain.MistakeNote; +import com.ohdab.mistakenote.repository.MistakeNoteRepository; +import com.ohdab.workbook.domain.Workbook; +import com.ohdab.workbook.domain.workbookInfo.WorkbookInfo; +import com.ohdab.workbook.domain.workbookid.WorkbookId; +import com.ohdab.workbook.repository.WorkbookRepository; +import java.util.List; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class AddWorkbookService implements AddWorkbookUsecase { + + private final ClassroomRepository classroomRepository; + private final WorkbookRepository workbookRepository; + private final MistakeNoteRepository mistakeNoteRepository; + + @Override + public void addWorkbookByClassroomId(long classroomId, Request addWorkbookDto) { + Classroom classroom = + ClassroomHelperService.findExistingClassroom(classroomId, classroomRepository); + ClassroomId classroomId1 = new ClassroomId(classroomId); + ClassroomHelperService.throwIfDuplicatedWorkbookName( + workbookRepository, classroomId1, addWorkbookDto.getName()); + Workbook workbook = saveWorkbook(classroomId1, addWorkbookDto); + WorkbookId workbookId = new WorkbookId(workbook.getId()); + classroom.addWorkbook(workbookId); + saveMistakeNote(classroomId, workbookId); + } + + private Workbook saveWorkbook( + ClassroomId classroomId, ClassroomAddWorkbookDto.Request addWorkbookDto) { + Workbook workbook = + Workbook.builder() + .workbookInfo( + WorkbookInfo.builder() + .name(addWorkbookDto.getName()) + .description(addWorkbookDto.getDescription()) + .startingNumber(addWorkbookDto.getStartingNumber()) + .endingNumber(addWorkbookDto.getEndingNumber()) + .build()) + .classroomId(classroomId) + .build(); + return workbookRepository.save(workbook); + } + + private void saveMistakeNote(long classroomId, WorkbookId workbookId) { + List studentIdList = classroomRepository.findStudentsById(classroomId); + List mistakeNoteList = + studentIdList.stream() + .map( + studentId -> + MistakeNote.builder() + .studentId(studentId) + .workbookId(workbookId) + .build()) + .collect(Collectors.toList()); + mistakeNoteRepository.saveAll(mistakeNoteList); + } +} diff --git a/src/main/java/com/ohdab/classroom/service/ClassroomDetailService.java b/src/main/java/com/ohdab/classroom/service/ClassroomDetailService.java new file mode 100644 index 00000000..49471837 --- /dev/null +++ b/src/main/java/com/ohdab/classroom/service/ClassroomDetailService.java @@ -0,0 +1,33 @@ +package com.ohdab.classroom.service; + +import static com.ohdab.classroom.service.dto.ClassroomDetailDto.ClassroomDetailDtoResponse; + +import com.ohdab.classroom.domain.Classroom; +import com.ohdab.classroom.exception.NoClassroomException; +import com.ohdab.classroom.repository.ClassroomRepository; +import com.ohdab.classroom.service.mapper.ClassroomDetailServiceMapper; +import com.ohdab.classroom.service.usecase.ClassroomDetailUsecase; +import com.ohdab.core.exception.ExceptionEnum; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class ClassroomDetailService implements ClassroomDetailUsecase { + + private final ClassroomRepository classroomRepository; + + @Override + public ClassroomDetailDtoResponse getClassroomDetailById(long classroomId) { + Classroom classroom = + classroomRepository + .findById(classroomId) + .orElseThrow( + () -> + new NoClassroomException( + ExceptionEnum.NO_CLASSROOM.getMessage())); + return ClassroomDetailServiceMapper.classroomToClassroomDetail(classroom); + } +} diff --git a/src/main/java/com/ohdab/classroom/service/DeleteClassroomService.java b/src/main/java/com/ohdab/classroom/service/DeleteClassroomService.java new file mode 100644 index 00000000..5b86d714 --- /dev/null +++ b/src/main/java/com/ohdab/classroom/service/DeleteClassroomService.java @@ -0,0 +1,24 @@ +package com.ohdab.classroom.service; + +import static com.ohdab.classroom.service.helper.ClassroomHelperService.findExistingClassroom; + +import com.ohdab.classroom.domain.Classroom; +import com.ohdab.classroom.repository.ClassroomRepository; +import com.ohdab.classroom.service.usecase.DeleteClassroomUsecase; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class DeleteClassroomService implements DeleteClassroomUsecase { + + private final ClassroomRepository classroomRepository; + + @Override + public void deleteClassroomById(long classroomId) { + Classroom classroom = findExistingClassroom(classroomId, classroomRepository); + classroomRepository.delete(classroom); + } +} diff --git a/src/main/java/com/ohdab/classroom/service/DeleteStudentService.java b/src/main/java/com/ohdab/classroom/service/DeleteStudentService.java new file mode 100644 index 00000000..586ddf00 --- /dev/null +++ b/src/main/java/com/ohdab/classroom/service/DeleteStudentService.java @@ -0,0 +1,30 @@ +package com.ohdab.classroom.service; + +import static com.ohdab.classroom.service.helper.ClassroomHelperService.findExistingClassroom; +import static com.ohdab.member.service.helper.MemberHelperService.findExistingMemberById; + +import com.ohdab.classroom.domain.Classroom; +import com.ohdab.classroom.repository.ClassroomRepository; +import com.ohdab.classroom.service.usecase.DeleteStudentUsecase; +import com.ohdab.member.domain.Member; +import com.ohdab.member.repository.MemberRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional +public class DeleteStudentService implements DeleteStudentUsecase { + + private final ClassroomRepository classroomRepository; + private final MemberRepository memberRepository; + + @Override + public void deleteStudent(long classroomId, long studentId) { + Classroom classroom = findExistingClassroom(classroomId, classroomRepository); + Member student = findExistingMemberById(memberRepository, studentId); + student.withdrawal(); + classroom.deleteStudent(studentId); + } +} diff --git a/src/main/java/com/ohdab/classroom/service/FindClassroomDetailService.java b/src/main/java/com/ohdab/classroom/service/FindClassroomDetailService.java new file mode 100644 index 00000000..3665967b --- /dev/null +++ b/src/main/java/com/ohdab/classroom/service/FindClassroomDetailService.java @@ -0,0 +1,33 @@ +package com.ohdab.classroom.service; + +import static com.ohdab.classroom.service.dto.ClassroomDetailDto.ClassroomDetailDtoResponse; + +import com.ohdab.classroom.domain.Classroom; +import com.ohdab.classroom.exception.NoClassroomException; +import com.ohdab.classroom.repository.ClassroomRepository; +import com.ohdab.classroom.service.mapper.ClassroomDetailServiceMapper; +import com.ohdab.classroom.service.usecase.FindClassroomDetailUsecase; +import com.ohdab.core.exception.ExceptionEnum; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class FindClassroomDetailService implements FindClassroomDetailUsecase { + + private final ClassroomRepository classroomRepository; + + @Override + public ClassroomDetailDtoResponse getClassroomDetailById(long classroomId) { + Classroom classroom = + classroomRepository + .findById(classroomId) + .orElseThrow( + () -> + new NoClassroomException( + ExceptionEnum.NO_CLASSROOM.getMessage())); + return ClassroomDetailServiceMapper.classroomToClassroomDetail(classroom); + } +} diff --git a/src/main/java/com/ohdab/classroom/service/FindClassroomListService.java b/src/main/java/com/ohdab/classroom/service/FindClassroomListService.java new file mode 100644 index 00000000..7bef280d --- /dev/null +++ b/src/main/java/com/ohdab/classroom/service/FindClassroomListService.java @@ -0,0 +1,25 @@ +package com.ohdab.classroom.service; + +import com.ohdab.classroom.domain.Classroom; +import com.ohdab.classroom.repository.ClassroomRepository; +import com.ohdab.classroom.service.dto.ClassroomDto; +import com.ohdab.classroom.service.mapper.ClassroomServiceMapper; +import com.ohdab.classroom.service.usecase.FindClassroomListUsecase; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class FindClassroomListService implements FindClassroomListUsecase { + + private final ClassroomRepository classroomRepository; + + @Override + public List findClassroomListByTeacherId(long teacherId) { + List classroomList = classroomRepository.findAllByTeacherId(teacherId); + return ClassroomServiceMapper.classroomListToClassroomDtoList(classroomList); + } +} diff --git a/src/main/java/com/ohdab/classroom/service/GetWorkbookListService.java b/src/main/java/com/ohdab/classroom/service/GetWorkbookListService.java new file mode 100644 index 00000000..cc001e05 --- /dev/null +++ b/src/main/java/com/ohdab/classroom/service/GetWorkbookListService.java @@ -0,0 +1,51 @@ +package com.ohdab.classroom.service; + +import com.ohdab.classroom.domain.classroomid.ClassroomId; +import com.ohdab.classroom.exception.NoClassroomException; +import com.ohdab.classroom.repository.ClassroomRepository; +import com.ohdab.classroom.service.dto.ClassroomWorkbookDto; +import com.ohdab.classroom.service.usecase.GetWorkbookListUsecase; +import com.ohdab.core.exception.ExceptionEnum; +import com.ohdab.workbook.domain.Workbook; +import com.ohdab.workbook.repository.WorkbookRepository; +import java.util.List; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class GetWorkbookListService implements GetWorkbookListUsecase { + + private final ClassroomRepository classroomRepository; + private final WorkbookRepository workbookRepository; + + @Override + public List getWorkbookListByClassroomId(long classroomId) { + throwIfUnknownClassroomId(classroomId); + List workbookList = + workbookRepository.findByClassroomId(new ClassroomId(classroomId)); + return workbookDomainListToWorkbookDtoList(workbookList); + } + + private void throwIfUnknownClassroomId(long classroomId) { + if (!classroomRepository.existsById(classroomId)) { + throw new NoClassroomException(ExceptionEnum.NO_CLASSROOM.getMessage()); + } + } + + private List workbookDomainListToWorkbookDtoList( + List workbookList) { + return workbookList.stream() + .map( + workbook -> + ClassroomWorkbookDto.Response.builder() + .id(workbook.getId()) + .name(workbook.getWorkbookInfo().getName()) + .createdAt(workbook.getCreatedAt()) + .build()) + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/com/ohdab/classroom/service/UpdateClassroomInfoService.java b/src/main/java/com/ohdab/classroom/service/UpdateClassroomInfoService.java new file mode 100644 index 00000000..90240488 --- /dev/null +++ b/src/main/java/com/ohdab/classroom/service/UpdateClassroomInfoService.java @@ -0,0 +1,33 @@ +package com.ohdab.classroom.service; + +import static com.ohdab.classroom.service.dto.ClassroomUpdateDto.ClassroomUpdateDtoRequest; +import static com.ohdab.classroom.service.helper.ClassroomHelperService.findExistingClassroom; +import static com.ohdab.classroom.service.helper.ClassroomHelperService.findGradeByString; + +import com.ohdab.classroom.domain.Classroom; +import com.ohdab.classroom.domain.classroomInfo.ClassroomInfo; +import com.ohdab.classroom.repository.ClassroomRepository; +import com.ohdab.classroom.service.usecase.UpdateClassroomInfoUsecase; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class UpdateClassroomInfoService implements UpdateClassroomInfoUsecase { + + private final ClassroomRepository classroomRepository; + + @Override + public void updateClassroomInfo(ClassroomUpdateDtoRequest request) { + Classroom classroom = findExistingClassroom(request.getClassroomId(), classroomRepository); + classroom.updateClassroomInfo( + ClassroomInfo.builder() + .name(request.getName()) + .description(request.getDescription()) + .grade(findGradeByString(request.getGrade())) + .build()); + classroomRepository.save(classroom); + } +} diff --git a/src/main/java/com/ohdab/classroom/service/UpdateWorkbookInfoService.java b/src/main/java/com/ohdab/classroom/service/UpdateWorkbookInfoService.java new file mode 100644 index 00000000..4dc73487 --- /dev/null +++ b/src/main/java/com/ohdab/classroom/service/UpdateWorkbookInfoService.java @@ -0,0 +1,46 @@ +package com.ohdab.classroom.service; + +import com.ohdab.classroom.service.dto.ClassroomWorkbookUpdateDto.Request; +import com.ohdab.classroom.service.helper.ClassroomHelperService; +import com.ohdab.classroom.service.usecase.UpdateWorkbookInfoUsecase; +import com.ohdab.core.exception.ExceptionEnum; +import com.ohdab.workbook.domain.Workbook; +import com.ohdab.workbook.domain.workbookInfo.WorkbookInfo; +import com.ohdab.workbook.exception.NoWorkbookException; +import com.ohdab.workbook.repository.WorkbookRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class UpdateWorkbookInfoService implements UpdateWorkbookInfoUsecase { + + private final WorkbookRepository workbookRepository; + + @Override + public void updateWorkbookInfo(Request updateWorkbookReq) { + throwIfUnknownWorkbookId(updateWorkbookReq.getId()); + Workbook workbook = workbookRepository.findById(updateWorkbookReq.getId()).get(); + ClassroomHelperService.throwIfDuplicatedWorkbookName( + workbookRepository, workbook.getClassroomId(), updateWorkbookReq.getName()); + workbook.updateWorkbookInfo(setWorkbookInfo(updateWorkbookReq, workbook)); + workbookRepository.save(workbook); + } + + private void throwIfUnknownWorkbookId(long id) { + if (!workbookRepository.existsById(id)) { + throw new NoWorkbookException(ExceptionEnum.NO_WORKBOOK.getMessage()); + } + } + + private WorkbookInfo setWorkbookInfo(Request updateWorkbookReq, Workbook workbook) { + return WorkbookInfo.builder() + .name(updateWorkbookReq.getName()) + .description(updateWorkbookReq.getDescription()) + .startingNumber(workbook.getWorkbookInfo().getStartingNumber()) + .endingNumber(workbook.getWorkbookInfo().getEndingNumber()) + .build(); + } +} diff --git a/src/main/java/com/ohdab/classroom/service/dto/AddStudentDto.java b/src/main/java/com/ohdab/classroom/service/dto/AddStudentDto.java new file mode 100644 index 00000000..5f86bff5 --- /dev/null +++ b/src/main/java/com/ohdab/classroom/service/dto/AddStudentDto.java @@ -0,0 +1,18 @@ +package com.ohdab.classroom.service.dto; + +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class AddStudentDto { + + @Getter + @Builder + public static class Request { + + private long classroomId; + private String studentName; + } +} diff --git a/src/main/java/com/ohdab/classroom/service/dto/ClassroomAddWorkbookDto.java b/src/main/java/com/ohdab/classroom/service/dto/ClassroomAddWorkbookDto.java new file mode 100644 index 00000000..3555e565 --- /dev/null +++ b/src/main/java/com/ohdab/classroom/service/dto/ClassroomAddWorkbookDto.java @@ -0,0 +1,19 @@ +package com.ohdab.classroom.service.dto; + +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class ClassroomAddWorkbookDto { + + @Getter + @Builder + public static class Request { + String name; + String description; + int startingNumber; + int endingNumber; + } +} diff --git a/src/main/java/com/ohdab/classroom/service/dto/ClassroomDetailDto.java b/src/main/java/com/ohdab/classroom/service/dto/ClassroomDetailDto.java new file mode 100644 index 00000000..3dbdc648 --- /dev/null +++ b/src/main/java/com/ohdab/classroom/service/dto/ClassroomDetailDto.java @@ -0,0 +1,38 @@ +package com.ohdab.classroom.service.dto; + +import java.util.List; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class ClassroomDetailDto { + + @Getter + @Builder + public static class ClassroomDetailDtoInfo { + private String name; + private String description; + private String grade; + } + + @Getter + @Builder + public static class ClassroomDetailDtoRequest { + private long classroomId; + } + + @Getter + @Builder + public static class ClassroomDetailDtoResponse { + private long classroomId; + + private long teacherId; + + private ClassroomDetailDtoInfo info; + + private List studentIds; + + private List workbookIds; + } +} diff --git a/src/main/java/com/ohdab/classroom/service/dto/ClassroomDto.java b/src/main/java/com/ohdab/classroom/service/dto/ClassroomDto.java new file mode 100644 index 00000000..3391df22 --- /dev/null +++ b/src/main/java/com/ohdab/classroom/service/dto/ClassroomDto.java @@ -0,0 +1,39 @@ +package com.ohdab.classroom.service.dto; + +import java.util.List; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class ClassroomDto { + + @Getter + @Builder + public static class Info { + private String name; + private String description; + private String grade; + } + + @Getter + @Builder + public static class Request { + private Info info; + private long teacherId; + } + + @Getter + @Builder + public static class Response { + private long id; + + private long teacherId; + + private Info info; + + private List studentIds; + + private List workbookIds; + } +} diff --git a/src/main/java/com/ohdab/classroom/service/dto/ClassroomUpdateDto.java b/src/main/java/com/ohdab/classroom/service/dto/ClassroomUpdateDto.java new file mode 100644 index 00000000..5e1813c5 --- /dev/null +++ b/src/main/java/com/ohdab/classroom/service/dto/ClassroomUpdateDto.java @@ -0,0 +1,19 @@ +package com.ohdab.classroom.service.dto; + +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class ClassroomUpdateDto { + + @Getter + @Builder + public static class ClassroomUpdateDtoRequest { + private long classroomId; + + private String name; + private String description; + private String grade; + } +} diff --git a/src/main/java/com/ohdab/classroom/service/dto/ClassroomWorkbookDto.java b/src/main/java/com/ohdab/classroom/service/dto/ClassroomWorkbookDto.java new file mode 100644 index 00000000..16ea079b --- /dev/null +++ b/src/main/java/com/ohdab/classroom/service/dto/ClassroomWorkbookDto.java @@ -0,0 +1,19 @@ +package com.ohdab.classroom.service.dto; + +import java.time.LocalDateTime; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class ClassroomWorkbookDto { + + @Getter + @Builder + public static class Response { + Long id; + String name; + LocalDateTime createdAt; + } +} diff --git a/src/main/java/com/ohdab/classroom/service/dto/ClassroomWorkbookUpdateDto.java b/src/main/java/com/ohdab/classroom/service/dto/ClassroomWorkbookUpdateDto.java new file mode 100644 index 00000000..84bc1e0f --- /dev/null +++ b/src/main/java/com/ohdab/classroom/service/dto/ClassroomWorkbookUpdateDto.java @@ -0,0 +1,18 @@ +package com.ohdab.classroom.service.dto; + +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class ClassroomWorkbookUpdateDto { + + @Builder + @Getter + public static class Request { + long id; + String name; + String description; + } +} diff --git a/src/main/java/com/ohdab/classroom/service/dto/DeleteStudentDto.java b/src/main/java/com/ohdab/classroom/service/dto/DeleteStudentDto.java new file mode 100644 index 00000000..36513cd8 --- /dev/null +++ b/src/main/java/com/ohdab/classroom/service/dto/DeleteStudentDto.java @@ -0,0 +1,15 @@ +package com.ohdab.classroom.service.dto; + +import lombok.Builder; +import lombok.Getter; + +public class DeleteStudentDto { + + @Getter + @Builder + public static class Request { + + private long classroomId; + private long studentId; + } +} diff --git a/src/main/java/com/ohdab/classroom/service/helper/ClassroomHelperService.java b/src/main/java/com/ohdab/classroom/service/helper/ClassroomHelperService.java new file mode 100644 index 00000000..82b743bc --- /dev/null +++ b/src/main/java/com/ohdab/classroom/service/helper/ClassroomHelperService.java @@ -0,0 +1,42 @@ +package com.ohdab.classroom.service.helper; + +import com.ohdab.classroom.domain.Classroom; +import com.ohdab.classroom.domain.classroomInfo.Grade; +import com.ohdab.classroom.domain.classroomid.ClassroomId; +import com.ohdab.classroom.exception.NoClassroomException; +import com.ohdab.classroom.exception.NoGradeException; +import com.ohdab.classroom.repository.ClassroomRepository; +import com.ohdab.core.exception.ExceptionEnum; +import com.ohdab.workbook.exception.DuplicatedWorkbookException; +import com.ohdab.workbook.repository.WorkbookRepository; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public final class ClassroomHelperService { + + public static Grade findGradeByString(String stringGrade) { + try { + return Grade.valueOfLabel(stringGrade); + } catch (NullPointerException e) { + throw new NoGradeException(ExceptionEnum.NO_GRADE.getMessage()); + } catch (ClassCastException e) { + throw new IllegalArgumentException("인자의 자료형이 잘못되었습니다."); + } + } + + public static Classroom findExistingClassroom( + long classroomId, ClassroomRepository classroomRepository) { + return classroomRepository + .findById(classroomId) + .orElseThrow( + () -> new NoClassroomException(ExceptionEnum.NO_CLASSROOM.getMessage())); + } + + public static void throwIfDuplicatedWorkbookName( + WorkbookRepository workbookRepository, ClassroomId classroomId, String name) { + if (workbookRepository.existsByClassroomIdAndWorkbookInfoName(classroomId, name)) { + throw new DuplicatedWorkbookException(ExceptionEnum.DUPLICATED_WORKBOOK.getMessage()); + } + } +} diff --git a/src/main/java/com/ohdab/classroom/service/mapper/ClassroomDetailServiceMapper.java b/src/main/java/com/ohdab/classroom/service/mapper/ClassroomDetailServiceMapper.java new file mode 100644 index 00000000..1bb1c07e --- /dev/null +++ b/src/main/java/com/ohdab/classroom/service/mapper/ClassroomDetailServiceMapper.java @@ -0,0 +1,36 @@ +package com.ohdab.classroom.service.mapper; + +import static com.ohdab.classroom.service.dto.ClassroomDetailDto.ClassroomDetailDtoInfo; +import static com.ohdab.classroom.service.dto.ClassroomDetailDto.ClassroomDetailDtoResponse; + +import com.ohdab.classroom.domain.Classroom; +import com.ohdab.member.domain.student.studentid.StudentId; +import com.ohdab.workbook.domain.workbookid.WorkbookId; +import java.util.stream.Collectors; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class ClassroomDetailServiceMapper { + + public static ClassroomDetailDtoResponse classroomToClassroomDetail(Classroom classroom) { + return ClassroomDetailDtoResponse.builder() + .classroomId(classroom.getId()) + .teacherId(classroom.getTeacher().getId()) + .info( + ClassroomDetailDtoInfo.builder() + .name(classroom.getClassroomInfo().getName()) + .description(classroom.getClassroomInfo().getDescription()) + .grade(classroom.getClassroomInfo().getGrade().getLabel()) + .build()) + .studentIds( + classroom.getStudents().stream() + .map(StudentId::getId) + .collect(Collectors.toList())) + .workbookIds( + classroom.getWorkbooks().stream() + .map(WorkbookId::getId) + .collect(Collectors.toList())) + .build(); + } +} diff --git a/src/main/java/com/ohdab/classroom/service/mapper/ClassroomServiceMapper.java b/src/main/java/com/ohdab/classroom/service/mapper/ClassroomServiceMapper.java new file mode 100644 index 00000000..b61c6f4c --- /dev/null +++ b/src/main/java/com/ohdab/classroom/service/mapper/ClassroomServiceMapper.java @@ -0,0 +1,43 @@ +package com.ohdab.classroom.service.mapper; + +import com.ohdab.classroom.domain.Classroom; +import com.ohdab.classroom.service.dto.ClassroomDto; +import com.ohdab.member.domain.student.studentid.StudentId; +import com.ohdab.workbook.domain.workbookid.WorkbookId; +import java.util.List; +import java.util.stream.Collectors; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class ClassroomServiceMapper { + + public static List classroomListToClassroomDtoList( + List classrooms) { + return classrooms.stream() + .map(ClassroomServiceMapper::classroomToClassroomDto) + .collect(Collectors.toList()); + } + + public static ClassroomDto.Response classroomToClassroomDto(Classroom classroom) { + + return ClassroomDto.Response.builder() + .id(classroom.getId()) + .teacherId(classroom.getTeacher().getId()) + .info( + ClassroomDto.Info.builder() + .name(classroom.getClassroomInfo().getName()) + .description(classroom.getClassroomInfo().getDescription()) + .grade(classroom.getClassroomInfo().getGrade().getLabel()) + .build()) + .studentIds( + classroom.getStudents().stream() + .map(StudentId::getId) + .collect(Collectors.toList())) + .workbookIds( + classroom.getWorkbooks().stream() + .map(WorkbookId::getId) + .collect(Collectors.toList())) + .build(); + } +} diff --git a/src/main/java/com/ohdab/classroom/service/usecase/AddClassroomUsecase.java b/src/main/java/com/ohdab/classroom/service/usecase/AddClassroomUsecase.java new file mode 100644 index 00000000..26ca4e4c --- /dev/null +++ b/src/main/java/com/ohdab/classroom/service/usecase/AddClassroomUsecase.java @@ -0,0 +1,8 @@ +package com.ohdab.classroom.service.usecase; + +import com.ohdab.classroom.service.dto.ClassroomDto; + +public interface AddClassroomUsecase { + + void addClassroom(ClassroomDto.Request classroomReqDto); +} diff --git a/src/main/java/com/ohdab/classroom/service/usecase/AddStudentUsecase.java b/src/main/java/com/ohdab/classroom/service/usecase/AddStudentUsecase.java new file mode 100644 index 00000000..455d3bdd --- /dev/null +++ b/src/main/java/com/ohdab/classroom/service/usecase/AddStudentUsecase.java @@ -0,0 +1,8 @@ +package com.ohdab.classroom.service.usecase; + +import com.ohdab.classroom.service.dto.AddStudentDto; + +public interface AddStudentUsecase { + + void addStudent(AddStudentDto.Request addStudentReq); +} diff --git a/src/main/java/com/ohdab/classroom/service/usecase/AddWorkbookUsecase.java b/src/main/java/com/ohdab/classroom/service/usecase/AddWorkbookUsecase.java new file mode 100644 index 00000000..d18bebf6 --- /dev/null +++ b/src/main/java/com/ohdab/classroom/service/usecase/AddWorkbookUsecase.java @@ -0,0 +1,8 @@ +package com.ohdab.classroom.service.usecase; + +import com.ohdab.classroom.service.dto.ClassroomAddWorkbookDto; + +public interface AddWorkbookUsecase { + + void addWorkbookByClassroomId(long classroomId, ClassroomAddWorkbookDto.Request addWorkbookDto); +} diff --git a/src/main/java/com/ohdab/classroom/service/usecase/ClassroomDetailUsecase.java b/src/main/java/com/ohdab/classroom/service/usecase/ClassroomDetailUsecase.java new file mode 100644 index 00000000..e8b7113b --- /dev/null +++ b/src/main/java/com/ohdab/classroom/service/usecase/ClassroomDetailUsecase.java @@ -0,0 +1,8 @@ +package com.ohdab.classroom.service.usecase; + +import static com.ohdab.classroom.service.dto.ClassroomDetailDto.ClassroomDetailDtoResponse; + +public interface ClassroomDetailUsecase { + + ClassroomDetailDtoResponse getClassroomDetailById(long classroomId); +} diff --git a/src/main/java/com/ohdab/classroom/service/usecase/DeleteClassroomUsecase.java b/src/main/java/com/ohdab/classroom/service/usecase/DeleteClassroomUsecase.java new file mode 100644 index 00000000..ad02e544 --- /dev/null +++ b/src/main/java/com/ohdab/classroom/service/usecase/DeleteClassroomUsecase.java @@ -0,0 +1,6 @@ +package com.ohdab.classroom.service.usecase; + +public interface DeleteClassroomUsecase { + + void deleteClassroomById(long classroomId); +} diff --git a/src/main/java/com/ohdab/classroom/service/usecase/DeleteStudentUsecase.java b/src/main/java/com/ohdab/classroom/service/usecase/DeleteStudentUsecase.java new file mode 100644 index 00000000..4fa32f8e --- /dev/null +++ b/src/main/java/com/ohdab/classroom/service/usecase/DeleteStudentUsecase.java @@ -0,0 +1,6 @@ +package com.ohdab.classroom.service.usecase; + +public interface DeleteStudentUsecase { + + void deleteStudent(long classroomId, long studentId); +} diff --git a/src/main/java/com/ohdab/classroom/service/usecase/FindClassroomDetailUsecase.java b/src/main/java/com/ohdab/classroom/service/usecase/FindClassroomDetailUsecase.java new file mode 100644 index 00000000..b314251e --- /dev/null +++ b/src/main/java/com/ohdab/classroom/service/usecase/FindClassroomDetailUsecase.java @@ -0,0 +1,8 @@ +package com.ohdab.classroom.service.usecase; + +import static com.ohdab.classroom.service.dto.ClassroomDetailDto.ClassroomDetailDtoResponse; + +public interface FindClassroomDetailUsecase { + + ClassroomDetailDtoResponse getClassroomDetailById(long classroomId); +} diff --git a/src/main/java/com/ohdab/classroom/service/usecase/FindClassroomListUsecase.java b/src/main/java/com/ohdab/classroom/service/usecase/FindClassroomListUsecase.java new file mode 100644 index 00000000..990e555a --- /dev/null +++ b/src/main/java/com/ohdab/classroom/service/usecase/FindClassroomListUsecase.java @@ -0,0 +1,9 @@ +package com.ohdab.classroom.service.usecase; + +import com.ohdab.classroom.service.dto.ClassroomDto; +import java.util.List; + +public interface FindClassroomListUsecase { + + List findClassroomListByTeacherId(long teacherId); +} diff --git a/src/main/java/com/ohdab/classroom/service/usecase/GetWorkbookListUsecase.java b/src/main/java/com/ohdab/classroom/service/usecase/GetWorkbookListUsecase.java new file mode 100644 index 00000000..37120e8d --- /dev/null +++ b/src/main/java/com/ohdab/classroom/service/usecase/GetWorkbookListUsecase.java @@ -0,0 +1,9 @@ +package com.ohdab.classroom.service.usecase; + +import com.ohdab.classroom.service.dto.ClassroomWorkbookDto; +import java.util.List; + +public interface GetWorkbookListUsecase { + + List getWorkbookListByClassroomId(long classroomId); +} diff --git a/src/main/java/com/ohdab/classroom/service/usecase/UpdateClassroomInfoUsecase.java b/src/main/java/com/ohdab/classroom/service/usecase/UpdateClassroomInfoUsecase.java new file mode 100644 index 00000000..51cc942f --- /dev/null +++ b/src/main/java/com/ohdab/classroom/service/usecase/UpdateClassroomInfoUsecase.java @@ -0,0 +1,8 @@ +package com.ohdab.classroom.service.usecase; + +import static com.ohdab.classroom.service.dto.ClassroomUpdateDto.ClassroomUpdateDtoRequest; + +public interface UpdateClassroomInfoUsecase { + + void updateClassroomInfo(ClassroomUpdateDtoRequest request); +} diff --git a/src/main/java/com/ohdab/classroom/service/usecase/UpdateWorkbookInfoUsecase.java b/src/main/java/com/ohdab/classroom/service/usecase/UpdateWorkbookInfoUsecase.java new file mode 100644 index 00000000..d127b2e3 --- /dev/null +++ b/src/main/java/com/ohdab/classroom/service/usecase/UpdateWorkbookInfoUsecase.java @@ -0,0 +1,8 @@ +package com.ohdab.classroom.service.usecase; + +import com.ohdab.classroom.service.dto.ClassroomWorkbookUpdateDto; + +public interface UpdateWorkbookInfoUsecase { + + void updateWorkbookInfo(ClassroomWorkbookUpdateDto.Request updateWorkbookReq); +} diff --git a/src/main/java/com/ohdab/core/exception/ExceptionEnum.java b/src/main/java/com/ohdab/core/exception/ExceptionEnum.java new file mode 100644 index 00000000..b559b734 --- /dev/null +++ b/src/main/java/com/ohdab/core/exception/ExceptionEnum.java @@ -0,0 +1,44 @@ +package com.ohdab.core.exception; + +import lombok.Getter; + +@Getter +public enum ExceptionEnum { + + // 600 - classroom + NO_CLASSROOM(600, "존재하지 않는 교실입니다."), + NO_GRADE(601, "존재하지 않는 학년입니다."), + NO_STUDENT(602, "존재하지 않는 학생입니다."), + NO_TEACHER(603, "존재하지 않는 선생님입니다."), + + // 700 - member + ALREADY_WITHDRAWL(700, "이미 탈퇴한 계정입니다."), + DUPLICATED_MEMBER(701, "이미 존재하는 회원입니다."), + NO_MEMBER(702, "존재하지 않는 회원입니다."), + MEMBER_CONTENT_OVERFLOW(703, "최대 글자수를 초과했습니다."), + NO_AUTHORITY(704, "권한정보가 누락되었습니다."), + + // 800 - mistakeNote + NO_MISTAKE_NOTE(800, "존재하지 않는 오답노트입니다."), + NO_NUMBERS_WRONG_N_TIMES(801, ""), + NUMBER_IS_OUT_OF_RANGE(802, "N번 이상 틀린 문제가 없습니다."), + MISTAKE_NUMBERS_SIZE(803, "기록 가능한 문제수를 초과했습니다."), + + // 900 - workbook + WORKBOOK_CONTENT_OVERFLOW(900, "최대 글자수를 초과했습니다."), + DUPLICATED_WORKBOOK(901, "이미 존재하는 교재입니다."), + INVALID_WORKBOOK_NUMBER_RANGE(902, "허용 범위를 벗어난 문제 번호입니다."), + NO_WORKBOOK(903, "존재하지 않는 교재입니다."), + + // 1000 - null + IS_NULL(1000, "필수 입력값이 누락되었습니다."), + ; + + private int errorCode; + private String message; + + ExceptionEnum(int errorCode, String message) { + this.errorCode = errorCode; + this.message = message; + } +} diff --git a/src/main/java/com/ohdab/core/exception/handler/ClassroomExceptionHandler.java b/src/main/java/com/ohdab/core/exception/handler/ClassroomExceptionHandler.java new file mode 100644 index 00000000..e635ce3f --- /dev/null +++ b/src/main/java/com/ohdab/core/exception/handler/ClassroomExceptionHandler.java @@ -0,0 +1,55 @@ +package com.ohdab.core.exception.handler; + +import com.ohdab.classroom.exception.NoClassroomException; +import com.ohdab.classroom.exception.NoGradeException; +import com.ohdab.classroom.exception.NoStudentException; +import com.ohdab.classroom.exception.NoTeacherException; +import com.ohdab.core.exception.ExceptionEnum; +import com.ohdab.core.template.ErrorMessage; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; + +@ControllerAdvice +public class ClassroomExceptionHandler { + + @ExceptionHandler + public ResponseEntity noClassroomException(NoClassroomException e) { + return ResponseEntity.badRequest() + .body( + ErrorMessage.builder() + .errorCode(ExceptionEnum.NO_CLASSROOM.getErrorCode()) + .message(e.getMessage()) + .build()); + } + + @ExceptionHandler + public ResponseEntity noGradeException(NoGradeException e) { + return ResponseEntity.badRequest() + .body( + ErrorMessage.builder() + .errorCode(ExceptionEnum.NO_GRADE.getErrorCode()) + .message(e.getMessage()) + .build()); + } + + @ExceptionHandler + public ResponseEntity noStudentException(NoStudentException e) { + return ResponseEntity.badRequest() + .body( + ErrorMessage.builder() + .errorCode(ExceptionEnum.NO_STUDENT.getErrorCode()) + .message(e.getMessage()) + .build()); + } + + @ExceptionHandler + public ResponseEntity noTeacherException(NoTeacherException e) { + return ResponseEntity.badRequest() + .body( + ErrorMessage.builder() + .errorCode(ExceptionEnum.NO_TEACHER.getErrorCode()) + .message(e.getMessage()) + .build()); + } +} diff --git a/src/main/java/com/ohdab/core/exception/handler/CommonExceptionHandler.java b/src/main/java/com/ohdab/core/exception/handler/CommonExceptionHandler.java new file mode 100644 index 00000000..fb20b792 --- /dev/null +++ b/src/main/java/com/ohdab/core/exception/handler/CommonExceptionHandler.java @@ -0,0 +1,21 @@ +package com.ohdab.core.exception.handler; + +import com.ohdab.core.exception.ExceptionEnum; +import com.ohdab.core.template.ErrorMessage; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; + +@ControllerAdvice +public class CommonExceptionHandler { + + @ExceptionHandler + public ResponseEntity illegalArgumentException(IllegalArgumentException e) { + return ResponseEntity.badRequest() + .body( + ErrorMessage.builder() + .errorCode(ExceptionEnum.IS_NULL.getErrorCode()) + .message(e.getMessage()) + .build()); + } +} diff --git a/src/main/java/com/ohdab/core/exception/handler/MemberExceptionHandler.java b/src/main/java/com/ohdab/core/exception/handler/MemberExceptionHandler.java new file mode 100644 index 00000000..58cdb067 --- /dev/null +++ b/src/main/java/com/ohdab/core/exception/handler/MemberExceptionHandler.java @@ -0,0 +1,62 @@ +package com.ohdab.core.exception.handler; + +import com.ohdab.core.exception.ExceptionEnum; +import com.ohdab.core.template.ErrorMessage; +import com.ohdab.member.exception.*; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; + +@ControllerAdvice +public class MemberExceptionHandler { + + @ExceptionHandler + public ResponseEntity alreadyWithdrawException(AlreadyWithdrawlException e) { + return ResponseEntity.badRequest() + .body( + ErrorMessage.builder() + .errorCode(ExceptionEnum.ALREADY_WITHDRAWL.getErrorCode()) + .message(e.getMessage()) + .build()); + } + + @ExceptionHandler + public ResponseEntity duplicatedMemberException(DuplicatedMemberException e) { + return ResponseEntity.badRequest() + .body( + ErrorMessage.builder() + .errorCode(ExceptionEnum.DUPLICATED_MEMBER.getErrorCode()) + .message(e.getMessage()) + .build()); + } + + @ExceptionHandler + public ResponseEntity noMemberException(NoMemberException e) { + return ResponseEntity.badRequest() + .body( + ErrorMessage.builder() + .errorCode(ExceptionEnum.NO_MEMBER.getErrorCode()) + .message(e.getMessage()) + .build()); + } + + @ExceptionHandler + public ResponseEntity contentOverflowException(MemberContentOverflowException e) { + return ResponseEntity.badRequest() + .body( + ErrorMessage.builder() + .errorCode(ExceptionEnum.MEMBER_CONTENT_OVERFLOW.getErrorCode()) + .message(e.getMessage()) + .build()); + } + + @ExceptionHandler + public ResponseEntity noAuthorityException(NoAuthorityException e) { + return ResponseEntity.badRequest() + .body( + ErrorMessage.builder() + .errorCode(ExceptionEnum.NO_AUTHORITY.getErrorCode()) + .message(e.getMessage()) + .build()); + } +} diff --git a/src/main/java/com/ohdab/core/exception/handler/MistakeNoteExceptionHandler.java b/src/main/java/com/ohdab/core/exception/handler/MistakeNoteExceptionHandler.java new file mode 100644 index 00000000..38b984fc --- /dev/null +++ b/src/main/java/com/ohdab/core/exception/handler/MistakeNoteExceptionHandler.java @@ -0,0 +1,56 @@ +package com.ohdab.core.exception.handler; + +import com.ohdab.core.exception.ExceptionEnum; +import com.ohdab.core.template.ErrorMessage; +import com.ohdab.mistakenote.exception.MistakeNumbersSizeException; +import com.ohdab.mistakenote.exception.NoMistakeNoteException; +import com.ohdab.mistakenote.exception.NoNumbersWrongNTimesException; +import com.ohdab.mistakenote.exception.NumberIsOutOfRangeException; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; + +@ControllerAdvice +public class MistakeNoteExceptionHandler { + + @ExceptionHandler + public ResponseEntity noMistakeException(NoMistakeNoteException e) { + return ResponseEntity.badRequest() + .body( + ErrorMessage.builder() + .errorCode(ExceptionEnum.NO_MISTAKE_NOTE.getErrorCode()) + .message(e.getMessage()) + .build()); + } + + @ExceptionHandler + public ResponseEntity noNumbersWrongNTimesException( + NoNumbersWrongNTimesException e) { + return ResponseEntity.badRequest() + .body( + ErrorMessage.builder() + .errorCode(ExceptionEnum.NO_NUMBERS_WRONG_N_TIMES.getErrorCode()) + .message(e.getMessage()) + .build()); + } + + @ExceptionHandler + public ResponseEntity numberIsOutOfRangeException(NumberIsOutOfRangeException e) { + return ResponseEntity.badRequest() + .body( + ErrorMessage.builder() + .errorCode(ExceptionEnum.NUMBER_IS_OUT_OF_RANGE.getErrorCode()) + .message(e.getMessage()) + .build()); + } + + @ExceptionHandler + public ResponseEntity mistakeNumberSizeException(MistakeNumbersSizeException e) { + return ResponseEntity.badRequest() + .body( + ErrorMessage.builder() + .errorCode(ExceptionEnum.MISTAKE_NUMBERS_SIZE.getErrorCode()) + .message(e.getMessage()) + .build()); + } +} diff --git a/src/main/java/com/ohdab/core/exception/handler/WorkbookExceptionHandler.java b/src/main/java/com/ohdab/core/exception/handler/WorkbookExceptionHandler.java new file mode 100644 index 00000000..d8f66f73 --- /dev/null +++ b/src/main/java/com/ohdab/core/exception/handler/WorkbookExceptionHandler.java @@ -0,0 +1,58 @@ +package com.ohdab.core.exception.handler; + +import com.ohdab.core.exception.ExceptionEnum; +import com.ohdab.core.template.ErrorMessage; +import com.ohdab.workbook.exception.DuplicatedWorkbookException; +import com.ohdab.workbook.exception.InvalidWorkbookNumberRangeException; +import com.ohdab.workbook.exception.NoWorkbookException; +import com.ohdab.workbook.exception.WorkbookContentOverflowException; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; + +@ControllerAdvice +public class WorkbookExceptionHandler { + + @ExceptionHandler + public ResponseEntity contentOverflowException( + WorkbookContentOverflowException e) { + return ResponseEntity.badRequest() + .body( + ErrorMessage.builder() + .errorCode(ExceptionEnum.WORKBOOK_CONTENT_OVERFLOW.getErrorCode()) + .message(e.getMessage()) + .build()); + } + + @ExceptionHandler + public ResponseEntity duplicatedWorkbookException(DuplicatedWorkbookException e) { + return ResponseEntity.badRequest() + .body( + ErrorMessage.builder() + .errorCode(ExceptionEnum.DUPLICATED_WORKBOOK.getErrorCode()) + .message(e.getMessage()) + .build()); + } + + @ExceptionHandler + public ResponseEntity invalidWorkbookNumberRangeException( + InvalidWorkbookNumberRangeException e) { + return ResponseEntity.badRequest() + .body( + ErrorMessage.builder() + .errorCode( + ExceptionEnum.INVALID_WORKBOOK_NUMBER_RANGE.getErrorCode()) + .message(e.getMessage()) + .build()); + } + + @ExceptionHandler + public ResponseEntity noWorkbookException(NoWorkbookException e) { + return ResponseEntity.badRequest() + .body( + ErrorMessage.builder() + .errorCode(ExceptionEnum.NO_WORKBOOK.getErrorCode()) + .message(e.getMessage()) + .build()); + } +} diff --git a/src/main/java/com/ohdab/core/util/event/handler/StudentAddedHandler.java b/src/main/java/com/ohdab/core/util/event/handler/StudentAddedHandler.java new file mode 100644 index 00000000..40ed849a --- /dev/null +++ b/src/main/java/com/ohdab/core/util/event/handler/StudentAddedHandler.java @@ -0,0 +1,26 @@ +package com.ohdab.core.util.event.handler; + +import com.ohdab.classroom.event.StudentAddedEvent; +import com.ohdab.member.service.dto.MemberDtoForJoin; +import com.ohdab.member.service.usecase.JoinUsecase; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class StudentAddedHandler { + + private final JoinUsecase joinUsecase; + + @EventListener(StudentAddedEvent.class) + public void join(StudentAddedEvent event) { + joinUsecase.join( + MemberDtoForJoin.Request.builder() + .name(event.getStudentName()) + .password(event.getPassword()) + .role(List.of("STUDENT")) + .build()); + } +} diff --git a/src/main/java/com/ohdab/member/controller/MemberController.java b/src/main/java/com/ohdab/member/controller/MemberController.java index 601283cd..dfd642b0 100644 --- a/src/main/java/com/ohdab/member/controller/MemberController.java +++ b/src/main/java/com/ohdab/member/controller/MemberController.java @@ -4,19 +4,11 @@ import com.ohdab.member.controller.request.AddTeacherReq; import com.ohdab.member.controller.request.JoinReq; import com.ohdab.member.controller.request.LoginReq; -import com.ohdab.member.controller.response.AddTeacherRes; -import com.ohdab.member.controller.response.DeleteTeacherRes; -import com.ohdab.member.controller.response.GetTeacherListRes; -import com.ohdab.member.controller.response.JoinRes; -import com.ohdab.member.controller.response.LoginRes; +import com.ohdab.member.controller.response.*; import com.ohdab.member.service.dto.MemberDtoForAddTeacher; import com.ohdab.member.service.dto.MemberDtoForGetTeacherList; import com.ohdab.member.service.dto.MemberDtoForLogin; -import com.ohdab.member.service.usecase.AddTeacherUsecase; -import com.ohdab.member.service.usecase.DeleteTeacherUsecase; -import com.ohdab.member.service.usecase.GetTeacherListUsecase; -import com.ohdab.member.service.usecase.JoinUsecase; -import com.ohdab.member.service.usecase.LoginUsecase; +import com.ohdab.member.service.usecase.*; import java.util.List; import javax.validation.Valid; import lombok.RequiredArgsConstructor; @@ -33,6 +25,7 @@ public class MemberController { private final GetTeacherListUsecase getTeacherListUsecase; private final AddTeacherUsecase addTeacherUsecase; private final DeleteTeacherUsecase deleteTeacherUsecase; + private final WithdrawlUsecase withdrawlUsecase; @PostMapping("/join") public ResponseEntity join(@Valid @RequestBody JoinReq joinReq) { @@ -47,9 +40,10 @@ public ResponseEntity login(@Valid @RequestBody LoginReq loginReq) { return ResponseEntity.ok(MemberWebMapper.toLoginRes(loginResDto)); } - @GetMapping("/test") - public String adminAndTokenTest() { - return "hohoho"; + @PatchMapping("/withdrawl/{member-id}") + public ResponseEntity withdrawl(@PathVariable(name = "member-id") long memberId) { + withdrawlUsecase.withdrawl(memberId); + return ResponseEntity.ok(MemberWebMapper.createWithdrawlRes()); } @GetMapping("/teachers") diff --git a/src/main/java/com/ohdab/member/controller/mapper/MemberWebMapper.java b/src/main/java/com/ohdab/member/controller/mapper/MemberWebMapper.java index 3097a5d7..4829ad56 100644 --- a/src/main/java/com/ohdab/member/controller/mapper/MemberWebMapper.java +++ b/src/main/java/com/ohdab/member/controller/mapper/MemberWebMapper.java @@ -3,11 +3,7 @@ import com.ohdab.member.controller.request.AddTeacherReq; import com.ohdab.member.controller.request.JoinReq; import com.ohdab.member.controller.request.LoginReq; -import com.ohdab.member.controller.response.AddTeacherRes; -import com.ohdab.member.controller.response.DeleteTeacherRes; -import com.ohdab.member.controller.response.GetTeacherListRes; -import com.ohdab.member.controller.response.JoinRes; -import com.ohdab.member.controller.response.LoginRes; +import com.ohdab.member.controller.response.*; import com.ohdab.member.service.dto.MemberDtoForAddTeacher; import com.ohdab.member.service.dto.MemberDtoForGetTeacherList; import com.ohdab.member.service.dto.MemberDtoForJoin; @@ -76,4 +72,8 @@ public static AddTeacherRes createAddTeacherRes() { public static DeleteTeacherRes createDeleteTeacherRes() { return DeleteTeacherRes.builder().message("선생님 삭제 및 탈퇴에 성공하였습니다.").build(); } + + public static WithdrawlRes createWithdrawlRes() { + return WithdrawlRes.builder().message("탈퇴되었습니다.").build(); + } } diff --git a/src/main/java/com/ohdab/member/controller/response/DeleteStudentRes.java b/src/main/java/com/ohdab/member/controller/response/DeleteStudentRes.java new file mode 100644 index 00000000..9c8364a4 --- /dev/null +++ b/src/main/java/com/ohdab/member/controller/response/DeleteStudentRes.java @@ -0,0 +1,11 @@ +package com.ohdab.member.controller.response; + +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class DeleteStudentRes { + + private String message; +} diff --git a/src/main/java/com/ohdab/member/controller/response/WithdrawlRes.java b/src/main/java/com/ohdab/member/controller/response/WithdrawlRes.java new file mode 100644 index 00000000..3f210609 --- /dev/null +++ b/src/main/java/com/ohdab/member/controller/response/WithdrawlRes.java @@ -0,0 +1,11 @@ +package com.ohdab.member.controller.response; + +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class WithdrawlRes { + + private String message; +} diff --git a/src/main/java/com/ohdab/member/domain/Member.java b/src/main/java/com/ohdab/member/domain/Member.java index e7a49bda..7cea412a 100644 --- a/src/main/java/com/ohdab/member/domain/Member.java +++ b/src/main/java/com/ohdab/member/domain/Member.java @@ -1,7 +1,13 @@ package com.ohdab.member.domain; import com.ohdab.core.baseentity.BaseEntity; +import com.ohdab.core.exception.ExceptionEnum; import com.ohdab.member.domain.memberinfo.MemberInfo; +import com.ohdab.member.exception.AlreadyWithdrawlException; +import com.ohdab.member.exception.MemberContentOverflowException; +import com.ohdab.member.exception.NoAuthorityException; +import io.jsonwebtoken.lang.Assert; +import java.util.ArrayList; import java.util.List; import javax.persistence.*; import lombok.AccessLevel; @@ -30,13 +36,15 @@ public class Member extends BaseEntity { @ElementCollection @CollectionTable(name = "MEMBER_AUTHORITY", joinColumns = @JoinColumn(name = "member_id")) - private List authorities; + private List authorities = new ArrayList<>(); @Enumerated(EnumType.STRING) private MemberStatus status; @Builder public Member(MemberInfo memberInfo, List authorities) { + Assert.notNull(memberInfo, ExceptionEnum.IS_NULL.getMessage()); + Assert.notNull(authorities, ExceptionEnum.IS_NULL.getMessage()); setMemberInfo(memberInfo); setAuthorities(authorities); this.status = MemberStatus.ACTIVE; @@ -44,17 +52,15 @@ public Member(MemberInfo memberInfo, List authorities) { private void setAuthorities(List authorities) { if (authorities.isEmpty()) { - throw new IllegalArgumentException("권한은 반드시 추가해야함"); + throw new NoAuthorityException(ExceptionEnum.NO_AUTHORITY.getMessage()); } this.authorities = authorities; } private void setMemberInfo(MemberInfo memberInfo) { if (memberInfo.getName().length() > 20) { - throw new IllegalStateException( - "Name length cannot exceed 20 : current length \"" - + memberInfo.getName().length() - + "\""); + throw new MemberContentOverflowException( + ExceptionEnum.MEMBER_CONTENT_OVERFLOW.getMessage()); } this.memberInfo = memberInfo; } @@ -66,7 +72,7 @@ public boolean matchPassword( public void withdrawal() { if (this.status == MemberStatus.INACTIVE) { - throw new IllegalStateException("예외"); + throw new AlreadyWithdrawlException(ExceptionEnum.ALREADY_WITHDRAWL.getMessage()); } this.status = MemberStatus.INACTIVE; } diff --git a/src/main/java/com/ohdab/member/exception/AlreadyWithdrawlException.java b/src/main/java/com/ohdab/member/exception/AlreadyWithdrawlException.java new file mode 100644 index 00000000..a42c0cd1 --- /dev/null +++ b/src/main/java/com/ohdab/member/exception/AlreadyWithdrawlException.java @@ -0,0 +1,18 @@ +package com.ohdab.member.exception; + +public class AlreadyWithdrawlException extends RuntimeException { + + public AlreadyWithdrawlException() {} + + public AlreadyWithdrawlException(String message) { + super(message); + } + + public AlreadyWithdrawlException(String message, Throwable cause) { + super(message, cause); + } + + public AlreadyWithdrawlException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/com/ohdab/member/exception/MemberContentOverflowException.java b/src/main/java/com/ohdab/member/exception/MemberContentOverflowException.java new file mode 100644 index 00000000..266519c1 --- /dev/null +++ b/src/main/java/com/ohdab/member/exception/MemberContentOverflowException.java @@ -0,0 +1,18 @@ +package com.ohdab.member.exception; + +public class MemberContentOverflowException extends RuntimeException { + + public MemberContentOverflowException() {} + + public MemberContentOverflowException(String message) { + super(message); + } + + public MemberContentOverflowException(String message, Throwable cause) { + super(message, cause); + } + + public MemberContentOverflowException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/com/ohdab/member/exception/NoAuthorityException.java b/src/main/java/com/ohdab/member/exception/NoAuthorityException.java new file mode 100644 index 00000000..610b2a31 --- /dev/null +++ b/src/main/java/com/ohdab/member/exception/NoAuthorityException.java @@ -0,0 +1,18 @@ +package com.ohdab.member.exception; + +public class NoAuthorityException extends RuntimeException { + + public NoAuthorityException() {} + + public NoAuthorityException(String message) { + super(message); + } + + public NoAuthorityException(String message, Throwable cause) { + super(message, cause); + } + + public NoAuthorityException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/com/ohdab/member/repository/MemberRepository.java b/src/main/java/com/ohdab/member/repository/MemberRepository.java index 86adad8a..ddeee0c3 100644 --- a/src/main/java/com/ohdab/member/repository/MemberRepository.java +++ b/src/main/java/com/ohdab/member/repository/MemberRepository.java @@ -16,5 +16,5 @@ public interface MemberRepository extends JpaRepository { Long countByMemberInfoNameContaining(String name); - boolean existsById(long id); + Optional findActiveMemberById(long memberId); } diff --git a/src/main/java/com/ohdab/member/repository/mapper/MemberMapper.java b/src/main/java/com/ohdab/member/repository/mapper/MemberMapper.java new file mode 100644 index 00000000..2131b97e --- /dev/null +++ b/src/main/java/com/ohdab/member/repository/mapper/MemberMapper.java @@ -0,0 +1,12 @@ +package com.ohdab.member.repository.mapper; + +import static com.ohdab.mistakenote.service.dto.GetAllMistakeNoteInfoDto.Response.StudentInfoDto; + +import java.util.List; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface MemberMapper { + + List findAllStudent(List studentIdList); +} diff --git a/src/main/java/com/ohdab/member/service/AddTeacherService.java b/src/main/java/com/ohdab/member/service/AddTeacherService.java index fe29a39c..d25031c9 100644 --- a/src/main/java/com/ohdab/member/service/AddTeacherService.java +++ b/src/main/java/com/ohdab/member/service/AddTeacherService.java @@ -1,10 +1,12 @@ package com.ohdab.member.service; +import static com.ohdab.member.service.helper.MemberHelperService.checkIfMemberExistByName; + +import com.ohdab.core.exception.ExceptionEnum; import com.ohdab.member.exception.NoMemberException; import com.ohdab.member.repository.MemberRepository; import com.ohdab.member.service.dto.MemberDtoForAddTeacher; import com.ohdab.member.service.dto.MemberDtoForJoin; -import com.ohdab.member.service.helper.MemberHelperService; import com.ohdab.member.service.usecase.AddTeacherUsecase; import com.ohdab.member.service.usecase.JoinUsecase; import java.util.List; @@ -19,7 +21,6 @@ public class AddTeacherService implements AddTeacherUsecase { private final MemberRepository memberRepository; private final JoinUsecase joinUsecase; - private final MemberHelperService memberHelperService; @Override public void addTeacher(MemberDtoForAddTeacher.Request addTeacherReqDto) { @@ -38,7 +39,7 @@ public void addTeacher(MemberDtoForAddTeacher.Request addTeacherReqDto) { } private String changeNameIfDuplicated(String name) { - if (memberHelperService.checkIfMemberExistByName(memberRepository, name)) { + if (checkIfMemberExistByName(memberRepository, name)) { long sameNameCount = memberRepository.countByMemberInfoNameContaining(name); return name = name + sameNameCount; } @@ -46,8 +47,8 @@ private String changeNameIfDuplicated(String name) { } private void throwIfJoinFailed(String name) { - if (!memberHelperService.checkIfMemberExistByName(memberRepository, name)) { - throw new NoMemberException("Join Failed with teacher name \"" + name + "\""); + if (!checkIfMemberExistByName(memberRepository, name)) { + throw new NoMemberException(ExceptionEnum.NO_MEMBER.getMessage()); } } } diff --git a/src/main/java/com/ohdab/member/service/DeleteTeacherService.java b/src/main/java/com/ohdab/member/service/DeleteTeacherService.java index 56c2298b..65e1138b 100644 --- a/src/main/java/com/ohdab/member/service/DeleteTeacherService.java +++ b/src/main/java/com/ohdab/member/service/DeleteTeacherService.java @@ -1,9 +1,10 @@ package com.ohdab.member.service; +import static com.ohdab.member.service.helper.MemberHelperService.findExistingMemberById; + import com.ohdab.member.domain.Member; import com.ohdab.member.domain.MemberStatus; import com.ohdab.member.repository.MemberRepository; -import com.ohdab.member.service.helper.MemberHelperService; import com.ohdab.member.service.usecase.DeleteTeacherUsecase; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -15,11 +16,10 @@ public class DeleteTeacherService implements DeleteTeacherUsecase { private final MemberRepository memberRepository; - private final MemberHelperService memberHelperService; @Override public void deleteTeacherById(long id) { - Member member = memberHelperService.findExistingMemberById(memberRepository, id); + Member member = findExistingMemberById(memberRepository, id); throwIfInactiveMember(member); member.withdrawal(); } diff --git a/src/main/java/com/ohdab/member/service/JoinService.java b/src/main/java/com/ohdab/member/service/JoinService.java index 28466b09..26d68467 100644 --- a/src/main/java/com/ohdab/member/service/JoinService.java +++ b/src/main/java/com/ohdab/member/service/JoinService.java @@ -1,5 +1,6 @@ package com.ohdab.member.service; +import com.ohdab.core.exception.ExceptionEnum; import com.ohdab.member.domain.Authority; import com.ohdab.member.domain.Member; import com.ohdab.member.domain.memberinfo.MemberInfo; @@ -34,7 +35,7 @@ public void join(MemberDtoForJoin.Request joinReqDto) { private void checkDuplicatedMember(String name) { Optional member = memberRepository.findByMemberInfoName(name); if (member.isPresent()) { - throw new DuplicatedMemberException("이미 존재하는 회원입니다."); + throw new DuplicatedMemberException(ExceptionEnum.DUPLICATED_WORKBOOK.getMessage()); } } diff --git a/src/main/java/com/ohdab/member/service/LoginService.java b/src/main/java/com/ohdab/member/service/LoginService.java index fb25e982..e121414d 100644 --- a/src/main/java/com/ohdab/member/service/LoginService.java +++ b/src/main/java/com/ohdab/member/service/LoginService.java @@ -1,10 +1,11 @@ package com.ohdab.member.service; +import static com.ohdab.member.service.helper.MemberHelperService.findExistingMemberByName; + import com.ohdab.core.util.jwt.JwtTokenProvider; import com.ohdab.member.domain.Member; import com.ohdab.member.repository.MemberRepository; import com.ohdab.member.service.dto.MemberDtoForLogin; -import com.ohdab.member.service.helper.MemberHelperService; import com.ohdab.member.service.usecase.LoginUsecase; import lombok.RequiredArgsConstructor; import org.springframework.security.authentication.BadCredentialsException; @@ -22,7 +23,6 @@ public class LoginService implements LoginUsecase { private final MemberRepository memberRepository; - private final MemberHelperService memberHelperService; private final UserDetailsService userDetailsService; private final JwtTokenProvider jwtTokenProvider; private final PasswordEncoder passwordEncoder; @@ -30,9 +30,7 @@ public class LoginService implements LoginUsecase { @Override public MemberDtoForLogin.Response login(MemberDtoForLogin.Request loginReqDto) { UserDetails userDetails = userDetailsService.loadUserByUsername(loginReqDto.getName()); - Member member = - memberHelperService.findExistingMemberByName( - memberRepository, loginReqDto.getName()); + Member member = findExistingMemberByName(memberRepository, loginReqDto.getName()); if (!member.matchPassword( passwordEncoder, loginReqDto.getPassword(), userDetails.getPassword())) { throw new BadCredentialsException("비밀번호가 일치하지 않습니다."); diff --git a/src/main/java/com/ohdab/member/service/UserDetailServiceImpl.java b/src/main/java/com/ohdab/member/service/UserDetailServiceImpl.java index ba9e2aed..ceccb6fc 100644 --- a/src/main/java/com/ohdab/member/service/UserDetailServiceImpl.java +++ b/src/main/java/com/ohdab/member/service/UserDetailServiceImpl.java @@ -1,8 +1,9 @@ package com.ohdab.member.service; +import static com.ohdab.member.service.helper.MemberHelperService.findExistingMemberByName; + import com.ohdab.member.domain.Member; import com.ohdab.member.repository.MemberRepository; -import com.ohdab.member.service.helper.MemberHelperService; import java.util.List; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; @@ -18,11 +19,10 @@ public class UserDetailServiceImpl implements UserDetailsService { private final MemberRepository memberRepository; - private final MemberHelperService memberHelperService; @Override public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException { - Member member = memberHelperService.findExistingMemberByName(memberRepository, name); + Member member = findExistingMemberByName(memberRepository, name); return createUserDetails(member); } diff --git a/src/main/java/com/ohdab/member/service/WithdrawlService.java b/src/main/java/com/ohdab/member/service/WithdrawlService.java new file mode 100644 index 00000000..eb8df379 --- /dev/null +++ b/src/main/java/com/ohdab/member/service/WithdrawlService.java @@ -0,0 +1,15 @@ +package com.ohdab.member.service; + +import com.ohdab.member.service.usecase.WithdrawlUsecase; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional +public class WithdrawlService implements WithdrawlUsecase { + + @Override + public void withdrawl(long memberId) {} +} diff --git a/src/main/java/com/ohdab/member/service/dto/MemberDtoForAddTeacher.java b/src/main/java/com/ohdab/member/service/dto/MemberDtoForAddTeacher.java index 7531ca45..e0c0c1a4 100644 --- a/src/main/java/com/ohdab/member/service/dto/MemberDtoForAddTeacher.java +++ b/src/main/java/com/ohdab/member/service/dto/MemberDtoForAddTeacher.java @@ -1,10 +1,11 @@ package com.ohdab.member.service.dto; +import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; +import lombok.NoArgsConstructor; -@Getter -@Builder +@NoArgsConstructor(access = AccessLevel.PROTECTED) public class MemberDtoForAddTeacher { @Builder diff --git a/src/main/java/com/ohdab/member/service/dto/MemberDtoForGetTeacherList.java b/src/main/java/com/ohdab/member/service/dto/MemberDtoForGetTeacherList.java index d1b9970f..21faeb2c 100644 --- a/src/main/java/com/ohdab/member/service/dto/MemberDtoForGetTeacherList.java +++ b/src/main/java/com/ohdab/member/service/dto/MemberDtoForGetTeacherList.java @@ -1,11 +1,12 @@ package com.ohdab.member.service.dto; import java.util.List; +import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; +import lombok.NoArgsConstructor; -@Builder -@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) public class MemberDtoForGetTeacherList { @Builder diff --git a/src/main/java/com/ohdab/member/service/dto/MemberDtoForJoin.java b/src/main/java/com/ohdab/member/service/dto/MemberDtoForJoin.java index c36df827..a14fc777 100644 --- a/src/main/java/com/ohdab/member/service/dto/MemberDtoForJoin.java +++ b/src/main/java/com/ohdab/member/service/dto/MemberDtoForJoin.java @@ -1,11 +1,12 @@ package com.ohdab.member.service.dto; import java.util.List; +import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; +import lombok.NoArgsConstructor; -@Getter -@Builder +@NoArgsConstructor(access = AccessLevel.PROTECTED) public class MemberDtoForJoin { @Builder diff --git a/src/main/java/com/ohdab/member/service/dto/MemberDtoForLogin.java b/src/main/java/com/ohdab/member/service/dto/MemberDtoForLogin.java index 1137d91c..c68bd001 100644 --- a/src/main/java/com/ohdab/member/service/dto/MemberDtoForLogin.java +++ b/src/main/java/com/ohdab/member/service/dto/MemberDtoForLogin.java @@ -1,10 +1,11 @@ package com.ohdab.member.service.dto; +import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; +import lombok.NoArgsConstructor; -@Getter -@Builder +@NoArgsConstructor(access = AccessLevel.PROTECTED) public class MemberDtoForLogin { @Getter diff --git a/src/main/java/com/ohdab/member/service/helper/MemberHelperService.java b/src/main/java/com/ohdab/member/service/helper/MemberHelperService.java index 39127bca..1c027dba 100644 --- a/src/main/java/com/ohdab/member/service/helper/MemberHelperService.java +++ b/src/main/java/com/ohdab/member/service/helper/MemberHelperService.java @@ -1,28 +1,28 @@ package com.ohdab.member.service.helper; +import com.ohdab.core.exception.ExceptionEnum; import com.ohdab.member.domain.Member; import com.ohdab.member.exception.NoMemberException; import com.ohdab.member.repository.MemberRepository; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; -@Service -@RequiredArgsConstructor +@NoArgsConstructor(access = AccessLevel.PROTECTED) public final class MemberHelperService { - public Member findExistingMemberByName(MemberRepository memberRepository, String name) { + public static Member findExistingMemberByName(MemberRepository memberRepository, String name) { return memberRepository .findByMemberInfoName(name) - .orElseThrow(() -> new NoMemberException("존재하지 않는 회원입니다.")); + .orElseThrow(() -> new NoMemberException(ExceptionEnum.NO_MEMBER.getMessage())); } - public Member findExistingMemberById(MemberRepository memberRepository, long id) { + public static Member findExistingMemberById(MemberRepository memberRepository, long id) { return memberRepository .findById(id) - .orElseThrow(() -> new NoMemberException("Unknown member with id \"" + id + "\"")); + .orElseThrow(() -> new NoMemberException(ExceptionEnum.NO_MEMBER.getMessage())); } - public boolean checkIfMemberExistByName(MemberRepository memberRepository, String name) { + public static boolean checkIfMemberExistByName(MemberRepository memberRepository, String name) { return memberRepository.existsByMemberInfoName(name); } } diff --git a/src/main/java/com/ohdab/member/service/usecase/WithdrawlUsecase.java b/src/main/java/com/ohdab/member/service/usecase/WithdrawlUsecase.java new file mode 100644 index 00000000..d8aecbe5 --- /dev/null +++ b/src/main/java/com/ohdab/member/service/usecase/WithdrawlUsecase.java @@ -0,0 +1,6 @@ +package com.ohdab.member.service.usecase; + +public interface WithdrawlUsecase { + + void withdrawl(long memberId); +} diff --git a/src/main/java/com/ohdab/mistakenote/controller/MistakeNoteController.java b/src/main/java/com/ohdab/mistakenote/controller/MistakeNoteController.java new file mode 100644 index 00000000..17487b26 --- /dev/null +++ b/src/main/java/com/ohdab/mistakenote/controller/MistakeNoteController.java @@ -0,0 +1,73 @@ +package com.ohdab.mistakenote.controller; + +import com.ohdab.mistakenote.controller.mapper.MistakeNoteMapper; +import com.ohdab.mistakenote.controller.request.SaveMistakeNoteInfoReq; +import com.ohdab.mistakenote.controller.response.GetAllMistakeNoteInfoRes; +import com.ohdab.mistakenote.controller.response.GetMistakeNoteInfoOfStudentRes; +import com.ohdab.mistakenote.controller.response.GetNumberWrongNTimes; +import com.ohdab.mistakenote.controller.response.SaveMistakeNoteInfoRes; +import com.ohdab.mistakenote.service.dto.GetAllMistakeNoteInfoDto; +import com.ohdab.mistakenote.service.dto.GetMistakeNoteInfoOfStudentDto; +import com.ohdab.mistakenote.service.dto.GetNumberWrongNTimesDto; +import com.ohdab.mistakenote.service.usecase.GetMistakeNoteInfoUsecase; +import com.ohdab.mistakenote.service.usecase.GetNumberWrongNTimesUsecase; +import com.ohdab.mistakenote.service.usecase.SaveMistakeNoteInfoUsecase; +import java.util.List; +import javax.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/mistake-notes") +public class MistakeNoteController { + + private final GetMistakeNoteInfoUsecase getMistakeNoteInfoUsecase; + private final GetNumberWrongNTimesUsecase getNumberWrongNTimesUsecase; + private final SaveMistakeNoteInfoUsecase saveMistakeNoteInfoUsecase; + + @GetMapping("/workbooks/{workbook-id}/students/{student-id}") + public ResponseEntity> getMistakeNoteInfoOfStudent( + @PathVariable(name = "workbook-id") long workbookId, + @PathVariable(name = "student-id") long studentId) { + GetMistakeNoteInfoOfStudentDto.Response mistakeNoteInfo = + getMistakeNoteInfoUsecase.getMistakeNoteInfoOfStudent(workbookId, studentId); + return ResponseEntity.ok( + MistakeNoteMapper.toGetMistakeNoteInfoOfStudentRes(mistakeNoteInfo)); + } + + @GetMapping("/workbooks/{workbook-id}/{mistake-note-id}") + public ResponseEntity getNumberWrongNTimes( + @PathVariable(name = "workbook-id") long workbookId, + @PathVariable(name = "mistake-note-id") long mistakeNoteId, + @RequestParam(name = "count") int count, + @RequestParam(name = "from") int from, + @RequestParam(name = "to") int to) { + GetNumberWrongNTimesDto.Response numberWrongNTimes = + getNumberWrongNTimesUsecase.getNumberWrongNTimes( + MistakeNoteMapper.toGetNumberWrongNTimeDto( + workbookId, mistakeNoteId, count, from, to)); + return ResponseEntity.ok(MistakeNoteMapper.toGetNumberWrongNTimesRes(numberWrongNTimes)); + } + + @PostMapping("/workbooks/{workbook-id}/students/{student-id}") + public ResponseEntity saveMistakeNoteInfo( + @PathVariable(name = "workbook-id") long workbookId, + @PathVariable(name = "student-id") long studentId, + @Valid @RequestBody SaveMistakeNoteInfoReq saveMistakeNoteInfoReq) { + saveMistakeNoteInfoUsecase.saveMistakeNoteInfo( + MistakeNoteMapper.toSaveMistakeNoteInfoDto( + workbookId, studentId, saveMistakeNoteInfoReq)); + return ResponseEntity.ok(SaveMistakeNoteInfoRes.builder().message("오답이 기록되었습니다.").build()); + } + + @GetMapping("/workbooks/{workbook-id}") + public ResponseEntity getAllMistakeNoteInfo( + @PathVariable(name = "workbook-id") long workbookId) { + GetAllMistakeNoteInfoDto.Response getAllMistakeNoteInfoDto = + getMistakeNoteInfoUsecase.getAllMistakeNoteInfo(workbookId); + return ResponseEntity.ok( + MistakeNoteMapper.toGetAllMistakeNoteInfoRes(getAllMistakeNoteInfoDto)); + } +} diff --git a/src/main/java/com/ohdab/mistakenote/controller/mapper/MistakeNoteMapper.java b/src/main/java/com/ohdab/mistakenote/controller/mapper/MistakeNoteMapper.java new file mode 100644 index 00000000..14fd25d6 --- /dev/null +++ b/src/main/java/com/ohdab/mistakenote/controller/mapper/MistakeNoteMapper.java @@ -0,0 +1,92 @@ +package com.ohdab.mistakenote.controller.mapper; + +import com.ohdab.mistakenote.controller.request.SaveMistakeNoteInfoReq; +import com.ohdab.mistakenote.controller.response.GetAllMistakeNoteInfoRes; +import com.ohdab.mistakenote.controller.response.GetMistakeNoteInfoOfStudentRes; +import com.ohdab.mistakenote.controller.response.GetNumberWrongNTimes; +import com.ohdab.mistakenote.service.dto.GetAllMistakeNoteInfoDto; +import com.ohdab.mistakenote.service.dto.GetAllMistakeNoteInfoDto.Response.StudentInfoDto; +import com.ohdab.mistakenote.service.dto.GetMistakeNoteInfoOfStudentDto; +import com.ohdab.mistakenote.service.dto.GetNumberWrongNTimesDto; +import com.ohdab.mistakenote.service.dto.SaveMistakeNoteInfoDto; +import java.util.List; +import java.util.stream.Collectors; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class MistakeNoteMapper { + + public static List toGetMistakeNoteInfoOfStudentRes( + GetMistakeNoteInfoOfStudentDto.Response responseDto) { + return responseDto.getMistakeNoteInfo().stream() + .map( + dto -> + GetMistakeNoteInfoOfStudentRes.builder() + .wrongNumber(dto.getWrongNumber()) + .wrongCount(dto.getWrongCount()) + .build()) + .collect(Collectors.toList()); + } + + public static SaveMistakeNoteInfoDto toSaveMistakeNoteInfoDto( + long workbookId, long studentId, SaveMistakeNoteInfoReq saveMistakeNoteInfoReq) { + return SaveMistakeNoteInfoDto.builder() + .workbookId(workbookId) + .studentId(studentId) + .mistakeNumbers(saveMistakeNoteInfoReq.getMistakeNumbers()) + .build(); + } + + public static GetAllMistakeNoteInfoRes toGetAllMistakeNoteInfoRes( + GetAllMistakeNoteInfoDto.Response responseDto) { + return GetAllMistakeNoteInfoRes.builder() + .students(mapToStudentInfoRes(responseDto.getStudents())) + .mistakeNoteInfo( + mapToMistakeNoteInfoOfStudentRes(responseDto.getAllMistakeNoteInfo())) + .build(); + } + + private static List mapToStudentInfoRes( + List students) { + return students.stream() + .map( + dto -> + GetAllMistakeNoteInfoRes.StudentInfoRes.builder() + .studentId(dto.getStudentId()) + .name(dto.getName()) + .build()) + .collect(Collectors.toList()); + } + + private static List + mapToMistakeNoteInfoOfStudentRes( + List mistakeNoteInfo) { + return mistakeNoteInfo.stream() + .map( + dto -> + GetAllMistakeNoteInfoRes.AllMistakeNoteInfoRes.builder() + .wrongNumber(dto.getWrongNumber()) + .wrongStudentsCount(dto.getWrongStudentsCount()) + .build()) + .collect(Collectors.toList()); + } + + public static GetNumberWrongNTimesDto.Request toGetNumberWrongNTimeDto( + long workbookId, long mistakeNoteId, int count, int from, int to) { + return GetNumberWrongNTimesDto.Request.builder() + .workbookId(workbookId) + .mistakeNoteId(mistakeNoteId) + .count(count) + .from(from) + .to(to) + .build(); + } + + public static GetNumberWrongNTimes toGetNumberWrongNTimesRes( + GetNumberWrongNTimesDto.Response numbersWrongNTimes) { + return GetNumberWrongNTimes.builder() + .wrongNumber(numbersWrongNTimes.getWrongNumber()) + .build(); + } +} diff --git a/src/main/java/com/ohdab/mistakenote/controller/request/SaveMistakeNoteInfoReq.java b/src/main/java/com/ohdab/mistakenote/controller/request/SaveMistakeNoteInfoReq.java new file mode 100644 index 00000000..62ee7df2 --- /dev/null +++ b/src/main/java/com/ohdab/mistakenote/controller/request/SaveMistakeNoteInfoReq.java @@ -0,0 +1,17 @@ +package com.ohdab.mistakenote.controller.request; + +import java.util.List; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import lombok.*; + +@Getter +@Builder +@AllArgsConstructor +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class SaveMistakeNoteInfoReq { + + @NotNull(message = "기록할 문제 번호를 하나 이상 입력해야 합니다.") + @Size(min = 1, max = 6000) + private List mistakeNumbers; +} diff --git a/src/main/java/com/ohdab/mistakenote/controller/response/GetAllMistakeNoteInfoRes.java b/src/main/java/com/ohdab/mistakenote/controller/response/GetAllMistakeNoteInfoRes.java new file mode 100644 index 00000000..bdc9095d --- /dev/null +++ b/src/main/java/com/ohdab/mistakenote/controller/response/GetAllMistakeNoteInfoRes.java @@ -0,0 +1,29 @@ +package com.ohdab.mistakenote.controller.response; + +import java.util.List; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class GetAllMistakeNoteInfoRes { + + private List students; + private List mistakeNoteInfo; + + @Getter + @Builder + public static class StudentInfoRes { + + private long studentId; + private String name; + } + + @Getter + @Builder + public static class AllMistakeNoteInfoRes { + + private int wrongNumber; + private int wrongStudentsCount; + } +} diff --git a/src/main/java/com/ohdab/mistakenote/controller/response/GetMistakeNoteInfoOfStudentRes.java b/src/main/java/com/ohdab/mistakenote/controller/response/GetMistakeNoteInfoOfStudentRes.java new file mode 100644 index 00000000..f5688208 --- /dev/null +++ b/src/main/java/com/ohdab/mistakenote/controller/response/GetMistakeNoteInfoOfStudentRes.java @@ -0,0 +1,12 @@ +package com.ohdab.mistakenote.controller.response; + +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class GetMistakeNoteInfoOfStudentRes { + + private int wrongNumber; + private int wrongCount; +} diff --git a/src/main/java/com/ohdab/mistakenote/controller/response/GetNumberWrongNTimes.java b/src/main/java/com/ohdab/mistakenote/controller/response/GetNumberWrongNTimes.java new file mode 100644 index 00000000..45ff2e73 --- /dev/null +++ b/src/main/java/com/ohdab/mistakenote/controller/response/GetNumberWrongNTimes.java @@ -0,0 +1,11 @@ +package com.ohdab.mistakenote.controller.response; + +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class GetNumberWrongNTimes { + + private String wrongNumber; +} diff --git a/src/main/java/com/ohdab/mistakenote/controller/response/SaveMistakeNoteInfoRes.java b/src/main/java/com/ohdab/mistakenote/controller/response/SaveMistakeNoteInfoRes.java new file mode 100644 index 00000000..66fdcf92 --- /dev/null +++ b/src/main/java/com/ohdab/mistakenote/controller/response/SaveMistakeNoteInfoRes.java @@ -0,0 +1,11 @@ +package com.ohdab.mistakenote.controller.response; + +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class SaveMistakeNoteInfoRes { + + private String message; +} diff --git a/src/main/java/com/ohdab/mistakenote/domain/MistakeNote.java b/src/main/java/com/ohdab/mistakenote/domain/MistakeNote.java index f2bb2c0f..3b41e32f 100644 --- a/src/main/java/com/ohdab/mistakenote/domain/MistakeNote.java +++ b/src/main/java/com/ohdab/mistakenote/domain/MistakeNote.java @@ -1,8 +1,13 @@ package com.ohdab.mistakenote.domain; import com.ohdab.core.baseentity.BaseEntity; +import com.ohdab.core.exception.ExceptionEnum; import com.ohdab.member.domain.student.studentid.StudentId; +import com.ohdab.mistakenote.exception.MistakeNumbersSizeException; +import com.ohdab.workbook.domain.Workbook; +import com.ohdab.workbook.domain.service.NumberScopeCheckService; import com.ohdab.workbook.domain.workbookid.WorkbookId; +import io.jsonwebtoken.lang.Assert; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -40,22 +45,47 @@ public class MistakeNote extends BaseEntity { @Builder public MistakeNote( WorkbookId workbookId, StudentId studentId, Map mistakeRecords) { + Assert.notNull(workbookId, ExceptionEnum.IS_NULL.getMessage()); + Assert.notNull(studentId, ExceptionEnum.IS_NULL.getMessage()); this.workbookId = workbookId; this.studentId = studentId; + setMistakeRecords(mistakeRecords); + } + + private void setMistakeRecords(Map mistakeRecords) { + if (mistakeRecords == null) mistakeRecords = new HashMap<>(); this.mistakeRecords = mistakeRecords; } - // TODO: refactoring - public void addMistakeNumbers(List numbers) { - if (numbers.isEmpty()) { - throw new IllegalArgumentException("예외"); - } - for (int number : numbers) { - if (mistakeRecords.containsKey(number)) { - mistakeRecords.put(number, mistakeRecords.get(number) + 1); - continue; - } - mistakeRecords.put(number, 1); + @Builder + public MistakeNote(WorkbookId workbookId, StudentId studentId) { + this.workbookId = workbookId; + this.studentId = studentId; + } + + public void addMistakeNumbers( + NumberScopeCheckService numberScopeCheckService, + Workbook workbook, + List numbers) { + numberScopeCheckService.numberScopeCheck(workbook, numbers); + checkMistakeNumbersSize(numbers); + updateWrongCount(numbers); + } + + private void checkMistakeNumbersSize(List numbers) { + if (numbers.isEmpty() || numbers.size() > 500) { + throw new MistakeNumbersSizeException(ExceptionEnum.MISTAKE_NUMBERS_SIZE.getMessage()); } } + + private void updateWrongCount(List numbers) { + numbers.forEach( + number -> { + if (mistakeRecords.containsKey(number)) { + mistakeRecords.put(number, mistakeRecords.get(number) + 1); + } else { + mistakeRecords.put(number, 1); + } + }); + } } diff --git a/src/main/java/com/ohdab/mistakenote/exception/MistakeNumbersSizeException.java b/src/main/java/com/ohdab/mistakenote/exception/MistakeNumbersSizeException.java new file mode 100644 index 00000000..3c04ead4 --- /dev/null +++ b/src/main/java/com/ohdab/mistakenote/exception/MistakeNumbersSizeException.java @@ -0,0 +1,18 @@ +package com.ohdab.mistakenote.exception; + +public class MistakeNumbersSizeException extends RuntimeException { + + public MistakeNumbersSizeException() {} + + public MistakeNumbersSizeException(String message) { + super(message); + } + + public MistakeNumbersSizeException(String message, Throwable cause) { + super(message, cause); + } + + public MistakeNumbersSizeException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/com/ohdab/mistakenote/exception/NoMistakeNoteException.java b/src/main/java/com/ohdab/mistakenote/exception/NoMistakeNoteException.java new file mode 100644 index 00000000..aaad1f6e --- /dev/null +++ b/src/main/java/com/ohdab/mistakenote/exception/NoMistakeNoteException.java @@ -0,0 +1,18 @@ +package com.ohdab.mistakenote.exception; + +public class NoMistakeNoteException extends RuntimeException { + + public NoMistakeNoteException() {} + + public NoMistakeNoteException(String message) { + super(message); + } + + public NoMistakeNoteException(String message, Throwable cause) { + super(message, cause); + } + + public NoMistakeNoteException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/com/ohdab/mistakenote/exception/NoNumbersWrongNTimesException.java b/src/main/java/com/ohdab/mistakenote/exception/NoNumbersWrongNTimesException.java new file mode 100644 index 00000000..94c797b9 --- /dev/null +++ b/src/main/java/com/ohdab/mistakenote/exception/NoNumbersWrongNTimesException.java @@ -0,0 +1,18 @@ +package com.ohdab.mistakenote.exception; + +public class NoNumbersWrongNTimesException extends RuntimeException { + + public NoNumbersWrongNTimesException() {} + + public NoNumbersWrongNTimesException(String message) { + super(message); + } + + public NoNumbersWrongNTimesException(String message, Throwable cause) { + super(message, cause); + } + + public NoNumbersWrongNTimesException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/com/ohdab/mistakenote/exception/NumberIsOutOfRangeException.java b/src/main/java/com/ohdab/mistakenote/exception/NumberIsOutOfRangeException.java new file mode 100644 index 00000000..14305781 --- /dev/null +++ b/src/main/java/com/ohdab/mistakenote/exception/NumberIsOutOfRangeException.java @@ -0,0 +1,18 @@ +package com.ohdab.mistakenote.exception; + +public class NumberIsOutOfRangeException extends RuntimeException { + + public NumberIsOutOfRangeException() {} + + public NumberIsOutOfRangeException(String message) { + super(message); + } + + public NumberIsOutOfRangeException(String message, Throwable cause) { + super(message, cause); + } + + public NumberIsOutOfRangeException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/com/ohdab/mistakenote/repository/MistakeNoteRepository.java b/src/main/java/com/ohdab/mistakenote/repository/MistakeNoteRepository.java new file mode 100644 index 00000000..74b833b4 --- /dev/null +++ b/src/main/java/com/ohdab/mistakenote/repository/MistakeNoteRepository.java @@ -0,0 +1,15 @@ +package com.ohdab.mistakenote.repository; + +import com.ohdab.member.domain.student.studentid.StudentId; +import com.ohdab.mistakenote.domain.MistakeNote; +import com.ohdab.workbook.domain.workbookid.WorkbookId; +import java.util.List; +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface MistakeNoteRepository extends JpaRepository { + + Optional findByWorkbookIdAndStudentId(WorkbookId workbookId, StudentId studentId); + + List findByWorkbookId(WorkbookId workbookId); +} diff --git a/src/main/java/com/ohdab/mistakenote/repository/mapper/MistakeRecordMapper.java b/src/main/java/com/ohdab/mistakenote/repository/mapper/MistakeRecordMapper.java new file mode 100644 index 00000000..71e4a94a --- /dev/null +++ b/src/main/java/com/ohdab/mistakenote/repository/mapper/MistakeRecordMapper.java @@ -0,0 +1,14 @@ +package com.ohdab.mistakenote.repository.mapper; + +import com.ohdab.mistakenote.service.dto.GetAllMistakeNoteInfoDto.Response.AllMistakeNoteInfoDto; +import com.ohdab.mistakenote.service.dto.GetNumberWrongNTimesDto; +import java.util.List; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface MistakeRecordMapper { + + List findAllMistakeNoteInfo(List mistakeNoteIdList); + + List findNumbersWrongNTimes(GetNumberWrongNTimesDto.Request request); +} diff --git a/src/main/java/com/ohdab/mistakenote/service/GetMistakeNoteInfoService.java b/src/main/java/com/ohdab/mistakenote/service/GetMistakeNoteInfoService.java new file mode 100644 index 00000000..9461b54c --- /dev/null +++ b/src/main/java/com/ohdab/mistakenote/service/GetMistakeNoteInfoService.java @@ -0,0 +1,93 @@ +package com.ohdab.mistakenote.service; + +import static com.ohdab.mistakenote.service.helper.MistakeNoteHelperService.isNotExistingMember; + +import com.ohdab.core.exception.ExceptionEnum; +import com.ohdab.member.domain.student.studentid.StudentId; +import com.ohdab.member.exception.NoMemberException; +import com.ohdab.member.repository.MemberRepository; +import com.ohdab.member.repository.mapper.MemberMapper; +import com.ohdab.mistakenote.domain.MistakeNote; +import com.ohdab.mistakenote.exception.NoMistakeNoteException; +import com.ohdab.mistakenote.repository.MistakeNoteRepository; +import com.ohdab.mistakenote.repository.mapper.MistakeRecordMapper; +import com.ohdab.mistakenote.service.dto.GetAllMistakeNoteInfoDto; +import com.ohdab.mistakenote.service.dto.GetAllMistakeNoteInfoDto.Response.AllMistakeNoteInfoDto; +import com.ohdab.mistakenote.service.dto.GetAllMistakeNoteInfoDto.Response.StudentInfoDto; +import com.ohdab.mistakenote.service.dto.GetMistakeNoteInfoOfStudentDto; +import com.ohdab.mistakenote.service.dto.GetMistakeNoteInfoOfStudentDto.Response.MistakeNoteInfoDto; +import com.ohdab.mistakenote.service.usecase.GetMistakeNoteInfoUsecase; +import com.ohdab.workbook.domain.workbookid.WorkbookId; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class GetMistakeNoteInfoService implements GetMistakeNoteInfoUsecase { + + private final MistakeNoteRepository mistakeNoteRepository; + private final MemberRepository memberRepository; + private final MistakeRecordMapper mistakeRecordMapper; + private final MemberMapper memberMapper; + + @Override + public GetMistakeNoteInfoOfStudentDto.Response getMistakeNoteInfoOfStudent( + long workbookId, long studentId) { + if (isNotExistingMember(memberRepository, studentId)) { + throw new NoMemberException(ExceptionEnum.NO_MEMBER.getMessage()); + } + MistakeNote mistakeNote = + mistakeNoteRepository + .findByWorkbookIdAndStudentId( + new WorkbookId(workbookId), new StudentId(studentId)) + .orElseThrow( + () -> + new NoMistakeNoteException( + ExceptionEnum.NO_MISTAKE_NOTE.getMessage())); + return mapToMistakeNoteInfo(mistakeNote); + } + + private GetMistakeNoteInfoOfStudentDto.Response mapToMistakeNoteInfo(MistakeNote mistakeNote) { + List mistakeNoteInfo = new ArrayList<>(); + Map mistakeRecords = mistakeNote.getMistakeRecords(); + mistakeRecords.forEach( + (number, count) -> + mistakeNoteInfo.add( + MistakeNoteInfoDto.builder() + .wrongNumber(number) + .wrongCount(count) + .build())); + return GetMistakeNoteInfoOfStudentDto.Response.builder() + .mistakeNoteInfo(mistakeNoteInfo) + .build(); + } + + @Override + public GetAllMistakeNoteInfoDto.Response getAllMistakeNoteInfo(long workbookId) { + List mistakeNotes = + mistakeNoteRepository.findByWorkbookId(new WorkbookId(workbookId)); + List students = memberMapper.findAllStudent(getStudentIdList(mistakeNotes)); + List allMistakeNoteInfoDto = + mistakeRecordMapper.findAllMistakeNoteInfo(getMistakeNoteIdList(mistakeNotes)); + return GetAllMistakeNoteInfoDto.Response.builder() + .students(students) + .allMistakeNoteInfo(allMistakeNoteInfoDto) + .build(); + } + + private List getStudentIdList(List mistakeNotes) { + return mistakeNotes.stream() + .map(mistakeNote -> mistakeNote.getStudentId().getId()) + .collect(Collectors.toList()); + } + + private List getMistakeNoteIdList(List mistakeNotes) { + return mistakeNotes.stream().map(MistakeNote::getId).collect(Collectors.toList()); + } +} diff --git a/src/main/java/com/ohdab/mistakenote/service/GetNumberWrongNTimesService.java b/src/main/java/com/ohdab/mistakenote/service/GetNumberWrongNTimesService.java new file mode 100644 index 00000000..679fd3be --- /dev/null +++ b/src/main/java/com/ohdab/mistakenote/service/GetNumberWrongNTimesService.java @@ -0,0 +1,84 @@ +package com.ohdab.mistakenote.service; + +import com.ohdab.core.exception.ExceptionEnum; +import com.ohdab.mistakenote.exception.NoNumbersWrongNTimesException; +import com.ohdab.mistakenote.exception.NumberIsOutOfRangeException; +import com.ohdab.mistakenote.repository.mapper.MistakeRecordMapper; +import com.ohdab.mistakenote.service.dto.GetNumberWrongNTimesDto; +import com.ohdab.mistakenote.service.usecase.GetNumberWrongNTimesUsecase; +import com.ohdab.workbook.domain.Workbook; +import com.ohdab.workbook.exception.NoWorkbookException; +import com.ohdab.workbook.repository.WorkbookRepository; +import java.util.List; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class GetNumberWrongNTimesService implements GetNumberWrongNTimesUsecase { + + private final MistakeRecordMapper mistakeRecordMapper; + private final WorkbookRepository workbookRepository; + + @Override + public GetNumberWrongNTimesDto.Response getNumberWrongNTimes( + GetNumberWrongNTimesDto.Request getNumberWrongNTimeDto) { + Workbook workbook = + workbookRepository + .findById(getNumberWrongNTimeDto.getWorkbookId()) + .orElseThrow( + () -> + new NoWorkbookException( + ExceptionEnum.NO_WORKBOOK.getMessage())); + checkNumberIsInRange(getNumberWrongNTimeDto, workbook); + List numberWrongNTimes = + mistakeRecordMapper.findNumbersWrongNTimes(getNumberWrongNTimeDto); + return GetNumberWrongNTimesDto.Response.builder() + .wrongNumber(wrongNumbersToString(numberWrongNTimes)) + .build(); + } + + private void checkNumberIsInRange( + GetNumberWrongNTimesDto.Request getNumberWrongNTimeDto, Workbook workbook) { + int startingNumber = getStartingNumber(workbook); + int endingNumber = getEndingNumber(workbook); + int from = getFrom(getNumberWrongNTimeDto); + int to = getTo(getNumberWrongNTimeDto); + if (isNotInRange(from, startingNumber, endingNumber) + || isNotInRange(to, startingNumber, endingNumber)) { + throw new NumberIsOutOfRangeException( + ExceptionEnum.NUMBER_IS_OUT_OF_RANGE.getMessage()); + } + } + + private int getStartingNumber(Workbook workbook) { + return workbook.getWorkbookInfo().getStartingNumber(); + } + + private int getEndingNumber(Workbook workbook) { + return workbook.getWorkbookInfo().getEndingNumber(); + } + + private int getTo(GetNumberWrongNTimesDto.Request getNumberWrongNTimeDto) { + return getNumberWrongNTimeDto.getTo(); + } + + private int getFrom(GetNumberWrongNTimesDto.Request getNumberWrongNTimeDto) { + return getNumberWrongNTimeDto.getFrom(); + } + + private boolean isNotInRange(int target, int startingNumber, int endingNumber) { + return (target < startingNumber || endingNumber < target); + } + + private String wrongNumbersToString(List numberWrongNTimes) { + if (numberWrongNTimes.isEmpty()) { + throw new NoNumbersWrongNTimesException( + ExceptionEnum.NO_NUMBERS_WRONG_N_TIMES.getMessage()); + } + return numberWrongNTimes.stream().map(String::valueOf).collect(Collectors.joining(",")); + } +} diff --git a/src/main/java/com/ohdab/mistakenote/service/GetNumbersWrongNTimesService.java b/src/main/java/com/ohdab/mistakenote/service/GetNumbersWrongNTimesService.java new file mode 100644 index 00000000..5d93977f --- /dev/null +++ b/src/main/java/com/ohdab/mistakenote/service/GetNumbersWrongNTimesService.java @@ -0,0 +1,19 @@ +package com.ohdab.mistakenote.service; + +import com.ohdab.mistakenote.service.dto.GetNumberWrongNTimesDto; +import com.ohdab.mistakenote.service.usecase.GetNumbersWrongNTimesUsecase; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class GetNumbersWrongNTimesService implements GetNumbersWrongNTimesUsecase { + + @Override + public GetNumberWrongNTimesDto.Response getNumberWrongNTimes( + GetNumberWrongNTimesDto.Request getNumberWrongNTimeDto) { + return null; + } +} diff --git a/src/main/java/com/ohdab/mistakenote/service/SaveMistakeNoteInfoService.java b/src/main/java/com/ohdab/mistakenote/service/SaveMistakeNoteInfoService.java new file mode 100644 index 00000000..e186ab84 --- /dev/null +++ b/src/main/java/com/ohdab/mistakenote/service/SaveMistakeNoteInfoService.java @@ -0,0 +1,57 @@ +package com.ohdab.mistakenote.service; + +import static com.ohdab.mistakenote.service.helper.MistakeNoteHelperService.isNotExistingMember; + +import com.ohdab.core.exception.ExceptionEnum; +import com.ohdab.member.domain.student.studentid.StudentId; +import com.ohdab.member.exception.NoMemberException; +import com.ohdab.member.repository.MemberRepository; +import com.ohdab.mistakenote.domain.MistakeNote; +import com.ohdab.mistakenote.exception.NoMistakeNoteException; +import com.ohdab.mistakenote.repository.MistakeNoteRepository; +import com.ohdab.mistakenote.service.dto.SaveMistakeNoteInfoDto; +import com.ohdab.mistakenote.service.usecase.SaveMistakeNoteInfoUsecase; +import com.ohdab.workbook.domain.Workbook; +import com.ohdab.workbook.domain.service.NumberScopeCheckService; +import com.ohdab.workbook.domain.workbookid.WorkbookId; +import com.ohdab.workbook.exception.NoWorkbookException; +import com.ohdab.workbook.repository.WorkbookRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional +public class SaveMistakeNoteInfoService implements SaveMistakeNoteInfoUsecase { + + private final NumberScopeCheckService numberScopeCheckService; + private final MemberRepository memberRepository; + private final MistakeNoteRepository mistakeNoteRepository; + private final WorkbookRepository workbookRepository; + + @Override + public void saveMistakeNoteInfo(SaveMistakeNoteInfoDto saveMistakeNoteInfoDto) { + if (isNotExistingMember(memberRepository, saveMistakeNoteInfoDto.getStudentId())) { + throw new NoMemberException(ExceptionEnum.NO_MEMBER.getMessage()); + } + MistakeNote mistakeNote = + mistakeNoteRepository + .findByWorkbookIdAndStudentId( + new WorkbookId(saveMistakeNoteInfoDto.getWorkbookId()), + new StudentId(saveMistakeNoteInfoDto.getStudentId())) + .orElseThrow( + () -> + new NoMistakeNoteException( + ExceptionEnum.NO_MISTAKE_NOTE.getMessage())); + Workbook workbook = + workbookRepository + .findById(saveMistakeNoteInfoDto.getWorkbookId()) + .orElseThrow( + () -> + new NoWorkbookException( + ExceptionEnum.NO_WORKBOOK.getMessage())); + mistakeNote.addMistakeNumbers( + numberScopeCheckService, workbook, saveMistakeNoteInfoDto.getMistakeNumbers()); + } +} diff --git a/src/main/java/com/ohdab/mistakenote/service/dto/GetAllMistakeNoteInfoDto.java b/src/main/java/com/ohdab/mistakenote/service/dto/GetAllMistakeNoteInfoDto.java new file mode 100644 index 00000000..ab557842 --- /dev/null +++ b/src/main/java/com/ohdab/mistakenote/service/dto/GetAllMistakeNoteInfoDto.java @@ -0,0 +1,32 @@ +package com.ohdab.mistakenote.service.dto; + +import java.util.List; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class GetAllMistakeNoteInfoDto { + + @Getter + @Builder + public static class Response { + private List students; + private List allMistakeNoteInfo; + + @Getter + @Builder + public static class StudentInfoDto { + private long studentId; + private String name; + } + + @Getter + @Builder + public static class AllMistakeNoteInfoDto { + private int wrongNumber; + private int wrongStudentsCount; + } + } +} diff --git a/src/main/java/com/ohdab/mistakenote/service/dto/GetMistakeNoteInfoOfStudentDto.java b/src/main/java/com/ohdab/mistakenote/service/dto/GetMistakeNoteInfoOfStudentDto.java new file mode 100644 index 00000000..b7705cec --- /dev/null +++ b/src/main/java/com/ohdab/mistakenote/service/dto/GetMistakeNoteInfoOfStudentDto.java @@ -0,0 +1,24 @@ +package com.ohdab.mistakenote.service.dto; + +import java.util.List; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class GetMistakeNoteInfoOfStudentDto { + + @Getter + @Builder + public static class Response { + private List mistakeNoteInfo; + + @Getter + @Builder + public static class MistakeNoteInfoDto { + private int wrongNumber; + private int wrongCount; + } + } +} diff --git a/src/main/java/com/ohdab/mistakenote/service/dto/GetNumberWrongNTimesDto.java b/src/main/java/com/ohdab/mistakenote/service/dto/GetNumberWrongNTimesDto.java new file mode 100644 index 00000000..bfd43c18 --- /dev/null +++ b/src/main/java/com/ohdab/mistakenote/service/dto/GetNumberWrongNTimesDto.java @@ -0,0 +1,28 @@ +package com.ohdab.mistakenote.service.dto; + +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class GetNumberWrongNTimesDto { + + @Getter + @Builder + public static class Request { + + private long workbookId; + private long mistakeNoteId; + private int count; + private int from; + private int to; + } + + @Getter + @Builder + public static class Response { + + private String wrongNumber; + } +} diff --git a/src/main/java/com/ohdab/mistakenote/service/dto/SaveMistakeNoteInfoDto.java b/src/main/java/com/ohdab/mistakenote/service/dto/SaveMistakeNoteInfoDto.java new file mode 100644 index 00000000..c1795131 --- /dev/null +++ b/src/main/java/com/ohdab/mistakenote/service/dto/SaveMistakeNoteInfoDto.java @@ -0,0 +1,14 @@ +package com.ohdab.mistakenote.service.dto; + +import java.util.List; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class SaveMistakeNoteInfoDto { + + private long workbookId; + private long studentId; + private List mistakeNumbers; +} diff --git a/src/main/java/com/ohdab/mistakenote/service/helper/MistakeNoteHelperService.java b/src/main/java/com/ohdab/mistakenote/service/helper/MistakeNoteHelperService.java new file mode 100644 index 00000000..a8052491 --- /dev/null +++ b/src/main/java/com/ohdab/mistakenote/service/helper/MistakeNoteHelperService.java @@ -0,0 +1,16 @@ +package com.ohdab.mistakenote.service.helper; + +import com.ohdab.member.domain.Member; +import com.ohdab.member.repository.MemberRepository; +import java.util.Optional; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public final class MistakeNoteHelperService { + + public static boolean isNotExistingMember(MemberRepository memberRepository, long memberId) { + Optional memberOpt = memberRepository.findActiveMemberById(memberId); + return memberOpt.isEmpty(); + } +} diff --git a/src/main/java/com/ohdab/mistakenote/service/usecase/GetMistakeNoteInfoUsecase.java b/src/main/java/com/ohdab/mistakenote/service/usecase/GetMistakeNoteInfoUsecase.java new file mode 100644 index 00000000..4ce4c857 --- /dev/null +++ b/src/main/java/com/ohdab/mistakenote/service/usecase/GetMistakeNoteInfoUsecase.java @@ -0,0 +1,12 @@ +package com.ohdab.mistakenote.service.usecase; + +import com.ohdab.mistakenote.service.dto.GetAllMistakeNoteInfoDto; +import com.ohdab.mistakenote.service.dto.GetMistakeNoteInfoOfStudentDto; + +public interface GetMistakeNoteInfoUsecase { + + GetMistakeNoteInfoOfStudentDto.Response getMistakeNoteInfoOfStudent( + long workbookId, long studentId); + + GetAllMistakeNoteInfoDto.Response getAllMistakeNoteInfo(long workbookId); +} diff --git a/src/main/java/com/ohdab/mistakenote/service/usecase/GetNumberWrongNTimesUsecase.java b/src/main/java/com/ohdab/mistakenote/service/usecase/GetNumberWrongNTimesUsecase.java new file mode 100644 index 00000000..8e5ea748 --- /dev/null +++ b/src/main/java/com/ohdab/mistakenote/service/usecase/GetNumberWrongNTimesUsecase.java @@ -0,0 +1,9 @@ +package com.ohdab.mistakenote.service.usecase; + +import com.ohdab.mistakenote.service.dto.GetNumberWrongNTimesDto; + +public interface GetNumberWrongNTimesUsecase { + + GetNumberWrongNTimesDto.Response getNumberWrongNTimes( + GetNumberWrongNTimesDto.Request getNumbersWrongNTimeDto); +} diff --git a/src/main/java/com/ohdab/mistakenote/service/usecase/GetNumbersWrongNTimesUsecase.java b/src/main/java/com/ohdab/mistakenote/service/usecase/GetNumbersWrongNTimesUsecase.java new file mode 100644 index 00000000..4ddca95a --- /dev/null +++ b/src/main/java/com/ohdab/mistakenote/service/usecase/GetNumbersWrongNTimesUsecase.java @@ -0,0 +1,9 @@ +package com.ohdab.mistakenote.service.usecase; + +import com.ohdab.mistakenote.service.dto.GetNumberWrongNTimesDto; + +public interface GetNumbersWrongNTimesUsecase { + + GetNumberWrongNTimesDto.Response getNumberWrongNTimes( + GetNumberWrongNTimesDto.Request getNumbersWrongNTimeDto); +} diff --git a/src/main/java/com/ohdab/mistakenote/service/usecase/SaveMistakeNoteInfoUsecase.java b/src/main/java/com/ohdab/mistakenote/service/usecase/SaveMistakeNoteInfoUsecase.java new file mode 100644 index 00000000..32854a23 --- /dev/null +++ b/src/main/java/com/ohdab/mistakenote/service/usecase/SaveMistakeNoteInfoUsecase.java @@ -0,0 +1,8 @@ +package com.ohdab.mistakenote.service.usecase; + +import com.ohdab.mistakenote.service.dto.SaveMistakeNoteInfoDto; + +public interface SaveMistakeNoteInfoUsecase { + + void saveMistakeNoteInfo(SaveMistakeNoteInfoDto saveMistakeNoteInfoDto); +} diff --git a/src/main/java/com/ohdab/workbook/domain/Workbook.java b/src/main/java/com/ohdab/workbook/domain/Workbook.java index 37057542..2aa886e4 100644 --- a/src/main/java/com/ohdab/workbook/domain/Workbook.java +++ b/src/main/java/com/ohdab/workbook/domain/Workbook.java @@ -2,7 +2,9 @@ import com.ohdab.classroom.domain.classroomid.ClassroomId; import com.ohdab.core.baseentity.BaseEntity; +import com.ohdab.core.exception.ExceptionEnum; import com.ohdab.workbook.domain.workbookInfo.WorkbookInfo; +import io.jsonwebtoken.lang.Assert; import javax.persistence.*; import lombok.AccessLevel; import lombok.Builder; @@ -35,14 +37,14 @@ public class Workbook extends BaseEntity { @Builder public Workbook(WorkbookInfo workbookInfo, ClassroomId classroomId) { - setWorkbookInfo(workbookInfo); + Assert.notNull(workbookInfo, ExceptionEnum.IS_NULL.getMessage()); + Assert.notNull(classroomId, ExceptionEnum.IS_NULL.getMessage()); + this.workbookInfo = workbookInfo; this.classroomId = classroomId; } - private void setWorkbookInfo(WorkbookInfo workbookInfo) { - if (workbookInfo == null) { - throw new IllegalArgumentException("예외"); - } + public void updateWorkbookInfo(WorkbookInfo workbookInfo) { + Assert.notNull(workbookInfo, ExceptionEnum.IS_NULL.getMessage()); this.workbookInfo = workbookInfo; } } diff --git a/src/main/java/com/ohdab/workbook/domain/service/NumberScopeCheckService.java b/src/main/java/com/ohdab/workbook/domain/service/NumberScopeCheckService.java new file mode 100644 index 00000000..536998ec --- /dev/null +++ b/src/main/java/com/ohdab/workbook/domain/service/NumberScopeCheckService.java @@ -0,0 +1,34 @@ +package com.ohdab.workbook.domain.service; + +import com.ohdab.workbook.domain.Workbook; +import java.util.List; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional(readOnly = true) +public class NumberScopeCheckService { + + public void numberScopeCheck(Workbook workbook, List numbers) { + int startingNumber = getStartingNumber(workbook); + int endingNumber = getEndingNumber(workbook); + verify(numbers, startingNumber, endingNumber); + } + + private int getEndingNumber(Workbook workbook) { + return workbook.getWorkbookInfo().getEndingNumber(); + } + + private int getStartingNumber(Workbook workbook) { + return workbook.getWorkbookInfo().getStartingNumber(); + } + + private void verify(List numbers, int startingNumber, int endingNumber) { + numbers.forEach( + number -> { + if (number < startingNumber || number > endingNumber) { + throw new IllegalArgumentException("책에 없는 문제 번호가 포함되어있습니다."); + } + }); + } +} diff --git a/src/main/java/com/ohdab/workbook/domain/workbookInfo/WorkbookInfo.java b/src/main/java/com/ohdab/workbook/domain/workbookInfo/WorkbookInfo.java index ffd777ff..41c0edd8 100644 --- a/src/main/java/com/ohdab/workbook/domain/workbookInfo/WorkbookInfo.java +++ b/src/main/java/com/ohdab/workbook/domain/workbookInfo/WorkbookInfo.java @@ -1,5 +1,8 @@ package com.ohdab.workbook.domain.workbookInfo; +import com.ohdab.core.exception.ExceptionEnum; +import com.ohdab.workbook.exception.InvalidWorkbookNumberRangeException; +import com.ohdab.workbook.exception.WorkbookContentOverflowException; import javax.persistence.Embeddable; import lombok.AccessLevel; import lombok.Builder; @@ -26,18 +29,16 @@ public WorkbookInfo(String name, String description, int startingNumber, int end private void setName(String name) { if (name.length() > 20) { - throw new IllegalStateException( - "Name length cannot exceed 20 : current length \"" + name.length() + "\""); + throw new WorkbookContentOverflowException( + ExceptionEnum.WORKBOOK_CONTENT_OVERFLOW.getMessage()); } this.name = name; } private void setDescription(String description) { if (description != null && description.length() > 30) { - throw new IllegalStateException( - "Description length cannot exceed 30 : current length \"" - + description.length() - + "\""); + throw new WorkbookContentOverflowException( + ExceptionEnum.WORKBOOK_CONTENT_OVERFLOW.getMessage()); } this.description = description; } @@ -47,10 +48,12 @@ private void setRange(int startingNumber, int endingNumber) { || startingNumber > 5000 || endingNumber < 0 || endingNumber > 5000) { - throw new IllegalStateException(""); + throw new InvalidWorkbookNumberRangeException( + ExceptionEnum.INVALID_WORKBOOK_NUMBER_RANGE.getMessage()); } if (startingNumber > endingNumber) { - throw new IllegalStateException(""); + throw new InvalidWorkbookNumberRangeException( + ExceptionEnum.INVALID_WORKBOOK_NUMBER_RANGE.getMessage()); } this.startingNumber = startingNumber; this.endingNumber = endingNumber; diff --git a/src/main/java/com/ohdab/workbook/exception/DuplicatedWorkbookException.java b/src/main/java/com/ohdab/workbook/exception/DuplicatedWorkbookException.java new file mode 100644 index 00000000..f43c2ffe --- /dev/null +++ b/src/main/java/com/ohdab/workbook/exception/DuplicatedWorkbookException.java @@ -0,0 +1,18 @@ +package com.ohdab.workbook.exception; + +public class DuplicatedWorkbookException extends RuntimeException { + + public DuplicatedWorkbookException() {} + + public DuplicatedWorkbookException(String message) { + super(message); + } + + public DuplicatedWorkbookException(String message, Throwable cause) { + super(message, cause); + } + + public DuplicatedWorkbookException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/com/ohdab/workbook/exception/InvalidWorkbookNumberRangeException.java b/src/main/java/com/ohdab/workbook/exception/InvalidWorkbookNumberRangeException.java new file mode 100644 index 00000000..af6cb257 --- /dev/null +++ b/src/main/java/com/ohdab/workbook/exception/InvalidWorkbookNumberRangeException.java @@ -0,0 +1,18 @@ +package com.ohdab.workbook.exception; + +public class InvalidWorkbookNumberRangeException extends RuntimeException { + + public InvalidWorkbookNumberRangeException() {} + + public InvalidWorkbookNumberRangeException(String message) { + super(message); + } + + public InvalidWorkbookNumberRangeException(String message, Throwable cause) { + super(message, cause); + } + + public InvalidWorkbookNumberRangeException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/com/ohdab/workbook/exception/NoWorkbookException.java b/src/main/java/com/ohdab/workbook/exception/NoWorkbookException.java new file mode 100644 index 00000000..97538bcc --- /dev/null +++ b/src/main/java/com/ohdab/workbook/exception/NoWorkbookException.java @@ -0,0 +1,18 @@ +package com.ohdab.workbook.exception; + +public class NoWorkbookException extends RuntimeException { + + public NoWorkbookException() {} + + public NoWorkbookException(String message) { + super(message); + } + + public NoWorkbookException(String message, Throwable cause) { + super(message, cause); + } + + public NoWorkbookException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/com/ohdab/workbook/exception/WorkbookContentOverflowException.java b/src/main/java/com/ohdab/workbook/exception/WorkbookContentOverflowException.java new file mode 100644 index 00000000..6fe5513a --- /dev/null +++ b/src/main/java/com/ohdab/workbook/exception/WorkbookContentOverflowException.java @@ -0,0 +1,18 @@ +package com.ohdab.workbook.exception; + +public class WorkbookContentOverflowException extends RuntimeException { + + public WorkbookContentOverflowException() {} + + public WorkbookContentOverflowException(String message) { + super(message); + } + + public WorkbookContentOverflowException(String message, Throwable cause) { + super(message, cause); + } + + public WorkbookContentOverflowException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/com/ohdab/workbook/repository/WorkbookRepository.java b/src/main/java/com/ohdab/workbook/repository/WorkbookRepository.java new file mode 100644 index 00000000..d33d7bb8 --- /dev/null +++ b/src/main/java/com/ohdab/workbook/repository/WorkbookRepository.java @@ -0,0 +1,13 @@ +package com.ohdab.workbook.repository; + +import com.ohdab.classroom.domain.classroomid.ClassroomId; +import com.ohdab.workbook.domain.Workbook; +import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface WorkbookRepository extends JpaRepository { + + List findByClassroomId(ClassroomId id); + + boolean existsByClassroomIdAndWorkbookInfoName(ClassroomId classroomId, String name); +} diff --git a/src/main/resources/mapper/MemberMapper.xml b/src/main/resources/mapper/MemberMapper.xml new file mode 100644 index 00000000..1375935a --- /dev/null +++ b/src/main/resources/mapper/MemberMapper.xml @@ -0,0 +1,14 @@ + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/MistakeRecordMapper.xml b/src/main/resources/mapper/MistakeRecordMapper.xml new file mode 100644 index 00000000..74b97799 --- /dev/null +++ b/src/main/resources/mapper/MistakeRecordMapper.xml @@ -0,0 +1,24 @@ + + + + + + + \ No newline at end of file diff --git a/src/test/java/com/ohdab/classroom/controller/ClassroomControllerTest.java b/src/test/java/com/ohdab/classroom/controller/ClassroomControllerTest.java new file mode 100644 index 00000000..34ff84f6 --- /dev/null +++ b/src/test/java/com/ohdab/classroom/controller/ClassroomControllerTest.java @@ -0,0 +1,366 @@ +package com.ohdab.classroom.controller; + +import static com.ohdab.classroom.service.dto.ClassroomDetailDto.ClassroomDetailDtoInfo; +import static com.ohdab.classroom.service.dto.ClassroomDetailDto.ClassroomDetailDtoResponse; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.when; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.*; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.ohdab.classroom.controller.request.*; +import com.ohdab.classroom.service.dto.AddStudentDto; +import com.ohdab.classroom.service.dto.ClassroomDto; +import com.ohdab.classroom.service.dto.ClassroomWorkbookDto; +import com.ohdab.classroom.service.usecase.*; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.web.servlet.MockMvc; + +@AutoConfigureRestDocs +@WebMvcTest(controllers = ClassroomController.class) +class ClassroomControllerTest { + + @Autowired private MockMvc mockMvc; + @Autowired private ObjectMapper objectMapper; + @MockBean private AddClassroomUsecase addClassroomUsecase; + @MockBean private FindClassroomListUsecase findClassroomListUsecase; + @MockBean private FindClassroomDetailUsecase findClassroomDetailUsecase; + @MockBean private UpdateClassroomInfoUsecase updateClassroomInfoUsecase; + @MockBean private DeleteClassroomUsecase deleteClassroomUsecase; + @MockBean private DeleteStudentUsecase deleteStudentUsecase; + @MockBean private GetWorkbookListUsecase getWorkbookListUsecase; + @MockBean private AddWorkbookUsecase addWorkbookUsecase; + @MockBean private UpdateWorkbookInfoUsecase updateWorkbookInfoUsecase; + @MockBean private AddStudentUsecase addStudentUsecase; + + @Test + @WithMockUser + void 반추가() throws Exception { + // given + final String url = "/classrooms/enrollment"; + final AddClassroomReq addClassroomReq = + AddClassroomReq.builder() + .name("1반") + .description("1반 설명입니다.") + .grade("high1") + .teacherId(1) + .build(); + + // when + + // then + mockMvc.perform( + post(url) + .with(csrf()) + .content(objectMapper.writeValueAsString(addClassroomReq)) + .contentType(MediaType.APPLICATION_JSON)) + .andExpectAll( + status().isOk(), + content().contentType(MediaType.APPLICATION_JSON), + jsonPath("$.message").value("반이 추가되었습니다.")) + .andDo(print()) + .andDo(createDocument("classrooms/enrollment")); + } + + @Test + @WithMockUser + void 선생님_아이디로_반목록_조회() throws Exception { + // given + final String url = "/classrooms"; + + List responseList = new ArrayList<>(); + + responseList.add( + ClassroomDto.Response.builder() + .teacherId(1L) + .id(1) + .info( + ClassroomDto.Info.builder() + .name("1") + .description("111") + .grade("high1") + .build()) + .build()); + responseList.add( + ClassroomDto.Response.builder() + .teacherId(1L) + .id(2) + .info( + ClassroomDto.Info.builder() + .name("2") + .description("222") + .grade("high2") + .build()) + .build()); + + // when + when(findClassroomListUsecase.findClassroomListByTeacherId(1L)).thenReturn(responseList); + // then + mockMvc.perform(get(url).with(csrf()).param("teacherId", "1")) + .andExpectAll( + status().isOk(), + content().contentType(MediaType.APPLICATION_JSON), + jsonPath("$.classroomInfoList[0].id").value(1), + jsonPath("$.classroomInfoList[0].name").value(1), + jsonPath("$.classroomInfoList[1].id").value(2), + jsonPath("$.classroomInfoList[1].name").value(2), + jsonPath("$.classroomInfoList[1].description").value(222), + jsonPath("$.classroomInfoList[1].grade").value("high2")) + .andDo(print()) + .andDo(createDocument("classrooms")); + } + + @Test + @WithMockUser + void 반_상세조회() throws Exception { + // given + final String url = "/classrooms/"; + + List studentIds = new ArrayList<>(); + studentIds.add(3L); + + List workbookIds = new ArrayList<>(); + workbookIds.add(4L); + + ClassroomDetailDtoResponse classroomDetailDtoResponse = + ClassroomDetailDtoResponse.builder() + .classroomId(1) + .teacherId(2) + .info( + ClassroomDetailDtoInfo.builder() + .name("1반") + .description("1반 설명") + .grade("high1") + .build()) + .studentIds(studentIds) + .workbookIds(workbookIds) + .build(); + + // when + when(findClassroomDetailUsecase.getClassroomDetailById(1L)) + .thenReturn(classroomDetailDtoResponse); + + // then + mockMvc.perform(get(url + "{classroom-id}", 1).with(csrf())) + .andExpectAll( + status().isOk(), + content().contentType(MediaType.APPLICATION_JSON), + jsonPath("$.id").value(1), + jsonPath("$.teacherId").value(2), + jsonPath("$.name").value("1반"), + jsonPath("$.description").value("1반 설명"), + jsonPath("$.grade").value("high1"), + jsonPath("$.studentIds[0]").value(3), + jsonPath("$.workbookIds[0]").value(4)) + .andDo(print()) + .andDo(createDocument("classrooms/{classroom-id}")); + } + + @Test + @WithMockUser + void 반정보수정() throws Exception { + // given + final String url = "/classrooms/info/"; + UpdateClassroomReq request = + UpdateClassroomReq.builder().name("2반").description("2222").grade("high2").build(); + + // when + + // then + mockMvc.perform( + patch(url + "{classroom-id}", 1) + .with(csrf()) + .content(objectMapper.writeValueAsString(request)) + .contentType(MediaType.APPLICATION_JSON)) + .andExpectAll( + status().isOk(), + content().contentType(MediaType.APPLICATION_JSON), + jsonPath("$.message").value("반 정보 수정 성공")) + .andDo(print()) + .andDo(createDocument("classrooms/info/{classroom-id}")); + } + + @Test + @WithMockUser + void 반삭제() throws Exception { + // given + final String url = "/classrooms/expulsion/"; + + // when + + // then + mockMvc.perform(delete(url + "{classroom-id}", 1).with(csrf())) + .andExpectAll( + status().isOk(), + content().contentType(MediaType.APPLICATION_JSON), + jsonPath("$.message").value("반 삭제 성공")) + .andDo(print()) + .andDo(createDocument("classrooms/expulsion/{classroom-id}")); + } + + @Test + @WithMockUser + void 학생_삭제() throws Exception { + // given + final String url = "/classrooms/{classroom-id}/expulsion/students/{student-id}"; + + // when + doNothing().when(deleteStudentUsecase).deleteStudent(anyLong(), anyLong()); + + // then + mockMvc.perform(patch(url, 1L, 2L).with(csrf()).contentType(MediaType.APPLICATION_JSON)) + .andExpectAll(status().isOk(), content().contentType(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andDo(createDocument("classrooms/deleteStudent")); + } + + @Test + @WithMockUser + void 반_식별자로_교재_목록_조회() throws Exception { + // given + final String url = "/classrooms/{classroom-id}/workbooks"; + List workbookDtoList = new ArrayList<>(); + ClassroomWorkbookDto.Response workbookDtoRes1 = createWorkbookDto(1L, "교재"); + ClassroomWorkbookDto.Response workbookDtoRes2 = createWorkbookDto(2L, "교재2"); + ClassroomWorkbookDto.Response workbookDtoRes3 = createWorkbookDto(3L, "교재3"); + workbookDtoList.add(workbookDtoRes1); + workbookDtoList.add(workbookDtoRes2); + workbookDtoList.add(workbookDtoRes3); + + // when + when(getWorkbookListUsecase.getWorkbookListByClassroomId(Mockito.anyLong())) + .thenReturn(workbookDtoList); + + // then + mockMvc.perform(get(url, 1L).with(csrf())) + .andExpectAll( + status().isOk(), + content().contentType(MediaType.APPLICATION_JSON), + jsonPath("$.workbooks[0].id").value(workbookDtoRes1.getId()), + jsonPath("$.workbooks[0].name").value(workbookDtoRes1.getName()), + jsonPath("$.workbooks[0].createdAt") + .value(workbookDtoRes1.getCreatedAt().toLocalDate().toString()), + jsonPath("$.workbooks[1].id").value(workbookDtoRes2.getId()), + jsonPath("$.workbooks[1].name").value(workbookDtoRes2.getName()), + jsonPath("$.workbooks[1].createdAt") + .value(workbookDtoRes2.getCreatedAt().toLocalDate().toString()), + jsonPath("$.workbooks[2].id").value(workbookDtoRes3.getId()), + jsonPath("$.workbooks[2].name").value(workbookDtoRes3.getName()), + jsonPath("$.workbooks[2].createdAt") + .value(workbookDtoRes3.getCreatedAt().toLocalDate().toString())) + .andDo(print()) + .andDo(createDocument("classrooms/{classroom-id}/workbooks")); + } + + @Test + @WithMockUser + void 반_식별자로_반에_교재_추가() throws Exception { + // given + String url = "/classrooms/{classroom-id}/workbooks"; + AddWorkbookReq addWorkbookReq = + AddWorkbookReq.builder() + .name("교재") + .description("교재에 대한 설명입니다.") + .startingNumber(1) + .endingNumber(2000) + .build(); + long classroomId = 1L; + + // when + + // then + mockMvc.perform( + post(url, classroomId) + .with(csrf()) + .content(objectMapper.writeValueAsString(addWorkbookReq)) + .contentType(MediaType.APPLICATION_JSON)) + .andExpectAll( + status().isOk(), + content().contentType(MediaType.APPLICATION_JSON), + jsonPath("$.message").value("해당 반에 교재 및 오답노트가 추가되었습니다.")) + .andDo(print()) + .andDo(createDocument("classrooms/{classroom-id}/addWorkbooks")); + } + + @Test + @WithMockUser + void 교재_식별자로_교재_정보_수정() throws Exception { + // given + String url = "/classrooms/workbooks/info/{workbook-id}"; + UpdateWorkbookInfoReq updateWorkbookInfoReq = + UpdateWorkbookInfoReq.builder() + .name("수정할 교재명") + .description("수정할 교재에 대한 설명입니다.") + .build(); + long workbookId = 1L; + + // when + + // then + mockMvc.perform( + patch(url, workbookId) + .with(csrf()) + .content(objectMapper.writeValueAsString(updateWorkbookInfoReq)) + .contentType(MediaType.APPLICATION_JSON)) + .andExpectAll( + status().isOk(), + content().contentType(MediaType.APPLICATION_JSON), + jsonPath("$.message").value("교재 정보가 수정 되었습니다.")) + .andDo(print()) + .andDo(createDocument("classrooms/workbooks/info/{workbook-id}")); + } + + @Test + @WithMockUser + void 학생_추가() throws Exception { + // given + final String ADD_STUDENT_URL = "/classrooms/{classroom-id}/students/enrollment"; + final AddStudentReq addStudentReq = AddStudentReq.builder().studentName("갑").build(); + + // when + doNothing().when(addStudentUsecase).addStudent(any(AddStudentDto.Request.class)); + + // then + mockMvc.perform( + post(ADD_STUDENT_URL, 1) + .with(csrf()) + .content(objectMapper.writeValueAsString(addStudentReq)) + .contentType(MediaType.APPLICATION_JSON)) + .andExpectAll( + status().isOk(), + content().contentType(MediaType.APPLICATION_JSON), + jsonPath("$.message").value("해당 반에 학생이 추가되었습니다.")) + .andDo(print()) + .andDo(createDocument("classrooms/addStudent")); + } + + private ClassroomWorkbookDto.Response createWorkbookDto(long id, String name) { + return ClassroomWorkbookDto.Response.builder() + .id(id) + .name(name) + .createdAt(LocalDateTime.now()) + .build(); + } + + private RestDocumentationResultHandler createDocument(String identifier) { + return document( + identifier, preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint())); + } +} diff --git a/src/test/java/com/ohdab/classroom/repository/AddClassroomRepositoryTest.java b/src/test/java/com/ohdab/classroom/repository/AddClassroomRepositoryTest.java new file mode 100644 index 00000000..dcb85f2a --- /dev/null +++ b/src/test/java/com/ohdab/classroom/repository/AddClassroomRepositoryTest.java @@ -0,0 +1,47 @@ +package com.ohdab.classroom.repository; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ohdab.classroom.domain.Classroom; +import com.ohdab.classroom.domain.classroomInfo.ClassroomInfo; +import com.ohdab.classroom.domain.classroomInfo.Grade; +import com.ohdab.member.domain.teacher.teacherid.TeacherId; +import java.util.List; +import javax.persistence.EntityManager; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; + +@DataJpaTest +class AddClassroomRepositoryTest { + + @Autowired private ClassroomRepository classroomRepository; + @Autowired private EntityManager em; + + @Test + @DisplayName("반 추가 (저장) 테스트 -> 선생님 아이디를 통해 조회") + void 반_추가_테스트() { + // given + long id = 1L; + TeacherId teacherId = TeacherId.builder().id(id).build(); + String name = "1반"; + String desc = "1반에 대한 설명입니다."; + + ClassroomInfo classroomInfo = + ClassroomInfo.builder().name(name).description(desc).grade(Grade.HIGH_1).build(); + + Classroom classroom = + Classroom.builder().classroomInfo(classroomInfo).teacher(teacherId).build(); + + // when + classroomRepository.save(classroom); + List foundClassrooms = classroomRepository.findAllByTeacherId(teacherId.getId()); + + // then + assertThat(foundClassrooms.get(0).getTeacher().getId()).isEqualTo(teacherId.getId()); + assertThat(foundClassrooms.get(0).getClassroomInfo().getName()).isEqualTo(name); + assertThat(foundClassrooms.get(0).getClassroomInfo().getDescription()).isEqualTo(desc); + assertThat(foundClassrooms.get(0).getClassroomInfo().getGrade()).isEqualTo(Grade.HIGH_1); + } +} diff --git a/src/test/java/com/ohdab/classroom/repository/DeleteClassroomRepositoryTest.java b/src/test/java/com/ohdab/classroom/repository/DeleteClassroomRepositoryTest.java new file mode 100644 index 00000000..fee1988d --- /dev/null +++ b/src/test/java/com/ohdab/classroom/repository/DeleteClassroomRepositoryTest.java @@ -0,0 +1,49 @@ +package com.ohdab.classroom.repository; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ohdab.classroom.domain.Classroom; +import com.ohdab.classroom.domain.classroomInfo.ClassroomInfo; +import com.ohdab.classroom.domain.classroomInfo.Grade; +import com.ohdab.member.domain.teacher.teacherid.TeacherId; +import java.util.List; +import javax.persistence.EntityManager; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; + +@DataJpaTest +class DeleteClassroomRepositoryTest { + + @Autowired private ClassroomRepository classroomRepository; + @Autowired private EntityManager em; + + @Test + @DisplayName("반 삭제 테스트") + void 반삭제() { + // given + long id = 1L; + TeacherId teacherId = TeacherId.builder().id(id).build(); + String name = "1반"; + String desc = "1반에 대한 설명입니다."; + + ClassroomInfo classroomInfo = + ClassroomInfo.builder().name(name).description(desc).grade(Grade.HIGH_1).build(); + + Classroom classroom = + Classroom.builder().classroomInfo(classroomInfo).teacher(teacherId).build(); + + Classroom savedClassroom = classroomRepository.save(classroom); + + // when + classroomRepository.delete(savedClassroom); + em.flush(); + em.clear(); + + List classrooms = classroomRepository.findAllByTeacherId(1); + + // then + assertThat(classrooms).isEmpty(); + } +} diff --git a/src/test/java/com/ohdab/classroom/repository/FindAllClassroomByTeacherIdRepositoryTest.java b/src/test/java/com/ohdab/classroom/repository/FindAllClassroomByTeacherIdRepositoryTest.java new file mode 100644 index 00000000..2fde2af7 --- /dev/null +++ b/src/test/java/com/ohdab/classroom/repository/FindAllClassroomByTeacherIdRepositoryTest.java @@ -0,0 +1,62 @@ +package com.ohdab.classroom.repository; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ohdab.classroom.domain.Classroom; +import com.ohdab.classroom.domain.classroomInfo.ClassroomInfo; +import com.ohdab.classroom.domain.classroomInfo.Grade; +import com.ohdab.member.domain.teacher.teacherid.TeacherId; +import java.util.List; +import javax.persistence.EntityManager; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; + +@DataJpaTest +class FindAllClassroomByTeacherIdRepositoryTest { + + @Autowired private ClassroomRepository classroomRepository; + @Autowired private EntityManager em; + + @Test + void 선생님_아이디로_반목록_조회() { + // given + Classroom classroom1 = + Classroom.builder() + .teacher(TeacherId.builder().id(1L).build()) + .classroomInfo( + ClassroomInfo.builder() + .name("1반") + .description("1반 설명") + .grade(Grade.HIGH_1) + .build()) + .build(); + classroomRepository.save(classroom1); + + Classroom classroom2 = + Classroom.builder() + .teacher(TeacherId.builder().id(1L).build()) + .classroomInfo( + ClassroomInfo.builder() + .name("2반") + .description("2반 설명") + .grade(Grade.HIGH_1) + .build()) + .build(); + classroomRepository.save(classroom2); + + // when + List foundClassrooms = classroomRepository.findAllByTeacherId(1L); + + // then + assertThat(foundClassrooms.get(0).getTeacher().getId()).isEqualTo(1L); + assertThat(foundClassrooms.get(0).getClassroomInfo().getName()).isEqualTo("1반"); + assertThat(foundClassrooms.get(0).getClassroomInfo().getDescription()).isEqualTo("1반 설명"); + assertThat(foundClassrooms.get(0).getClassroomInfo().getGrade()).isEqualTo(Grade.HIGH_1); + + assertThat(foundClassrooms.get(1).getTeacher().getId()).isEqualTo(1L); + assertThat(foundClassrooms.get(1).getClassroomInfo().getName()).isEqualTo("2반"); + assertThat(foundClassrooms.get(1).getClassroomInfo().getDescription()).isEqualTo("2반 설명"); + assertThat(foundClassrooms.get(1).getClassroomInfo().getGrade()).isEqualTo(Grade.HIGH_1); + } +} diff --git a/src/test/java/com/ohdab/classroom/repository/FindAllClassroomByTeacherIdRepositoryTestReq.java b/src/test/java/com/ohdab/classroom/repository/FindAllClassroomByTeacherIdRepositoryTestReq.java new file mode 100644 index 00000000..cdcbb974 --- /dev/null +++ b/src/test/java/com/ohdab/classroom/repository/FindAllClassroomByTeacherIdRepositoryTestReq.java @@ -0,0 +1,64 @@ +package com.ohdab.classroom.repository; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ohdab.classroom.domain.Classroom; +import com.ohdab.classroom.domain.classroomInfo.ClassroomInfo; +import com.ohdab.classroom.domain.classroomInfo.Grade; +import com.ohdab.member.domain.teacher.teacherid.TeacherId; +import java.util.List; +import javax.persistence.EntityManager; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; + +@DataJpaTest +class FindAllClassroomByTeacherIdRepositoryTestReq { + + @Autowired private ClassroomRepository classroomRepository; + @Autowired private EntityManager em; + + @Test + void 선생님_아이디로_반목록_조회() { + // given + Classroom classroom1 = + Classroom.builder() + .teacher(TeacherId.builder().id(1L).build()) + .classroomInfo( + ClassroomInfo.builder() + .name("1반") + .description("1반 설명") + .grade(Grade.HIGH_1) + .build()) + .build(); + classroomRepository.save(classroom1); + + Classroom classroom2 = + Classroom.builder() + .teacher(TeacherId.builder().id(1L).build()) + .classroomInfo( + ClassroomInfo.builder() + .name("2반") + .description("2반 설명") + .grade(Grade.HIGH_1) + .build()) + .build(); + classroomRepository.save(classroom2); + em.flush(); + em.clear(); + + // when + List foundClassrooms = classroomRepository.findAllByTeacherId(1L); + + // then + assertThat(foundClassrooms.get(0).getTeacher().getId()).isEqualTo(1L); + assertThat(foundClassrooms.get(0).getClassroomInfo().getName()).isEqualTo("1반"); + assertThat(foundClassrooms.get(0).getClassroomInfo().getDescription()).isEqualTo("1반 설명"); + assertThat(foundClassrooms.get(0).getClassroomInfo().getGrade()).isEqualTo(Grade.HIGH_1); + + assertThat(foundClassrooms.get(1).getTeacher().getId()).isEqualTo(1L); + assertThat(foundClassrooms.get(1).getClassroomInfo().getName()).isEqualTo("2반"); + assertThat(foundClassrooms.get(1).getClassroomInfo().getDescription()).isEqualTo("2반 설명"); + assertThat(foundClassrooms.get(1).getClassroomInfo().getGrade()).isEqualTo(Grade.HIGH_1); + } +} diff --git a/src/test/java/com/ohdab/classroom/repository/FindClassroomByIdRepositoryTest.java b/src/test/java/com/ohdab/classroom/repository/FindClassroomByIdRepositoryTest.java new file mode 100644 index 00000000..1dc2c042 --- /dev/null +++ b/src/test/java/com/ohdab/classroom/repository/FindClassroomByIdRepositoryTest.java @@ -0,0 +1,53 @@ +package com.ohdab.classroom.repository; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ohdab.classroom.domain.Classroom; +import com.ohdab.classroom.domain.classroomInfo.ClassroomInfo; +import com.ohdab.classroom.domain.classroomInfo.Grade; +import com.ohdab.member.domain.student.studentid.StudentId; +import com.ohdab.member.domain.teacher.teacherid.TeacherId; +import com.ohdab.workbook.domain.workbookid.WorkbookId; +import javax.persistence.EntityManager; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; + +@DataJpaTest +class FindClassroomByIdRepositoryTest { + + @Autowired private ClassroomRepository classroomRepository; + @Autowired private EntityManager em; + + @Test + void 반_상세조회() { + + // given + Classroom classroom = + Classroom.builder() + .teacher(TeacherId.builder().id(2L).build()) + .classroomInfo( + ClassroomInfo.builder() + .name("1반") + .description("1반 설명") + .grade(Grade.HIGH_1) + .build()) + .build(); + classroom.addStudent(StudentId.builder().id(3).build()); + classroom.addWorkbook(WorkbookId.builder().id(4).build()); + classroomRepository.save(classroom); + long id = classroom.getId(); + + // when + Classroom foundClassroom = classroomRepository.findById(id).get(); + + // then + assertThat(foundClassroom.getId()).isEqualTo(id); + assertThat(foundClassroom.getTeacher().getId()).isEqualTo(2); + assertThat(foundClassroom.getClassroomInfo().getName()).isEqualTo("1반"); + assertThat(foundClassroom.getClassroomInfo().getDescription()).isEqualTo("1반 설명"); + assertThat(foundClassroom.getClassroomInfo().getGrade()).isEqualTo(Grade.HIGH_1); + assertThat(foundClassroom.getStudents().get(0).getId()).isEqualTo(3); + assertThat(foundClassroom.getWorkbooks().get(0).getId()).isEqualTo(4); + } +} diff --git a/src/test/java/com/ohdab/classroom/repository/UpdateClassroomRepositoryTest.java b/src/test/java/com/ohdab/classroom/repository/UpdateClassroomRepositoryTest.java new file mode 100644 index 00000000..58397f6e --- /dev/null +++ b/src/test/java/com/ohdab/classroom/repository/UpdateClassroomRepositoryTest.java @@ -0,0 +1,48 @@ +package com.ohdab.classroom.repository; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ohdab.classroom.domain.Classroom; +import com.ohdab.classroom.domain.classroomInfo.ClassroomInfo; +import com.ohdab.classroom.domain.classroomInfo.Grade; +import com.ohdab.member.domain.teacher.teacherid.TeacherId; +import javax.persistence.EntityManager; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; + +@DataJpaTest +class UpdateClassroomRepositoryTest { + + @Autowired private ClassroomRepository classroomRepository; + @Autowired private EntityManager em; + + @Test + @DisplayName("반 수정 repo 테스트") + void 반_수정_레포_테스트() { + // given + long id = 1L; + TeacherId teacherId = TeacherId.builder().id(id).build(); + String name = "1반"; + String desc = "1반에 대한 설명입니다."; + + ClassroomInfo classroomInfo = + ClassroomInfo.builder().name(name).description(desc).grade(Grade.HIGH_1).build(); + + Classroom classroom = + Classroom.builder().classroomInfo(classroomInfo).teacher(teacherId).build(); + Classroom savedClassroom = classroomRepository.save(classroom); + + // when + savedClassroom.updateClassroomInfo( + ClassroomInfo.builder().name("2반").description("22").grade(Grade.HIGH_2).build()); + em.flush(); + em.clear(); + + // then + assertThat(savedClassroom.getClassroomInfo().getName()).isEqualTo("2반"); + assertThat(savedClassroom.getClassroomInfo().getDescription()).isEqualTo("22"); + assertThat(savedClassroom.getClassroomInfo().getGrade()).isEqualTo(Grade.HIGH_2); + } +} diff --git a/src/test/java/com/ohdab/classroom/service/AddClassroomServiceTest.java b/src/test/java/com/ohdab/classroom/service/AddClassroomServiceTest.java new file mode 100644 index 00000000..ef645409 --- /dev/null +++ b/src/test/java/com/ohdab/classroom/service/AddClassroomServiceTest.java @@ -0,0 +1,50 @@ +package com.ohdab.classroom.service; + +import static org.assertj.core.api.Assertions.assertThatNoException; +import static org.mockito.Mockito.anyLong; +import static org.mockito.Mockito.when; + +import com.ohdab.classroom.repository.ClassroomRepository; +import com.ohdab.classroom.service.dto.ClassroomDto; +import com.ohdab.member.repository.MemberRepository; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = {AddClassroomService.class}) +class AddClassroomServiceTest { + + @Autowired private AddClassroomService addClassroomService; + @MockBean private MemberRepository memberRepository; + @MockBean private ClassroomRepository classroomRepository; + + @Test + @DisplayName("반 정보와 선생님 id를 통해 반을 추가 테스트") + void 반_추가() throws Exception { + // given + long id = 1L; + String name = "1반"; + String desc = "1반에 대한 설명입니다."; + String grade = "high1"; + ClassroomDto.Request classroomReqDto = + ClassroomDto.Request.builder() + .info( + ClassroomDto.Info.builder() + .name(name) + .description(desc) + .grade(grade) + .build()) + .teacherId(id) + .build(); + // when + when(memberRepository.existsById(anyLong())).thenReturn(true); + + // then + assertThatNoException().isThrownBy(() -> addClassroomService.addClassroom(classroomReqDto)); + } +} diff --git a/src/test/java/com/ohdab/classroom/service/AddStudentServiceTest.java b/src/test/java/com/ohdab/classroom/service/AddStudentServiceTest.java new file mode 100644 index 00000000..f4c371ed --- /dev/null +++ b/src/test/java/com/ohdab/classroom/service/AddStudentServiceTest.java @@ -0,0 +1,100 @@ +package com.ohdab.classroom.service; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.ohdab.classroom.domain.Classroom; +import com.ohdab.classroom.domain.classroomInfo.ClassroomInfo; +import com.ohdab.classroom.domain.classroomInfo.Grade; +import com.ohdab.classroom.exception.NoClassroomException; +import com.ohdab.classroom.repository.ClassroomRepository; +import com.ohdab.classroom.service.dto.AddStudentDto; +import com.ohdab.classroom.service.usecase.AddStudentUsecase; +import com.ohdab.member.domain.Member; +import com.ohdab.member.domain.teacher.teacherid.TeacherId; +import com.ohdab.member.repository.MemberRepository; +import com.ohdab.mistakenote.repository.MistakeNoteRepository; +import java.util.Optional; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = {AddStudentService.class}) +class AddStudentServiceTest { + + @Autowired private AddStudentUsecase addStudentUsecase; + @Autowired private ApplicationEventPublisher publisher; + @MockBean private ClassroomRepository classroomRepository; + @MockBean private MemberRepository memberRepository; + @MockBean private MistakeNoteRepository mistakeNoteRepository; + + @DisplayName("addStudent 메서드는") + @Nested + class AddStudent { + + @DisplayName("해당 반이 존재한다면") + @Nested + class ExistClassroom { + + @DisplayName("회원가입 이벤트 발생, 해당 반 학생 목록에 학생 id를 추가 및 해당 반의 교재에 대한 모든 오답노트를 생성한다.") + @Test + void joinStudentAndAddStudent() { + // given + final AddStudentDto.Request addStudentReq = + AddStudentDto.Request.builder().classroomId(1L).studentName("갑").build(); + + final Classroom classroom = + Classroom.builder() + .teacher(new TeacherId(10L)) + .classroomInfo( + ClassroomInfo.builder() + .name("1반") + .description("설명") + .grade(Grade.HIGH_1) + .build()) + .build(); + + // when + when(classroomRepository.findById(anyLong())) + .thenReturn(Optional.ofNullable(classroom)); + when(memberRepository.findByMemberInfoName(anyString())) + .thenReturn(Optional.ofNullable((mock(Member.class)))); + when(mock(Member.class).getId()).thenReturn(20L); + addStudentUsecase.addStudent(addStudentReq); + + // then + assertThat(classroom.getStudents()).hasSize(1); + } + } + + @DisplayName("해당 반이 존재하지 않는다면") + @Nested + class DoesNotExistClassroom { + @DisplayName("NoClassroomException 예외를 던진다.") + @Test + void throwNoClassroomException() { + // given + final AddStudentDto.Request addStudentReq = + AddStudentDto.Request.builder().classroomId(1L).studentName("갑").build(); + + // when + when(classroomRepository.findById(anyLong())).thenReturn(Optional.empty()); + + // then + assertThatThrownBy(() -> addStudentUsecase.addStudent(addStudentReq)) + .isInstanceOf(NoClassroomException.class); + } + } + } +} diff --git a/src/test/java/com/ohdab/classroom/service/AddWorkbookServiceTest.java b/src/test/java/com/ohdab/classroom/service/AddWorkbookServiceTest.java new file mode 100644 index 00000000..7f30c4f5 --- /dev/null +++ b/src/test/java/com/ohdab/classroom/service/AddWorkbookServiceTest.java @@ -0,0 +1,88 @@ +package com.ohdab.classroom.service; + +import static org.assertj.core.api.Assertions.assertThatNoException; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.mockito.Mockito.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.ohdab.classroom.domain.Classroom; +import com.ohdab.classroom.domain.classroomInfo.ClassroomInfo; +import com.ohdab.classroom.domain.classroomInfo.Grade; +import com.ohdab.classroom.repository.ClassroomRepository; +import com.ohdab.classroom.service.dto.ClassroomAddWorkbookDto; +import com.ohdab.classroom.service.usecase.AddWorkbookUsecase; +import com.ohdab.member.domain.student.studentid.StudentId; +import com.ohdab.member.domain.teacher.teacherid.TeacherId; +import com.ohdab.mistakenote.repository.MistakeNoteRepository; +import com.ohdab.workbook.domain.Workbook; +import com.ohdab.workbook.repository.WorkbookRepository; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = {AddWorkbookService.class}) +public class AddWorkbookServiceTest { + + @Autowired private AddWorkbookUsecase addWorkbookUsecase; + @MockBean private WorkbookRepository workbookRepository; + @MockBean private ClassroomRepository classroomRepository; + @MockBean private MistakeNoteRepository mistakeNoteRepository; + + @Test + @DisplayName("교재 추가 성공 테스트") + void 교재_추가_성공() { + // given + long classroomId = 1L; + Classroom classroom = + Classroom.builder() + .classroomInfo( + ClassroomInfo.builder() + .name("1반") + .description("1반 설명입니다") + .grade(Grade.HIGH_1) + .build()) + .teacher(new TeacherId(1L)) + .build(); + long workbookId = 1L; + ClassroomAddWorkbookDto.Request addWorkbookDto = + ClassroomAddWorkbookDto.Request.builder() + .name("교재") + .description("교재 설명입니다.") + .startingNumber(1) + .endingNumber(2000) + .build(); + List studentIdList = new ArrayList<>(); + studentIdList.add(new StudentId(1L)); + studentIdList.add(new StudentId(2L)); + studentIdList.add(new StudentId(3L)); + + // when + when(classroomRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.ofNullable(classroom)); + when(workbookRepository.existsByClassroomIdAndWorkbookInfoName( + Mockito.any(), Mockito.any())) + .thenReturn(false); + when(workbookRepository.save(Mockito.any())).thenReturn(mock(Workbook.class)); + when(mock(Workbook.class).getId()).thenReturn(workbookId); + when(classroomRepository.findStudentsById(Mockito.anyLong())).thenReturn(studentIdList); + + // then + assertThatNoException() + .isThrownBy( + () -> + addWorkbookUsecase.addWorkbookByClassroomId( + classroomId, addWorkbookDto)); + assertThat(classroom.getWorkbooks().size()).isEqualTo(workbookId); + Mockito.verify(mistakeNoteRepository).saveAll(Mockito.any()); + } +} diff --git a/src/test/java/com/ohdab/classroom/service/DeleteStudentServiceTest.java b/src/test/java/com/ohdab/classroom/service/DeleteStudentServiceTest.java new file mode 100644 index 00000000..c4f41d7a --- /dev/null +++ b/src/test/java/com/ohdab/classroom/service/DeleteStudentServiceTest.java @@ -0,0 +1,233 @@ +package com.ohdab.classroom.service; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.when; + +import com.ohdab.classroom.domain.Classroom; +import com.ohdab.classroom.domain.classroomInfo.ClassroomInfo; +import com.ohdab.classroom.domain.classroomInfo.Grade; +import com.ohdab.classroom.exception.NoClassroomException; +import com.ohdab.classroom.exception.NoStudentException; +import com.ohdab.classroom.repository.ClassroomRepository; +import com.ohdab.classroom.service.dto.DeleteStudentDto; +import com.ohdab.classroom.service.usecase.DeleteStudentUsecase; +import com.ohdab.member.domain.Authority; +import com.ohdab.member.domain.Member; +import com.ohdab.member.domain.MemberStatus; +import com.ohdab.member.domain.memberinfo.MemberInfo; +import com.ohdab.member.domain.student.studentid.StudentId; +import com.ohdab.member.domain.teacher.teacherid.TeacherId; +import com.ohdab.member.exception.AlreadyWithdrawlException; +import com.ohdab.member.repository.MemberRepository; +import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@ContextConfiguration( + classes = { + DeleteStudentService.class, + }) +class DeleteStudentServiceTest { + + @Autowired private DeleteStudentUsecase deleteStudentUsecase; + @MockBean private ClassroomRepository classroomRepository; + @MockBean private MemberRepository memberRepository; + + @DisplayName("deleteStudent 메서드는") + @Nested + class deleteStudent { + + @DisplayName("요청받은 교실이 존재하고") + @Nested + class ifClassroomExist { + + @DisplayName("삭제하려는 학생이 정상 회원이라면") + @Nested + class ifActiveStudent { + + @DisplayName("해당 학생을 학생 목록에서 삭제하고 탈퇴처리한다.") + @Test + void removeAndExpulsion() { + // given + final long classroomId = 1L; + final long studentId = 2L; + final DeleteStudentDto.Request requestDto = + DeleteStudentDto.Request.builder() + .classroomId(classroomId) + .studentId(studentId) + .build(); + + final Classroom classroom = + Classroom.builder() + .classroomInfo( + ClassroomInfo.builder() + .name("1반") + .description("설명") + .grade(Grade.HIGH_1) + .build()) + .teacher(new TeacherId(10L)) + .build(); + classroom.addStudent(new StudentId(studentId)); + + final Member student = + Member.builder() + .memberInfo( + MemberInfo.builder().name("값").password("1234").build()) + .authorities(List.of(new Authority("STUDENT"))) + .build(); + + // when + when(classroomRepository.findById(anyLong())) + .thenReturn(Optional.ofNullable(classroom)); + when(memberRepository.findById(anyLong())) + .thenReturn(Optional.ofNullable(student)); + + // then + assertThatCode(() -> deleteStudentUsecase.deleteStudent(classroomId, studentId)) + .doesNotThrowAnyException(); + assertThat(student.getStatus()).isEqualTo(MemberStatus.INACTIVE); + assertThat(classroom.getStudents()).isEmpty(); + } + } + + @DisplayName("삭제하려는 학생이 교실에 없는 학생이라면") + @Nested + class ifNotInClassroom { + + @DisplayName("NoStudentException 예외를 던진다.") + @Test + void throwNoStudentException() { + // given + final long classroomId = 1L; + final long studentId = 2L; + final DeleteStudentDto.Request requestDto = + DeleteStudentDto.Request.builder() + .classroomId(classroomId) + .studentId(studentId) + .build(); + + final Classroom classroom = + Classroom.builder() + .classroomInfo( + ClassroomInfo.builder() + .name("1반") + .description("설명") + .grade(Grade.HIGH_1) + .build()) + .teacher(new TeacherId(10L)) + .build(); + classroom.addStudent(new StudentId(3L)); + + final Member student = + Member.builder() + .memberInfo( + MemberInfo.builder().name("값").password("1234").build()) + .authorities(List.of(new Authority("STUDENT"))) + .build(); + + // when + when(classroomRepository.findById(anyLong())) + .thenReturn(Optional.ofNullable(classroom)); + when(memberRepository.findById(anyLong())) + .thenReturn(Optional.ofNullable(student)); + Throwable thrown = + catchException( + () -> + deleteStudentUsecase.deleteStudent( + classroomId, studentId)); + + // then + assertThat(thrown).isInstanceOf(NoStudentException.class); + } + } + + @DisplayName("삭제하려는 학생이 이미 탈퇴하였다면") + @Nested + class ifInActiveStudent { + + @DisplayName("AlreadyWithdrawlException 예외를 던진다.") + @Test + void throwAlreadyWithdrawlException() { + // given + final long classroomId = 1L; + final long studentId = 2L; + final DeleteStudentDto.Request requestDto = + DeleteStudentDto.Request.builder() + .classroomId(classroomId) + .studentId(studentId) + .build(); + + final Classroom classroom = + Classroom.builder() + .classroomInfo( + ClassroomInfo.builder() + .name("1반") + .description("설명") + .grade(Grade.HIGH_1) + .build()) + .teacher(new TeacherId(10L)) + .build(); + classroom.addStudent(new StudentId(studentId)); + + final Member student = + Member.builder() + .memberInfo( + MemberInfo.builder().name("값").password("1234").build()) + .authorities(List.of(new Authority("STUDENT"))) + .build(); + student.withdrawal(); + + // when + when(classroomRepository.findById(anyLong())) + .thenReturn(Optional.ofNullable(classroom)); + when(memberRepository.findById(anyLong())) + .thenReturn(Optional.ofNullable(student)); + Throwable thrown = + catchException( + () -> + deleteStudentUsecase.deleteStudent( + classroomId, studentId)); + + // then + assertThat(thrown).isInstanceOf(AlreadyWithdrawlException.class); + } + } + } + + @DisplayName("요청받은 교실이 존재하지 않는다면") + @Nested + class ifClassroomDoesNotExist { + + @DisplayName("NoClassroomException 예외를 던진다.") + @Test + void throwNoClassroomException() { + // given + final long classroomId = 1L; + final long studentId = 2L; + final DeleteStudentDto.Request requestDto = + DeleteStudentDto.Request.builder() + .classroomId(classroomId) + .studentId(studentId) + .build(); + + // when + when(classroomRepository.findById(anyLong())).thenThrow(NoClassroomException.class); + Throwable thrown = + catchException( + () -> deleteStudentUsecase.deleteStudent(classroomId, studentId)); + + // then + assertThat(thrown).isInstanceOf(NoClassroomException.class); + } + } + } +} diff --git a/src/test/java/com/ohdab/classroom/service/GetWorkbookListServiceTest.java b/src/test/java/com/ohdab/classroom/service/GetWorkbookListServiceTest.java new file mode 100644 index 00000000..7e874d9a --- /dev/null +++ b/src/test/java/com/ohdab/classroom/service/GetWorkbookListServiceTest.java @@ -0,0 +1,73 @@ +package com.ohdab.classroom.service; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +import com.ohdab.classroom.domain.classroomid.ClassroomId; +import com.ohdab.classroom.repository.ClassroomRepository; +import com.ohdab.classroom.service.dto.ClassroomWorkbookDto; +import com.ohdab.classroom.service.usecase.GetWorkbookListUsecase; +import com.ohdab.workbook.domain.Workbook; +import com.ohdab.workbook.domain.workbookInfo.WorkbookInfo; +import com.ohdab.workbook.repository.WorkbookRepository; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = {GetWorkbookListService.class}) +class GetWorkbookListServiceTest { + + @Autowired private GetWorkbookListUsecase getWorkbookListUsecase; + @MockBean private ClassroomRepository classroomRepository; + @MockBean private WorkbookRepository workbookRepository; + + @Test + @DisplayName("교재 목록 조회 성공 테스트") + void 교재_목록_조회_성공() { + // given + long classroomId = 1L; + Workbook workbook1 = createWorkbook("교재"); + Workbook workbook2 = createWorkbook("교재2"); + Workbook workbook3 = createWorkbook("교재3"); + List workbookList = new ArrayList<>(); + workbookList.add(workbook1); + workbookList.add(workbook2); + workbookList.add(workbook3); + + // when + when(classroomRepository.existsById(Mockito.anyLong())).thenReturn(true); + when(workbookRepository.findByClassroomId(Mockito.any())).thenReturn(workbookList); + List results = + getWorkbookListUsecase.getWorkbookListByClassroomId(classroomId); + + // then + assertThat(results) + .hasSize(3) + .extracting(w -> w.getName()) + .contains( + workbook1.getWorkbookInfo().getName(), + workbook2.getWorkbookInfo().getName(), + workbook3.getWorkbookInfo().getName()); + } + + private Workbook createWorkbook(String name) { + return Workbook.builder() + .workbookInfo( + WorkbookInfo.builder() + .name(name) + .description(name + "의 설명입니다.") + .startingNumber(1) + .endingNumber(2000) + .build()) + .classroomId(new ClassroomId(1L)) + .build(); + } +} diff --git a/src/test/java/com/ohdab/classroom/service/UpdateClassroomInfoServiceTest.java b/src/test/java/com/ohdab/classroom/service/UpdateClassroomInfoServiceTest.java new file mode 100644 index 00000000..57c6cb86 --- /dev/null +++ b/src/test/java/com/ohdab/classroom/service/UpdateClassroomInfoServiceTest.java @@ -0,0 +1,64 @@ +package com.ohdab.classroom.service; + +import static org.assertj.core.api.Assertions.assertThatNoException; +import static org.mockito.Mockito.anyLong; +import static org.mockito.Mockito.when; + +import com.ohdab.classroom.domain.Classroom; +import com.ohdab.classroom.domain.classroomInfo.ClassroomInfo; +import com.ohdab.classroom.domain.classroomInfo.Grade; +import com.ohdab.classroom.repository.ClassroomRepository; +import com.ohdab.classroom.service.dto.ClassroomUpdateDto; +import com.ohdab.member.domain.teacher.teacherid.TeacherId; +import com.ohdab.member.repository.MemberRepository; +import java.util.Optional; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = {UpdateClassroomInfoService.class}) +class UpdateClassroomInfoServiceTest { + + @Autowired private UpdateClassroomInfoService updateClassroomInfoService; + @MockBean private MemberRepository memberRepository; + @MockBean private ClassroomRepository classroomRepository; + + @Test + @DisplayName("반 정보 수정 테스트") + void updateClassroomInfo() { + // given + String name = "1반"; + String desc = "1반에 대한 설명입니다."; + Classroom classroom = + Classroom.builder() + .teacher(TeacherId.builder().id(1).build()) + .classroomInfo( + ClassroomInfo.builder() + .name(name) + .description(desc) + .grade(Grade.HIGH_1) + .build()) + .build(); + + ClassroomUpdateDto.ClassroomUpdateDtoRequest request = + ClassroomUpdateDto.ClassroomUpdateDtoRequest.builder() + .classroomId(1L) + .name("2반") + .description("22") + .grade("high2") + .build(); + + // when + when(memberRepository.existsById(anyLong())).thenReturn(true); + when(classroomRepository.findById(anyLong())).thenReturn(Optional.ofNullable(classroom)); + + // then + assertThatNoException() + .isThrownBy(() -> updateClassroomInfoService.updateClassroomInfo(request)); + } +} diff --git a/src/test/java/com/ohdab/classroom/service/UpdateWorkbookInfoServiceTest.java b/src/test/java/com/ohdab/classroom/service/UpdateWorkbookInfoServiceTest.java new file mode 100644 index 00000000..ac15c3ad --- /dev/null +++ b/src/test/java/com/ohdab/classroom/service/UpdateWorkbookInfoServiceTest.java @@ -0,0 +1,64 @@ +package com.ohdab.classroom.service; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThatNoException; +import static org.mockito.Mockito.when; + +import com.ohdab.classroom.domain.classroomid.ClassroomId; +import com.ohdab.classroom.service.dto.ClassroomWorkbookUpdateDto; +import com.ohdab.classroom.service.usecase.UpdateWorkbookInfoUsecase; +import com.ohdab.workbook.domain.Workbook; +import com.ohdab.workbook.domain.workbookInfo.WorkbookInfo; +import com.ohdab.workbook.repository.WorkbookRepository; +import java.util.Optional; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = {UpdateWorkbookInfoService.class}) +public class UpdateWorkbookInfoServiceTest { + + @Autowired private UpdateWorkbookInfoUsecase updateWorkbookInfoUsecase; + @MockBean private WorkbookRepository workbookRepository; + + @Test + @DisplayName("교재 정보 수정 성공 테스트") + void 교재_정보_수정_성공() { + // given + long classroomId = 1L; + long workbookId = 2L; + String name = "수정된 교재명"; + String description = "수정된 교재 정보입니다."; + ClassroomWorkbookUpdateDto.Request updateWorkbookReq = + ClassroomWorkbookUpdateDto.Request.builder() + .id(workbookId) + .name(name) + .description(description) + .build(); + Workbook workbook = + Workbook.builder() + .workbookInfo( + WorkbookInfo.builder() + .name("교재") + .description("교재 정보입니다.") + .startingNumber(1) + .endingNumber(2000) + .build()) + .classroomId(new ClassroomId(classroomId)) + .build(); + + // when + when(workbookRepository.existsById(Mockito.anyLong())).thenReturn(true); + when(workbookRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.ofNullable(workbook)); + + // then + assertThatNoException() + .isThrownBy(() -> updateWorkbookInfoUsecase.updateWorkbookInfo(updateWorkbookReq)); + } +} diff --git a/src/test/java/com/ohdab/core/util/event/handler/StudentAddedHandlerTest.java b/src/test/java/com/ohdab/core/util/event/handler/StudentAddedHandlerTest.java new file mode 100644 index 00000000..8ca8b7a0 --- /dev/null +++ b/src/test/java/com/ohdab/core/util/event/handler/StudentAddedHandlerTest.java @@ -0,0 +1,37 @@ +package com.ohdab.core.util.event.handler; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ohdab.classroom.event.StudentAddedEvent; +import com.ohdab.classroom.service.dto.AddStudentDto; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.test.context.event.ApplicationEvents; +import org.springframework.test.context.event.RecordApplicationEvents; + +@SpringBootTest +@RecordApplicationEvents +class StudentAddedHandlerTest { + + @Autowired private ApplicationEventPublisher publisher; + @Autowired private ApplicationEvents events; + + @DisplayName("학생 추가 이벤트 발생시 회원가입을 시킨다.") + @Test + void 학생_추가_이벤트_발생시_회원가입() { + // given + final AddStudentDto.Request addStudentReq = + AddStudentDto.Request.builder().classroomId(1L).studentName("갑").build(); + + // when + publisher.publishEvent( + StudentAddedEvent.builder().studentName(addStudentReq.getStudentName()).build()); + + // then + long count = events.stream(StudentAddedEvent.class).count(); + assertThat(count).isEqualTo(1); + } +} diff --git a/src/test/java/com/ohdab/member/Controller/MemberControllerTest.java b/src/test/java/com/ohdab/member/controller/MemberControllerTest.java similarity index 91% rename from src/test/java/com/ohdab/member/Controller/MemberControllerTest.java rename to src/test/java/com/ohdab/member/controller/MemberControllerTest.java index 1d650359..0a45c917 100644 --- a/src/test/java/com/ohdab/member/Controller/MemberControllerTest.java +++ b/src/test/java/com/ohdab/member/controller/MemberControllerTest.java @@ -1,4 +1,4 @@ -package com.ohdab.member.Controller; +package com.ohdab.member.controller; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; @@ -12,7 +12,6 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; import com.fasterxml.jackson.databind.ObjectMapper; -import com.ohdab.member.controller.MemberController; import com.ohdab.member.controller.request.AddTeacherReq; import com.ohdab.member.controller.request.JoinReq; import com.ohdab.member.controller.request.LoginReq; @@ -20,11 +19,7 @@ import com.ohdab.member.controller.response.LoginRes; import com.ohdab.member.service.dto.MemberDtoForGetTeacherList; import com.ohdab.member.service.dto.MemberDtoForLogin; -import com.ohdab.member.service.usecase.AddTeacherUsecase; -import com.ohdab.member.service.usecase.DeleteTeacherUsecase; -import com.ohdab.member.service.usecase.GetTeacherListUsecase; -import com.ohdab.member.service.usecase.JoinUsecase; -import com.ohdab.member.service.usecase.LoginUsecase; +import com.ohdab.member.service.usecase.*; import java.util.ArrayList; import java.util.List; import org.junit.jupiter.api.Test; @@ -48,6 +43,7 @@ class MemberControllerTest { @MockBean private GetTeacherListUsecase getTeacherListUsecase; @MockBean private AddTeacherUsecase addTeacherUsecase; @MockBean private DeleteTeacherUsecase deleteTeacherUsecase; + @MockBean private WithdrawlUsecase withdrawlUsecase; @Test @WithMockUser @@ -153,6 +149,27 @@ private MemberDtoForGetTeacherList.Response createTeacher(long id, String name) .build(); } + @Test + @WithMockUser + void 회원탈퇴() throws Exception { + // given + final String WITHDRAWL_URL = "/members/withdrawl/{member-id}"; + + // when + + // then + mockMvc.perform( + patch(WITHDRAWL_URL, 1) + .with(csrf()) + .contentType(MediaType.APPLICATION_JSON)) + .andExpectAll( + status().isOk(), + content().contentType(MediaType.APPLICATION_JSON), + jsonPath("$.message").value("탈퇴되었습니다.")) + .andDo(print()) + .andDo(createDocument("members/withdrawl")); + } + @Test @WithMockUser void 선생님_추가() throws Exception { diff --git a/src/test/java/com/ohdab/member/repository/MemberRepositoryTest.java b/src/test/java/com/ohdab/member/repository/MemberRepositoryTest.java index ea8752d6..6ddcecbc 100644 --- a/src/test/java/com/ohdab/member/repository/MemberRepositoryTest.java +++ b/src/test/java/com/ohdab/member/repository/MemberRepositoryTest.java @@ -16,7 +16,7 @@ import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; @DataJpaTest -public class MemberRepositoryTest { +class MemberRepositoryTest { @Autowired private MemberRepository memberRepository; @Autowired private EntityManager entityManager; diff --git a/src/test/java/com/ohdab/member/repository/mapper/MemberMapperTest.java b/src/test/java/com/ohdab/member/repository/mapper/MemberMapperTest.java new file mode 100644 index 00000000..b30834b3 --- /dev/null +++ b/src/test/java/com/ohdab/member/repository/mapper/MemberMapperTest.java @@ -0,0 +1,70 @@ +package com.ohdab.member.repository.mapper; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.tuple; + +import com.ohdab.member.domain.Authority; +import com.ohdab.member.domain.Member; +import com.ohdab.member.domain.memberinfo.MemberInfo; +import com.ohdab.member.repository.MemberRepository; +import com.ohdab.mistakenote.service.dto.GetAllMistakeNoteInfoDto.Response.StudentInfoDto; +import java.util.List; +import javax.persistence.EntityManager; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mybatis.spring.boot.test.autoconfigure.AutoConfigureMybatis; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; + +@DataJpaTest +@AutoConfigureMybatis +class MemberMapperTest { + + @Autowired private MemberMapper memberMapper; + @Autowired private MemberRepository memberRepository; + @Autowired private EntityManager em; + + @DisplayName("특정 반의 학생 명단을 조회한다.") + @Test + void 교재_상세조회_학생명단() { + // given + final Member student1 = + Member.builder() + .memberInfo(MemberInfo.builder().name("갑").password("1234").build()) + .authorities(List.of(new Authority("STUDENT"))) + .build(); + final Member student2 = + Member.builder() + .memberInfo(MemberInfo.builder().name("을").password("1234").build()) + .authorities(List.of(new Authority("STUDENT"))) + .build(); + final Member student3 = + Member.builder() + .memberInfo(MemberInfo.builder().name("병").password("1234").build()) + .authorities(List.of(new Authority("STUDENT"))) + .build(); + + Member savedStudent1 = memberRepository.save(student1); + Member savedStudent2 = memberRepository.save(student2); + Member savedStudent3 = memberRepository.save(student3); + + em.flush(); + em.clear(); + + // when + List result = + memberMapper.findAllStudent( + List.of( + savedStudent1.getId(), + savedStudent2.getId(), + savedStudent3.getId())); + + // then + assertThat(result) + .hasSize(3) + .extracting("studentId", "name") + .contains(tuple(savedStudent1.getId(), "갑")) + .contains(tuple(savedStudent2.getId(), "을")) + .contains(tuple(savedStudent3.getId(), "병")); + } +} diff --git a/src/test/java/com/ohdab/member/service/AddTeacherServiceTest.java b/src/test/java/com/ohdab/member/service/AddTeacherServiceTest.java index 7c40438a..6849343a 100644 --- a/src/test/java/com/ohdab/member/service/AddTeacherServiceTest.java +++ b/src/test/java/com/ohdab/member/service/AddTeacherServiceTest.java @@ -4,7 +4,6 @@ import com.ohdab.member.repository.MemberRepository; import com.ohdab.member.service.dto.MemberDtoForAddTeacher; -import com.ohdab.member.service.helper.MemberHelperService; import com.ohdab.member.service.usecase.AddTeacherUsecase; import com.ohdab.member.service.usecase.JoinUsecase; import org.junit.jupiter.api.DisplayName; @@ -17,8 +16,8 @@ import org.springframework.test.context.junit.jupiter.SpringExtension; @ExtendWith(SpringExtension.class) -@ContextConfiguration(classes = {AddTeacherService.class, MemberHelperService.class}) -public class AddTeacherServiceTest { +@ContextConfiguration(classes = {AddTeacherService.class}) +class AddTeacherServiceTest { @Autowired private AddTeacherUsecase addTeacherUsecase; @MockBean private MemberRepository memberRepository; diff --git a/src/test/java/com/ohdab/member/service/DeleteTeacherServiceTest.java b/src/test/java/com/ohdab/member/service/DeleteTeacherServiceTest.java index fff4a4ed..1347b723 100644 --- a/src/test/java/com/ohdab/member/service/DeleteTeacherServiceTest.java +++ b/src/test/java/com/ohdab/member/service/DeleteTeacherServiceTest.java @@ -23,7 +23,7 @@ @ExtendWith(SpringExtension.class) @ContextConfiguration(classes = {DeleteTeacherService.class, MemberHelperService.class}) -public class DeleteTeacherServiceTest { +class DeleteTeacherServiceTest { @Autowired private DeleteTeacherUsecase deleteTeacherUsecase; @MockBean private MemberRepository memberRepository; diff --git a/src/test/java/com/ohdab/member/service/GetTeacherListServiceTest.java b/src/test/java/com/ohdab/member/service/GetTeacherListServiceTest.java index dbc1bea6..c8e8f255 100644 --- a/src/test/java/com/ohdab/member/service/GetTeacherListServiceTest.java +++ b/src/test/java/com/ohdab/member/service/GetTeacherListServiceTest.java @@ -22,7 +22,7 @@ @ExtendWith(SpringExtension.class) @ContextConfiguration(classes = {GetTeacherListService.class}) -public class GetTeacherListServiceTest { +class GetTeacherListServiceTest { @Autowired private GetTeacherListUsecase getTeacherListUsecase; @MockBean private MemberRepository memberRepository; diff --git a/src/test/java/com/ohdab/mistakenote/controller/MistakeNoteControllerTest.java b/src/test/java/com/ohdab/mistakenote/controller/MistakeNoteControllerTest.java new file mode 100644 index 00000000..8ac346c7 --- /dev/null +++ b/src/test/java/com/ohdab/mistakenote/controller/MistakeNoteControllerTest.java @@ -0,0 +1,220 @@ +package com.ohdab.mistakenote.controller; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.when; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.*; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.ohdab.mistakenote.controller.request.SaveMistakeNoteInfoReq; +import com.ohdab.mistakenote.service.dto.GetAllMistakeNoteInfoDto; +import com.ohdab.mistakenote.service.dto.GetAllMistakeNoteInfoDto.Response.StudentInfoDto; +import com.ohdab.mistakenote.service.dto.GetMistakeNoteInfoOfStudentDto; +import com.ohdab.mistakenote.service.dto.GetMistakeNoteInfoOfStudentDto.Response.MistakeNoteInfoDto; +import com.ohdab.mistakenote.service.dto.GetNumberWrongNTimesDto; +import com.ohdab.mistakenote.service.dto.SaveMistakeNoteInfoDto; +import com.ohdab.mistakenote.service.usecase.GetMistakeNoteInfoUsecase; +import com.ohdab.mistakenote.service.usecase.GetNumberWrongNTimesUsecase; +import com.ohdab.mistakenote.service.usecase.SaveMistakeNoteInfoUsecase; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.web.servlet.MockMvc; + +@AutoConfigureRestDocs +@WebMvcTest(controllers = MistakeNoteController.class) +class MistakeNoteControllerTest { + + @Autowired private MockMvc mockMvc; + @Autowired private ObjectMapper objectMapper; + @MockBean private GetMistakeNoteInfoUsecase getMistakeNoteInfoUsecase; + @MockBean private GetNumberWrongNTimesUsecase getNumberWrongNTimesUsecase; + @MockBean private SaveMistakeNoteInfoUsecase saveMistakeNoteInfoUsecase; + + @Test + @WithMockUser + void 학생별_오답노트_조회() throws Exception { + // given + final String GET_MISTAKE_NOTE_INFO_BY_STUDENT_URL = + "/mistake-notes/workbooks/{workbook-id}/students/{student-id}"; + + final List mistakeNoteInfo = new ArrayList<>(); + mistakeNoteInfo.add(MistakeNoteInfoDto.builder().wrongNumber(1).wrongCount(3).build()); + mistakeNoteInfo.add(MistakeNoteInfoDto.builder().wrongNumber(2).wrongCount(1).build()); + final GetMistakeNoteInfoOfStudentDto.Response responseDto = + GetMistakeNoteInfoOfStudentDto.Response.builder() + .mistakeNoteInfo(mistakeNoteInfo) + .build(); + + // when + when(getMistakeNoteInfoUsecase.getMistakeNoteInfoOfStudent(anyLong(), anyLong())) + .thenReturn(responseDto); + + // then + mockMvc.perform( + get(GET_MISTAKE_NOTE_INFO_BY_STUDENT_URL, 1, 2) + .with(csrf()) + .contentType(MediaType.APPLICATION_JSON)) + .andExpectAll( + status().isOk(), + content().contentType(MediaType.APPLICATION_JSON), + jsonPath("$[0].wrongNumber") + .value(responseDto.getMistakeNoteInfo().get(0).getWrongNumber()), + jsonPath("$[0].wrongCount") + .value(responseDto.getMistakeNoteInfo().get(0).getWrongCount()), + jsonPath("$[1].wrongNumber") + .value(responseDto.getMistakeNoteInfo().get(1).getWrongNumber()), + jsonPath("$[1].wrongCount") + .value(responseDto.getMistakeNoteInfo().get(1).getWrongCount())) + .andDo(print()) + .andDo(createDocument("mistake_note/getMistakeNoteInfoByStudent")); + } + + @Test + @WithMockUser + void 오답_기록하기() throws Exception { + // given + final String SAVE_MISTAKE_NOTE_INFO_URL = + "/mistake-notes/workbooks/{workbook-id}/students/{student-id}"; + + final List mistakeNumbers = new ArrayList<>(); + mistakeNumbers.add(1); + mistakeNumbers.add(2); + mistakeNumbers.add(3); + final SaveMistakeNoteInfoReq saveMistakeNoteInfoReq = + SaveMistakeNoteInfoReq.builder().mistakeNumbers(mistakeNumbers).build(); + + // when + doNothing() + .when(saveMistakeNoteInfoUsecase) + .saveMistakeNoteInfo(any(SaveMistakeNoteInfoDto.class)); + + // then + mockMvc.perform( + post(SAVE_MISTAKE_NOTE_INFO_URL, 1, 2) + .with(csrf()) + .content(objectMapper.writeValueAsString(saveMistakeNoteInfoReq)) + .contentType(MediaType.APPLICATION_JSON)) + .andExpectAll( + status().isOk(), + content().contentType(MediaType.APPLICATION_JSON), + jsonPath("$.message").value("오답이 기록되었습니다.")) + .andDo(print()) + .andDo(createDocument("mistake_note/saveMistakeNoteInfo")); + } + + @Test + @WithMockUser + void 교재_상세조회() throws Exception { + // given + final String GET_MISTAKE_NOTE_INFO_OF_CLASSROOM_URL = + "/mistake-notes/workbooks/{workbook-id}"; + + final List students = new ArrayList<>(); + students.add(StudentInfoDto.builder().studentId(2).name("갑").build()); + students.add(StudentInfoDto.builder().studentId(3).name("을").build()); + students.add(StudentInfoDto.builder().studentId(4).name("병").build()); + + final List mistakeNoteInfo = + new ArrayList<>(); + mistakeNoteInfo.add( + GetAllMistakeNoteInfoDto.Response.AllMistakeNoteInfoDto.builder() + .wrongNumber(1) + .wrongStudentsCount(4) + .build()); + mistakeNoteInfo.add( + GetAllMistakeNoteInfoDto.Response.AllMistakeNoteInfoDto.builder() + .wrongNumber(4) + .wrongStudentsCount(2) + .build()); + mistakeNoteInfo.add( + GetAllMistakeNoteInfoDto.Response.AllMistakeNoteInfoDto.builder() + .wrongNumber(10) + .wrongStudentsCount(7) + .build()); + + final GetAllMistakeNoteInfoDto.Response responseDto = + GetAllMistakeNoteInfoDto.Response.builder() + .students(students) + .allMistakeNoteInfo(mistakeNoteInfo) + .build(); + + // when + when(getMistakeNoteInfoUsecase.getAllMistakeNoteInfo(anyLong())).thenReturn(responseDto); + + // then + mockMvc.perform( + get(GET_MISTAKE_NOTE_INFO_OF_CLASSROOM_URL, 1) + .with(csrf()) + .contentType(MediaType.APPLICATION_JSON)) + .andExpectAll( + status().isOk(), + content().contentType(MediaType.APPLICATION_JSON), + jsonPath("$.students.[0].studentId").value(2), + jsonPath("$.students.[0].name").value("갑"), + jsonPath("$.students.[1].studentId").value(3), + jsonPath("$.students.[1].name").value("을"), + jsonPath("$.students.[2].studentId").value(4), + jsonPath("$.students.[2].name").value("병"), + jsonPath("$.mistakeNoteInfo.[0].wrongNumber").value(1), + jsonPath("$.mistakeNoteInfo.[0].wrongStudentsCount").value(4), + jsonPath("$.mistakeNoteInfo.[1].wrongNumber").value(4), + jsonPath("$.mistakeNoteInfo.[1].wrongStudentsCount").value(2), + jsonPath("$.mistakeNoteInfo.[2].wrongNumber").value(10), + jsonPath("$.mistakeNoteInfo.[2].wrongStudentsCount").value(7)) + .andDo(print()) + .andDo(createDocument("mistake_note/getAllMistakeNoteInfo")); + } + + @Test + @WithMockUser + void 학생별_N번_이상_틀린_문제_출력() throws Exception { + // given + final String GET_NUMBER_WRONG_N_TIMES = + "/mistake-notes/workbooks/{workbook-id}/{mistake-note-id}"; + + final String wrongNumber = "30,31,33,40,45,50"; + + final GetNumberWrongNTimesDto.Response responseDto = + GetNumberWrongNTimesDto.Response.builder().wrongNumber(wrongNumber).build(); + + // when + when(getNumberWrongNTimesUsecase.getNumberWrongNTimes( + any(GetNumberWrongNTimesDto.Request.class))) + .thenReturn(responseDto); + + // then + mockMvc.perform( + get(GET_NUMBER_WRONG_N_TIMES, 1L, 2L) + .param("count", "2") + .param("from", "30") + .param("to", "50") + .with(csrf()) + .contentType(MediaType.APPLICATION_JSON)) + .andExpectAll( + status().isOk(), + content().contentType(MediaType.APPLICATION_JSON), + jsonPath("$.wrongNumber").value(wrongNumber)) + .andDo(print()) + .andDo(createDocument("mistake_note/getNumberWrongNTimes")); + } + + private RestDocumentationResultHandler createDocument(String identifier) { + return document( + identifier, preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint())); + } +} diff --git a/src/test/java/com/ohdab/mistakenote/repository/MistakeNoteRepositoryTest.java b/src/test/java/com/ohdab/mistakenote/repository/MistakeNoteRepositoryTest.java new file mode 100644 index 00000000..c2c0984e --- /dev/null +++ b/src/test/java/com/ohdab/mistakenote/repository/MistakeNoteRepositoryTest.java @@ -0,0 +1,135 @@ +package com.ohdab.mistakenote.repository; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ohdab.member.domain.student.studentid.StudentId; +import com.ohdab.mistakenote.domain.MistakeNote; +import com.ohdab.workbook.domain.workbookid.WorkbookId; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.persistence.EntityManager; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; + +@DataJpaTest +class MistakeNoteRepositoryTest { + + @Autowired private MistakeNoteRepository mistakeNoteRepository; + @Autowired private EntityManager em; + + @DisplayName("교재 id와 학생 id를 통해 오답노트를 조회한다.") + @Test + void 학생별_오답노트_조회() { + // given + final StudentId studentId = new StudentId(1L); + final WorkbookId workbookId = new WorkbookId(2L); + + final Map mistakeRecords = new HashMap<>(); + mistakeRecords.put(1, 2); + mistakeRecords.put(2, 4); + mistakeRecords.put(4, 1); + final MistakeNote mistakeNote = + MistakeNote.builder() + .workbookId(workbookId) + .studentId(studentId) + .mistakeRecords(mistakeRecords) + .build(); + + mistakeNoteRepository.save(mistakeNote); + em.flush(); + em.clear(); + + // when + MistakeNote result = + mistakeNoteRepository.findByWorkbookIdAndStudentId(workbookId, studentId).get(); + + // then + assertThat(result.getWorkbookId().getId()).isEqualTo(workbookId.getId()); + assertThat(result.getStudentId().getId()).isEqualTo(studentId.getId()); + assertThat(result.getMistakeRecords()) + .containsEntry(1, 2) + .containsEntry(2, 4) + .containsEntry(4, 1); + } + + @DisplayName("변경감지를 활용하여 틀린 문제 번호마다 틀린 횟수를 저장한다.") + @Test + void 오답_기록하기() { + // given + final List numbers = new ArrayList<>(); + numbers.add(1); + numbers.add(2); + numbers.add(3); + numbers.add(5); + + final StudentId studentId = new StudentId(1L); + final WorkbookId workbookId = new WorkbookId(2L); + + final Map mistakeRecords = new HashMap<>(); + mistakeRecords.put(1, 2); + mistakeRecords.put(2, 4); + mistakeRecords.put(4, 1); + final MistakeNote mistakeNote = + MistakeNote.builder() + .workbookId(workbookId) + .studentId(studentId) + .mistakeRecords(mistakeRecords) + .build(); + + MistakeNote savedMistakeNote = mistakeNoteRepository.save(mistakeNote); + Map savedRecords = savedMistakeNote.getMistakeRecords(); + + // when + numbers.forEach( + number -> { + if (savedRecords.containsKey(number)) { + savedRecords.put(number, savedRecords.get(number) + 1); + } else { + savedRecords.put(number, 1); + } + }); + em.flush(); + em.clear(); + + // then + MistakeNote result = mistakeNoteRepository.findById(savedMistakeNote.getId()).get(); + Map resultRecords = result.getMistakeRecords(); + assertThat(resultRecords) + .containsEntry(1, 3) + .containsEntry(2, 5) + .containsEntry(3, 1) + .containsEntry(4, 1) + .containsEntry(5, 1); + } + + @Test + @DisplayName("오답 노트 생성 성공 테스트") + void 오답_노트_생성_성공_테스트() { + // given + MistakeNote mistakeNote = + MistakeNote.builder() + .studentId(new StudentId(1L)) + .workbookId(new WorkbookId(2L)) + .build(); + + // when + mistakeNote = mistakeNoteRepository.save(mistakeNote); + + // then + assertThat(mistakeNote) + .extracting( + m -> m.getId(), + m -> m.getWorkbookId().getId(), + m -> m.getStudentId().getId(), + m -> m.getMistakeRecords().size()) + .containsExactly( + mistakeNote.getId(), + mistakeNote.getWorkbookId().getId(), + mistakeNote.getStudentId().getId(), + mistakeNote.getMistakeRecords().size()); + } +} diff --git a/src/test/java/com/ohdab/mistakenote/repository/mapper/MistakeRecordMapperTest.java b/src/test/java/com/ohdab/mistakenote/repository/mapper/MistakeRecordMapperTest.java new file mode 100644 index 00000000..4c662826 --- /dev/null +++ b/src/test/java/com/ohdab/mistakenote/repository/mapper/MistakeRecordMapperTest.java @@ -0,0 +1,146 @@ +package com.ohdab.mistakenote.repository.mapper; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.tuple; + +import com.ohdab.member.domain.student.studentid.StudentId; +import com.ohdab.mistakenote.domain.MistakeNote; +import com.ohdab.mistakenote.repository.MistakeNoteRepository; +import com.ohdab.mistakenote.service.dto.GetAllMistakeNoteInfoDto.Response.AllMistakeNoteInfoDto; +import com.ohdab.mistakenote.service.dto.GetNumberWrongNTimesDto; +import com.ohdab.workbook.domain.workbookid.WorkbookId; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.persistence.EntityManager; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mybatis.spring.boot.test.autoconfigure.AutoConfigureMybatis; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; + +@DataJpaTest +@AutoConfigureMybatis +class MistakeRecordMapperTest { + + @Autowired private MistakeRecordMapper mistakeRecordMapper; + @Autowired private MistakeNoteRepository mistakeNoteRepository; + @Autowired private EntityManager em; + + @DisplayName("전체 학생에 대한 오답노트를 조회한다.") + @Test + void 교재_상세조회() { + // given + final WorkbookId workbookId = new WorkbookId(10L); + + final StudentId studentId1 = new StudentId(1L); + final Map mistakeRecords1 = new HashMap<>(); + mistakeRecords1.put(1, 1); + mistakeRecords1.put(2, 2); + mistakeRecords1.put(3, 3); + final MistakeNote mistakeNote1 = + MistakeNote.builder() + .workbookId(workbookId) + .studentId(studentId1) + .mistakeRecords(mistakeRecords1) + .build(); + + final StudentId studentId2 = new StudentId(2L); + final Map mistakeRecords2 = new HashMap<>(); + mistakeRecords2.put(3, 1); + mistakeRecords2.put(4, 2); + mistakeRecords2.put(5, 1); + final MistakeNote mistakeNote2 = + MistakeNote.builder() + .workbookId(workbookId) + .studentId(studentId2) + .mistakeRecords(mistakeRecords2) + .build(); + + final StudentId studentId3 = new StudentId(3L); + final Map mistakeRecords3 = new HashMap<>(); + mistakeRecords3.put(1, 1); + mistakeRecords3.put(102, 1); + mistakeRecords3.put(110, 2); + final MistakeNote mistakeNote3 = + MistakeNote.builder() + .workbookId(workbookId) + .studentId(studentId3) + .mistakeRecords(mistakeRecords3) + .build(); + + MistakeNote savedMistakeNote1 = mistakeNoteRepository.save(mistakeNote1); + MistakeNote savedMistakeNote2 = mistakeNoteRepository.save(mistakeNote2); + MistakeNote savedMistakeNote3 = mistakeNoteRepository.save(mistakeNote3); + + em.flush(); + em.clear(); + + // when + List result = + mistakeRecordMapper.findAllMistakeNoteInfo( + List.of( + savedMistakeNote1.getId(), + savedMistakeNote2.getId(), + savedMistakeNote3.getId())); + + // then + assertThat(result) + .extracting( + AllMistakeNoteInfoDto::getWrongNumber, + AllMistakeNoteInfoDto::getWrongStudentsCount) + .contains(tuple(1, 2)) + .contains(tuple(2, 1)) + .contains(tuple(3, 2)) + .contains(tuple(4, 1)) + .contains(tuple(5, 1)) + .contains(tuple(102, 1)) + .contains(tuple(110, 1)); + } + + @DisplayName("주어진 범위 내에서 N번 이상 틀린 문제 번호를 오름차순으로 조회한다.") + @Test + void 학생별_N번_이상_틀린_문제_출력() { + // given + final WorkbookId workbookId = new WorkbookId(10L); + + final StudentId studentId = new StudentId(1L); + final Map mistakeRecords = new HashMap<>(); + mistakeRecords.put(1, 1); + mistakeRecords.put(2, 2); + + mistakeRecords.put(10, 2); + mistakeRecords.put(20, 3); + mistakeRecords.put(22, 1); + mistakeRecords.put(25, 2); + mistakeRecords.put(30, 1); + + mistakeRecords.put(40, 4); + final MistakeNote mistakeNote = + MistakeNote.builder() + .workbookId(workbookId) + .studentId(studentId) + .mistakeRecords(mistakeRecords) + .build(); + + MistakeNote savedMistakeNote = mistakeNoteRepository.save(mistakeNote); + + em.flush(); + em.clear(); + + final GetNumberWrongNTimesDto.Request requestDto = + GetNumberWrongNTimesDto.Request.builder() + .workbookId(10L) + .mistakeNoteId(savedMistakeNote.getId()) + .count(2) + .from(10) + .to(30) + .build(); + + // when + List result = mistakeRecordMapper.findNumbersWrongNTimes(requestDto); + + // then + assertThat(result).hasSize(3).contains(10, 20, 25); + } +} diff --git a/src/test/java/com/ohdab/mistakenote/service/GetMistakeNoteInfoServiceTest.java b/src/test/java/com/ohdab/mistakenote/service/GetMistakeNoteInfoServiceTest.java new file mode 100644 index 00000000..ca0bbb67 --- /dev/null +++ b/src/test/java/com/ohdab/mistakenote/service/GetMistakeNoteInfoServiceTest.java @@ -0,0 +1,172 @@ +package com.ohdab.mistakenote.service; + +import static com.ohdab.mistakenote.service.dto.GetMistakeNoteInfoOfStudentDto.Response.MistakeNoteInfoDto; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.tuple; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.when; + +import com.ohdab.member.domain.Authority; +import com.ohdab.member.domain.Member; +import com.ohdab.member.domain.memberinfo.MemberInfo; +import com.ohdab.member.domain.student.studentid.StudentId; +import com.ohdab.member.repository.MemberRepository; +import com.ohdab.member.repository.mapper.MemberMapper; +import com.ohdab.mistakenote.domain.MistakeNote; +import com.ohdab.mistakenote.repository.MistakeNoteRepository; +import com.ohdab.mistakenote.repository.mapper.MistakeRecordMapper; +import com.ohdab.mistakenote.service.dto.GetAllMistakeNoteInfoDto; +import com.ohdab.mistakenote.service.dto.GetAllMistakeNoteInfoDto.Response.AllMistakeNoteInfoDto; +import com.ohdab.mistakenote.service.dto.GetAllMistakeNoteInfoDto.Response.StudentInfoDto; +import com.ohdab.mistakenote.service.dto.GetMistakeNoteInfoOfStudentDto.Response; +import com.ohdab.mistakenote.service.usecase.GetMistakeNoteInfoUsecase; +import com.ohdab.workbook.domain.workbookid.WorkbookId; +import java.util.*; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = {GetMistakeNoteInfoService.class}) +class GetMistakeNoteInfoServiceTest { + + @Autowired private GetMistakeNoteInfoUsecase getMistakeNoteInfoUsecase; + @MockBean private MistakeNoteRepository mistakeNoteRepository; + @MockBean private MemberRepository memberRepository; + @MockBean private MistakeRecordMapper mistakeRecordMapper; + @MockBean private MemberMapper memberMapper; + + @DisplayName("교재 Id, 학생 Id를 통해 학생별 오답노트를 조회한다.") + @Test + void 학생별_오답노트_조회() throws Exception { + // given + final long workbookId = 1; + final long studentId = 2; + + final List authorities = new ArrayList<>(); + authorities.add(new Authority("TEACHER")); + + final Member findMember = + Member.builder() + .memberInfo(MemberInfo.builder().name("test").password("1234").build()) + .authorities(authorities) + .build(); + + final Map mistakeRecords = new HashMap<>(); + mistakeRecords.put(1, 2); + mistakeRecords.put(2, 4); + mistakeRecords.put(4, 1); + + final MistakeNote mistakeNote = + MistakeNote.builder() + .workbookId(new WorkbookId(workbookId)) + .studentId(new StudentId(studentId)) + .mistakeRecords(mistakeRecords) + .build(); + + // when + when(memberRepository.findActiveMemberById(anyLong())).thenReturn(Optional.of(findMember)); + when(mistakeNoteRepository.findByWorkbookIdAndStudentId( + any(WorkbookId.class), any(StudentId.class))) + .thenReturn(Optional.of(mistakeNote)); + Response result = + getMistakeNoteInfoUsecase.getMistakeNoteInfoOfStudent(workbookId, studentId); + + // then + assertThat(result.getMistakeNoteInfo()) + .extracting(MistakeNoteInfoDto::getWrongNumber, MistakeNoteInfoDto::getWrongCount) + .contains(tuple(1, 2)) + .contains(tuple(2, 4)) + .contains(tuple(4, 1)); + } + + @DisplayName("교재 id를 통해 해당 교재에 대한 모든 학생들의 오답 기록을 조회한다.") + @Test + void 교재_상세조회() { + // given + final WorkbookId workbookId = new WorkbookId(1L); + + List mistakeNotes = new ArrayList<>(); + + final Map mistakeRecords2 = new HashMap<>(); + mistakeRecords2.put(1, 2); + mistakeRecords2.put(2, 2); + mistakeRecords2.put(3, 2); + mistakeNotes.add( + MistakeNote.builder() + .workbookId(workbookId) + .studentId(new StudentId(2L)) + .mistakeRecords(mistakeRecords2) + .build()); + + final Map mistakeNoteRecords3 = new HashMap<>(); + mistakeNoteRecords3.put(2, 2); + mistakeNoteRecords3.put(3, 2); + mistakeNoteRecords3.put(4, 2); + mistakeNotes.add( + MistakeNote.builder() + .workbookId(workbookId) + .studentId(new StudentId(3L)) + .mistakeRecords(mistakeNoteRecords3) + .build()); + + final Map mistakeRecords4 = new HashMap<>(); + mistakeRecords4.put(3, 2); + mistakeRecords4.put(4, 2); + mistakeRecords4.put(5, 2); + mistakeNotes.add( + MistakeNote.builder() + .workbookId(workbookId) + .studentId(new StudentId(4L)) + .mistakeRecords(mistakeRecords4) + .build()); + + final List students = new ArrayList<>(); + students.add(StudentInfoDto.builder().studentId(10L).name("갑").build()); + students.add(StudentInfoDto.builder().studentId(11L).name("을").build()); + students.add(StudentInfoDto.builder().studentId(12L).name("병").build()); + + final List allMistakeNoteInfoDto = new ArrayList<>(); + allMistakeNoteInfoDto.add( + AllMistakeNoteInfoDto.builder().wrongNumber(1).wrongStudentsCount(1).build()); + allMistakeNoteInfoDto.add( + AllMistakeNoteInfoDto.builder().wrongNumber(2).wrongStudentsCount(2).build()); + allMistakeNoteInfoDto.add( + AllMistakeNoteInfoDto.builder().wrongNumber(3).wrongStudentsCount(3).build()); + allMistakeNoteInfoDto.add( + AllMistakeNoteInfoDto.builder().wrongNumber(4).wrongStudentsCount(2).build()); + allMistakeNoteInfoDto.add( + AllMistakeNoteInfoDto.builder().wrongNumber(5).wrongStudentsCount(1).build()); + + // when + when(mistakeNoteRepository.findByWorkbookId(any(WorkbookId.class))) + .thenReturn(mistakeNotes); + when(memberMapper.findAllStudent(anyList())).thenReturn(students); + when(mistakeRecordMapper.findAllMistakeNoteInfo(anyList())) + .thenReturn(allMistakeNoteInfoDto); + GetAllMistakeNoteInfoDto.Response result = + getMistakeNoteInfoUsecase.getAllMistakeNoteInfo(workbookId.getId()); + + // then + assertThat(result.getAllMistakeNoteInfo()).hasSize(5); + assertThat(result.getAllMistakeNoteInfo()) + .extracting( + AllMistakeNoteInfoDto::getWrongNumber, + AllMistakeNoteInfoDto::getWrongStudentsCount) + .contains(tuple(1, 1)) + .contains(tuple(2, 2)) + .contains(tuple(3, 3)) + .contains(tuple(4, 2)) + .contains(tuple(5, 1)); + assertThat(result.getStudents()).hasSize(3); + assertThat(result.getStudents()) + .extracting(StudentInfoDto::getStudentId, StudentInfoDto::getName) + .contains(tuple(10L, "갑")) + .contains(tuple(11L, "을")) + .contains(tuple(12L, "병")); + } +} diff --git a/src/test/java/com/ohdab/mistakenote/service/GetNumberWrongNTimesServiceTest.java b/src/test/java/com/ohdab/mistakenote/service/GetNumberWrongNTimesServiceTest.java new file mode 100644 index 00000000..c6a19ab1 --- /dev/null +++ b/src/test/java/com/ohdab/mistakenote/service/GetNumberWrongNTimesServiceTest.java @@ -0,0 +1,180 @@ +package com.ohdab.mistakenote.service; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchException; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.when; + +import com.ohdab.classroom.domain.classroomid.ClassroomId; +import com.ohdab.mistakenote.exception.NoNumbersWrongNTimesException; +import com.ohdab.mistakenote.exception.NumberIsOutOfRangeException; +import com.ohdab.mistakenote.repository.mapper.MistakeRecordMapper; +import com.ohdab.mistakenote.service.dto.GetNumberWrongNTimesDto; +import com.ohdab.mistakenote.service.usecase.GetNumberWrongNTimesUsecase; +import com.ohdab.workbook.domain.Workbook; +import com.ohdab.workbook.domain.workbookInfo.WorkbookInfo; +import com.ohdab.workbook.repository.WorkbookRepository; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = {GetNumberWrongNTimesService.class}) +class GetNumberWrongNTimesServiceTest { + + @Autowired private GetNumberWrongNTimesUsecase getNumberWrongNTimesUsecase; + + @MockBean private MistakeRecordMapper mistakeRecordMapper; + @MockBean private WorkbookRepository workbookRepository; + + @DisplayName("getNumbersWrongNTimes 메서드는") + @Nested + class getNumbersWrongNTimes { + + @DisplayName("요청받은 범위가 해당 교재의 문제범위에 속하고") + @Nested + class ifInRange { + + @DisplayName("N번 이상 틀린 문제가 존재한다면") + @Nested + class ifResultIsExist { + @DisplayName("틀린 문제번호들을 쉼표로 구분하여 공백없는 문자열로 반환한다") + @Test + void success() { + // given + final GetNumberWrongNTimesDto.Request requestDto = + GetNumberWrongNTimesDto.Request.builder() + .workbookId(1L) + .mistakeNoteId(2L) + .count(2) + .from(10) + .to(20) + .build(); + + final Workbook workbook = + Workbook.builder() + .classroomId(new ClassroomId(10L)) + .workbookInfo( + WorkbookInfo.builder() + .name("책이름") + .description("설명") + .startingNumber(1) + .endingNumber(1000) + .build()) + .build(); + + final List numberWrongNTimes = List.of(10, 11, 12, 19, 20); + + // when + when(workbookRepository.findById(anyLong())) + .thenReturn(Optional.ofNullable(workbook)); + when(mistakeRecordMapper.findNumbersWrongNTimes(requestDto)) + .thenReturn(numberWrongNTimes); + GetNumberWrongNTimesDto.Response result = + getNumberWrongNTimesUsecase.getNumberWrongNTimes(requestDto); + + // then + assertThat(result) + .extracting(GetNumberWrongNTimesDto.Response::getWrongNumber) + .isEqualTo("10,11,12,19,20"); + } + } + + @DisplayName("N번 이상 틀린 문제가 없다면") + @Nested + class ifNoResult { + + @DisplayName("NoNumbersWrongNTimesException 예외를 던진다.") + @Test + void throwNoNumbersWrongNTimesException() { + // given + final GetNumberWrongNTimesDto.Request requestDto = + GetNumberWrongNTimesDto.Request.builder() + .workbookId(1L) + .mistakeNoteId(2L) + .count(2) + .from(10) + .to(20) + .build(); + + final Workbook workbook = + Workbook.builder() + .classroomId(new ClassroomId(10L)) + .workbookInfo( + WorkbookInfo.builder() + .name("책이름") + .description("설명") + .startingNumber(1) + .endingNumber(1000) + .build()) + .build(); + + final List numberWrongNTimes = new ArrayList<>(); + + // when + when(workbookRepository.findById(anyLong())) + .thenReturn(Optional.ofNullable(workbook)); + when(mistakeRecordMapper.findNumbersWrongNTimes(requestDto)) + .thenReturn(numberWrongNTimes); + Throwable thrown = + catchException( + () -> + getNumberWrongNTimesUsecase.getNumberWrongNTimes( + requestDto)); + + // then + assertThat(thrown).isInstanceOf(NoNumbersWrongNTimesException.class); + } + } + } + + @DisplayName("요청받은 범위가 해당 교재의 문제범위에 속하지 않는다면") + @Nested + class ifIsNotInRange { + + @DisplayName("NumberIsOutOfRangeException 예외를 던진다.") + @Test + void trowNumberIsOutOfRangeException() { + // given + final GetNumberWrongNTimesDto.Request requestDto = + GetNumberWrongNTimesDto.Request.builder() + .workbookId(1L) + .mistakeNoteId(2L) + .count(2) + .from(20) + .to(2000) + .build(); + + final Workbook workbook = + Workbook.builder() + .classroomId(new ClassroomId(10L)) + .workbookInfo( + WorkbookInfo.builder() + .name("책이름") + .description("설명") + .startingNumber(1) + .endingNumber(1000) + .build()) + .build(); + + // when + when(workbookRepository.findById(anyLong())) + .thenReturn(Optional.ofNullable(workbook)); + Throwable thrown = + catchException( + () -> getNumberWrongNTimesUsecase.getNumberWrongNTimes(requestDto)); + + // then + assertThat(thrown).isInstanceOf(NumberIsOutOfRangeException.class); + } + } + } +} diff --git a/src/test/java/com/ohdab/mistakenote/service/SaveMistakeNoteInfoServiceTest.java b/src/test/java/com/ohdab/mistakenote/service/SaveMistakeNoteInfoServiceTest.java new file mode 100644 index 00000000..5d270a32 --- /dev/null +++ b/src/test/java/com/ohdab/mistakenote/service/SaveMistakeNoteInfoServiceTest.java @@ -0,0 +1,108 @@ +package com.ohdab.mistakenote.service; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.when; + +import com.ohdab.classroom.domain.classroomid.ClassroomId; +import com.ohdab.member.domain.Authority; +import com.ohdab.member.domain.Member; +import com.ohdab.member.domain.memberinfo.MemberInfo; +import com.ohdab.member.domain.student.studentid.StudentId; +import com.ohdab.member.repository.MemberRepository; +import com.ohdab.mistakenote.domain.MistakeNote; +import com.ohdab.mistakenote.repository.MistakeNoteRepository; +import com.ohdab.mistakenote.service.dto.SaveMistakeNoteInfoDto; +import com.ohdab.mistakenote.service.usecase.SaveMistakeNoteInfoUsecase; +import com.ohdab.workbook.domain.Workbook; +import com.ohdab.workbook.domain.service.NumberScopeCheckService; +import com.ohdab.workbook.domain.workbookInfo.WorkbookInfo; +import com.ohdab.workbook.domain.workbookid.WorkbookId; +import com.ohdab.workbook.repository.WorkbookRepository; +import java.util.*; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = {SaveMistakeNoteInfoService.class, NumberScopeCheckService.class}) +class SaveMistakeNoteInfoServiceTest { + + @Autowired private SaveMistakeNoteInfoUsecase saveMistakeNoteInfoUsecase; + @MockBean private MemberRepository memberRepository; + @MockBean private MistakeNoteRepository mistakeNoteRepository; + @MockBean private WorkbookRepository workbookRepository; + + @DisplayName("틀린 문제의 번호들을 입력하여 학생의 오답을 기록한다.") + @Test + void 오답_기록하기() { + // given + final long workbookId = 1L; + final long studentId = 2L; + + final List authorities = new ArrayList<>(); + authorities.add(new Authority("STUDENT")); + final Member findMember = + Member.builder() + .memberInfo(MemberInfo.builder().name("test").password("1234").build()) + .authorities(authorities) + .build(); + + final List mistakeNumbers = new ArrayList<>(); + mistakeNumbers.add(1); + mistakeNumbers.add(2); + mistakeNumbers.add(3); + mistakeNumbers.add(5); + final SaveMistakeNoteInfoDto saveMistakeNoteInfoDto = + SaveMistakeNoteInfoDto.builder() + .workbookId(workbookId) + .studentId(studentId) + .mistakeNumbers(mistakeNumbers) + .build(); + + final Map mistakeRecords = new HashMap<>(); + mistakeRecords.put(1, 2); + mistakeRecords.put(2, 4); + mistakeRecords.put(4, 1); + final MistakeNote mistakeNote = + MistakeNote.builder() + .workbookId(new WorkbookId(workbookId)) + .studentId(new StudentId(studentId)) + .mistakeRecords(mistakeRecords) + .build(); + + final WorkbookInfo workbookInfo = + WorkbookInfo.builder() + .name("test workbook") + .description("test description") + .startingNumber(1) + .endingNumber(4000) + .build(); + final Workbook workbook = + Workbook.builder() + .classroomId(new ClassroomId(3L)) + .workbookInfo(workbookInfo) + .build(); + + // when + when(memberRepository.findActiveMemberById(anyLong())).thenReturn(Optional.of(findMember)); + when(mistakeNoteRepository.findByWorkbookIdAndStudentId( + any(WorkbookId.class), any(StudentId.class))) + .thenReturn(Optional.of(mistakeNote)); + when(workbookRepository.findById(anyLong())).thenReturn(Optional.of(workbook)); + saveMistakeNoteInfoUsecase.saveMistakeNoteInfo(saveMistakeNoteInfoDto); + + // then + assertThat(mistakeNote.getMistakeRecords()) + .containsEntry(1, 3) + .containsEntry(2, 5) + .containsEntry(3, 1) + .containsEntry(4, 1) + .containsEntry(5, 1); + } +} diff --git a/src/test/java/com/ohdab/workbook/repository/WorkbookRepositoryTest.java b/src/test/java/com/ohdab/workbook/repository/WorkbookRepositoryTest.java new file mode 100644 index 00000000..35d5ac70 --- /dev/null +++ b/src/test/java/com/ohdab/workbook/repository/WorkbookRepositoryTest.java @@ -0,0 +1,176 @@ +package com.ohdab.workbook.repository; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.tuple; + +import com.ohdab.classroom.domain.classroomid.ClassroomId; +import com.ohdab.workbook.domain.Workbook; +import com.ohdab.workbook.domain.workbookInfo.WorkbookInfo; +import java.time.format.DateTimeFormatter; +import java.util.List; +import javax.persistence.EntityManager; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; + +@DataJpaTest +class WorkbookRepositoryTest { + + @Autowired private WorkbookRepository workbookRepository; + + @Autowired private EntityManager entityManager; + + @Test + @DisplayName("반 식별자로 반에 있는 교재 목록 조회 성공 테스트") + void 반_식별자로_반에_있는_교재_목록_조회_성공() { + // given + long classroomId = 1L; + Workbook workbook1 = createAndSaveWorkbook("교재", classroomId); + Workbook workbook2 = createAndSaveWorkbook("교재2", classroomId); + Workbook workbook3 = createAndSaveWorkbook("교재3", 2L); + + // when + List results = workbookRepository.findByClassroomId(new ClassroomId(classroomId)); + + // then + assertThat(results) + .hasSize(2) + .extracting( + Workbook::getId, + w -> w.getClassroomId().getId(), + w -> w.getWorkbookInfo().getName(), + w -> w.getWorkbookInfo().getDescription(), + w -> w.getWorkbookInfo().getStartingNumber(), + w -> w.getWorkbookInfo().getEndingNumber(), + w -> + w.getCreatedAt() + .format( + DateTimeFormatter.ofPattern( + "uuuu-MM-dd'T'HH:mm:ss"))) + .contains( + tuple( + workbook1.getId(), + workbook1.getClassroomId().getId(), + workbook1.getWorkbookInfo().getName(), + workbook1.getWorkbookInfo().getDescription(), + workbook1.getWorkbookInfo().getStartingNumber(), + workbook1.getWorkbookInfo().getEndingNumber(), + workbook1 + .getCreatedAt() + .format( + DateTimeFormatter.ofPattern( + "uuuu-MM-dd'T'HH:mm:ss"))), + tuple( + workbook2.getId(), + workbook2.getClassroomId().getId(), + workbook2.getWorkbookInfo().getName(), + workbook2.getWorkbookInfo().getDescription(), + workbook2.getWorkbookInfo().getStartingNumber(), + workbook2.getWorkbookInfo().getEndingNumber(), + workbook2 + .getCreatedAt() + .format( + DateTimeFormatter.ofPattern( + "uuuu-MM-dd'T'HH:mm:ss")))); + } + + @Test + @DisplayName("교재 저장 성공 테스트") + void 교재_저장_성공() { + // given + Workbook workbook = createAndSaveWorkbook("교재", 1L); + + // when + workbook = workbookRepository.save(workbook); + Workbook result = workbookRepository.findById(workbook.getId()).get(); + + // then + assertThat(result) + .extracting( + Workbook::getId, + w -> w.getWorkbookInfo().getName(), + w -> w.getWorkbookInfo().getDescription(), + w -> w.getWorkbookInfo().getStartingNumber(), + w -> w.getWorkbookInfo().getEndingNumber(), + w -> w.getClassroomId().getId()) + .containsExactly( + workbook.getId(), + workbook.getWorkbookInfo().getName(), + workbook.getWorkbookInfo().getDescription(), + workbook.getWorkbookInfo().getStartingNumber(), + workbook.getWorkbookInfo().getEndingNumber(), + workbook.getClassroomId().getId()); + } + + @Test + @DisplayName("반 식별자와 교재 이름으로 교재 존재 여부 확인 성공 테스트") + void 반_식별자와_교재_이름으로_교재_존재_여부_확인_성공() { + // given + long classroomId = 1L; + String name = "교재"; + Workbook workbook = createAndSaveWorkbook(name, classroomId); + + // when + workbook = workbookRepository.save(workbook); + boolean result = + workbookRepository.existsByClassroomIdAndWorkbookInfoName( + new ClassroomId(classroomId), name); + + // then + assertThat(result).isTrue(); + } + + @Test + @DisplayName("교재 정보 수정 성공 테스트") + void 교재_정보_수정_성공() { + // given + Workbook workbook = createAndSaveWorkbook("교재", 1L); + String name = "수정 교재명"; + String description = "수정된 교재 정보입니다."; + + // when + workbook = workbookRepository.save(workbook); + workbook.updateWorkbookInfo( + WorkbookInfo.builder() + .name(name) + .description(description) + .startingNumber(workbook.getWorkbookInfo().getStartingNumber()) + .endingNumber(workbook.getWorkbookInfo().getEndingNumber()) + .build()); + entityManager.flush(); + entityManager.clear(); + Workbook result = workbookRepository.findById(workbook.getId()).get(); + + // then + assertThat(result) + .extracting( + Workbook::getId, + w -> w.getWorkbookInfo().getName(), + w -> w.getWorkbookInfo().getDescription(), + w -> w.getWorkbookInfo().getStartingNumber(), + w -> w.getWorkbookInfo().getEndingNumber(), + w -> w.getClassroomId().getId()) + .containsExactly( + workbook.getId(), + name, + description, + workbook.getWorkbookInfo().getStartingNumber(), + workbook.getWorkbookInfo().getEndingNumber(), + workbook.getClassroomId().getId()); + } + + private Workbook createAndSaveWorkbook(String name, long classroomId) { + return workbookRepository.save( + Workbook.builder() + .workbookInfo( + WorkbookInfo.builder() + .name(name) + .description(name + "의 설명입니다.") + .startingNumber(1) + .endingNumber(2000) + .build()) + .classroomId(new ClassroomId(classroomId)) + .build()); + } +} diff --git a/src/test/resources/application.yml b/src/test/resources/application.yml index b076decc..1bc70598 100644 --- a/src/test/resources/application.yml +++ b/src/test/resources/application.yml @@ -9,4 +9,8 @@ spring: properties: hibernate: format_sql: true - use_sql_comments: true \ No newline at end of file + use_sql_comments: true + +mybatis: + mapper-locations: mapper/*.xml + type-aliases-package: com/ohdab \ No newline at end of file