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

[RELEASE] release: 리팩토링 후 첫 릴리즈 배포 #56

Merged
merged 30 commits into from
Aug 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
61e9f7c
feat : add getMyFourCutFiles base codes (#43)
gmkim20713 Jul 20, 2024
6883c71
feat: update uribuilderfactory
CChuYong Jul 20, 2024
c7eac81
feat: add filter predicate for v1/photos
CChuYong Jul 22, 2024
ec8e601
chore: disable zipkin for default
CChuYong Jul 22, 2024
66c81e0
chore: add production application.yaml
CChuYong Jul 22, 2024
8b32eed
Merge pull request #46 from YAPP-Github/feature/#45
CChuYong Jul 22, 2024
5a14063
feat: change kakao auth code to access token
CChuYong Jul 24, 2024
820fd84
feat: add transactional to member
CChuYong Jul 24, 2024
af85ae5
feat: add transactional to photo
CChuYong Jul 24, 2024
d575dae
feat: add photogray brand
CChuYong Jul 24, 2024
d0612f2
feat: implement photogray brand
CChuYong Jul 24, 2024
8df0aee
refactor: move vendor logics to seperate classes
CChuYong Jul 24, 2024
55134f4
feat: add error handling
CChuYong Jul 24, 2024
5ea42f5
Merge pull request #49 from YAPP-Github/hotfix/#48
gmkim20713 Jul 24, 2024
0508c7f
Merge pull request #50 from YAPP-Github/feature/MAFOO-26
gmkim20713 Jul 24, 2024
17cf408
Merge branch 'dev' into feature/MAFOO-25
gmkim20713 Jul 24, 2024
77e2ded
Merge pull request #47 from YAPP-Github/feature/MAFOO-25
CChuYong Jul 25, 2024
0891ae3
feat: add MonoMansion vendor
CChuYong Jul 25, 2024
b4ee0d4
feat: add PhotoSignature vendor
CChuYong Jul 25, 2024
3632075
feat: accept any header
CChuYong Jul 25, 2024
4a46508
feat: add PicDot qr Vendor
CChuYong Jul 25, 2024
a16f704
Merge pull request #51 from YAPP-Github/feature/MAFOO-46
CChuYong Jul 25, 2024
4b20ec0
feat : create updateOwnerMemberId for photo entity
gmkim20713 Jul 27, 2024
a222963
feat : add photo entity ownerMemberId checkout and setting logic if null
gmkim20713 Jul 27, 2024
b54b3f4
refactor: add hasOwnerMemberId in photo service
gmkim20713 Jul 27, 2024
9f6833b
refactor: add hasOwnerMemberId in photo entity
gmkim20713 Jul 28, 2024
e5c460d
Merge pull request #52 from YAPP-Github/MAFOO-38
gmkim20713 Jul 28, 2024
22ee734
feat: add mafoo qr vendor
CChuYong Jul 29, 2024
00bd6e7
feat: update image url
CChuYong Jul 29, 2024
94f2f1c
Merge pull request #53 from YAPP-Github/feature/MAFOO-58
CChuYong Jul 30, 2024
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
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
Loading