Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

release: v2.1.0 #932

Merged
merged 15 commits into from
Mar 12, 2023
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
4a11b0c
feat: 비밀번호 변경 기능 (#917)
tributetothemoon Mar 12, 2023
23a5203
feat: 회원 정보 수정에서 회원 스스로의 닉네임은 중복검사에서 제외하는 분기 생성 (#922)
tributetothemoon Mar 12, 2023
e515447
docs: build-fe.sh script 초기 세팅 부분 제거 (#921)
sakjung Mar 12, 2023
b8677b0
feat: 비회원 예약 조회 개선 (#919)
sakjung Mar 12, 2023
b896406
feat: 내 정보 수정 페이지 UI 및 API 연동 구현 (#924)
Puterism Mar 12, 2023
61b5024
fix: iOS에서 로그인 후 예약 시 이름 필드 흐리게 보이는 현상 해결 (#925)
Puterism Mar 12, 2023
bec7e39
fix: 비밀번호 변경 테스트 요청 url 오기입 수정 (#926)
tributetothemoon Mar 12, 2023
874d9b9
docs: 비밀번호 변경 API 문서 추가 (#927)
tributetothemoon Mar 12, 2023
c67951c
feat: 비활성화 상태를 좀 더 명확하게 구분하기 (#920)
SunYoungKwon Mar 12, 2023
b2a3170
feat: 로그인 유저의 비밀번호 변경 기능 (#928)
yujo11 Mar 12, 2023
0f9f550
feat: 비회원 예약 조회 loader 추가 (#930)
sakjung Mar 12, 2023
df8fd09
feat: 비밀번호 변경 api에서 기존 비밀번호 오기입시 에러 메세지 구체화, 기존 비밀번호에 대해 패턴 검사를 실시하지 …
tributetothemoon Mar 12, 2023
0faed7b
chore: version up 2.0.0 -> 2.1.0 (#931)
yujo11 Mar 12, 2023
de9756a
feat: 내 정보 조회시 oauth provider 정보 필드 추가 (#936)
sakjung Mar 12, 2023
3942978
feat: OAuth 로그인일 경우 비밀번호 변경 텍스트, 링크가 보이지 않도록 하는 기능 (#935)
yujo11 Mar 12, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions backend/src/docs/asciidoc/member.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ include::{snippets}/member/myinfo/put/http-request.adoc[]
==== Response
include::{snippets}/member/myinfo/put/http-response.adoc[]

=== 비밀번호 변경
==== Request
include::{snippets}/member/password/put/http-request.adoc[]
==== Response
include::{snippets}/member/password/put/http-response.adoc[]

=== 회원 탈퇴
==== Request
include::{snippets}/member/myinfo/delete/http-request.adoc[]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.woowacourse.zzimkkong.config.logaspect.LogMethodExecutionTime;
import com.woowacourse.zzimkkong.domain.LoginEmail;
import com.woowacourse.zzimkkong.dto.member.ChangePasswordRequest;
import com.woowacourse.zzimkkong.dto.member.*;
import com.woowacourse.zzimkkong.dto.member.oauth.OauthMemberSaveRequest;
import com.woowacourse.zzimkkong.service.MemberService;
Expand Down Expand Up @@ -76,4 +77,10 @@ public ResponseEntity<ProfileEmojisResponse> getEmojis() {
ProfileEmojisResponse profileEmojis = memberService.getProfileEmojis();
return ResponseEntity.ok().body(profileEmojis);
}

@PutMapping("/me/password")
public ResponseEntity<Void> changePassword(@LoginEmail final LoginUserEmail loginUserEmail, @RequestBody @Valid final ChangePasswordRequest changePasswordRequest) {
memberService.changePassword(loginUserEmail, changePasswordRequest);
return ResponseEntity.ok().build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,8 @@ public void update(final MemberUpdateRequest memberUpdateRequest) {
public boolean hasEmail(String email) {
return this.email.equals(email);
}

public void updatePassword(String password) {
this.password = password;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.woowacourse.zzimkkong.dto.member;

import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;

import static com.woowacourse.zzimkkong.dto.ValidatorMessage.*;

@Getter
@NoArgsConstructor
public class ChangePasswordRequest {
@NotBlank(message = EMPTY_MESSAGE)
private String oldPassword;

@NotNull(message = EMPTY_MESSAGE)
@Pattern(regexp = MEMBER_PW_FORMAT, message = MEMBER_PW_MESSAGE)
private String newPassword;

@NotNull(message = EMPTY_MESSAGE)
@Pattern(regexp = MEMBER_PW_FORMAT, message = MEMBER_PW_MESSAGE)
private String newPasswordConfirm;

public ChangePasswordRequest(String oldPassword, String newPassword, String newPasswordConfirm) {
this.oldPassword = oldPassword;
this.newPassword = newPassword;
this.newPasswordConfirm = newPasswordConfirm;
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package com.woowacourse.zzimkkong.dto.member;

import com.woowacourse.zzimkkong.domain.ProfileEmoji;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ProfileEmojiResponse {
private ProfileEmoji name;
private String code;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
package com.woowacourse.zzimkkong.dto.reservation;

import com.woowacourse.zzimkkong.domain.Reservation;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.List;
import java.util.stream.Collectors;

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ReservationInfiniteScrollResponse {
private List<ReservationOwnerResponse> data;
private Boolean hasNext;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@

import com.fasterxml.jackson.annotation.JsonFormat;
import com.woowacourse.zzimkkong.domain.Map;
import com.woowacourse.zzimkkong.domain.Member;
import com.woowacourse.zzimkkong.domain.Reservation;
import com.woowacourse.zzimkkong.domain.Space;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.time.ZonedDateTime;

Expand All @@ -15,6 +16,8 @@

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ReservationOwnerResponse {
private Long id;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = DATETIME_FORMAT)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.woowacourse.zzimkkong.dto.space;

import com.woowacourse.zzimkkong.domain.Space;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.Collection;
import java.util.List;
Expand All @@ -11,6 +13,8 @@

@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class SpaceFindAllAvailabilityResponse {
private Long mapId;
private List<SpaceFindAvailabilityResponse> spaces;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
package com.woowacourse.zzimkkong.dto.space;

import com.woowacourse.zzimkkong.domain.Space;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.Collection;
import java.util.Set;


@Builder
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SpaceFindAvailabilityResponse {
private Long spaceId;
private Boolean isAvailable;
Expand All @@ -21,3 +23,4 @@ public static SpaceFindAvailabilityResponse of(final Space space, final Collecti
.build();
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.woowacourse.zzimkkong.exception.member;

import com.woowacourse.zzimkkong.exception.ZzimkkongException;
import org.springframework.http.HttpStatus;

public class ConfirmationNewPasswordMismatchException extends ZzimkkongException {
private static final String MESSAGE = "새 비밀번호가 확인란과 일치하지 않습니다.";

public ConfirmationNewPasswordMismatchException() {
super(MESSAGE, HttpStatus.BAD_REQUEST);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.woowacourse.zzimkkong.exception.member;

import com.woowacourse.zzimkkong.exception.InputFieldException;
import org.springframework.http.HttpStatus;

public class PasswordMismatchException extends InputFieldException {
private static final String MESSAGE = "기존 비밀번호가 일치하지 않습니다.";

public PasswordMismatchException() {
super(MESSAGE, HttpStatus.BAD_REQUEST, PASSWORD);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ Slice<Reservation> findAllByMemberAndReservationTimeDateLessThanEqualAndReservat
final LocalDateTime dateTime,
final Pageable pageable);

Slice<Reservation> findAllByUserNameAndReservationTimeDateGreaterThanEqualAndReservationTimeStartTimeGreaterThanEqualAndMemberIsNull(
Slice<Reservation> findAllByUserNameAndReservationTimeDateGreaterThanEqualAndReservationTimeEndTimeGreaterThanEqualAndMemberIsNull(
final String userName,
final LocalDate date,
final LocalDateTime dateTime,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,15 @@
import com.woowacourse.zzimkkong.domain.ProfileEmoji;
import com.woowacourse.zzimkkong.dto.member.*;
import com.woowacourse.zzimkkong.dto.member.oauth.OauthMemberSaveRequest;
import com.woowacourse.zzimkkong.exception.member.DuplicateEmailException;
import com.woowacourse.zzimkkong.exception.member.DuplicateUserNameException;
import com.woowacourse.zzimkkong.exception.member.NoSuchMemberException;
import com.woowacourse.zzimkkong.exception.member.ReservationExistsOnMemberException;
import com.woowacourse.zzimkkong.exception.member.*;
import com.woowacourse.zzimkkong.repository.MemberRepository;
import com.woowacourse.zzimkkong.repository.ReservationRepository;
import net.logstash.logback.encoder.org.apache.commons.lang3.StringUtils;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Transactional
Expand Down Expand Up @@ -93,7 +87,9 @@ public void updateMember(final LoginUserEmail loginUserEmail, final MemberUpdate
Member member = members.findByEmail(loginUserEmail.getEmail())
.orElseThrow(NoSuchMemberException::new);

validateDuplicateUserName(memberUpdateRequest.getUserName());
if (!member.getUserName().equals(memberUpdateRequest.getUserName())) {
validateDuplicateUserName(memberUpdateRequest.getUserName());
}

member.update(memberUpdateRequest);
}
Expand All @@ -113,4 +109,26 @@ public void deleteMember(final LoginUserEmail loginUserEmail) {
public ProfileEmojisResponse getProfileEmojis() {
return ProfileEmojisResponse.from(List.of(ProfileEmoji.values()));
}

public void changePassword(final LoginUserEmail loginUserEmail, final ChangePasswordRequest changePasswordRequest) {
Member member = members.findByEmail(loginUserEmail.getEmail())
.orElseThrow(NoSuchMemberException::new);
validateOldPassword(member, changePasswordRequest);
validateConfirmationPassword(changePasswordRequest);

String newPassword = passwordEncoder.encode(changePasswordRequest.getNewPassword());
member.updatePassword(newPassword);
}

private void validateOldPassword(final Member member, final ChangePasswordRequest changePasswordRequest) {
if (!passwordEncoder.matches(changePasswordRequest.getOldPassword(), member.getPassword())) {
throw new PasswordMismatchException();
}
}

private void validateConfirmationPassword(final ChangePasswordRequest changePasswordRequest) {
if (!changePasswordRequest.getNewPassword().equals(changePasswordRequest.getNewPasswordConfirm())) {
throw new ConfirmationNewPasswordMismatchException();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ public ReservationInfiniteScrollResponse findUpcomingNonLoginReservations(
final String userName,
final LocalDateTime searchStartTime,
final Pageable pageable) {
Slice<Reservation> reservationSlice = reservations.findAllByUserNameAndReservationTimeDateGreaterThanEqualAndReservationTimeStartTimeGreaterThanEqualAndMemberIsNull(
Slice<Reservation> reservationSlice = reservations.findAllByUserNameAndReservationTimeDateGreaterThanEqualAndReservationTimeEndTimeGreaterThanEqualAndMemberIsNull(
userName,
TimeZoneUtils.convertTo(searchStartTime, ServiceZone.KOREA).toLocalDate(),
searchStartTime,
Expand Down
2 changes: 1 addition & 1 deletion backend/src/main/resources/config
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,24 @@ void findEmojis() {
assertThat(actual).usingRecursiveComparison().isEqualTo(expected);
}

@Test
@DisplayName("비밀번호를 변경할 수 있다.")
void changePassword() {
//given
String newPassword = "newPassword1234";
ChangePasswordRequest changePasswordRequest = new ChangePasswordRequest(PW, newPassword, newPassword);

//when
ExtractableResponse<Response> response = changePassword(changePasswordRequest);

//then
assertThat(response.statusCode()).isEqualTo(HttpStatus.OK.value());

LoginRequest loginRequest = new LoginRequest(EMAIL, newPassword);
ExtractableResponse<Response> loginResponse = login(loginRequest);
assertThat(loginResponse.statusCode()).isEqualTo(HttpStatus.OK.value());
}

static ExtractableResponse<Response> saveMember(final MemberSaveRequest memberSaveRequest) {
return RestAssured
.given(getRequestSpecification()).log().all()
Expand Down Expand Up @@ -240,4 +258,27 @@ private ExtractableResponse<Response> findProfileEmojis() {
.when().get("/api/members/emojis")
.then().log().all().extract();
}

private ExtractableResponse<Response> changePassword(ChangePasswordRequest changePasswordRequest) {
return RestAssured
.given(getRequestSpecification()).log().all()
.accept("application/json")
.header("Authorization", AuthorizationExtractor.AUTHENTICATION_TYPE + " " + accessToken)
.filter(document("member/password/put", getRequestPreprocessor(), getResponsePreprocessor()))
.contentType(MediaType.APPLICATION_JSON_VALUE)
.body(changePasswordRequest)
.when().put("/api/members/me/password")
.then().log().all().extract();
}

private ExtractableResponse<Response> login(final LoginRequest loginRequest) {
return RestAssured
.given(getRequestSpecification()).log().all()
.accept("application/json")
.filter(document("member/login", getRequestPreprocessor(), getResponsePreprocessor()))
.contentType(MediaType.APPLICATION_JSON_VALUE)
.body(loginRequest)
.when().post("/api/members/login/token")
.then().log().all().extract();
}
}
Loading