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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ db_dev.trace.db
.DS_Store
.env
/src/main/generated/
/k6

### GA4 Service Account Key (민감 정보!) ###
src/main/resources/ga4-service-account.json
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,32 @@
import com.back.domain.funding.dto.request.FundingNewsCreateRequest;
import com.back.domain.funding.service.FundingNewsService;
import com.back.global.rsData.RsData;
import com.back.global.s3.FileType;
import com.back.global.s3.S3Service;
import com.back.global.s3.UploadResultResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Positive;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;

@RestController
@RequestMapping("/api/fundings")
@RequiredArgsConstructor
@Tag(name = "펀딩 새소식", description = "펀딩 새소식 API 컨트롤러")
public class FundingNewsController{
private final FundingNewsService fundingNewsService;
private final S3Service s3Service;

@PostMapping("/{id}/news")
@PreAuthorize("isAuthenticated()")
Expand All @@ -34,6 +43,34 @@ public ResponseEntity<RsData<?>> addNews(
.body(new RsData<>("201", "새소식이 등록되었습니다.", newsId));
}

@PostMapping(value = "/{id}/news/images", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@PreAuthorize("hasAuthority('ROLE_ARTIST') or hasAuthority('ROLE_ADMIN') or hasAuthority('ROLE_ROOT')")
@Operation(
summary = "펀딩 새소식 이미지 업로드",
description = "펀딩 새소식에 사용할 이미지 업로드. 한 장만 업로드 가능"
)
public ResponseEntity<RsData<List<UploadResultResponse>>> uploadNewsImage(
@PathVariable @Positive Long id,
@Parameter(description = "업로드 할 이미지 파일", required = true)
@RequestPart("file")MultipartFile file) {
List<UploadResultResponse> result = s3Service.uploadFile(file, "funding-news-images", FileType.ADDITIONAL);
return ResponseEntity.ok(RsData.of("200", "이미지 업로드 성공", result));
}

@DeleteMapping("/{id}/news/images")
@PreAuthorize("hasAuthority('ROLE_ARTIST') or hasAuthority('ROLE_ADMIN') or hasAuthority('ROLE_ROOT')")
@Operation(
summary = "펀딩 새소식 이미지 삭제",
description = "S3에 업로드된 이미지 삭제"
)
public ResponseEntity<RsData<String>> deleteNewsImages(
@PathVariable @Positive Long id,
@Parameter(description = "삭제할 파일의 s3Key", required = true)
@RequestParam String s3Key) {
s3Service.deleteFile(s3Key);
return ResponseEntity.ok(RsData.of("200", "이미지가 성공적으로 삭제되었습니다.", s3Key));
}

@DeleteMapping("/{fundingId}/news/{newsId}")
@PreAuthorize("isAuthenticated()")
@Operation(summary = "펀딩 새소식 삭제", description = "펀딩 새소식을 삭제")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@
public record FundingNewsCreateRequest(
@NotBlank String title,
@NotBlank String content,
String imageUrl
String imageUrl,
String s3Key
) {}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public record FundingNewsItemDto(
String title,
String content,
String imageUrl,
String s3Key,
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
LocalDateTime createDate
) {
Expand All @@ -21,6 +22,7 @@ public FundingNewsItemDto(FundingNews u) {
u.getTitle(),
u.getContent(),
u.getImageUrl(),
u.getS3Key(),
u.getCreateDate()
);
}
Expand Down
7 changes: 7 additions & 0 deletions src/main/java/com/back/domain/funding/entity/FundingNews.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,18 @@ public class FundingNews extends BaseEntity {

private String imageUrl;

private String s3Key;

@Column(nullable = false)
@Builder.Default
private boolean deleted = false;

public void delete() {
this.deleted = true;
}

public void removeImage() {
this.imageUrl = null;
this.s3Key = null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import com.back.domain.user.entity.User;
import com.back.domain.user.repository.UserRepository;
import com.back.global.exception.ServiceException;
import com.back.global.s3.S3Service;
import com.back.global.s3.S3ValidationService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand All @@ -18,6 +20,8 @@ public class FundingNewsService {
private final FundingNewsRepository fundingNewsRepository;
private final FundingRepository fundingRepository;
private final UserRepository userRepository;
private final S3Service s3Service;
private final S3ValidationService s3ValidationService;

@Transactional
public Long addFundingNews(Long fundingId, FundingNewsCreateRequest req, String userEmail) {
Expand All @@ -31,12 +35,17 @@ public Long addFundingNews(Long fundingId, FundingNewsCreateRequest req, String
throw new ServiceException("403", "권한이 없습니다.");
}

if (req.s3Key() != null && !req.s3Key().isBlank()) {
s3ValidationService.validateFileExists(req.s3Key());
}

FundingNews news = FundingNews.builder()
.funding(funding)
.artist(artist)
.title(req.title())
.content(req.content())
.imageUrl(req.imageUrl())
.s3Key(req.s3Key())
.build();

fundingNewsRepository.save(news);
Expand All @@ -54,6 +63,9 @@ public void deleteFundingNews(Long fundingId ,Long newsId, String userEmail) {
if (!funding.getUser().getId().equals(artist.getId())) {
throw new ServiceException("403", "권한이 없습니다.");
}
if (news.getS3Key() != null && !news.getS3Key().isBlank()){
s3Service.deleteFile(news.getS3Key());
}
news.delete();
}
}