Skip to content
This repository has been archived by the owner on Jul 29, 2024. It is now read-only.

Commit

Permalink
Merge branch 'develop' into feature/toast-251
Browse files Browse the repository at this point in the history
  • Loading branch information
nangkyeonglim authored Aug 16, 2023
2 parents 1f38c86 + 40b1c2d commit 6913f51
Show file tree
Hide file tree
Showing 68 changed files with 873 additions and 307 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/deploy-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ jobs:
echo "TISTORY_CLIENT_SECRET=${{ secrets.TISTORY_CLIENT_SECRET }}" >> .env
echo "NOTION_CLIENT_ID=${{ secrets.NOTION_CLIENT_ID }}" >> .env
echo "NOTION_CLIENT_SECRET=${{ secrets.NOTION_CLIENT_SECRET }}" >> .env
echo "JWT_SECRET_KET=${{ secrets.JWT_SECRET_KEY }}" >> .env
echo "ACCESS_TOKEN_EXPIRE=${{ secrets.ACCESS_TOKEN_EXPIRE_LENGTH }}" >> .env
echo "JWT_SECRET_KEY=${{ secrets.JWT_SECRET_KEY }}" >> .env
echo "ACCESS_TOKEN_EXPIRE_LENGTH=${{ secrets.ACCESS_TOKEN_EXPIRE_LENGTH }}" >> .env
echo "REFRESH_TOKEN_EXPIRE_LENGTH=${{ secrets.REFRESH_TOKEN_EXPIRE_LENGTH }}" >> .env
## deploy to production
- name: Deploy to prod
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/deploy-prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ jobs:
echo "TISTORY_CLIENT_SECRET=${{ secrets.TISTORY_CLIENT_SECRET }}" >> .env
echo "NOTION_CLIENT_ID=${{ secrets.NOTION_CLIENT_ID }}" >> .env
echo "NOTION_CLIENT_SECRET=${{ secrets.NOTION_CLIENT_SECRET }}" >> .env
echo "JWT_SECRET_KET=${{ secrets.JWT_SECRET_KEY }}" >> .env
echo "ACCESS_TOKEN_EXPIRE=${{ secrets.ACCESS_TOKEN_EXPIRE_LENGTH }}" >> .env
echo "JWT_SECRET_KEY=${{ secrets.JWT_SECRET_KEY }}" >> .env
echo "ACCESS_TOKEN_EXPIRE_LENGTH=${{ secrets.ACCESS_TOKEN_EXPIRE_LENGTH }}" >> .env
echo "REFRESH_TOKEN_EXPIRE_LENGTH=${{ secrets.REFRESH_TOKEN_EXPIRE_LENGTH }}" >> .env
## deploy to production
- name: Deploy to prod
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.donggle.backend.application.repository;

import org.donggle.backend.domain.category.Category;
import org.donggle.backend.domain.category.CategoryName;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
Expand All @@ -18,6 +19,8 @@ public interface CategoryRepository extends JpaRepository<Category, Long> {

Optional<Category> findFirstByMemberId(final Long memberId);

boolean existsByCategoryName(final CategoryName categoryName);

@Query("select c from Category c " +
"where c.nextCategory.id = :categoryId")
Optional<Category> findPreCategoryByCategoryId(@Param("categoryId") final Long categoryId);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package org.donggle.backend.application.repository;

import org.donggle.backend.auth.JwtToken;
import org.donggle.backend.auth.RefreshToken;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;

public interface TokenRepository extends JpaRepository<JwtToken, Long> {
Optional<JwtToken> findByMemberId(final Long memberId);
public interface TokenRepository extends JpaRepository<RefreshToken, Long> {
Optional<RefreshToken> findByMemberId(final Long memberId);

void deleteByMemberId(Long memberId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import org.donggle.backend.application.repository.MemberRepository;
import org.donggle.backend.application.repository.TokenRepository;
import org.donggle.backend.application.service.oauth.kakao.dto.KakaoProfileResponse;
import org.donggle.backend.auth.JwtTokenProvider;
import org.donggle.backend.auth.JwtTokenService;
import org.donggle.backend.auth.exception.NoSuchTokenException;
import org.donggle.backend.auth.RefreshToken;
import org.donggle.backend.domain.member.Member;
import org.donggle.backend.domain.member.MemberName;
import org.donggle.backend.exception.notfound.MemberNotFoundException;
import org.donggle.backend.ui.response.TokenResponse;
import org.springframework.stereotype.Service;

Expand All @@ -18,7 +19,7 @@
public class AuthService {
private final MemberRepository memberRepository;
private final JwtTokenProvider jwtTokenProvider;
private final JwtTokenService jwtTokenService;
private final TokenRepository tokenRepository;

public TokenResponse loginByKakao(final KakaoProfileResponse kakaoProfileResponse) {
final Member loginMember = memberRepository.findByKakaoId(kakaoProfileResponse.id())
Expand All @@ -30,8 +31,8 @@ public TokenResponse loginByKakao(final KakaoProfileResponse kakaoProfileRespons
}

public TokenResponse reissueAccessTokenAndRefreshToken(final Long memberId) {
final Member member = memberRepository.findById(memberId).
orElseThrow(NoSuchTokenException::new);
final Member member = memberRepository.findById(memberId)
.orElseThrow(() -> new MemberNotFoundException(memberId));

return createTokens(member);
}
Expand All @@ -40,8 +41,23 @@ private TokenResponse createTokens(final Member loginMember) {
final String accessToken = jwtTokenProvider.createAccessToken(loginMember.getId());
final String refreshToken = jwtTokenProvider.createRefreshToken(loginMember.getId());

jwtTokenService.synchronizeRefreshToken(loginMember, refreshToken);
synchronizeRefreshToken(loginMember, refreshToken);

return new TokenResponse(accessToken, refreshToken);
}

public void logout(final Long memberId) {
final Member member = memberRepository.findById(memberId)
.orElseThrow(() -> new MemberNotFoundException(memberId));

tokenRepository.deleteByMemberId(member.getId());
}

private void synchronizeRefreshToken(final Member member, final String refreshToken) {
tokenRepository.findByMemberId(member.getId())
.ifPresentOrElse(
token -> token.update(refreshToken),
() -> tokenRepository.save(new RefreshToken(refreshToken, member))
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@
import org.donggle.backend.domain.category.CategoryName;
import org.donggle.backend.domain.member.Member;
import org.donggle.backend.domain.writing.Writing;
import org.donggle.backend.exception.business.DuplicateCategoryNameException;
import org.donggle.backend.exception.business.EmptyCategoryNameException;
import org.donggle.backend.exception.business.InvalidBasicCategoryException;
import org.donggle.backend.exception.business.OverLengthCategoryNameException;
import org.donggle.backend.exception.notfound.CategoryNotFoundException;
import org.donggle.backend.exception.notfound.MemberNotFoundException;
import org.donggle.backend.ui.response.CategoryListResponse;
Expand Down Expand Up @@ -41,13 +44,27 @@ public class CategoryService {
public Long addCategory(final Long memberId, final CategoryAddRequest request) {
//TODO: member checking
final Member findMember = findMember(memberId);
final Category category = Category.of(new CategoryName(request.categoryName()), findMember);
final CategoryName categoryName = new CategoryName(request.categoryName());
validateCategoryName(categoryName);
final Category category = Category.of(categoryName, findMember);
final Category lastCategory = findLastCategoryByMemberId(memberId);
final Category savedCategory = categoryRepository.save(category);
lastCategory.changeNextCategory(savedCategory);
return savedCategory.getId();
}

private void validateCategoryName(final CategoryName categoryName) {
if (categoryRepository.existsByCategoryName(categoryName)) {
throw new DuplicateCategoryNameException(categoryName.getName());
}
if (categoryName.isBlank()) {
throw new EmptyCategoryNameException();
}
if (categoryName.isOverLength()) {
throw new OverLengthCategoryNameException();
}
}

@Transactional(readOnly = true)
public CategoryListResponse findAll(final Long memberId) {
//TODO: member checking
Expand Down Expand Up @@ -115,14 +132,18 @@ private List<Writing> sortWriting(final List<Writing> findWritings, Writing targ
public void modifyCategoryName(final Long memberId, final Long categoryId, final CategoryModifyRequest request) {
//TODO: member checking
final Category findCategory = findCategory(categoryId);
validateBasicCategory(findCategory);
findCategory.changeName(new CategoryName(request.categoryName()));
validateBasicCategory(memberId, findCategory);

final CategoryName categoryName = new CategoryName(request.categoryName());
validateCategoryName(categoryName);

findCategory.changeName(categoryName);
}

public void removeCategory(final Long memberId, final Long categoryId) {
//TODO: member checking
final Category findCategory = findCategory(categoryId);
validateBasicCategory(findCategory);
validateBasicCategory(memberId, findCategory);
transferToBasicCategory(memberId, findCategory);
deleteCategory(findCategory);
}
Expand Down Expand Up @@ -156,7 +177,7 @@ private void deleteCategory(final Category findCategory) {
public void modifyCategoryOrder(final Long memberId, final Long categoryId, final CategoryModifyRequest request) {
final Long nextCategoryId = request.nextCategoryId();
final Category source = findCategory(categoryId);
validateBasicCategory(source);
validateBasicCategory(memberId, source);
deleteCategoryOrder(source);
addCategoryOrder(nextCategoryId, source, memberId);
}
Expand All @@ -182,9 +203,11 @@ private void addCategoryOrder(final Long nextCategoryId, final Category category
}
}

private void validateBasicCategory(final Category category) {
if (category.isBasic()) {
throw new InvalidBasicCategoryException();
private void validateBasicCategory(final Long memberId, final Category category) {
final Category basicCategory = categoryRepository.findFirstByMemberId(memberId)
.orElseThrow(IllegalStateException::new);
if (basicCategory.equals(category)) {
throw new InvalidBasicCategoryException(category.getId());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import org.donggle.backend.application.service.vendor.medium.dto.response.MediumPublishResponse;
import org.donggle.backend.application.service.vendor.tistory.TistoryApiService;
import org.donggle.backend.application.service.vendor.tistory.dto.request.TistoryPublishRequest;
import org.donggle.backend.application.service.vendor.tistory.dto.response.TistoryPublishWritingResponse;
import org.donggle.backend.application.service.vendor.tistory.dto.response.TistoryGetWritingResponseWrapper;
import org.donggle.backend.domain.blog.Blog;
import org.donggle.backend.domain.blog.BlogType;
import org.donggle.backend.domain.blog.BlogWriting;
Expand Down Expand Up @@ -84,7 +84,7 @@ private MediumPublishRequest buildMediumRequest(final Member member, final Publi

private BlogWriting createBlogWritingAfterTistoryPublish(final PublishRequest publishRequest, final Member member, final Blog blog, final Writing writing, final String content) {
final TistoryPublishRequest request = buildTistoryRequest(member, publishRequest, writing, content);
final TistoryPublishWritingResponse response = tistoryApiService.publishContent(request);
final TistoryGetWritingResponseWrapper response = tistoryApiService.publishContent(request);
return new BlogWriting(blog, writing, response.getDateTime(), response.getTags());
}

Expand All @@ -93,7 +93,7 @@ private TistoryPublishRequest buildTistoryRequest(final Member member, final Pub
final MemberCredentials memberCredentials = memberCredentialsRepository.findMemberCredentialsByMember(member).orElseThrow();
//TODO TistoryBlogName ๋ชป์ฐพ์€ ์˜ˆ์™ธ ๋ฐœ์ƒ์‹œํ‚ค๊ธฐ
final String tistoryToken = memberCredentials.getTistoryToken();
final String tistoryBlogName = memberCredentials.getTistoryBlogName();
final String tistoryBlogName = tistoryApiService.getDefaultTistoryBlogName(tistoryToken);
return TistoryPublishRequest.builder()
.access_token(tistoryToken)
.blogName(tistoryBlogName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public Long uploadMarkDownFile(final Long memberId, final MarkdownUploadRequest
//TODO: member checking
final String originalFilename = request.file().getOriginalFilename();
if (!Objects.requireNonNull(originalFilename).endsWith(MD_FORMAT)) {
throw new InvalidFileFormatException();
throw new InvalidFileFormatException(originalFilename);
}
final String originalFileText = new String(request.file().getBytes(), StandardCharsets.UTF_8);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package org.donggle.backend.application.service.request;

import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.NotBlank;

public record CategoryAddRequest(
@NotNull(message = "์นดํ…Œ๊ณ ๋ฆฌ ์ด๋ฆ„์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.")
@NotBlank(message = "์นดํ…Œ๊ณ ๋ฆฌ ์ด๋ฆ„์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.")
String categoryName
) {
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
package org.donggle.backend.application.service.request;

public record CategoryModifyRequest(String categoryName, Long nextCategoryId) {
public record CategoryModifyRequest(
String categoryName,
Long nextCategoryId) {
}
Original file line number Diff line number Diff line change
@@ -1,69 +1,85 @@
package org.donggle.backend.application.service.vendor.tistory;

import org.donggle.backend.application.service.vendor.exception.VendorApiInternalServerError;
import org.donggle.backend.application.service.vendor.tistory.dto.TistoryBlogInfoResponseWrapper;
import org.donggle.backend.application.service.vendor.tistory.dto.TistoryBlogResponse;
import org.donggle.backend.application.service.vendor.tistory.dto.request.TistoryPublishPropertyRequest;
import org.donggle.backend.application.service.vendor.tistory.dto.request.TistoryPublishRequest;
import org.donggle.backend.application.service.vendor.tistory.dto.response.TistoryPublishStatusResponse;
import org.donggle.backend.application.service.vendor.tistory.dto.response.TistoryPublishWritingResponse;
import org.donggle.backend.application.service.vendor.tistory.dto.response.TistoryResponse;
import org.donggle.backend.application.service.vendor.tistory.dto.response.TistoryGetWritingResponseWrapper;
import org.donggle.backend.application.service.vendor.tistory.dto.response.TistoryPublishWritingResponseWrapper;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.util.UriComponentsBuilder;

import static org.donggle.backend.application.service.vendor.exception.VendorApiException.handle4xxException;

public class TistoryApiService {
public static final String PLATFORM_NAME = "Tistory";
private static final String TISTORY_URL = "https://www.tistory.com/apis";
private static final int OK = 200;

private final WebClient webClient;

public TistoryApiService() {
this.webClient = WebClient.create(TISTORY_URL);
}

public TistoryPublishWritingResponse publishContent(final TistoryPublishRequest request) {
final TistoryPublishStatusResponse response = webClient.post()
public TistoryGetWritingResponseWrapper publishContent(final TistoryPublishRequest request) {
final TistoryPublishWritingResponseWrapper response = webClient.post()
.uri("/post/write?")
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(request)
.retrieve()
.onStatus(HttpStatusCode::is4xxClientError, clientResponse -> handle4xxException(clientResponse.statusCode().value(), PLATFORM_NAME))
.onStatus(HttpStatusCode::is5xxServerError, clientResponse -> clientResponse.bodyToMono(String.class)
.map(e -> new VendorApiInternalServerError(PLATFORM_NAME)))
.bodyToMono(TistoryPublishStatusResponse.class)
.bodyToMono(TistoryPublishWritingResponseWrapper.class)
.block();
validateResponse(response);

return findPublishProperty(makeTistoryPublishPropertyRequest(request, response));
}

private TistoryPublishPropertyRequest makeTistoryPublishPropertyRequest(final TistoryPublishRequest request, final TistoryPublishStatusResponse response) {
private TistoryPublishPropertyRequest makeTistoryPublishPropertyRequest(final TistoryPublishRequest request, final TistoryPublishWritingResponseWrapper response) {
return TistoryPublishPropertyRequest.builder()
.access_token(request.access_token())
.postId(response.tistory().postId())
.blogName(request.blogName())
.blogName(getDefaultTistoryBlogName(request.access_token()))
.build();
}

private void validateResponse(final TistoryResponse response) {
if (response.getStatus() != OK) {
throw new IllegalArgumentException("๋ธ”๋กœ๊ทธ๋กœ ๋ฐœํ–‰์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.");
}
public String getDefaultTistoryBlogName(final String access_token) {
final String blogInfoUri = UriComponentsBuilder.fromUriString(TISTORY_URL)
.path("/blog/info")
.queryParam("access_token", access_token)
.queryParam("output", "json")
.build()
.toUriString();
final TistoryBlogInfoResponseWrapper blogInfo = webClient.get()
.uri(blogInfoUri)
.retrieve()
.bodyToMono(TistoryBlogInfoResponseWrapper.class)
.block();
return blogInfo.tistory().item().blogs().stream()
.filter(blog -> blog.defaultValue().equals("Y"))
.map(TistoryBlogResponse::name)
.findFirst()
.orElseThrow();
}

public TistoryPublishWritingResponse findPublishProperty(final TistoryPublishPropertyRequest request) {
public TistoryGetWritingResponseWrapper findPublishProperty(final TistoryPublishPropertyRequest request) {
final String publishPropertyUri = UriComponentsBuilder.fromUriString("/post/read")
.queryParam("access_token", request.access_token())
.queryParam("blogName", request.blogName())
.queryParam("postId", request.postId())
.queryParam("output", "json")
.build()
.toUriString();
return webClient.get()
.uri("/post/read?" +
"access_token=" + request.access_token() +
"&blogName=" + request.blogName() +
"&postId=" + request.postId() +
"&output=json")
.uri(publishPropertyUri)
.retrieve()
.onStatus(HttpStatusCode::is4xxClientError, clientResponse -> handle4xxException(clientResponse.statusCode().value(), PLATFORM_NAME))
.onStatus(HttpStatusCode::is5xxServerError, clientResponse -> clientResponse.bodyToMono(String.class)
.map(e -> new VendorApiInternalServerError(PLATFORM_NAME)))
.bodyToMono(TistoryPublishWritingResponse.class)
.bodyToMono(TistoryGetWritingResponseWrapper.class)
.block();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.donggle.backend.application.service.vendor.tistory.dto;

import java.util.List;

public record TistoryBlogInfoResponse(
String id,
Long userId,
List<TistoryBlogResponse> blogs
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.donggle.backend.application.service.vendor.tistory.dto;

import org.donggle.backend.application.service.vendor.tistory.dto.response.TistoryItemResponse;

public record TistoryBlogInfoResponseWrapper(
TistoryItemResponse<TistoryBlogInfoResponse> tistory
) {
}
Loading

0 comments on commit 6913f51

Please sign in to comment.