Skip to content

Commit

Permalink
Merge pull request #115 from KCY-Fit-a-Pet/hotfix/111
Browse files Browse the repository at this point in the history
🔧 (개발 회의 안건) 프론트엔드 요구 사항 픽스
  • Loading branch information
heejinnn authored Feb 18, 2024
2 parents 4467d86 + e9c6003 commit e9351d5
Show file tree
Hide file tree
Showing 21 changed files with 149 additions and 99 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/kakao_ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ jobs:

- name: run kakao-chat at macOS
if: runner.os == 'macOS'
uses: psychology50/kakao-chat-ci@v1.8
uses: psychology50/kakao-chat-ci@v1.6
env:
KAKAO_CLIENT: ${{ secrets.KAKAO_CLIENT }}
KAKAO_EMAIL: ${{ secrets.KAKAO_EMAIL }}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package kr.co.fitapet.api.apis.auth.dto;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;

Expand All @@ -17,8 +20,12 @@ public record SmsRes(
@Schema(description = "수신자 번호")
String to,
@Schema(description = "발송 시간")
@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
LocalDateTime sendTime,
@Schema(description = "만료 시간 (default: 3분)", example = "2021-08-01T00:00:00")
@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
LocalDateTime expireTime
) {
public static SmsRes of(String to, LocalDateTime sendTime, LocalDateTime expireTime) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import kr.co.fitapet.api.apis.memo.dto.MemoPatchReq;
import kr.co.fitapet.api.apis.memo.dto.MemoCategorySaveRes;
import kr.co.fitapet.api.apis.memo.dto.MemoUpdateReq;
import kr.co.fitapet.api.apis.memo.usecase.MemoUseCase;
import kr.co.fitapet.api.common.response.SuccessResponse;
import kr.co.fitapet.domain.domains.memo.dto.MemoInfoDto;
import kr.co.fitapet.domain.domains.memo.dto.MemoSaveReq;
import kr.co.fitapet.api.apis.memo.dto.MemoSaveReq;
import kr.co.fitapet.api.apis.memo.dto.SubMemoCategorySaveReq;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.PageableDefault;
import org.springframework.data.web.SortDefault;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
Expand All @@ -43,10 +43,11 @@ public ResponseEntity<?> saveSubMemoCategory(
@PathVariable("root_memo_category_id") Long rootMemoCategoryId,
@RequestBody @Valid SubMemoCategorySaveReq req
) {
memoUseCase.saveSubMemoCategory(petId, rootMemoCategoryId, req);
return ResponseEntity.status(HttpStatus.CREATED).body(SuccessResponse.noContent());
MemoCategorySaveRes res = memoUseCase.saveSubMemoCategory(petId, rootMemoCategoryId, req);
return ResponseEntity.ok(SuccessResponse.from(res));
}

@Deprecated(since = "2024-02-18")
@Operation(summary = "메모 카테고리 리스트 조회", description = "메모 카테고리 타입이 root인 경우, 서브 메모 카테고리 리스트도 함께 조회합니다.")
@Parameters({
@Parameter(name = "pet_id", description = "반려동물 ID", in = ParameterIn.PATH, required = true),
Expand Down Expand Up @@ -155,8 +156,7 @@ public ResponseEntity<?> saveMemo(
@PathVariable("memo_category_id") Long memoCategoryId,
@RequestBody @Valid MemoSaveReq req
) {
memoUseCase.saveMemo(memoCategoryId, req);
return ResponseEntity.status(HttpStatus.CREATED).body(SuccessResponse.noContent());
return ResponseEntity.ok(SuccessResponse.from(memoUseCase.saveMemo(memoCategoryId, req)));
}

@Operation(summary = "메모 삭제")
Expand All @@ -182,15 +182,16 @@ public ResponseEntity<?> deleteMemo(
@Parameter(name = "memo_category_id", description = "메모 카테고리 ID", in = ParameterIn.PATH, required = true),
@Parameter(name = "memo_id", description = "메모 ID", in = ParameterIn.PATH, required = true)
})
@PatchMapping("/memo-categories/{memo_category_id}/memos/{memo_id}")
@PreAuthorize("isAuthenticated() and @managerAuthorize.isManager(principal.userId, #petId) and @memoAuthorize.isValidMemoCategoryAndMemo(#memoCategoryId, #memoId, #petId)")
public ResponseEntity<?> patchMemo(
@PutMapping("/memo-categories/{memo_category_id}/memos/{memo_id}")
@PreAuthorize("isAuthenticated() and @managerAuthorize.isManager(principal.userId, #petId) and @memoAuthorize.isValidMemoCategoryAndMemo(#memoCategoryId, #memoId, #petId)" +
"and @memoAuthorize.isValidMemoCategory(#req.memoCategoryId(), #petId)")
public ResponseEntity<?> putMemo(
@PathVariable("pet_id") Long petId,
@PathVariable("memo_category_id") Long memoCategoryId,
@PathVariable("memo_id") Long memoId,
@RequestBody @Valid MemoPatchReq req
@RequestBody @Valid MemoUpdateReq req
) {
memoUseCase.patchMemo(memoId, req);
memoUseCase.updateMemo(memoId, req);
return ResponseEntity.ok(SuccessResponse.noContent());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package kr.co.fitapet.api.apis.memo.dto;

import kr.co.fitapet.common.annotation.Dto;

@Dto(name = "memoCategory")
public record MemoCategorySaveRes(
Long memoCategoryId
) {
public static MemoCategorySaveRes valueOf(Long memoCategoryId) {
return new MemoCategorySaveRes(memoCategoryId);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package kr.co.fitapet.domain.domains.memo.dto;
package kr.co.fitapet.api.apis.memo.dto;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package kr.co.fitapet.api.apis.memo.dto;

import kr.co.fitapet.common.annotation.Dto;

@Dto(name = "memo")
public record MemoSaveRes(
Long memoId
) {
public static MemoSaveRes valueOf(Long memoId) {
return new MemoSaveRes(memoId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package kr.co.fitapet.api.apis.memo.dto;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import kr.co.fitapet.domain.domains.memo.domain.Memo;

import java.util.List;

@Schema(description = "메모 수정 요청")
public record MemoUpdateReq(
@Schema(description = "기록 옮길 카테고리 아이디 (변경 사항 없으면 원래 아이디 값 그대로)", example = "1", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
@NotNull(message = "메모 카테고리 아이디는 필수입니다.")
Long memoCategoryId,
@NotBlank(message = "제목은 필수입니다.")
@Schema(description = "제목", example = "오늘의 일기", requiredMode = Schema.RequiredMode.REQUIRED)
@Size(max = 21, message = "제목은 21자 이하로 입력해주세요.")
String title,
@NotBlank(message = "내용은 필수입니다.")
@Schema(description = "내용", example = "오늘은 매우 행복했다.", requiredMode = Schema.RequiredMode.REQUIRED)
String content,
@NotNull(message = "메모 이미지는 필수입니다. 없으면 빈 배열을 보내주세요.")
@Schema(description = "메모 이미지", example = "[\"https://fitapet.com/image/1.jpg\", \"https://fitapet.com/image/2.jpg\"]", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
List<String> memoImageUrls
) {
public Memo toEntity() {
return Memo.of(title, content);
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
package kr.co.fitapet.api.apis.memo.usecase;

import kr.co.fitapet.api.apis.memo.dto.MemoPatchReq;
import kr.co.fitapet.api.apis.memo.dto.*;
import kr.co.fitapet.common.annotation.UseCase;
import kr.co.fitapet.common.execption.GlobalErrorException;
import kr.co.fitapet.domain.domains.memo.domain.Memo;
import kr.co.fitapet.domain.domains.memo.domain.MemoCategory;
import kr.co.fitapet.domain.domains.memo.domain.MemoImage;
import kr.co.fitapet.domain.domains.memo.dto.MemoCategoryInfoDto;
import kr.co.fitapet.domain.domains.memo.dto.MemoInfoDto;
import kr.co.fitapet.domain.domains.memo.dto.MemoSaveReq;
import kr.co.fitapet.api.apis.memo.dto.SubMemoCategorySaveReq;
import kr.co.fitapet.domain.domains.memo.exception.MemoErrorCode;
import kr.co.fitapet.domain.domains.memo.service.MemoDeleteService;
import kr.co.fitapet.domain.domains.memo.service.MemoSaveService;
import kr.co.fitapet.domain.domains.memo.service.MemoSearchService;
Expand All @@ -36,21 +32,23 @@ public class MemoUseCase {
private final NcpObjectStorageService ncpObjectStorageService;

@Transactional
public void saveSubMemoCategory(Long petId, Long rootMemoCategoryId, SubMemoCategorySaveReq req) {
req.toEntity(memoSearchService.findMemoCategoryById(rootMemoCategoryId), petSearchService.findPetById(petId));
public MemoCategorySaveRes saveSubMemoCategory(Long petId, Long rootMemoCategoryId, SubMemoCategorySaveReq req) {
MemoCategory memoCategory = req.toEntity(memoSearchService.findMemoCategoryById(rootMemoCategoryId), petSearchService.findPetById(petId));
return MemoCategorySaveRes.valueOf(memoSaveService.saveMemoCategory(memoCategory).getId());
}

@Transactional
public void saveMemo(Long MemoCategoryId, MemoSaveReq req) {
public MemoSaveRes saveMemo(Long MemoCategoryId, MemoSaveReq req) {
MemoCategory memoCategory = memoSearchService.findMemoCategoryById(MemoCategoryId);

Memo memo = req.toEntity();
memo.updateMemoCategory(memoCategory);
memoSaveService.saveMemo(memo);

if (req.memoImageUrls() != null) {
memoSaveService.saveMemo(memo);
if (req.memoImageUrls() != null)
req.memoImageUrls().forEach(url -> MemoImage.of(url, memo));
}

return MemoSaveRes.valueOf(memo.getId());
}

@Transactional(readOnly = true)
Expand Down Expand Up @@ -83,31 +81,24 @@ public void deleteMemo(Long memoId) {
}

@Transactional
public void patchMemo(Long memoId, MemoPatchReq req) {
public void updateMemo(Long memoId, MemoUpdateReq req) {
Memo memo = memoSearchService.findMemoById(memoId);
memo.updateMemo(req.toEntity());

if (req.title() != null) {
if (req.title().isBlank()) throw new GlobalErrorException(MemoErrorCode.MEMO_TITLE_NOT_EMPTY);
memo.updateTitle(req.title());
}

if (req.content() != null) {
if (req.content().isBlank()) throw new GlobalErrorException(MemoErrorCode.MEMO_CONTENT_NOT_EMPTY);
memo.updateContent(req.content());
if (!memo.getMemoCategory().getId().equals(req.memoCategoryId())) {
MemoCategory memoCategory = memoSearchService.findMemoCategoryById(req.memoCategoryId());
memo.updateMemoCategory(memoCategory);
log.info("카테고리 이동 {} -> {}", memo.getMemoCategory().getId(), req.memoCategoryId());
}

if (req.removedMemoImageIds() != null) {
List<MemoImage> memoImages = memoSearchService.findMemoImagesByMemoId(memoId);
List<MemoImage> removedMemoImages = memoImages.stream().filter(memoImage -> req.removedMemoImageIds().contains(memoImage.getId())).toList();
log.info("removedMemoImages: {}", removedMemoImages);
List<MemoImage> originalMemoImages = memoSearchService.findMemoImagesByMemoId(memoId);
List<MemoImage> addedMemoImages = req.memoImageUrls().stream().filter(url -> originalMemoImages.stream().noneMatch(memoImage -> memoImage.getImgUrl().equals(url))).map(url -> MemoImage.of(url, memo)).toList();
List<MemoImage> removedMemoImages = originalMemoImages.stream().filter(memoImage -> !req.memoImageUrls().contains(memoImage.getImgUrl())).toList();
log.info("addedMemoImages: {}, removedMemoImages: {}", addedMemoImages, removedMemoImages);

if (!removedMemoImages.isEmpty()) {
memoDeleteService.deleteMemoImages(removedMemoImages);
ncpObjectStorageService.deleteObjects(removedMemoImages.stream().map(MemoImage::getImgUrl).toList());
}

if (req.addedMemoImageUrls() != null) {
log.info("addedMemoImageUrls: {}", req.addedMemoImageUrls());
req.addedMemoImageUrls().forEach(url -> MemoImage.of(url, memo));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,4 @@ public record AccountSearchReq(
public String getNewEncodedPassword(PasswordEncoder passwordEncoder) {
return passwordEncoder.encode(newPassword);
}

@Override
public String newPassword() {
throw new UnsupportedOperationException();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
import kr.co.fitapet.domain.domains.member.dto.MemberInfo;
import kr.co.fitapet.domain.domains.member.dto.UidRes;
import kr.co.fitapet.domain.domains.member.exception.AccountErrorCode;
import kr.co.fitapet.domain.domains.member.exception.AccountErrorException;
import kr.co.fitapet.domain.domains.member.service.MemberSaveService;
import kr.co.fitapet.domain.domains.member.service.MemberSearchService;
import kr.co.fitapet.domain.domains.member.type.MemberAttrType;
import kr.co.fitapet.domain.domains.memo.dto.MemoCategoryInfoDto;
Expand Down Expand Up @@ -93,11 +91,6 @@ public void overwritePassword(AccountSearchReq req, String code, SmsPrefix prefi
validatePhone(req.phone(), code, prefix);
Member member = memberSearchService.findByPhone(req.phone());

if (!StringUtils.hasText(req.newPassword())) {
BaseErrorCode errorCode = AccountErrorCode.INVALID_PASSWORD_REQUEST;
log.warn("비밀번호 변경 실패: {}", errorCode.getExplainError());
throw new GlobalErrorException(errorCode);
}
member.updateEncodedPassword(req.getNewEncodedPassword(bCryptPasswordEncoder));
smsRedisMapper.removeCode(req.phone(), prefix);
}
Expand Down Expand Up @@ -139,7 +132,7 @@ public List<MemoCategoryInfoDto.MemoCategoryInfo> getMemoCategories(Long userId)
List<Long> petIds = memberSearchService.findMyPetIds(userId);
log.info("userId: {}, petIds: {}", userId, petIds);

List<Long> rootMemoCategoryIds = memoSearchService.findRootMemoCategoriesIdByPetIds(petIds);
List<Long> rootMemoCategoryIds = memoSearchService.findRootMemoCategoryIdsByPetIds(petIds);
List<MemoCategoryInfoDto.MemoCategoryInfo> rootMemoCategories = new ArrayList<>();

for (Long rootMemoCategoryId : rootMemoCategoryIds) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package kr.co.fitapet.domain.common.annotation;

import org.springframework.beans.factory.annotation.Qualifier;

import java.lang.annotation.*;

@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD,
ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Qualifier("javaTimeRedisTemplate")
public @interface JavaTimeRedisTemplate {
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package kr.co.fitapet.domain.common.redis.manager;

import jakarta.annotation.Resource;
import kr.co.fitapet.domain.common.annotation.JavaTimeRedisTemplate;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
Expand All @@ -14,7 +15,7 @@ public class ManagerInvitationRepositoryImpl implements ManagerInvitationReposit
private final HashOperations<String, Long, LocalDateTime> ops;
private static final String KEY = "managerInvitation";

public ManagerInvitationRepositoryImpl(RedisTemplate<String, Object> redisTemplate) {
public ManagerInvitationRepositoryImpl(@JavaTimeRedisTemplate RedisTemplate<String, Object> redisTemplate) {
this.ops = redisTemplate.opsForHash();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import kr.co.fitapet.domain.common.annotation.JavaTimeRedisTemplate;
import kr.co.fitapet.domain.common.annotation.RedisCacheConnectionFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
Expand Down Expand Up @@ -46,6 +47,18 @@ public RedisConnectionFactory redisConnectionFactory() {
@Primary
public RedisTemplate<String, ?> redisTemplate() {
RedisTemplate<String, ?> template = new RedisTemplate<>();

template.setConnectionFactory(redisConnectionFactory());

template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
return template;
}

@Bean
@JavaTimeRedisTemplate
public RedisTemplate<String, ?> javaTimeRedisTemplate() {
RedisTemplate<String, ?> template = new RedisTemplate<>();
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,8 @@ public void updateMemoCategory(MemoCategory memoCategory) {
memoCategory.getMemos().add(this);
}

public void updateTitle(String title) {
this.title = title;
}

public void updateContent(String content) {
this.content = content;
public void updateMemo(Memo memo) {
this.title = memo.title;
this.content = memo.content;
}
}
Loading

0 comments on commit e9351d5

Please sign in to comment.