Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weโ€™ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Weekly/10]: Reservation/unit test #91

Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@
import lombok.RequiredArgsConstructor;
import org.ktc2.cokaen.wouldyouin.Image.api.dto.ImageResponse;
import org.ktc2.cokaen.wouldyouin.Image.application.ImageServiceFactory;
import org.ktc2.cokaen.wouldyouin.Image.application.ImageStorage;
import org.ktc2.cokaen.wouldyouin._common.api.ApiResponse;
import org.ktc2.cokaen.wouldyouin._common.api.ApiResponseBody;
import org.ktc2.cokaen.wouldyouin._common.exception.FailToReadImageException;
import org.ktc2.cokaen.wouldyouin.auth.Authorize;
import org.ktc2.cokaen.wouldyouin.auth.MemberIdentifier;
import org.ktc2.cokaen.wouldyouin.member.persist.MemberType;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
Expand All @@ -29,8 +33,10 @@ public class ImageController {

private final ImageServiceFactory imageServiceFactory;

// Todo: authorize
@PostMapping("/images")
public ResponseEntity<ApiResponseBody<List<ImageResponse>>> uploadImages(@RequestParam List<MultipartFile> images,
public ResponseEntity<ApiResponseBody<List<ImageResponse>>> uploadImages(
@RequestParam List<MultipartFile> images,
@RequestParam(value = "type") ImageDomain imageDomain) {
return ApiResponse.ok(imageServiceFactory.getImageServiceByImageType(imageDomain).saveAndCreateImages(images));
}
Expand All @@ -44,9 +50,11 @@ public ResponseEntity<byte[]> getImage(@PathVariable String path) {
}
}

// Authorize ๋กœ์ง
// Todo: authorize
@DeleteMapping("/images/{id}")
public ResponseEntity<ApiResponseBody<Void>> deleteImage(@PathVariable Long id, @RequestParam ImageDomain imageDomain) {
public ResponseEntity<ApiResponseBody<Void>> deleteImage(
@PathVariable Long id,
@RequestParam(value = "type") ImageDomain imageDomain) {
imageServiceFactory.getImageServiceByImageType(imageDomain).deleteAndDelete(id);
return ApiResponse.noContent();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ public class ImageResponse {
private LocalDateTime createdDate;
private Long size;

public static ImageResponse from(Image image) {
public static ImageResponse from(Image image, String domainName) {
System.out.println("๋„๋ฉ”์ธ" + domainName);
return ImageResponse.builder()
.id(image.getId())
.url(image.getUrl())
.url(domainName + image.getUrl())
.size(image.getSize())
.createdDate(image.getCreatedDate())
.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,10 @@
@RequiredArgsConstructor
public class AdvertisementImageService extends ImageService<AdvertisementImage> {

@Value("${image.upload.ad.sub-path}")
private String subPath;

private final ImageStorage imageStorage;

private final AdvertisementImageRepository adImageRepository;
@Value("${image.upload.ad.sub-path}")
private String subPath;

@Override
protected ImageRepository<AdvertisementImage> getImageRepository() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
package org.ktc2.cokaen.wouldyouin.Image.application;

import java.util.List;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.ktc2.cokaen.wouldyouin.Image.api.ImageDomain;
import org.ktc2.cokaen.wouldyouin.Image.api.dto.ImageRequest;
import org.ktc2.cokaen.wouldyouin.Image.persist.CurationImage;
import org.ktc2.cokaen.wouldyouin.Image.persist.EventImage;
import org.ktc2.cokaen.wouldyouin.Image.persist.EventImageRepository;
import org.ktc2.cokaen.wouldyouin.Image.persist.ImageRepository;
import org.ktc2.cokaen.wouldyouin._common.exception.EntityNotFoundException;
import org.ktc2.cokaen.wouldyouin._common.exception.EntityParamIsNullException;
import org.ktc2.cokaen.wouldyouin.advertisement.persist.Advertisement;
import org.ktc2.cokaen.wouldyouin.curation.persist.CurationCard;
import org.ktc2.cokaen.wouldyouin.event.persist.Event;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.ktc2.cokaen.wouldyouin.Image.persist.ImageRepository;
import org.ktc2.cokaen.wouldyouin._common.exception.EntityNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
Expand All @@ -20,6 +21,9 @@ public abstract class ImageService<T extends Image> {
@Autowired
protected ImageStorage imageStorage;

@Value("${spring.wouldyouin-domain-name}")
private String domainName;

protected abstract ImageRepository<T> getImageRepository();

protected abstract ImageDomain getImageDomain();
Expand All @@ -34,7 +38,7 @@ public T getById(Long id) {
}

protected ImageResponse create(ImageRequest imageRequest) {
return ImageResponse.from(getImageRepository().save(toEntity(imageRequest)));
return ImageResponse.from(getImageRepository().save(toEntity(imageRequest)), domainName);
}

protected void delete(Long id) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,16 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import org.ktc2.cokaen.wouldyouin.Image.api.ImageDomain;
import org.ktc2.cokaen.wouldyouin._common.exception.FailedToDeleteImageException;
import org.ktc2.cokaen.wouldyouin._common.exception.FailedToUploadImageException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClient;
import org.springframework.web.multipart.MultipartFile;

@Component
Expand All @@ -18,13 +23,38 @@ public class ImageStorage {
private String commonPath;

public String save(MultipartFile image, String subPath) {
String fileName = generateUuidName() + "." + getExtension(image);
Path path = Paths.get(commonPath, subPath, fileName);
String fileName = "";
try {
fileName = generateUuidName() + "." + getExtension(image);
Path path = Paths.get(commonPath, subPath, fileName);
Files.createDirectories(path.getParent());
Files.write(path, image.getBytes());
} catch (IOException ex) {
throw new RuntimeException("failed to upload image.");
throw new FailedToUploadImageException();
}
return subPath + "/" + fileName;
}

// Todo: payment๋ž‘ ์ด๋ถ€๋ถ„ restclient ์œ ํ‹ธ๋กœ ๋นผ๊ธฐ
public String save(String imageUrl, String subPath) {
RestClient client = RestClient.builder().build();
String fileName = "";
try {
ResponseEntity<byte[]> response = client.get()
.uri(imageUrl)
.retrieve()
.toEntity(byte[].class);

if (Optional.ofNullable(response).isPresent() && response.getStatusCode().is2xxSuccessful()) {
byte[] imageBytes = response.getBody();

fileName = generateUuidName() + "." + getExtension(imageUrl);
Path path = Paths.get(commonPath, subPath, fileName);
Files.createDirectories(path.getParent());
Files.write(path, response.getBody());
}
} catch (IOException ex) {
throw new FailedToUploadImageException();
}
return subPath + "/" + fileName;
}
Expand All @@ -33,14 +63,19 @@ public void delete(String imagePath) {
try {
Files.deleteIfExists(Paths.get(imagePath));
} catch (IOException ex) {
throw new RuntimeException("failed to delete image.");
throw new FailedToDeleteImageException();
}
}

protected static String getExtension(MultipartFile image) {
return Objects.requireNonNull(image.getContentType()).split("/")[1];
}

protected static String getExtension(String imageUrl) {
String[] splitted = imageUrl.split("\\.");
return splitted[splitted.length - 1];
}

private static String generateUuidName() {
return UUID.randomUUID().toString().replace("-", "");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,35 +61,9 @@ public void setBaseMember(MemberImage image, BaseMember member) {
}

// TODO: imageUrl์„ MemberImage๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๋กœ์ง ์ถ”๊ฐ€ ํ•„์š”
// Todo: extension๊ณผ size ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
public MemberImage convert(String imageUrl) {

RestClient client = RestClient.builder().build();

try {
ResponseEntity<byte[]> response = client.get()
.uri(imageUrl)
.retrieve()
.toEntity(byte[].class);

// ์š”์ฒญ ์„ฑ๊ณต ์‹œ ์ด๋ฏธ์ง€ ์ €์žฅ
if (response != null && response.getStatusCode() == HttpStatus.OK) {
byte[] imageBytes = response.getBody();

if (imageBytes != null) {
// ํŒŒ์ผ ์ด๋ฆ„๊ณผ ๊ฒฝ๋กœ ์„ค์ •
Path path = Paths.get("src/main/resources/static", subPath, "testFilename");
Files.createDirectories(path.getParent());
Files.write(path, response.getBody());
}
}
} catch (Exception ex) {
throw new RuntimeException("failed to get image.");
}

return MemberImage.builder()
.url("http://example.com/images/MockMemberImageUrl")
.size(10L)
.extension(".jpeg")
.build();
var request = ImageRequest.of(imageStorage.save(imageUrl, subPath), 123123L, "jpg");
return memberImageRepository.save(toEntity(request));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@ public class ParamDefaults {
public static final String PAGE = "0";
public static final String PAGE_SIZE = "10";
public static final String LAST_ID = Long.MAX_VALUE + "";
public static final String START_LATITUDE = "-90.0";
public static final String END_LATITUDE = "90.0";
public static final String START_LONGITUDE = "-180.0";
public static final String END_LONGITUDE = "180.0";
public static final String TITLE = "";
public static final String AREA = "์ „์ฒด";
public static final String CATEGORY = "์ „์ฒด";
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,13 @@ public enum ErrorCode {

UNAUTHORIZED(HttpStatus.UNAUTHORIZED.value(), "-20400", "Unauthorized, %s."),

ENTITY_PARAM_IS_NULL(HttpStatus.BAD_REQUEST.value(), "-20400", "%s is null");
ENTITY_PARAM_IS_NULL(HttpStatus.BAD_REQUEST.value(), "-20400", "%s is null"),

FAIL_TO_UPLOAD_IMAGE(HttpStatus.CONFLICT.value(), "-20400", "Fail to upload image"),

FAIL_TO_DELETE_IMAGE(HttpStatus.CONFLICT.value(), "-20400", "Fail to delete image"),

CURRENT_LOCATION_EMPTY(HttpStatus.BAD_REQUEST.value(), "-20400", "ํ˜„์žฌ ์œ„์น˜ ์ •๋ณด๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.");

private final Integer status;
private final String code;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.ktc2.cokaen.wouldyouin._common.exception;

import org.ktc2.cokaen.wouldyouin._common.error.ErrorCode;

public class CurrentLocationEmptyException extends BusinessException {

public CurrentLocationEmptyException() {
super(ErrorCode.CURRENT_LOCATION_EMPTY, "ํ˜„์žฌ ์œ„์น˜ ์ •๋ณด๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.ktc2.cokaen.wouldyouin._common.exception;

import org.ktc2.cokaen.wouldyouin._common.error.ErrorCode;

public class FailedToDeleteImageException extends BusinessException {

public FailedToDeleteImageException() {
super(ErrorCode.FAIL_TO_DELETE_IMAGE, ErrorCode.FAIL_TO_DELETE_IMAGE.getMessage());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.ktc2.cokaen.wouldyouin._common.exception;

import org.ktc2.cokaen.wouldyouin._common.error.ErrorCode;

public class FailedToUploadImageException extends BusinessException {

public FailedToUploadImageException() {
super(ErrorCode.FAIL_TO_UPLOAD_IMAGE, ErrorCode.FAIL_TO_UPLOAD_IMAGE.getMessage());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,15 @@ public class EventController {
public ResponseEntity<ApiResponseBody<EventSliceResponse>> getEventsByFilterOrderByDistanceAsc(
@ModelAttribute LocationFilter locationFilter,
@ModelAttribute Location currentLocation,
@RequestParam(defaultValue = ParamDefaults.TITLE) String title,
@RequestParam(defaultValue = ParamDefaults.CATEGORY) Category category,
@RequestParam(defaultValue = ParamDefaults.AREA) Area area,
@RequestParam(defaultValue = ParamDefaults.PAGE) Integer page,
@RequestParam(defaultValue = ParamDefaults.PAGE_SIZE) Integer size,
@RequestParam(defaultValue = ParamDefaults.LAST_ID) Long lastId
) {
return ApiResponse.ok(eventService.getAllByFilterOrderByDistanceAsc(
locationFilter, currentLocation, category, area, PageRequest.of(page, size), lastId));
locationFilter, currentLocation, title, category, area, PageRequest.of(page, size), lastId));
}

@GetMapping("/hosts/{hostId}")
Expand All @@ -62,8 +63,6 @@ public ResponseEntity<ApiResponseBody<EventSliceResponse>> getEventsByHostId(
hostId, PageRequest.of(page, size), lastId));
}

// Todo: ์ด๋ฆ„์œผ๋กœ ๊ฒ€์ƒ‰

@GetMapping("/{eventId}")
public ResponseEntity<ApiResponseBody<EventResponse>> getEventByEventId(
@PathVariable("eventId") Long eventId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.ktc2.cokaen.wouldyouin.Image.application.EventImageService;
import org.ktc2.cokaen.wouldyouin._common.exception.CurrentLocationEmptyException;
import org.ktc2.cokaen.wouldyouin._common.exception.EntityNotFoundException;
import org.ktc2.cokaen.wouldyouin._common.exception.UnauthorizedException;
import org.ktc2.cokaen.wouldyouin._common.vo.Area;
Expand Down Expand Up @@ -30,12 +31,19 @@ public class EventService {
private final EventImageService eventImageService;

@Transactional(readOnly = true)
public EventSliceResponse getAllByFilterOrderByDistanceAsc(LocationFilter location, Location currentLocation,
public EventSliceResponse getAllByFilterOrderByDistanceAsc(LocationFilter location, Location currentLocation, String title,
Category category, Area area, Pageable pageable, Long lastId) {
validateCurrentLocation(currentLocation);
return getEventSliceResponse(
eventRepository.findAllByFilterOrderByDistance(location.getStartLatitude(), location.getStartLongitude(),
location.getEndLatitude(), location.getEndLongitude(), currentLocation.getLatitude(), currentLocation.getLongitude(),
category, area, pageable), lastId);
title, category, area, pageable), lastId);
}

private void validateCurrentLocation(Location currentLocation) {
if (currentLocation.getLatitude() == null || currentLocation.getLongitude() == null) {
throw new CurrentLocationEmptyException();
}
}

@Transactional(readOnly = true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@ public interface EventRepository extends JpaRepository<Event, Long> {
@Query("SELECT E FROM Event E JOIN FETCH E.host "
+ "WHERE (E.location.latitude between :startLatitude AND :endLatitude) "
+ "AND (E.location.longitude between :startLongitude AND :endLongitude) "
+ "AND (E.title LIKE %:title%) "
+ "AND (:category = '์ „์ฒด' OR E.category = :category) "
+ "AND (:area = '์ „์ฒด' OR E.area = :area) "
+ "ORDER BY (:currentLatitude - E.location.latitude) * (:currentLatitude - E.location.latitude) + "
+ "(:currentLongitude - E.location.longitude) * (:currentLongitude - E.location.longitude) ASC")
Slice<Event> findAllByFilterOrderByDistance(
Double startLatitude, Double startLongitude, Double endLatitude, Double endLongitude,
Double currentLatitude, Double currentLongitude, Category category, Area area, Pageable pageable);
Double currentLatitude, Double currentLongitude, String title, Category category, Area area, Pageable pageable);
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ public class ReservationController {

@GetMapping
public ResponseEntity<ApiResponseBody<ReservationSliceResponse>> getReservationsByMemberId(
@Authorize({MemberType.normal, MemberType.curator}) Long memberId,
@Authorize({MemberType.normal, MemberType.curator}) MemberIdentifier member,
@RequestParam(defaultValue = ParamDefaults.PAGE) Integer page,
@RequestParam(defaultValue = ParamDefaults.PAGE_SIZE) Integer size,
@RequestParam(defaultValue = ParamDefaults.LAST_ID) Long lastId) {
return ApiResponse.ok(reservationService.getAllByMemberId(memberId, PageRequest.of(page, size), lastId));
return ApiResponse.ok(reservationService.getAllByMemberId(member.id(), PageRequest.of(page, size), lastId));
}

@GetMapping("/events/{eventId}")
Expand Down
Loading
Loading