-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
Feature/question/#34
- Loading branch information
Showing
32 changed files
with
1,033 additions
and
4 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
77 changes: 77 additions & 0 deletions
77
baebae-BE/src/main/java/com/web/baebaeBE/application/answer/AnswerApplication.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package com.web.baebaeBE.application.answer; | ||
|
||
import com.web.baebaeBE.domain.answer.exception.AnswerError; | ||
import com.web.baebaeBE.domain.answer.service.AnswerService; | ||
import com.web.baebaeBE.domain.member.exception.MemberError; | ||
import com.web.baebaeBE.global.error.exception.BusinessException; | ||
import com.web.baebaeBE.global.image.s3.S3ImageStorageService; | ||
import com.web.baebaeBE.infra.answer.entity.Answer; | ||
import com.web.baebaeBE.infra.answer.repository.AnswerMapper; | ||
import com.web.baebaeBE.infra.member.entity.Member; | ||
import com.web.baebaeBE.infra.member.repository.MemberRepository; | ||
import com.web.baebaeBE.infra.question.entity.Question; | ||
import com.web.baebaeBE.infra.question.repository.QuestionRepository; | ||
import com.web.baebaeBE.presentation.answer.dto.AnswerCreateRequest; | ||
import com.web.baebaeBE.presentation.answer.dto.AnswerDetailResponse; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.data.domain.Page; | ||
import org.springframework.data.domain.Pageable; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.web.multipart.MultipartFile; | ||
|
||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
|
||
@Service | ||
@RequiredArgsConstructor | ||
public class AnswerApplication { | ||
private final AnswerService answerService; | ||
private final AnswerMapper answerMapper; | ||
private final MemberRepository memberRepository; | ||
private final QuestionRepository questionRepository; | ||
private final S3ImageStorageService s3ImageStorageService; | ||
|
||
public AnswerDetailResponse createAnswer(AnswerCreateRequest request, Long memberId) { | ||
Member member = memberRepository.findById(memberId) | ||
.orElseThrow(() -> new BusinessException(MemberError.NOT_EXIST_MEMBER)); | ||
Question question = questionRepository.findById(request.getQuestionId()) | ||
.orElseThrow(() -> new BusinessException(AnswerError.NO_EXIST_QUESTION)); | ||
List<String> imageUrls = uploadImages(request.getImageFiles()); | ||
Answer answerEntity = answerMapper.toEntity(request, question, member); | ||
Answer savedAnswerEntity = answerService.createAnswer(answerEntity, request.getImageFiles()); | ||
return answerMapper.toDomain(savedAnswerEntity); | ||
} | ||
|
||
private List<String> uploadImages(List<MultipartFile> files) { | ||
List<String> urls = new ArrayList<>(); | ||
for (MultipartFile file : files) { | ||
try { | ||
String fileName = System.currentTimeMillis() + "_" + file.getOriginalFilename(); | ||
String path = "answers/images"; | ||
InputStream inputStream = file.getInputStream(); | ||
String url = s3ImageStorageService.uploadFile(path, fileName, inputStream, file.getSize(), file.getContentType()); | ||
urls.add(url); | ||
} catch (IOException e) { | ||
throw new BusinessException(AnswerError.IMAGE_PROCESSING_ERROR); | ||
} | ||
} | ||
return urls; | ||
} | ||
|
||
public Page<AnswerDetailResponse> getAllAnswers(Long memberId, Pageable pageable) { | ||
Page<Answer> answerPage = answerService.getAllAnswers(memberId, pageable); | ||
return answerPage.map(answerMapper::toDomain); | ||
} | ||
|
||
public AnswerDetailResponse updateAnswer(Long answerId, AnswerCreateRequest request, MultipartFile[] imageFiles) { | ||
Answer updatedAnswer = answerService.updateAnswer(answerId, request, imageFiles); | ||
return answerMapper.toDomain(updatedAnswer); | ||
} | ||
|
||
public void deleteAnswer(Long answerId) { | ||
answerService.deleteAnswer(answerId); | ||
} | ||
} |
56 changes: 56 additions & 0 deletions
56
baebae-BE/src/main/java/com/web/baebaeBE/application/question/QuestionApplication.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package com.web.baebaeBE.application.question; | ||
|
||
import com.web.baebaeBE.domain.member.exception.MemberError; | ||
import com.web.baebaeBE.domain.question.service.QuestionService; | ||
import com.web.baebaeBE.global.error.exception.BusinessException; | ||
import com.web.baebaeBE.infra.member.entity.Member; | ||
import com.web.baebaeBE.infra.member.repository.MemberRepository; | ||
import com.web.baebaeBE.infra.question.entity.Question; | ||
import com.web.baebaeBE.infra.question.repository.QuestionMapper; | ||
import com.web.baebaeBE.presentation.question.dto.QuestionCreateRequest; | ||
import com.web.baebaeBE.presentation.question.dto.QuestionDetailResponse; | ||
import jakarta.transaction.Transactional; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
import org.springframework.data.domain.Page; | ||
import org.springframework.data.domain.Pageable; | ||
import org.springframework.stereotype.Service; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
@Transactional | ||
public class QuestionApplication { | ||
private final QuestionService questionService; | ||
private final QuestionMapper questionMapper; | ||
private final MemberRepository memberRepository; | ||
|
||
public QuestionDetailResponse createQuestion(QuestionCreateRequest request, Long senderId, Long receiverId, String token) { | ||
Member sender = memberRepository.findById(senderId) | ||
.orElseThrow(() -> new BusinessException(MemberError.NOT_EXIST_MEMBER)); | ||
Member receiver = memberRepository.findById(receiverId) | ||
.orElseThrow(() -> new BusinessException(MemberError.NOT_EXIST_MEMBER)); | ||
|
||
Question questionEntity = questionMapper.toEntity(request, sender, receiver); | ||
Question savedQuestionEntity = questionService.createQuestion(questionEntity); | ||
return questionMapper.toDomain(savedQuestionEntity, token); | ||
} | ||
|
||
public Page<QuestionDetailResponse> getAllQuestions(Long memberId, Pageable pageable, boolean isSender) { | ||
Page<Question> questionPage; | ||
if (isSender) { | ||
questionPage = questionService.getQuestionsBySenderId(memberId, pageable); | ||
} else { | ||
questionPage = questionService.getQuestionsByReceiverId(memberId, pageable); | ||
} | ||
return questionPage.map(question -> questionMapper.toDomain(question, "appropriate token here")); | ||
} | ||
|
||
public QuestionDetailResponse updateQuestion(Long questionId, String content, String token) { | ||
Question updatedQuestion = questionService.updateQuestion(questionId, content); | ||
return questionMapper.toDomain(updatedQuestion, token); | ||
} | ||
|
||
public void deleteQuestion(Long questionId) { | ||
questionService.deleteQuestion(questionId); | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
baebae-BE/src/main/java/com/web/baebaeBE/domain/answer/exception/AnswerError.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package com.web.baebaeBE.domain.answer.exception; | ||
|
||
import com.web.baebaeBE.global.error.ErrorCode; | ||
import lombok.Getter; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.http.HttpStatus; | ||
|
||
@Getter | ||
@RequiredArgsConstructor | ||
public enum AnswerError implements ErrorCode { | ||
|
||
NO_EXIST_MEMBER(HttpStatus.NOT_FOUND, "M-001", "존재하지 않는 회원입니다."), | ||
NO_EXIST_ANSWER(HttpStatus.NOT_FOUND, "M-002", "존재하지 않는 답변입니다."), | ||
NO_EXIST_QUESTION(HttpStatus.NOT_FOUND, "M-003", "존재하지 않는 질문입니다."), | ||
IMAGE_PROCESSING_ERROR(HttpStatus.NOT_FOUND, "M-004", "이미지 업로드 오류입니다."); | ||
|
||
private final HttpStatus httpStatus; | ||
private final String errorCode; | ||
private final String message; | ||
|
||
} |
85 changes: 85 additions & 0 deletions
85
baebae-BE/src/main/java/com/web/baebaeBE/domain/answer/service/AnswerService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
package com.web.baebaeBE.domain.answer.service; | ||
|
||
import com.web.baebaeBE.domain.answer.exception.AnswerError; | ||
import com.web.baebaeBE.global.error.exception.BusinessException; | ||
import com.web.baebaeBE.global.image.s3.S3ImageStorageService; | ||
import com.web.baebaeBE.infra.answer.entity.Answer; | ||
import com.web.baebaeBE.infra.answer.repository.AnswerRepository; | ||
import com.web.baebaeBE.presentation.answer.dto.AnswerCreateRequest; | ||
import jakarta.transaction.Transactional; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.data.domain.Page; | ||
import org.springframework.data.domain.Pageable; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.web.multipart.MultipartFile; | ||
|
||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
@RequiredArgsConstructor | ||
@Service | ||
public class AnswerService { | ||
private final AnswerRepository answerRepository; | ||
private final S3ImageStorageService s3ImageStorageService; | ||
|
||
public Answer createAnswer(Answer answer, List<MultipartFile> imageFiles) { | ||
List<String> urls = new ArrayList<>(); | ||
try { | ||
for (MultipartFile file : imageFiles) { | ||
String fileName = System.currentTimeMillis() + "_" + file.getOriginalFilename(); | ||
String path = "answers/images"; | ||
InputStream inputStream = file.getInputStream(); | ||
String url = s3ImageStorageService.uploadFile(path, fileName, inputStream, file.getSize(), file.getContentType()); | ||
urls.add(url); | ||
} | ||
} catch (IOException e) { | ||
throw new BusinessException(AnswerError.IMAGE_PROCESSING_ERROR); | ||
} | ||
answer.setImageFiles(urls); | ||
return answerRepository.save(answer); | ||
} | ||
|
||
@Transactional | ||
public Page<Answer> getAllAnswers(Long memberId, Pageable pageable) { | ||
return answerRepository.findAllByMemberId(memberId, pageable); | ||
} | ||
|
||
@Transactional | ||
public Answer updateAnswer(Long answerId, AnswerCreateRequest request, MultipartFile[] imageFiles) { | ||
Answer answer = answerRepository.findByAnswerId(answerId) | ||
.orElseThrow(() -> new BusinessException(AnswerError.NO_EXIST_ANSWER)); | ||
|
||
List<String> urls = new ArrayList<>(); | ||
try { | ||
for (MultipartFile file : imageFiles) { | ||
String fileName = file.getOriginalFilename(); | ||
String path = "answers/images"; | ||
InputStream inputStream = file.getInputStream(); | ||
String url = s3ImageStorageService.uploadFile(path, fileName, inputStream, file.getSize(), file.getContentType()); | ||
urls.add(url); | ||
} | ||
} catch (IOException e) { | ||
throw new BusinessException(AnswerError.IMAGE_PROCESSING_ERROR); | ||
} | ||
answer.setImageFiles(urls); | ||
|
||
answer.setContent(request.getContent()); | ||
answer.setLinkAttachments(request.getLinkAttachments()); | ||
answer.setMusicName(request.getMusicName()); | ||
|
||
return answerRepository.save(answer); | ||
} | ||
|
||
@Transactional | ||
public void deleteAnswer(Long answerId) { | ||
Answer answer = answerRepository.findByAnswerId(answerId) | ||
.orElseThrow(() -> new IllegalArgumentException("No answer found with id " + answerId)); | ||
answer.getImageFiles().forEach(url -> { | ||
String fileName = url.substring(url.lastIndexOf("/") + 1); | ||
s3ImageStorageService.deleteFile("answers/images", fileName); | ||
}); | ||
answerRepository.delete(answer); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
18 changes: 18 additions & 0 deletions
18
baebae-BE/src/main/java/com/web/baebaeBE/domain/question/exception/QuestionError.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package com.web.baebaeBE.domain.question.exception; | ||
|
||
import com.web.baebaeBE.global.error.ErrorCode; | ||
import lombok.Getter; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.http.HttpStatus; | ||
|
||
@Getter | ||
@RequiredArgsConstructor | ||
public enum QuestionError implements ErrorCode { | ||
NO_EXIST_MEMBER(HttpStatus.NOT_FOUND, "M-001", "존재하지 않는 회원입니다."), | ||
UNFILLED_QUESTION(HttpStatus.NOT_FOUND, "M-002", "빈칸으로 제출할 수 없습니다."), | ||
NO_EXIST_QUESTION(HttpStatus.NOT_FOUND, "M-003", "존재하지 않는 질문입니다."); | ||
|
||
private final HttpStatus httpStatus; | ||
private final String errorCode; | ||
private final String message; | ||
} |
48 changes: 48 additions & 0 deletions
48
baebae-BE/src/main/java/com/web/baebaeBE/domain/question/service/QuestionService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package com.web.baebaeBE.domain.question.service; | ||
|
||
import com.web.baebaeBE.domain.question.exception.QuestionError; | ||
import com.web.baebaeBE.global.error.exception.BusinessException; | ||
import com.web.baebaeBE.infra.question.entity.Question; | ||
import com.web.baebaeBE.infra.question.repository.QuestionRepository; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.data.domain.Page; | ||
import org.springframework.data.domain.Pageable; | ||
import org.springframework.transaction.annotation.Transactional; | ||
import org.springframework.stereotype.Service; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
public class QuestionService { | ||
private final QuestionRepository questionRepository; | ||
|
||
@Transactional | ||
public Question createQuestion(Question question) { | ||
return questionRepository.save(question); | ||
} | ||
|
||
@Transactional(readOnly = true) | ||
public Page<Question> getQuestionsBySenderId(Long senderId, Pageable pageable) { | ||
return questionRepository.findAllBySenderId(senderId, pageable); | ||
} | ||
|
||
@Transactional(readOnly = true) | ||
public Page<Question> getQuestionsByReceiverId(Long receiverId, Pageable pageable) { | ||
return questionRepository.findAllByReceiverId(receiverId, pageable); | ||
} | ||
|
||
@Transactional | ||
public Question updateQuestion(Long questionId, String content) { | ||
Question questionEntity = questionRepository.findById(questionId) | ||
.orElseThrow(() -> new BusinessException(QuestionError.NO_EXIST_QUESTION)); | ||
questionEntity.updateContent(content); | ||
return questionRepository.save(questionEntity); | ||
} | ||
|
||
@Transactional | ||
public void deleteQuestion(Long questionId) { | ||
Question questionEntity = questionRepository.findById(questionId) | ||
.orElseThrow(() -> new BusinessException(QuestionError.NO_EXIST_QUESTION)); | ||
questionRepository.delete(questionEntity); | ||
} | ||
|
||
} |
18 changes: 18 additions & 0 deletions
18
baebae-BE/src/main/java/com/web/baebaeBE/global/converter/StringListConverter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package com.web.baebaeBE.global.converter; | ||
|
||
import jakarta.persistence.AttributeConverter; | ||
|
||
import java.util.Arrays; | ||
import java.util.List; | ||
|
||
public class StringListConverter implements AttributeConverter<List<String>, String> { | ||
@Override | ||
public String convertToDatabaseColumn(List<String> attribute) { | ||
return (attribute == null || attribute.isEmpty()) ? "" : String.join(",", attribute); | ||
} | ||
|
||
@Override | ||
public List<String> convertToEntityAttribute(String dbData) { | ||
return (dbData == null || dbData.trim().isEmpty()) ? null : Arrays.asList(dbData.split(",")); | ||
} | ||
} |
Oops, something went wrong.