diff --git a/build.gradle b/build.gradle index 6ddcb097..dc3b9517 100644 --- a/build.gradle +++ b/build.gradle @@ -35,7 +35,6 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'mysql:mysql-connector-java:8.0.32' implementation 'org.springframework.boot:spring-boot-starter-validation' - implementation 'org.openapitools:jackson-databind-nullable:0.2.1' } diff --git a/src/main/java/umc/kkijuk/server/common/LoginUser.java b/src/main/java/umc/kkijuk/server/common/LoginUser.java index 462f53ad..755d2077 100644 --- a/src/main/java/umc/kkijuk/server/common/LoginUser.java +++ b/src/main/java/umc/kkijuk/server/common/LoginUser.java @@ -1,12 +1,19 @@ package umc.kkijuk.server.common; +import lombok.Getter; + +@Getter public class LoginUser { - private static final LoginUser LOGIN_USER = new LoginUser(0L); + + private Long id; + private static final LoginUser LOGIN_USER = new LoginUser(1L); public LoginUser(Long id) { + this.id = id; } public static LoginUser get() { return LOGIN_USER; } + } diff --git a/src/main/java/umc/kkijuk/server/member/controller/MemberController.java b/src/main/java/umc/kkijuk/server/member/controller/MemberController.java index 0463df36..4994fa20 100644 --- a/src/main/java/umc/kkijuk/server/member/controller/MemberController.java +++ b/src/main/java/umc/kkijuk/server/member/controller/MemberController.java @@ -1,13 +1,181 @@ package umc.kkijuk.server.member.controller; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Controller; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import umc.kkijuk.server.common.LoginUser; +import umc.kkijuk.server.member.domain.Member; +import umc.kkijuk.server.member.dto.MemberFieldDto; +import umc.kkijuk.server.member.dto.MemberInfoChangeDto; +import umc.kkijuk.server.member.dto.MemberJoinDto; import umc.kkijuk.server.member.service.MemberService; +import lombok.Data; +import lombok.RequiredArgsConstructor; + +import java.time.LocalDate; +import java.util.List; + -@Controller +@Tag(name = "member", description = "회원 관리 API") +@RestController +@RequestMapping("/member") @RequiredArgsConstructor public class MemberController { private final MemberService memberService; + @Operation( + summary = "회원가입 요청", + description = "회원가입 요청을 받아 성공/실패 여부를 반환합니다.") + @PostMapping + public ResponseEntity saveMember(@RequestBody @Valid MemberJoinDto memberJoinDto) { + String passwordConfirm = memberJoinDto.getPasswordConfirm(); + if (!passwordConfirm.equals(memberJoinDto.getPassword())) { + return ResponseEntity + .status(HttpStatus.BAD_REQUEST) + .body(new CreateMemberResponse("Passwords do not match")); + } + + try { + Long memberId = memberService.join(memberJoinDto.toEntity()); + return ResponseEntity + .status(HttpStatus.CREATED) + .body(new CreateMemberResponse(memberId, "Member created successfully")); + } catch (Exception e) { + e.printStackTrace(); + return ResponseEntity + .status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(new CreateMemberResponse("Member creation failed")); + } + } + + /** + 일단 RequestParam 사용, 나중에 jwt토큰으로 사용자 정보 식별할 수 있도록 변경 + */ + @Operation( + summary = "내 정보 조회", + description = "마이페이지에서 내 정보들을 가져옵니다.") + @GetMapping("/myPage/info") + public ResponseEntity getInfo() { + try { + Long loginUser = LoginUser.get().getId(); + Member member = memberService.getMemberInfo(loginUser); + MemberInfoResponse response = new MemberInfoResponse( + member.getEmail(), + member.getName(), + member.getPhoneNumber(), + member.getBirthDate() + ); + return ResponseEntity.ok(response); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } + + @Operation( + summary = "내 정보 수정", + description = "내 정보 수정 요청을 받아 성공/실패를 반환합니다.") + @PutMapping("/myPage/info") + public ResponseEntity changeMemberInfo(@RequestBody MemberInfoChangeDto memberInfoChangeDto) { + Long loginUser = LoginUser.get().getId(); + try { + memberService.updateMemberInfo(loginUser, memberInfoChangeDto); + return ResponseEntity.ok() + .body(new ResultResponse("information update success")); + }catch (Exception e){ + return ResponseEntity + .status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(new ResultResponse("information update failed")); + } + + } + + + @Operation( + summary = "관심분야 조회", + description = "마이페이지에서 관심분야를 조회합니다.") + @GetMapping("/myPage/field") + public ResponseEntity getField() { + try { + Long loginUser = LoginUser.get().getId(); + List memberField = memberService.getMemberField(loginUser); + return ResponseEntity.ok().body(new MemberFieldResponse(memberField)); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } + + @Operation( + summary = "관심분야 등록/수정", + description = "초기/마이페이지에서 관심분야를 등록/수정합니다.") + @PostMapping({"/field", "/myPage/field"}) + public ResponseEntity postField(@RequestBody @Valid MemberFieldDto memberFieldDto) { + try { + Long loginUserId = LoginUser.get().getId(); + List updatedMember = memberService.updateMemberField(loginUserId, memberFieldDto); + MemberFieldResponse response = new MemberFieldResponse(updatedMember); + return ResponseEntity.ok(response); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } + + + + @Data + static class CreateMemberResponse { + private Long id; + private String message; + + public CreateMemberResponse(String message) { + this.message = message; + } + + public CreateMemberResponse(Long id, String message) { + this.id = id; + this.message = message; + } + } + + @Data + static class ResultResponse{ + private String message; + + public ResultResponse(String message) { + this.message = message; + } + } + + @Data + static class MemberInfoResponse { + private String email; + private String name; + private String phoneNumber; + private LocalDate birthDate; + + public MemberInfoResponse(String email, String name, String phoneNumber, LocalDate birthDate) { + this.email = email; + this.name = name; + this.phoneNumber = phoneNumber; + this.birthDate = birthDate; + } + } + + @Data + static class MemberFieldResponse{ + private List field; + + public MemberFieldResponse(List field) { + this.field = field; + } + } } + + + + + + diff --git a/src/main/java/umc/kkijuk/server/member/domain/MarketingAgree.java b/src/main/java/umc/kkijuk/server/member/domain/MarketingAgree.java new file mode 100644 index 00000000..a35aa651 --- /dev/null +++ b/src/main/java/umc/kkijuk/server/member/domain/MarketingAgree.java @@ -0,0 +1,11 @@ +package umc.kkijuk.server.member.domain; + +public enum MarketingAgree { + BOTH, + + EMAIL, + + SMS, + + NONE +} diff --git a/src/main/java/umc/kkijuk/server/member/domain/Member.java b/src/main/java/umc/kkijuk/server/member/domain/Member.java index 2628beb1..a3e9016e 100644 --- a/src/main/java/umc/kkijuk/server/member/domain/Member.java +++ b/src/main/java/umc/kkijuk/server/member/domain/Member.java @@ -1,22 +1,23 @@ package umc.kkijuk.server.member.domain; + import jakarta.persistence.*; import jakarta.validation.constraints.NotNull; import lombok.*; -import umc.kkijuk.server.member.converter.StringListConverter; import java.time.LocalDate; import java.util.List; -import java.util.ArrayList; + +import umc.kkijuk.server.common.converter.StringListToStringConverter; @Entity +@Getter @Builder -@Getter @Setter -@NoArgsConstructor @AllArgsConstructor +@NoArgsConstructor public class Member { - @Id @GeneratedValue + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "member_id") private Long id; @@ -35,17 +36,22 @@ public class Member { @NotNull private String password; - @Convert(converter = StringListConverter.class) - private List field = new ArrayList<>(); + + @Convert(converter = StringListToStringConverter.class) + private List field; @NotNull - private Boolean marketingAgree; + @Enumerated(EnumType.STRING) + private MarketingAgree marketingAgree; @NotNull @Enumerated(EnumType.STRING) private State userState; - public Member(String email, String name, String phoneNumber, LocalDate birthDate, String password, Boolean marketingAgree, State userState) { + private LocalDate deleteDate; + + + public Member( String email, String name, String phoneNumber, LocalDate birthDate, String password, MarketingAgree marketingAgree, State userState) { this.email = email; this.name = name; this.phoneNumber = phoneNumber; @@ -54,5 +60,16 @@ public Member(String email, String name, String phoneNumber, LocalDate birthDate this.marketingAgree = marketingAgree; this.userState = userState; } -} + public void changeFieldInfo(List field){ + this.field = field; + } + + public void changeMemberInfo(String phoneNumber, LocalDate birthDate, MarketingAgree marketingAgree){ + this.phoneNumber = phoneNumber; + this.birthDate = birthDate; + this.marketingAgree = marketingAgree; + } + + +} diff --git a/src/main/java/umc/kkijuk/server/member/dto/MemberFieldDto.java b/src/main/java/umc/kkijuk/server/member/dto/MemberFieldDto.java new file mode 100644 index 00000000..f84fcb94 --- /dev/null +++ b/src/main/java/umc/kkijuk/server/member/dto/MemberFieldDto.java @@ -0,0 +1,19 @@ +package umc.kkijuk.server.member.dto; + +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + + +@Data +@NoArgsConstructor +public class MemberFieldDto { + private List field; + + @Builder + public MemberFieldDto(List field) { + this.field = field; + } +} diff --git a/src/main/java/umc/kkijuk/server/member/dto/MemberInfoChangeDto.java b/src/main/java/umc/kkijuk/server/member/dto/MemberInfoChangeDto.java new file mode 100644 index 00000000..b4df23ea --- /dev/null +++ b/src/main/java/umc/kkijuk/server/member/dto/MemberInfoChangeDto.java @@ -0,0 +1,25 @@ +package umc.kkijuk.server.member.dto; + + +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import umc.kkijuk.server.member.domain.MarketingAgree; + +import java.time.LocalDate; + +@Data +@NoArgsConstructor +public class MemberInfoChangeDto { + private Long id; //jwt토큰으로 받을땐 제거 + private String phoneNumber; + private LocalDate birthDate; + private MarketingAgree marketingAgree; + + @Builder + public MemberInfoChangeDto(String phoneNumber, LocalDate birthDate, MarketingAgree marketingAgree) { + this.phoneNumber = phoneNumber; + this.birthDate = birthDate; + this.marketingAgree = marketingAgree; + } +} diff --git a/src/main/java/umc/kkijuk/server/member/dto/MemberJoinDto.java b/src/main/java/umc/kkijuk/server/member/dto/MemberJoinDto.java new file mode 100644 index 00000000..85bd9421 --- /dev/null +++ b/src/main/java/umc/kkijuk/server/member/dto/MemberJoinDto.java @@ -0,0 +1,62 @@ +package umc.kkijuk.server.member.dto; + +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import umc.kkijuk.server.member.domain.MarketingAgree; +import umc.kkijuk.server.member.domain.Member; +import umc.kkijuk.server.member.domain.State; + +import java.time.LocalDate; + +@Data +@NoArgsConstructor +public class MemberJoinDto { + + private String email; + private String name; + private String phoneNumber; + private LocalDate birthDate; + private String password; + private String passwordConfirm; + private MarketingAgree marketingAgree; + private State userState; + +// @Builder +// public MemberJoinDto(String email, String name, String phoneNumber, LocalDate birthDate, +// String password, Boolean marketingAgree, State userState) { +// this.email = email; +// this.name = name; +// this.phoneNumber = phoneNumber; +// this.birthDate = birthDate; +// this.password = password; +// this.marketingAgree = marketingAgree; +// this.userState = userState; +// } + + @Builder + public MemberJoinDto(String email, String name, String phoneNumber, LocalDate birthDate, + String password, String passwordConfirm, MarketingAgree marketingAgree, State userState) { + this.email = email; + this.name = name; + this.phoneNumber = phoneNumber; + this.birthDate = birthDate; + this.password = password; + this.passwordConfirm = passwordConfirm; + this.marketingAgree = marketingAgree; + this.userState = userState; + } + + public Member toEntity() { + return Member.builder() + .email(email) + .name(name) + .phoneNumber(phoneNumber) + .birthDate(birthDate) + .password(password) + .marketingAgree(marketingAgree) + .userState(userState) + .build(); + } + +} diff --git a/src/main/java/umc/kkijuk/server/member/service/MemberService.java b/src/main/java/umc/kkijuk/server/member/service/MemberService.java index 5b6bd96e..3ba0a4ff 100644 --- a/src/main/java/umc/kkijuk/server/member/service/MemberService.java +++ b/src/main/java/umc/kkijuk/server/member/service/MemberService.java @@ -4,9 +4,11 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import umc.kkijuk.server.member.domain.Member; +import umc.kkijuk.server.member.dto.MemberFieldDto; +import umc.kkijuk.server.member.dto.MemberInfoChangeDto; import umc.kkijuk.server.member.repository.MemberJpaRepository; -import umc.kkijuk.server.recruit.domain.Recruit; -import umc.kkijuk.server.recruit.infrastructure.RecruitEntity; + +import java.util.List; @Service @Transactional(readOnly = true) @@ -20,9 +22,38 @@ public Member findOne(Long memberId) { //아직 인터페이스 구현 x, 추후에 구현 후 MemberService -> MemberServiceImpl로 수정 예정. + @Transactional public Long join(Member member) { memberJpaRepository.save(member); return member.getId(); } + public Member getMemberInfo(Long memberId) { + return memberJpaRepository.findById(memberId) + .orElseThrow(() -> new IllegalArgumentException("Member not found")); + } + + public List getMemberField(Long memberId){ + Member member = memberJpaRepository.findById(memberId) + .orElseThrow(() -> new IllegalArgumentException("Member not found")); + return member.getField(); + } + + @Transactional + public List updateMemberField(Long id,MemberFieldDto memberFieldDto){ + Member member = memberJpaRepository.findById(id) + .orElseThrow(() -> new IllegalArgumentException("Member not found")); + member.changeFieldInfo(memberFieldDto.getField()); + return member.getField(); + } + + @Transactional + public Long updateMemberInfo(Long id,MemberInfoChangeDto memberInfoChangeDto){ + Member member = memberJpaRepository.findById(id) + .orElseThrow(() -> new IllegalArgumentException("Member not found")); + member.changeMemberInfo(memberInfoChangeDto.getPhoneNumber(), memberInfoChangeDto.getBirthDate(), memberInfoChangeDto.getMarketingAgree()); + return member.getId(); + } + + } diff --git a/src/test/java/umc/kkijuk/server/member/service/MemberServiceTest.java b/src/test/java/umc/kkijuk/server/member/service/MemberServiceTest.java index 879f0bb3..a25613f9 100644 --- a/src/test/java/umc/kkijuk/server/member/service/MemberServiceTest.java +++ b/src/test/java/umc/kkijuk/server/member/service/MemberServiceTest.java @@ -1,39 +1,98 @@ package umc.kkijuk.server.member.service; - import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.transaction.annotation.Transactional; +import umc.kkijuk.server.member.domain.MarketingAgree; import umc.kkijuk.server.member.domain.Member; import umc.kkijuk.server.member.domain.State; +import umc.kkijuk.server.member.dto.MemberJoinDto; import umc.kkijuk.server.member.repository.MemberJpaRepository; import java.time.LocalDate; -import java.util.List; import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; - -@SpringBootTest +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @Transactional public class MemberServiceTest { - @Autowired MemberService memberService; + @Autowired + MemberService memberService; + @Autowired MemberJpaRepository memberJpaRepository; + @Autowired + private TestRestTemplate restTemplate; + @Test public void 유저정보db저장및조회() throws Exception { - //given - Member member1 = new Member("asd@naver.com", "홍길동", "010-7444-1768", LocalDate.now(), "passwordTest", Boolean.TRUE, State.ACTIVATE); - //when + // given + Member member1 = new Member("asd@naver.com", "홍길동", "010-7444-1768", LocalDate.now(), "passwordTest", MarketingAgree.BOTH, State.ACTIVATE); + + // when Long savedId = memberService.join(member1); Optional member2 = memberJpaRepository.findById(savedId); - //then + + // then assertEquals(member1, member2.get()); } + + @Test + public void 회원가입성공() { + // given + MemberJoinDto memberJoinDto = MemberJoinDto.builder() + .email("asd@naver.com") + .name("홍길동") + .phoneNumber("010-7444-1768") + .birthDate(LocalDate.now()) + .password("passwordTest") + .passwordConfirm("passwordTest") + .marketingAgree(MarketingAgree.BOTH) + .userState(State.ACTIVATE) + .build(); + + HttpEntity request = new HttpEntity<>(memberJoinDto); + + // when + ResponseEntity response = restTemplate.postForEntity("/member", request, String.class); + + // then + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED); + assertThat(response.getBody()).contains("Member created successfully"); + } + + @Test + public void 회원가입실패_비밀번호불일치() { + // given + MemberJoinDto memberJoinDto = MemberJoinDto.builder() + .email("asd@naver.com") + .name("홍길동") + .phoneNumber("010-7444-1768") + .birthDate(LocalDate.now()) + .password("passwordTest") + .passwordConfirm("wrongPassword") + .marketingAgree(MarketingAgree.BOTH) + .userState(State.ACTIVATE) + .build(); + + HttpEntity request = new HttpEntity<>(memberJoinDto); + + // when + ResponseEntity response = restTemplate.postForEntity("/member", request, String.class); + + // then + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST); + assertThat(response.getBody()).contains("Passwords do not match"); + } + + }