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
403 changes: 403 additions & 0 deletions hs_err_pid12404.log

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -25,24 +25,29 @@ public class CardController {
private final CardService cardService;

@PostMapping
public CardCreateResponse createCard(@RequestBody CardCreateRequest request) {
return cardService.createCard(request);
public CardCreateResponse createCard(
@RequestHeader("x-auth-sub") UUID userId,
@RequestBody CardCreateRequest request) {
return cardService.createCard(userId, request);
}

@GetMapping("/{cardId}")
public CardCreateResponse getCardDetails(@PathVariable UUID cardId) {
return cardService.getCardDetails(cardId);
public CardCreateResponse getCardDetails(
@RequestHeader("x-auty-sub") UUID userId,
@PathVariable UUID cardId) {
return cardService.getCardDetails(userId, cardId);
}

@GetMapping("/by-space")
public List<CardCreateResponse> getCardsBySpace(
@RequestHeader("x-auth-sub") UUID userId,
@RequestParam UUID spaceId,
@RequestParam(defaultValue = "10") int count,
@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "createdAt") String sortBy) {

try {
return cardService.getCardsBySpace(spaceId, count, page, sortBy);
return cardService.getCardsBySpace(userId, spaceId, count, page, sortBy);
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("400 Bad Request: " + e.getMessage());
} catch (EntityNotFoundException e) {
Expand All @@ -64,14 +69,17 @@ public ResponseEntity<List<Card>> getCardlinkedCards(

@PatchMapping("/{cardId}")
public CardResponse updateCard(
@RequestHeader("x-auth-sub") UUID userId,
@PathVariable UUID cardId,
@RequestBody CardUpdateRequest request) {
return cardService.updateCard(cardId, request);
return cardService.updateCard(userId, cardId, request);
}

@DeleteMapping("/{cardId}")
public ResponseEntity<Void> deleteCard(@PathVariable UUID cardId) {
cardService.deleteCard(cardId);
public ResponseEntity<Void> deleteCard(
@RequestHeader("x-auth-sub") UUID userId,
@PathVariable UUID cardId) {
cardService.deleteCard(userId, cardId);
return ResponseEntity.ok().build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,21 @@ public class CardlinkController {

@PostMapping
public ResponseEntity<CardlinkResponse> createCardlink(
@RequestHeader("x-auth-sub") UUID userId,
@PathVariable UUID cardId,
@RequestBody CardlinkCreateRequest request
) {
CardlinkResponse response = cardlinkService.createCardlink(cardId, request);
CardlinkResponse response = cardlinkService.createCardlink(userId, cardId, request);
return ResponseEntity.status(HttpStatus.CREATED).body(response);
}

@DeleteMapping("/{cardlinkId}")
public ResponseEntity<Void> deleteCardlink(
@RequestHeader("x-auth-sub") UUID userId,
@PathVariable UUID cardId,
@PathVariable UUID cardlinkId) {

cardlinkService.deleteCardlink(cardId, cardlinkId);
cardlinkService.deleteCardlink(userId, cardId, cardlinkId);
return ResponseEntity.ok().build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,26 @@ public class CardService {
private final CardlinkRepository cardlinkRepository;
private final UUIDHelper uuidHelper;

//지식카드 생성
public CardCreateResponse createCard(CardCreateRequest request) {
// 권한 체크: userId가 해당 spaceId에 접근 가능한지 검사
private void validateUserAccessToSpace(UUID userId, byte[] spaceId) {
boolean exists = spaceRepository.existsBySpaceIdAndUserId(spaceId, uuidHelper.convertUUIDToByteArray(userId));
if (!exists) {
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "User does not have access to the specified space");
}
}

// cardId로 카드 조회 후 권한 체크 포함 반환
private Card getCardWithAccessCheck(UUID userId, UUID cardId) {
Card card = cardRepository.findByCardId(uuidHelper.convertUUIDToByteArray(cardId))
.orElseThrow(() -> new ResponseStatusException(NOT_FOUND, "Card not found"));
validateUserAccessToSpace(userId, card.getSpaceId());
return card;
}

//새 지식카드 생성 - 사용자가 직접 생성
public CardCreateResponse createCard(UUID userId, CardCreateRequest request) {

validateUserAccessToSpace(userId, uuidHelper.convertUUIDToByteArray(request.getSpaceId()));

// 한국 시간으로 LocalDateTime 생성
LocalDateTime nowInKorea = ZonedDateTime.now(ZoneId.of("Asia/Seoul")).toLocalDateTime();
Expand Down Expand Up @@ -71,9 +89,8 @@ public CardCreateResponse createCard(CardCreateRequest request) {

//지식카드 세부정보 조회
@Transactional(readOnly = true)
public CardCreateResponse getCardDetails(UUID cardId) {
Card card = cardRepository.findByCardId(uuidHelper.convertUUIDToByteArray(cardId))
.orElseThrow(() -> new IllegalArgumentException("Card not found"));
public CardCreateResponse getCardDetails(UUID userId, UUID cardId) {
Card card = getCardWithAccessCheck(userId, cardId);


List<CardlinkResponse> cardlinkDtos = cardlinkRepository.findByCard_CardId(uuidHelper.convertUUIDToByteArray(cardId)).stream()
Expand All @@ -100,11 +117,13 @@ public CardCreateResponse getCardDetails(UUID cardId) {

//특정 스페이스의 지식카드 목록 조회
@Transactional(readOnly = true)
public List<CardCreateResponse> getCardsBySpace(UUID spaceId, int count, int page, String sortBy) {
public List<CardCreateResponse> getCardsBySpace(UUID userId, UUID spaceId, int count, int page, String sortBy) {
if (!"createdAt".equals(sortBy)) {
throw new IllegalArgumentException("400 Bad Request: Invalid sortBy value");
}

validateUserAccessToSpace(userId, uuidHelper.convertUUIDToByteArray(spaceId));

Pageable pageable = PageRequest.of(page - 1, count, Sort.by(Sort.Direction.DESC, "createdAt"));
Page<Card> cardPage = cardRepository.findBySpaceId(uuidHelper.convertUUIDToByteArray(spaceId), pageable);

Expand Down Expand Up @@ -188,12 +207,11 @@ public List<CardshareResponse> getSharedCards(UUID sharingId, int count, int pag

}

//지식카드 정보 수정
//지식카드 수정(제목)
@Transactional
public CardResponse updateCard(UUID cardId, CardUpdateRequest request) {
public CardResponse updateCard(UUID userId, UUID cardId, CardUpdateRequest request) {

Card card = cardRepository.findByCardId(uuidHelper.convertUUIDToByteArray(cardId))
.orElseThrow(() -> new ResponseStatusException(NOT_FOUND, "Card not found"));
Card card = getCardWithAccessCheck(userId, cardId);

// null이 아닌 값만 업데이트
if (request.getTitle() != null) {
Expand Down Expand Up @@ -235,12 +253,11 @@ public CardResponse updateCard(UUID cardId, CardUpdateRequest request) {

//지식카드 삭제
@Transactional
public void deleteCard(UUID cardId) {
boolean exists = cardRepository.existsById(uuidHelper.convertUUIDToByteArray(cardId));
if (!exists) {
throw new ResponseStatusException(NOT_FOUND, "Card not found");
}
cardRepository.deleteByCardId(uuidHelper.convertUUIDToByteArray(cardId));
public void deleteCard(UUID userId, UUID cardId) {

Card card = getCardWithAccessCheck(userId, cardId);

cardRepository.deleteByCardId(card.getCardId());
}

//오늘 생성된 지식카드 목록 조회
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@
import com.example.gp_backend_data.card.domain.entity.Card;
import com.example.gp_backend_data.card.repository.CardlinkRepository;
import com.example.gp_backend_data.card.repository.CardRepository;
import com.example.gp_backend_data.space.domain.entity.Space;
import com.example.gp_backend_data.space.repository.SpaceRepository;
import com.example.gp_backend_data.utils.UUIDHelper;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.server.ResponseStatusException;

import java.util.Arrays;
import java.util.UUID;

@Service
Expand All @@ -22,13 +25,22 @@ public class CardlinkService {
private final CardRepository cardRepository;
private final CardlinkRepository cardlinkRepository;
private final UUIDHelper uuidHelper;
private final SpaceRepository spaceRepository;

//지식카드 내 새 지식링크 생성
public CardlinkResponse createCardlink(UUID cardId, CardlinkCreateRequest request) {
//새 지식링크 생성 (지식카드 내) - 사용자가 직접 추가 생성
public CardlinkResponse createCardlink(UUID userId, UUID cardId, CardlinkCreateRequest request) {
byte[] cardIdBytes = uuidHelper.convertUUIDToByteArray(cardId);
Card card = cardRepository.findById(cardIdBytes)
Card card = cardRepository.findByCardId(cardIdBytes)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Card not found"));

// 권한 체크: card가 속한 space 조회 후 userId와 일치하는지 확인
Space space = spaceRepository.findById(card.getSpaceId())
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Space not found"));

if (!Arrays.equals(uuidHelper.convertUUIDToByteArray(userId), space.getUserId())) {
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "User not authorized for this space");
}

Cardlink cardlink = new Cardlink();
cardlink.setCard(card);
cardlink.setCardlinkId(uuidHelper.generateUUIDBytes());
Expand All @@ -46,13 +58,21 @@ public CardlinkResponse createCardlink(UUID cardId, CardlinkCreateRequest reques
.build();
}

//지식카드 내 지식링크 삭제
//지식링크 삭제 (지식카드 내)
@Transactional
public void deleteCardlink(UUID cardId, UUID cardlinkId) {
public void deleteCardlink(UUID userId, UUID cardId, UUID cardlinkId) {
//하이라이트 존재 여부 확인
Cardlink cardlink = cardlinkRepository.findByCardlinkIdAndCard_CardId(uuidHelper.convertUUIDToByteArray(cardlinkId), uuidHelper.convertUUIDToByteArray(cardId))
Cardlink cardlink = cardlinkRepository.findByCardlinkIdAndCard_CardId(
uuidHelper.convertUUIDToByteArray(cardlinkId), uuidHelper.convertUUIDToByteArray(cardId))
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Cardlink not found"));

Space space = spaceRepository.findById(cardlink.getCard().getSpaceId())
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Space not found"));

if (!Arrays.equals(uuidHelper.convertUUIDToByteArray(userId), space.getUserId())) {
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "User not authorized for this space");
}

cardlinkRepository.delete(cardlink);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,28 @@ public class GraphController {
private final GraphService graphService;

@GetMapping
public ResponseEntity<GraphResponse> getGraph(@RequestParam UUID spaceId) {
GraphResponse response = graphService.getGraphBySpaceId(spaceId);
public ResponseEntity<GraphResponse> getGraph(
@RequestHeader("x-auth-sub") UUID userId,
@RequestParam UUID spaceId) {
GraphResponse response = graphService.getGraphBySpaceId(userId, spaceId);
return ResponseEntity.ok(response);
}

@GetMapping("/{graphId}")
public ResponseEntity<GraphResponse> getGraphs(@PathVariable UUID graphId) {
GraphResponse response = graphService.getGraphById(graphId);
public ResponseEntity<GraphResponse> getGraphs(
@RequestHeader("x-auth-sub") UUID userId,
@PathVariable UUID graphId) {
GraphResponse response = graphService.getGraphById(userId, graphId);
return ResponseEntity.ok(response);
}

@PatchMapping("/{graphId}")
public ResponseEntity<GraphResponse> updateGraph(
@RequestHeader("x-auth-sub") UUID userId,
@PathVariable UUID graphId,
@RequestBody GraphRequest request) {

GraphResponse response = graphService.updateGraph(graphId, request);
GraphResponse response = graphService.updateGraph(userId, graphId, request);
return ResponseEntity.ok(response);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@
import jakarta.persistence.EntityNotFoundException;
import lombok.RequiredArgsConstructor;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.server.ResponseStatusException;

import java.util.Optional;
import java.util.UUID;
Expand All @@ -29,8 +31,14 @@ public class GraphService {

//특정 스페이스의 그래프 조회
@Transactional
public GraphResponse getGraphBySpaceId(UUID spaceId) {
byte[] spaceIdBytes = uuidHelper.convertUUIDToByteArray(spaceId);
public GraphResponse getGraphBySpaceId(UUID userId, UUID spaceId) {

Space space = spaceRepository.findBySpaceIdAndUserId(
uuidHelper.convertUUIDToByteArray(spaceId),
uuidHelper.convertUUIDToByteArray(userId) //유저 권한 체크 추가
).orElseThrow(() -> new ResponseStatusException(HttpStatus.FORBIDDEN, "You do not have access to this space"));

byte[] spaceIdBytes = space.getSpaceId();

Graph graph = graphRepository.findBySpaceId(spaceIdBytes)
.orElseGet(() -> createNewGraphForSpace(spaceIdBytes));
Expand Down Expand Up @@ -87,37 +95,52 @@ private Graph createNewGraphForSpace(byte[] spaceIdBytes) {


//그래프 세부 정보 조회
public GraphResponse getGraphById(UUID graphId) {
Optional<Graph> graphOptional = graphRepository.findByGraphId(uuidHelper.convertUUIDToByteArray(graphId));

return graphOptional.map(graph -> {
try {
return new GraphResponse(
uuidHelper.convertByteArrayToUUID(graph.getGraphId()),
uuidHelper.convertByteArrayToUUID(graph.getSpaceId()),
objectMapper.readTree(graph.getData())
);
} catch (Exception e) {
throw new RuntimeException("Error parsing graph data", e);
}
}).orElseThrow(() -> new IllegalArgumentException("Graph not found for graphId: " + graphId));
public GraphResponse getGraphById(UUID userId, UUID graphId) {
Graph graph = graphRepository.findByGraphId(uuidHelper.convertUUIDToByteArray(graphId))
.orElseThrow(() -> new IllegalArgumentException("Graph not found for graphId: " + graphId));

// 해당 그래프가 속한 스페이스가 본인 소유인지 확인
Space space = spaceRepository.findBySpaceIdAndUserId(
graph.getSpaceId(),
uuidHelper.convertUUIDToByteArray(userId)
).orElseThrow(() -> new ResponseStatusException(HttpStatus.FORBIDDEN, "You do not have access to this graph"));

try {
return new GraphResponse(
uuidHelper.convertByteArrayToUUID(graph.getGraphId()),
uuidHelper.convertByteArrayToUUID(space.getSpaceId()),
objectMapper.readTree(graph.getData())
);
} catch (Exception e) {
throw new RuntimeException("Error parsing graph data", e);
}
}

//그래프 수정
@Transactional
public GraphResponse updateGraph(UUID graphId, GraphRequest request) {
public GraphResponse updateGraph(UUID userId, UUID graphId, GraphRequest request) {
Graph graph = graphRepository.findByGraphId(uuidHelper.convertUUIDToByteArray(graphId))
.orElseThrow(() -> new IllegalArgumentException("Graph not found for graphId: " + graphId));

//권한 체크 추가
spaceRepository.findBySpaceIdAndUserId(
graph.getSpaceId(),
uuidHelper.convertUUIDToByteArray(userId)
).orElseThrow(() -> new ResponseStatusException(HttpStatus.FORBIDDEN, "You do not have access to update this graph"));


try {
String updatedData = objectMapper.writeValueAsString(request.getItems());
graph.updateGraph(updatedData);
} catch (Exception e) {
throw new RuntimeException("Error updating graph data", e);
}

return new GraphResponse(uuidHelper.convertByteArrayToUUID(graph.getGraphId()), uuidHelper.convertByteArrayToUUID(graph.getSpaceId()), request.getItems());
return new GraphResponse(
uuidHelper.convertByteArrayToUUID(graph.getGraphId()),
uuidHelper.convertByteArrayToUUID(graph.getSpaceId()),
request.getItems()
);

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@

@NonNullApi
public interface SpaceRepository extends JpaRepository<Space, byte[]> {
Optional<Space> findById(byte[] spaceId);
List<Space> findAllByUserId(byte[] userId, Sort sort);
Optional<Space> findBySpaceIdAndUserId(byte[] spaceId, byte[] userId);
List<Space> findByUserId(byte[] userId);
boolean existsBySpaceIdAndUserId(byte[] spaceId, byte[] userId);
Optional<Space> findBySharingIdAndIsShared(byte[] sharingId, boolean isShared);
Optional<Space> findBySharingId(byte[] sharingId);
}
Loading
Loading