Skip to content

Commit

Permalink
chore: #133 merge conflict resolved
Browse files Browse the repository at this point in the history
  • Loading branch information
tnals2384 committed Aug 25, 2024
2 parents de05d00 + f4b448f commit 5ce4f11
Show file tree
Hide file tree
Showing 18 changed files with 683 additions and 10 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/cicd-production.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ on:
push:
tags:
- 'v**'
- '!v**-**'

env:
REGISTRY: ghcr.io
Expand Down Expand Up @@ -81,4 +82,4 @@ jobs:
sudo docker container rm spring
sudo docker image rm ${{ env.SPRING_IMAGE }}
sudo docker-compose --env-file=config/env/prod.env -f docker-compose.prod.yml -p backend up -d
sudo docker image prune -af
sudo docker image prune -af
10 changes: 5 additions & 5 deletions .github/workflows/cicd-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ name: Release Deploy

on:
push:
branches:
- 'release-**'
tags:
- 'v**-**'

env:
REGISTRY: ghcr.io
Expand Down Expand Up @@ -38,15 +38,15 @@ jobs:
- name: Get Version
run: |
echo "VERSION=$( echo ${{ github.ref_name }} | cut -c 9- )" >> ${GITHUB_ENV}
echo "VERSION=$( git tag --points-at )" >> ${GITHUB_ENV}
- name: Set Spring Image Environment Variable
run: |
echo "SPRING_IMAGE=${{ env.REGISTRY }}/${{ env.REPOSITORY }}-release:${{ env.VERSION }}" >> ${GITHUB_ENV}
- name: Write Version
run: |
echo "server-version: ${{ env.VERSION }}" >> config/application.yml
echo -e "\nserver-version: ${{ env.VERSION }}" >> config/application-release.yml
- name: Build Image
run: docker build --no-cache -t ${{ env.SPRING_IMAGE }} -f Dockerfile-deploy .
Expand Down Expand Up @@ -127,4 +127,4 @@ jobs:
path: ./*.jar
compression-level: 9
retention-days: 1
overwrite: true
overwrite: true
2 changes: 1 addition & 1 deletion config
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
.requestMatchers("/members/sign-in","/members/sign-up", "/members/local-sign-in", "/token/**", "/members/email/check", "/members/nickname/check", "/members/email/certification", "/members/email/certification/check").permitAll()
.requestMatchers("/admin/**", "/members/email/whitelist/register").hasRole(Role.ROLE_ADMIN.getName())
.requestMatchers("/answers","/answers/**").authenticated()
.requestMatchers("/answerComments","/answerComments/**").authenticated()
.requestMatchers("/members","/members/**").authenticated()
.requestMatchers("/tags","/tags/**").authenticated()
.requestMatchers("/questions","/questions/**").authenticated()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.server.capple.domain.answerComment.controller;

import com.server.capple.config.security.AuthMember;
import com.server.capple.domain.answerComment.dto.AnswerCommentRequest;
import com.server.capple.domain.answerComment.dto.AnswerCommentResponse.*;
import com.server.capple.domain.answerComment.service.AnswerCommentService;
import com.server.capple.domain.member.entity.Member;
import com.server.capple.global.common.BaseResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

@Tag(name = "답변 댓글 API", description = "답변 댓글 API입니다.")
@RestController
@RequiredArgsConstructor
@RequestMapping("/answerComments")
public class AnswerCommentController {

private final AnswerCommentService answerCommentService;

@Operation(summary = "답변 댓글 생성 API", description = " 답변 댓글 생성 API 입니다. pathvariable로 answerId를 주세요.")
@PostMapping("/answer/{answerId}")
public BaseResponse<AnswerCommentId> createAnswerComment(@AuthMember Member member, @PathVariable(value = "answerId") Long answerId, @RequestBody @Valid AnswerCommentRequest request) {
return BaseResponse.onSuccess(answerCommentService.createAnswerComment(member, answerId, request));
}

@Operation(summary = "답변 댓글 삭제 API", description = " 답변 댓글 삭제 API 입니다. pathvariable 으로 commentId를 주세요.")
@DeleteMapping("/{commentId}")
public BaseResponse<AnswerCommentId> deleteAnswerComment(@AuthMember Member member, @PathVariable(value = "commentId") Long commentId) {
return BaseResponse.onSuccess(answerCommentService.deleteAnswerComment(member, commentId));
}

@Operation(summary = "답변 댓글 수정 API", description = " 답변 댓글 수정 API 입니다. pathvariable 으로 commentId를 주세요.")
@PatchMapping("/{commentId}")
public BaseResponse<AnswerCommentId> updateAnswerComment(@AuthMember Member member, @PathVariable(value = "commentId") Long commentId, @RequestBody @Valid AnswerCommentRequest request) {
return BaseResponse.onSuccess(answerCommentService.updateAnswerComment(member, commentId, request));
}

@Operation(summary = "답변 댓글 좋아요/취소 토글 API", description = " 답변 댓글 좋아요/취소 토글 API 입니다. pathvariable 으로 commentId를 주세요.")
@PatchMapping("/heart/{commentId}")
public BaseResponse<AnswerCommentHeart> heartAnswerComment(@AuthMember Member member, @PathVariable(value = "commentId") Long commentId) {
return BaseResponse.onSuccess(answerCommentService.heartAnswerComment(member, commentId));
}

@Operation(summary = "답변에 대한 댓글 조회 API", description = " 답변에 대한 댓글 조회 API 입니다. pathvariable 으로 answerId를 주세요.")
@GetMapping("/{answerId}")
public BaseResponse<AnswerCommentInfos> getAnswerCommentInfos(@PathVariable(value = "answerId") Long answerId) {
return BaseResponse.onSuccess(answerCommentService.getAnswerCommentInfos(answerId));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.server.capple.domain.answerComment.dto;

import jakarta.validation.constraints.NotEmpty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AnswerCommentRequest {

@NotEmpty
private String answerComment;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.server.capple.domain.answerComment.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;

import java.time.LocalDateTime;
import java.util.List;

public class AnswerCommentResponse {
@Getter
@AllArgsConstructor
public static class AnswerCommentId {
private Long answerCommentId;
}

@Getter
@AllArgsConstructor
public static class AnswerCommentHeart {
private Long answerCommentId;
private Boolean isLiked;
}

@Getter
@Builder
public static class AnswerCommentInfo {
private Long answerCommentId;
private String writer;
private String content;
private Long heartCount;
private LocalDateTime createdAt;

}

@Getter
@AllArgsConstructor
public static class AnswerCommentInfos {
private List<AnswerCommentInfo> answerCommentInfos;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.server.capple.domain.answerComment.entity;

import com.server.capple.domain.answer.entity.Answer;
import com.server.capple.domain.member.entity.Member;
import com.server.capple.global.common.BaseEntity;
import jakarta.persistence.*;
import lombok.*;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.SQLRestriction;

@Getter
@Builder
@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@SQLRestriction("deleted_at is null")
@DynamicInsert
public class AnswerComment extends BaseEntity {

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

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

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "answer_id", nullable = false)
private Answer answer;

@Column(nullable = false)
private String content;

public void update(String content) {
this.content = content;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.server.capple.domain.answerComment.mapper;

import com.server.capple.domain.answer.entity.Answer;
import com.server.capple.domain.answerComment.dto.AnswerCommentResponse.*;
import com.server.capple.domain.answerComment.entity.AnswerComment;
import com.server.capple.domain.member.entity.Member;
import org.springframework.stereotype.Component;


@Component
public class AnswerCommentMapper {
public AnswerComment toAnswerCommentEntity(Member member, Answer answer, String answerComment) {
return AnswerComment.builder()
.member(member)
.answer(answer)
.content(answerComment)
.build();
}

public AnswerCommentInfo toAnswerCommentInfo(AnswerComment comment, Long heartCount) {
return AnswerCommentInfo.builder()
.answerCommentId(comment.getId())
.writer(comment.getMember().getNickname())
.content(comment.getContent())
.heartCount(heartCount)
.createdAt(comment.getCreatedAt())
.build();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.server.capple.domain.answerComment.repository;

import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.stereotype.Repository;

import java.io.Serializable;

import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE;

@Repository
@RequiredArgsConstructor
public class AnswerCommentHeartRedisRepository implements Serializable {
public static final String ANSWER_COMMENT_HEART_KEY_PREFIX = "answerCommentHeart-";
public static final String MEMBER_KEY_PREFIX = "member-";

private final RedisTemplate<String, String> redisTemplate;

public Boolean toggleAnswerCommentHeart(Long commentId, Long memberId) {
String key = ANSWER_COMMENT_HEART_KEY_PREFIX + commentId.toString();
String member = MEMBER_KEY_PREFIX + memberId.toString();

SetOperations<String, String> setOperations = redisTemplate.opsForSet();

// 유저가 좋아요를 눌렀는지 확인
Boolean isLiked = setOperations.isMember(key, member);

// 좋아요 취소
if (FALSE.equals(isLiked)) {
setOperations.add(key, member);
return TRUE;
} else {
setOperations.remove(key, member);
return FALSE;
}
}

public Long getAnswerCommentHeartsCount(Long commentId) {
String key = ANSWER_COMMENT_HEART_KEY_PREFIX + commentId.toString();
return redisTemplate.opsForSet().size(key);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.server.capple.domain.answerComment.repository;

import com.server.capple.domain.answerComment.entity.AnswerComment;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import java.util.List;

public interface AnswerCommentRepository extends JpaRepository<AnswerComment, Long> {
@Query("SELECT a FROM AnswerComment a WHERE a.answer.id = :answerId ORDER BY a.createdAt")
List<AnswerComment> findAnswerCommentByAnswerId(Long answerId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.server.capple.domain.answerComment.service;

import com.server.capple.domain.answerComment.dto.AnswerCommentRequest;
import com.server.capple.domain.answerComment.dto.AnswerCommentResponse.*;
import com.server.capple.domain.answerComment.entity.AnswerComment;
import com.server.capple.domain.member.entity.Member;

public interface AnswerCommentService {
AnswerComment findAnswerComment(Long answerCommentId);
AnswerCommentId createAnswerComment(Member member, Long answerId, AnswerCommentRequest request);
AnswerCommentId deleteAnswerComment(Member member, Long commentId);
AnswerCommentId updateAnswerComment(Member member, Long commentId, AnswerCommentRequest request);
AnswerCommentHeart heartAnswerComment(Member member, Long commentId);
AnswerCommentInfos getAnswerCommentInfos(Long answerId);
}
Loading

0 comments on commit 5ce4f11

Please sign in to comment.