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

문의하기 서비스 구현 #135 #136

Merged
merged 10 commits into from
Dec 1, 2023
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package io.oduck.api.domain.inquiry.dto;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class CheckAnswerRequest {
private Long inquiryId;

public static CheckAnswerRequest from(Long inquiryId) {
return new CheckAnswerRequest(inquiryId);
}
}
17 changes: 17 additions & 0 deletions src/main/java/io/oduck/api/domain/inquiry/dto/InquiryFeedback.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package io.oduck.api.domain.inquiry.dto;

import io.oduck.api.domain.inquiry.entity.FeedbackType;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class InquiryFeedback {
private Long inquiryId;
private FeedbackType helpful;

public static InquiryFeedback from(Long inquiryId, FeedbackType helpful) {
return new InquiryFeedback(inquiryId, helpful);
}
}
28 changes: 28 additions & 0 deletions src/main/java/io/oduck/api/domain/inquiry/dto/InquiryReq.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package io.oduck.api.domain.inquiry.dto;

import io.oduck.api.domain.inquiry.entity.InquiryType;
import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.hibernate.validator.constraints.Length;

public class InquiryReq {
@Getter
@AllArgsConstructor
public static class PostReq {
@NotBlank
@Length(min = 1, max = 50,
message = "글자 수는 1~50을 허용합니다.")
private InquiryType type;

@NotBlank
@Length(min = 1, max = 50,
message = "글자 수는 1~50을 허용합니다.")
private String title;

@NotBlank
@Length(min = 1, max = 1000,
message = "글자 수는 1~1000를 허용합니다.")
private String content;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package io.oduck.api.domain.inquiry.dto;

import io.oduck.api.domain.inquiry.dto.InquiryReq.PostReq;
import io.oduck.api.domain.inquiry.entity.Inquiry;
import io.oduck.api.domain.member.entity.Member;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;

@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Getter
public class InquiryRequestHolder {
private Inquiry inquiry;

public static InquiryRequestHolder from(PostReq request, Member member) {
Inquiry inquiry = Inquiry.builder()
.title(request.getTitle())
.content(request.getContent())
.type(request.getType())
.answer(false)
.check(false)
.member(member)
.build();
return new InquiryRequestHolder(inquiry);
}
}
39 changes: 39 additions & 0 deletions src/main/java/io/oduck/api/domain/inquiry/dto/InquiryRes.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package io.oduck.api.domain.inquiry.dto;

import io.oduck.api.domain.inquiry.entity.Inquiry;
import java.time.LocalDate;
import java.time.LocalDateTime;
import lombok.AllArgsConstructor;
import lombok.Getter;

public class InquiryRes {

@Getter
@AllArgsConstructor
public static class MyInquiry {
private Long id;
private String title;
private LocalDate localDate;
private boolean answer;

public MyInquiry(Long id, String title, LocalDateTime localDateTime, boolean answer) {
this.id = id;
this.title = title;
this.localDate = localDateTime.toLocalDate();
this.answer = answer;
}
}

@Getter
@AllArgsConstructor
public static class DetailRes {
private String title;
private LocalDate localDate;
private boolean answer;

public static DetailRes from(Inquiry inquiry) {
return new DetailRes(inquiry.getTitle(), inquiry.getCreatedAt().toLocalDate(), inquiry.isAnswer());
}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.oduck.api.domain.inquiry.entity;

public enum FeedbackType {
HELPFUL,
NOT_HELPFUL,
NOT_SELECT
}
42 changes: 28 additions & 14 deletions src/main/java/io/oduck/api/domain/inquiry/entity/Inquiry.java
Original file line number Diff line number Diff line change
@@ -1,41 +1,55 @@
package io.oduck.api.domain.inquiry.entity;

import io.oduck.api.domain.member.entity.Member;
import io.oduck.api.global.audit.BaseEntity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import java.time.LocalDateTime;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToOne;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.CreationTimestamp;

@Entity
@Getter
@NoArgsConstructor(access = lombok.AccessLevel.PROTECTED)
public class Inquiry {
@AllArgsConstructor
@Builder
public class Inquiry extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(nullable = false, length = 100)
private String email;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id")
private Member member;

@Column(nullable = false, length = 100)
private String title;

@Column(nullable = false, length = 1000)
private String content;

@Enumerated(EnumType.STRING)
private Status status;
private InquiryType type;

private boolean answer = false;
private boolean check = false;

@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "inquiry_answer_id")
private InquiryAnswer inquiryAnswer;

@Enumerated(EnumType.STRING)
private Result result;
public void checkAnswer() {
check = true;
}

@CreationTimestamp
@Column(nullable = false, updatable = false)
protected LocalDateTime createdAt;
public void feedback(FeedbackType helpful) {
inquiryAnswer.feedback(helpful);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package io.oduck.api.domain.inquiry.entity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Getter
@NoArgsConstructor(access = lombok.AccessLevel.PROTECTED)
@AllArgsConstructor
@Builder
public class InquiryAnswer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(nullable = false, columnDefinition = "TEXT")
private String content;

private FeedbackType helpful;

public void feedback(FeedbackType helpful) {
this.helpful = helpful;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.oduck.api.domain.inquiry.entity;

public enum InquiryType {
ADD_REQUEST,
BUG_REPORT,
ETC_REQUEST
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package io.oduck.api.domain.inquiry.repository;

import io.oduck.api.domain.inquiry.entity.Inquiry;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

public interface InquiryRepository extends JpaRepository<Inquiry, Long>, InquiryRepositoryCustom {

@Query("select i from Inquiry i join fetch i.member where i.id = :id")
Optional<Inquiry> findWithMemberById(@Param("id") Long id);

boolean existsByIdAndCheck(Long id, boolean isCheck);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package io.oduck.api.domain.inquiry.repository;

import io.oduck.api.domain.inquiry.dto.InquiryRes.MyInquiry;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

public interface InquiryRepositoryCustom {
Page<MyInquiry> getAllByMemberId(Long memberId, Pageable pageable);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package io.oduck.api.domain.inquiry.repository;

import static io.oduck.api.domain.inquiry.entity.QInquiry.inquiry;

import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import io.oduck.api.domain.inquiry.dto.InquiryRes.MyInquiry;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.support.PageableExecutionUtils;
import org.springframework.stereotype.Repository;

@Slf4j
@Repository
@RequiredArgsConstructor
public class InquiryRepositoryCustomImpl implements InquiryRepositoryCustom {

private final JPAQueryFactory queryFactory;

@Override
public Page<MyInquiry> getAllByMemberId(Long memberId, Pageable pageable) {

List<MyInquiry> content = queryFactory.select(
Projections.constructor(
MyInquiry.class,
inquiry.id,
inquiry.title,
inquiry.createdAt,
inquiry.answer
)
).from(inquiry)
.where(memberIdEq(memberId))
.fetch();

JPAQuery<Long> expression = queryFactory.select(inquiry.id.count()).from(inquiry)
.where(memberIdEq(memberId));

return PageableExecutionUtils.getPage(content, pageable, expression::fetchOne);
}

private BooleanExpression memberIdEq(Long memberId) {
return memberId == null ? null : inquiry.member.id.eq(memberId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package io.oduck.api.domain.inquiry.service;

import io.oduck.api.domain.inquiry.entity.Inquiry;
import io.oduck.api.domain.member.entity.Member;
import io.oduck.api.global.exception.ForbiddenException;
import org.springframework.stereotype.Component;

@Component
public class InquiryPolicy {

public void isAccessOwnInquiry(Inquiry inquiry, Member member) {
if(!isOwnInquiry(inquiry, member)) {
throw new ForbiddenException("not has permission");
}
inquiry.getMember().getId();
}

private boolean isOwnInquiry(Inquiry inquiry, Member member) {
return inquiry.getMember().getId().equals(member.getId());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package io.oduck.api.domain.inquiry.service;

import io.oduck.api.domain.inquiry.dto.InquiryReq.PostReq;
import io.oduck.api.domain.inquiry.dto.InquiryRes.DetailRes;
import io.oduck.api.domain.inquiry.dto.InquiryRes.MyInquiry;
import io.oduck.api.domain.inquiry.entity.FeedbackType;
import io.oduck.api.global.common.PageResponse;

public interface InquiryService {
void inquiry(Long memberId, PostReq request);

PageResponse<MyInquiry> getAllByMemberId(Long memberId, int page, int size);

DetailRes getByMemberId(Long inquiryId, Long memberId);

boolean hasNotCheckedAnswer(Long id, Long memberId);

void feedbackAnswer(Long id, Long memberId, FeedbackType helpful);

// Page<?> getAll();
//
// void answer();
//
// void update(Long id);
}
Loading