Skip to content

Commit

Permalink
Merge pull request #56 from YAPP-Github/dev
Browse files Browse the repository at this point in the history
[RELEASE] release: 리팩토링 후 첫 릴리즈 배포
  • Loading branch information
CChuYong authored Aug 4, 2024
2 parents 7367384 + 94f2f1c commit 7d5821b
Show file tree
Hide file tree
Showing 29 changed files with 468 additions and 140 deletions.
3 changes: 3 additions & 0 deletions api-gateway/src/main/resources/application-prod.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
management:
tracing:
enabled: true
8 changes: 8 additions & 0 deletions api-gateway/src/main/resources/application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ spring:
filters:
- JWTAuthenticationFilter
- RewritePath=/user/(?<segment>/?.*), /$\{segment}
- id: photo-service-add-photo
uri: http://photo-service
predicates:
- Path=/photo/v1/photos
- Method=POST
filters:
- RewritePath=/photo/(?<segment>/?.*), /$\{segment}
- id: photo-service
uri: http://photo-service
predicates:
Expand All @@ -64,6 +71,7 @@ management:
tracing:
sampling:
probability: 1.0
enabled: false
zipkin:
tracing:
endpoint: http://zipkin/api/v2/spans
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.springframework.web.reactive.config.WebFluxConfigurer;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.result.method.annotation.ArgumentResolverConfigurer;
import org.springframework.web.util.DefaultUriBuilderFactory;

@EnableWebFlux
@Configuration
Expand All @@ -17,7 +18,10 @@ public void configureArgumentResolvers(ArgumentResolverConfigurer configurer) {

@Bean("externalWebClient")
public WebClient externalServiceWebClient() {
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory();
factory.setEncodingMode(DefaultUriBuilderFactory.EncodingMode.NONE);
return WebClient.builder()
.uriBuilderFactory(factory)
.codecs(clientCodecConfigurer -> {
clientCodecConfigurer
.defaultCodecs()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,6 @@ public Mono<PhotoResponse> createPhoto(
String memberId,
PhotoCreateRequest request
){

// HACK : 프엔 응급 요청으로 더미 응답 추가했습니다. - 추후 삭제 예정
if (request.qrUrl().equals("https://mafoo.kr/")) {
return Mono.just(new PhotoResponse("id", "https://kr.object.ncloudstorage.com/mafoo//24c576bc-60b0-4e43-af9a-0c3311b97f35", LIFE_FOUR_CUTS, null));
}

return photoService
.createNewPhoto(request.qrUrl(), memberId)
.map(PhotoResponse::fromEntity);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ public enum BrandType {
PHOTOISM(Pattern.compile("https://qr\\.seobuk\\.kr/.*")),
HARU_FILM(Pattern.compile("http://haru\\d+\\.mx\\d+\\.co\\.kr/.*")),
DONT_LOOK_UP(Pattern.compile("https://x\\.dontlxxkup\\.kr/.*")),
MY_FOUR_CUT(Pattern.compile("https://firebasestorage\\.googleapis\\.com:443/v0/b/my4ccu\\.appspot\\.com/.*")),
PHOTOGRAY(Pattern.compile("https://pgshort\\.aprd\\.io/.*")),
MONOMANSION(Pattern.compile("https://monomansion\\.net/.*")),
PHOTO_SIGNATURE(Pattern.compile("http://photoqr3\\.kr/.*")),
PICDOT(Pattern.compile("https://picdot\\.kr/.*")),
MAFOO(Pattern.compile("https://mafoo\\.kr/.*"))
;

private final Pattern urlPattern;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,15 @@ public String getId() {
return photoId;
}

public Boolean hasOwnerMemberId() {
return this.getOwnerMemberId() != null;
}

public PhotoEntity updateOwnerMemberId(String ownerMemberId) {
this.ownerMemberId = ownerMemberId;
return this;
}

public PhotoEntity updateAlbumId(String albumId) {
this.albumId = albumId;
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import kr.mafoo.photo.util.IdGenerator;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

Expand All @@ -15,6 +16,7 @@
public class AlbumService {
private final AlbumRepository albumRepository;

@Transactional
public Mono<AlbumEntity> createNewAlbum(String ownerMemberId, String albumName, AlbumType albumType) {
AlbumEntity albumEntity = AlbumEntity.newAlbum(IdGenerator.generate(), albumName, albumType, ownerMemberId);
return albumRepository.save(albumEntity);
Expand All @@ -38,6 +40,7 @@ public Mono<AlbumEntity> findByAlbumId(String albumId, String requestMemberId) {
});
}

@Transactional
public Mono<Void> deleteAlbumById(String albumId, String requestMemberId) {
return albumRepository
.findById(albumId)
Expand All @@ -52,6 +55,7 @@ public Mono<Void> deleteAlbumById(String albumId, String requestMemberId) {
});
}

@Transactional
public Mono<AlbumEntity> updateAlbumName(String albumId, String albumName, String requestMemberId) {
return albumRepository
.findById(albumId)
Expand All @@ -66,6 +70,7 @@ public Mono<AlbumEntity> updateAlbumName(String albumId, String albumName, Strin
});
}

@Transactional
public Mono<AlbumEntity> updateAlbumType(String albumId, AlbumType albumType, String requestMemberId) {
return albumRepository
.findById(albumId)
Expand All @@ -80,6 +85,7 @@ public Mono<AlbumEntity> updateAlbumType(String albumId, AlbumType albumType, St
});
}

@Transactional
public Mono<Void> increaseAlbumPhotoCount(String albumId, String requestMemberId) {
return albumRepository
.findById(albumId)
Expand All @@ -94,6 +100,7 @@ public Mono<Void> increaseAlbumPhotoCount(String albumId, String requestMemberId
});
}

@Transactional
public Mono<Void> decreaseAlbumPhotoCount(String albumId, String requestMemberId) {

if (albumId == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@
import kr.mafoo.photo.repository.PhotoRepository;
import kr.mafoo.photo.util.IdGenerator;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@Slf4j
@RequiredArgsConstructor
@Service
public class PhotoService {
Expand All @@ -21,6 +24,7 @@ public class PhotoService {
private final QrService qrService;
private final ObjectStorageService objectStorageService;

@Transactional
public Mono<PhotoEntity> createNewPhoto(String qrUrl, String requestMemberId) {
return qrService
.getFileFromQrUrl(qrUrl)
Expand All @@ -37,7 +41,7 @@ public Flux<PhotoEntity> findAllByAlbumId(String albumId, String requestMemberId
.findById(albumId)
.switchIfEmpty(Mono.error(new AlbumNotFoundException()))
.flatMapMany(albumEntity -> {
if(!albumEntity.getOwnerMemberId().equals(requestMemberId)) {
if (!albumEntity.getOwnerMemberId().equals(requestMemberId)) {
// 내 앨범이 아니면 그냥 없는 앨범 처리
return Mono.error(new AlbumNotFoundException());
} else {
Expand All @@ -46,12 +50,13 @@ public Flux<PhotoEntity> findAllByAlbumId(String albumId, String requestMemberId
});
}

@Transactional
public Mono<Void> deletePhotoById(String photoId, String requestMemberId) {
return photoRepository
.findById(photoId)
.switchIfEmpty(Mono.error(new PhotoNotFoundException()))
.flatMap(photoEntity -> {
if(!photoEntity.getOwnerMemberId().equals(requestMemberId)) {
if (!photoEntity.getOwnerMemberId().equals(requestMemberId)) {
// 내 사진이 아니면 그냥 없는 사진 처리
return Mono.error(new PhotoNotFoundException());
} else {
Expand All @@ -61,20 +66,26 @@ public Mono<Void> deletePhotoById(String photoId, String requestMemberId) {
});
}

@Transactional
public Mono<PhotoEntity> updatePhotoAlbumId(String photoId, String albumId, String requestMemberId) {
return photoRepository
.findById(photoId)
.switchIfEmpty(Mono.error(new PhotoNotFoundException()))
.flatMap(photoEntity -> {
if(!photoEntity.getOwnerMemberId().equals(requestMemberId)) {

if (!photoEntity.hasOwnerMemberId()) {
photoRepository.save(photoEntity.updateOwnerMemberId(requestMemberId));
}

if (!photoEntity.getOwnerMemberId().equals(requestMemberId)) {
// 내 사진이 아니면 그냥 없는 사진 처리
return Mono.error(new PhotoNotFoundException());
} else {
return albumRepository
.findById(albumId)
.switchIfEmpty(Mono.error(new AlbumNotFoundException()))
.flatMap(albumEntity -> {
if(!albumEntity.getOwnerMemberId().equals(requestMemberId)) {
if (!albumEntity.getOwnerMemberId().equals(requestMemberId)) {
// 내 앨범이 아니면 그냥 없는 앨범 처리
return Mono.error(new AlbumNotFoundException());
} else {
Expand Down
148 changes: 25 additions & 123 deletions photo-service/src/main/java/kr/mafoo/photo/service/QrService.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,150 +2,52 @@

import kr.mafoo.photo.domain.BrandType;
import kr.mafoo.photo.exception.PhotoBrandNotExistsException;
import kr.mafoo.photo.exception.PhotoQrUrlExpiredException;
import kr.mafoo.photo.exception.RedirectUriNotFoundException;
import kr.mafoo.photo.service.dto.FileDto;
import kr.mafoo.photo.service.vendors.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;

@Slf4j
@RequiredArgsConstructor
@Service
public class QrService {

private final WebClient externalWebClient;
private final LifeFourCutsQrVendor lifeFourCutsQrVendor;
private final PhotoismQrVendor photoismQrVendor;
private final DontLookUpQrVendor dontLookUpQrVendor;
private final HaruFilmQrVendor haruFilmQrVendor;
private final MyFourCutQrVendor myFourCutQrVendor;
private final PhotoGrayQrVendor photoGrayQrVendor;
private final MonoMansionQrVendor monoMansionQrVendor;
private final PhotoSignatureQrVendor photoSignatureQrVendor;
private final PicDotQrVendor picDotQrVendor;
private final MafooQrVendor mafooQrVendor;


public Mono<FileDto> getFileFromQrUrl(String qrUrl) {
BrandType brandType = Optional.ofNullable(BrandType.matchBrandType(qrUrl))
.orElseThrow(PhotoBrandNotExistsException::new);

return switch (brandType) {
case LIFE_FOUR_CUTS -> createFileDto(brandType, getLifeFourCutsFiles(qrUrl));
case PHOTOISM -> createFileDto(brandType, getPhotoismFiles(qrUrl));
case HARU_FILM -> createFileDto(brandType, getHaruFilmFiles(qrUrl));
case DONT_LOOK_UP -> createFileDto(brandType, getDontLookUpFiles(qrUrl));
QrVendor qrVendor = switch (brandType) {
case LIFE_FOUR_CUTS -> lifeFourCutsQrVendor;
case PHOTOISM -> photoismQrVendor;
case HARU_FILM -> haruFilmQrVendor;
case DONT_LOOK_UP -> dontLookUpQrVendor;
case MY_FOUR_CUT -> myFourCutQrVendor;
case PHOTOGRAY -> photoGrayQrVendor;
case MONOMANSION -> monoMansionQrVendor;
case PHOTO_SIGNATURE -> photoSignatureQrVendor;
case PICDOT -> picDotQrVendor;
case MAFOO -> mafooQrVendor;
};

return createFileDto(brandType, qrVendor.extractImageFromQrUrl(qrUrl));
}

private Mono<FileDto> createFileDto(BrandType brandType, Mono<byte[]> fileMono) {
return fileMono.map(file -> new FileDto(brandType, file));
}

private Mono<byte[]> getLifeFourCutsFiles(String qrUrl) {

return getRedirectUri(qrUrl)
.flatMap(redirectUri -> {
String imageUrl = extractValueFromUrl(redirectUri, "path=")[1].replace("index.html", "image.jpg");

// TODO : 추후 비디오 URL 추가 예정
// String videoUrl = redirectUri.toString().replace("index.html", "video.mp4");

return getFileAsByte(imageUrl);
})
.onErrorMap(e -> new PhotoQrUrlExpiredException());
}

private Mono<byte[]> getPhotoismFiles(String qrUrl) {
return getRedirectUri(qrUrl)
.flatMap(redirectUri -> {
String uid = extractValueFromUrl(redirectUri, "u=")[1];

return externalWebClient
.post()
.uri("https://cmsapi.seobuk.kr/v1/etc/seq/resource")
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(Map.of("uid", uid))
.retrieve()
.bodyToMono(LinkedHashMap.class)
.flatMap(responseBody -> {
LinkedHashMap<String, Object> content = (LinkedHashMap<String, Object>) responseBody.get("content");
LinkedHashMap<String, Object> fileInfo = (LinkedHashMap<String, Object>) content.get("fileInfo");
LinkedHashMap<String, Object> picFile = (LinkedHashMap<String, Object>) fileInfo.get("picFile");
String imageUrl = (String) picFile.get("path");

return getFileAsByte(imageUrl);
});
})
.onErrorMap(e -> {
e.printStackTrace();
return new PhotoQrUrlExpiredException();
});
}

private Mono<byte[]> getHaruFilmFiles(String qrUrl) {
String[] urlValueList = extractValueFromUrl(qrUrl, "/@");
String albumCode = urlValueList[1];

String baseUrl = urlValueList[0] + "/base_api?command=albumdn&albumCode=";
String imageUrl = baseUrl + albumCode + "&type=photo&file_name=output.jpg&max=10&limit=+24 hours";

// TODO : 추후 비디오 URL 추가 예정
// String videoUrl = baseUrl + albumCode + "&type=video&max=10&limit=+24 hours";

return getFileAsByte(imageUrl)
.onErrorMap(e -> new PhotoQrUrlExpiredException());
}

private Mono<byte[]> getDontLookUpFiles(String qrUrl) {
String imageName = extractValueFromUrl(qrUrl, ".kr/image/")[1];

String baseUrl = "https://x.dontlxxkup.kr/uploads/";
String imageUrl = baseUrl + imageName;

// TODO : 추후 비디오 URL 추가 예정
// String videoName = imageName.replace("image", "video").replace(".jpg", ".mp4");
// String videoUrl = baseUrl + videoName;

return getRedirectUri(qrUrl)
.flatMap(redirectUri -> {
if (redirectUri.endsWith("/delete")) {
return Mono.error(new PhotoQrUrlExpiredException());
} else {
return getFileAsByte(imageUrl);
}
})
.onErrorResume(
RedirectUriNotFoundException.class, e -> getFileAsByte(imageUrl)
);
}

private Mono<String> getRedirectUri(String url) {
return externalWebClient
.get()
.uri(url)
.retrieve()
.toBodilessEntity()
.flatMap(response -> {
URI redirectUri = response.getHeaders().getLocation();
if (redirectUri == null) {
return Mono.error(new RedirectUriNotFoundException());
} else {
return Mono.just(redirectUri.toString());
}
});
}

private String[] extractValueFromUrl(String url, String delimiter) {
return url.split(delimiter);
}

private Mono<byte[]> getFileAsByte(String url) {
return externalWebClient
.get()
.uri(url)
.accept(MediaType.APPLICATION_OCTET_STREAM)
.retrieve()
.bodyToMono(byte[].class);
}


}
Loading

0 comments on commit 7d5821b

Please sign in to comment.