Skip to content

Commit

Permalink
Merge pull request #24 from DDD-Community/feature/ITDS-43-report-log
Browse files Browse the repository at this point in the history
Feature/itds-43 report log
  • Loading branch information
kikingki authored Sep 13, 2024
2 parents 25e5e46 + c48b500 commit b93faf2
Show file tree
Hide file tree
Showing 8 changed files with 167 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ public enum ErrorCode {
NON_EXISTENT_INFO_POST_ID(HttpStatus.NOT_FOUND, "해당 id의 공고 게시글이 존재하지 않습니다."),
REPORTED_INFO_POST_ID(HttpStatus.NOT_FOUND, "해당 id의 게시글은 신고 처리되었습니다."),

// 409
ALREADY_REPORTED_POST(HttpStatus.CONFLICT, "이미 신고한 공고입니다."),

// 500
IO_EXCEPTION(HttpStatus.INTERNAL_SERVER_ERROR, "파일 입출력 에러"),
INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "서버 내부 에러");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.dissonance.itit.dto.response.InfoPostDetailRes;
import com.dissonance.itit.dto.response.InfoPostRes;
import com.dissonance.itit.service.InfoPostService;
import com.dissonance.itit.service.ReportService;

import io.swagger.v3.oas.annotations.Operation;
import jakarta.validation.Valid;
Expand All @@ -30,6 +31,7 @@
@RequestMapping("/info-posts")
public class InfoPostController {
private final InfoPostService infoPostService;
private final ReportService reportService;

@PostMapping(consumes = {MediaType.MULTIPART_FORM_DATA_VALUE, MediaType.APPLICATION_JSON_VALUE})
@Operation(summary = "공고 게시글 등록", description = "공고 게시글을 등록합니다.")
Expand All @@ -47,9 +49,9 @@ public ResponseEntity<InfoPostDetailRes> getInfoPostDetail(@PathVariable Long in
}

@PatchMapping("/{infoPostId}/reports")
@Operation(summary = "공고 게시글 신고", description = "공고 게시글을 신고 처리합니다. (즉시 반영)")
public ResponseEntity<String> reportedInfoPost(@PathVariable Long infoPostId) {
Long resultId = infoPostService.reportedInfoPost(infoPostId);
@Operation(summary = "공고 게시글 신고", description = "공고 게시글을 신고 처리합니다.")
public ResponseEntity<String> reportedInfoPost(@PathVariable Long infoPostId, @CurrentUser User loginUser) {
Long resultId = reportService.reportedInfoPost(infoPostId, loginUser);
return ResponseEntity.ok(resultId + "번 게시글의 신고가 성공적으로 접수되었습니다.");
}

Expand Down
42 changes: 27 additions & 15 deletions src/main/java/com/dissonance/itit/domain/entity/Report.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
package com.dissonance.itit.domain.entity;

import jakarta.persistence.*;
import jakarta.persistence.Column;
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 jakarta.persistence.Table;
import jakarta.validation.constraints.Size;
import lombok.*;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@Builder
Expand All @@ -11,20 +23,20 @@
@Entity
@Table(name = "report")
public class Report {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private String id;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "info_post_id")
private InfoPost infoPost;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "info_post_id")
private InfoPost infoPost;

@Size(max = 255)
@Column(name = "content")
private String content;
@Size(max = 255)
@Column(name = "content")
private String content;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.dissonance.itit.repository;

import org.springframework.data.jpa.repository.JpaRepository;

import com.dissonance.itit.domain.entity.Report;

public interface ReportRepository extends JpaRepository<Report, Long> {
boolean existsByInfoPostIdAndUserId(Long infoPostId, Long UserId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,10 @@ public InfoPostDetailRes getInfoPostDetailById(Long infoPostId) {
return InfoPostDetailRes.of(infoPostInfo, positionInfos);
}

@Transactional
public Long reportedInfoPost(Long infoPostId) {
InfoPost infoPost = infoPostRepository.findById(infoPostId)
@Transactional(readOnly = true)
public InfoPost findById(Long infoPostId) {
return infoPostRepository.findById(infoPostId)
.orElseThrow(() -> new CustomException(ErrorCode.NON_EXISTENT_INFO_POST_ID));
infoPost.updateReported();
return infoPost.getId();
}

@Transactional(readOnly = true)
Expand Down
38 changes: 38 additions & 0 deletions src/main/java/com/dissonance/itit/service/ReportService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.dissonance.itit.service;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.dissonance.itit.common.exception.CustomException;
import com.dissonance.itit.common.exception.ErrorCode;
import com.dissonance.itit.domain.entity.InfoPost;
import com.dissonance.itit.domain.entity.Report;
import com.dissonance.itit.domain.entity.User;
import com.dissonance.itit.repository.ReportRepository;

import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class ReportService {
private final ReportRepository reportRepository;

private final InfoPostService infoPostService;

@Transactional
public Long reportedInfoPost(Long infoPostId, User user) {
InfoPost infoPost = infoPostService.findById(infoPostId);

if (reportRepository.existsByInfoPostIdAndUserId(infoPostId, user.getId())) {
throw new CustomException(ErrorCode.ALREADY_REPORTED_POST);
}

Report report = Report.builder()
.infoPost(infoPost)
.user(user)
.build();
reportRepository.save(report);

return infoPost.getId();
}
}
47 changes: 13 additions & 34 deletions src/test/java/com/dissonance/itit/service/InfoPostServiceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -136,40 +136,6 @@ void getInfoPostDetailById_throwCustomException_givenReportedInfoPostId() {
.hasMessage(ErrorCode.REPORTED_INFO_POST_ID.getMessage());
}

@Test
@DisplayName("게시글 신고")
void reportedInfoPost_returnInfoPostId() {
// given
Long infoPostId = 1L;
InfoPostReq infoPostReq = TestFixture.createInfoPostReq();
User author = TestFixture.createUser();
Image image = TestFixture.createImage();
Category category = TestFixture.createCategory();
InfoPost infoPost = TestFixture.createInfoPost(infoPostReq, author, image, category);

given(infoPostRepository.findById(infoPostId)).willReturn(Optional.of(infoPost));

// when
Long result = infoPostService.reportedInfoPost(infoPostId);

// then
assertThat(result).isEqualTo(infoPostId);
verify(infoPostRepository).findById(infoPostId);
}

@Test
@DisplayName("게시글 신고시 존재하지 않는 ID로 조회하여 exception 발생")
void reportedInfoPost_throwCustomException_givenNonExistentId() {
// given
Long infoPostId = 999L;
given(infoPostRepository.findById(infoPostId)).willReturn(Optional.empty());

// when & then
assertThatThrownBy(() -> infoPostService.reportedInfoPost(infoPostId))
.isInstanceOf(CustomException.class)
.hasMessage(ErrorCode.NON_EXISTENT_INFO_POST_ID.getMessage());
}

@Test
@DisplayName("공고 게시글 목록 page 조회")
void getInfoPostsByCategoryId_returnInfoPostResPage() {
Expand All @@ -195,4 +161,17 @@ void getInfoPostsByCategoryId_returnInfoPostResPage() {
() -> assertThat(content.get(2).getRemainingDays()).isEqualTo("D+3")
);
}

@Test
@DisplayName("존재하지 않는 ID로 조회하여 exception 발생")
void findById_throwCustomException_givenNonExistentId() {
// given
Long infoPostId = 999L;
given(infoPostRepository.findById(infoPostId)).willReturn(Optional.empty());

// when & then
assertThatThrownBy(() -> infoPostService.findById(infoPostId))
.isInstanceOf(CustomException.class)
.hasMessage(ErrorCode.NON_EXISTENT_INFO_POST_ID.getMessage());
}
}
69 changes: 69 additions & 0 deletions src/test/java/com/dissonance/itit/service/ReportServiceTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package com.dissonance.itit.service;

import static org.assertj.core.api.Assertions.*;
import static org.mockito.BDDMockito.*;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import com.dissonance.itit.common.exception.CustomException;
import com.dissonance.itit.common.exception.ErrorCode;
import com.dissonance.itit.domain.entity.Category;
import com.dissonance.itit.domain.entity.Image;
import com.dissonance.itit.domain.entity.InfoPost;
import com.dissonance.itit.domain.entity.User;
import com.dissonance.itit.dto.request.InfoPostReq;
import com.dissonance.itit.fixture.TestFixture;
import com.dissonance.itit.repository.ReportRepository;

@ExtendWith(MockitoExtension.class)
public class ReportServiceTest {
@InjectMocks
private ReportService reportService;
@Mock
private ReportRepository reportRepository;
@Mock
private InfoPostService infoPostService;

@Test
@DisplayName("게시글 신고")
void reportedInfoPost_returnInfoPostId() {
// given
Long infoPostId = 1L;
InfoPostReq infoPostReq = TestFixture.createInfoPostReq();
User author = TestFixture.createUser();
Image image = TestFixture.createImage();
Category category = TestFixture.createCategory();
InfoPost infoPost = TestFixture.createInfoPost(infoPostReq, author, image, category);

given(infoPostService.findById(infoPostId)).willReturn(infoPost);
given(reportRepository.existsByInfoPostIdAndUserId(infoPostId, author.getId()))
.willReturn(false);

// when
Long result = reportService.reportedInfoPost(infoPostId, author);

// then
assertThat(result).isEqualTo(infoPostId);
verify(reportRepository, times(1)).save(any());
}

@Test
@DisplayName("게시글 신고시 중복 신고로 인한 exception 발생")
void reportedInfoPost_throwCustomException_givenDuplicateReports() {
// given
Long infoPostId = 999L;
User loginUser = TestFixture.createUser();
given(reportRepository.existsByInfoPostIdAndUserId(infoPostId, loginUser.getId()))
.willReturn(true);

// when & then
assertThatThrownBy(() -> reportService.reportedInfoPost(infoPostId, loginUser))
.isInstanceOf(CustomException.class)
.hasMessage(ErrorCode.ALREADY_REPORTED_POST.getMessage());
}
}

0 comments on commit b93faf2

Please sign in to comment.