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
4 changes: 4 additions & 0 deletions backend/pcloud-api/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ dependencies {
// actuator, prometheus
implementation 'org.springframework.boot:spring-boot-starter-actuator'
runtimeOnly 'io.micrometer:micrometer-registry-prometheus'

// AWS S3
implementation platform("software.amazon.awssdk:bom:2.20.143")
implementation "software.amazon.awssdk:s3"
}

def generated = 'src/main/generated'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
= exhibition API 문서
= Exhibition API 문서
:doctype: book
:icons: font
:source-highlighter: highlightjs
:toc: left
:toclevels: 3

= Exhibiton

== 개인전시회를 생성한다 (POST /api/exhibitions)

Expand Down Expand Up @@ -45,7 +44,7 @@ include::{snippets}/exhibition-controller-web-mvc-test/patch_exhibition/request-

include::{snippets}/exhibition-controller-web-mvc-test/patch_exhibition/http-response.adoc[]

== 개인전시회를 삭제한다 (DELETE /api/exhibitions)
== 개인전시회를 삭제한다 (DELETE /api/exhibitions/{exhibitionId})

=== Request

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,19 @@ include::{snippets}/popups-controller-web-mvc-test/patch_popups/http-request.ado

include::{snippets}/popups-controller-web-mvc-test/patch_popups/http-response.adoc[]

== 팝업스토어를 삭제한다 (DELETE /api/popups/{popupsId})

=== Request

include::{snippets}/popups-controller-web-mvc-test/delete_popups/http-request.adoc[]
include::{snippets}/popups-controller-web-mvc-test/delete_popups/path-parameters.adoc[]
include::{snippets}/popups-controller-web-mvc-test/delete_popups/request-headers.adoc[]

=== Response

include::{snippets}/popups-controller-web-mvc-test/delete_popups/http-response.adoc[]


== 팝업스토어를 좋아요 처리 및 취소한다 (POST /api/popups/{popupsId}/likes)

=== Request
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,13 @@ public String loginWithOAuth(final OAuthPlatform platform, final String oAuthPer
private Member signup(final Member member) {
return memberRepository.save(member);
}

// ADMIN test용 로그인 기능입니다.(추후에 삭제 예정)
@Transactional
public String test() {
Member member = memberRepository.save(Member.createWithNormalRole("1234", "kakao", "email"));
member.changeMemberRoleToAdmin();

return tokenProvider.create(member.getId());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,12 @@ public ResponseEntity<TokenResponse> loginWithOAuth(
String token = authService.loginWithOAuth(platform, oAuthPermittedCode);
return ResponseEntity.ok(new TokenResponse(token));
}


// test용 로그인 기능입니다.(추후에 삭제 예정)
@PostMapping("/login/test")
public ResponseEntity<TokenResponse> test() {
String token = authService.test();
return ResponseEntity.ok(new TokenResponse(token));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
import com.domain.customtag.domain.CustomTag;
import com.domain.customtag.domain.CustomTagRepository;
import com.domain.show.exhibition.event.ExhibitionTagsCreatedEvents;
import com.domain.show.exhibition.event.ExhibitionTagsDeletedEvent;
import com.domain.show.exhibition.event.ExhibitionTagsUpdatedEvents;
import com.domain.show.popups.event.PopupsTagsCreatedEvent;
import com.domain.show.popups.event.PopupsTagsDeletedEvent;
import com.domain.show.popups.event.PopupsTagsUpdatedEvent;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -44,6 +46,11 @@ public void updatePopupsTags(final PopupsTagsUpdatedEvent event) {
customTagRepository.saveAll(customTags);
}

@EventListener(PopupsTagsDeletedEvent.class)
public void deletePopupsTags(final PopupsTagsDeletedEvent event) {
customTagRepository.deleteAllByTypeAndTargetId(event.type(), event.popupsId());
}

@EventListener(ExhibitionTagsCreatedEvents.class)
public void saveExhibitionTags(final ExhibitionTagsCreatedEvents event) {
List<CustomTag> customTags = getCustomTag(event.tags(), event.type(), event.exhibitionId());
Expand All @@ -56,4 +63,9 @@ public void updateExhibitionTags(final ExhibitionTagsUpdatedEvents event) {
customTagRepository.deleteAllByTypeAndTargetId(event.type(), event.exhibitionId());
customTagRepository.saveAll(customTags);
}

@EventListener(ExhibitionTagsDeletedEvent.class)
public void deleteExhibitionTags(final ExhibitionTagsDeletedEvent event) {
customTagRepository.deleteAllByTypeAndTargetId(event.type(), event.exhibitionId());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.api.global.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;

@Configuration
public class S3Config {

@Value("${cloud.aws.credentials.accessKey}")
private String accessKey;

@Value("${cloud.aws.credentials.secretKey}")
private String secretKey;

@Value("${cloud.aws.region.static}")
private String region;

@Bean
public S3Client getS3Client() {
return S3Client.builder()
.credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create(accessKey, secretKey)))
.region(Region.of(region))
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.api.show.common.event;

import com.domain.common.ShowType;
import java.util.List;

public record ImageCreatedEvent(
ShowType showType,
Long targetId,
List<String> imageNames
) {

public static ImageCreatedEvent createdPopupsImages(final Long targetId, final List<String> imageNames) {
return new ImageCreatedEvent(ShowType.POPUPS, targetId, imageNames);
}

public static ImageCreatedEvent createdExhibitionImages(final Long targetId, final List<String> imageNames) {
return new ImageCreatedEvent(ShowType.EXHIBITION, targetId, imageNames);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.api.show.common.event;

import com.domain.common.ShowType;

public record ImageDeletedEvent(
ShowType showType,
Long targetId
) {

public static ImageDeletedEvent deletedPopupsImages(final Long targetId) {
return new ImageDeletedEvent(ShowType.POPUPS, targetId);
}

public static ImageDeletedEvent deletedExhibitionImages(final Long targetId) {
return new ImageDeletedEvent(ShowType.EXHIBITION, targetId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.api.show.common.event;

import com.domain.common.ShowType;
import java.util.List;

public record ImageUpdatedEvent(
ShowType showType,
Long targetId,
List<String> imageNames
) {

public static ImageUpdatedEvent updatedPopupsImages(
final Long targetId,
final List<String> imageNames
) {
return new ImageUpdatedEvent(
ShowType.POPUPS,
targetId,
imageNames
);
}

public static ImageUpdatedEvent updatedExhibitionImages(
final Long targetId,
final List<String> imageNames
) {
return new ImageUpdatedEvent(
ShowType.EXHIBITION,
targetId,
imageNames
);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.api.show.exhibition.application;

import com.api.show.common.event.ImageCreatedEvent;
import com.api.show.common.event.ImageDeletedEvent;
import com.api.show.common.event.ImageUpdatedEvent;
import com.api.show.exhibition.application.dto.ExhibitionCreateRequest;
import com.api.show.exhibition.application.dto.ExhibitionUpdateRequest;
import com.common.config.event.Events;
Expand All @@ -8,6 +11,7 @@
import com.domain.show.exhibition.domain.ExhibitionRepository;
import com.domain.show.exhibition.domain.LikedExhibition;
import com.domain.show.exhibition.event.ExhibitionTagsCreatedEvents;
import com.domain.show.exhibition.event.ExhibitionTagsDeletedEvent;
import com.domain.show.exhibition.event.ExhibitionTagsUpdatedEvents;
import com.domain.show.exhibition.exception.ExhibitionException;
import lombok.RequiredArgsConstructor;
Expand All @@ -30,6 +34,7 @@ public Long create(final Long memberId, final ExhibitionCreateRequest request) {
request.tags(),
CustomTagType.PERSONAL_EXHIBITION
));
Events.raise(ImageCreatedEvent.createdExhibitionImages(savedExhibition.getId(), request.imageNames()));

return savedExhibition.getId();
}
Expand All @@ -40,13 +45,18 @@ public void patchById(
final ExhibitionUpdateRequest request
) {
Exhibition foundExhibition = findExhibition(exhibitionId);
Exhibition updateExhibition = request.toDomain(memberId);
foundExhibition.update(updateExhibition);
foundExhibition.validateOwnerWithOwnerId(memberId);
foundExhibition.update(request.toDomain(memberId));
Events.raise(new ExhibitionTagsUpdatedEvents(
foundExhibition.getId(),
exhibitionId,
request.tags(),
CustomTagType.PERSONAL_EXHIBITION)
);

Events.raise(ImageUpdatedEvent.updatedExhibitionImages(
exhibitionId,
request.imageNames()
));
}

private Exhibition findExhibition(final Long exhibitionId) {
Expand All @@ -56,8 +66,10 @@ private Exhibition findExhibition(final Long exhibitionId) {

public void deleteById(final Long memberId, final Long exhibitionId) {
Exhibition foundExhibition = findExhibition(exhibitionId);
foundExhibition.validateOwnerEquals(memberId);
foundExhibition.validateOwnerWithOwnerId(memberId);
exhibitionRepository.deleteById(foundExhibition.getId());
Events.raise(new ExhibitionTagsDeletedEvent(exhibitionId, CustomTagType.PERSONAL_EXHIBITION));
Events.raise(ImageDeletedEvent.deletedExhibitionImages(exhibitionId));
}

public boolean toggleLike(final Long memberId, final Long exhibitionId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

import com.domain.show.exhibition.domain.Exhibition;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import java.time.LocalDateTime;
import java.util.List;

public record ExhibitionCreateRequest(

@NotBlank(message = "개인전시회 제목을 입력해주세요.")
String title,

Expand Down Expand Up @@ -53,7 +53,11 @@ public record ExhibitionCreateRequest(
@NotBlank(message = "개인전시회 퍼블릭 태그를 붙여주세요.")
String publicTag,

List<String> tags
@NotEmpty(message = "개인전시회 커스텀 태그를 붙여주세요.")
List<String> tags,

@NotEmpty(message = "개인전시회 이미지명을 입력해주세요.")
List<String> imageNames
) {
public Exhibition toDomain(final Long memberId) {
return Exhibition.of(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.domain.show.exhibition.domain.Exhibition;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import java.time.LocalDateTime;
import java.util.List;
Expand Down Expand Up @@ -53,7 +54,10 @@ public record ExhibitionUpdateRequest(
@NotBlank(message = "개인전시회 퍼블릭 태그를 붙여주세요.")
String publicTag,

List<String> tags
@NotEmpty(message = "팝업스토어 커스텀 태그를 붙여주세요.")
List<String> tags,

List<String> imageNames
) {

public Exhibition toDomain(final Long memberId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import com.domain.annotation.AuthMember;
import com.domain.annotation.AuthMembers;
import com.domain.show.exhibition.domain.dto.ExhibitionSpecificResponse;
import jakarta.validation.Valid;
import java.net.URI;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
Expand All @@ -20,8 +22,6 @@
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.net.URI;

import static com.domain.member.domain.vo.MemberRole.ADMIN;
import static com.domain.member.domain.vo.MemberRole.MANAGER;

Expand All @@ -35,13 +35,10 @@ public class ExhibitionController {
private final ExhibitionService exhibitionService;
private final ExhibitionQueryService exhibitionQueryService;

/**
* TODO: 이미지 처리
*/
@PostMapping
public ResponseEntity<Void> create(
@AuthMembers(permit = {MANAGER, ADMIN}) final Long memberId,
@RequestBody final ExhibitionCreateRequest request
@RequestBody @Valid final ExhibitionCreateRequest request
) {
Long createdExhibitionId = exhibitionService.create(memberId, request);
return ResponseEntity.created(URI.create(URI_PREFIX + createdExhibitionId))
Expand All @@ -51,21 +48,18 @@ public ResponseEntity<Void> create(
@GetMapping("/{exhibitionId}")
public ResponseEntity<ExhibitionSpecificResponse> findById(
@PathVariable final Long exhibitionId,
@ClientIpFinder final String clientIp) {
@ClientIpFinder final String clientIp
) {
return ResponseEntity.ok(exhibitionQueryService.findById(exhibitionId, clientIp));
}

@PatchMapping("/{exhibitionId}")
public ResponseEntity<Void> patchById(
@AuthMembers(permit = {ADMIN, MANAGER}) final Long memberId,
@PathVariable final Long exhibitionId,
@RequestBody final ExhibitionUpdateRequest request
@RequestBody @Valid final ExhibitionUpdateRequest request
) {
exhibitionService.patchById(
memberId,
exhibitionId,
request
);
exhibitionService.patchById(memberId, exhibitionId, request);

return ResponseEntity.noContent()
.build();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.api.show.image.application;

import com.domain.common.ShowType;
import com.domain.show.common.image.domain.Image;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;

public interface ImagePreProcessor {

List<Image> convertMultipartFileToImage(
ShowType showType,
Long targetId,
List<MultipartFile> imageFiles);
}
Loading
Loading