Skip to content

Commit

Permalink
Merge pull request #87 from side-peek/feat/#85-user-profile-swagger
Browse files Browse the repository at this point in the history
회원 프로필 조회/수정 및 비밀번호 수정 api 스웨거 설정
  • Loading branch information
Sehee-Lee-01 authored Mar 5, 2024
2 parents 7f87e15 + 19bcaff commit 1b50f5c
Show file tree
Hide file tree
Showing 24 changed files with 293 additions and 46 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package sixgaezzang.sidepeek.common.exception.message;

import static sixgaezzang.sidepeek.common.util.CommonConstant.MAX_TEXT_LENGTH;

public class CommonErrorMessage {
// Github url
public static final String GITHUB_URL_IS_INVALID = "Github URL 형식이 유효하지 않습니다.";
public static final String GITHUB_URL_IS_NULL = "Github URL을 입력해주세요.";
public static final String GITHUB_URL_OVER_MAX_LENGTH = "Github URL은 " + MAX_TEXT_LENGTH + "자 이하여야 합니다.";
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import static sixgaezzang.sidepeek.projects.exception.message.MemberErrorMessage.MEMBER_IS_INVALID;
import static sixgaezzang.sidepeek.projects.util.ProjectConstant.MAX_ROLE_LENGTH;
import static sixgaezzang.sidepeek.users.domain.User.MAX_NICKNAME_LENGTH;
import static sixgaezzang.sidepeek.users.util.UserConstant.MAX_NICKNAME_LENGTH;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import static sixgaezzang.sidepeek.projects.exception.message.MemberErrorMessage.NON_FELLOW_MEMBER_NICKNAME_OVER_MAX_LENGTH;
import static sixgaezzang.sidepeek.projects.exception.message.MemberErrorMessage.ROLE_OVER_MAX_LENGTH;
import static sixgaezzang.sidepeek.projects.util.ProjectConstant.MAX_ROLE_LENGTH;
import static sixgaezzang.sidepeek.users.domain.User.MAX_NICKNAME_LENGTH;
import static sixgaezzang.sidepeek.users.util.UserConstant.MAX_NICKNAME_LENGTH;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Min;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package sixgaezzang.sidepeek.projects.dto.request;

import static sixgaezzang.sidepeek.common.exception.message.CommonErrorMessage.GITHUB_URL_IS_INVALID;
import static sixgaezzang.sidepeek.common.exception.message.CommonErrorMessage.GITHUB_URL_IS_NULL;
import static sixgaezzang.sidepeek.common.util.CommonConstant.MIN_ID;
import static sixgaezzang.sidepeek.common.util.Regex.URL_REGEXP;
import static sixgaezzang.sidepeek.projects.exception.message.ProjectErrorMessage.DEPLOY_URL_IS_INVALID;
import static sixgaezzang.sidepeek.projects.exception.message.ProjectErrorMessage.DESCRIPTION_IS_NULL;
import static sixgaezzang.sidepeek.projects.exception.message.ProjectErrorMessage.GITHUB_URL_IS_INVALID;
import static sixgaezzang.sidepeek.projects.exception.message.ProjectErrorMessage.GITHUB_URL_IS_NULL;
import static sixgaezzang.sidepeek.projects.exception.message.ProjectErrorMessage.NAME_IS_NULL;
import static sixgaezzang.sidepeek.projects.exception.message.ProjectErrorMessage.NAME_OVER_MAX_LENGTH;
import static sixgaezzang.sidepeek.projects.exception.message.ProjectErrorMessage.OVERVIEW_IS_NULL;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import static sixgaezzang.sidepeek.projects.util.ProjectConstant.MAX_MEMBER_COUNT;
import static sixgaezzang.sidepeek.projects.util.ProjectConstant.MAX_ROLE_LENGTH;
import static sixgaezzang.sidepeek.users.domain.User.MAX_NICKNAME_LENGTH;
import static sixgaezzang.sidepeek.users.util.UserConstant.MAX_NICKNAME_LENGTH;

public class MemberErrorMessage {
public static final String MEMBERS_OVER_MAX_COUNT = "멤버 수는 " + MAX_MEMBER_COUNT + "명 미만이어야 합니다.";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,6 @@ public class ProjectErrorMessage {
public static final String DESCRIPTION_IS_NULL = "프로젝트 기능 설명을 입력해주세요.";
public static final String DESCRIPTION_OVER_MAX_LENGTH = "프로젝트 기능 설명은 " + MAX_TEXT_LENGTH + "자 이하여야 합니다.";

// Github url
public static final String GITHUB_URL_IS_INVALID = "프로젝트 Github URL 형식이 유효하지 않습니다.";
public static final String GITHUB_URL_IS_NULL = "프로젝트 Github URL을 입력해주세요.";
public static final String GITHUB_URL_OVER_MAX_LENGTH = "프로젝트 Github URL은 " + MAX_TEXT_LENGTH + "자 이하여야 합니다.";

// Duration
public static final String DURATION_IS_REVERSED = "시작 날짜가 종료 날짜와 같거나 종료 날짜보다 이전이어야합니다.";
public static final String DURATION_IS_INVALID = "프로젝트 기간은 시작 날짜와 종료 날짜가 모두 기입되어야 합니다.";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import static sixgaezzang.sidepeek.projects.exception.message.MemberErrorMessage.USER_ID_OF_FELLOW_MEMBER_IS_NULL;
import static sixgaezzang.sidepeek.projects.util.ProjectConstant.MAX_MEMBER_COUNT;
import static sixgaezzang.sidepeek.projects.util.ProjectConstant.MAX_ROLE_LENGTH;
import static sixgaezzang.sidepeek.users.domain.User.MAX_NICKNAME_LENGTH;
import static sixgaezzang.sidepeek.users.util.UserConstant.MAX_NICKNAME_LENGTH;

import io.jsonwebtoken.lang.Assert;
import java.util.List;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package sixgaezzang.sidepeek.projects.util.validation;

import static sixgaezzang.sidepeek.common.exception.message.CommonErrorMessage.GITHUB_URL_IS_INVALID;
import static sixgaezzang.sidepeek.common.exception.message.CommonErrorMessage.GITHUB_URL_IS_NULL;
import static sixgaezzang.sidepeek.common.exception.message.CommonErrorMessage.GITHUB_URL_OVER_MAX_LENGTH;
import static sixgaezzang.sidepeek.common.util.ValidationUtils.validateMaxLength;
import static sixgaezzang.sidepeek.common.util.ValidationUtils.validateNotBlank;
import static sixgaezzang.sidepeek.common.util.ValidationUtils.validateTextLength;
Expand All @@ -10,9 +13,6 @@
import static sixgaezzang.sidepeek.projects.exception.message.ProjectErrorMessage.DESCRIPTION_OVER_MAX_LENGTH;
import static sixgaezzang.sidepeek.projects.exception.message.ProjectErrorMessage.DURATION_IS_INVALID;
import static sixgaezzang.sidepeek.projects.exception.message.ProjectErrorMessage.DURATION_IS_REVERSED;
import static sixgaezzang.sidepeek.projects.exception.message.ProjectErrorMessage.GITHUB_URL_IS_INVALID;
import static sixgaezzang.sidepeek.projects.exception.message.ProjectErrorMessage.GITHUB_URL_IS_NULL;
import static sixgaezzang.sidepeek.projects.exception.message.ProjectErrorMessage.GITHUB_URL_OVER_MAX_LENGTH;
import static sixgaezzang.sidepeek.projects.exception.message.ProjectErrorMessage.NAME_IS_NULL;
import static sixgaezzang.sidepeek.projects.exception.message.ProjectErrorMessage.NAME_OVER_MAX_LENGTH;
import static sixgaezzang.sidepeek.projects.exception.message.ProjectErrorMessage.OVERVIEW_IS_NULL;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package sixgaezzang.sidepeek.users.controller;

import static sixgaezzang.sidepeek.users.domain.User.MAX_NICKNAME_LENGTH;
import static sixgaezzang.sidepeek.users.exception.message.UserErrorMessage.NICKNAME_OVER_MAX_LENGTH;
import static sixgaezzang.sidepeek.users.util.UserConstant.MAX_NICKNAME_LENGTH;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
Expand All @@ -13,16 +15,22 @@
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import sixgaezzang.sidepeek.common.annotation.Login;
import sixgaezzang.sidepeek.users.dto.request.CheckEmailRequest;
import sixgaezzang.sidepeek.users.dto.request.CheckNicknameRequest;
import sixgaezzang.sidepeek.users.dto.request.SignUpRequest;
import sixgaezzang.sidepeek.users.dto.request.UpdatePasswordRequest;
import sixgaezzang.sidepeek.users.dto.request.UpdateUserProfileRequest;
import sixgaezzang.sidepeek.users.dto.response.CheckDuplicateResponse;
import sixgaezzang.sidepeek.users.dto.response.UserProfileResponse;
import sixgaezzang.sidepeek.users.dto.response.UserSearchResponse;
import sixgaezzang.sidepeek.users.service.UserService;

Expand Down Expand Up @@ -52,18 +60,25 @@ public ResponseEntity<Void> signUp(@RequestBody @Valid SignUpRequest request) {
.build();
}

@GetMapping
@Operation(summary = "회원 검색")
@ApiResponse(responseCode = "200", description = "회원 검색 성공")
@Parameter(name = "keyword", description = "검색어", example = "sixgaezzang6")
public ResponseEntity<UserSearchResponse> searchByNickname(
@RequestParam(required = false)
@Size(max = MAX_NICKNAME_LENGTH, message = "최대 " + MAX_NICKNAME_LENGTH
+ "자의 키워드로 검색할 수 있습니다.")
String keyword
@PutMapping("/{id}/password")
@Operation(summary = "비밀번호 수정")
@ApiResponse(responseCode = "204", description = "비밀번호 수정 성공")
public ResponseEntity<Void> updatePassword(
@Schema(description = "로그인한 회원 식별자(토큰에서 추출)")
@Login
Long loginId,

@Schema(description = "수정할 회원 식별자")
@PathVariable
Long id,

@RequestBody
@Valid
UpdatePasswordRequest request
) {
return ResponseEntity.ok()
.body(userService.searchByNickname(keyword));
// TODO: 비밀번호 변경 서비스 기능 구현
return ResponseEntity.noContent()
.build();
}

@PostMapping("/email/check")
Expand Down Expand Up @@ -92,4 +107,49 @@ public ResponseEntity<CheckDuplicateResponse> checkNicknameDuplicate(
.body(response);
}

@GetMapping("/nickname")
@Operation(summary = "회원 닉네임 검색")
@ApiResponse(responseCode = "200", description = "회원 검색 성공")
@Parameter(name = "keyword", description = "검색어", example = "sixgaezzang6")
public ResponseEntity<UserSearchResponse> searchByNickname(
@RequestParam(required = false)
@Size(max = MAX_NICKNAME_LENGTH, message = NICKNAME_OVER_MAX_LENGTH)
String keyword
) {
return ResponseEntity.ok()
.body(userService.searchByNickname(keyword));
}

@GetMapping("/{id}")
@Operation(summary = "회원 프로필 정보 조회")
@ApiResponse(responseCode = "200", description = "회원 프로필 정보 조회 성공")
public ResponseEntity<UserProfileResponse> getById(
@Schema(description = "회원 식별자")
@PathVariable
Long id
) {
// TODO: 프로필 정보 조회 서비스 로직 구현
return null;
}

@PutMapping("/{id}")
@Operation(summary = "회원 프로필 정보 수정")
@ApiResponse(responseCode = "200", description = "회원 프로필 정보 조회 성공")
public ResponseEntity<UserProfileResponse> update(
@Schema(description = "로그인한 회원 식별자(토큰에서 추출)")
@Login
Long loginId,

@Schema(description = "수정할 회원 식별자")
@PathVariable
Long id,

@RequestBody
@Valid
UpdateUserProfileRequest request
) {
// TODO: 프로필 정보 수정 서비스 로직 구현
return null;
}

}
3 changes: 1 addition & 2 deletions src/main/java/sixgaezzang/sidepeek/users/domain/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import static sixgaezzang.sidepeek.users.exception.UserErrorCode.BLANK_NICKNAME;
import static sixgaezzang.sidepeek.users.exception.UserErrorCode.EXCESSIVE_NICKNAME_LENGTH;
import static sixgaezzang.sidepeek.users.exception.UserErrorCode.INVALID_EMAIL_FORMAT;
import static sixgaezzang.sidepeek.users.util.UserConstant.MAX_NICKNAME_LENGTH;

import jakarta.persistence.Column;
import jakarta.persistence.Embedded;
Expand All @@ -32,8 +33,6 @@
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class User extends BaseTimeEntity {

public static final int MAX_NICKNAME_LENGTH = 20;

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package sixgaezzang.sidepeek.users.dto.request;

import static sixgaezzang.sidepeek.users.domain.User.MAX_NICKNAME_LENGTH;
import static sixgaezzang.sidepeek.users.exception.message.UserErrorMessage.NICKNAME_OVER_MAX_LENGTH;
import static sixgaezzang.sidepeek.users.util.UserConstant.MAX_NICKNAME_LENGTH;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;

public record CheckNicknameRequest(
@NotBlank(message = "닉네임을 입력해주세요.")
@Size(max = MAX_NICKNAME_LENGTH, message = "닉네임은 " + MAX_NICKNAME_LENGTH + "자 이하여야 합니다.")
@Size(max = MAX_NICKNAME_LENGTH, message = NICKNAME_OVER_MAX_LENGTH)
String nickname
) {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package sixgaezzang.sidepeek.users.dto.request;

import static sixgaezzang.sidepeek.users.domain.User.MAX_NICKNAME_LENGTH;
import static sixgaezzang.sidepeek.users.exception.message.UserErrorMessage.NICKNAME_OVER_MAX_LENGTH;
import static sixgaezzang.sidepeek.users.util.UserConstant.MAX_NICKNAME_LENGTH;

import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
Expand All @@ -16,7 +17,7 @@ public record SignUpRequest(
@Pattern(regexp = Password.PASSWORD_REGXP, message = "비밀번호는 8자 이상이며 영문, 숫자, 특수문자를 포함해야 합니다.")
String password,
@NotBlank(message = "닉네임을 입력해주세요.")
@Size(max = MAX_NICKNAME_LENGTH, message = "닉네임은 " + MAX_NICKNAME_LENGTH + "자 이하여야 합니다.")
@Size(max = MAX_NICKNAME_LENGTH, message = NICKNAME_OVER_MAX_LENGTH)
String nickname
) {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package sixgaezzang.sidepeek.users.dto.request;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;
import sixgaezzang.sidepeek.users.domain.Password;

@Schema(description = "비밀번호 수정 요청 정보")
public record UpdatePasswordRequest(
@Schema(description = "기존 비밀번호", example = "sidepeek6!")
@NotBlank(message = "기존 비밀번호를 입력해주세요.")
@Pattern(regexp = Password.PASSWORD_REGXP, message = "비밀번호는 8자 이상이며 영문, 숫자, 특수문자를 포함해야 합니다.")
String originalPassword,

@Schema(description = "새로운 비밀번호", example = "sidepeek678!")
@NotBlank(message = "새로운 비밀번호를 입력해주세요.")
@Pattern(regexp = Password.PASSWORD_REGXP, message = "비밀번호는 8자 이상이며 영문, 숫자, 특수문자를 포함해야 합니다.")
String password
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package sixgaezzang.sidepeek.users.dto.request;

import static sixgaezzang.sidepeek.common.exception.message.CommonErrorMessage.GITHUB_URL_OVER_MAX_LENGTH;
import static sixgaezzang.sidepeek.common.util.CommonConstant.MAX_TEXT_LENGTH;
import static sixgaezzang.sidepeek.users.exception.message.UserErrorMessage.BLOG_URL_OVER_MAX_LENGTH;
import static sixgaezzang.sidepeek.users.exception.message.UserErrorMessage.CAREER_OVER_MAX_LENGTH;
import static sixgaezzang.sidepeek.users.exception.message.UserErrorMessage.INTRODUCTION_OVER_MAX_LENGTH;
import static sixgaezzang.sidepeek.users.exception.message.UserErrorMessage.JOB_OVER_MAX_LENGTH;
import static sixgaezzang.sidepeek.users.exception.message.UserErrorMessage.NICKNAME_IS_NULL;
import static sixgaezzang.sidepeek.users.exception.message.UserErrorMessage.NICKNAME_OVER_MAX_LENGTH;
import static sixgaezzang.sidepeek.users.util.UserConstant.MAX_CAREER_LENGTH;
import static sixgaezzang.sidepeek.users.util.UserConstant.MAX_INTRODUCTION_LENGTH;
import static sixgaezzang.sidepeek.users.util.UserConstant.MAX_JOB_LENGTH;
import static sixgaezzang.sidepeek.users.util.UserConstant.MAX_NICKNAME_LENGTH;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import java.util.List;

@Schema(description = "회원 프로필 수정 요청 정보")
public record UpdateUserProfileRequest(
@Schema(description = "회원 닉네임", example = "의진")
@NotNull(message = NICKNAME_IS_NULL)
@Size(max = MAX_NICKNAME_LENGTH, message = NICKNAME_OVER_MAX_LENGTH)
String nickname,

@Schema(description = "회원 프로필 이미지 URL", example = "https://sidepeek.image/profile1")
@Size(max = MAX_TEXT_LENGTH, message = "")
String profileImageUrl,

@Schema(description = "회원 소개", example = "전 최고의 백엔드 개발자입니다.")
@Size(max = MAX_INTRODUCTION_LENGTH, message = INTRODUCTION_OVER_MAX_LENGTH)
String introduction,

@Schema(description = "회원 직업", example = "백엔드 개발자")
@Size(max = MAX_JOB_LENGTH, message = JOB_OVER_MAX_LENGTH)
String job,

@Schema(description = "회원 경력", example = "1-3년차")
@Size(max = MAX_CAREER_LENGTH, message = CAREER_OVER_MAX_LENGTH)
String career,

@Schema(description = "회원 깃허브 URL", example = "https://github.com")
@Size(max = MAX_TEXT_LENGTH, message = GITHUB_URL_OVER_MAX_LENGTH)
String githubUrl,

@Schema(description = "회원 블로그 URL", example = "https://medium.com")
@Size(max = MAX_TEXT_LENGTH, message = BLOG_URL_OVER_MAX_LENGTH)
String blogUrl,

@Schema(description = "회원 기술 스택 목록")
List<UpdateUserSkillRequest> techStacks
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package sixgaezzang.sidepeek.users.dto.request;

import static sixgaezzang.sidepeek.common.util.CommonConstant.MIN_ID;
import static sixgaezzang.sidepeek.projects.util.ProjectConstant.MAX_CATEGORY_LENGTH;
import static sixgaezzang.sidepeek.skill.util.validation.SkillErrorMessage.CATEGORY_IS_NULL;
import static sixgaezzang.sidepeek.skill.util.validation.SkillErrorMessage.CATEGORY_OVER_MAX_LENGTH;
import static sixgaezzang.sidepeek.skill.util.validation.SkillErrorMessage.SKILL_ID_IS_NULL;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;

@Schema(description = "회원 수정 요청 내 회원 기술 스택 정보")
public record UpdateUserSkillRequest(
@Schema(description = "기술 스택 Id", example = "1")
@Min(value = MIN_ID, message = "스킬 id는 " + MIN_ID + "보다 작을 수 없습니다.")
@NotNull(message = SKILL_ID_IS_NULL)
Long skillId,

@Schema(description = "기술 스택 카테고리", example = "프론트엔드")
@Size(max = MAX_CATEGORY_LENGTH, message = CATEGORY_OVER_MAX_LENGTH)
@NotBlank(message = CATEGORY_IS_NULL)
String category
) {
}
Loading

0 comments on commit 1b50f5c

Please sign in to comment.