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
7 changes: 6 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ dependencies {
// Spring AI
implementation "org.springframework.ai:spring-ai-starter-model-openai"


// 크롤링
implementation("org.jsoup:jsoup:1.21.2")

Expand All @@ -87,6 +86,12 @@ dependencies {
// Mysql driver
implementation 'mysql:mysql-connector-java:8.0.33'

// AWS SDK for S3
implementation 'io.awspring.cloud:spring-cloud-aws-starter-s3:3.4.0'

// Playwright for Java
implementation 'com.microsoft.playwright:playwright:1.54.0'

}

dependencyManagement {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ public String main() {
String kakaoLoginUrl = "/oauth2/authorization/kakao";
String googleLoginUrl = "/oauth2/authorization/google";
String logoutUrl = "/api/v1/auth/logout";
String testS3UploadUrl = "/test/upload-file";
String testThumbnailUrl = "/test/generate-thumbnail";

return """
<h1>API 서버</h1>
Expand All @@ -56,6 +58,23 @@ public String main() {
<input type="text" name="query" placeholder="검색어 입력"/>
<input type="submit" value="검색"/>
</form>
""".formatted(localHost.getHostName(), localHost.getHostAddress(), kakaoLoginUrl, googleLoginUrl, logoutUrl);

<h2>S3 파일 업로드 테스트</h2>
<form action="%s" method="post" enctype="multipart/form-data">
<input type="text" name="fileName" placeholder="S3에 저장될 파일명 (예: images/test.jpg)"/>
<br><br>
<input type="file" name="file"/>
<br><br>
<input type="submit" value="업로드"/>
</form>

<hr>
<h2>썸네일 생성 테스트</h2>
<div>
<a href="%s">
<button>썸네일 생성 및 S3 업로드 테스트</button>
</a>
</div>
""".formatted(localHost.getHostName(), localHost.getHostAddress(), kakaoLoginUrl, googleLoginUrl, logoutUrl, testS3UploadUrl, testThumbnailUrl);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ public RsData<ResBodyForSpaceInviteList> getMyInvites(
List<SpaceMembershipInfoWithoutAuthority> invitationInfos = invitations.stream()
.map(membership -> new SpaceMembershipInfoWithoutAuthority(
membership.getSpace().getId(),
membership.getSpace().getName()
membership.getSpace().getName(),
membership.getSpace().getThumbnailUrl()
))
.toList();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.tuna.zoopzoop.backend.domain.space.membership.repository;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.tuna.zoopzoop.backend.domain.member.entity.Member;
import org.tuna.zoopzoop.backend.domain.space.membership.entity.Membership;
Expand All @@ -12,10 +14,12 @@
public interface MembershipRepository extends JpaRepository<Membership, Integer> {
boolean existsByMemberAndSpace(Member member, Space space);

List<Membership> findAllByMemberAndAuthority(Member member, Authority authority);
Page<Membership> findAllByMemberAndAuthority(Member member, Authority authority, Pageable pageable);
Page<Membership> findAllByMemberAndAuthorityIsNot(Member member, Authority authority, Pageable pageable);
Page<Membership> findAllByMember(Member member, Pageable pageable);

List<Membership> findAllByMemberAndAuthority(Member member, Authority authority);
List<Membership> findAllByMemberAndAuthorityIsNot(Member member, Authority authority);

List<Membership> findAllByMember(Member member);

boolean existsByMemberAndSpaceAndAuthorityIsNot(Member member, Space space, Authority authority);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import jakarta.validation.constraints.PositiveOrZero;
import lombok.RequiredArgsConstructor;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.tuna.zoopzoop.backend.domain.member.entity.Member;
import org.tuna.zoopzoop.backend.domain.member.service.MemberService;
Expand Down Expand Up @@ -50,6 +52,22 @@ public Membership findByMemberAndSpace(Member member, Space space) {
.orElseThrow(() -> new NoResultException("해당 멤버는 스페이스에 속해있지 않습니다."));
}

/**
* 멤버가 속한 스페이스 목록 조회
* @param member 조회할 멤버
* @param state 멤버의 가입 상태로 필터링 (PENDING, JOINED, ALL)
* @return 멤버가 속한 스페이스 목록
*/
public Page<Membership> findByMember(Member member, String state, Pageable pageable) {
if (state.equalsIgnoreCase("PENDING")) {
return membershipRepository.findAllByMemberAndAuthority(member, Authority.PENDING, pageable);
} else if (state.equalsIgnoreCase("JOINED")) {
return membershipRepository.findAllByMemberAndAuthorityIsNot(member, Authority.PENDING, pageable);
} else {
return membershipRepository.findAllByMember(member, pageable);
}
}

/**
* 멤버가 속한 스페이스 목록 조회
* @param member 조회할 멤버
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,24 @@
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.PageableDefault;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.tuna.zoopzoop.backend.domain.member.entity.Member;
import org.tuna.zoopzoop.backend.domain.space.membership.entity.Membership;
import org.tuna.zoopzoop.backend.domain.space.membership.enums.Authority;
import org.tuna.zoopzoop.backend.domain.space.membership.enums.JoinState;
import org.tuna.zoopzoop.backend.domain.space.membership.service.MembershipService;
import org.tuna.zoopzoop.backend.domain.space.space.dto.req.ReqBodyForSpaceSave;
import org.tuna.zoopzoop.backend.domain.space.space.dto.res.ResBodyForSpaceInfo;
import org.tuna.zoopzoop.backend.domain.space.space.dto.res.ResBodyForSpaceList;
import org.tuna.zoopzoop.backend.domain.space.space.dto.etc.SpaceMembershipInfo;
import org.tuna.zoopzoop.backend.domain.space.space.dto.res.ResBodyForSpaceListPage;
import org.tuna.zoopzoop.backend.domain.space.space.dto.res.ResBodyForSpaceSave;
import org.tuna.zoopzoop.backend.domain.space.space.entity.Space;
import org.tuna.zoopzoop.backend.domain.space.space.service.SpaceService;
Expand All @@ -22,6 +30,7 @@

import java.nio.file.AccessDeniedException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@RestController
Expand Down Expand Up @@ -99,33 +108,49 @@ public RsData<ResBodyForSpaceSave> updateSpaceName(
);
}

@PutMapping(path = "/thumbnail/{spaceId}", consumes = {"multipart/form-data"})
@Operation(summary = "스페이스 썸네일 이미지 갱신")
public RsData<Void> updateSpaceThumbnail(
@AuthenticationPrincipal CustomUserDetails userDetails,
@PathVariable Integer spaceId,
@RequestPart(value = "image", required = false) MultipartFile image
) {
Member member = userDetails.getMember();

spaceService.updateSpaceThumbnail(spaceId, member, image);

return new RsData<>(
"200",
"스페이스 썸네일 이미지가 갱신됐습니다.",
null
);
}

@GetMapping
@Operation(summary = "스페이스 목록 조회")
public RsData<ResBodyForSpaceList> getAllSpaces(
@Operation(summary = "나의 스페이스 목록 조회")
public RsData<ResBodyForSpaceListPage> getAllSpaces(
@AuthenticationPrincipal CustomUserDetails userDetails,
@RequestParam(required = false) JoinState state
@RequestParam(required = false) JoinState state,
@PageableDefault(size = 10, sort = "createDate", direction = Sort.Direction.DESC) Pageable pageable
) {
// 현재 로그인한 사용자 정보 가져오기
Member member = userDetails.getMember();

// 멤버가 속한 스페이스 목록 조회
List<Membership> memberships;
if (state == null) {
memberships = membershipService.findByMember(member, "ALL");
}
else {
memberships = membershipService.findByMember(member, state.name());
}

// 반환 값 생성
List<SpaceMembershipInfo> spaceInfos = memberships.stream()
.map(membership -> new SpaceMembershipInfo(
membership.getSpace().getId(),
membership.getSpace().getName(),
membership.getAuthority()
))
.collect(Collectors.toList());
ResBodyForSpaceList resBody = new ResBodyForSpaceList(spaceInfos);
String stateStr = (state == null) ? "ALL" : state.name();
Page<Membership> membershipsPage = membershipService.findByMember(member, stateStr, pageable);

// Page<Membership>를 Page<SpaceMembershipInfo>로 변환
// Page 객체의 map() 메서드를 사용하면 페이징 정보는 그대로 유지하면서 내용물만 쉽게 바꿀 수 있습니다.
Page<SpaceMembershipInfo> spaceInfosPage = membershipsPage.map(membership -> new SpaceMembershipInfo(
membership.getSpace().getId(),
membership.getSpace().getName(),
membership.getSpace().getThumbnailUrl(),
membership.getAuthority()
));

// 새로운 응답 DTO 생성
ResBodyForSpaceListPage resBody = new ResBodyForSpaceListPage(spaceInfosPage);

return new RsData<>(
"200",
Expand All @@ -134,6 +159,32 @@ public RsData<ResBodyForSpaceList> getAllSpaces(
);
}

@GetMapping("/{spaceId}")
@Operation(summary = "스페이스 단건 조회")
public RsData<ResBodyForSpaceInfo> getSpace(
@AuthenticationPrincipal CustomUserDetails userDetails,
@PathVariable Integer spaceId
) {
Member member = userDetails.getMember();
Space space = spaceService.findById(spaceId);

// 해당 스페이스에 속한 멤버인지 확인
Membership membership = membershipService.findByMemberAndSpace(member, space);

ResBodyForSpaceInfo resBody = new ResBodyForSpaceInfo(
space.getId(),
space.getName(),
space.getThumbnailUrl(),
membership.getAuthority().name(),
space.getSharingArchive().getId()
);

return new RsData<>(
"200",
String.format("%s - 스페이스가 조회됐습니다.", space.getName()),
resBody
);
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
public record SpaceMembershipInfo(
Integer id,
String name,
String thumbnailUrl,
Authority authority
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

public record SpaceMembershipInfoWithoutAuthority(
Integer id,
String name
String name,
String thumbnailUrl
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.tuna.zoopzoop.backend.domain.space.space.dto.res;

public record ResBodyForSpaceInfo (
Integer spaceId,
String spaceName,
String thumbnailUrl,
String userAuthority,
Integer sharingArchiveId
){
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.tuna.zoopzoop.backend.domain.space.space.dto.res;

import lombok.Getter;
import org.springframework.data.domain.Page;
import org.tuna.zoopzoop.backend.domain.space.space.dto.etc.SpaceMembershipInfo;

import java.util.List;

@Getter
public class ResBodyForSpaceListPage {
private final List<SpaceMembershipInfo> spaces; // 현재 페이지의 데이터
private final int page; // 현재 페이지 번호 (0부터 시작)
private final int size; // 페이지 크기
private final long totalElements; // 전체 요소 수
private final int totalPages; // 전체 페이지 수
private final boolean isLast; // 마지막 페이지 여부

public ResBodyForSpaceListPage(Page<SpaceMembershipInfo> page) {
this.spaces = page.getContent();
this.page = page.getNumber();
this.size = page.getSize();
this.totalElements = page.getTotalElements();
this.totalPages = page.getTotalPages();
this.isLast = page.isLast();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ public class Space extends BaseEntity {
@OneToOne(mappedBy = "space", cascade = CascadeType.ALL, orphanRemoval = true)
private SharingArchive sharingArchive;

@Column(nullable = true)
private String thumbnailUrl;

//연결된 MemberShip
//Space 삭제시 cascade.all
@OneToMany(mappedBy = "space", cascade = CascadeType.ALL, orphanRemoval = true)
Expand All @@ -36,11 +39,12 @@ public Space() {
}

@Builder
public Space(String name, Boolean active) {
public Space(String name, Boolean active, String thumbnailUrl) {
this.name = name;

if (active != null)
this.active = active;
if( thumbnailUrl != null)
this.thumbnailUrl = thumbnailUrl;

this.sharingArchive = new SharingArchive(this);
}
Expand Down
Loading