diff --git a/src/main/java/com/kamco/cd/kamcoback/members/MembersApiController.java b/src/main/java/com/kamco/cd/kamcoback/members/MembersApiController.java index 4d548fe4..c6bf97d4 100644 --- a/src/main/java/com/kamco/cd/kamcoback/members/MembersApiController.java +++ b/src/main/java/com/kamco/cd/kamcoback/members/MembersApiController.java @@ -5,6 +5,7 @@ import com.kamco.cd.kamcoback.members.dto.MembersDto; import com.kamco.cd.kamcoback.members.dto.MembersDto.Basic; import com.kamco.cd.kamcoback.members.service.AdminService; import com.kamco.cd.kamcoback.members.service.MembersService; +import com.kamco.cd.kamcoback.scheduler.service.MemberInactiveJobService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.Content; @@ -34,6 +35,7 @@ public class MembersApiController { private final MembersService membersService; private final AdminService adminService; + private final MemberInactiveJobService memberInactiveJobService; @Operation(summary = "회원정보 목록", description = "회원정보 조회") @ApiResponses( @@ -157,4 +159,13 @@ public class MembersApiController { String employeeNo) { return ApiResponseDto.ok(adminService.existsByEmployeeNo(employeeNo)); } + + @Operation( + summary = "라벨러/검수자 최종로그인 28일 경과 이후 사용중지(스케줄링 실행)", + description = "라벨러/검수자 최종로그인 28일 경과 이후 사용중지 처리") + @GetMapping("/member-inactive-job") + public ApiResponseDto memberInactiveJob() { + memberInactiveJobService.memberActive28daysToInactive(); + return ApiResponseDto.ok(null); + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/core/MemberInactiveJobCoreService.java b/src/main/java/com/kamco/cd/kamcoback/postgres/core/MemberInactiveJobCoreService.java new file mode 100644 index 00000000..58101bf6 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/core/MemberInactiveJobCoreService.java @@ -0,0 +1,22 @@ +package com.kamco.cd.kamcoback.postgres.core; + +import com.kamco.cd.kamcoback.postgres.repository.members.MemberInactiveJobRepository; +import com.kamco.cd.kamcoback.scheduler.dto.MemberInactiveJobDto.MemberInfo; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class MemberInactiveJobCoreService { + + private final MemberInactiveJobRepository memberInactiveJobRepository; + + public List findInactiveLabelerReviewer() { + return memberInactiveJobRepository.findInactiveLabelerReviewer(); + } + + public void updateMemberStatusInactive(MemberInfo memberInfo) { + memberInactiveJobRepository.updateMemberStatusInactive(memberInfo); + } +} diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/members/MemberInactiveJobRepository.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/members/MemberInactiveJobRepository.java new file mode 100644 index 00000000..e9ccd024 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/members/MemberInactiveJobRepository.java @@ -0,0 +1,7 @@ +package com.kamco.cd.kamcoback.postgres.repository.members; + +import com.kamco.cd.kamcoback.postgres.entity.MemberEntity; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface MemberInactiveJobRepository + extends JpaRepository, MemberInactiveJobRepositoryCustom {} diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/members/MemberInactiveJobRepositoryCustom.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/members/MemberInactiveJobRepositoryCustom.java new file mode 100644 index 00000000..b939eb47 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/members/MemberInactiveJobRepositoryCustom.java @@ -0,0 +1,11 @@ +package com.kamco.cd.kamcoback.postgres.repository.members; + +import com.kamco.cd.kamcoback.scheduler.dto.MemberInactiveJobDto.MemberInfo; +import java.util.List; + +public interface MemberInactiveJobRepositoryCustom { + + List findInactiveLabelerReviewer(); + + void updateMemberStatusInactive(MemberInfo memberInfo); +} diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/members/MemberInactiveJobRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/members/MemberInactiveJobRepositoryImpl.java new file mode 100644 index 00000000..2408ace0 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/members/MemberInactiveJobRepositoryImpl.java @@ -0,0 +1,44 @@ +package com.kamco.cd.kamcoback.postgres.repository.members; + +import com.kamco.cd.kamcoback.common.enums.RoleType; +import com.kamco.cd.kamcoback.common.enums.StatusType; +import com.kamco.cd.kamcoback.postgres.entity.QMemberEntity; +import com.kamco.cd.kamcoback.scheduler.dto.MemberInactiveJobDto.MemberInfo; +import com.querydsl.core.types.Projections; +import com.querydsl.jpa.impl.JPAQueryFactory; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class MemberInactiveJobRepositoryImpl implements MemberInactiveJobRepositoryCustom { + + private final JPAQueryFactory queryFactory; + private final QMemberEntity memberEntity = QMemberEntity.memberEntity; + + @Override + public List findInactiveLabelerReviewer() { + ZonedDateTime checkTime = ZonedDateTime.now(ZoneId.of("Asia/Seoul")).minusDays(14); + return queryFactory + .select(Projections.constructor(MemberInfo.class, memberEntity.id, memberEntity.employeeNo)) + .from(memberEntity) + .where( + memberEntity.userRole.in(RoleType.LABELER.getId(), RoleType.REVIEWER.getId()), + memberEntity.status.eq(StatusType.ACTIVE.getId()), + memberEntity.lastLoginDttm.lt(checkTime)) + .fetch(); + } + + @Override + public void updateMemberStatusInactive(MemberInfo memberInfo) { + queryFactory + .update(memberEntity) + .set(memberEntity.status, StatusType.INACTIVE.getId()) + .set(memberEntity.statusChgDttm, ZonedDateTime.now()) + .where(memberEntity.id.eq(memberInfo.getId())) + .execute(); + } +} diff --git a/src/main/java/com/kamco/cd/kamcoback/scheduler/dto/MemberInactiveJobDto.java b/src/main/java/com/kamco/cd/kamcoback/scheduler/dto/MemberInactiveJobDto.java new file mode 100644 index 00000000..d0e3dfe4 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/scheduler/dto/MemberInactiveJobDto.java @@ -0,0 +1,19 @@ +package com.kamco.cd.kamcoback.scheduler.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; + +public class MemberInactiveJobDto { + + @Getter + @Setter + @RequiredArgsConstructor + @AllArgsConstructor + public static class MemberInfo { + + private Long id; + private String employeeNo; + } +} diff --git a/src/main/java/com/kamco/cd/kamcoback/scheduler/service/MemberInactiveJobService.java b/src/main/java/com/kamco/cd/kamcoback/scheduler/service/MemberInactiveJobService.java new file mode 100644 index 00000000..836aab2f --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/scheduler/service/MemberInactiveJobService.java @@ -0,0 +1,49 @@ +package com.kamco.cd.kamcoback.scheduler.service; + +import com.kamco.cd.kamcoback.postgres.core.MemberInactiveJobCoreService; +import com.kamco.cd.kamcoback.scheduler.dto.MemberInactiveJobDto.MemberInfo; +import jakarta.transaction.Transactional; +import java.util.List; +import lombok.RequiredArgsConstructor; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; + +@Log4j2 +@Service +@RequiredArgsConstructor +public class MemberInactiveJobService { + + private final MemberInactiveJobCoreService memberInactiveJobCoreService; + + @Value("${spring.profiles.active}") + private String profile; + + private boolean isLocalProfile() { + return "local".equalsIgnoreCase(profile); + } + + @Transactional + @Scheduled(cron = "0 0 1 * * *") + public void memberActive28daysToInactive() { + + if (isLocalProfile()) { + return; + } + + try { + List list = memberInactiveJobCoreService.findInactiveLabelerReviewer(); + + if (list.isEmpty()) { + return; + } + + for (MemberInfo memberInfo : list) { + memberInactiveJobCoreService.updateMemberStatusInactive(memberInfo); + } + } catch (Exception e) { + log.error("배치 처리 중 예외", e); + } + } +}