Skip to content

Commit

Permalink
알림 읽기 기능 구현 (#775)
Browse files Browse the repository at this point in the history
* chore: (#766) 코드 컨벤션 수정

* feat: (#766) 알림 읽음 기능 구현

* refactor: (#766) 알림 리팩터링

* feat: (#766) 알림 대상 검증 기능 구현

* feat: (#766) 알림 읽는 기능 구현

* feat: (#766) 알림 읽기 API 구현

* fix: (#766) 테이블 추가

* fix: (#766) 비동기 테스트를 위한 sleep 추가

* feat: (#766) 알림 타입 추가

* test: (#766) 알림 타입이 없는 경우 테스트

* feat: (#766) 신고 알림 읽는 기능 구현

* feat: (#766) 알림 액션 타입 생성 기능 구현

* feat: (#766) 타입에 따른 알림 읽기 기능 구현

* docs: (#766) 예외 상황 문서화

* chore: (#766) 코드 컨벤션 수정

* docs: (#766) 예외 발생 문서화

* chore: (#766) 코드 컨벤션 수정

* chore: (#766) 개행 컨벤션 수정

* fix: (#766) DB 예약어 수정

* fix: (#766) 이벤트 테스트 임시 수정
  • Loading branch information
woo-chang authored Oct 18, 2023
1 parent c2b3f4c commit df585f2
Show file tree
Hide file tree
Showing 38 changed files with 737 additions and 111 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.votogether.domain.alarm.controller;

import com.votogether.domain.alarm.service.AlarmCommandService;
import com.votogether.domain.member.entity.Member;
import com.votogether.global.jwt.Auth;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Positive;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@Validated
@RequiredArgsConstructor
@RequestMapping("/alarms")
@RestController
public class AlarmCommandController implements AlarmCommandControllerDocs {

private final AlarmCommandService alarmCommandService;

@PatchMapping("/{id}")
public ResponseEntity<Void> readAlarm(
@PathVariable("id") @Positive(message = "알림 ID는 양수만 가능합니다.") final Long alarmId,
@RequestParam("type") @NotBlank(message = "알림 타입이 공백이거나 존재하지 않습니다.") final String type,
@Auth final Member loginMember
) {
alarmCommandService.readAlarm(alarmId, type, loginMember);
return ResponseEntity.ok().build();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.votogether.domain.alarm.controller;

import com.votogether.domain.member.entity.Member;
import com.votogether.global.exception.ExceptionResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Positive;
import org.springframework.http.ResponseEntity;

@Tag(name = "알림 커맨드", description = "알림 커맨드 API")
public interface AlarmCommandControllerDocs {

@Operation(
summary = "알림 읽기",
description = "알림을 읽을 수 있는 대상이라면 알림을 읽습니다."
)
@ApiResponses({
@ApiResponse(
responseCode = "200",
description = "알림 읽기 성공"
),
@ApiResponse(
responseCode = "400",
description = """
1.알림 ID가 양수가 아닌 경우
2.알림을 읽을 수 있는 대상이 아닌 경우
""",
content = @Content(schema = @Schema(implementation = ExceptionResponse.class))
),
@ApiResponse(
responseCode = "404",
description = "알림이 존재하지 않은 경우",
content = @Content(schema = @Schema(implementation = ExceptionResponse.class))
)
})
ResponseEntity<Void> readAlarm(
@Parameter(description = "알림 ID", example = "1")
@Positive(message = "알림 ID는 양수만 가능합니다.") final Long alarmId,
@Parameter(description = "알림 타입", example = "CONTENT")
@NotBlank(message = "알림 타입이 공백이거나 존재하지 않습니다.") final String alarmType,
final Member loginMember
);

}
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,19 @@ public ResponseEntity<List<PostAlarmResponse>> getPostAlarm(
@GetMapping("/report")
public ResponseEntity<List<ReportActionAlarmResponse>> getReportActionAlarms(
@RequestParam @PositiveOrZero(message = "페이지는 0이상 정수만 가능합니다.") final int page,
@Auth final Member loginMember
@Auth final Member member
) {
final List<ReportActionAlarmResponse> response = alarmQueryService.getReportActionAlarms(loginMember, page);
final List<ReportActionAlarmResponse> response = alarmQueryService.getReportActionAlarms(member, page);
return ResponseEntity.ok(response);
}

@GetMapping("/report/{id}")
public ResponseEntity<ReportActionResponse> getReportActionAlarm(
@PathVariable("id") final Long reportActionAlarmId,
@Auth final Member loginMember
@Auth final Member member
) {
final ReportActionResponse response = alarmQueryService.getReportActionAlarm(reportActionAlarmId, loginMember);
final ReportActionResponse response =
alarmQueryService.getReportActionAlarm(reportActionAlarmId, member);
return ResponseEntity.ok(response);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@
import java.util.List;
import org.springframework.http.ResponseEntity;

@Tag(name = "알림", description = "알림 API")
@Tag(name = "알림 조회", description = "알림 조회 API")
public interface AlarmQueryControllerDocs {

@Operation(summary = "게시글 내역 알림 조회", description = "게시글 내역 알림을 조회한다.")
@Operation(
summary = "게시글 내역 알림 조회",
description = "게시글 내역 알림을 조회한다."
)
@ApiResponses({
@ApiResponse(
responseCode = "200",
Expand All @@ -37,18 +40,37 @@ ResponseEntity<List<PostAlarmResponse>> getPostAlarm(
@Auth final Member loginMember
);

@Operation(summary = "신고 조치 알림 조회", description = "신고 조치 알림 목록을 조회한다.")
@ApiResponse(responseCode = "200", description = "조회 성공")
@Operation(
summary = "신고조치알림 조회",
description = "신고조치알림목록을 조회한다."
)
@ApiResponses({
@ApiResponse(
responseCode = "201",
description = "신고조치알림 조회 성공"
),
@ApiResponse(
responseCode = "400",
description = "페이지가 0이상 정수가 아닌 경우",
content = @Content(schema = @Schema(implementation = ExceptionResponse.class))
)
})
ResponseEntity<List<ReportActionAlarmResponse>> getReportActionAlarms(
@Parameter(description = "현재 페이지 위치", example = "0")
@PositiveOrZero(message = "페이지는 0이상 정수만 가능합니다.") final int page,
final Member member
);

@Operation(summary = "신고 조치 알림 상세 조회", description = "신고 조치 알림를 상세 조회한다.")
@ApiResponse(responseCode = "200", description = "조회 성공")
@Operation(
summary = "신고조치알림 상세 조회",
description = "신고조치알림를 상세 조회한다."
)
@ApiResponse(
responseCode = "201",
description = "신고조치알림 상세 조회 성공"
)
ResponseEntity<ReportActionResponse> getReportActionAlarm(
@Parameter(description = "신고 조치 알림 ID", example = "1") final Long reportActionAlarmId,
@Parameter(description = "신고조치알림 ID", example = "1") final Long reportActionAlarmId,
final Member member
);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.votogether.domain.alarm.entity;

import com.votogether.domain.alarm.entity.vo.AlarmType;
import com.votogether.domain.alarm.exception.AlarmExceptionType;
import com.votogether.domain.common.BaseEntity;
import com.votogether.domain.member.entity.Member;
import com.votogether.global.exception.BadRequestException;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
Expand All @@ -13,6 +15,7 @@
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import java.util.Objects;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.EqualsAndHashCode;
Expand Down Expand Up @@ -61,4 +64,14 @@ private Alarm(
this.isChecked = isChecked;
}

public void read() {
this.isChecked = true;
}

public void checkOwner(final Member member) {
if (!Objects.equals(this.member.getId(), member.getId())) {
throw new BadRequestException(AlarmExceptionType.NOT_OWNER);
}
}

}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.votogether.domain.alarm.entity;

import com.votogether.domain.alarm.exception.AlarmExceptionType;
import com.votogether.domain.common.BaseEntity;
import com.votogether.domain.member.entity.Member;
import com.votogether.domain.report.entity.vo.ReportType;
import com.votogether.global.exception.BadRequestException;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
Expand All @@ -13,6 +15,7 @@
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import java.util.Objects;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.EqualsAndHashCode;
Expand Down Expand Up @@ -61,4 +64,14 @@ private ReportActionAlarm(
this.isChecked = isChecked;
}

public void read() {
this.isChecked = true;
}

public void checkOwner(final Member member) {
if (!Objects.equals(this.member.getId(), member.getId())) {
throw new BadRequestException(AlarmExceptionType.NOT_OWNER);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.votogether.domain.alarm.entity.vo;

import com.votogether.domain.alarm.exception.AlarmExceptionType;
import com.votogether.global.exception.BadRequestException;
import java.util.Arrays;

public enum AlarmActionType {

CONTENT,
REPORT,
;

public static AlarmActionType from(final String actionType) {
return Arrays.stream(AlarmActionType.values())
.filter(alarmActionType -> alarmActionType.name().equals(actionType))
.findFirst()
.orElseThrow(() -> new BadRequestException(AlarmExceptionType.NOT_FOUND_ACTION_TYPE));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.votogether.domain.alarm.exception;

import com.votogether.global.exception.ExceptionType;
import lombok.Getter;

@Getter
public enum AlarmExceptionType implements ExceptionType {

NOT_FOUND_ACTION(1300, "신고조치알림이 존재하지 않습니다."),
NOT_FOUND(1301, "알림이 존재하지 않습니다."),
NOT_OWNER(1302, "알림을 읽을 대상이 아닙니다."),
NOT_FOUND_ACTION_TYPE(1303, "등록되지 않은 알림 동작입니다."),
;

private final int code;
private final String message;

AlarmExceptionType(final int code, final String message) {
this.code = code;
this.message = message;
}

}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.votogether.domain.alarm.service;

import com.votogether.domain.alarm.entity.vo.AlarmActionType;
import com.votogether.domain.alarm.service.strategy.AlarmReadStrategy;
import com.votogether.domain.alarm.service.strategy.AlarmReadStrategyProvider;
import com.votogether.domain.member.entity.Member;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@RequiredArgsConstructor
@Transactional
@Service
public class AlarmCommandService {

private final AlarmReadStrategyProvider alarmReadStrategyProvider;

public void readAlarm(
final Long alarmId,
final String type,
final Member loginMember
) {
final AlarmActionType alarmActionType = AlarmActionType.from(type);
final AlarmReadStrategy alarmReadStrategy = alarmReadStrategyProvider.getStrategy(alarmActionType);
alarmReadStrategy.read(alarmId, loginMember);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import com.votogether.domain.alarm.entity.Alarm;
import com.votogether.domain.alarm.entity.ReportActionAlarm;
import com.votogether.domain.alarm.entity.vo.AlarmType;
import com.votogether.domain.alarm.exception.ReportActionAlarmExceptionType;
import com.votogether.domain.alarm.exception.AlarmExceptionType;
import com.votogether.domain.alarm.repository.AlarmRepository;
import com.votogether.domain.alarm.repository.ReportActionAlarmRepository;
import com.votogether.domain.member.entity.Member;
Expand Down Expand Up @@ -55,8 +55,11 @@ private String makeNicknameBy(final Alarm alarm) {
}

public List<ReportActionAlarmResponse> getReportActionAlarms(final Member member, final int page) {
final PageRequest pageRequest = PageRequest.of(page, BASIC_PAGE_SIZE,
Sort.by(Sort.Direction.DESC, "createdAt"));
final PageRequest pageRequest = PageRequest.of(
page,
BASIC_PAGE_SIZE,
Sort.by(Sort.Direction.DESC, "createdAt")
);
final List<ReportActionAlarm> reportActionAlarms = reportActionAlarmRepository
.findByMember(member, pageRequest);

Expand All @@ -68,7 +71,7 @@ public List<ReportActionAlarmResponse> getReportActionAlarms(final Member member
public ReportActionResponse getReportActionAlarm(final Long reportActionAlarmId, final Member member) {
final ReportActionAlarm reportActionAlarm = reportActionAlarmRepository
.findByIdAndMember(reportActionAlarmId, member)
.orElseThrow(() -> new NotFoundException(ReportActionAlarmExceptionType.NOT_FOUND));
.orElseThrow(() -> new NotFoundException(AlarmExceptionType.NOT_FOUND_ACTION));

return ReportActionResponse.from(reportActionAlarm);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.votogether.domain.alarm.service.strategy;

import com.votogether.domain.member.entity.Member;

public interface AlarmReadStrategy {

void read(final Long id, final Member member);

}
Loading

0 comments on commit df585f2

Please sign in to comment.