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 #87

Merged
merged 5 commits into from
Dec 13, 2024
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 @@ -50,9 +50,14 @@ public Mono<AlbumResponse> createAlbum(
String memberId,
AlbumCreateRequest request
){
if (request.name().equals("SUMONE")) {
if (request.type().equals("SUMONE")) {
throw new RuntimeException(); // should not be happened
}
if(request.sumoneInviteCode() != null) {
return albumService
.addSumoneAlbum(request.name(), request.type(), memberId, request.sumoneInviteCode())
.map(AlbumResponse::fromEntity);
}
return albumService
.addAlbum(request.name(), request.type(), memberId)
.map(AlbumResponse::fromEntity);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import kr.mafoo.photo.domain.enums.AlbumType;
import kr.mafoo.photo.domain.enums.BrandType;
import kr.mafoo.photo.exception.*;
import kr.mafoo.photo.repository.AlbumRepository;
import kr.mafoo.photo.repository.SumoneEventMappingRepository;
import kr.mafoo.photo.service.AlbumCommand;
import kr.mafoo.photo.service.AlbumQuery;
Expand Down Expand Up @@ -46,6 +47,7 @@ public class SumoneController {
private final RecapService recapService;
private final RecapLambdaService recapLambdaService;
private final SumoneEventMappingRepository sumoneEventMappingRepository;
private final AlbumRepository albumRepository;

@Operation(summary = "통계 api")
@GetMapping("/summary")
Expand All @@ -58,21 +60,10 @@ public Mono<SumoneSummaryResponse> getSummary() {
@Transactional
@Operation(summary = "앨범 생성 api")
@PostMapping("/albums")
public Mono<SumoneAlbumResponse> createAlbum(
@RequestBody SumoneAlbumCreateRequest request
) {
if(request.userId() == null || request.userId().isEmpty()) {
return Mono.error(new DomainException(ErrorCode.REQUEST_INPUT_NOT_VALID));
}

return sumoneEventMappingRepository
.findById(request.userId())
.switchIfEmpty(sumoneEventMappingRepository.save(SumoneEventMappingEntity.newEventMember(
request.userId(),
RandomCodeGenerator.generateAlphanumericString(8)
)))
.then(albumCommand.addAlbum(sumoneAlbumCommonName, "SUMONE", sumoneAlbumCommonMemberId, "SUMONE_" + request.userId())
.map(SumoneAlbumResponse::fromEntity));
public Mono<SumoneAlbumResponse> createAlbum() {
return albumCommand
.addAlbum(sumoneAlbumCommonName, "SUMONE", sumoneAlbumCommonMemberId, null)
.map(SumoneAlbumResponse::fromEntity);
}

@Operation(summary = "앨범에 이미지 url 추가")
Expand Down Expand Up @@ -139,15 +130,26 @@ Mono<RecapUrlDto> createRecapVideo(
@RequestBody
SumoneRecapCreateRequest request
) {
if(request.fileUrls().size() < 1 || request.fileUrls().size() > 10) {
if(request.fileUrls().isEmpty() || request.fileUrls().size() > 10) {
return Mono.error(new RecapPhotoCountNotValidException());
}
if(request.userId() == null || request.userId().isEmpty()) {
return Mono.error(new DomainException(ErrorCode.REQUEST_INPUT_NOT_VALID));
}
return albumQuery.findById(albumId).flatMap(album -> {
if(album.getType() != AlbumType.SUMONE) {
return Mono.error(new AlbumNotFoundException());
}
//TODO: add timeout
return recapLambdaService.generateVideo(request.fileUrls());

return sumoneEventMappingRepository
.findById(request.userId())
.switchIfEmpty(sumoneEventMappingRepository.save(SumoneEventMappingEntity.newEventMember(
request.userId(),
RandomCodeGenerator.generateAlphanumericString(8)
)))
.then(albumRepository.save(album.setExternalId("SUMONE_" + request.userId())))
.then(recapLambdaService.generateVideo(request.fileUrls()));
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ public record AlbumCreateRequest(

@MatchEnum(enumClass = AlbumType.class)
@Schema(description = "앨범 타입")
String type
String type,

@Schema(description = "초대 코드")
String sumoneInviteCode
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ public record SumoneRecapCreateRequest(
schema = @Schema(description = "파일 URL 목록"),
arraySchema = @Schema(example = "[\"file_url_1\", \"file_url_2\", \"file_url_3\"]")
)
List<String> fileUrls
List<String> fileUrls,

@Schema(description = "썸원 유저ID")
String userId
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ public AlbumEntity decreasePhotoCount(int count) {
return this;
}

public AlbumEntity setExternalId(String externalId) {
this.externalId = externalId;
return this;
}

public static AlbumEntity newAlbum(String albumId, String albumName, AlbumType albumType, String ownerMemberId, String externalId) {
AlbumEntity album = new AlbumEntity();
album.albumId = albumId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,6 @@ public interface AlbumRepository extends R2dbcRepository<AlbumEntity, String> {
Flux<AlbumEntity> findAllByOwnerMemberIdOrderByAlbumIdDesc(String ownerMemberId, Pageable pageable);

Mono<Long> countAlbumEntityByType(AlbumType albumType);

Flux<AlbumEntity> findAllByExternalId(String externalId);
}
108 changes: 74 additions & 34 deletions photo-service/src/main/java/kr/mafoo/photo/service/AlbumService.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,17 @@

import java.util.Comparator;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;

import kr.mafoo.photo.domain.AlbumEntity;
import kr.mafoo.photo.domain.enums.AlbumType;
import kr.mafoo.photo.domain.enums.BrandType;
import kr.mafoo.photo.exception.AlbumNotFoundException;
import kr.mafoo.photo.exception.AlbumOwnerChangeDeniedException;
import kr.mafoo.photo.exception.SharedMemberNotFoundException;
import kr.mafoo.photo.repository.AlbumRepository;
import kr.mafoo.photo.repository.PhotoRepository;
import kr.mafoo.photo.repository.SumoneEventMappingRepository;
import kr.mafoo.photo.service.dto.AlbumDto;
import kr.mafoo.photo.service.dto.SharedAlbumDto;
import kr.mafoo.photo.service.dto.SharedMemberDto;
Expand All @@ -26,84 +32,118 @@ public class AlbumService {

private final AlbumQuery albumQuery;
private final AlbumCommand albumCommand;
private final AlbumRepository albumRepository;

private final PhotoCommand photoCommand;
private final PhotoRepository photoRepository;


private final AlbumPermissionVerifier albumPermissionVerifier;

private final SharedMemberQuery sharedMemberQuery;
private final MemberService memberService;
private final SharedMemberCommand sharedMemberCommand;

private final SumoneEventMappingRepository sumoneEventMappingRepository;

@Transactional(readOnly = true)
public Flux<AlbumDto> findAlbumListByMemberId(String memberId, String token) {
return Flux.merge(
findOwnedAlbumListByMemberId(memberId),
findSharedAlbumListByMemberId(memberId, token)
findOwnedAlbumListByMemberId(memberId),
findSharedAlbumListByMemberId(memberId, token)
).sort(Comparator.comparing(AlbumDto::createdAt).reversed());
}

private Flux<AlbumDto> findOwnedAlbumListByMemberId(String memberId) {
return albumQuery.findByMemberId(memberId)
.onErrorResume(AlbumNotFoundException.class, ex -> Mono.empty())
.map(AlbumDto::fromOwnedAlbum);
.onErrorResume(AlbumNotFoundException.class, ex -> Mono.empty())
.map(AlbumDto::fromOwnedAlbum);
}

private Flux<AlbumDto> findSharedAlbumListByMemberId(String memberId, String token) {
return sharedMemberQuery.findAllByMemberIdWhereStatusNotRejected(memberId)
.onErrorResume(SharedMemberNotFoundException.class, ex -> Mono.empty())
.concatMap(sharedMember -> albumQuery.findById(sharedMember.getAlbumId())
.flatMap(album -> memberService.getMemberInfoById(album.getOwnerMemberId(), token)
.flatMap(member -> Mono.just(AlbumDto.fromSharedAlbum(album, sharedMember, member)))
)
);
.onErrorResume(SharedMemberNotFoundException.class, ex -> Mono.empty())
.concatMap(sharedMember -> albumQuery.findById(sharedMember.getAlbumId())
.flatMap(album -> memberService.getMemberInfoById(album.getOwnerMemberId(), token)
.flatMap(member -> Mono.just(AlbumDto.fromSharedAlbum(album, sharedMember, member)))
)
);
}

@Transactional(readOnly = true)
public Mono<SharedAlbumDto> findAlbumDetailById(String albumId, String requestMemberId, String token) {
return albumPermissionVerifier.verifyOwnershipOrAccessPermission(albumId, requestMemberId, VIEW_ACCESS)
.flatMap(album -> sharedMemberQuery.findAllByAlbumIdWhereStatusNotRejected(albumId)
.onErrorResume(SharedMemberNotFoundException.class, ex -> Mono.empty())

.flatMap(sharedMember -> memberService.getMemberInfoById(sharedMember.getMemberId(), token)
.map(memberInfo -> SharedMemberDto.fromSharedMember(sharedMember, memberInfo)))
.sort(Comparator.comparing(SharedMemberDto::shareStatus))
.collectList()
.flatMap(sharedMembers -> memberService.getMemberInfoById(album.getOwnerMemberId(), token)
.map(ownerMember -> SharedAlbumDto.fromSharedAlbum(album, ownerMember, sharedMembers))
)

.switchIfEmpty(Mono.just(SharedAlbumDto.fromOwnedAlbum(album)))
);
.flatMap(album -> sharedMemberQuery.findAllByAlbumIdWhereStatusNotRejected(albumId)
.onErrorResume(SharedMemberNotFoundException.class, ex -> Mono.empty())

.flatMap(sharedMember -> memberService.getMemberInfoById(sharedMember.getMemberId(), token)
.map(memberInfo -> SharedMemberDto.fromSharedMember(sharedMember, memberInfo)))
.sort(Comparator.comparing(SharedMemberDto::shareStatus))
.collectList()
.flatMap(sharedMembers -> memberService.getMemberInfoById(album.getOwnerMemberId(), token)
.map(ownerMember -> SharedAlbumDto.fromSharedAlbum(album, ownerMember, sharedMembers))
)

.switchIfEmpty(Mono.just(SharedAlbumDto.fromOwnedAlbum(album)))
);
}

@Transactional
public Mono<AlbumEntity> addAlbum(String albumName, String albumType, String requestMemberId) {
return albumCommand.addAlbum(albumName, albumType, requestMemberId, null);
}

@Transactional
public Mono<AlbumEntity> addSumoneAlbum(String albumName, String albumType, String requestMemberId, String inviteCode) {
AtomicInteger displayIndex = new AtomicInteger(0);
return albumCommand
.addAlbum(albumName, albumType, requestMemberId, null)
.flatMap(album -> sumoneEventMappingRepository
.findByInviteCode(inviteCode)
.switchIfEmpty(Mono.error(new AlbumNotFoundException()))
.flatMap(sumoneEventMappingEntity ->
sumoneEventMappingRepository.delete(sumoneEventMappingEntity).then(Mono.just(sumoneEventMappingEntity)))
.map(entity -> "SUMONE_" + entity.getId())
.flatMapMany(albumRepository::findAllByExternalId)
.flatMap(sumoneAlbum ->
photoRepository.findAllByAlbumIdOrderByCreatedAtAsc(sumoneAlbum.getAlbumId()).flatMap(photo ->
photoCommand.addPhoto(
photo.getPhotoUrl(),
BrandType.EXTERNAL,
album.getAlbumId(),
displayIndex.getAndIncrement(),
requestMemberId
)
)
)
.then(albumQuery.findById(album.getAlbumId()))
.flatMap(newAlbum -> albumCommand.increaseAlbumPhotoCount(newAlbum, displayIndex.get())));
}

@Transactional
public Mono<AlbumEntity> modifyAlbumNameAndType(String albumId, String newAlbumName, String newAlbumType, String requestMemberId) {
return albumPermissionVerifier.verifyOwnershipOrAccessPermission(albumId, requestMemberId, FULL_ACCESS)
.flatMap(album -> albumCommand.modifyAlbumNameAndType(album, newAlbumName, newAlbumType));
.flatMap(album -> albumCommand.modifyAlbumNameAndType(album, newAlbumName, newAlbumType));
}

@Transactional
public Mono<AlbumEntity> modifyAlbumOwnership(String albumId, String newOwnerMemberId, String requestMemberId) {
return albumPermissionVerifier.verifyOwnership(albumId, requestMemberId)
.flatMap(album -> sharedMemberQuery.findByAlbumIdAndMemberIdWhereStatusAccepted(albumId, newOwnerMemberId)
.onErrorResume(SharedMemberNotFoundException.class, ex ->
Mono.error(new AlbumOwnerChangeDeniedException())
)
.flatMap(sharedMemberCommand::removeSharedMember)
.then(albumCommand.modifyAlbumOwnership(album, newOwnerMemberId))
.then(sharedMemberCommand.addSharedMember(albumId, String.valueOf(FULL_ACCESS), Optional.of(ACCEPTED), requestMemberId))
.thenReturn(album)
);
.flatMap(album -> sharedMemberQuery.findByAlbumIdAndMemberIdWhereStatusAccepted(albumId, newOwnerMemberId)
.onErrorResume(SharedMemberNotFoundException.class, ex ->
Mono.error(new AlbumOwnerChangeDeniedException())
)
.flatMap(sharedMemberCommand::removeSharedMember)
.then(albumCommand.modifyAlbumOwnership(album, newOwnerMemberId))
.then(sharedMemberCommand.addSharedMember(albumId, String.valueOf(FULL_ACCESS), Optional.of(ACCEPTED), requestMemberId))
.thenReturn(album)
);
}

@Transactional
public Mono<Void> removeAlbum(String albumId, String requestMemberId) {
return albumPermissionVerifier.verifyOwnership(albumId, requestMemberId)
.flatMap(albumCommand::removeAlbum);
.flatMap(albumCommand::removeAlbum);
}

public Mono<Long> countAlbumByAlbumType(AlbumType albumType) {
Expand Down
12 changes: 9 additions & 3 deletions user-service/src/main/java/kr/mafoo/user/api/MeApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import kr.mafoo.user.annotation.RequestMemberId;
import kr.mafoo.user.controller.dto.request.ChangeNameRequest;
import kr.mafoo.user.controller.dto.response.MemberResponse;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Mono;

@Tag(name = "로그인 사용자 정보 API", description = "현재 토큰 주인의 정보를 다루는 API")
Expand All @@ -26,4 +25,11 @@ Mono<MemberResponse> getMemberWhoRequested(
Mono<Void> deleteMemberWhoRequested(
@RequestMemberId @Parameter(hidden = true) String memberId
);

@Operation(summary = "이름 변경", description = "현재 토큰 주인의 이름을 변경합니다.")
@PostMapping("/name")
Mono<MemberResponse> changeName(
@RequestMemberId @Parameter(hidden = true) String memberId,
@RequestBody ChangeNameRequest name
);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package kr.mafoo.user.controller;

import kr.mafoo.user.api.MeApi;
import kr.mafoo.user.controller.dto.request.ChangeNameRequest;
import kr.mafoo.user.controller.dto.response.MemberResponse;
import kr.mafoo.user.service.MemberService;
import lombok.RequiredArgsConstructor;
Expand All @@ -24,4 +25,11 @@ public Mono<Void> deleteMemberWhoRequested(String memberId) {
return memberService
.quitMemberByMemberId(memberId);
}

@Override
public Mono<MemberResponse> changeName(String memberId, ChangeNameRequest name) {
return memberService
.changeName(memberId, name.name())
.map(MemberResponse::fromEntity);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package kr.mafoo.user.controller.dto.request;

import io.swagger.v3.oas.annotations.media.Schema;

@Schema(description = "이름 변경 요청")
public record ChangeNameRequest(
@Schema(description = "새 이름", example = "염수연")
String name
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,16 @@ public Mono<MemberEntity> createNewMember(String username, String profileImageUr
.then(Mono.just(savedMember))
);
}

@Transactional
public Mono<MemberEntity> changeName(String memberId, String name) {
return memberRepository
.findById(memberId)
.switchIfEmpty(Mono.error(new MemberNotFoundException()))
.map(member -> {
member.setName(name);
return member;
})
.flatMap(memberRepository::save);
}
}
Loading