Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
27 changes: 0 additions & 27 deletions src/main/java/com/somemore/domains/Review.java

This file was deleted.

25 changes: 0 additions & 25 deletions src/main/java/com/somemore/domains/VolunteerManagement.java

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ public enum ExceptionMessage {
FILE_SIZE_EXCEEDED("파일 크기가 허용된 한도를 초과했습니다."),
EMPTY_FILE("파일이 존재하지 않습니다."),
INSTANTIATION_NOT_ALLOWED("인스턴스화 할 수 없는 클래스 입니다."),
NOT_EXISTS_VOLUNTEER_APPLY("존재하지 않는 봉사 활동 지원입니다."),
REVIEW_ALREADY_EXISTS("이미 작성한 리뷰가 존재합니다."),
REVIEW_RESTRICTED_TO_ATTENDED("리뷰는 참석한 봉사에 한해서만 작성할 수 있습니다.")
CANNOT_CANCEL_DELETED_INTEREST_CENTER("이미 삭제된 관심 기관은 취소할 수 없습니다."),
DUPLICATE_INTEREST_CENTER("이미 관심 표시한 기관입니다.")
;
Expand Down
53 changes: 53 additions & 0 deletions src/main/java/com/somemore/review/domain/Review.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.somemore.review.domain;

import static jakarta.persistence.GenerationType.IDENTITY;
import static lombok.AccessLevel.PROTECTED;

import com.somemore.global.common.BaseEntity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.Lob;
import jakarta.persistence.Table;
import java.util.UUID;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor(access = PROTECTED)
@Entity
@Table(name = "review")
public class Review extends BaseEntity {

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

@Column(name = "volunteer_apply_id", nullable = false)
private Long volunteerApplyId;

@Column(name = "volunteer_id", nullable = false, length = 16)
private UUID volunteerId;

@Column(name = "title", nullable = false)
private String title;

@Lob
@Column(name = "content", nullable = false)
private String content;

@Column(name = "img_url", nullable = false)
private String imgUrl;

@Builder
public Review(Long volunteerApplyId, UUID volunteerId, String title,
String content, String imgUrl) {
this.volunteerApplyId = volunteerApplyId;
this.volunteerId = volunteerId;
this.title = title;
this.content = content;
this.imgUrl = imgUrl;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.somemore.review.dto.request;

import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import com.somemore.review.domain.Review;
import com.somemore.volunteerapply.domain.VolunteerApply;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import java.util.UUID;
import lombok.Builder;

@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
@Builder
public record ReviewCreateRequestDto(
@Schema(description = "봉사 모집글 아이디", example = "1")
@NotNull(message = "봉사 모집글 아이디는 필수 값입니다.")
Long recruitBoardId,
@Schema(description = "리뷰 제목", example = "내 인생 최고의 봉사 활동")
@NotBlank(message = "리뷰 제목은 필수 값입니다.")
String title,
@Schema(description = "리뷰 내용", example = "담당자님도 정말 친절하였고 정말 보람찬 봉사였어요 더보기..<br>")
@NotBlank(message = "리뷰 내용은 필수 값입니다.")
String content
) {

public Review toEntity(VolunteerApply apply, UUID volunteerId, String imgUrl) {
return Review.builder()
.volunteerApplyId(apply.getId())
.volunteerId(volunteerId)
.title(title)
.content(content)
.imgUrl(imgUrl)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.somemore.review.repository;

import com.somemore.review.domain.Review;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

public interface ReviewJpaRepository extends JpaRepository<Review, Long> {

Optional<Review> findByIdAndDeletedFalse(Long id);

@Query("SELECT COUNT(r) > 0 FROM Review r WHERE r.volunteerApplyId = :volunteerId AND r.deleted = false")
boolean existsByVolunteerApplyId(Long volunteerId);

}
13 changes: 13 additions & 0 deletions src/main/java/com/somemore/review/repository/ReviewRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.somemore.review.repository;

import com.somemore.review.domain.Review;
import java.util.Optional;

public interface ReviewRepository {

Review save(Review review);

Optional<Review> findById(Long id);

boolean existsByVolunteerApplyId(Long volunteerApplyId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.somemore.review.repository;

import com.querydsl.jpa.impl.JPAQueryFactory;
import com.somemore.review.domain.Review;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;

@RequiredArgsConstructor
@Repository
public class ReviewRepositoryImpl implements ReviewRepository {

private final ReviewJpaRepository reviewJpaRepository;
private final JPAQueryFactory queryFactory;

@Override
public Review save(Review review) {
return reviewJpaRepository.save(review);
}

@Override
public Optional<Review> findById(Long id) {
return reviewJpaRepository.findByIdAndDeletedFalse(id);
}

@Override
public boolean existsByVolunteerApplyId(Long volunteerApplyId) {
return reviewJpaRepository.existsByVolunteerApplyId(volunteerApplyId);
}
}
52 changes: 52 additions & 0 deletions src/main/java/com/somemore/review/service/CreateReviewService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.somemore.review.service;

import static com.somemore.global.exception.ExceptionMessage.REVIEW_ALREADY_EXISTS;
import static com.somemore.global.exception.ExceptionMessage.REVIEW_RESTRICTED_TO_ATTENDED;

import com.somemore.global.exception.BadRequestException;
import com.somemore.review.domain.Review;
import com.somemore.review.dto.request.ReviewCreateRequestDto;
import com.somemore.review.repository.ReviewRepository;
import com.somemore.review.usecase.CreateReviewUseCase;
import com.somemore.volunteerapply.domain.VolunteerApply;
import com.somemore.volunteerapply.usecase.VolunteerApplyQueryUseCase;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@RequiredArgsConstructor
@Transactional
@Service
public class CreateReviewService implements CreateReviewUseCase {

private final ReviewRepository reviewRepository;
private final VolunteerApplyQueryUseCase volunteerApplyQueryUseCase;

@Override
public Long createReview(ReviewCreateRequestDto requestDto, UUID volunteerId, String imgUrl) {
VolunteerApply apply = getVolunteerApply(requestDto.recruitBoardId(), volunteerId);
validateReviewNotExist(apply);
validateActivityCompletion(apply);

Review review = requestDto.toEntity(apply, volunteerId, imgUrl);
return reviewRepository.save(review).getId();
}

private VolunteerApply getVolunteerApply(Long recruitBoardId, UUID volunteerId) {
return volunteerApplyQueryUseCase.getByRecruitIdAndVolunteerId(recruitBoardId, volunteerId);
}

private void validateReviewNotExist(VolunteerApply apply) {
if (reviewRepository.existsByVolunteerApplyId(apply.getId())) {
throw new BadRequestException(REVIEW_ALREADY_EXISTS.getMessage());
}
}

private void validateActivityCompletion(VolunteerApply apply) {
if (apply.isVolunteerActivityCompleted()) {
return;
}
throw new BadRequestException(REVIEW_RESTRICTED_TO_ATTENDED.getMessage());
}
}
11 changes: 11 additions & 0 deletions src/main/java/com/somemore/review/usecase/CreateReviewUseCase.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.somemore.review.usecase;

import com.somemore.review.dto.request.ReviewCreateRequestDto;
import java.util.UUID;

public interface CreateReviewUseCase {

Long createReview(ReviewCreateRequestDto requestDto, UUID volunteerId, String imgUrl);


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.somemore.volunteerapply.domain;

public enum ApplyStatus {
WAITING,
APPROVED,
REJECTED,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package com.somemore.volunteerapply.domain;

import static com.somemore.volunteerapply.domain.ApplyStatus.APPROVED;

import com.somemore.global.common.BaseEntity;
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.Table;
import java.util.UUID;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
@Table(name = "volunteer_apply")
public class VolunteerApply extends BaseEntity {

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

@Column(name = "volunteer_id", nullable = false, columnDefinition = "BINARY(16)")
private UUID volunteerId;

@Column(name = "recruit_board_id", nullable = false)
private Long recruitBoardId;

@Enumerated(EnumType.STRING)
@Column(name = "status", nullable = false, length = 20)
private ApplyStatus status = ApplyStatus.WAITING;

@Column(name = "attended", nullable = false)
private Boolean attended = false;

@Builder
public VolunteerApply(UUID volunteerId, Long recruitBoardId, ApplyStatus status,
Boolean attended) {
this.volunteerId = volunteerId;
this.recruitBoardId = recruitBoardId;
this.status = status;
this.attended = attended;
}

public void changeStatus(ApplyStatus status) {
if (isVolunteerActivityCompleted()) {
throw new IllegalStateException("이미 완료된 봉사활동에 대해서는 변경이 불가능합니다.");
}
this.status = status;
}

public void changeAttended(Boolean attended) {
if (this.status != APPROVED) {
throw new IllegalStateException("승인되지 않은 봉사 지원은 참석 여부를 변경할 수 없습니다.");
}
this.attended = attended;
}

public boolean isVolunteerActivityCompleted() {
return this.attended && this.status == APPROVED;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.somemore.volunteerapply.repository;

import com.somemore.volunteerapply.domain.VolunteerApply;
import org.springframework.data.jpa.repository.JpaRepository;

public interface VolunteerApplyJpaRepository extends JpaRepository<VolunteerApply, Long> {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.somemore.volunteerapply.repository;

import com.somemore.volunteerapply.domain.VolunteerApply;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

public interface VolunteerApplyRepository {

VolunteerApply save(VolunteerApply volunteerApply);
Optional<VolunteerApply> findById(Long id);
List<UUID> findVolunteerIdsByRecruitIds(List<Long> recruitIds);
Page<VolunteerApply> findAllByRecruitId(Long recruitId, Pageable pageable);
Optional<VolunteerApply> findByRecruitIdAndVolunteerId(Long recruitId, UUID volunteerId);

}
Loading
Loading