Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
be08c8f
feat: 로그인유저 isAdmin 쿠키로 응답
yu-so-young2 Nov 18, 2024
dabe76c
Merge pull request #132 from dreamyPatisiel/DP-431
ssosee Nov 20, 2024
c7359f1
feat: 기술블로그 추천/추천취소 기능
yu-so-young2 Dec 23, 2024
f1847a3
feat: 비회원 기술블로그 추천/추천취소 기능 추가
yu-so-young2 Dec 23, 2024
b5502b8
test: 회원/비회원 기술블로그 추천 API 테스트코드
yu-so-young2 Dec 24, 2024
50dc79c
feat(CommentMapper): findByMemberIdAndPickCommentIdAndTechCommentIdOr…
ssosee Dec 29, 2024
67d2c39
test: 회원/비회원 기술블로그 추천 API 테스트코드
yu-so-young2 Dec 29, 2024
15e63d9
fix: 일반회원 픽픽픽 작성시 자동 승인
yu-so-young2 Dec 30, 2024
f8d2da8
feat(CommentRepository): findMyWrittenCommentsByCursor(..)
ssosee Dec 31, 2024
95ab0b1
feat(MemberService): findMyWrittenComments(..)
ssosee Jan 1, 2025
7d79068
Merge pull request #134 from dreamyPatisiel/DP-452
ssosee Jan 1, 2025
bb009ed
fix: 코드리뷰 반영
yu-so-young2 Jan 1, 2025
d499d8b
feat(MypageController): getMyWrittenComments(..)
ssosee Jan 2, 2025
5be4a1a
Merge pull request #133 from dreamyPatisiel/DP-447
ssosee Jan 3, 2025
05d6087
fix: GA 값 없을 경우 대응
yu-so-young2 Jan 5, 2025
ff78970
Merge pull request #136 from dreamyPatisiel/DP-447
ssosee Jan 5, 2025
357c5f0
feat(MypageController): getMyWrittenComments(..)
ssosee Jan 5, 2025
aa0a029
Merge branch 'develop' into DP-449
ssosee Jan 6, 2025
1cfc706
fix(MemberServiceTest): BookmarkRepository 패키징 변경
ssosee Jan 8, 2025
7673017
fix(build.yml): build 시 로그 레벨 수정
ssosee Jan 9, 2025
704f8b7
fix(MemberServiceTest): 시간 nano sec 설정
ssosee Jan 9, 2025
5c4c97c
fix(MemberServiceTest): 시간 필드 검증 제외
ssosee Jan 9, 2025
1325e4c
fix(MemberServiceTest): 시간 필드 검증 제외
ssosee Jan 9, 2025
c4f6273
fix(PR 반영):
ssosee Jan 12, 2025
68407e4
Merge pull request #137 from dreamyPatisiel/DP-449
yu-so-young2 Jan 12, 2025
0ff7f21
bugfix: 회원/익명회원의 추천 여부 조회 메서드 -> 해당 추천의 추천자가 회원/익명회원인지 필터링하는 로직 추가
yu-so-young2 Jan 12, 2025
afe69bc
Merge pull request #138 from dreamyPatisiel/DP-464
ssosee Jan 12, 2025
fcea8cb
hotfix(application-dev.yml): application-dev.yml mybatis 설정 추가
ralph-teuida Jan 15, 2025
089f80d
fix: 기술블로그 추천 API 응답에 총 추천수 추가
yu-so-young2 Jan 18, 2025
b63c6af
Merge pull request #139 from dreamyPatisiel/DP-471
ssosee Jan 19, 2025
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
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ jobs:
run: chmod +x ./gradlew

- name: Build and Test with Gradle
run: ./gradlew bootJar -Pprofile=dev
run: ./gradlew bootJar -Pprofile=dev --info



3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ dependencies {
implementation 'org.opensearch.client:spring-data-opensearch:1.3.0'
implementation 'org.opensearch.client:opensearch-java:2.9.1'

// mybatis
implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.4'

compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.h2database:h2'
runtimeOnly 'org.mariadb.jdbc:mariadb-java-client'
Expand Down
37 changes: 37 additions & 0 deletions src/docs/asciidoc/api/mypage/comment-get.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
[[Comment-Get]]
== 내가 썼어요 댓글/답글 조회 API(GET: /devdevdev/api/v1/mypage/comments)

* 회원이 작성한 댓글/답글을 조회한다.
* 최초 요청시 pickCommentId, techCommentId 는 가장 큰 숫자 값을 요청해야 합니다.

=== 정상 요청/응답

==== HTTP Request

include::{snippets}/mypage-comments/http-request.adoc[]

==== HTTP Request Header Fields

include::{snippets}/mypage-comments/request-headers.adoc[]

==== HTTP Request Query Parameters Fields

include::{snippets}/mypage-comments/query-parameters.adoc[]

==== HTTP Response

include::{snippets}/mypage-comments/http-response.adoc[]

==== HTTP Response Fields

include::{snippets}/mypage-comments/response-fields.adoc[]

=== 예외

==== HTTP Response

* `익명 회원은 사용할 수 없는 기능 입니다.`: 익명 회원인 경우
* `회원을 찾을 수 없습니다.`: 회원이 존재하지 않는 경우
* `유효하지 않은 회원 입니다.`: 회원이 유효하지 않은 경우

include::{snippets}/mypage-comments-member-exception/response-body.adoc[]
1 change: 1 addition & 0 deletions src/docs/asciidoc/api/mypage/mypage.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ include::mypick-main.adoc[]
include::exit-member.adoc[]
include::exit-survey.adoc[]
include::record-exit-survey.adoc[]
include::comment-get.adoc[]
22 changes: 22 additions & 0 deletions src/docs/asciidoc/api/tech-article/recommend.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[[TechArticleRecommend]]
== 기술블로그 추천 API(POST: /devdevdev/api/v1/articles/{techArticleId}/recommend)
* 회원과 익명회원은 기술블로그를 추천하거나 추천 취소할 수 있다.

=== 정상 요청/응답
==== HTTP Request
include::{snippets}/tech-article-recommend/http-request.adoc[]
==== HTTP Request Header Fields
include::{snippets}/tech-article-recommend/request-headers.adoc[]
==== HTTP Request Path Parameters Fields
include::{snippets}/tech-article-recommend/path-parameters.adoc[]

==== HTTP Response
include::{snippets}/tech-article-recommend/http-response.adoc[]
==== HTTP Response Fields
include::{snippets}/tech-article-recommend/response-fields.adoc[]


=== 예외
==== HTTP Response
include::{snippets}/not-found-tech-article-exception/response-body.adoc[]
include::{snippets}/not-found-member-exception/response-body.adoc[]
1 change: 1 addition & 0 deletions src/docs/asciidoc/api/tech-article/tech-article.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ include::main.adoc[]
include::detail.adoc[]
include::bookmark.adoc[]
include::keyword.adoc[]
include::recommend.adoc[]
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import com.dreamypatisiel.devdevdev.domain.entity.enums.WordType;
import com.dreamypatisiel.devdevdev.domain.policy.PickPopularScorePolicy;
import com.dreamypatisiel.devdevdev.domain.repository.BlameTypeRepository;
import com.dreamypatisiel.devdevdev.domain.repository.BookmarkRepository;
import com.dreamypatisiel.devdevdev.domain.repository.techArticle.BookmarkRepository;
import com.dreamypatisiel.devdevdev.domain.repository.CompanyRepository;
import com.dreamypatisiel.devdevdev.domain.repository.member.MemberRepository;
import com.dreamypatisiel.devdevdev.domain.repository.member.memberNicknameDictionary.MemberNicknameDictionaryRepository;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public class Pick extends BasicTime {
private List<String> embeddings;

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

@OneToMany(mappedBy = "pick")
Expand Down Expand Up @@ -125,12 +125,13 @@ public static Pick create(Title title, String author, Member member) {
pick.popularScore = Count.defaultCount();
pick.blameTotalCount = Count.defaultCount();
pick.author = author;
pick.contentStatus = getDefaultContentStatusByMemberRole(member);
pick.contentStatus = ContentStatus.APPROVAL;
pick.member = member;

return pick;
}

@Deprecated // 신고 기능 추가로 인한 삭제
private static ContentStatus getDefaultContentStatusByMemberRole(Member member) {
if (member.isAdmin()) {
return ContentStatus.APPROVAL;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.dreamypatisiel.devdevdev.domain.entity;

import com.dreamypatisiel.devdevdev.domain.entity.embedded.Count;
import com.dreamypatisiel.devdevdev.domain.entity.embedded.Title;
import com.dreamypatisiel.devdevdev.domain.entity.embedded.Url;
import com.dreamypatisiel.devdevdev.domain.policy.TechArticlePopularScorePolicy;
import com.dreamypatisiel.devdevdev.elastic.domain.document.ElasticTechArticle;
Expand Down Expand Up @@ -35,6 +36,8 @@ public class TechArticle extends BasicTime {
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private Title title;

@Embedded
@AttributeOverride(name = "count",
column = @Column(name = "view_total_count")
Expand Down Expand Up @@ -75,9 +78,14 @@ public class TechArticle extends BasicTime {
@OneToMany(mappedBy = "techArticle")
private List<Bookmark> bookmarks = new ArrayList<>();

@OneToMany(mappedBy = "techArticle")
private List<TechArticleRecommend> recommends = new ArrayList<>();

@Builder
private TechArticle(Count viewTotalCount, Count recommendTotalCount, Count commentTotalCount, Count popularScore,
private TechArticle(Title title, Count viewTotalCount, Count recommendTotalCount, Count commentTotalCount,
Count popularScore,
Url techArticleUrl, Company company, String elasticId) {
this.title = title;
this.techArticleUrl = techArticleUrl;
this.viewTotalCount = viewTotalCount;
this.recommendTotalCount = recommendTotalCount;
Expand All @@ -89,6 +97,7 @@ private TechArticle(Count viewTotalCount, Count recommendTotalCount, Count comme

public static TechArticle createTechArticle(ElasticTechArticle elasticTechArticle, Company company) {
TechArticle techArticle = TechArticle.builder()
.title(new Title(elasticTechArticle.getTitle()))
.techArticleUrl(new Url(elasticTechArticle.getTechArticleUrl()))
.viewTotalCount(new Count(elasticTechArticle.getViewTotalCount()))
.recommendTotalCount(new Count(elasticTechArticle.getRecommendTotalCount()))
Expand All @@ -102,10 +111,11 @@ public static TechArticle createTechArticle(ElasticTechArticle elasticTechArticl
return techArticle;
}

public static TechArticle createTechArticle(Url techArticleUrl, Count viewTotalCount, Count recommendTotalCount,
Count commentTotalCount,
Count popularScore, String elasticId, Company company) {
public static TechArticle createTechArticle(Title title, Url techArticleUrl, Count viewTotalCount,
Count recommendTotalCount, Count commentTotalCount, Count popularScore,
String elasticId, Company company) {
return TechArticle.builder()
.title(title)
.techArticleUrl(techArticleUrl)
.viewTotalCount(viewTotalCount)
.recommendTotalCount(recommendTotalCount)
Expand All @@ -127,6 +137,10 @@ public void changePopularScore(TechArticlePopularScorePolicy policy) {
this.popularScore = this.calculatePopularScore(policy);
}

private Count calculatePopularScore(TechArticlePopularScorePolicy policy) {
return policy.calculatePopularScore(this);
}

public void changeCompany(Company company) {
company.getTechArticles().add(this);
this.company = company;
Expand All @@ -136,15 +150,20 @@ public void incrementViewTotalCount() {
this.viewTotalCount = Count.plusOne(this.viewTotalCount);
}

private Count calculatePopularScore(TechArticlePopularScorePolicy policy) {
return policy.calculatePopularScore(this);
}

public void incrementCommentCount() {
this.commentTotalCount = Count.plusOne(this.commentTotalCount);
}

public void decrementCommentCount() {
this.commentTotalCount = Count.minusOne(this.commentTotalCount);
}


public void incrementRecommendTotalCount() {
this.recommendTotalCount = Count.plusOne(this.recommendTotalCount);
}

public void decrementRecommendTotalCount() {
this.recommendTotalCount = Count.minusOne(this.recommendTotalCount);
}
}
Original file line number Diff line number Diff line change
@@ -1,27 +1,81 @@
package com.dreamypatisiel.devdevdev.domain.entity;

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.*;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class TechArticleRecommend extends BasicTime {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(nullable = false)
private boolean status;

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

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "anonymous_member_id")
private AnonymousMember anonymousMember;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "tech_article_id", nullable = false)
private TechArticle techArticle;

@Builder
private TechArticleRecommend(boolean status, Member member, AnonymousMember anonymousMember, TechArticle techArticle) {
this.status = status;
this.member = member;
this.anonymousMember = anonymousMember;
this.techArticle = techArticle;
}


public static TechArticleRecommend create(Member member, TechArticle techArticle) {
return TechArticleRecommend.builder()
.member(member)
.techArticle(techArticle)
.status(true)
.build();
}

public static TechArticleRecommend create(AnonymousMember anonymousMember, TechArticle techArticle) {
return TechArticleRecommend.builder()
.anonymousMember(anonymousMember)
.techArticle(techArticle)
.status(true)
.build();
}

public void changeTechArticle(TechArticle techArticle) {
this.techArticle = techArticle;
techArticle.getRecommends().add(this);
}

public void cancelRecommend() {
this.status = false;
}

public void registerRecommend() {
this.status = true;
}

public boolean isRecommended() {
return this.status;
}

public boolean isAnonymousMemberNotNull() {
return this.anonymousMember != null;
}
public boolean isMemberNotNull() {
return this.member != null;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.dreamypatisiel.devdevdev.domain.repository.comment;

import com.dreamypatisiel.devdevdev.domain.repository.comment.mybatis.CommentMapper;
import com.dreamypatisiel.devdevdev.domain.repository.pick.PickCommentRepository;
import com.dreamypatisiel.devdevdev.domain.repository.techArticle.TechCommentRepository;
import com.dreamypatisiel.devdevdev.web.dto.SliceCustom;
import com.dreamypatisiel.devdevdev.web.dto.request.comment.MyWrittenCommentFilter;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Repository;

@Repository
@RequiredArgsConstructor
public class CommentRepository {

private final CommentMapper commentMapper;
private final PickCommentRepository pickCommentRepository;
private final TechCommentRepository techCommentRepository;

public SliceCustom<MyWrittenCommentDto> findMyWrittenCommentsByCursor(Long memberId,
Long pickCommentId,
Long techCommentId,
MyWrittenCommentFilter myWrittenCommentSort,
Pageable pageable) {

// 픽픽픽
if (MyWrittenCommentFilter.PICK.equals(myWrittenCommentSort)) {
return pickCommentRepository.findMyWrittenPickCommentsByCursor(memberId, pickCommentId, pageable);
}

// 기술블로그
if (MyWrittenCommentFilter.TECH_ARTICLE.equals(myWrittenCommentSort)) {
return techCommentRepository.findMyWrittenTechCommentsByCursor(memberId, techCommentId, pageable);
}

// 전체
// 회원이 작성한 픽픽픽, 기술블로그 댓글 조회
List<MyWrittenCommentDto> findMyWrittenComments = commentMapper.findByMemberIdAndPickCommentIdAndTechCommentIdOrderByCommentCreatedAtDesc(
memberId, pickCommentId, techCommentId, pageable.getPageSize());

// 다음 페이지 존재 여부
boolean hasNext = findMyWrittenComments.size() >= pageable.getPageSize();

// 회원이 작성한 댓글 총 갯수(삭제 미포함)
Long commentTotalCount = countByCreatedByIdAndDeletedAtIsNull(memberId);

return new SliceCustom<>(findMyWrittenComments, pageable, hasNext, commentTotalCount);
}

private Long countByCreatedByIdAndDeletedAtIsNull(Long createdById) {

// 회원이 작성한 픽픽픽 댓글 갯수(삭제 미포함)
Long pickCommentTotal = pickCommentRepository.countByCreatedByIdAndDeletedAtIsNull(createdById);

// 회원이 작성한 기술블로그 댓글 갯수(삭제 미포함)
Long techCommentTotal = techCommentRepository.countByCreatedByIdAndDeletedAtIsNull(createdById);

return pickCommentTotal + techCommentTotal;
}
}
Loading
Loading