-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'dev' of https://github.com/SWYP-4rd-6/backend into dev
- Loading branch information
Showing
14 changed files
with
295 additions
and
90 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
version=0.0.1 | ||
version=0.1.0 |
33 changes: 33 additions & 0 deletions
33
src/main/java/com/swygbro/trip/backend/domain/guideProduct/dto/SimpleGuideProductDto.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package com.swygbro.trip.backend.domain.guideProduct.dto; | ||
|
||
import io.swagger.v3.oas.annotations.media.Schema; | ||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
import lombok.Setter; | ||
|
||
import java.time.ZonedDateTime; | ||
|
||
|
||
/** | ||
* 유저 프로필에서 가이드 상품을 보여주기 위한 DTO | ||
*/ | ||
@Getter | ||
@Setter | ||
@NoArgsConstructor | ||
@AllArgsConstructor | ||
public class SimpleGuideProductDto { | ||
@Schema(description = "가이드 상품 ID", example = "1") | ||
private Long id; | ||
@Schema(description = "가이드 상품 제목", example = "상품 이름") | ||
private String title; | ||
@Schema(description = "가이드 상품 설명", example = "설명") | ||
private String description; | ||
@Schema(description = "가이드 상품 섬네일", example = "https://S3저장소URL/저장위치/난수화된 이미지이름.이미지 타입") | ||
private String thumb; | ||
// private Point location; // TODO 위치 정보 추가 | ||
@Schema(description = "가이드 상품 시작 시간", example = "2024-05-05 00:00:00") | ||
private ZonedDateTime guideStart; | ||
@Schema(description = "가이드 상품 종료 시간", example = "2024-05-05 00:00:00") | ||
private ZonedDateTime guideEnd; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,26 +1,40 @@ | ||
package com.swygbro.trip.backend.domain.user.api; | ||
|
||
import com.swygbro.trip.backend.domain.user.application.LoginService; | ||
import com.swygbro.trip.backend.domain.user.application.UserService; | ||
import com.swygbro.trip.backend.domain.user.dto.CreateUserRequest; | ||
import com.swygbro.trip.backend.domain.user.dto.LoginRequest; | ||
import com.swygbro.trip.backend.global.document.ValidationErrorResponse; | ||
import com.swygbro.trip.backend.global.exception.ApiErrorResponse; | ||
import com.swygbro.trip.backend.global.jwt.dto.TokenDto; | ||
import com.swygbro.trip.backend.infra.discordbot.DiscordMessageProvider; | ||
import io.swagger.v3.oas.annotations.Operation; | ||
import io.swagger.v3.oas.annotations.media.Content; | ||
import io.swagger.v3.oas.annotations.media.ExampleObject; | ||
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; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.http.MediaType; | ||
import org.springframework.web.bind.annotation.PostMapping; | ||
import org.springframework.web.bind.annotation.RequestBody; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
@RestController | ||
@RequestMapping("/api/v1/login") | ||
@RequestMapping("/api/v1/auth") | ||
@RequiredArgsConstructor | ||
@Tag(name = "Login", description = "로그인 관련 API") | ||
public class LoginController { | ||
|
||
private final LoginService loginService; | ||
private final UserService userService; | ||
private final DiscordMessageProvider discordMessageProvider; | ||
|
||
@PostMapping | ||
@Operation(summary = "로그인", description = """ | ||
|
||
@PostMapping("/login") | ||
@Operation(summary = "이메일 로그인", description = """ | ||
# 로그인 | ||
|
@@ -31,15 +45,84 @@ public class LoginController { | |
- 로그인 성공 시 `200` 코드와 함께 토큰을 반환합니다. | ||
- 토큰은 `access_token`과 `refresh_token`으로 구성되어 있습니다. | ||
- 로그인 실패 시 `400` 에러를 반환합니다. | ||
- 계정이 존재하지 않거나 비밀번호가 일치하지 않을 경우 발생합니다. | ||
""") | ||
@ApiResponse( | ||
responseCode = "200", | ||
description = "로그인 성공 시 토큰을 반환합니다." | ||
description = "로그인 성공 시 토큰을 반환합니다.", | ||
content = @Content( | ||
mediaType = MediaType.APPLICATION_JSON_VALUE, | ||
schema = @Schema(implementation = TokenDto.class), | ||
examples = @ExampleObject(value = """ | ||
{ | ||
"accessToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyMDFAZW1haWwuY29tIiwiZXhwIjoxNzE1MDA2OTc4LCJpYXQiOjE3MTUwMDMzNzh9.4mVSMEiBNmbD0VXo0w5ZtOl45Qu5V1a4dZEArkibbIQ", | ||
"refreshToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyMDFAZW1haWwuY29tIiwiZXhwIjoxNzE1MDg5Nzc4LCJpYXQiOjE3MTUwMDMzNzh9.GK01DHHZYxYc5FXl_c5Aq0qJg9YbUoSl-U6YCj8L7ik" | ||
} | ||
""") | ||
) | ||
) | ||
@ApiResponse( | ||
responseCode = "400", | ||
description = "", | ||
content = @Content( | ||
mediaType = MediaType.APPLICATION_JSON_VALUE, | ||
schema = @Schema(implementation = ApiErrorResponse.class), | ||
examples = @ExampleObject(value = """ | ||
{ | ||
"status": "BAD_REQUEST", | ||
"message": "로그인에 실패했습니다." | ||
} | ||
""") | ||
) | ||
) | ||
public TokenDto login(@Valid @RequestBody LoginRequest dto) { | ||
return loginService.login(dto); | ||
} | ||
|
||
@PostMapping("/signup") | ||
@Operation(summary = "회원 가입", description = """ | ||
# 회원가입 | ||
회원을 생성합니다. 회원 가입 시 사용자 이메일, 닉네임, 이름, 전화번호, 국적, 성별, 비밀번호, 비밀번호 확인을 입력합니다. | ||
각 필드의 제약 조건은 다음과 같습니다. | ||
| 필드명 | 설명 | 제약조건 | 중복확인 | 예시 | | ||
|--------|------|----------|----------|------| | ||
|email| 사용자의 이메일 | 이메일 형식 | Y | [email protected] | | ||
|nickname| 다른 사용자들에게 보이는 닉네임 | 4~20자 | Y | nickname01 | | ||
|name| 사용자의 이름 | 2~20자 | N | name01 | | ||
|phone| 사용자의 전화번호 | '-'를 제외한 숫자 | Y | 01012345678 | | ||
|nationality| 사용자의 국적 | 영문3자 국가 코드 | N | KOR | | ||
|gender| 성별 | Male, Female 중 하나 | N | Male | | ||
|password| 사용자의 비밀번호 | 영문(대소문자), 숫자, 특수문자를 포함한 8~32자 | N | password01! | | ||
|passwordCheck| 사용자의 비밀번호 확인 | password와 동일한 입력 | N | password01! | | ||
## 응답 | ||
- 회원 가입 성공 시 `200` 코드와 함께 회원 이메일을 문자열로 반환합니다. | ||
- 중복된 값이 있을 경우 `409` 에러를 반환합니다. | ||
- 입력 양식에 오류가 있을 경우 `400` 에러를 반환합니다. | ||
""") | ||
@ApiResponse( | ||
responseCode = "200", | ||
description = "생성한 계정 고유 번호를 반환합니다.", | ||
content = @Content( | ||
mediaType = MediaType.TEXT_PLAIN_VALUE, | ||
schema = @Schema(implementation = Long.class, example = "1"))) | ||
@ApiResponse( | ||
responseCode = "409", | ||
description = "입력 값 중 중복된 값이 있습니다.", | ||
content = @Content( | ||
mediaType = MediaType.APPLICATION_JSON_VALUE, | ||
schema = @Schema(implementation = ApiErrorResponse.class), | ||
examples = @ExampleObject(value = "{\n \"status\": \"CONFLICT\",\n \"message\": \"데이터 중복\"\n}") | ||
) | ||
) | ||
@ValidationErrorResponse | ||
public Long createUser(@Valid @RequestBody CreateUserRequest dto) { | ||
return userService.createUser(dto); | ||
} | ||
|
||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,8 +3,15 @@ | |
|
||
import com.fasterxml.jackson.core.JsonProcessingException; | ||
import com.swygbro.trip.backend.domain.user.application.GoogleOauthService; | ||
import io.swagger.v3.oas.annotations.Operation; | ||
import io.swagger.v3.oas.annotations.Parameter; | ||
import io.swagger.v3.oas.annotations.headers.Header; | ||
import io.swagger.v3.oas.annotations.media.Content; | ||
import io.swagger.v3.oas.annotations.responses.ApiResponse; | ||
import io.swagger.v3.oas.annotations.tags.Tag; | ||
import jakarta.servlet.http.HttpServletResponse; | ||
import lombok.RequiredArgsConstructor; | ||
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.RequestParam; | ||
|
@@ -15,18 +22,80 @@ | |
@RestController | ||
@RequestMapping("/api/v1/oauth2") | ||
@RequiredArgsConstructor | ||
@Tag(name = "Login", description = "로그인 관련 API") | ||
public class Oauth2Controller { | ||
|
||
private final GoogleOauthService googleOauthService; | ||
|
||
@GetMapping("/google") | ||
@Operation(summary = "구글 로그인", description = """ | ||
# 구글 로그인 | ||
- 이 API를 호출하면 구글 로그인 페이지로 리다이렉트됩니다. | ||
- 이 API를 구글 로그인 버튼의 링크로 사용합니다. | ||
- 구글 로그인 페이지에서 로그인을 완료하면 콜백 URL로 리다이렉트됩니다. | ||
- 콜백 URL에서 구글 인가 코드를 받아서 처리합니다. | ||
""") | ||
|
||
@ApiResponse( | ||
responseCode = "302", | ||
headers = { | ||
@Header( | ||
name = "Location", | ||
description = """ | ||
- 구글 로그인 페이지 URL | ||
- ex) https://accounts.google.com/o/oauth2/v2/auth?client_id={client_id}&redirect_uri={redirect_uri}&response_type=code&scope=openid profile email | ||
""") | ||
}, | ||
description = "구글 로그인 페이지로 리다이렉트됩니다.") | ||
public void redirectGoogle(HttpServletResponse response) throws IOException { | ||
response.sendRedirect(googleOauthService.getGoogleLoginUrl()); | ||
} | ||
|
||
@GetMapping("/callback") | ||
public void callback(@RequestParam String code) throws JsonProcessingException { | ||
googleOauthService.callback(code); | ||
@Operation(summary = "구글 로그인 콜백", description = """ | ||
- 프론트엔드에서 테스트 필요 | ||
- 301 응답 시 회원가입 페이지로 이동 및 응답 데이터를 받아서 회원가입 페이지에서 사용할 수 있는지... | ||
--- | ||
# 구글 로그인 콜백 | ||
- 구글 로그인 페이지에서 로그인을 완료하면 구글 인가 코드와 함께 이 API로 리다이렉트됩니다. | ||
- 구글 인가 코드를 사용해 계정의 정보를 조회 및 처리합니다. | ||
- DB에 등록된 이메일이면 로그인 처리, 등록되지 않은 이메일이면 회원가입 페이지로 이동 합니다. | ||
- 로그인 시 200 코드와 함께 JWT 토큰을 반환합니다. | ||
- 회원가입 시 301 코드와 함께 회원 정보를 반환합니다. | ||
- 반환 정보는 추후 협의 필요 | ||
회원정보 반환 예시: | ||
```json | ||
{ | ||
"id": "114210435473335230303", | ||
"name": "Mat thew", | ||
"given_name": "Mat", | ||
"family_name": "thew", | ||
"locale": "ko", | ||
"email": "[email protected]", | ||
"verified_email": true, | ||
"picture": "https://lh3.googleusercontent.com/a/ACg8ocKrQm8D09Njibbo_vgeOQZt_oBdu63c6qOgxsWZ6QOJdcflxA=s96-c" | ||
} | ||
""") | ||
@Parameter(name = "code", description = "구글 인가 코드", required = true) | ||
@ApiResponse( | ||
responseCode = "200", | ||
description = "로그인 성공 시 JWT 토큰을 반환합니다.", | ||
content = @Content(mediaType = "application/json")) | ||
@ApiResponse( | ||
responseCode = "301", | ||
description = "회원가입 페이지", | ||
content = @Content(mediaType = "application/json")) | ||
public ResponseEntity<?> callback(@RequestParam String code) throws JsonProcessingException { | ||
return googleOauthService.callback(code); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,10 @@ | ||
package com.swygbro.trip.backend.domain.user.api; | ||
|
||
import com.swygbro.trip.backend.domain.user.application.UserService; | ||
import com.swygbro.trip.backend.domain.user.dto.CreateUserRequest; | ||
import com.swygbro.trip.backend.domain.user.dto.UpdateUserRequest; | ||
import com.swygbro.trip.backend.domain.user.dto.UserProfileDto; | ||
import com.swygbro.trip.backend.global.document.ForbiddenResponse; | ||
import com.swygbro.trip.backend.global.document.InvalidTokenResponse; | ||
import com.swygbro.trip.backend.global.document.ValidationErrorResponse; | ||
import com.swygbro.trip.backend.global.exception.ApiErrorResponse; | ||
import io.swagger.v3.oas.annotations.Operation; | ||
import io.swagger.v3.oas.annotations.Parameter; | ||
|
@@ -34,59 +32,14 @@ | |
### 주요 기능 | ||
- 회원 가입 | ||
- 회원 정보 조회 | ||
- 회원 정보 수정 | ||
""") | ||
public class UserController { | ||
|
||
private final UserService userService; | ||
|
||
@PostMapping | ||
@Operation(summary = "회원 가입", description = """ | ||
# 회원가입 | ||
회원을 생성합니다. 회원 가입 시 사용자 이메일, 닉네임, 이름, 전화번호, 국적, 성별, 비밀번호, 비밀번호 확인을 입력합니다. | ||
각 필드의 제약 조건은 다음과 같습니다. | ||
| 필드명 | 설명 | 제약조건 | 중복확인 | 예시 | | ||
|--------|------|----------|----------|------| | ||
|email| 사용자의 이메일 | 이메일 형식 | Y | [email protected] | | ||
|nickname| 다른 사용자들에게 보이는 닉네임 | 4~20자 | Y | nickname01 | | ||
|name| 사용자의 이름 | 2~20자 | N | name01 | | ||
|phone| 사용자의 전화번호 | '-'를 제외한 숫자 | Y | 01012345678 | | ||
|nationality| 사용자의 국적 | 영문3자 국가 코드 | N | KOR | | ||
|gender| 성별 | Male, Female 중 하나 | N | Male | | ||
|password| 사용자의 비밀번호 | 영문(대소문자), 숫자, 특수문자를 포함한 8~32자 | N | password01! | | ||
|passwordCheck| 사용자의 비밀번호 확인 | password와 동일한 입력 | N | password01! | | ||
## 응답 | ||
- 회원 가입 성공 시 `200` 코드와 함께 회원 이메일을 문자열로 반환합니다. | ||
- 중복된 값이 있을 경우 `409` 에러를 반환합니다. | ||
- 입력 양식에 오류가 있을 경우 `400` 에러를 반환합니다. | ||
""") | ||
@ApiResponse( | ||
responseCode = "200", | ||
description = "생성한 계정 고유 번호를 반환합니다.", | ||
content = @Content( | ||
mediaType = MediaType.TEXT_PLAIN_VALUE, | ||
schema = @Schema(implementation = Long.class, example = "1"))) | ||
@ApiResponse( | ||
responseCode = "409", | ||
description = "입력 값 중 중복된 값이 있습니다.", | ||
content = @Content( | ||
mediaType = MediaType.APPLICATION_JSON_VALUE, | ||
schema = @Schema(implementation = ApiErrorResponse.class), | ||
examples = @ExampleObject(value = "{\n \"status\": \"CONFLICT\",\n \"message\": \"데이터 중복\"\n}") | ||
) | ||
) | ||
@ValidationErrorResponse | ||
public Long createUser(@Valid @RequestBody CreateUserRequest dto) { | ||
return userService.createUser(dto); | ||
} | ||
|
||
@GetMapping("/{userId}") | ||
@Operation(summary = "사용자 조회", description = "사용자의 프로필을 조회합니다.") | ||
@Parameters({ | ||
|
@@ -112,8 +65,8 @@ public Long createUser(@Valid @RequestBody CreateUserRequest dto) { | |
) | ||
) | ||
) | ||
public UserProfileDto getUser(@PathVariable Long userId) { | ||
return userService.getUser(userId); | ||
public UserProfileDto getUserProfile(@PathVariable Long userId) { | ||
return userService.getUserProfile(userId); | ||
} | ||
|
||
@PutMapping(value = "{userId}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.