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

신고조치알림 관련 기능 구현 #756

Merged
merged 22 commits into from
Oct 17, 2023
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
dcb37f6
feat: (#744) 테이블 엔티티 생성
aiaiaiai1 Oct 14, 2023
e16c998
feat: (#744) 신고조치알림목록 조회 api 구현
aiaiaiai1 Oct 14, 2023
4a17eea
test: (#744) 테스트코드 추가
aiaiaiai1 Oct 14, 2023
3e44754
refactor: (#744) 메서드명 수정
aiaiaiai1 Oct 14, 2023
873c036
refactor: (#744) 코드 리포맷팅
aiaiaiai1 Oct 14, 2023
510929c
refactor: (#744) api 명세 수정으로 인한 dto 수정
aiaiaiai1 Oct 15, 2023
5c29ee3
feat: (#744) 신고조치알림 상세조회 api 구현
aiaiaiai1 Oct 15, 2023
cbc6a77
test: (#744) 리파지터리 테스트 추가
aiaiaiai1 Oct 15, 2023
3bc198f
fix: (#744) list set으로 수정
aiaiaiai1 Oct 15, 2023
8aa93bb
refactor: (#744) dto 필드명 수정
aiaiaiai1 Oct 16, 2023
16a4b72
refactor: (#744) 테이블 삭제 및 컬럼추가로 인한 수정사항 변경
aiaiaiai1 Oct 16, 2023
684e4bb
test: (#744) 컨트롤러 테스트 추가
aiaiaiai1 Oct 16, 2023
4468b95
refactor: (#744) 예외 변환
aiaiaiai1 Oct 16, 2023
ae0a76a
feat: (#744) swagger 추가
aiaiaiai1 Oct 16, 2023
a479894
feat: (#744) 게시글 조회 추가된 요구사항 적용
aiaiaiai1 Oct 16, 2023
e3024ef
refactor: (#744) 개행 정리 및 컨벤션 적용
aiaiaiai1 Oct 17, 2023
be9dc76
refactor: (#744) 트랜잭션 어노테이션 및 fetch 타입 설정
aiaiaiai1 Oct 17, 2023
50a23c4
refactor: (#744) swagger 어노테이션 추가
aiaiaiai1 Oct 17, 2023
7a43d49
refactor: (#744) 테이블 삭제로 인한 엔티티 삭제
aiaiaiai1 Oct 17, 2023
b63e1df
refactor: (#744) 응답 방식 수정
aiaiaiai1 Oct 17, 2023
34c90f2
refactor: (#744) 클래스 이름 수정 및 상수화
aiaiaiai1 Oct 17, 2023
2f30127
refactor: (#744) 메서드 추출로 중복 제거
aiaiaiai1 Oct 17, 2023
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
@@ -0,0 +1,44 @@
package com.votogether.domain.alarm.controller;

import com.votogether.domain.alarm.dto.ReportActionAlarmResponse;
import com.votogether.domain.alarm.dto.ReportActionResponse;
import com.votogether.domain.alarm.service.AlarmService;
import com.votogether.domain.member.entity.Member;
import com.votogether.global.jwt.Auth;
import jakarta.validation.constraints.PositiveOrZero;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
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
@RestController
@RequiredArgsConstructor
@RequestMapping("/alarms")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Validated
@RequiredArgsConstructor
@RequestMapping("/alarms")
@RestController

다른 컨트롤러와 일관성있게 순서를 맞춰주면 감사합니다 :)

public class AlarmController implements AlarmControllerDocs {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

조회에 관한 API만 존재하니 AlarmController -> AlarmCommandController 로 바꿔야 할 것 같아요.


private final AlarmService alarmService;

@RequestMapping("/report")
public ResponseEntity<List<ReportActionAlarmResponse>> getReportActionAlarms(
@RequestParam @PositiveOrZero(message = "페이지는 0이상 정수만 가능합니다.") final int page,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RequestParam 는 생략해도 될 것 같아요 :)

Copy link
Collaborator Author

@aiaiaiai1 aiaiaiai1 Oct 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

다른 컨트롤러에서는 @RequestParam을 생략하지 않고 명시해두어서 여기서도 따로 생략하지는 않았습니다!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

생각해보니 다 붙이고 있었네요...ㅋㅋ

@Auth final Member member
) {
final List<ReportActionAlarmResponse> reportActionAlarms = alarmService.getReportActionAlarms(member, page);
return ResponseEntity.ok().body(reportActionAlarms);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return ResponseEntity.ok(reportActionAlarms);

요런 방법은 어떤가요?!

}

@RequestMapping("/report/{id}")
public ResponseEntity<ReportActionResponse> getReportActionAlarm(
@PathVariable("id") final Long reportActionAlarmId,
@Auth final Member member
) {
final ReportActionResponse response = alarmService.getReportActionAlarm(reportActionAlarmId, member);
return ResponseEntity.ok().body(response);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

}

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

import com.votogether.domain.alarm.dto.ReportActionAlarmResponse;
import com.votogether.domain.alarm.dto.ReportActionResponse;
import com.votogether.domain.member.entity.Member;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.constraints.PositiveOrZero;
import java.util.List;
import org.springframework.http.ResponseEntity;

@Tag(name = "알림", description = "알림 API")
public interface AlarmControllerDocs {

@Operation(summary = "신고조치알림 조회", description = "신고조치알림목록을 조회한다.")
@ApiResponse(responseCode = "201", description = "조회 성공")
ResponseEntity<List<ReportActionAlarmResponse>> getReportActionAlarms(
@Parameter(description = "현재 페이지 위치", example = "0")
@PositiveOrZero(message = "페이지는 0이상 정수만 가능합니다.") final int page,
final Member member
);

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

}


Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이상한 개행이 있어요 🥲

Copy link
Collaborator Author

@aiaiaiai1 aiaiaiai1 Oct 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

개행 빌런이였네요 ㅋㅋ

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

import com.votogether.domain.alarm.entity.ReportActionAlarm;
import io.swagger.v3.oas.annotations.media.Schema;

@Schema(description = "신고조치알림 응답")
public record ReportActionAlarmResponse(

@Schema(description = "알림 ID", example = "1")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

불필요한 공백 발견 👀

Long alarmId,

@Schema(description = "확인 여부", example = "false")
boolean isChecked,

@Schema(description = "신고조치 세부정보")
ReportActionResponse detail

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

위에 다즐도 적어주셨지만, record의 파라미터 적는 곳에선 앞 뒤 공백이 없어야 하는 것으로 알고 있습니다 :)

) {

public static ReportActionAlarmResponse from(
final ReportActionAlarm reportActionAlarm
) {
return new ReportActionAlarmResponse(
reportActionAlarm.getId(),
reportActionAlarm.isChecked(),
ReportActionResponse.from(reportActionAlarm)
);
}

}


Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기도 공백 발견 👀

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

import com.votogether.domain.alarm.entity.ReportActionAlarm;
import com.votogether.domain.report.entity.vo.ReportType;
import io.swagger.v3.oas.annotations.media.Schema;
import java.time.LocalDateTime;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public record ReportActionResponse(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

어떤 응답인지에 대한 설명도 추가해주면 좋을 것 같아요 :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

추가하였습니다~!

@Schema(description = "신고조치 ID", example = "1")
Long reportActionId,

@Schema(description = "신고조치타입", example = "POST")
ReportType type,

@Schema(description = "신고대상내용", example = "1")
String content,

@Schema(description = "신고사유")
Set<String> reasons,

@Schema(description = "신고조치시간", example = "2023-08-01 13:56")
LocalDateTime createdAt
) {

public static ReportActionResponse from(final ReportActionAlarm reportActionAlarm) {
final Set<String> reasons = Stream.of(reportActionAlarm.getReasons().split(","))
.map(String::strip)
.collect(Collectors.toSet());

return new ReportActionResponse(
reportActionAlarm.getId(),
reportActionAlarm.getReportType(),
reportActionAlarm.getTarget(),
reasons,
reportActionAlarm.getCreatedAt()
);
}
}


Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

개행 정리해주시면 감사합니다 😚

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

import com.votogether.domain.common.BaseEntity;
import com.votogether.domain.member.entity.Member;
import com.votogether.domain.report.entity.vo.ReportType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@EqualsAndHashCode(of = {"id"}, callSuper = false)
public class ReportActionAlarm extends BaseEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fetch 타입 설정이 필요해 보여요 !

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

빼먹었네요! 감사합니다~

@JoinColumn(name = "member_id", nullable = false)
private Member member;

@Enumerated(value = EnumType.STRING)
@Column(length = 20, nullable = false)
private ReportType reportType;

@Column(length = 500, nullable = false)
private String target;

@Column(length = 500, nullable = false)
private String reasons;

@Column(nullable = false)
private boolean isChecked;

@Builder
public ReportActionAlarm(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

빌더 생성자는 일관성 있게 private로 설정하는게 어떨까요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수정했습니다!

final Member member,
final ReportType reportType,
final String target,
final String reasons,
final boolean isChecked
) {
this.member = member;
this.reportType = reportType;
this.target = target;
this.reasons = reasons;
this.isChecked = isChecked;
}

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

import com.votogether.domain.common.BaseEntity;
import com.votogether.domain.report.entity.Report;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Getter
@EqualsAndHashCode(of = {"id"}, callSuper = false)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class ReportToAction extends BaseEntity {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ERD에서 해당 도메인이 삭제된 것으로 이해했는데 맞을까요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

네 맞아요 삭제해두었씁니다


@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "report_id", nullable = false)
private Report report;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "report_action_alarm_id", nullable = false)
private ReportActionAlarm reportActionAlarm;

@Builder
public ReportToAction(
final Report report,
final ReportActionAlarm reportActionAlarm
) {
this.report = report;
this.reportActionAlarm = reportActionAlarm;
}

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

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

@Getter
public enum ReportActionAlarmExceptionType implements ExceptionType {

NOT_FOUND(1300, "신고조치알림이 존재하지 않습니다."),
;

private final int code;
private final String message;

ReportActionAlarmExceptionType(final int code, final String message) {
this.code = code;
this.message = message;
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

개행 발견 👀

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

import com.votogether.domain.alarm.entity.ReportActionAlarm;
import com.votogether.domain.member.entity.Member;
import java.util.List;
import java.util.Optional;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;

public interface ReportActionAlarmRepository extends JpaRepository<ReportActionAlarm, Long> {

List<ReportActionAlarm> findByMember(final Member member, final Pageable pageable);

Optional<ReportActionAlarm> findByIdAndMember(final Long Id, final Member member);

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

import com.votogether.domain.alarm.dto.ReportActionAlarmResponse;
import com.votogether.domain.alarm.dto.ReportActionResponse;
import com.votogether.domain.alarm.entity.ReportActionAlarm;
import com.votogether.domain.alarm.exception.ReportActionAlarmExceptionType;
import com.votogether.domain.alarm.repository.ReportActionAlarmRepository;
import com.votogether.domain.member.entity.Member;
import com.votogether.global.exception.NotFoundException;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

@RequiredArgsConstructor
@Service
public class AlarmService {

private final ReportActionAlarmRepository reportActionAlarmRepository;

public List<ReportActionAlarmResponse> getReportActionAlarms(final Member member, final int page) {
final PageRequest pageRequest = PageRequest.of(page, 10, Sort.by(Sort.Direction.DESC, "createdAt"));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

일관성과 가독성을 위해서 10을

private static final int BASIC_PAGE_SIZE = 10;

이렇게 상수화 해주는 것은 어떨까요.

final List<ReportActionAlarm> reportActionAlarms = reportActionAlarmRepository
.findByMember(member, pageRequest);

return reportActionAlarms.stream()
.map(ReportActionAlarmResponse::from)
.toList();
}

public ReportActionResponse getReportActionAlarm(final Long reportActionAlarmId, final Member member) {
final ReportActionAlarm reportActionAlarm = reportActionAlarmRepository
.findByIdAndMember(reportActionAlarmId, member)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

id로 찾게되면 member없이도 항상 id를 통해서만 조회되지 않을까요?

member를 추가적으로 찾는 조건으로 넣은 이유가 궁금해요 🤓

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

api요청으로 사용자가 다른 사용자의 알림을 조회 하는 경우를 막기위해 member조건을 추가해주었습니다!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

와 전혀 생각지도 못한 부분인데 꼼꼼하게 구현해주셨네요 대박 배워갑니다 👍👍

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 코멘트를 보고 궁금한 점이 생겼는데 다른 사용자의 알림이 의도적으로 조회가 가능한가요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

백엔드서버로 직접 api를 알림id만 바꾸어 쏘면 조회가 가능할거같아요

.orElseThrow(() -> new NotFoundException(ReportActionAlarmExceptionType.NOT_FOUND));

return ReportActionResponse.from(reportActionAlarm);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Transactional 어노테이션이 빠져있어요 !


}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
@RequiredArgsConstructor
@RequestMapping("/posts")
@RestController
public class PostCommandController {
public class PostCommandController implements PostCommandControllerDocs {

private final PostCommandService postCommandService;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ private static long countVotesForUser(
final PostOption postOption,
final boolean isVoted
) {
if (post.isHidden() && post.isWriter(user)) {
return HIDDEN_COUNT;
}
if (post.isClosed() || post.isWriter(user) || isVoted) {
return postOption.getVoteCount();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ private static long countVotesForUser(
final boolean isVoted,
final long totalVoteCount
) {
if (post.isHidden() && post.isWriter(user)) {
return HIDDEN_COUNT;
}
if (post.isClosed() || post.isWriter(user) || isVoted) {
return totalVoteCount;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,19 @@ public List<PostResponse> getPosts(
public PostResponse getPost(final Long postId, final Member loginMember) {
final Post post = postRepository.findById(postId)
.orElseThrow(() -> new NotFoundException(PostExceptionType.NOT_FOUND));
validateHiddenPost(post);

if (post.isWriter(loginMember) && post.isHidden()) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍👍

return PostResponse.ofUser(
loginMember,
post,
postCategoryRepository.findAllByPost(post),
post.getFirstContentImage(),
post.getPostOptions(),
voteRepository.findByMemberAndPostOptionPost(loginMember, post)
);
}

validateHiddenPost(post);
return PostResponse.ofUser(
loginMember,
post,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return PostResponse.ofUser(
                    loginMember,
                    post,
                    postCategoryRepository.findAllByPost(post),
                    post.getFirstContentImage(),
                    post.getPostOptions(),
                    voteRepository.findByMemberAndPostOptionPost(loginMember, post)
            );

이 부분이 완전히 바로 밑에 return문과 중복되는 것으로 보여서 따로 메서드로 빼는 것은 어떨까요??

보니까 PostQueryService의 가장 밑에 있는 메서드인 convertToResponses 에서도 위의 return문과 완전 똑같은 로직이 존재하는데, 그거까지 같이 처리할 겸, 위 return문을 메서드로 분리해 보는 것이 좋을 것 같아요 :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

메서드 추출해서 중복 제거해보았습니다 훨씬 깔끔해졌네요 ㅎㅎ

Expand Down
Loading