Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import project.flipnote.cardset.model.CardSetDetailResponse;
import project.flipnote.cardset.model.CardSetSearchRequest;
import project.flipnote.cardset.model.CardSetSummaryResponse;
import project.flipnote.cardset.model.CardSetUpdateRequest;
import project.flipnote.cardset.model.CreateCardSetRequest;
import project.flipnote.cardset.model.CreateCardSetResponse;
import project.flipnote.common.model.response.IdResponse;
import project.flipnote.common.model.response.PagingResponse;
import project.flipnote.common.security.dto.AuthPrinciple;

@Tag(name = "CardSet", description = "CardSet API")
Expand All @@ -29,4 +33,10 @@ ResponseEntity<CardSetDetailResponse> updateCardSet(
CardSetUpdateRequest req,
AuthPrinciple authPrinciple
);

@Operation(summary = "그룹별 카드셋 조회", security = {@SecurityRequirement(name = "access-token")})
ResponseEntity<PagingResponse<CardSetSummaryResponse>> getCardSets(Long groupId, CardSetSearchRequest req);

@Operation(summary = "카드셋 삭제", security = {@SecurityRequirement(name = "access-token")})
ResponseEntity<IdResponse> deleteCardSet(Long groupId, Long cardSetId, AuthPrinciple authPrinciple);
}
15 changes: 13 additions & 2 deletions src/main/java/project/flipnote/cardset/entity/CardSet.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ public class CardSet extends BaseEntity {
@Column(nullable = false, length = 50)
private String name;

@Column(nullable = false)
private Long author;

@ManyToOne
@JoinColumn(name = "group_id", nullable = false)
private Group group;
Expand All @@ -48,9 +51,17 @@ public class CardSet extends BaseEntity {
private String imageUrl;

@Builder
private CardSet(String name, Group group, Boolean publicVisible, Category category, String hashtag,
String imageUrl) {
private CardSet(
String name,
Long author,
Group group,
Boolean publicVisible,
Category category,
String hashtag,
String imageUrl
) {
this.name = name;
this.author = author;
this.group = group;
this.publicVisible = publicVisible;
this.category = category;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package project.flipnote.cardset.model;

import java.util.List;

import org.hibernate.validator.constraints.URL;
import java.util.Set;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import project.flipnote.group.entity.Category;
Expand All @@ -25,6 +25,9 @@ public record CardSetUpdateRequest(
@NotNull
List<String> hashtag,

@NotEmpty @Size(min = 1)
Set<Long> managers,

Long imageRefId
) {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package project.flipnote.cardset.model;

import java.util.List;

import org.hibernate.validator.constraints.URL;
import java.util.Set;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import project.flipnote.group.entity.Category;
Expand All @@ -24,6 +24,9 @@ public record CreateCardSetRequest(
@NotNull
List<String> hashtag,

@NotEmpty @Size(min = 1)
Set<Long> managers,

Long imageRefId
) {
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package project.flipnote.cardset.repository;

import java.util.Set;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

import project.flipnote.cardset.entity.CardSetManager;
Expand All @@ -11,4 +14,9 @@ public interface CardSetManagerRepository extends JpaRepository<CardSetManager,
boolean existsByUser_IdAndCardSet_Id(Long userId, Long cardSetId);

int deleteByCardSet_Id(Long cardSetId);

@Query("SELECT cm.user.id FROM CardSetManager cm WHERE cm.cardSet.id = :cardSetId")
Set<Long> findUserIdsByCardSetId(Long cardSetId);

int deleteByCardSet_IdAndUser_IdIn(Long cardSetId, Set<Long> userIds);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package project.flipnote.cardset.service;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.springframework.stereotype.Service;

import lombok.RequiredArgsConstructor;
import project.flipnote.cardset.entity.CardSet;
import project.flipnote.cardset.entity.CardSetManager;
import project.flipnote.cardset.repository.CardSetManagerRepository;
import project.flipnote.user.repository.UserProfileRepository;

@RequiredArgsConstructor
@Service
public class CardSetManagerWriter {

private final CardSetManagerRepository cardSetManagerRepository;
private final UserProfileRepository userProfileRepository;

/**
* 카드셋에 매니저들을 할당
* 카드셋 생성시 생성자는 항상 매니저로 포함됨
*
* @param cardSet 매니저를 할당할 카드셋
* @param managerIds 요청된 매니저 ID 목록
* @author 윤정환
*/
public void assignManagers(CardSet cardSet, Set<Long> managerIds) {
Set<Long> finalManagerIds = includeAuthor(cardSet.getAuthor(), managerIds);

List<CardSetManager> managers = finalManagerIds.stream()
.map(id -> CardSetManager.builder()
.cardSet(cardSet)
.user(userProfileRepository.getReferenceById(id))
.build())
.toList();

cardSetManagerRepository.saveAll(managers);
}

/**
* 카드셋의 매니저를 수정
* 차집합을 이용해 삭제/추가할 매니저만 처리
*
* @param cardSet 매니저를 수정할 카드셋
* @param newManagerIds 새로운 매니저 ID 목록
* @author 윤정환
*/
public void updateManagers(CardSet cardSet, Set<Long> newManagerIds) {
Set<Long> currentManagerIds = cardSetManagerRepository.findUserIdsByCardSetId(cardSet.getId());

Set<Long> toDelete = difference(currentManagerIds, newManagerIds);
Set<Long> toAdd = difference(newManagerIds, currentManagerIds);

Comment on lines +51 to +56
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

업데이트에서도 작성자 강제 포함 필요

현재 updateManagersnewManagerIds에 작성자가 없으면 작성자 매니저가 삭제될 수 있습니다. “작성자는 항상 매니저”라는 규칙을 유지하려면 업데이트에서도 작성자를 포함한 집합으로 diff를 계산해야 합니다.

✅ 수정 제안
 public void updateManagers(CardSet cardSet, Set<Long> newManagerIds) {
-    Set<Long> currentManagerIds = cardSetManagerRepository.findUserIdsByCardSetId(cardSet.getId());
-
-    Set<Long> toDelete = difference(currentManagerIds, newManagerIds);
-    Set<Long> toAdd = difference(newManagerIds, currentManagerIds);
+    Set<Long> finalManagerIds = includeAuthor(cardSet.getAuthor(), newManagerIds);
+    Set<Long> currentManagerIds = cardSetManagerRepository.findUserIdsByCardSetId(cardSet.getId());
+
+    Set<Long> toDelete = difference(currentManagerIds, finalManagerIds);
+    Set<Long> toAdd = difference(finalManagerIds, currentManagerIds);
🤖 Prompt for AI Agents
In `@src/main/java/project/flipnote/cardset/service/CardSetManagerWriter.java`
around lines 51 - 56, updateManagers currently computes diffs directly from
newManagerIds which can remove the card author as a manager; ensure the author
is always included by adding the card's author id to the set used for diffing
before computing toDelete/toAdd. Concretely, obtain the author id from cardSet
(e.g., cardSet.getAuthorId() or cardSet.getAuthor().getId()), create a copy of
newManagerIds that adds that author id (if missing), and then compute
difference(currentManagerIds, adjustedNewManagerIds) and
difference(adjustedNewManagerIds, currentManagerIds) for toDelete and toAdd
respectively in updateManagers.

if (!toDelete.isEmpty()) {
cardSetManagerRepository.deleteByCardSet_IdAndUser_IdIn(cardSet.getId(), toDelete);
}

if (!toAdd.isEmpty()) {
List<CardSetManager> managers = toAdd.stream()
.map(id -> CardSetManager.builder()
.cardSet(cardSet)
.user(userProfileRepository.getReferenceById(id))
.build())
.toList();
cardSetManagerRepository.saveAll(managers);
}
}

private Set<Long> includeAuthor(Long authorId, Set<Long> managerIds) {
Set<Long> result = new HashSet<>(managerIds);
result.add(authorId);
return result;
}

private Set<Long> difference(Set<Long> a, Set<Long> b) {
Set<Long> result = new HashSet<>(a);
result.removeAll(b);
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import project.flipnote.bookmark.service.BookmarkReader;
import project.flipnote.bookmark.service.BookmarkWriter;
import project.flipnote.cardset.entity.CardSet;
import project.flipnote.cardset.entity.CardSetManager;
import project.flipnote.cardset.entity.CardSetMetadata;
import project.flipnote.cardset.exception.CardSetErrorCode;
import project.flipnote.cardset.model.CardSetDetailResponse;
Expand Down Expand Up @@ -64,6 +63,7 @@ public class CardSetService {
private final GroupRepository groupRepository;
private final GroupMemberRepository groupMemberRepository;
private final CardSetManagerRepository cardSetManagerRepository;
private final CardSetManagerWriter cardSetManagerWriter;
private final CardSetPolicyService cardSetPolicyService;
private final CardSetMetadataRepository cardSetMetadataRepository;
private final ImageService imageService;
Expand Down Expand Up @@ -121,6 +121,7 @@ public CreateCardSetResponse createCardSet(Long groupId, AuthPrinciple authPrinc

CardSet cardSet = CardSet.builder()
.name(req.name())
.author(user.getId())
.group(group)
.publicVisible(req.publicVisible())
.category(req.category())
Expand All @@ -140,13 +141,7 @@ public CreateCardSetResponse createCardSet(Long groupId, AuthPrinciple authPrinc
.build();
cardSetMetadataRepository.save(metadata);

//카드셋 매니저도 저장
CardSetManager cardSetManager = CardSetManager.builder()
.user(user)
.cardSet(cardSet)
.build();

cardSetManagerRepository.save(cardSetManager);
cardSetManagerWriter.assignManagers(cardSet, req.managers());

return CreateCardSetResponse.from(cardSet.getId());
}
Expand Down Expand Up @@ -216,6 +211,8 @@ public CardSetDetailResponse updateCardSet(Long userId, Long groupId, Long cardS

cardSetRepository.saveAndFlush(cardSet);

cardSetManagerWriter.updateManagers(cardSet, req.managers());

boolean liked = likeReader.isLiked(userId, LikeTargetType.CARD_SET, cardSetId);
boolean bookmarked = bookmarkReader.isBookmarked(userId, BookmarkTargetType.CARD_SET, cardSetId);

Expand Down
Loading