From efbce95c3413d68a1ae5246a6a98b012efb99042 Mon Sep 17 00:00:00 2001 From: saint6839 Date: Tue, 27 Dec 2022 22:31:07 +0900 Subject: [PATCH 1/3] =?UTF-8?q?DEP-300=20refactor=20:=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9E=90=20=EC=A0=95=EB=B3=B4=20=EC=88=98=EC=A0=95=20api=20end?= =?UTF-8?q?points=20=ED=86=B5=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../usecase/member/SaveConsentUseCase.java | 34 ------------------- .../usecase/member/SaveNameUseCase.java | 33 ------------------ ...eUseCase.java => UpdateMemberUseCase.java} | 28 ++++++++------- .../web/controller/MemberController.java | 32 ++++------------- .../request/member/MemberUpdateRequest.java | 18 ++++++++++ .../data/entity/member/MemberEntity.java | 7 ++++ 6 files changed, 46 insertions(+), 106 deletions(-) delete mode 100644 app/src/main/java/com/depromeet/threedays/front/domain/usecase/member/SaveConsentUseCase.java delete mode 100644 app/src/main/java/com/depromeet/threedays/front/domain/usecase/member/SaveNameUseCase.java rename app/src/main/java/com/depromeet/threedays/front/domain/usecase/member/{SaveResourceUseCase.java => UpdateMemberUseCase.java} (63%) create mode 100644 app/src/main/java/com/depromeet/threedays/front/web/request/member/MemberUpdateRequest.java diff --git a/app/src/main/java/com/depromeet/threedays/front/domain/usecase/member/SaveConsentUseCase.java b/app/src/main/java/com/depromeet/threedays/front/domain/usecase/member/SaveConsentUseCase.java deleted file mode 100644 index 436da914..00000000 --- a/app/src/main/java/com/depromeet/threedays/front/domain/usecase/member/SaveConsentUseCase.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.depromeet.threedays.front.domain.usecase.member; - -import com.depromeet.threedays.data.entity.member.MemberEntity; -import com.depromeet.threedays.data.enums.MemberStatus; -import com.depromeet.threedays.front.config.security.AuditorHolder; -import com.depromeet.threedays.front.domain.converter.member.MemberConverter; -import com.depromeet.threedays.front.domain.model.member.Member; -import com.depromeet.threedays.front.exception.ResourceNotFoundException; -import com.depromeet.threedays.front.persistence.repository.member.MemberRepository; -import com.depromeet.threedays.front.web.request.member.MemberNotificationConsentUpdateRequest; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Transactional -@RequiredArgsConstructor -@Service -public class SaveConsentUseCase { - - private final MemberRepository memberRepository; - - public Member execute(final MemberNotificationConsentUpdateRequest request) { - Long memberId = AuditorHolder.get(); - return MemberConverter.from(updateNotificationConsent(memberId, request)); - } - - public MemberEntity updateNotificationConsent( - final Long memberId, final MemberNotificationConsentUpdateRequest request) { - return memberRepository - .findByIdAndStatus(memberId, MemberStatus.REGULAR) - .map(it -> it.updateNotificationConsent(request.isNotificationConsent())) - .orElseThrow(() -> new ResourceNotFoundException("member.not.found")); - } -} diff --git a/app/src/main/java/com/depromeet/threedays/front/domain/usecase/member/SaveNameUseCase.java b/app/src/main/java/com/depromeet/threedays/front/domain/usecase/member/SaveNameUseCase.java deleted file mode 100644 index f2430128..00000000 --- a/app/src/main/java/com/depromeet/threedays/front/domain/usecase/member/SaveNameUseCase.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.depromeet.threedays.front.domain.usecase.member; - -import com.depromeet.threedays.data.entity.member.MemberEntity; -import com.depromeet.threedays.data.enums.MemberStatus; -import com.depromeet.threedays.front.config.security.AuditorHolder; -import com.depromeet.threedays.front.domain.converter.member.MemberConverter; -import com.depromeet.threedays.front.domain.model.member.Member; -import com.depromeet.threedays.front.exception.ResourceNotFoundException; -import com.depromeet.threedays.front.persistence.repository.member.MemberRepository; -import com.depromeet.threedays.front.web.request.member.MemberNameUpdateRequest; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Transactional -@RequiredArgsConstructor -@Service -public class SaveNameUseCase { - - private final MemberRepository memberRepository; - - public Member execute(final MemberNameUpdateRequest request) { - Long memberId = AuditorHolder.get(); - return MemberConverter.from(this.updateName(memberId, request)); - } - - public MemberEntity updateName(final Long memberId, final MemberNameUpdateRequest request) { - return memberRepository - .findByIdAndStatus(memberId, MemberStatus.REGULAR) - .map(it -> it.updateName(request.getName())) - .orElseThrow(() -> new ResourceNotFoundException("member.not.found")); - } -} diff --git a/app/src/main/java/com/depromeet/threedays/front/domain/usecase/member/SaveResourceUseCase.java b/app/src/main/java/com/depromeet/threedays/front/domain/usecase/member/UpdateMemberUseCase.java similarity index 63% rename from app/src/main/java/com/depromeet/threedays/front/domain/usecase/member/SaveResourceUseCase.java rename to app/src/main/java/com/depromeet/threedays/front/domain/usecase/member/UpdateMemberUseCase.java index 278d897d..05dc4f66 100644 --- a/app/src/main/java/com/depromeet/threedays/front/domain/usecase/member/SaveResourceUseCase.java +++ b/app/src/main/java/com/depromeet/threedays/front/domain/usecase/member/UpdateMemberUseCase.java @@ -8,36 +8,38 @@ import com.depromeet.threedays.front.exception.ResourceNotFoundException; import com.depromeet.threedays.front.persistence.repository.member.MemberRepository; import com.depromeet.threedays.front.support.converter.MemberInfoJsonConverter; -import com.depromeet.threedays.front.web.request.member.MemberResourceUpdateRequest; +import com.depromeet.threedays.front.web.request.member.MemberUpdateRequest; import com.google.gson.JsonElement; import java.util.Map; import java.util.Set; import lombok.RequiredArgsConstructor; import org.json.simple.JSONObject; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -@Transactional @RequiredArgsConstructor @Service -public class SaveResourceUseCase { +public class UpdateMemberUseCase { - private final MemberRepository memberRepository; + private final MemberRepository repository; - public Member execute(final MemberResourceUpdateRequest request) { - Long memberId = AuditorHolder.get(); - return MemberConverter.from(this.updateResource(memberId, request)); + public Member execute(final MemberUpdateRequest request) { + + return MemberConverter.from(this.update(AuditorHolder.get(), request)); } - private MemberEntity updateResource( - final Long memberId, final MemberResourceUpdateRequest request) { - return memberRepository + private MemberEntity update(final Long memberId, final MemberUpdateRequest request) { + return repository .findByIdAndStatus(memberId, MemberStatus.REGULAR) - .map(it -> it.updateResource(this.updateResource(it.getResource(), request.getResource()))) + .map( + it -> + it.update( + request.getName(), + request.isNotificationConsent(), + this.parseSource(it.getResource(), request.getResource()))) .orElseThrow(() -> new ResourceNotFoundException("member.not.found")); } - private String updateResource(String resource, JSONObject newResource) { + private String parseSource(final String resource, final JSONObject newResource) { JSONObject asis = MemberInfoJsonConverter.from(resource); Set> element = newResource.entrySet(); diff --git a/app/src/main/java/com/depromeet/threedays/front/web/controller/MemberController.java b/app/src/main/java/com/depromeet/threedays/front/web/controller/MemberController.java index cc530e6f..b504d1f6 100644 --- a/app/src/main/java/com/depromeet/threedays/front/web/controller/MemberController.java +++ b/app/src/main/java/com/depromeet/threedays/front/web/controller/MemberController.java @@ -12,10 +12,7 @@ import com.depromeet.threedays.front.support.ApiResponseGenerator; import com.depromeet.threedays.front.support.MessageCode; import com.depromeet.threedays.front.web.request.client.DeleteClientRequest; -import com.depromeet.threedays.front.web.request.member.MemberNameUpdateRequest; -import com.depromeet.threedays.front.web.request.member.MemberNotificationConsentUpdateRequest; -import com.depromeet.threedays.front.web.request.member.MemberResourceUpdateRequest; -import com.depromeet.threedays.front.web.request.member.SignMemberRequest; +import com.depromeet.threedays.front.web.request.member.*; import com.depromeet.threedays.front.web.response.SaveMemberResponse; import javax.validation.Valid; import lombok.RequiredArgsConstructor; @@ -29,9 +26,7 @@ public class MemberController { private final SignMemberUseCaseFacade signUseCase; - private final SaveNameUseCase saveNameUseCase; - private final SaveConsentUseCase saveConsentUseCase; - private final SaveResourceUseCase saveResourceUseCase; + private final UpdateMemberUseCase updateMemberUsecase; private final GetTokenUseCase getTokenUseCase; private final DeleteMemberUseCase deleteUseCase; private final DeleteClientUseCase deleteClientUseCase; @@ -50,25 +45,10 @@ public ApiResponse> add( } } - /** 닉네임 변경 */ - @PatchMapping("/name") - public ApiResponse> updateName( - @RequestBody @Valid MemberNameUpdateRequest request) { - return ApiResponseGenerator.success(saveNameUseCase.execute(request), HttpStatus.OK); - } - - /** 알림 수신 설정 변경 */ - @PatchMapping("/consents") - public ApiResponse> updateConsent( - @RequestBody @Valid MemberNotificationConsentUpdateRequest request) { - return ApiResponseGenerator.success(saveConsentUseCase.execute(request), HttpStatus.OK); - } - - /** 사용자 정보 업데이트 */ - @PatchMapping("/resources") - public ApiResponse> updateResource( - @RequestBody @Valid MemberResourceUpdateRequest request) { - return ApiResponseGenerator.success(saveResourceUseCase.execute(request), HttpStatus.OK); + @PatchMapping("/me") + public ApiResponse> updateMember( + @RequestBody @Valid MemberUpdateRequest request) { + return ApiResponseGenerator.success(updateMemberUsecase.execute(request), HttpStatus.OK); } /** 토근 발급 */ diff --git a/app/src/main/java/com/depromeet/threedays/front/web/request/member/MemberUpdateRequest.java b/app/src/main/java/com/depromeet/threedays/front/web/request/member/MemberUpdateRequest.java new file mode 100644 index 00000000..de2e5fc4 --- /dev/null +++ b/app/src/main/java/com/depromeet/threedays/front/web/request/member/MemberUpdateRequest.java @@ -0,0 +1,18 @@ +package com.depromeet.threedays.front.web.request.member; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.json.simple.JSONObject; + +@Getter +@AllArgsConstructor +@NoArgsConstructor +@Builder(toBuilder = true) +public class MemberUpdateRequest { + + private String name; + private boolean notificationConsent; + private JSONObject resource; +} diff --git a/data/src/main/java/com/depromeet/threedays/data/entity/member/MemberEntity.java b/data/src/main/java/com/depromeet/threedays/data/entity/member/MemberEntity.java index 23925dd3..0a355aff 100644 --- a/data/src/main/java/com/depromeet/threedays/data/entity/member/MemberEntity.java +++ b/data/src/main/java/com/depromeet/threedays/data/entity/member/MemberEntity.java @@ -69,6 +69,13 @@ public MemberEntity updateResource(String resource) { return this; } + public MemberEntity update(String name, Boolean consent, String resource) { + this.name = name; + this.notificationConsent = consent; + this.resource = resource; + return this; + } + public MemberEntity withdraw() { status = MemberStatus.WITHDRAWN; return this; From ec547a90377469a8b8b2b2fe7ac3923c4825c6ec Mon Sep 17 00:00:00 2001 From: saint6839 Date: Tue, 27 Dec 2022 22:31:37 +0900 Subject: [PATCH 2/3] =?UTF-8?q?DEP-300=20refactor=20:=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=ED=86=B5=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SaveMemberConsentUseCaseSpec.groovy | 34 ------------------ .../member/SaveMemberNameUseCaseSpec.groovy | 35 ------------------- ....groovy => UpdateMemberUseCaseSpec.groovy} | 15 ++++---- 3 files changed, 9 insertions(+), 75 deletions(-) delete mode 100644 app/src/integration-test/groovy/com/depromeet/threedays/front/domain/usecase/member/SaveMemberConsentUseCaseSpec.groovy delete mode 100644 app/src/integration-test/groovy/com/depromeet/threedays/front/domain/usecase/member/SaveMemberNameUseCaseSpec.groovy rename app/src/integration-test/groovy/com/depromeet/threedays/front/domain/usecase/member/{SaveMemberResourceUseCaseSpec.groovy => UpdateMemberUseCaseSpec.groovy} (66%) diff --git a/app/src/integration-test/groovy/com/depromeet/threedays/front/domain/usecase/member/SaveMemberConsentUseCaseSpec.groovy b/app/src/integration-test/groovy/com/depromeet/threedays/front/domain/usecase/member/SaveMemberConsentUseCaseSpec.groovy deleted file mode 100644 index 2b0c8bf1..00000000 --- a/app/src/integration-test/groovy/com/depromeet/threedays/front/domain/usecase/member/SaveMemberConsentUseCaseSpec.groovy +++ /dev/null @@ -1,34 +0,0 @@ -package com.depromeet.threedays.front.domain.usecase.member - -import com.depromeet.threedays.data.enums.MemberStatus -import com.depromeet.threedays.front.IntegrationTestSpecification -import com.depromeet.threedays.front.data.member.MemberInitializer -import com.depromeet.threedays.front.persistence.repository.member.MemberRepository -import com.depromeet.threedays.front.web.request.member.MemberNotificationConsentUpdateRequest -import org.springframework.beans.factory.annotation.Autowired - -class SaveMemberConsentUseCaseSpec extends IntegrationTestSpecification { - @Autowired - MemberInitializer initializer - MemberRepository mockRepo - SaveConsentUseCase useCase - - def setup() { - initializer.initialize() - mockRepo = Mock(MemberRepository.class) - useCase = new SaveConsentUseCase(mockRepo) - } - - def "사용자는 알림 수신 정책을 수정할 수 있다"() { - setup: - def id = initializer.data[2] - def expected = MemberNotificationConsentUpdateRequest.builder().notificationConsent(false).build() - - when: - def actual = useCase.execute(expected) - - then: - mockRepo.findByIdAndStatus(_ as Long, _ as MemberStatus) >> Optional.of(id) - !actual.notificationConsent - } -} diff --git a/app/src/integration-test/groovy/com/depromeet/threedays/front/domain/usecase/member/SaveMemberNameUseCaseSpec.groovy b/app/src/integration-test/groovy/com/depromeet/threedays/front/domain/usecase/member/SaveMemberNameUseCaseSpec.groovy deleted file mode 100644 index 24267a69..00000000 --- a/app/src/integration-test/groovy/com/depromeet/threedays/front/domain/usecase/member/SaveMemberNameUseCaseSpec.groovy +++ /dev/null @@ -1,35 +0,0 @@ -package com.depromeet.threedays.front.domain.usecase.member - -import com.depromeet.threedays.data.enums.MemberStatus -import com.depromeet.threedays.front.IntegrationTestSpecification -import com.depromeet.threedays.front.data.member.MemberInitializer -import com.depromeet.threedays.front.persistence.repository.member.MemberRepository -import com.depromeet.threedays.front.web.request.member.MemberNameUpdateRequest -import org.springframework.beans.factory.annotation.Autowired - -class SaveMemberNameUseCaseSpec extends IntegrationTestSpecification { - - @Autowired - MemberInitializer initializer - MemberRepository mockRepo - SaveNameUseCase useCase - - def setup() { - mockRepo = Mock(MemberRepository.class) - useCase = new SaveNameUseCase(mockRepo) - initializer.initialize() - } - - def "사용자는 이름을 새로 등록할 수 있다"() { - setup: - def id = initializer.data[2] - def expected = MemberNameUpdateRequest.builder().name("admin").build() - - when: - def actual = useCase.execute(expected) - - then: - mockRepo.findByIdAndStatus(_ as Long, _ as MemberStatus) >> Optional.of(id) - actual.name == expected.name - } -} diff --git a/app/src/integration-test/groovy/com/depromeet/threedays/front/domain/usecase/member/SaveMemberResourceUseCaseSpec.groovy b/app/src/integration-test/groovy/com/depromeet/threedays/front/domain/usecase/member/UpdateMemberUseCaseSpec.groovy similarity index 66% rename from app/src/integration-test/groovy/com/depromeet/threedays/front/domain/usecase/member/SaveMemberResourceUseCaseSpec.groovy rename to app/src/integration-test/groovy/com/depromeet/threedays/front/domain/usecase/member/UpdateMemberUseCaseSpec.groovy index 2abb40d2..d674ff6a 100644 --- a/app/src/integration-test/groovy/com/depromeet/threedays/front/domain/usecase/member/SaveMemberResourceUseCaseSpec.groovy +++ b/app/src/integration-test/groovy/com/depromeet/threedays/front/domain/usecase/member/UpdateMemberUseCaseSpec.groovy @@ -4,30 +4,31 @@ import com.depromeet.threedays.data.enums.MemberStatus import com.depromeet.threedays.front.IntegrationTestSpecification import com.depromeet.threedays.front.data.member.MemberInitializer import com.depromeet.threedays.front.persistence.repository.member.MemberRepository -import com.depromeet.threedays.front.web.request.member.MemberResourceUpdateRequest +import com.depromeet.threedays.front.web.request.member.MemberUpdateRequest import org.json.simple.JSONObject import org.springframework.beans.factory.annotation.Autowired -class SaveMemberResourceUseCaseSpec extends IntegrationTestSpecification { + +class UpdateMemberUseCaseSpec extends IntegrationTestSpecification { @Autowired MemberInitializer initializer MemberRepository mockRepo - SaveResourceUseCase useCase + UpdateMemberUseCase useCase def setup() { initializer.initialize() mockRepo = Mock(MemberRepository.class) - useCase = new SaveResourceUseCase(mockRepo) + useCase = new UpdateMemberUseCase(mockRepo) } - def "사용자는 resource 값을 추가할 수 있다."() { + def "사용자는 name 데이터를 업데이트 할 수 있다"() { setup: def id = initializer.data[2] def json = new JSONObject() json.put("test", "test") - def expected = MemberResourceUpdateRequest.builder().resource(json).build() + def expected = MemberUpdateRequest.builder().resource(json).name("admin").notificationConsent(false).build() when: def actual = useCase.execute(expected) @@ -35,5 +36,7 @@ class SaveMemberResourceUseCaseSpec extends IntegrationTestSpecification { then: mockRepo.findByIdAndStatus(_ as Long, _ as MemberStatus) >> Optional.of(id) actual.resource.get("test") == json.get("test") + actual.name == expected.name + !actual.notificationConsent } } From 150132ded40859e1e52363806b2ac0e478774c2d Mon Sep 17 00:00:00 2001 From: saint6839 Date: Tue, 27 Dec 2022 22:32:06 +0900 Subject: [PATCH 3/3] =?UTF-8?q?DEP-300=20docs=20:=20endpoints=20=ED=86=B5?= =?UTF-8?q?=ED=95=A9=EC=97=90=20=EB=94=B0=EB=A5=B8=20api=20spec=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/resources/static/openapi3.yml | 113 +++++---------------- 1 file changed, 24 insertions(+), 89 deletions(-) diff --git a/app/src/main/resources/static/openapi3.yml b/app/src/main/resources/static/openapi3.yml index 5f777bde..2bb5a1b3 100644 --- a/app/src/main/resources/static/openapi3.yml +++ b/app/src/main/resources/static/openapi3.yml @@ -431,87 +431,17 @@ paths: example: - code: "uncaught error" message: "서버 에러" - /api/v1/members/logout: - post: - tags: - - Member - summary: 로그아웃 API - operationId: logoutMember - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - identificationKey: - type: string - example: identificationKey - responses: - '200': - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/ApiResponse' - '500': - description: INTERNAL SERVER ERROR - content: - application/json: - schema: - $ref: '#/components/schemas/ApiFailureResponse' - example: - - code: "uncaught error" - message: "서버 에러" - /api/v1/members/name: - patch: - tags: - - Member - summary: 닉네임 수정 API - operationId: patchMemberName - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/MemberNameUpdateRequest' - responses: - '200': - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/Member' - '400': - description: BAD REQUEST - content: - application/json: - schema: - $ref: '#/components/schemas/ApiFailureResponse' - example: - - code: "invalid.id" - message: "id는 숫자여야만 합니다." - '500': - description: INTERNAL SERVER ERROR - content: - application/json: - schema: - $ref: '#/components/schemas/ApiFailureResponse' - example: - - code: "uncaught error" - message: "서버 에러" - /api/v1/members/consents: patch: tags: - Member - summary: 알림수신여부 수정 API - operationId: patchMemberNotificationConsent + summary: 사용자 관련 정보 수정 API + operationId: patchMember requestBody: required: true content: application/json: schema: - $ref: '#/components/schemas/MemberNotificationConsentUpdateRequest' + $ref: '#/components/schemas/MemberUpdateRequest' responses: '200': description: OK @@ -537,35 +467,29 @@ paths: example: - code: "uncaught error" message: "서버 에러" - /api/v1/members/resource: - patch: + /api/v1/members/logout: + post: tags: - Member - summary: 리소스 수정 API - description: 멤버용 리소스를 저장하기 위한 API입니다. 전송한 키값이 기존에 존재하는 경우 새로운 값으로 덮어써지며, 새로운 키값의 경우에는 추가됩니다(리소스 오브젝트가 전체 교체되지 않습니다) - operationId: patchMemberResource + summary: 로그아웃 API + operationId: logoutMember requestBody: required: true content: application/json: schema: - $ref: '#/components/schemas/MemberResourceRequest' + type: object + properties: + identificationKey: + type: string + example: identificationKey responses: '200': description: OK content: application/json: schema: - $ref: '#/components/schemas/Member' - '400': - description: BAD REQUEST - content: - application/json: - schema: - $ref: '#/components/schemas/ApiFailureResponse' - example: - - code: "invalid.id" - message: "id는 숫자여야만 합니다." + $ref: '#/components/schemas/ApiResponse' '500': description: INTERNAL SERVER ERROR content: @@ -1052,6 +976,17 @@ components: socialToken: type: string example: "oauth access token" + MemberUpdateRequest: + type: object + properties: + name: + type: string + example: admin + notificationConsent: + type: boolean + example: false + resource: + type: object MemberNameUpdateRequest: type: object properties: