Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,6 @@ public ApiResponse<Void> createCurriculum(@RequestBody @Valid CreateCurriculumRe
return ApiResponse.onCreate();
}

// @GetMapping()
// @Operation(summary = "커리큘럼 목록 조회")
// public ApiResponse<ListCurriculumResponse> getCurriculumList(
// @ParameterObject @ModelAttribute @Valid SearchCurriculumRequest request) {
// return ApiResponse.onSuccess(curriculumService.getCurriculumList(request));
// }

@GetMapping("/{curriculum-id}")
@Operation(summary = "커리큘럼 상세 조회")
public ApiResponse<DetailCurriculumResponse> getCurriculum(@PathVariable("curriculum-id") Long curriculumId) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.example.domain.curriculum.controller.request;

import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;

@Schema(description = "커리큘럼 순서 변경 요청 객체")
public record ReorderCurriculumRequest(

@Schema(description = "커리큘럼 ID 목록")
List<Long> curriculumIdList
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.querydsl.jpa.impl.JPAQueryFactory;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.example.domain.curriculum.Curriculum;
import org.example.domain.curriculum.controller.response.ListCurriculumDto;
import org.springframework.stereotype.Repository;

Expand Down Expand Up @@ -41,8 +42,27 @@ public List<ListCurriculumDto> getCurriculumList(Long studyId) {
.where(curriculum.study.id.eq(studyId))
.orderBy(
curriculum.week.asc(),
curriculum.id.asc()
curriculum.orderNumber.asc()
)
.fetch();
}

public List<Curriculum> getCurriculumListOver(Long studyId, int week) {

return queryFactory
.selectFrom(curriculum)
.where(
curriculum.study.id.eq(studyId),
curriculum.orderNumber.goe(
JPAExpressions
.select(curriculum.orderNumber.min())
.from(curriculum)
.where(
curriculum.study.id.eq(studyId),
curriculum.week.gt(week))
)
)
.orderBy(curriculum.orderNumber.asc())
.fetch();
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
package org.example.domain.curriculum.service;

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.example.api_response.exception.GeneralException;
import org.example.api_response.status.ErrorStatus;
import org.example.domain.curriculum.Curriculum;
import org.example.domain.curriculum.controller.request.CreateCurriculumRequest;
import org.example.domain.curriculum.controller.request.ReorderCurriculumRequest;
import org.example.domain.curriculum.controller.request.UpdateCurriculumRequest;
import org.example.domain.curriculum.repository.CurriculumRepository;
import org.example.domain.curriculum.repository.ListCurriculumRepository;
import org.example.domain.study.Study;
import org.example.domain.study.enums.StudyType;
import org.example.domain.study.service.CoreStudyService;
Expand All @@ -21,6 +28,7 @@ public class CreateCurriculumService {

private final CoreCurriculumService coreCurriculumService;
private final CoreStudyService coreStudyService;
private final ListCurriculumRepository listCurriculumRepository;
private final CurriculumRepository curriculumRepository;

/**
Expand All @@ -37,14 +45,22 @@ public void createCurriculum(CreateCurriculumRequest request) {
throw new GeneralException(ErrorStatus.BAD_REQUEST, "자율 스터디는 커리큘럼을 생성할 수 없습니다.");
}

// 요청 주차의 이후의 모든 커리큘럼 조회
List<Curriculum> curriculumList = listCurriculumRepository.getCurriculumListOver(request.studyId(), request.week());

int newOrderNumber = getNewOrderNumber(curriculumList, study);
curriculumList.forEach(Curriculum::increaseOrderNumber); // 순서 재조정

curriculumRepository.save(
Curriculum.builder()
.study(study)
.title(request.title())
.week(request.week())
.content(request.content())
.orderNumber(newOrderNumber)
.build()
);

}

/**
Expand All @@ -64,19 +80,66 @@ public void updateCurriculum(Long curriculumId, UpdateCurriculumRequest request)
throw new GeneralException(ErrorStatus.BAD_REQUEST, "자율 스터디는 커리큘럼을 생성할 수 없습니다.");
}
}

int newOrderNumber = curriculum.getOrderNumber(); // 주차 변경 없으면 기존 순서 유지
if (!curriculum.getWeek().equals(request.week())) { // 주차 변경 시 순서 재조정
// 요청 주차의 이후의 모든 커리큘럼 조회
List<Curriculum> curriculumList = listCurriculumRepository.getCurriculumListOver(request.studyId(), request.week());
newOrderNumber = getNewOrderNumber(curriculumList, study);
curriculumList.forEach(Curriculum::increaseOrderNumber);
}

curriculum.update(
study,
request.title(),
request.week(),
request.content()
request.content(),
newOrderNumber
);
}

private int getNewOrderNumber(List<Curriculum> curriculumList, Study study) {
return curriculumList.isEmpty() ?
Optional.ofNullable(curriculumRepository.findMaxOrderNumberByStudy(study)).orElse(0) + 1 :
curriculumList.get(0).getOrderNumber();
}

/**
* 커리큘럼 삭제
*/
public void deleteCurriculum(Long curriculumId) {
Curriculum curriculum = coreCurriculumService.findById(curriculumId);
curriculumRepository.delete(curriculum);
}

/**
* 커리큘럼 순서 변경
*/
public void reorderCurriculum(Long studyId, ReorderCurriculumRequest request) {
List<Curriculum> curriculumList = curriculumRepository.findAllById(request.curriculumIdList());
if (request.curriculumIdList().size() != curriculumRepository.findAllByStudy(coreStudyService.findById(studyId)).size())
throw new GeneralException(ErrorStatus.BAD_REQUEST, "모든 커리큘럼을 포함해야 합니다.");

// 조회한 커리큘럼 목록을 요청 순서대로 재정렬
Map<Long, Curriculum> idMap = curriculumList.stream().collect(Collectors.toMap(Curriculum::getId, Function.identity()));
List<Curriculum> orderedCurriculumList = request.curriculumIdList().stream().map(idMap::get).toList();

int orderNumber = 1;
for (int i = 0; i < orderedCurriculumList.size(); i++) {
Curriculum curriculum = orderedCurriculumList.get(i);
if (!curriculum.getStudy().getId().equals(studyId))
throw new GeneralException(ErrorStatus.BAD_REQUEST, "요청이 올바르지 않습니다. 스터디 ID 및 커리큘럼ID를 확인해주세요.");
if (i > 0 && curriculum.getWeek() < orderedCurriculumList.get(i - 1).getWeek()) {
throw new GeneralException(ErrorStatus.NOTICE_BAD_REQUEST, "주차 정보는 오름차순(같은 숫자 포함)이어야 합니다.");
}

curriculum.update(
curriculum.getStudy(),
curriculum.getTitle(),
curriculum.getWeek(),
curriculum.getContent(),
orderNumber++
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import lombok.RequiredArgsConstructor;
import org.example.domain.curriculum.controller.request.CreateCurriculumRequest;
import org.example.domain.curriculum.controller.request.ReorderCurriculumRequest;
import org.example.domain.curriculum.controller.request.UpdateCurriculumRequest;
import org.example.domain.curriculum.controller.response.DetailCurriculumResponse;
import org.example.domain.curriculum.controller.response.ListCurriculumResponse;
Expand Down Expand Up @@ -49,4 +50,11 @@ public void updateCurriculum(Long curriculumId, UpdateCurriculumRequest request)
public void deleteCurriculum(Long curriculumId) {
createCurriculumService.deleteCurriculum(curriculumId);
}

/**
* 커리큘럼 순서 변경
*/
public void reorderCurriculum(Long studyId, ReorderCurriculumRequest request) {
createCurriculumService.reorderCurriculum(studyId, request);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.example.api_response.ApiResponse;
import org.example.domain.attendance.controller.response.ListAttendanceResponse;
import org.example.domain.attendance.service.AttendanceService;
import org.example.domain.curriculum.controller.request.ReorderCurriculumRequest;
import org.example.domain.curriculum.controller.response.ListCurriculumResponse;
import org.example.domain.curriculum.service.CurriculumService;
import org.example.domain.member.controller.request.SearchMemberRequest;
Expand Down Expand Up @@ -98,6 +99,15 @@ public ApiResponse<ListCurriculumResponse> getCurriculumList(
return ApiResponse.onSuccess(curriculumService.getCurriculumList(studyId));
}

@PatchMapping("/{study-id}/curriculum/reorder")
@Operation(summary = "정규 스터디 커리큘럼 순서 변경")
public ApiResponse<Void> reorderCurriculum(
@PathVariable("study-id") Long studyId,
@RequestBody @Valid ReorderCurriculumRequest request) {
curriculumService.reorderCurriculum(studyId, request);
return ApiResponse.onSuccess();
}

@GetMapping("/{study-id}/attendance")
@Operation(summary = "정규 스터디 출석부 조회")
public ApiResponse<ListAttendanceResponse> getAttendanceList(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ public class Curriculum {
@Column(length = 1000000)
private String content;

@Comment("순서")
private Integer orderNumber;

@CreatedDate
@Column(updatable = false)
private LocalDateTime createdTime;
Expand All @@ -64,17 +67,23 @@ public class Curriculum {
private String updatedBy;

@Builder
public Curriculum(Study study, String title, Integer week, String content) {
public Curriculum(Study study, String title, Integer week, String content, Integer orderNumber) {
this.study = study;
this.title = title;
this.week = week;
this.content = content;
this.orderNumber = orderNumber;
}

public void update(Study study, String title, Integer week, String content) {
public void update(Study study, String title, Integer week, String content, Integer orderNumber) {
if (study != null) this.study = study;
if (StringUtils.hasText(title)) this.title = title;
if (week != null) this.week = week;
if (StringUtils.hasText(content)) this.content = content;
if (orderNumber != null) this.orderNumber = orderNumber;
}

public void increaseOrderNumber() {
this.orderNumber++;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,13 @@
import org.example.domain.curriculum.Curriculum;
import org.example.domain.study.Study;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

public interface CurriculumRepository extends JpaRepository<Curriculum, Long> {

List<Curriculum> findAllByStudy(Study study);

@Query("SELECT MAX(c.orderNumber) FROM Curriculum c WHERE c.study = :study")
Integer findMaxOrderNumberByStudy(@Param("study") Study study);
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
.requestMatchers(new AntPathRequestMatcher("/email/**")).permitAll()
.requestMatchers(new AntPathRequestMatcher("/sms/**")).permitAll()
.requestMatchers(new AntPathRequestMatcher("/health/**")).permitAll()
.requestMatchers(HttpMethod.GET, "/board").permitAll()
// 랜딩 페이지
.requestMatchers(new AntPathRequestMatcher("/study/count")).permitAll()
.requestMatchers(new AntPathRequestMatcher("/generation/max")).permitAll()
Expand Down
6 changes: 6 additions & 0 deletions module-core/src/main/java/org/example/util/SecurityUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

public class SecurityUtils {

private static final String ANONYMOUS_USER = "anonymousUser";

private static Authentication getAuthentication() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || authentication.getName() == null) {
Expand All @@ -19,4 +21,8 @@ public static String getCurrentMemberEmail() {
Authentication authentication = getAuthentication();
return authentication.getName();
}

public static boolean isLoggedIn() {
return !getCurrentMemberEmail().equals(ANONYMOUS_USER);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,11 @@ public ListBoardResponse getBoardList(SearchBoardRequest request) {
for (ListBoardDto board : boardList) {
board.updateCategory(board.getCategory());

// 정규 스터디 참여 이력 없으면 작성자 이름 미노출
if (!detailStudyMemberRepository.isRegularStudyMember()
&& coreMemberService.findByEmail(SecurityUtils.getCurrentMemberEmail()).getRole().equals(Role.ROLE_USER)) {
// 비로그인 or 정규 스터디 참여 이력 없으면 작성자 이름 미노출
String currentMemberEmail = SecurityUtils.getCurrentMemberEmail();
if (!SecurityUtils.isLoggedIn() ||
(!detailStudyMemberRepository.isRegularStudyMember()
&& coreMemberService.findByEmail(currentMemberEmail).getRole().equals(Role.ROLE_USER))) {
board.blindCreatedName();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public List<ListCurriculumDto> getCurriculumList(Long studyId) {
.where(curriculum.study.id.eq(studyId))
.orderBy(
curriculum.week.asc(),
curriculum.id.asc()
curriculum.orderNumber.asc()
)
.fetch();
}
Expand Down
Loading