Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

release : 1.2.0 배포 #204

Merged
merged 22 commits into from
Jan 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
b009a9f
PET-286 feat : 과반수 이상이 투두 완료시 알림 보내는 클래스 추가
tlarbals824 Jan 15, 2024
f4988dc
PET-286 feat : SetOperator에 당일 이후에는 만료되도록 데이터를 저장하는 메소드 추가 및 구현
tlarbals824 Jan 15, 2024
cb0b234
PET-286 fix : 토큰 재발급시 토큰 검증 메소드 추가
tlarbals824 Jan 15, 2024
42af082
Merge pull request #201 from TEAM-SAMSION/PET-286
tlarbals824 Jan 15, 2024
33444d9
PET-286 refactor : 과반수 이상 투두 완료시 알림 생성 로직 리팩터링
tlarbals824 Jan 16, 2024
eb956ae
PET-286 refactor : 불필요 의존성 제거
tlarbals824 Jan 16, 2024
6bcf59d
PET-286 feat : 투두 할당 정보 중 미완료 상태 할당 데이터 조회 메소드 추가 및 구현
tlarbals824 Jan 16, 2024
1816126
PET-286 refactor : 파라미터, 변수 불변성 보장 추가
tlarbals824 Jan 16, 2024
1fd94ae
PET-286 refactor : todoId, 완료 상태 파라미터로 받아 할당 카운트 조회 메소드 이름 변경
tlarbals824 Jan 16, 2024
96ad5f6
PET-286 refactor : todoId, 완료 상태 파라미터로 받아 할당 카운트 조회 메소드 이름 변경 반영
tlarbals824 Jan 16, 2024
2112d4c
Merge pull request #202 from TEAM-SAMSION/PET-286
tlarbals824 Jan 16, 2024
7b71efb
PET-287 refactor : 사용자 일치 여부 메소드 추가
tlarbals824 Jan 20, 2024
822ba5e
PET-287 refactor : 파라미터 타임 List -> Collection으로 변경
tlarbals824 Jan 20, 2024
dbd5f88
PET-287 refactor : 투두 할당 상태 변경 이벤트 클래스 이름 변경
tlarbals824 Jan 20, 2024
0061760
PET-287 refactor : 미완료 투두가 0개일떄는 발송 안되도록 필터링 추가
tlarbals824 Jan 20, 2024
70d5dc2
PET-287 feat : 에러 정보에 http 상태 코드도 함께 포함하도록 추가
tlarbals824 Jan 20, 2024
0f3efce
PET-287 refactor : 투두 할당 정보 변경 이벤트 클래스 이름 변경
tlarbals824 Jan 20, 2024
04242d8
PET-287 feat : 미완료 투두 갯수 알림 활성화
tlarbals824 Jan 20, 2024
e441a98
PET-287 refactor : 에러 인터페이스에 http 상태 코드 추가에 따른 GlobalExceptionHandler…
tlarbals824 Jan 20, 2024
9ab3ca4
PET-287 refactor : 에러 인터페이스에 http 상태 코드 추가에 따른 GlobalExceptionHandler…
tlarbals824 Jan 20, 2024
cb90a41
PET-287 refactor : 에러코드 타입 Integer -> int 로 변경
tlarbals824 Jan 20, 2024
78ec693
Merge pull request #203 from TEAM-SAMSION/PET-287
tlarbals824 Jan 20, 2024
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
@@ -1,23 +1,19 @@
package com.pawith.alarmmodule.exception;

import com.pawith.commonmodule.exception.Error;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;

@AllArgsConstructor
@Getter
@RequiredArgsConstructor
public enum AlarmError implements Error {
DEVICE_TOKEN_NOT_FOUND("FCM 디바이스 토큰이 없습니다.", 5000),
FCM_SEND_ERROR("FCM 전송에 실패하였습니다.", 5001),;
DEVICE_TOKEN_NOT_FOUND("FCM 디바이스 토큰이 없습니다.", 5000, HttpStatus.NOT_FOUND),
FCM_SEND_ERROR("FCM 전송에 실패하였습니다.", 5001, HttpStatus.INTERNAL_SERVER_ERROR),
;

private String message;
private Integer errorCode;

@Override
public String getMessage() {
return message;
}

@Override
public int getErrorCode() {
return errorCode;
}
private final String message;
private final int errorCode;
private final HttpStatusCode httpStatusCode;
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ public interface SetOperator<K> {

void addWithExpire(K k, long expire, TimeUnit timeUnit);

void addWithExpireAfterToday(K k);

void remove(K k);

boolean contains(K k);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,25 @@
import com.pawith.commonmodule.cache.operators.SetOperator;
import net.jodah.expiringmap.ExpirationPolicy;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;

public class DefaultSetOperator<K> extends ExpiredStorage<K,K> implements SetOperator<K> {
public class DefaultSetOperator<K> extends ExpiredStorage<K, K> implements SetOperator<K> {
@Override
public void add(K k) {
storage.put(k,k);
storage.put(k, k);
}

@Override
public void addWithExpire(K k, long expire, TimeUnit timeUnit) {
storage.put(k,k,ExpirationPolicy.CREATED,expire, TimeUnit.MINUTES);
storage.put(k, k, ExpirationPolicy.CREATED, expire, TimeUnit.MINUTES);
}

@Override
public void addWithExpireAfterToday(K k) {
final long expiredDuration = Duration.between(LocalDateTime.now(), LocalDateTime.now().plusDays(1)).toMinutes();
storage.put(k, k, ExpirationPolicy.CREATED, expiredDuration, TimeUnit.MINUTES);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.pawith.commonmodule.exception;

import lombok.Getter;
import org.springframework.http.HttpStatusCode;

@Getter
public class BusinessException extends RuntimeException{
Expand All @@ -17,4 +18,8 @@ public String getMessage(){
public int getErrorCode(){
return error.getErrorCode();
}

public HttpStatusCode getHttpStatusCode(){
return error.getHttpStatusCode();
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package com.pawith.commonmodule.exception;

import org.springframework.http.HttpStatusCode;


public interface Error {
String getMessage();
int getErrorCode();

HttpStatusCode getHttpStatusCode();
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.pawith.commonmodule.exception;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
Expand All @@ -11,6 +10,6 @@ public class GlobalExceptionHandler {
@ExceptionHandler(BusinessException.class)
public ResponseEntity<ErrorResponse> handleJwtException(BusinessException e) {
final ErrorResponse errorResponse = ErrorResponse.from(e);
return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST);
return new ResponseEntity<>(errorResponse, e.getHttpStatusCode());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public class ReissueUseCaseImpl implements ReissueUseCase {
@Override
public TokenReissueResponse reissue(String refreshTokenHeader) {
final String refreshToken = TokenExtractUtils.extractToken(refreshTokenHeader);
jwtProvider.validateToken(refreshToken, TokenType.REFRESH_TOKEN);
final String userEmail = jwtProvider.extractEmailFromToken(refreshToken, TokenType.REFRESH_TOKEN);
return reissueToken(refreshToken, userEmail);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,22 @@

import com.pawith.commonmodule.exception.Error;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;

@Getter
@RequiredArgsConstructor
public enum AuthError implements Error {

INVALID_TOKEN("유효하지 않은 토큰입니다.", 1000),
EXPIRED_TOKEN("만료된 토큰입니다.", 1001),
NOT_EXIST_TOKEN("토큰이 존재하지 않습니다.", 1002),
INVALID_AUTHORIZATION_TYPE("유효하지 않은 Authorization Type 입니다.", 1003),
EMPTY_AUTHORIZATION_HEADER("Authorization Header가 비어있습니다.", 1004),
OAUTH_FAIL("OAuth 인증에 실패하였습니다.", 1005);
INVALID_TOKEN("유효하지 않은 토큰입니다.", 1000, HttpStatus.BAD_REQUEST),
EXPIRED_TOKEN("만료된 토큰입니다.", 1001, HttpStatus.BAD_REQUEST),
NOT_EXIST_TOKEN("토큰이 존재하지 않습니다.", 1002, HttpStatus.BAD_REQUEST),
INVALID_AUTHORIZATION_TYPE("유효하지 않은 Authorization Type 입니다.", 1003, HttpStatus.BAD_REQUEST),
EMPTY_AUTHORIZATION_HEADER("Authorization Header가 비어있습니다.", 1004, HttpStatus.BAD_REQUEST),
OAUTH_FAIL("OAuth 인증에 실패하였습니다.", 1005, HttpStatus.BAD_REQUEST);

private final String message;
private final int errorCode;

AuthError(String message, int errorCode) {
this.message = message;
this.errorCode = errorCode;
}
private final HttpStatusCode httpStatusCode;
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,16 @@
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.concurrent.TimeUnit;

@Slf4j
//@Component
@Component
public class IncompleteTodoCountNotificationHandler extends AbstractBatchSchedulingHandler<IncompleteTodoCountInfoDao> {
private static final Integer BATCH_SIZE = 100;
private static final String CRON_EXPRESSION = "0 0 0 0 0 0";
private static final String CRON_EXPRESSION = "0 0 20 * * *"; // 매일 20시에 실행
private static final String NOTIFICATION_MESSAGE = "[%s] 오늘이 지나기 전, %s님에게 남은 %d개의 todo를 완료해주세요!";

private final RegisterRepository registerRepository;
Expand All @@ -43,6 +44,7 @@ protected List<IncompleteTodoCountInfoDao> extractBatchData(Pageable pageable) {
protected void processBatch(List<IncompleteTodoCountInfoDao> executionResult) {
cachingUserInfo(executionResult);
final List<NotificationEvent> notificationEventList = executionResult.stream()
.filter(incompleteTodoCountInfoDao -> incompleteTodoCountInfoDao.getIncompleteTodoCount() > 0)
.map(incompleteTodoCountInfoDao -> {
final String userNickname = valueOperator.get(incompleteTodoCountInfoDao.getUserId());
final String message = String.format(NOTIFICATION_MESSAGE, incompleteTodoCountInfoDao.getTodoTeamName(), userNickname, incompleteTodoCountInfoDao.getIncompleteTodoCount());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.pawith.todoapplication.handler;

import com.pawith.todoapplication.handler.event.TodoCompletionCheckEvent;
import com.pawith.todoapplication.handler.event.TodoAssignStatusChangeEvent;
import com.pawith.tododomain.entity.Assign;
import com.pawith.tododomain.entity.Todo;
import com.pawith.tododomain.service.AssignQueryService;
Expand All @@ -23,11 +23,11 @@ public class TodoCompletionCheckOnTodoHandler {
private final TodoQueryService todoQueryService;

@EventListener
public void changeTodoStatus(TodoCompletionCheckEvent todoCompletionCheckEvent) throws InterruptedException {
public void changeTodoStatus(TodoAssignStatusChangeEvent todoAssignStatusChangeEvent) throws InterruptedException {
while(true) {
try {
final List<Assign> assigns = assignQueryService.findAllAssignByTodoId(todoCompletionCheckEvent.todoId());
final Todo todo = todoQueryService.findTodoByTodoId(todoCompletionCheckEvent.todoId());
final List<Assign> assigns = assignQueryService.findAllAssignByTodoId(todoAssignStatusChangeEvent.todoId());
final Todo todo = todoQueryService.findTodoByTodoId(todoAssignStatusChangeEvent.todoId());
final boolean isAllCompleteTodo = assigns.stream().allMatch(Assign::isCompleted);
todo.updateCompletionStatus(isAllCompleteTodo);
break;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package com.pawith.todoapplication.handler;

import com.pawith.commonmodule.cache.CacheTemplate;
import com.pawith.commonmodule.event.MultiNotificationEvent;
import com.pawith.commonmodule.event.NotificationEvent;
import com.pawith.todoapplication.handler.event.TodoAssignStatusChangeEvent;
import com.pawith.tododomain.entity.CompletionStatus;
import com.pawith.tododomain.repository.dao.IncompleteAssignInfoDao;
import com.pawith.tododomain.service.AssignQueryService;
import com.pawith.userdomain.entity.User;
import com.pawith.userdomain.service.UserQueryService;
import lombok.RequiredArgsConstructor;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;

@Component
@RequiredArgsConstructor
@Transactional
public class TodoRemindHandler {
private static final String NOTIFICATION_MESSAGE = "'%s'을 %d명이 완료했어요! %s님도 얼른 완료해볼까요?";
private static final String REMIND_CACHE_KEY = "Remind:%s";

private final AssignQueryService assignQueryService;
private final UserQueryService userQueryService;
private final CacheTemplate<String, String> cacheTemplate;
private final ApplicationEventPublisher applicationEventPublisher;

@EventListener
public void remindTodo(final TodoAssignStatusChangeEvent todoAssignStatusChangeEvent){
final Long todoId = todoAssignStatusChangeEvent.todoId();
final String cacheKey = String.format(REMIND_CACHE_KEY, todoId);
final long completeAssignNumber = assignQueryService.countAssignByTodoIdAndCompleteStatus(todoId, CompletionStatus.COMPLETE);
if(isRemindable(todoId, completeAssignNumber)&& !cacheTemplate.opsForSet().contains(cacheKey)){
cacheTemplate.opsForSet().addWithExpireAfterToday(cacheKey);
final List<NotificationEvent> todoNotificationList = buildNotificationEvent(todoId, completeAssignNumber);
applicationEventPublisher.publishEvent(new MultiNotificationEvent(todoNotificationList));
}
}

private List<NotificationEvent> buildNotificationEvent(final Long todoId, final long completeAssignNumber) {
final List<IncompleteAssignInfoDao> incompleteAssignInfoDaoList = assignQueryService.findAllIncompleteAssignInfoByTodoId(todoId);
final List<Long> incompleteTodoUserIds = incompleteAssignInfoDaoList.stream()
.map(IncompleteAssignInfoDao::getUserId)
.toList();
final Map<Long, User> incompleteTodoUserMap = userQueryService.findMapWithUserIdKeyByIds(incompleteTodoUserIds);
return incompleteAssignInfoDaoList.stream()
.map(incompleteAssignInfo -> {
final User incompleteTodoUser = incompleteTodoUserMap.get(incompleteAssignInfo.getUserId());
final String notificationMessage = String.format(NOTIFICATION_MESSAGE, incompleteAssignInfo.getTodoDescription(), completeAssignNumber, incompleteTodoUser.getNickname());
return new NotificationEvent(incompleteTodoUser.getId(),incompleteAssignInfo.getTodoTeamName(), notificationMessage, todoId);
})
.toList();
}

private boolean isRemindable(final Long todoId, final long completeAssignNumber){
final long totalAssignNumber = assignQueryService.countAssignByTodoId(todoId);
return (float) completeAssignNumber >= (float) totalAssignNumber * 0.5;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import com.pawith.tododomain.service.AssignDeleteService;
import com.pawith.tododomain.service.RegisterDeleteService;
import com.pawith.tododomain.service.RegisterQueryService;
import com.pawith.tododomain.service.RegisterValidateService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
Expand All @@ -22,7 +21,6 @@
public class UserAccountDeleteOnTodoHandler {
private final RegisterQueryService registerQueryService;
private final RegisterDeleteService registerDeleteService;
private final RegisterValidateService registerValidateService;
private final AssignDeleteService assignDeleteService;

@EventListener
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.pawith.todoapplication.handler.event;

public record TodoAssignStatusChangeEvent(Long todoId) {
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import com.pawith.commonmodule.annotation.ApplicationService;
import com.pawith.todoapplication.dto.request.AssignChangeRequest;
import com.pawith.todoapplication.handler.event.TodoCompletionCheckEvent;
import com.pawith.todoapplication.handler.event.TodoAssignStatusChangeEvent;
import com.pawith.tododomain.entity.Assign;
import com.pawith.tododomain.entity.Register;
import com.pawith.tododomain.entity.Todo;
Expand Down Expand Up @@ -38,7 +38,7 @@ public void changeAssignStatus(Long todoId){
final User user = userUtils.getAccessUser();
final Assign assign = assignQueryService.findAssignByTodoIdAndUserId(todo.getId(), user.getId());
assign.updateCompletionStatus();
applicationEventPublisher.publishEvent(new TodoCompletionCheckEvent(todo.getId()));
applicationEventPublisher.publishEvent(new TodoAssignStatusChangeEvent(todo.getId()));
}

public void changeAssign(Long todoId, AssignChangeRequest request) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,10 @@ public class TodoGetUseCase {
private final AssignQueryService assignQueryService;
private final TodoNotificationQueryService todoNotificationQueryService;


public ListResponse<TodoInfoResponse> getTodoListByTodoTeamId(final Long todoTeamId) {
final User user = userUtils.getAccessUser();
final List<Assign> allAssigns = assignQueryService.findAllByUserIdAndTodoTeamIdAndScheduledDate(user.getId(), todoTeamId);
List<TodoInfoResponse> todoInfoResponses = allAssigns.stream()
final List<TodoInfoResponse> todoInfoResponses = allAssigns.stream()
.map(assign -> {
final Todo todo = assign.getTodo();
final Category category = todo.getCategory();
Expand All @@ -49,13 +48,13 @@ public ListResponse<TodoInfoResponse> getTodoListByTodoTeamId(final Long todoTea
return ListResponse.from(todoInfoResponses);
}

public ListResponse<CategorySubTodoResponse> getTodoListByCategoryId(Long categoryId, LocalDate moveDate) {
public ListResponse<CategorySubTodoResponse> getTodoListByCategoryId(final Long categoryId,final LocalDate moveDate) {
final User accessUser = userUtils.getAccessUser();

final List<Assign> assignList = assignQueryService.findAllAssignByCategoryIdAndScheduledDate(categoryId, moveDate);

final Map<Todo, List<Assign>> todoAssignMap = AssignUtils.convertToTodoAssignMap(assignList);
final List<Todo> todoList = List.copyOf(todoAssignMap.keySet());
final Collection<Todo> todoList = todoAssignMap.keySet();

final Map<Long, TodoNotification> todoNotificationMap =
todoNotificationQueryService.findMapTodoIdKeyAndTodoNotificationValueByTodoIdsAndUserId(todoList, accessUser.getId());
Expand All @@ -74,12 +73,12 @@ public ListResponse<CategorySubTodoResponse> getTodoListByCategoryId(Long catego
return ListResponse.from(subTodoResponseList);
}

private List<AssignUserInfoResponse> getAssignUserInfoResponses(List<Assign> assigns, Map<Long, User> userMap, Long accessUserId, AtomicReference<Boolean> isAssigned) {
private List<AssignUserInfoResponse> getAssignUserInfoResponses(final List<Assign> assigns, final Map<Long, User> userMap, final Long accessUserId, final AtomicReference<Boolean> isAssigned) {
return assigns.stream()
.map(assign -> {
final Register register = assign.getRegister();
final User findUser = userMap.get(register.getUserId());
if (Objects.equals(findUser.getId(), accessUserId)) {
if (findUser.isMatchingUser(accessUserId)) {
isAssigned.set(true);
}
return new AssignUserInfoResponse(findUser.getId(), findUser.getNickname(), assign.getCompletionStatus());
Expand Down
Loading
Loading