Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,8 @@
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.cherrypic.domain.image.dto.request.AlbumImageDeleteRequest;
import org.cherrypic.domain.image.dto.request.AlbumImageUploadRequest;
import org.cherrypic.domain.image.dto.request.ImageUploadRequest;
import org.cherrypic.domain.image.dto.response.AlbumImageListResponse;
import org.cherrypic.domain.image.dto.response.EventImageListResponse;
import org.cherrypic.domain.image.dto.response.ImageUploadListResponse;
import org.cherrypic.domain.image.dto.response.PresignedUrlResponse;
import org.cherrypic.domain.image.dto.request.*;
import org.cherrypic.domain.image.dto.response.*;
import org.cherrypic.domain.image.service.ImageService;
import org.cherrypic.global.annotation.PageSize;
import org.cherrypic.global.pagination.SliceResponse;
Expand Down Expand Up @@ -99,4 +94,23 @@ public ResponseEntity<Void> albumImageDelete(
imageService.deleteAlbumImage(albumId, request);
return ResponseEntity.noContent().build();
}

@PostMapping("temp-albums/{tempAlbumId}/images")
@Operation(
summary = "임시 앨범 이미지 업로드 Presigned URL들 생성",
description = "임시 앨범 이미지 업로드를 위한 Presigned URL들을 생성합니다.")
public TempAlbumImageUploadListResponse tempAlbumImageUploadUrlsCreate(
@PathVariable Long tempAlbumId,
@Valid @RequestBody TempAlbumImageUploadRequest request) {
return imageService.createTempAlbumImageUploadUrls(tempAlbumId, request);
}

@DeleteMapping("temp-albums/{tempAlbumId}/images")
@Operation(summary = "임시 앨범 이미지 삭제", description = "임시 앨범의 이미지를 삭제합니다.")
public ResponseEntity<Void> tempAlbumImageDelete(
@PathVariable Long tempAlbumId,
@Valid @RequestBody TempAlbumImageDeleteRequest request) {
imageService.deleteTempAlbumImage(tempAlbumId, request);
return ResponseEntity.noContent().build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.cherrypic.domain.image.dto.request;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotEmpty;
import java.util.List;

public record TempAlbumImageDeleteRequest(
@NotEmpty(message = "삭제하고자 하는 임시 앨범 이미지 ID들은 비워둘 수 없습니다.")
@Schema(description = "삭제하고자 하는 임시 앨범 이미지들의 ID", example = "[1,2,3,4]")
List<Long> tempAlbumImageIds) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.cherrypic.domain.image.dto.request;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.util.List;
import org.cherrypic.global.annotation.Enum;
import org.cherrypic.s3.enums.FileExtension;

public record TempAlbumImageUploadRequest(
@NotEmpty(message = "업로드할 피일들의 정보는 비워둘 수 없습니다.") @Valid @Schema(description = "업로드 요청 리스트")
List<Payload> payloads) {
public record Payload(
@Enum(
message =
"파일의 확장자는 비워둘 수 없으며, "
+ "이미지(PNG, JPG, JPEG, WEBP, HEIC, HEIF)와 동영상(MP4, WEBM, MOV, MKV, HEVC)만 지원됩니다.")
@Schema(description = "파일의 확장자", defaultValue = "JPEG")
FileExtension fileExtension,
@NotBlank(message = "MD5 해시값은 비워둘 수 없습니다.")
@Schema(description = "S3 업로드시 파일의 변형을 확인하기 위한 md5 해시")
String md5Hashes,
@NotNull(message = "파일의 용량은 비워둘 수 없습니다.")
@Schema(description = "업로드 하는 파일의 용량(GB)", example = "0.04")
BigDecimal capacity) {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.cherrypic.domain.image.dto.response;

import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;

public record TempAlbumImageUploadListResponse(
@Schema(description = "업로드된 임시 앨범 이미지들의 정보 리스트") List<Payload> payloads) {
public static TempAlbumImageUploadListResponse of(List<Payload> payloads) {
return new TempAlbumImageUploadListResponse(payloads);
}

public record Payload(
@Schema(description = "생성된 임시 앨범 이미지의 ID") Long tempAlbumImageId,
@Schema(description = "생성된 Presigned Url") String presignedUrl) {
public static Payload of(Long imageId, String presignedUrl) {
return new Payload(imageId, presignedUrl);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import org.cherrypic.domain.image.dto.response.EventImageListResponse;
import org.cherrypic.global.pagination.SortDirection;
import org.cherrypic.image.entity.Image;
import org.cherrypic.tempalbum.entity.TempAlbumImage;
import org.springframework.data.domain.Slice;

public interface ImageRepositoryCustom {
Expand All @@ -18,5 +19,9 @@ Slice<AlbumImageListResponse> findAllByAlbumId(

void bulkInsertImages(List<Image> images);

List<Long> findIdsByUrlsInOrder(List<String> urls);
void bulkInsertTempAlbumImages(List<TempAlbumImage> images);

List<Long> findImageIdsByUrlsInOrder(List<String> urls);

List<Long> findTempImageIdsByUrlsInOrder(List<String> urls);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static org.cherrypic.event.entity.QEventImage.eventImage;
import static org.cherrypic.image.entity.QImage.image;
import static org.cherrypic.tempalbum.entity.QTempAlbumImage.tempAlbumImage;

import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.BooleanExpression;
Expand All @@ -14,6 +15,7 @@
import org.cherrypic.domain.image.dto.response.EventImageListResponse;
import org.cherrypic.global.pagination.SortDirection;
import org.cherrypic.image.entity.Image;
import org.cherrypic.tempalbum.entity.TempAlbumImage;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.SliceImpl;
Expand Down Expand Up @@ -99,7 +101,45 @@ public void bulkInsertImages(List<Image> images) {
}

@Override
public List<Long> findIdsByUrlsInOrder(List<String> urls) {
public void bulkInsertTempAlbumImages(List<TempAlbumImage> images) {
String sql =
"INSERT INTO temp_album_image (temp_album_id, url, capacity_gb, created_at, updated_at) "
+ "VALUES (?, ?, ?, NOW(), NOW())";

jdbcTemplate.batchUpdate(
sql,
images,
100,
(ps, image) -> {
ps.setLong(1, image.getTempAlbum().getId());
ps.setString(2, image.getUrl());
ps.setBigDecimal(3, image.getCapacityGb());
});
}

@Override
public List<Long> findTempImageIdsByUrlsInOrder(List<String> urls) {
if (urls == null || urls.isEmpty()) {
return List.of();
}

var cases = new CaseBuilder().when(tempAlbumImage.url.eq(urls.get(0))).then(0);

for (int i = 1; i < urls.size(); i++) {
cases = cases.when(tempAlbumImage.url.eq(urls.get(i))).then(i);
}
NumberExpression<Integer> orderExpr = cases.otherwise(999_999);

return queryFactory
.select(tempAlbumImage.id)
.from(tempAlbumImage)
.where(tempAlbumImage.url.in(urls))
.orderBy(orderExpr.asc())
.fetch();
}

@Override
public List<Long> findImageIdsByUrlsInOrder(List<String> urls) {
if (urls == null || urls.isEmpty()) {
return List.of();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
package org.cherrypic.domain.image.service;

import org.cherrypic.domain.image.dto.request.AlbumImageDeleteRequest;
import org.cherrypic.domain.image.dto.request.AlbumImageUploadRequest;
import org.cherrypic.domain.image.dto.request.ImageUploadRequest;
import org.cherrypic.domain.image.dto.response.AlbumImageListResponse;
import org.cherrypic.domain.image.dto.response.EventImageListResponse;
import org.cherrypic.domain.image.dto.response.ImageUploadListResponse;
import org.cherrypic.domain.image.dto.response.PresignedUrlResponse;
import org.cherrypic.domain.image.dto.request.*;
import org.cherrypic.domain.image.dto.response.*;
import org.cherrypic.global.pagination.SliceResponse;
import org.cherrypic.global.pagination.SortDirection;

Expand All @@ -27,4 +22,9 @@ SliceResponse<EventImageListResponse> getEventImages(
Long eventId, Long lastImageId, int size, SortDirection direction);

void deleteAlbumImage(Long albumId, AlbumImageDeleteRequest request);

TempAlbumImageUploadListResponse createTempAlbumImageUploadUrls(
Long tempAlbumId, TempAlbumImageUploadRequest request);

void deleteTempAlbumImage(Long tempAlbumId, TempAlbumImageDeleteRequest request);
}
Loading