Skip to content

Commit

Permalink
Merge pull request #566 from TaskFlow-CLAP/CLAP-432
Browse files Browse the repository at this point in the history
CLAP-432 회원 수정 및 삭제 시에 검증 로직 추가
  • Loading branch information
joowojr authored Feb 14, 2025
2 parents 1fda805 + 89118c8 commit 4f14e17
Show file tree
Hide file tree
Showing 11 changed files with 67 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ public record MemberDetailsResponse(
@Schema(description = "부서")
String departmentName,
@Schema(description = "직무")
String departmentRole
String departmentRole,
@Schema(description = "잔여 작업, 등록이 되지 않은 회원은 Null로 출력됩니다.")
Integer remainingTasks
) {}

Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ public record MemberDetailInfoResponse(
@Schema(description = "직책")
String departmentRole,
@Schema(description = "알림 수신 여부")
NotificationSettingInfoResponse notificationSettingInfo
NotificationSettingInfoResponse notificationSettingInfo,
@Schema(description = "진행/검토 작업 수, 담당자가 아닐 경우에는 null입니다.")
MemberRemainingTaskCountsResponse remainingTaskCounts
) {
public static record NotificationSettingInfoResponse(
@Schema(description = "이메일 알림 수신 여부")
Expand All @@ -29,6 +31,14 @@ public static record NotificationSettingInfoResponse(
boolean kakaoWork
) {
}

public static record MemberRemainingTaskCountsResponse(
@Schema(description = "진행중 작업 수")
int totalInProgressTaskCount,
@Schema(description = "검토중 작업 수")
int totalInReviewingTaskCount
) {
}
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import clap.server.adapter.inbound.web.dto.admin.response.MemberDetailsResponse;
import clap.server.adapter.inbound.web.dto.member.response.MemberDetailInfoResponse;
import clap.server.adapter.inbound.web.dto.member.response.MemberProfileResponse;
import clap.server.adapter.outbound.persistense.entity.member.constant.MemberRole;
import clap.server.domain.model.member.Member;
import clap.server.domain.model.member.MemberInfo;

Expand Down Expand Up @@ -32,7 +33,15 @@ public static MemberDetailInfoResponse toMemberDetailInfoResponse(Member member)
member.getMemberInfo().getRole(),
member.getMemberInfo().getDepartment().getName(),
member.getMemberInfo().getDepartmentRole(),
toNotificationSettingInfoResponse(member)
toNotificationSettingInfoResponse(member),
member.getMemberInfo().getRole()!= MemberRole.ROLE_MANAGER ? null : toMemberRemainingTaskCountsResponse(member)
);
}

public static MemberDetailInfoResponse.MemberRemainingTaskCountsResponse toMemberRemainingTaskCountsResponse(Member member){
return new MemberDetailInfoResponse.MemberRemainingTaskCountsResponse(
member.getInProgressTaskCount(),
member.getInReviewingTaskCount()
);
}

Expand All @@ -54,7 +63,8 @@ public static MemberDetailsResponse toMemberDetailsResponse(Member member) {
member.getMemberInfo().getRole(),
member.getMemberInfo().getDepartment().getDepartmentId(),
member.getMemberInfo().getDepartment().getName(),
member.getMemberInfo().getDepartmentRole()
member.getMemberInfo().getDepartmentRole(),
member.getInProgressTaskCount() + member.getInReviewingTaskCount()
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import clap.server.domain.model.member.Department;
import clap.server.domain.model.member.Member;
import clap.server.domain.model.member.MemberInfo;
import clap.server.domain.policy.member.ManagerDepartmentPolicy;
import clap.server.domain.policy.member.ManagerInfoUpdatePolicy;
import clap.server.exception.ApplicationException;
import clap.server.exception.code.DepartmentErrorCode;
import clap.server.exception.code.MemberErrorCode;
Expand All @@ -30,7 +30,7 @@
public class CsvParseService {

private final LoadDepartmentPort loadDepartmentPort;
private final ManagerDepartmentPolicy managerDepartmentPolicy;
private final ManagerInfoUpdatePolicy managerInfoUpdatePolicy;

public List<Member> parseDataAndMapToMember(MultipartFile file) {
List<Member> members = new ArrayList<>();
Expand Down Expand Up @@ -67,7 +67,7 @@ private Member mapToMember(String[] fields, List<Department> departments) {
.findFirst()
.orElseThrow(() -> new ApplicationException(DepartmentErrorCode.DEPARTMENT_NOT_FOUND));

managerDepartmentPolicy.validateDepartment(department, MemberRole.valueOf(fields[5].trim()));
managerInfoUpdatePolicy.validateDepartment(department, MemberRole.valueOf(fields[5].trim()));
MemberInfo memberInfo = toMemberInfo(
fields[0].trim(), // name
fields[4].trim(), // email
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package clap.server.application.service.admin;

import clap.server.adapter.outbound.persistense.entity.member.constant.MemberRole;
import clap.server.application.port.inbound.admin.DeleteMemberUsecase;
import clap.server.application.port.outbound.member.CommandMemberPort;
import clap.server.application.port.outbound.member.LoadMemberPort;
import clap.server.common.annotation.architecture.ApplicationService;
import clap.server.domain.model.member.Member;
import clap.server.domain.policy.member.ManagerInfoUpdatePolicy;
import clap.server.exception.ApplicationException;
import clap.server.exception.code.MemberErrorCode;
import lombok.RequiredArgsConstructor;
Expand All @@ -16,17 +18,19 @@
public class DeleteMemberService implements DeleteMemberUsecase {
private final LoadMemberPort loadMemberPort;
private final CommandMemberPort commandMemberPort;
private final ManagerInfoUpdatePolicy managerInfoUpdatePolicy;

@Transactional
@Override
public void deleteMember(Long memberId) {
Member member = loadMemberPort.findById(memberId)
.orElseThrow(() -> new ApplicationException(MemberErrorCode.MEMBER_NOT_FOUND));

if(member.getMemberInfo().getRole().equals(MemberRole.ROLE_MANAGER)){
managerInfoUpdatePolicy.validateNoRemainingTasks(member);
}
Hibernate.initialize(member.getDepartment());

member.setStatusDeleted();

member.softDelete();
commandMemberPort.save(member);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import clap.server.adapter.inbound.web.dto.admin.request.UpdateMemberRequest;
import clap.server.adapter.inbound.web.dto.admin.response.MemberDetailsResponse;
import clap.server.adapter.outbound.persistense.entity.member.constant.MemberRole;
import clap.server.application.mapper.response.MemberResponseMapper;
import clap.server.application.port.inbound.admin.MemberDetailUsecase;
import clap.server.application.port.inbound.admin.UpdateMemberUsecase;
Expand All @@ -11,6 +12,7 @@
import clap.server.common.annotation.architecture.ApplicationService;
import clap.server.domain.model.member.Department;
import clap.server.domain.model.member.Member;
import clap.server.domain.policy.member.ManagerInfoUpdatePolicy;
import clap.server.exception.ApplicationException;
import clap.server.exception.code.DepartmentErrorCode;
import lombok.RequiredArgsConstructor;
Expand All @@ -22,14 +24,21 @@ class ManageMemberService implements UpdateMemberUsecase, MemberDetailUsecase {
private final MemberService memberService;
private final CommandMemberPort commandMemberPort;
private final LoadDepartmentPort loadDepartmentPort;
private final ManagerInfoUpdatePolicy managerInfoUpdatePolicy;

@Override
@Transactional
public void updateMemberInfo(Long adminId, Long memberId, UpdateMemberRequest request) {
Member member = memberService.findById(memberId);
Department department = loadDepartmentPort.findById(request.departmentId()).orElseThrow(() ->
new ApplicationException(DepartmentErrorCode.DEPARTMENT_NOT_FOUND));


managerInfoUpdatePolicy.validateDepartment(department, request.role());
if(member.getMemberInfo().getRole().equals(MemberRole.ROLE_MANAGER) &&
!request.role().equals(MemberRole.ROLE_MANAGER)){
managerInfoUpdatePolicy.validateNoRemainingTasks(member);
}

member.getMemberInfo().updateMemberInfoByAdmin(
request.name(), request.isReviewer(),
department, request.role(), request.departmentRole());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import clap.server.domain.model.member.Department;
import clap.server.domain.model.member.Member;
import clap.server.domain.model.member.MemberInfo;
import clap.server.domain.policy.member.ManagerDepartmentPolicy;
import clap.server.domain.policy.member.ManagerInfoUpdatePolicy;
import clap.server.exception.ApplicationException;
import clap.server.exception.code.DepartmentErrorCode;
import clap.server.exception.code.MemberErrorCode;
Expand All @@ -26,7 +26,7 @@ class RegisterMemberService implements RegisterMemberUsecase {
private final CommandMemberPort commandMemberPort;
private final LoadDepartmentPort loadDepartmentPort;
private final LoadMemberPort loadMemberPort;
private final ManagerDepartmentPolicy managerDepartmentPolicy;
private final ManagerInfoUpdatePolicy managerInfoUpdatePolicy;

@Override
@Transactional
Expand All @@ -39,7 +39,7 @@ public void registerMember(Long adminId, RegisterMemberRequest request) {
throw new ApplicationException(MemberErrorCode.DUPLICATE_NICKNAME_OR_EMAIL);
}

managerDepartmentPolicy.validateDepartment(department, request.role());
managerInfoUpdatePolicy.validateDepartment(department, request.role());
MemberInfo memberInfo = MemberInfo.toMemberInfo(request.name(), request.email(), request.nickname(), request.isReviewer(),
department, request.role(), request.departmentRole());
Member member = Member.createMember(admin, memberInfo);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ public class TerminateTaskService implements TerminateTaskUsecase {
public void terminateTask(Long memberId, Long taskId, String reason) {
Task task = taskService.findById(taskId);

updateProcessorTaskCountService.handleTaskStatusChange(task.getProcessor(), task.getTaskStatus(), TaskStatus.TERMINATED);
// 작업 종료의 경우. 작업 반려는 count를 업데이트를 하지 않음
if(task.getProcessor()!=null) {
updateProcessorTaskCountService.handleTaskStatusChange(task.getProcessor(), task.getTaskStatus(), TaskStatus.TERMINATED);
}
task.terminateTask();
taskService.upsert(task);

Expand Down
3 changes: 1 addition & 2 deletions src/main/java/clap/server/domain/model/member/Member.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import clap.server.adapter.outbound.persistense.entity.member.constant.MemberStatus;
import clap.server.domain.model.common.BaseTime;
import jakarta.persistence.Column;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
Expand Down Expand Up @@ -87,7 +86,7 @@ public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}

public void setStatusDeleted() {
public void softDelete() {
this.status = MemberStatus.DELETED;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,26 @@
import clap.server.adapter.outbound.persistense.entity.member.constant.MemberRole;
import clap.server.common.annotation.architecture.Policy;
import clap.server.domain.model.member.Department;
import clap.server.domain.model.member.Member;
import clap.server.exception.DomainException;
import clap.server.exception.code.MemberErrorCode;

@Policy
public class ManagerDepartmentPolicy {
public class ManagerInfoUpdatePolicy {

// 담당자 권한이 있는 부서의 인원만 담당자의 역할이 허용됨
public void validateDepartment(final Department department, final MemberRole memberRole) {
if (!department.isManager() ){
if(memberRole == MemberRole.ROLE_MANAGER){
throw new DomainException(MemberErrorCode.MANAGER_PERMISSION_DENIED);
}
}
}

// 담당자의 잔여 작업이 남아있는 경우 해당 회원의 데이터 수정이 허용되지 않음
public void validateNoRemainingTasks(final Member member){
if(member.getInReviewingTaskCount()>0 || member.getInProgressTaskCount()> 0){
throw new DomainException(MemberErrorCode.MANAGER_MEMBER_UPDATE_NOT_ALLOWED_WITH_TASKS);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ public enum MemberErrorCode implements BaseErrorCode {
COMMENT_PERMISSION_DENIED(HttpStatus.FORBIDDEN, "MEMBER_005", "댓글 작성 권한이 없습니다."),
PASSWORD_VERIFY_FAILED(HttpStatus.BAD_REQUEST, "MEMBER_006", "비밀번호 검증에 실패하였습니다"),
INVALID_CSV_FORMAT(HttpStatus.BAD_REQUEST, "MEMBER_007", "CSV 파일 형식이 잘못되었습니다."),
CSV_PARSING_ERROR(HttpStatus.BAD_REQUEST, "MEMBER_008", "CSV 데이터 파싱 중 오류가 발생했습니다."),
CSV_PARSING_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "MEMBER_008", "CSV 데이터 파싱 중 오류가 발생했습니다."),
REVIEW_PERMISSION_DENIED(HttpStatus.BAD_REQUEST, "MEMBER_009", "담당자만 리뷰 권한이 있습니다."),
NAME_CANNOT_BE_EMPTY(HttpStatus.BAD_REQUEST, "MEMBER_010", "이름은 공백일 수 없습니다."),
DUPLICATE_NICKNAME(HttpStatus.BAD_REQUEST,"MEMBER_011", "중복된 닉네임입니다"),
DUPLICATE_NICKNAME_OR_EMAIL(HttpStatus.BAD_REQUEST, "MEMBER_012", "중복된 닉네임이나 email이 존재합니다"),
MANAGER_PERMISSION_DENIED(HttpStatus.BAD_REQUEST, "MEMBER_013", "담당자 권한이 없는 부서입니다."),
INVALID_EMAIL_NICKNAME_MATCH(HttpStatus.BAD_REQUEST, "MEMBER_014", "닉네임과 이메일이 일치하지 않습니다"),
MANAGER_MEMBER_UPDATE_NOT_ALLOWED_WITH_TASKS(HttpStatus.BAD_REQUEST, "MEMBER_015", "잔여 작업이 남아있어 수정이 불가합니다."),
;

private final HttpStatus httpStatus;
Expand Down

0 comments on commit 4f14e17

Please sign in to comment.