From f22df6ccc3e00238951f6b028f53ddf81409d7e1 Mon Sep 17 00:00:00 2001 From: Eun-chan Cho Date: Mon, 11 Mar 2024 20:02:45 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20Tistory=20API=20=EC=97=B0=EA=B2=B0=20?= =?UTF-8?q?=EC=A2=85=EB=A3=8C=20(#616)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/tistory/TistoryApiClient.java | 514 ++++++------ .../tistory/TistoryConnectionClient.java | 247 +++--- .../donggle/backend/ui/BlogController.java | 52 +- .../backend/ui/ConnectionController.java | 55 +- .../donggle/backend/ui/PublishController.java | 18 +- .../client/tistory/TistoryApiClientTest.java | 752 +++++++++--------- .../tistory/TistoryConnectionClientTest.java | 214 ++--- .../backend/ui/BlogControllerTest.java | 84 +- .../backend/ui/ConnectionControllerTest.java | 124 +-- .../donggle/backend/ui/ControllerTest.java | 14 +- .../backend/ui/PublishControllerTest.java | 44 +- 11 files changed, 1059 insertions(+), 1059 deletions(-) diff --git a/backend/src/main/java/org/donggle/backend/infrastructure/client/tistory/TistoryApiClient.java b/backend/src/main/java/org/donggle/backend/infrastructure/client/tistory/TistoryApiClient.java index 5689663ef..5d7ef6f60 100644 --- a/backend/src/main/java/org/donggle/backend/infrastructure/client/tistory/TistoryApiClient.java +++ b/backend/src/main/java/org/donggle/backend/infrastructure/client/tistory/TistoryApiClient.java @@ -1,257 +1,257 @@ -package org.donggle.backend.infrastructure.client.tistory; - -import org.donggle.backend.application.client.BlogClient; -import org.donggle.backend.application.repository.MemberCredentialsRepository; -import org.donggle.backend.application.repository.MemberRepository; -import org.donggle.backend.application.service.request.ImageUploadRequest; -import org.donggle.backend.application.service.request.PublishRequest; -import org.donggle.backend.domain.blog.BlogType; -import org.donggle.backend.domain.blog.PublishStatus; -import org.donggle.backend.domain.member.Member; -import org.donggle.backend.domain.member.MemberCredentials; -import org.donggle.backend.exception.business.InvalidPublishRequestException; -import org.donggle.backend.exception.business.NotConnectedException; -import org.donggle.backend.exception.notfound.MemberNotFoundException; -import org.donggle.backend.infrastructure.client.exception.ClientInternalServerError; -import org.donggle.backend.infrastructure.client.tistory.dto.TistoryImageUploadResponseWrapper; -import org.donggle.backend.infrastructure.client.tistory.dto.request.TistoryPublishPropertyRequest; -import org.donggle.backend.infrastructure.client.tistory.dto.request.TistoryPublishRequest; -import org.donggle.backend.infrastructure.client.tistory.dto.response.TistoryBlogNameResponse; -import org.donggle.backend.infrastructure.client.tistory.dto.response.TistoryCategoryListResponseWrapper; -import org.donggle.backend.infrastructure.client.tistory.dto.response.TistoryCategoryListResponseWrapper.TistoryCategoryListResponse.TistoryCategoryResponse; -import org.donggle.backend.infrastructure.client.tistory.dto.response.TistoryGetWritingResponseWrapper; -import org.donggle.backend.infrastructure.client.tistory.dto.response.TistoryPublishWritingResponseWrapper; -import org.donggle.backend.ui.response.ImageUploadResponse; -import org.donggle.backend.ui.response.PublishResponse; -import org.donggle.backend.ui.response.TistoryCategoryListResponse; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.io.buffer.DataBuffer; -import org.springframework.http.HttpStatusCode; -import org.springframework.http.MediaType; -import org.springframework.http.client.MultipartBodyBuilder; -import org.springframework.stereotype.Component; -import org.springframework.web.reactive.function.BodyInserters; -import org.springframework.web.reactive.function.client.WebClient; -import org.springframework.web.util.UriComponentsBuilder; - -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.time.Instant; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import java.util.NoSuchElementException; -import java.util.Objects; - -import static org.donggle.backend.domain.blog.BlogType.TISTORY; -import static org.donggle.backend.infrastructure.client.exception.ClientException.handle4xxException; - -@Component -public class TistoryApiClient implements BlogClient { - private static final String PLATFORM_NAME = "Tistory"; - private static final String TISTORY_URL = "https://www.tistory.com/apis"; - - private final WebClient webClient; - private final MemberRepository memberRepository; - private final MemberCredentialsRepository memberCredentialsRepository; - - @Autowired - public TistoryApiClient(final MemberRepository memberRepository, - final MemberCredentialsRepository memberCredentialsRepository) { - this.memberRepository = memberRepository; - this.webClient = WebClient.create(TISTORY_URL); - this.memberCredentialsRepository = memberCredentialsRepository; - } - - public TistoryApiClient(final MemberRepository memberRepository, - final MemberCredentialsRepository memberCredentialsRepository, - final WebClient webClient) { - this.memberRepository = memberRepository; - this.memberCredentialsRepository = memberCredentialsRepository; - this.webClient = webClient; - } - - @Override - public PublishResponse publish(final String accessToken, final String content, final PublishRequest publishRequest, final String titleValue) { - final TistoryPublishRequest request = makePublishRequest(accessToken, titleValue, content, publishRequest); - 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 ClientInternalServerError(PLATFORM_NAME))) - .bodyToMono(TistoryPublishWritingResponseWrapper.class) - .block(); - return findPublishProperty(makeTistoryPublishPropertyRequest(accessToken, response.tistory().postId())) - .toPublishResponse(); - } - - @Override - public ImageUploadResponse uploadImage(final String accessToken, final ImageUploadRequest imageUploadRequest) { - final MultipartBodyBuilder builder = new MultipartBodyBuilder(); - builder.asyncPart("uploadedfile", imageUploadRequest.imageDataFlux(), DataBuffer.class) - .contentType(imageUploadRequest.mediaType()) - .filename("uploadedfile"); - builder.part("access_token", accessToken); - builder.part("blogName", findDefaultBlogName(accessToken)); - builder.part("output", "json"); - - System.out.println("builder.build() = " + builder.build()); - - final TistoryImageUploadResponseWrapper response = webClient - .post() - .uri("/post/attach") - .contentType(MediaType.MULTIPART_FORM_DATA) - .body(BodyInserters.fromMultipartData(builder.build())) - .retrieve() - .onStatus(HttpStatusCode::is4xxClientError, clientResponse -> handle4xxException(clientResponse.statusCode().value(), PLATFORM_NAME)) - .onStatus(HttpStatusCode::is5xxServerError, clientResponse -> clientResponse.bodyToMono(String.class) - .map(e -> new ClientInternalServerError(PLATFORM_NAME))) - .bodyToMono(TistoryImageUploadResponseWrapper.class) - .block(); - System.out.println("response = " + response); - return response.toImageUploadResponse(); - } - - private TistoryPublishPropertyRequest makeTistoryPublishPropertyRequest(final String accessToken, final Long postId) { - return TistoryPublishPropertyRequest.builder() - .access_token(accessToken) - .postId(postId) - .blogName(findDefaultBlogName(accessToken)) - .build(); - } - - private TistoryPublishRequest makePublishRequest( - final String accessToken, - final String titleValue, - final String content, - final PublishRequest publishRequest - ) { - final PublishStatus publishStatus = PublishStatus.from(publishRequest.publishStatus()); - if (publishStatus == PublishStatus.PROTECT) { - return TistoryPublishRequest.builder() - .access_token(accessToken) - .blogName(findDefaultBlogName(accessToken)) - .output("json") - .title(titleValue) - .content(content) - .visibility(publishStatus.getTistory()) - .category(publishRequest.categoryId()) - .tag(String.join(",", publishRequest.tags())) - .published(makePublishTime(publishRequest.publishTime())) - .password(publishRequest.password()) - .build(); - } - return TistoryPublishRequest.builder() - .access_token(accessToken) - .blogName(findDefaultBlogName(accessToken)) - .output("json") - .title(titleValue) - .content(content) - .visibility(publishStatus.getTistory()) - .category(publishRequest.categoryId()) - .tag(String.join(",", publishRequest.tags())) - .published(makePublishTime(publishRequest.publishTime())) - .build(); - } - - public TistoryCategoryListResponse findCategory(final Long memberId) { - final MemberCredentials memberCredentials = getMemberCredentials(memberId); - final String categoryListUri = UriComponentsBuilder.fromUriString("/category/list") - .queryParam("access_token", memberCredentials.getTistoryToken()) - .queryParam("output", "json") - .queryParam("blogName", memberCredentials.getTistoryBlogName()) - .build() - .toUriString(); - final TistoryCategoryListResponseWrapper categoryList = webClient.get() - .uri(categoryListUri) - .retrieve() - .onStatus(HttpStatusCode::is4xxClientError, clientResponse -> handle4xxException(clientResponse.statusCode().value(), PLATFORM_NAME)) - .onStatus(HttpStatusCode::is5xxServerError, clientResponse -> clientResponse.bodyToMono(String.class) - .map(e -> new ClientInternalServerError(PLATFORM_NAME))) - .bodyToMono(TistoryCategoryListResponseWrapper.class) - .block(); - final List categories = categoryList.tistory().item().categories(); - if (Objects.isNull(categories)) { - return new TistoryCategoryListResponse(Collections.emptyList()); - } - return new TistoryCategoryListResponse( - categories.stream() - .map(category -> new TistoryCategoryListResponse.TistoryCategoryResponse(category.id(), category.name())) - .toList()); - } - - private MemberCredentials getMemberCredentials(final Long memberId) { - final Member member = memberRepository.findById(memberId) - .orElseThrow(() -> new MemberNotFoundException(memberId)); - final MemberCredentials memberCredentials = memberCredentialsRepository.findByMember(member) - .orElseThrow(NoSuchElementException::new); - if (!memberCredentials.isTistoryConnected()) { - throw new NotConnectedException(TISTORY); - } - return memberCredentials; - } - - private Long makePublishTime(final String publishTime) { - if (publishTime.isBlank()) { - return Instant.now().getEpochSecond(); - } - final SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); - try { - final Date date = formatter.parse(publishTime); - final Instant instant = date.toInstant(); - if (instant.isBefore(Instant.now())) { - throw new InvalidPublishRequestException("현재 시간보다 과거의 시간은 입력될 수 없습니다."); - } - return instant.getEpochSecond(); - } catch (final ParseException e) { - throw new InvalidPublishRequestException("예약 시간 입력 형식이 잘못되었습니다."); - } - } - - public String findDefaultBlogName(final String access_token) { - final String blogInfoUri = UriComponentsBuilder.fromUriString("/blog/info") - .queryParam("access_token", access_token) - .queryParam("output", "json") - .build() - .toUriString(); - final TistoryBlogNameResponse blogInfo = webClient.get() - .uri(blogInfoUri) - .retrieve() - .onStatus(HttpStatusCode::is4xxClientError, clientResponse -> handle4xxException(clientResponse.statusCode().value(), PLATFORM_NAME)) - .onStatus(HttpStatusCode::is5xxServerError, clientResponse -> clientResponse.bodyToMono(String.class) - .map(e -> new ClientInternalServerError(PLATFORM_NAME))) - .bodyToMono(TistoryBlogNameResponse.class) - .block(); - return blogInfo.tistory().item().blogs().stream() - .filter(blog -> blog.defaultValue().equals("Y")) - .map(TistoryBlogNameResponse.TistoryBlogInfoResponse.TistoryBlogResponse::name) - .findFirst() - .orElseThrow(); - } - - private 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(publishPropertyUri) - .retrieve() - .onStatus(HttpStatusCode::is4xxClientError, clientResponse -> handle4xxException(clientResponse.statusCode().value(), PLATFORM_NAME)) - .onStatus(HttpStatusCode::is5xxServerError, clientResponse -> clientResponse.bodyToMono(String.class) - .map(e -> new ClientInternalServerError(PLATFORM_NAME))) - .bodyToMono(TistoryGetWritingResponseWrapper.class) - .block(); - } - - @Override - public BlogType getBlogType() { - return TISTORY; - } -} +//package org.donggle.backend.infrastructure.client.tistory; +// +//import org.donggle.backend.application.client.BlogClient; +//import org.donggle.backend.application.repository.MemberCredentialsRepository; +//import org.donggle.backend.application.repository.MemberRepository; +//import org.donggle.backend.application.service.request.ImageUploadRequest; +//import org.donggle.backend.application.service.request.PublishRequest; +//import org.donggle.backend.domain.blog.BlogType; +//import org.donggle.backend.domain.blog.PublishStatus; +//import org.donggle.backend.domain.member.Member; +//import org.donggle.backend.domain.member.MemberCredentials; +//import org.donggle.backend.exception.business.InvalidPublishRequestException; +//import org.donggle.backend.exception.business.NotConnectedException; +//import org.donggle.backend.exception.notfound.MemberNotFoundException; +//import org.donggle.backend.infrastructure.client.exception.ClientInternalServerError; +//import org.donggle.backend.infrastructure.client.tistory.dto.TistoryImageUploadResponseWrapper; +//import org.donggle.backend.infrastructure.client.tistory.dto.request.TistoryPublishPropertyRequest; +//import org.donggle.backend.infrastructure.client.tistory.dto.request.TistoryPublishRequest; +//import org.donggle.backend.infrastructure.client.tistory.dto.response.TistoryBlogNameResponse; +//import org.donggle.backend.infrastructure.client.tistory.dto.response.TistoryCategoryListResponseWrapper; +//import org.donggle.backend.infrastructure.client.tistory.dto.response.TistoryCategoryListResponseWrapper.TistoryCategoryListResponse.TistoryCategoryResponse; +//import org.donggle.backend.infrastructure.client.tistory.dto.response.TistoryGetWritingResponseWrapper; +//import org.donggle.backend.infrastructure.client.tistory.dto.response.TistoryPublishWritingResponseWrapper; +//import org.donggle.backend.ui.response.ImageUploadResponse; +//import org.donggle.backend.ui.response.PublishResponse; +//import org.donggle.backend.ui.response.TistoryCategoryListResponse; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.core.io.buffer.DataBuffer; +//import org.springframework.http.HttpStatusCode; +//import org.springframework.http.MediaType; +//import org.springframework.http.client.MultipartBodyBuilder; +//import org.springframework.stereotype.Component; +//import org.springframework.web.reactive.function.BodyInserters; +//import org.springframework.web.reactive.function.client.WebClient; +//import org.springframework.web.util.UriComponentsBuilder; +// +//import java.text.ParseException; +//import java.text.SimpleDateFormat; +//import java.time.Instant; +//import java.util.Collections; +//import java.util.Date; +//import java.util.List; +//import java.util.NoSuchElementException; +//import java.util.Objects; +// +//import static org.donggle.backend.domain.blog.BlogType.TISTORY; +//import static org.donggle.backend.infrastructure.client.exception.ClientException.handle4xxException; +// +//@Component +//public class TistoryApiClient implements BlogClient { +// private static final String PLATFORM_NAME = "Tistory"; +// private static final String TISTORY_URL = "https://www.tistory.com/apis"; +// +// private final WebClient webClient; +// private final MemberRepository memberRepository; +// private final MemberCredentialsRepository memberCredentialsRepository; +// +// @Autowired +// public TistoryApiClient(final MemberRepository memberRepository, +// final MemberCredentialsRepository memberCredentialsRepository) { +// this.memberRepository = memberRepository; +// this.webClient = WebClient.create(TISTORY_URL); +// this.memberCredentialsRepository = memberCredentialsRepository; +// } +// +// public TistoryApiClient(final MemberRepository memberRepository, +// final MemberCredentialsRepository memberCredentialsRepository, +// final WebClient webClient) { +// this.memberRepository = memberRepository; +// this.memberCredentialsRepository = memberCredentialsRepository; +// this.webClient = webClient; +// } +// +// @Override +// public PublishResponse publish(final String accessToken, final String content, final PublishRequest publishRequest, final String titleValue) { +// final TistoryPublishRequest request = makePublishRequest(accessToken, titleValue, content, publishRequest); +// 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 ClientInternalServerError(PLATFORM_NAME))) +// .bodyToMono(TistoryPublishWritingResponseWrapper.class) +// .block(); +// return findPublishProperty(makeTistoryPublishPropertyRequest(accessToken, response.tistory().postId())) +// .toPublishResponse(); +// } +// +// @Override +// public ImageUploadResponse uploadImage(final String accessToken, final ImageUploadRequest imageUploadRequest) { +// final MultipartBodyBuilder builder = new MultipartBodyBuilder(); +// builder.asyncPart("uploadedfile", imageUploadRequest.imageDataFlux(), DataBuffer.class) +// .contentType(imageUploadRequest.mediaType()) +// .filename("uploadedfile"); +// builder.part("access_token", accessToken); +// builder.part("blogName", findDefaultBlogName(accessToken)); +// builder.part("output", "json"); +// +// System.out.println("builder.build() = " + builder.build()); +// +// final TistoryImageUploadResponseWrapper response = webClient +// .post() +// .uri("/post/attach") +// .contentType(MediaType.MULTIPART_FORM_DATA) +// .body(BodyInserters.fromMultipartData(builder.build())) +// .retrieve() +// .onStatus(HttpStatusCode::is4xxClientError, clientResponse -> handle4xxException(clientResponse.statusCode().value(), PLATFORM_NAME)) +// .onStatus(HttpStatusCode::is5xxServerError, clientResponse -> clientResponse.bodyToMono(String.class) +// .map(e -> new ClientInternalServerError(PLATFORM_NAME))) +// .bodyToMono(TistoryImageUploadResponseWrapper.class) +// .block(); +// System.out.println("response = " + response); +// return response.toImageUploadResponse(); +// } +// +// private TistoryPublishPropertyRequest makeTistoryPublishPropertyRequest(final String accessToken, final Long postId) { +// return TistoryPublishPropertyRequest.builder() +// .access_token(accessToken) +// .postId(postId) +// .blogName(findDefaultBlogName(accessToken)) +// .build(); +// } +// +// private TistoryPublishRequest makePublishRequest( +// final String accessToken, +// final String titleValue, +// final String content, +// final PublishRequest publishRequest +// ) { +// final PublishStatus publishStatus = PublishStatus.from(publishRequest.publishStatus()); +// if (publishStatus == PublishStatus.PROTECT) { +// return TistoryPublishRequest.builder() +// .access_token(accessToken) +// .blogName(findDefaultBlogName(accessToken)) +// .output("json") +// .title(titleValue) +// .content(content) +// .visibility(publishStatus.getTistory()) +// .category(publishRequest.categoryId()) +// .tag(String.join(",", publishRequest.tags())) +// .published(makePublishTime(publishRequest.publishTime())) +// .password(publishRequest.password()) +// .build(); +// } +// return TistoryPublishRequest.builder() +// .access_token(accessToken) +// .blogName(findDefaultBlogName(accessToken)) +// .output("json") +// .title(titleValue) +// .content(content) +// .visibility(publishStatus.getTistory()) +// .category(publishRequest.categoryId()) +// .tag(String.join(",", publishRequest.tags())) +// .published(makePublishTime(publishRequest.publishTime())) +// .build(); +// } +// +// public TistoryCategoryListResponse findCategory(final Long memberId) { +// final MemberCredentials memberCredentials = getMemberCredentials(memberId); +// final String categoryListUri = UriComponentsBuilder.fromUriString("/category/list") +// .queryParam("access_token", memberCredentials.getTistoryToken()) +// .queryParam("output", "json") +// .queryParam("blogName", memberCredentials.getTistoryBlogName()) +// .build() +// .toUriString(); +// final TistoryCategoryListResponseWrapper categoryList = webClient.get() +// .uri(categoryListUri) +// .retrieve() +// .onStatus(HttpStatusCode::is4xxClientError, clientResponse -> handle4xxException(clientResponse.statusCode().value(), PLATFORM_NAME)) +// .onStatus(HttpStatusCode::is5xxServerError, clientResponse -> clientResponse.bodyToMono(String.class) +// .map(e -> new ClientInternalServerError(PLATFORM_NAME))) +// .bodyToMono(TistoryCategoryListResponseWrapper.class) +// .block(); +// final List categories = categoryList.tistory().item().categories(); +// if (Objects.isNull(categories)) { +// return new TistoryCategoryListResponse(Collections.emptyList()); +// } +// return new TistoryCategoryListResponse( +// categories.stream() +// .map(category -> new TistoryCategoryListResponse.TistoryCategoryResponse(category.id(), category.name())) +// .toList()); +// } +// +// private MemberCredentials getMemberCredentials(final Long memberId) { +// final Member member = memberRepository.findById(memberId) +// .orElseThrow(() -> new MemberNotFoundException(memberId)); +// final MemberCredentials memberCredentials = memberCredentialsRepository.findByMember(member) +// .orElseThrow(NoSuchElementException::new); +// if (!memberCredentials.isTistoryConnected()) { +// throw new NotConnectedException(TISTORY); +// } +// return memberCredentials; +// } +// +// private Long makePublishTime(final String publishTime) { +// if (publishTime.isBlank()) { +// return Instant.now().getEpochSecond(); +// } +// final SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); +// try { +// final Date date = formatter.parse(publishTime); +// final Instant instant = date.toInstant(); +// if (instant.isBefore(Instant.now())) { +// throw new InvalidPublishRequestException("현재 시간보다 과거의 시간은 입력될 수 없습니다."); +// } +// return instant.getEpochSecond(); +// } catch (final ParseException e) { +// throw new InvalidPublishRequestException("예약 시간 입력 형식이 잘못되었습니다."); +// } +// } +// +// public String findDefaultBlogName(final String access_token) { +// final String blogInfoUri = UriComponentsBuilder.fromUriString("/blog/info") +// .queryParam("access_token", access_token) +// .queryParam("output", "json") +// .build() +// .toUriString(); +// final TistoryBlogNameResponse blogInfo = webClient.get() +// .uri(blogInfoUri) +// .retrieve() +// .onStatus(HttpStatusCode::is4xxClientError, clientResponse -> handle4xxException(clientResponse.statusCode().value(), PLATFORM_NAME)) +// .onStatus(HttpStatusCode::is5xxServerError, clientResponse -> clientResponse.bodyToMono(String.class) +// .map(e -> new ClientInternalServerError(PLATFORM_NAME))) +// .bodyToMono(TistoryBlogNameResponse.class) +// .block(); +// return blogInfo.tistory().item().blogs().stream() +// .filter(blog -> blog.defaultValue().equals("Y")) +// .map(TistoryBlogNameResponse.TistoryBlogInfoResponse.TistoryBlogResponse::name) +// .findFirst() +// .orElseThrow(); +// } +// +// private 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(publishPropertyUri) +// .retrieve() +// .onStatus(HttpStatusCode::is4xxClientError, clientResponse -> handle4xxException(clientResponse.statusCode().value(), PLATFORM_NAME)) +// .onStatus(HttpStatusCode::is5xxServerError, clientResponse -> clientResponse.bodyToMono(String.class) +// .map(e -> new ClientInternalServerError(PLATFORM_NAME))) +// .bodyToMono(TistoryGetWritingResponseWrapper.class) +// .block(); +// } +// +// @Override +// public BlogType getBlogType() { +// return TISTORY; +// } +//} diff --git a/backend/src/main/java/org/donggle/backend/infrastructure/client/tistory/TistoryConnectionClient.java b/backend/src/main/java/org/donggle/backend/infrastructure/client/tistory/TistoryConnectionClient.java index 28a612305..e7e4200ed 100644 --- a/backend/src/main/java/org/donggle/backend/infrastructure/client/tistory/TistoryConnectionClient.java +++ b/backend/src/main/java/org/donggle/backend/infrastructure/client/tistory/TistoryConnectionClient.java @@ -1,123 +1,124 @@ -package org.donggle.backend.infrastructure.client.tistory; - -import org.donggle.backend.application.repository.MemberCredentialsRepository; -import org.donggle.backend.application.repository.MemberRepository; -import org.donggle.backend.application.service.request.OAuthAccessTokenRequest; -import org.donggle.backend.domain.member.Member; -import org.donggle.backend.domain.member.MemberCredentials; -import org.donggle.backend.exception.notfound.MemberNotFoundException; -import org.donggle.backend.infrastructure.client.exception.ClientException; -import org.donggle.backend.infrastructure.client.tistory.dto.response.TistoryAccessTokenResponse; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.HttpStatusCode; -import org.springframework.http.MediaType; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.reactive.function.client.WebClient; -import org.springframework.web.util.UriComponentsBuilder; - -import java.util.NoSuchElementException; - -@Service -@Transactional -public class TistoryConnectionClient { - private static final String AUTHORIZE_URL = "https://www.tistory.com/oauth/authorize"; - private static final String TOKEN_URL = "https://www.tistory.com/oauth"; - private static final String PLATFORM_NAME = "Tistory"; - - private final String clientId; - private final String clientSecret; - private final WebClient webClient; - private final MemberCredentialsRepository memberCredentialsRepository; - private final MemberRepository memberRepository; - private final TistoryApiClient tistoryApiService; - - @Autowired - public TistoryConnectionClient(@Value("${tistory_client_id}") final String clientId, - @Value("${tistory_client_secret}") final String clientSecret, - final MemberCredentialsRepository memberCredentialsRepository, - final MemberRepository memberRepository, - final TistoryApiClient tistoryApiService) { - this.clientId = clientId; - this.clientSecret = clientSecret; - this.memberCredentialsRepository = memberCredentialsRepository; - this.memberRepository = memberRepository; - this.tistoryApiService = tistoryApiService; - this.webClient = WebClient.create(TOKEN_URL); - } - - public TistoryConnectionClient(final String clientId, - final String clientSecret, - final MemberCredentialsRepository memberCredentialsRepository, - final MemberRepository memberRepository, - final TistoryApiClient tistoryApiService, - final WebClient webClient) { - this.clientId = clientId; - this.clientSecret = clientSecret; - this.memberCredentialsRepository = memberCredentialsRepository; - this.memberRepository = memberRepository; - this.tistoryApiService = tistoryApiService; - this.webClient = webClient; - } - - public String createAuthorizeRedirectUri(final String redirectUri) { - return UriComponentsBuilder.fromUriString(AUTHORIZE_URL) - .queryParam("client_id", clientId) - .queryParam("redirect_uri", redirectUri) - .queryParam("response_type", "code") - .build() - .toUriString(); - } - - public void saveAccessToken(final Long memberId, final OAuthAccessTokenRequest oAuthAccessTokenRequest) { - final Member member = findMember(memberId); - final MemberCredentials memberCredentials = findMemberCredentials(member); - - final String accessToken = getAccessToken(oAuthAccessTokenRequest.code(), oAuthAccessTokenRequest.redirect_uri()); - final String tistoryBlogName = tistoryApiService.findDefaultBlogName(accessToken); - - memberCredentials.updateTistory(accessToken, tistoryBlogName); - } - - private String getAccessToken(final String code, final String redirectUri) { - final String tokenUri = createTokenUri(redirectUri, code); - - return webClient.get() - .uri(tokenUri) - .accept(MediaType.APPLICATION_JSON) - .retrieve() - .onStatus(HttpStatusCode::is4xxClientError, clientResponse -> ClientException.handle4xxException(clientResponse.statusCode().value(), PLATFORM_NAME)) - .onStatus(HttpStatusCode::is5xxServerError, clientResponse -> ClientException.handle5xxException(PLATFORM_NAME)) - .bodyToMono(TistoryAccessTokenResponse.class) - .block().access_token(); - } - - public String createTokenUri(final String redirectUri, final String code) { - return UriComponentsBuilder.fromUriString("/access_token") - .queryParam("client_id", clientId) - .queryParam("client_secret", clientSecret) - .queryParam("redirect_uri", redirectUri) - .queryParam("code", code) - .queryParam("grant_type", "authorization_code") - .build() - .toUriString(); - } - - public void deleteAccessToken(final Long memberId) { - final Member member = findMember(memberId); - final MemberCredentials memberCredentials = findMemberCredentials(member); - - memberCredentials.deleteTistoryConnection(); - } - - private Member findMember(final Long memberId) { - return memberRepository.findById(memberId) - .orElseThrow(() -> new MemberNotFoundException(memberId)); - } - - private MemberCredentials findMemberCredentials(final Member member) { - return memberCredentialsRepository.findByMember(member) - .orElseThrow(NoSuchElementException::new); - } -} +//package org.donggle.backend.infrastructure.client.tistory; +// +//import org.donggle.backend.application.repository.MemberCredentialsRepository; +//import org.donggle.backend.application.repository.MemberRepository; +//import org.donggle.backend.application.service.request.OAuthAccessTokenRequest; +//import org.donggle.backend.domain.member.Member; +//import org.donggle.backend.domain.member.MemberCredentials; +//import org.donggle.backend.exception.notfound.MemberNotFoundException; +//import org.donggle.backend.infrastructure.client.exception.ClientException; +//import org.donggle.backend.infrastructure.client.tistory.dto.response.TistoryAccessTokenResponse; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.beans.factory.annotation.Value; +//import org.springframework.http.HttpStatusCode; +//import org.springframework.http.MediaType; +//import org.springframework.stereotype.Service; +//import org.springframework.transaction.annotation.Transactional; +//import org.springframework.web.reactive.function.client.WebClient; +//import org.springframework.web.util.UriComponentsBuilder; +// +//import java.util.NoSuchElementException; +// +//@Service +//@Transactional +//public class TistoryConnectionClient { +// private static final String AUTHORIZE_URL = "https://www.tistory.com/oauth/authorize"; +// private static final String TOKEN_URL = "https://www.tistory.com/oauth"; +// private static final String PLATFORM_NAME = "Tistory"; +// +// private final String clientId; +// private final String clientSecret; +// private final WebClient webClient; +// private final MemberCredentialsRepository memberCredentialsRepository; +// private final MemberRepository memberRepository; +// private final TistoryApiClient tistoryApiService; +// +// @Autowired +// public TistoryConnectionClient(@Value("${tistory_client_id}") final String clientId, +// @Value("${tistory_client_secret}") final String clientSecret, +// final MemberCredentialsRepository memberCredentialsRepository, +// final MemberRepository memberRepository +// final TistoryApiClient tistoryApiService +// ) { +// this.clientId = clientId; +// this.clientSecret = clientSecret; +// this.memberCredentialsRepository = memberCredentialsRepository; +// this.memberRepository = memberRepository; +// this.tistoryApiService = tistoryApiService; +// this.webClient = WebClient.create(TOKEN_URL); +// } +// +// public TistoryConnectionClient(final String clientId, +// final String clientSecret, +// final MemberCredentialsRepository memberCredentialsRepository, +// final MemberRepository memberRepository, +// final TistoryApiClient tistoryApiService, +// final WebClient webClient) { +// this.clientId = clientId; +// this.clientSecret = clientSecret; +// this.memberCredentialsRepository = memberCredentialsRepository; +// this.memberRepository = memberRepository; +// this.tistoryApiService = tistoryApiService; +// this.webClient = webClient; +// } +// +// public String createAuthorizeRedirectUri(final String redirectUri) { +// return UriComponentsBuilder.fromUriString(AUTHORIZE_URL) +// .queryParam("client_id", clientId) +// .queryParam("redirect_uri", redirectUri) +// .queryParam("response_type", "code") +// .build() +// .toUriString(); +// } +// +// public void saveAccessToken(final Long memberId, final OAuthAccessTokenRequest oAuthAccessTokenRequest) { +// final Member member = findMember(memberId); +// final MemberCredentials memberCredentials = findMemberCredentials(member); +// +// final String accessToken = getAccessToken(oAuthAccessTokenRequest.code(), oAuthAccessTokenRequest.redirect_uri()); +// final String tistoryBlogName = tistoryApiService.findDefaultBlogName(accessToken); +// +// memberCredentials.updateTistory(accessToken, tistoryBlogName); +// } +// +// private String getAccessToken(final String code, final String redirectUri) { +// final String tokenUri = createTokenUri(redirectUri, code); +// +// return webClient.get() +// .uri(tokenUri) +// .accept(MediaType.APPLICATION_JSON) +// .retrieve() +// .onStatus(HttpStatusCode::is4xxClientError, clientResponse -> ClientException.handle4xxException(clientResponse.statusCode().value(), PLATFORM_NAME)) +// .onStatus(HttpStatusCode::is5xxServerError, clientResponse -> ClientException.handle5xxException(PLATFORM_NAME)) +// .bodyToMono(TistoryAccessTokenResponse.class) +// .block().access_token(); +// } +// +// public String createTokenUri(final String redirectUri, final String code) { +// return UriComponentsBuilder.fromUriString("/access_token") +// .queryParam("client_id", clientId) +// .queryParam("client_secret", clientSecret) +// .queryParam("redirect_uri", redirectUri) +// .queryParam("code", code) +// .queryParam("grant_type", "authorization_code") +// .build() +// .toUriString(); +// } +// +// public void deleteAccessToken(final Long memberId) { +// final Member member = findMember(memberId); +// final MemberCredentials memberCredentials = findMemberCredentials(member); +// +// memberCredentials.deleteTistoryConnection(); +// } +// +// private Member findMember(final Long memberId) { +// return memberRepository.findById(memberId) +// .orElseThrow(() -> new MemberNotFoundException(memberId)); +// } +// +// private MemberCredentials findMemberCredentials(final Member member) { +// return memberCredentialsRepository.findByMember(member) +// .orElseThrow(NoSuchElementException::new); +// } +//} diff --git a/backend/src/main/java/org/donggle/backend/ui/BlogController.java b/backend/src/main/java/org/donggle/backend/ui/BlogController.java index 4fa519b86..05e1eea84 100644 --- a/backend/src/main/java/org/donggle/backend/ui/BlogController.java +++ b/backend/src/main/java/org/donggle/backend/ui/BlogController.java @@ -1,26 +1,26 @@ -package org.donggle.backend.ui; - -import lombok.RequiredArgsConstructor; -import org.donggle.backend.infrastructure.client.tistory.TistoryApiClient; -import org.donggle.backend.ui.common.AuthenticationPrincipal; -import org.donggle.backend.ui.response.TistoryCategoryListResponse; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - - -@RestController -@RequiredArgsConstructor -@RequestMapping("/blogs") -public class BlogController { - private final TistoryApiClient tistoryApiService; - - @GetMapping("/tistory/category") - public ResponseEntity tistoryCategoryList( - @AuthenticationPrincipal final Long memberId - ) { - final TistoryCategoryListResponse response = tistoryApiService.findCategory(memberId); - return ResponseEntity.ok(response); - } -} +//package org.donggle.backend.ui; +// +//import lombok.RequiredArgsConstructor; +//import org.donggle.backend.infrastructure.client.tistory.TistoryApiClient; +//import org.donggle.backend.ui.common.AuthenticationPrincipal; +//import org.donggle.backend.ui.response.TistoryCategoryListResponse; +//import org.springframework.http.ResponseEntity; +//import org.springframework.web.bind.annotation.GetMapping; +//import org.springframework.web.bind.annotation.RequestMapping; +//import org.springframework.web.bind.annotation.RestController; +// +// +//@RestController +//@RequiredArgsConstructor +//@RequestMapping("/blogs") +//public class BlogController { +// private final TistoryApiClient tistoryApiService; +// +// @GetMapping("/tistory/category") +// public ResponseEntity tistoryCategoryList( +// @AuthenticationPrincipal final Long memberId +// ) { +// final TistoryCategoryListResponse response = tistoryApiService.findCategory(memberId); +// return ResponseEntity.ok(response); +// } +//} diff --git a/backend/src/main/java/org/donggle/backend/ui/ConnectionController.java b/backend/src/main/java/org/donggle/backend/ui/ConnectionController.java index 764acd262..cc499af7d 100644 --- a/backend/src/main/java/org/donggle/backend/ui/ConnectionController.java +++ b/backend/src/main/java/org/donggle/backend/ui/ConnectionController.java @@ -5,7 +5,6 @@ import org.donggle.backend.application.service.request.TokenAddRequest; import org.donggle.backend.infrastructure.client.medium.MediumConnectionClient; import org.donggle.backend.infrastructure.client.notion.NotionConnectionClient; -import org.donggle.backend.infrastructure.client.tistory.TistoryConnectionClient; import org.donggle.backend.ui.common.AuthenticationPrincipal; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; @@ -21,38 +20,38 @@ @RequiredArgsConstructor @RequestMapping("/connections") public class ConnectionController { - private final TistoryConnectionClient tistoryConnectService; +// private final TistoryConnectionClient tistoryConnectService; private final NotionConnectionClient notionConnectionService; private final MediumConnectionClient mediumConnectionClient; - @GetMapping("/tistory/redirect") - public ResponseEntity connectionsRedirectTistory( - @RequestParam final String redirect_uri - ) { - final String redirectUri = tistoryConnectService.createAuthorizeRedirectUri(redirect_uri); - return ResponseEntity - .status(HttpStatus.FOUND) - .header(HttpHeaders.LOCATION, redirectUri) - .build(); - } +// @GetMapping("/tistory/redirect") +// public ResponseEntity connectionsRedirectTistory( +// @RequestParam final String redirect_uri +// ) { +// final String redirectUri = tistoryConnectService.createAuthorizeRedirectUri(redirect_uri); +// return ResponseEntity +// .status(HttpStatus.FOUND) +// .header(HttpHeaders.LOCATION, redirectUri) +// .build(); +// } - @PostMapping("/tistory") - public ResponseEntity connectionsAddTistory( - @AuthenticationPrincipal final Long memberId, - @RequestBody final OAuthAccessTokenRequest oAuthAccessTokenRequest - ) { - tistoryConnectService.saveAccessToken(memberId, oAuthAccessTokenRequest); - return ResponseEntity.ok().build(); - } - - @PostMapping("/tistory/disconnect") - public ResponseEntity connectionsDisconnectTistory( - @AuthenticationPrincipal final Long memberId - ) { - tistoryConnectService.deleteAccessToken(memberId); - return ResponseEntity.ok().build(); - } +// @PostMapping("/tistory") +// public ResponseEntity connectionsAddTistory( +// @AuthenticationPrincipal final Long memberId, +// @RequestBody final OAuthAccessTokenRequest oAuthAccessTokenRequest +// ) { +// tistoryConnectService.saveAccessToken(memberId, oAuthAccessTokenRequest); +// return ResponseEntity.ok().build(); +// } +// @PostMapping("/tistory/disconnect") +// public ResponseEntity connectionsDisconnectTistory( +// @AuthenticationPrincipal final Long memberId +// ) { +// tistoryConnectService.deleteAccessToken(memberId); +// return ResponseEntity.ok().build(); +// } +// @GetMapping("/notion/redirect") public ResponseEntity connectionsRedirectNotion( @RequestParam final String redirect_uri diff --git a/backend/src/main/java/org/donggle/backend/ui/PublishController.java b/backend/src/main/java/org/donggle/backend/ui/PublishController.java index b13ff90a6..e8c9788f0 100644 --- a/backend/src/main/java/org/donggle/backend/ui/PublishController.java +++ b/backend/src/main/java/org/donggle/backend/ui/PublishController.java @@ -19,15 +19,15 @@ public class PublishController { private final PublishFacadeService blogService; - @PostMapping("/tistory") - public ResponseEntity publishToTistory( - @AuthenticationPrincipal final Long memberId, - @PathVariable final Long writingId, - @Valid @RequestBody final PublishRequest request - ) { - blogService.publishWriting(memberId, writingId, BlogType.TISTORY, PublishRequest.tistory(request)); - return ResponseEntity.ok().build(); - } +// @PostMapping("/tistory") +// public ResponseEntity publishToTistory( +// @AuthenticationPrincipal final Long memberId, +// @PathVariable final Long writingId, +// @Valid @RequestBody final PublishRequest request +// ) { +// blogService.publishWriting(memberId, writingId, BlogType.TISTORY, PublishRequest.tistory(request)); +// return ResponseEntity.ok().build(); +// } @PostMapping("/medium") public ResponseEntity publishToMedium( diff --git a/backend/src/test/java/org/donggle/backend/infrastructure/client/tistory/TistoryApiClientTest.java b/backend/src/test/java/org/donggle/backend/infrastructure/client/tistory/TistoryApiClientTest.java index 89558debf..079d27999 100644 --- a/backend/src/test/java/org/donggle/backend/infrastructure/client/tistory/TistoryApiClientTest.java +++ b/backend/src/test/java/org/donggle/backend/infrastructure/client/tistory/TistoryApiClientTest.java @@ -1,376 +1,376 @@ -package org.donggle.backend.infrastructure.client.tistory; - -import okhttp3.mockwebserver.MockResponse; -import okhttp3.mockwebserver.MockWebServer; -import org.donggle.backend.application.repository.MemberCredentialsRepository; -import org.donggle.backend.application.repository.MemberRepository; -import org.donggle.backend.application.service.request.ImageUploadRequest; -import org.donggle.backend.application.service.request.PublishRequest; -import org.donggle.backend.domain.member.Member; -import org.donggle.backend.domain.member.MemberCredentials; -import org.donggle.backend.exception.business.InvalidPublishRequestException; -import org.donggle.backend.ui.response.ImageUploadResponse; -import org.donggle.backend.ui.response.PublishResponse; -import org.donggle.backend.ui.response.TistoryCategoryListResponse; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; -import org.springframework.core.io.buffer.DataBuffer; -import org.springframework.http.MediaType; -import org.springframework.web.reactive.function.client.WebClient; -import reactor.core.publisher.Flux; - -import java.io.IOException; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.util.List; -import java.util.Optional; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.BDDMockito.any; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; - -class TistoryApiClientTest { - - public static final String BLOG_NAME_RESPONSE = """ - { - "tistory": { - "status": "200", - "item": { - "id": "blog_oauth_test@daum.net", - "userId": "12345", - "blogs": [ - { - "name": "oauth-test", - "default": "Y", - "blogIconUrl": "https://blog_icon_url", - "faviconUrl": "https://favicon_url", - "profileThumbnailImageUrl": "https://profile_image", - "profileImageUrl": "https://profile_image", - "role": "소유자", - "blogId": "123", - "statistics": { - "post": "182", - "comment": "146", - "trackback": "0", - "guestbook": "39", - "invitation": "0" - } - } - ] - } - } - } - """; - private final Member member = mock(Member.class); - private final MemberCredentials memberCredentials = mock(MemberCredentials.class); - private MemberRepository memberRepository; - private MemberCredentialsRepository memberCredentialsRepository; - private MockWebServer mockWebServer; - private TistoryApiClient tistoryApiClient; - - @BeforeEach - void setUp() throws IOException { - memberRepository = Mockito.mock(MemberRepository.class); - memberCredentialsRepository = Mockito.mock(MemberCredentialsRepository.class); - mockWebServer = new MockWebServer(); - mockWebServer.start(); - final String mockServerUrl = mockWebServer.url("/").toString(); - tistoryApiClient = new TistoryApiClient(memberRepository, memberCredentialsRepository, WebClient.create(mockServerUrl)); - } - - @AfterEach - void shutDown() throws IOException { - mockWebServer.shutdown(); - } - - @Test - @DisplayName("tistory에 공개발행 테스트") - void publish_PUBLIC() { - // given - final String accessToken = "testToken"; - final String content = "

Test Content

"; - final LocalDateTime dateTime = LocalDateTime.parse("2023-06-01 12:30:00", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); - final PublishRequest publishRequest = new PublishRequest(List.of("tag1", "tag2"), "PUBLIC", "", "", ""); - final PublishResponse expectedResponse = PublishResponse.builder().dateTime(dateTime).tags(List.of("open", "api")).url("http://sampleUrl.tistory.com/74").build(); - - final String titleValue = "Test Title"; - final String publishResponseBody = """ - { - "tistory": { - "status": "200", - "postId": "74", - "url": "http://sampleUrl.tistory.com/74" - } - } - """; - - final String publishPropertyResponseBody = """ - { - "tistory":{ - "status":"200", - "item":{ - "url":"http://oauth.tistory.com", - "postUrl":"http://sampleUrl.tistory.com/74", - "tags":{ - "tag":["open", "api"] - }, - "date":"2023-06-01 12:30:00" - } - } - } - """; - - - given(memberRepository.findById(anyLong())).willReturn(Optional.of(member)); - given(memberCredentialsRepository.findByMember(any(Member.class))).willReturn(Optional.of(memberCredentials)); - mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(BLOG_NAME_RESPONSE).addHeader("Content-Type", "application/json")); - mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(publishResponseBody).addHeader("Content-Type", "application/json")); - mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(BLOG_NAME_RESPONSE).addHeader("Content-Type", "application/json")); - mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(publishPropertyResponseBody).addHeader("Content-Type", "application/json")); - - // when - final PublishResponse response = tistoryApiClient.publish(accessToken, content, publishRequest, titleValue); - - // then - assertThat(response).usingRecursiveComparison().isEqualTo(expectedResponse); - } - - @Test - @DisplayName("tistory에 보호 발행 테스트") - void publish_PROTECT() { - // given - final String accessToken = "testToken"; - final String content = "

Test Content

"; - final LocalDateTime dateTime = LocalDateTime.parse("2023-06-01 12:30:00", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); - final PublishRequest publishRequest = new PublishRequest(List.of("tag1", "tag2"), "PROTECT", "", "", ""); - final PublishResponse expectedResponse = PublishResponse.builder().dateTime(dateTime).tags(List.of("open", "api")).url("http://sampleUrl.tistory.com/74").build(); - - final String titleValue = "Test Title"; - final String publishResponseBody = """ - { - "tistory": { - "status": "200", - "postId": "74", - "url": "http://sampleUrl.tistory.com/74" - } - } - """; - - final String publishPropertyResponseBody = """ - { - "tistory":{ - "status":"200", - "item":{ - "url":"http://oauth.tistory.com", - "postUrl":"http://sampleUrl.tistory.com/74", - "tags":{ - "tag":["open", "api"] - }, - "date":"2023-06-01 12:30:00" - } - } - } - """; - - - given(memberRepository.findById(anyLong())).willReturn(Optional.of(member)); - given(memberCredentialsRepository.findByMember(any(Member.class))).willReturn(Optional.of(memberCredentials)); - mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(BLOG_NAME_RESPONSE).addHeader("Content-Type", "application/json")); - mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(publishResponseBody).addHeader("Content-Type", "application/json")); - mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(BLOG_NAME_RESPONSE).addHeader("Content-Type", "application/json")); - mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(publishPropertyResponseBody).addHeader("Content-Type", "application/json")); - - // when - final PublishResponse response = tistoryApiClient.publish(accessToken, content, publishRequest, titleValue); - - // then - assertThat(response).usingRecursiveComparison().isEqualTo(expectedResponse); - } - - @Test - @DisplayName("tistory에 발행할 때 발행시간이 과거일때 예외") - void publishTime_fail_timeIsInPast() { - // given - final String accessToken = "testToken"; - final String content = "

Test Content

"; - final PublishRequest publishRequest = new PublishRequest(List.of("tag1", "tag2"), "PUBLIC", "", "", "2001-06-01 12:30:00.000"); - - final String titleValue = "Test Title"; - final String publishResponseBody = """ - { - "tistory": { - "status": "200", - "postId": "74", - "url": "http://sampleUrl.tistory.com/74" - } - } - """; - - final String publishPropertyResponseBody = """ - { - "tistory":{ - "status":"200", - "item":{ - "url":"http://oauth.tistory.com", - "postUrl":"http://sampleUrl.tistory.com/74", - "tags":{ - "tag":["open", "api"] - }, - "date":"2023-06-01 12:30:00" - } - } - } - """; - - - given(memberRepository.findById(anyLong())).willReturn(Optional.of(member)); - given(memberCredentialsRepository.findByMember(any(Member.class))).willReturn(Optional.of(memberCredentials)); - mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(BLOG_NAME_RESPONSE).addHeader("Content-Type", "application/json")); - mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(publishResponseBody).addHeader("Content-Type", "application/json")); - mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(BLOG_NAME_RESPONSE).addHeader("Content-Type", "application/json")); - mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(publishPropertyResponseBody).addHeader("Content-Type", "application/json")); - - // when - assertThatThrownBy( - () -> tistoryApiClient.publish(accessToken, content, publishRequest, titleValue) - ).isInstanceOf(InvalidPublishRequestException.class).hasMessage("발행 정보가 잘못 입력되었습니다."); - } - - @Test - @DisplayName("tistory에 발행할 때 발행시간의 형식이 잘못될때 예외") - void publishTime_fail_formatIsInvalid() { - // Given - final String accessToken = "testToken"; - final String content = "

Test Content

"; - final PublishRequest publishRequest = new PublishRequest(List.of("tag1", "tag2"), "PUBLIC", "", "", "1231254323"); - - final String titleValue = "Test Title"; - final String publishResponseBody = """ - { - "tistory": { - "status": "200", - "postId": "74", - "url": "http://sampleUrl.tistory.com/74" - } - } - """; - - final String publishPropertyResponseBody = """ - { - "tistory":{ - "status":"200", - "item":{ - "url":"http://oauth.tistory.com", - "postUrl":"http://sampleUrl.tistory.com/74", - "tags":{ - "tag":["open", "api"] - }, - "date":"2023-06-01 12:30:00" - } - } - } - """; - - - given(memberRepository.findById(anyLong())).willReturn(Optional.of(member)); - given(memberCredentialsRepository.findByMember(any(Member.class))).willReturn(Optional.of(memberCredentials)); - mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(BLOG_NAME_RESPONSE).addHeader("Content-Type", "application/json")); - mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(publishResponseBody).addHeader("Content-Type", "application/json")); - mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(BLOG_NAME_RESPONSE).addHeader("Content-Type", "application/json")); - mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(publishPropertyResponseBody).addHeader("Content-Type", "application/json")); - - // When - // Then - assertThatThrownBy( - () -> tistoryApiClient.publish(accessToken, content, publishRequest, titleValue) - ).isInstanceOf(InvalidPublishRequestException.class).hasMessage("발행 정보가 잘못 입력되었습니다."); - } - - @Test - @DisplayName("Tistory 카테고리 조회 테스트") - void findCategory() { - // Given - final Long memberId = 1L; - final String accessToken = "testToken"; - final List categories = List.of("OAuth2.0 Athentication", "Blog API Series"); - - final String categoryListResponse = """ - { - "tistory":{ - "status":"200", - "item":{ - "url":"oauth", - "secondaryUrl":"", - "categories":[ - { - "id":"403929", - "name":"OAuth2.0 Athentication", - "parent":"", - "label":"OAuth2.0 Athentication", - "entries":"0" - }, - { - "id":"403930", - "name":"Blog API Series", - "parent":"", - "label":"Blog API Series", - "entries":"0" - } - ] - } - } - } - """; - given(memberRepository.findById(memberId)).willReturn(Optional.of(member)); - given(memberCredentialsRepository.findByMember(any(Member.class))).willReturn(Optional.of(memberCredentials)); - given(memberCredentials.getTistoryToken()).willReturn(Optional.of(accessToken)); - given(memberCredentials.isTistoryConnected()).willReturn(true); - given(memberCredentials.getTistoryBlogName()).willReturn(Optional.of("testBlog")); - - mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(categoryListResponse).addHeader("Content-Type", "application/json")); - - // When - final TistoryCategoryListResponse response = tistoryApiClient.findCategory(memberId); - - // Then - assertThat(response.categories()).anyMatch(category -> categories.contains(category.name())); - } - - @Test - @DisplayName("Tistory 파일 업로드 테스트") - void attachFile() { - //given - final Long memberId = 1L; - final String accessToken = "testToken"; - final String blogName = "testBlog"; - final Flux imageData = Flux.just(mock(DataBuffer.class)); - final ImageUploadRequest imageUploadRequest = new ImageUploadRequest(imageData, MediaType.IMAGE_PNG); - - final String fileUploadResponse = """ - { - "tistory": { - "status": "200", - "url": "http://cfile1.uf.tistory.com/image/dddd", - "replacer": "http://cfile1.uf.tistory.com/image/dddd" - } - } - """; - - mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(BLOG_NAME_RESPONSE).addHeader("Content-Type", "application/json")); - mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(fileUploadResponse).addHeader("Content-Type", "application/json")); - - System.out.println("enqueue"); - //when - final ImageUploadResponse imageUploadResponse = tistoryApiClient.uploadImage(accessToken, imageUploadRequest); - - System.out.println("uploadImage"); - //then - assertThat(imageUploadResponse.url()).isEqualTo("http://cfile1.uf.tistory.com/image/dddd"); - } -} +//package org.donggle.backend.infrastructure.client.tistory; +// +//import okhttp3.mockwebserver.MockResponse; +//import okhttp3.mockwebserver.MockWebServer; +//import org.donggle.backend.application.repository.MemberCredentialsRepository; +//import org.donggle.backend.application.repository.MemberRepository; +//import org.donggle.backend.application.service.request.ImageUploadRequest; +//import org.donggle.backend.application.service.request.PublishRequest; +//import org.donggle.backend.domain.member.Member; +//import org.donggle.backend.domain.member.MemberCredentials; +//import org.donggle.backend.exception.business.InvalidPublishRequestException; +//import org.donggle.backend.ui.response.ImageUploadResponse; +//import org.donggle.backend.ui.response.PublishResponse; +//import org.donggle.backend.ui.response.TistoryCategoryListResponse; +//import org.junit.jupiter.api.AfterEach; +//import org.junit.jupiter.api.BeforeEach; +//import org.junit.jupiter.api.DisplayName; +//import org.junit.jupiter.api.Test; +//import org.mockito.Mockito; +//import org.springframework.core.io.buffer.DataBuffer; +//import org.springframework.http.MediaType; +//import org.springframework.web.reactive.function.client.WebClient; +//import reactor.core.publisher.Flux; +// +//import java.io.IOException; +//import java.time.LocalDateTime; +//import java.time.format.DateTimeFormatter; +//import java.util.List; +//import java.util.Optional; +// +//import static org.assertj.core.api.Assertions.assertThat; +//import static org.assertj.core.api.Assertions.assertThatThrownBy; +//import static org.mockito.ArgumentMatchers.anyLong; +//import static org.mockito.BDDMockito.any; +//import static org.mockito.BDDMockito.given; +//import static org.mockito.Mockito.mock; +// +//class TistoryApiClientTest { +// +// public static final String BLOG_NAME_RESPONSE = """ +// { +// "tistory": { +// "status": "200", +// "item": { +// "id": "blog_oauth_test@daum.net", +// "userId": "12345", +// "blogs": [ +// { +// "name": "oauth-test", +// "default": "Y", +// "blogIconUrl": "https://blog_icon_url", +// "faviconUrl": "https://favicon_url", +// "profileThumbnailImageUrl": "https://profile_image", +// "profileImageUrl": "https://profile_image", +// "role": "소유자", +// "blogId": "123", +// "statistics": { +// "post": "182", +// "comment": "146", +// "trackback": "0", +// "guestbook": "39", +// "invitation": "0" +// } +// } +// ] +// } +// } +// } +// """; +// private final Member member = mock(Member.class); +// private final MemberCredentials memberCredentials = mock(MemberCredentials.class); +// private MemberRepository memberRepository; +// private MemberCredentialsRepository memberCredentialsRepository; +// private MockWebServer mockWebServer; +// private TistoryApiClient tistoryApiClient; +// +// @BeforeEach +// void setUp() throws IOException { +// memberRepository = Mockito.mock(MemberRepository.class); +// memberCredentialsRepository = Mockito.mock(MemberCredentialsRepository.class); +// mockWebServer = new MockWebServer(); +// mockWebServer.start(); +// final String mockServerUrl = mockWebServer.url("/").toString(); +// tistoryApiClient = new TistoryApiClient(memberRepository, memberCredentialsRepository, WebClient.create(mockServerUrl)); +// } +// +// @AfterEach +// void shutDown() throws IOException { +// mockWebServer.shutdown(); +// } +// +// @Test +// @DisplayName("tistory에 공개발행 테스트") +// void publish_PUBLIC() { +// // given +// final String accessToken = "testToken"; +// final String content = "

Test Content

"; +// final LocalDateTime dateTime = LocalDateTime.parse("2023-06-01 12:30:00", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); +// final PublishRequest publishRequest = new PublishRequest(List.of("tag1", "tag2"), "PUBLIC", "", "", ""); +// final PublishResponse expectedResponse = PublishResponse.builder().dateTime(dateTime).tags(List.of("open", "api")).url("http://sampleUrl.tistory.com/74").build(); +// +// final String titleValue = "Test Title"; +// final String publishResponseBody = """ +// { +// "tistory": { +// "status": "200", +// "postId": "74", +// "url": "http://sampleUrl.tistory.com/74" +// } +// } +// """; +// +// final String publishPropertyResponseBody = """ +// { +// "tistory":{ +// "status":"200", +// "item":{ +// "url":"http://oauth.tistory.com", +// "postUrl":"http://sampleUrl.tistory.com/74", +// "tags":{ +// "tag":["open", "api"] +// }, +// "date":"2023-06-01 12:30:00" +// } +// } +// } +// """; +// +// +// given(memberRepository.findById(anyLong())).willReturn(Optional.of(member)); +// given(memberCredentialsRepository.findByMember(any(Member.class))).willReturn(Optional.of(memberCredentials)); +// mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(BLOG_NAME_RESPONSE).addHeader("Content-Type", "application/json")); +// mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(publishResponseBody).addHeader("Content-Type", "application/json")); +// mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(BLOG_NAME_RESPONSE).addHeader("Content-Type", "application/json")); +// mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(publishPropertyResponseBody).addHeader("Content-Type", "application/json")); +// +// // when +// final PublishResponse response = tistoryApiClient.publish(accessToken, content, publishRequest, titleValue); +// +// // then +// assertThat(response).usingRecursiveComparison().isEqualTo(expectedResponse); +// } +// +// @Test +// @DisplayName("tistory에 보호 발행 테스트") +// void publish_PROTECT() { +// // given +// final String accessToken = "testToken"; +// final String content = "

Test Content

"; +// final LocalDateTime dateTime = LocalDateTime.parse("2023-06-01 12:30:00", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); +// final PublishRequest publishRequest = new PublishRequest(List.of("tag1", "tag2"), "PROTECT", "", "", ""); +// final PublishResponse expectedResponse = PublishResponse.builder().dateTime(dateTime).tags(List.of("open", "api")).url("http://sampleUrl.tistory.com/74").build(); +// +// final String titleValue = "Test Title"; +// final String publishResponseBody = """ +// { +// "tistory": { +// "status": "200", +// "postId": "74", +// "url": "http://sampleUrl.tistory.com/74" +// } +// } +// """; +// +// final String publishPropertyResponseBody = """ +// { +// "tistory":{ +// "status":"200", +// "item":{ +// "url":"http://oauth.tistory.com", +// "postUrl":"http://sampleUrl.tistory.com/74", +// "tags":{ +// "tag":["open", "api"] +// }, +// "date":"2023-06-01 12:30:00" +// } +// } +// } +// """; +// +// +// given(memberRepository.findById(anyLong())).willReturn(Optional.of(member)); +// given(memberCredentialsRepository.findByMember(any(Member.class))).willReturn(Optional.of(memberCredentials)); +// mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(BLOG_NAME_RESPONSE).addHeader("Content-Type", "application/json")); +// mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(publishResponseBody).addHeader("Content-Type", "application/json")); +// mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(BLOG_NAME_RESPONSE).addHeader("Content-Type", "application/json")); +// mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(publishPropertyResponseBody).addHeader("Content-Type", "application/json")); +// +// // when +// final PublishResponse response = tistoryApiClient.publish(accessToken, content, publishRequest, titleValue); +// +// // then +// assertThat(response).usingRecursiveComparison().isEqualTo(expectedResponse); +// } +// +// @Test +// @DisplayName("tistory에 발행할 때 발행시간이 과거일때 예외") +// void publishTime_fail_timeIsInPast() { +// // given +// final String accessToken = "testToken"; +// final String content = "

Test Content

"; +// final PublishRequest publishRequest = new PublishRequest(List.of("tag1", "tag2"), "PUBLIC", "", "", "2001-06-01 12:30:00.000"); +// +// final String titleValue = "Test Title"; +// final String publishResponseBody = """ +// { +// "tistory": { +// "status": "200", +// "postId": "74", +// "url": "http://sampleUrl.tistory.com/74" +// } +// } +// """; +// +// final String publishPropertyResponseBody = """ +// { +// "tistory":{ +// "status":"200", +// "item":{ +// "url":"http://oauth.tistory.com", +// "postUrl":"http://sampleUrl.tistory.com/74", +// "tags":{ +// "tag":["open", "api"] +// }, +// "date":"2023-06-01 12:30:00" +// } +// } +// } +// """; +// +// +// given(memberRepository.findById(anyLong())).willReturn(Optional.of(member)); +// given(memberCredentialsRepository.findByMember(any(Member.class))).willReturn(Optional.of(memberCredentials)); +// mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(BLOG_NAME_RESPONSE).addHeader("Content-Type", "application/json")); +// mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(publishResponseBody).addHeader("Content-Type", "application/json")); +// mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(BLOG_NAME_RESPONSE).addHeader("Content-Type", "application/json")); +// mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(publishPropertyResponseBody).addHeader("Content-Type", "application/json")); +// +// // when +// assertThatThrownBy( +// () -> tistoryApiClient.publish(accessToken, content, publishRequest, titleValue) +// ).isInstanceOf(InvalidPublishRequestException.class).hasMessage("발행 정보가 잘못 입력되었습니다."); +// } +// +// @Test +// @DisplayName("tistory에 발행할 때 발행시간의 형식이 잘못될때 예외") +// void publishTime_fail_formatIsInvalid() { +// // Given +// final String accessToken = "testToken"; +// final String content = "

Test Content

"; +// final PublishRequest publishRequest = new PublishRequest(List.of("tag1", "tag2"), "PUBLIC", "", "", "1231254323"); +// +// final String titleValue = "Test Title"; +// final String publishResponseBody = """ +// { +// "tistory": { +// "status": "200", +// "postId": "74", +// "url": "http://sampleUrl.tistory.com/74" +// } +// } +// """; +// +// final String publishPropertyResponseBody = """ +// { +// "tistory":{ +// "status":"200", +// "item":{ +// "url":"http://oauth.tistory.com", +// "postUrl":"http://sampleUrl.tistory.com/74", +// "tags":{ +// "tag":["open", "api"] +// }, +// "date":"2023-06-01 12:30:00" +// } +// } +// } +// """; +// +// +// given(memberRepository.findById(anyLong())).willReturn(Optional.of(member)); +// given(memberCredentialsRepository.findByMember(any(Member.class))).willReturn(Optional.of(memberCredentials)); +// mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(BLOG_NAME_RESPONSE).addHeader("Content-Type", "application/json")); +// mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(publishResponseBody).addHeader("Content-Type", "application/json")); +// mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(BLOG_NAME_RESPONSE).addHeader("Content-Type", "application/json")); +// mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(publishPropertyResponseBody).addHeader("Content-Type", "application/json")); +// +// // When +// // Then +// assertThatThrownBy( +// () -> tistoryApiClient.publish(accessToken, content, publishRequest, titleValue) +// ).isInstanceOf(InvalidPublishRequestException.class).hasMessage("발행 정보가 잘못 입력되었습니다."); +// } +// +// @Test +// @DisplayName("Tistory 카테고리 조회 테스트") +// void findCategory() { +// // Given +// final Long memberId = 1L; +// final String accessToken = "testToken"; +// final List categories = List.of("OAuth2.0 Athentication", "Blog API Series"); +// +// final String categoryListResponse = """ +// { +// "tistory":{ +// "status":"200", +// "item":{ +// "url":"oauth", +// "secondaryUrl":"", +// "categories":[ +// { +// "id":"403929", +// "name":"OAuth2.0 Athentication", +// "parent":"", +// "label":"OAuth2.0 Athentication", +// "entries":"0" +// }, +// { +// "id":"403930", +// "name":"Blog API Series", +// "parent":"", +// "label":"Blog API Series", +// "entries":"0" +// } +// ] +// } +// } +// } +// """; +// given(memberRepository.findById(memberId)).willReturn(Optional.of(member)); +// given(memberCredentialsRepository.findByMember(any(Member.class))).willReturn(Optional.of(memberCredentials)); +// given(memberCredentials.getTistoryToken()).willReturn(Optional.of(accessToken)); +// given(memberCredentials.isTistoryConnected()).willReturn(true); +// given(memberCredentials.getTistoryBlogName()).willReturn(Optional.of("testBlog")); +// +// mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(categoryListResponse).addHeader("Content-Type", "application/json")); +// +// // When +// final TistoryCategoryListResponse response = tistoryApiClient.findCategory(memberId); +// +// // Then +// assertThat(response.categories()).anyMatch(category -> categories.contains(category.name())); +// } +// +// @Test +// @DisplayName("Tistory 파일 업로드 테스트") +// void attachFile() { +// //given +// final Long memberId = 1L; +// final String accessToken = "testToken"; +// final String blogName = "testBlog"; +// final Flux imageData = Flux.just(mock(DataBuffer.class)); +// final ImageUploadRequest imageUploadRequest = new ImageUploadRequest(imageData, MediaType.IMAGE_PNG); +// +// final String fileUploadResponse = """ +// { +// "tistory": { +// "status": "200", +// "url": "http://cfile1.uf.tistory.com/image/dddd", +// "replacer": "http://cfile1.uf.tistory.com/image/dddd" +// } +// } +// """; +// +// mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(BLOG_NAME_RESPONSE).addHeader("Content-Type", "application/json")); +// mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(fileUploadResponse).addHeader("Content-Type", "application/json")); +// +// System.out.println("enqueue"); +// //when +// final ImageUploadResponse imageUploadResponse = tistoryApiClient.uploadImage(accessToken, imageUploadRequest); +// +// System.out.println("uploadImage"); +// //then +// assertThat(imageUploadResponse.url()).isEqualTo("http://cfile1.uf.tistory.com/image/dddd"); +// } +//} diff --git a/backend/src/test/java/org/donggle/backend/infrastructure/client/tistory/TistoryConnectionClientTest.java b/backend/src/test/java/org/donggle/backend/infrastructure/client/tistory/TistoryConnectionClientTest.java index e00cf5969..edd830462 100644 --- a/backend/src/test/java/org/donggle/backend/infrastructure/client/tistory/TistoryConnectionClientTest.java +++ b/backend/src/test/java/org/donggle/backend/infrastructure/client/tistory/TistoryConnectionClientTest.java @@ -1,107 +1,107 @@ -package org.donggle.backend.infrastructure.client.tistory; - -import okhttp3.mockwebserver.MockResponse; -import okhttp3.mockwebserver.MockWebServer; -import org.donggle.backend.application.repository.MemberCredentialsRepository; -import org.donggle.backend.application.repository.MemberRepository; -import org.donggle.backend.application.service.request.OAuthAccessTokenRequest; -import org.donggle.backend.domain.member.Member; -import org.donggle.backend.domain.member.MemberCredentials; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.web.reactive.function.client.WebClient; - -import java.io.IOException; -import java.util.Optional; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.BDDMockito.given; -import static org.mockito.BDDMockito.then; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.when; - -class TistoryConnectionClientTest { - - private TistoryConnectionClient tistoryConnectionClient; - private MemberCredentialsRepository memberCredentialsRepository; - private MemberRepository memberRepository; - private TistoryApiClient tistoryApiClient; - private MockWebServer mockWebServer; - - @BeforeEach - void setUp() throws IOException { - memberCredentialsRepository = mock(MemberCredentialsRepository.class); - memberRepository = mock(MemberRepository.class); - tistoryApiClient = mock(TistoryApiClient.class); - - mockWebServer = new MockWebServer(); - mockWebServer.start(); - - final WebClient webClient = WebClient.create(mockWebServer.url("/").toString()); - tistoryConnectionClient = new TistoryConnectionClient( - "clientId", - "clientSecret", - memberCredentialsRepository, - memberRepository, - tistoryApiClient, - webClient); - } - - @AfterEach - void shutDown() throws IOException { - mockWebServer.shutdown(); - } - - @Test - @DisplayName("RedirectUri가 정상적으로 만들어지는지 테스트") - void createAuthorizeRedirectUri() { - //given - //when - //then - assertThat(tistoryConnectionClient.createAuthorizeRedirectUri("redirect_uri")).isEqualTo("https://www.tistory.com/oauth/authorize?client_id=clientId&redirect_uri=redirect_uri&response_type=code"); - } - - @Test - @DisplayName("Tistory의 accessToken을 save하는 테스트") - void saveAccessToken() { - //given - final String accessToken = """ - { - "access_token": "accessToken" - } - """; - mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(accessToken).addHeader("Content-Type", "application/json")); - - final Member member = mock(Member.class); - final MemberCredentials memberCredentials = mock(MemberCredentials.class); - given(memberRepository.findById(anyLong())).willReturn(Optional.of(member)); - given(memberCredentialsRepository.findByMember(any(Member.class))).willReturn(Optional.of(memberCredentials)); - given(tistoryApiClient.findDefaultBlogName("accessToken")).willReturn("jeoninpyo726"); - - tistoryConnectionClient.saveAccessToken(1L, new OAuthAccessTokenRequest("redirect_uri", "code")); - then(memberCredentials).should(times(1)).updateTistory("accessToken", "jeoninpyo726"); - } - - @Test - @DisplayName("tistory의 accessToken을 제거하는 테스트") - void deleteAccessTokenTest() { - // Given - final Long memberId = 1L; - final Member member = mock(Member.class); - final MemberCredentials memberCredentials = mock(MemberCredentials.class); - - when(memberRepository.findById(memberId)).thenReturn(Optional.of(member)); - when(memberCredentialsRepository.findByMember(member)).thenReturn(Optional.of(memberCredentials)); - - // When - tistoryConnectionClient.deleteAccessToken(memberId); - - // Then - then(memberCredentials).should(times(1)).deleteTistoryConnection(); - } -} \ No newline at end of file +//package org.donggle.backend.infrastructure.client.tistory; +// +//import okhttp3.mockwebserver.MockResponse; +//import okhttp3.mockwebserver.MockWebServer; +//import org.donggle.backend.application.repository.MemberCredentialsRepository; +//import org.donggle.backend.application.repository.MemberRepository; +//import org.donggle.backend.application.service.request.OAuthAccessTokenRequest; +//import org.donggle.backend.domain.member.Member; +//import org.donggle.backend.domain.member.MemberCredentials; +//import org.junit.jupiter.api.AfterEach; +//import org.junit.jupiter.api.BeforeEach; +//import org.junit.jupiter.api.DisplayName; +//import org.junit.jupiter.api.Test; +//import org.springframework.web.reactive.function.client.WebClient; +// +//import java.io.IOException; +//import java.util.Optional; +// +//import static org.assertj.core.api.Assertions.assertThat; +//import static org.mockito.ArgumentMatchers.any; +//import static org.mockito.ArgumentMatchers.anyLong; +//import static org.mockito.BDDMockito.given; +//import static org.mockito.BDDMockito.then; +//import static org.mockito.Mockito.mock; +//import static org.mockito.Mockito.times; +//import static org.mockito.Mockito.when; +// +//class TistoryConnectionClientTest { +// +// private TistoryConnectionClient tistoryConnectionClient; +// private MemberCredentialsRepository memberCredentialsRepository; +// private MemberRepository memberRepository; +// private TistoryApiClient tistoryApiClient; +// private MockWebServer mockWebServer; +// +// @BeforeEach +// void setUp() throws IOException { +// memberCredentialsRepository = mock(MemberCredentialsRepository.class); +// memberRepository = mock(MemberRepository.class); +// tistoryApiClient = mock(TistoryApiClient.class); +// +// mockWebServer = new MockWebServer(); +// mockWebServer.start(); +// +// final WebClient webClient = WebClient.create(mockWebServer.url("/").toString()); +// tistoryConnectionClient = new TistoryConnectionClient( +// "clientId", +// "clientSecret", +// memberCredentialsRepository, +// memberRepository, +// tistoryApiClient, +// webClient); +// } +// +// @AfterEach +// void shutDown() throws IOException { +// mockWebServer.shutdown(); +// } +// +// @Test +// @DisplayName("RedirectUri가 정상적으로 만들어지는지 테스트") +// void createAuthorizeRedirectUri() { +// //given +// //when +// //then +// assertThat(tistoryConnectionClient.createAuthorizeRedirectUri("redirect_uri")).isEqualTo("https://www.tistory.com/oauth/authorize?client_id=clientId&redirect_uri=redirect_uri&response_type=code"); +// } +// +// @Test +// @DisplayName("Tistory의 accessToken을 save하는 테스트") +// void saveAccessToken() { +// //given +// final String accessToken = """ +// { +// "access_token": "accessToken" +// } +// """; +// mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(accessToken).addHeader("Content-Type", "application/json")); +// +// final Member member = mock(Member.class); +// final MemberCredentials memberCredentials = mock(MemberCredentials.class); +// given(memberRepository.findById(anyLong())).willReturn(Optional.of(member)); +// given(memberCredentialsRepository.findByMember(any(Member.class))).willReturn(Optional.of(memberCredentials)); +// given(tistoryApiClient.findDefaultBlogName("accessToken")).willReturn("jeoninpyo726"); +// +// tistoryConnectionClient.saveAccessToken(1L, new OAuthAccessTokenRequest("redirect_uri", "code")); +// then(memberCredentials).should(times(1)).updateTistory("accessToken", "jeoninpyo726"); +// } +// +// @Test +// @DisplayName("tistory의 accessToken을 제거하는 테스트") +// void deleteAccessTokenTest() { +// // Given +// final Long memberId = 1L; +// final Member member = mock(Member.class); +// final MemberCredentials memberCredentials = mock(MemberCredentials.class); +// +// when(memberRepository.findById(memberId)).thenReturn(Optional.of(member)); +// when(memberCredentialsRepository.findByMember(member)).thenReturn(Optional.of(memberCredentials)); +// +// // When +// tistoryConnectionClient.deleteAccessToken(memberId); +// +// // Then +// then(memberCredentials).should(times(1)).deleteTistoryConnection(); +// } +//} \ No newline at end of file diff --git a/backend/src/test/java/org/donggle/backend/ui/BlogControllerTest.java b/backend/src/test/java/org/donggle/backend/ui/BlogControllerTest.java index e010d0dea..d57ca370b 100644 --- a/backend/src/test/java/org/donggle/backend/ui/BlogControllerTest.java +++ b/backend/src/test/java/org/donggle/backend/ui/BlogControllerTest.java @@ -1,42 +1,42 @@ -package org.donggle.backend.ui; - -import org.donggle.backend.support.JwtSupporter; -import org.donggle.backend.ui.response.TistoryCategoryListResponse; -import org.donggle.backend.ui.response.TistoryCategoryListResponse.TistoryCategoryResponse; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -import java.util.List; - -import static org.mockito.BDDMockito.given; -import static org.springframework.http.HttpHeaders.AUTHORIZATION; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -class BlogControllerTest extends ControllerTest { - @Test - @DisplayName("tistory의 카테고리를 정상적으로 가져오면 200을 반환한다.") - void tistoryCategoryList() throws Exception { - //given - final Long memberId = 1L; - final String accessToken = JwtSupporter.generateToken(memberId); - final TistoryCategoryListResponse tistoryCategoryListResposnse = new TistoryCategoryListResponse( - List.of(new TistoryCategoryResponse("1", "카테고리1"), new TistoryCategoryResponse("2", "카테고리2"))); - - given(jwtTokenProvider.getPayload(accessToken)).willReturn(memberId); - given(tistoryApiService.findCategory(memberId)).willReturn(tistoryCategoryListResposnse); - - //when - //then - mockMvc.perform( - get("/blogs/tistory/category") - .header(AUTHORIZATION, "Bearer " + accessToken)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.categories.size()").value(2)) - .andExpect(jsonPath("$.categories[0].id").value("1")) - .andExpect(jsonPath("$.categories[0].name").value("카테고리1")) - .andExpect(jsonPath("$.categories[1].id").value("2")) - .andExpect(jsonPath("$.categories[1].name").value("카테고리2")); - } -} \ No newline at end of file +//package org.donggle.backend.ui; +// +//import org.donggle.backend.support.JwtSupporter; +//import org.donggle.backend.ui.response.TistoryCategoryListResponse; +//import org.donggle.backend.ui.response.TistoryCategoryListResponse.TistoryCategoryResponse; +//import org.junit.jupiter.api.DisplayName; +//import org.junit.jupiter.api.Test; +// +//import java.util.List; +// +//import static org.mockito.BDDMockito.given; +//import static org.springframework.http.HttpHeaders.AUTHORIZATION; +//import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +//import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +//import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +// +//class BlogControllerTest extends ControllerTest { +// @Test +// @DisplayName("tistory의 카테고리를 정상적으로 가져오면 200을 반환한다.") +// void tistoryCategoryList() throws Exception { +// //given +// final Long memberId = 1L; +// final String accessToken = JwtSupporter.generateToken(memberId); +// final TistoryCategoryListResponse tistoryCategoryListResposnse = new TistoryCategoryListResponse( +// List.of(new TistoryCategoryResponse("1", "카테고리1"), new TistoryCategoryResponse("2", "카테고리2"))); +// +// given(jwtTokenProvider.getPayload(accessToken)).willReturn(memberId); +// given(tistoryApiService.findCategory(memberId)).willReturn(tistoryCategoryListResposnse); +// +// //when +// //then +// mockMvc.perform( +// get("/blogs/tistory/category") +// .header(AUTHORIZATION, "Bearer " + accessToken)) +// .andExpect(status().isOk()) +// .andExpect(jsonPath("$.categories.size()").value(2)) +// .andExpect(jsonPath("$.categories[0].id").value("1")) +// .andExpect(jsonPath("$.categories[0].name").value("카테고리1")) +// .andExpect(jsonPath("$.categories[1].id").value("2")) +// .andExpect(jsonPath("$.categories[1].name").value("카테고리2")); +// } +//} \ No newline at end of file diff --git a/backend/src/test/java/org/donggle/backend/ui/ConnectionControllerTest.java b/backend/src/test/java/org/donggle/backend/ui/ConnectionControllerTest.java index 0a9888281..461999944 100644 --- a/backend/src/test/java/org/donggle/backend/ui/ConnectionControllerTest.java +++ b/backend/src/test/java/org/donggle/backend/ui/ConnectionControllerTest.java @@ -17,68 +17,68 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; class ConnectionControllerTest extends ControllerTest { - @Test - @DisplayName("tistory의 RedirectUri를 정상적으로 반한했을때 302를 반환한다.") - void connectionsRedirectTistory() throws Exception { - //given - final String redirectUri = "redirect_uri"; - final String serviceRedirectUri = "https://donggle.blog"; - - given(tistoryConnectService.createAuthorizeRedirectUri(redirectUri)).willReturn(serviceRedirectUri); - - //when - //then - mockMvc.perform( - get("/connections/tistory/redirect") - .param("redirect_uri", redirectUri) - ) - .andExpect(status().isFound()) - .andExpect(header().string(HttpHeaders.LOCATION, serviceRedirectUri)); - } - - @Test - @DisplayName("tistory의 token을 정상적으로 받았을 때 200을 반환한다.") - void connectionsAddTistory() throws Exception { - //given - final Long memberId = 1L; - final String redirectUri = "redirect_uri"; - final String code = "code"; - final String accessToken = JwtSupporter.generateToken(memberId); - final OAuthAccessTokenRequest oAuthAccessTokenRequest = new OAuthAccessTokenRequest(redirectUri, code); - - given(jwtTokenProvider.getPayload(accessToken)).willReturn(memberId); - willDoNothing().given(tistoryConnectService).saveAccessToken(memberId, oAuthAccessTokenRequest); - - //when - //then - mockMvc.perform( - post("/connections/tistory") - .contentType(APPLICATION_JSON) - .header(AUTHORIZATION, "Bearer " + accessToken) - .content(objectMapper.writeValueAsString(oAuthAccessTokenRequest)) - ) - .andExpect(status().isOk()); - } - - @Test - @DisplayName("tistory의 token을 정상적으로 삭제했을 때 200을 반환한다.") - void connectionsDisconnectTistory() throws Exception { - //given - final Long memberId = 1L; - final String accessToken = JwtSupporter.generateToken(memberId); - - given(jwtTokenProvider.getPayload(accessToken)).willReturn(memberId); - willDoNothing().given(tistoryConnectService).deleteAccessToken(memberId); - - //when - //then - mockMvc.perform( - post("/connections/tistory/disconnect") - .contentType(APPLICATION_JSON) - .header(AUTHORIZATION, "Bearer " + accessToken) - ) - .andExpect(status().isOk()); - } +// @Test +// @DisplayName("tistory의 RedirectUri를 정상적으로 반한했을때 302를 반환한다.") +// void connectionsRedirectTistory() throws Exception { +// //given +// final String redirectUri = "redirect_uri"; +// final String serviceRedirectUri = "https://donggle.blog"; +// +// given(tistoryConnectService.createAuthorizeRedirectUri(redirectUri)).willReturn(serviceRedirectUri); +// +// //when +// //then +// mockMvc.perform( +// get("/connections/tistory/redirect") +// .param("redirect_uri", redirectUri) +// ) +// .andExpect(status().isFound()) +// .andExpect(header().string(HttpHeaders.LOCATION, serviceRedirectUri)); +// } + +// @Test +// @DisplayName("tistory의 token을 정상적으로 받았을 때 200을 반환한다.") +// void connectionsAddTistory() throws Exception { +// //given +// final Long memberId = 1L; +// final String redirectUri = "redirect_uri"; +// final String code = "code"; +// final String accessToken = JwtSupporter.generateToken(memberId); +// final OAuthAccessTokenRequest oAuthAccessTokenRequest = new OAuthAccessTokenRequest(redirectUri, code); +// +// given(jwtTokenProvider.getPayload(accessToken)).willReturn(memberId); +// willDoNothing().given(tistoryConnectService).saveAccessToken(memberId, oAuthAccessTokenRequest); +// +// //when +// //then +// mockMvc.perform( +// post("/connections/tistory") +// .contentType(APPLICATION_JSON) +// .header(AUTHORIZATION, "Bearer " + accessToken) +// .content(objectMapper.writeValueAsString(oAuthAccessTokenRequest)) +// ) +// .andExpect(status().isOk()); +// } +// +// @Test +// @DisplayName("tistory의 token을 정상적으로 삭제했을 때 200을 반환한다.") +// void connectionsDisconnectTistory() throws Exception { +// //given +// final Long memberId = 1L; +// final String accessToken = JwtSupporter.generateToken(memberId); +// +// given(jwtTokenProvider.getPayload(accessToken)).willReturn(memberId); +// willDoNothing().given(tistoryConnectService).deleteAccessToken(memberId); +// +// //when +// //then +// mockMvc.perform( +// post("/connections/tistory/disconnect") +// .contentType(APPLICATION_JSON) +// .header(AUTHORIZATION, "Bearer " + accessToken) +// ) +// .andExpect(status().isOk()); +// } @Test @DisplayName("notion의 RedirectUri를 정상적으로 반한했을때 302를 반환한다.") diff --git a/backend/src/test/java/org/donggle/backend/ui/ControllerTest.java b/backend/src/test/java/org/donggle/backend/ui/ControllerTest.java index e2c479712..5697a34d1 100644 --- a/backend/src/test/java/org/donggle/backend/ui/ControllerTest.java +++ b/backend/src/test/java/org/donggle/backend/ui/ControllerTest.java @@ -12,8 +12,8 @@ import org.donggle.backend.domain.auth.JwtTokenProvider; import org.donggle.backend.infrastructure.client.medium.MediumConnectionClient; import org.donggle.backend.infrastructure.client.notion.NotionConnectionClient; -import org.donggle.backend.infrastructure.client.tistory.TistoryApiClient; -import org.donggle.backend.infrastructure.client.tistory.TistoryConnectionClient; +//import org.donggle.backend.infrastructure.client.tistory.TistoryApiClient; +//import org.donggle.backend.infrastructure.client.tistory.TistoryConnectionClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; @@ -21,7 +21,7 @@ @WebMvcTest({ AuthController.class, - BlogController.class, +// BlogController.class, CategoryController.class, ConnectionController.class, MemberController.class, @@ -42,12 +42,12 @@ public abstract class ControllerTest { protected JwtTokenProvider jwtTokenProvider; @MockBean protected TokenRepository tokenRepository; - @MockBean - protected TistoryApiClient tistoryApiService; +// @MockBean +// protected TistoryApiClient tistoryApiService; @MockBean protected CategoryService categoryService; - @MockBean - protected TistoryConnectionClient tistoryConnectService; +// @MockBean +// protected TistoryConnectionClient tistoryConnectService; @MockBean protected NotionConnectionClient notionConnectionService; @MockBean diff --git a/backend/src/test/java/org/donggle/backend/ui/PublishControllerTest.java b/backend/src/test/java/org/donggle/backend/ui/PublishControllerTest.java index 555072530..f58905405 100644 --- a/backend/src/test/java/org/donggle/backend/ui/PublishControllerTest.java +++ b/backend/src/test/java/org/donggle/backend/ui/PublishControllerTest.java @@ -17,28 +17,28 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; class PublishControllerTest extends ControllerTest { - @Test - @DisplayName("tistory로 정상적으로 발행했을때 200을 반환한다.") - void publishToTistory() throws Exception { - //given - final Long memberId = 1L; - final long writingId = 1L; - final String accessToken = JwtSupporter.generateToken(memberId); - final String categoryId = "1"; - final PublishRequest publishRequest = new PublishRequest(List.of("동글로 업로드한 글임"), "PUBLIC", "", categoryId, ""); - given(jwtTokenProvider.getPayload(accessToken)).willReturn(memberId); - willDoNothing().given(publishFacadeService).publishWriting(memberId, writingId, BlogType.TISTORY, PublishRequest.tistory(publishRequest)); - - //when - //then - mockMvc.perform( - post("/writings/{writingId}/publish/tistory", writingId) - .contentType(APPLICATION_JSON) - .header(AUTHORIZATION, "Bearer " + accessToken) - .content(objectMapper.writeValueAsString(publishRequest)) - ) - .andExpect(status().isOk()); - } +// @Test +// @DisplayName("tistory로 정상적으로 발행했을때 200을 반환한다.") +// void publishToTistory() throws Exception { +// //given +// final Long memberId = 1L; +// final long writingId = 1L; +// final String accessToken = JwtSupporter.generateToken(memberId); +// final String categoryId = "1"; +// final PublishRequest publishRequest = new PublishRequest(List.of("동글로 업로드한 글임"), "PUBLIC", "", categoryId, ""); +// given(jwtTokenProvider.getPayload(accessToken)).willReturn(memberId); +// willDoNothing().given(publishFacadeService).publishWriting(memberId, writingId, BlogType.TISTORY, PublishRequest.tistory(publishRequest)); +// +// //when +// //then +// mockMvc.perform( +// post("/writings/{writingId}/publish/tistory", writingId) +// .contentType(APPLICATION_JSON) +// .header(AUTHORIZATION, "Bearer " + accessToken) +// .content(objectMapper.writeValueAsString(publishRequest)) +// ) +// .andExpect(status().isOk()); +// } @Test @DisplayName("medium로 정상적으로 발행했을때 200을 반환한다.")