Skip to content

Commit

Permalink
Merge pull request #221 from SW-CSS/develop
Browse files Browse the repository at this point in the history
Release
  • Loading branch information
llddang authored Oct 18, 2024
2 parents a5a06d3 + 26c09ab commit cc3f682
Show file tree
Hide file tree
Showing 32 changed files with 557 additions and 95 deletions.
16 changes: 15 additions & 1 deletion backend/src/docs/asciidoc/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,21 @@ include::{snippets}/student-find-all/http-response.adoc[]
.Response Body
include::{snippets}/student-find-all/response-fields.adoc[]

=== `GET`: 교직원 목록 조회

.HTTP Request
include::{snippets}/faculty-find-all/http-request.adoc[]

.Path Parameters
include::{snippets}/faculty-find-all/query-parameters.adoc[]

.HTTP Response
include::{snippets}/faculty-find-all/http-response.adoc[]

.Response Body
include::{snippets}/faculty-find-all/response-fields.adoc[]


=== `PATCH`: 비밀번호 수정

.HTTP Request
Expand Down Expand Up @@ -334,4 +349,3 @@ include::{snippets}/admin-auth-delete/request-body.adoc[]

.HTTP Response
include::{snippets}/admin-auth-delete/http-response.adoc[]

Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public ResponseEntity<Void> registerFaculties(
public ResponseEntity<Void> deleteFaculty(
@SuperAdminInterface FacultyMember facultyMember,
@RequestBody @Valid DeleteFacultyRequest request) {
adminAuthCommandService.deleteFaculty(request.member_id());
adminAuthCommandService.deleteFaculty(request.faculty_id());
return ResponseEntity.noContent().build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,12 @@ public void registerFaculties(MultipartFile file) {
}

@Transactional
public void deleteFaculty(Long memberId) {
FacultyMember facultyMember = facultyMemberRepository.findById(memberId)
public void deleteFaculty(Long facultyId) {
FacultyMember facultyMember = facultyMemberRepository.findById(facultyId)
.orElseThrow(() -> new AdminAuthException(AdminAuthExceptionType.MEMBER_NOT_FOUND));

if(facultyMember.getId() == 1) throw new AdminAuthException(AdminAuthExceptionType.MEMBER_NOT_FOUND);

Member member = facultyMember.getMember();

checkIsMemberDeleted(member);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package sw_css.admin.auth.application.dto.request;

public record DeleteFacultyRequest(
Long member_id
Long faculty_id
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public enum AdminAuthExceptionType implements BaseExceptionType {
FAILED_REGISTER_FACULTY(HttpStatus.BAD_REQUEST, ""),
MEMBER_EMAIL_DUPLICATE(HttpStatus.CONFLICT, "이메일이 중복됩니다."),
MEMBER_NOT_FOUND(HttpStatus.NOT_FOUND, "해당 회원을 찾을 수 없습니다."),
CANNOT_DELETE_SUPER_ADMIN(HttpStatus.FORBIDDEN, "최고 관리자는 삭제할 수 없습니다.")
;

private final HttpStatus httpStatus;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,38 @@

import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import sw_css.admin.member.application.MemberAdminQueryService;
import sw_css.admin.member.application.dto.response.FacultyMemberResponse;
import sw_css.member.application.dto.response.StudentMemberResponse;
import sw_css.member.domain.FacultyMember;
import sw_css.utils.annotation.AdminInterface;

@Validated
@RequestMapping("/admin/members")
@RequestMapping("/admin/member")
@RestController
@RequiredArgsConstructor
public class MemberAdminController {
private final MemberAdminQueryService memberAdminQueryService;

@GetMapping
public ResponseEntity<List<StudentMemberResponse>> findAllStudent() {
@GetMapping("/students")
public ResponseEntity<List<StudentMemberResponse>> findAllStudent(@AdminInterface FacultyMember facultyMember) {
return ResponseEntity.ok(memberAdminQueryService.findStudentMembers());
}

@GetMapping("/faculties")
public ResponseEntity<Page<FacultyMemberResponse>> findAllFaculty(
@AdminInterface FacultyMember facultyMember,
@RequestParam(value = "field", required = false) final Integer field,
@RequestParam(value = "keyword", required = false) final String keyword,
final Pageable pageable) {
return ResponseEntity.ok(memberAdminQueryService.findFacultyMembers(field, keyword, pageable));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,33 @@

import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import sw_css.admin.member.application.dto.response.FacultyMemberResponse;
import sw_css.member.application.dto.response.StudentMemberResponse;
import sw_css.member.domain.FacultyMember;
import sw_css.member.domain.StudentMember;
import sw_css.member.domain.repository.FacultyMemberCustomRepository;
import sw_css.member.domain.repository.FacultyMemberRepository;
import sw_css.member.domain.repository.StudentMemberRepository;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class MemberAdminQueryService {
private final StudentMemberRepository studentMemberRepository;
private final FacultyMemberCustomRepository facultyMemberCustomRepository;

public List<StudentMemberResponse> findStudentMembers() {
final List<StudentMember> students = studentMemberRepository.findAll();
return students.stream().map(StudentMemberResponse::from).toList();
}

public Page<FacultyMemberResponse> findFacultyMembers(final Integer field, final String keyword, final Pageable pageable) {
final Page<FacultyMember> faculties = facultyMemberCustomRepository.findFacultyMembers(field, keyword, pageable);

return FacultyMemberResponse.from(faculties, pageable);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package sw_css.admin.member.application.dto.response;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import sw_css.member.domain.FacultyMember;

public record FacultyMemberResponse(
Long id,
Long facultyId,
String email,
String name,
String phoneNumber) {
public static FacultyMemberResponse from(final FacultyMember facultyMember) {
return new FacultyMemberResponse(
facultyMember.getMember().getId(),
facultyMember.getId(),
facultyMember.getMember().getEmail(),
facultyMember.getMember().getName(),
facultyMember.getMember().getPhoneNumber()
);
}

public static Page<FacultyMemberResponse> from(final Page<FacultyMember> faculties, final Pageable pageable) {
return new PageImpl<>(faculties.stream()
.map(FacultyMemberResponse::from)
.toList(), pageable, faculties.getTotalElements());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.IntStream;
import lombok.RequiredArgsConstructor;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.Cell;
Expand All @@ -30,6 +32,7 @@
import sw_css.admin.milestone.application.dto.response.MilestoneHistoryResponse;
import sw_css.admin.milestone.application.dto.response.MilestoneScoreResponse;
import sw_css.admin.milestone.persistence.StudentAndMilestoneScoreInfo;
import sw_css.admin.milestone.persistence.StudentAndMilestoneTotalScoreInfoMapping;
import sw_css.member.application.dto.response.StudentMemberReferenceResponse;
import sw_css.milestone.application.dto.response.MilestoneScoreOfStudentResponse;
import sw_css.milestone.domain.MilestoneCategory;
Expand Down Expand Up @@ -173,31 +176,31 @@ public Page<MilestoneScoreResponse> findAllMilestoneHistoryScores(final String s
final Pageable pageable) {
final LocalDate parsedStartDate = parseDate(startDate);
final LocalDate parsedEndDate = parseDate(endDate);
final long categoryCount = milestoneCategoryRepository.count();
final List<StudentAndMilestoneScoreInfo> milestoneHistoryInfos = milestoneScoreRepository.findMilestoneScoresWithStudentInfoByPeriod(
parsedStartDate, parsedEndDate, pageable.getPageNumber() * pageable.getPageSize() * categoryCount,
pageable.getPageSize() * categoryCount);
final List<StudentAndMilestoneTotalScoreInfoMapping> milestoneHistoryInfos = milestoneScoreRepository.findMilestoneScoresWithStudentInfoByPeriod(
parsedStartDate, parsedEndDate, pageable.getPageNumber() * pageable.getPageSize() * 1L, pageable.getPageSize() * 1L);

System.out.println(milestoneHistoryInfos);

final Long totalMilestoneHistoryInfoCount = milestoneScoreRepository.countAllMilestoneScoresWithStudentInfoByPeriod();
final Map<StudentMemberReferenceResponse, List<StudentAndMilestoneScoreInfo>> groupedMilestoneScoresByStudentId = milestoneHistoryInfos.stream()
.collect(groupingBy(
(info -> new StudentMemberReferenceResponse(info.studentId(), info.studentName()))));
final List<MilestoneScoreResponse> content = groupedMilestoneScoresByStudentId.entrySet()
.stream()
.map(entry -> new MilestoneScoreResponse(
entry.getKey(),
entry.getValue()
.stream()
.map(info -> new MilestoneScoreOfStudentResponse(
info.categoryId(), info.categoryName(), info.milestoneGroup(),
info.limitScore(), info.score()))
.collect(groupingBy(MilestoneScoreOfStudentResponse::group))))
.sorted(Comparator.comparing(
(MilestoneScoreResponse response) -> response.milestoneScores().entrySet().stream()
.flatMap(entry -> entry.getValue().stream())
.mapToInt(MilestoneScoreOfStudentResponse::score)
.sum()
).reversed())
.toList();

final List<MilestoneScoreResponse> content = milestoneHistoryInfos.stream().map(entry -> {
Long[] categoryIds = Arrays.stream(entry.categoryIds().split(",")).map(Long::valueOf).toArray(Long[]::new);
String[] categoryNames = entry.categoryNames().split(",");
MilestoneGroup[] milestoneGroups = Arrays.stream(entry.milestoneGroups().split(",")).map(MilestoneGroup::valueOf).toArray(MilestoneGroup[]::new);
Integer[] scores = Arrays.stream(entry.scores().split(",")).map(Integer::valueOf).toArray(Integer[]::new);
Integer[] limitScores = Arrays.stream(entry.limitScores().split(",")).map(Integer::valueOf).toArray(Integer[]::new);

return new MilestoneScoreResponse(
new StudentMemberReferenceResponse(entry.studentId(), entry.studentName()),
IntStream.range(0, categoryIds.length).mapToObj(i -> new MilestoneScoreOfStudentResponse(
categoryIds[i], categoryNames[i], milestoneGroups[i], limitScores[i], scores[i]))
.sorted(Comparator.comparing(MilestoneScoreOfStudentResponse::id))
.collect(groupingBy(MilestoneScoreOfStudentResponse::group))
);
}).toList();

System.out.println(content);

return new PageImpl<>(content, pageable, totalMilestoneHistoryInfoCount);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package sw_css.admin.milestone.persistence;

import jakarta.persistence.ColumnResult;
import java.lang.reflect.Array;
import java.util.List;
import sw_css.milestone.domain.MilestoneGroup;

public record StudentAndMilestoneTotalScoreInfoMapping(
Long studentId,
String studentName,
String categoryIds,
String categoryNames,
String milestoneGroups,
String limitScores,
String scores,
Long totalScore) {
}
26 changes: 26 additions & 0 deletions backend/src/main/java/sw_css/member/domain/FacultySearchField.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package sw_css.member.domain;

import java.util.Arrays;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import sw_css.member.exception.MemberException;
import sw_css.member.exception.MemberExceptionType;

@RequiredArgsConstructor
public enum FacultySearchField {
FACULTY_ID(1),
MEMBER_NAME(2),
MEMBER_EMAIL(3);

final Integer fieldId;

public static FacultySearchField fromValue(final Integer fieldId) {
return Arrays.stream(values()).filter(field -> Objects.equals(field.getFieldId(), fieldId)).findFirst()
.orElseThrow(() -> new MemberException(
MemberExceptionType.INVALID_SEARCH_FIELD_ID));
}

public Integer getFieldId() {
return fieldId;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package sw_css.member.domain.repository;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.lang.Nullable;
import sw_css.member.domain.FacultyMember;

public interface FacultyMemberCustomRepository {

Page<FacultyMember> findFacultyMembers(@Nullable final Integer field,
@Nullable final String keyword,
final Pageable pageable);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,5 @@
import sw_css.member.domain.FacultyMember;

public interface FacultyMemberRepository extends JpaRepository<FacultyMember, Long> {
boolean existsByMemberId(Long memberId);

Optional<FacultyMember> findByMemberId(Long memberId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
public enum MemberExceptionType implements BaseExceptionType {
MEMBER_NOT_FOUND(HttpStatus.NOT_FOUND, "해당 회원을 찾을 수 없습니다."),
MEMBER_WRONG_PASSWORD(HttpStatus.BAD_REQUEST, "비밀번호가 잘못되었습니다."),
NOT_FOUND_STUDENT(HttpStatus.NOT_FOUND, "해당하는 학생이 존재하지 않습니다.");
NOT_FOUND_STUDENT(HttpStatus.NOT_FOUND, "해당하는 학생이 존재하지 않습니다."),
INVALID_SEARCH_FIELD_ID(HttpStatus.BAD_REQUEST, "검색 유형이 올바르지 않습니다."),
;


private final HttpStatus httpStatus;
Expand Down
Loading

0 comments on commit cc3f682

Please sign in to comment.