Skip to content

Commit 71c900d

Browse files
authored
Merge pull request #20 from prgrms-web-devcourse-final-project/feat/be/2
feat(be) : User 엔티티 및 기본 구조 설계
2 parents 0c1a69c + 2fbde5d commit 71c900d

File tree

14 files changed

+318
-23
lines changed

14 files changed

+318
-23
lines changed

setup-git-hooks.sh

100644100755
File mode changed.
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package com.back.koreaTravelGuide.domain.guide.controller
2+
3+
import com.back.koreaTravelGuide.common.ApiResponse
4+
import com.back.koreaTravelGuide.domain.guide.service.GuideService
5+
import com.back.koreaTravelGuide.domain.user.dto.request.GuideUpdateRequest
6+
import com.back.koreaTravelGuide.domain.user.dto.response.GuideResponse
7+
import io.swagger.v3.oas.annotations.Operation
8+
import io.swagger.v3.oas.annotations.tags.Tag
9+
import org.springframework.http.ResponseEntity
10+
import org.springframework.security.access.prepost.PreAuthorize
11+
import org.springframework.security.core.annotation.AuthenticationPrincipal
12+
import org.springframework.web.bind.annotation.GetMapping
13+
import org.springframework.web.bind.annotation.PatchMapping
14+
import org.springframework.web.bind.annotation.PathVariable
15+
import org.springframework.web.bind.annotation.RequestBody
16+
import org.springframework.web.bind.annotation.RequestMapping
17+
import org.springframework.web.bind.annotation.RestController
18+
19+
@Tag(name = "가이드 API", description = "가이드 조회 및 프로필 관리에 대한 API")
20+
@RestController
21+
@RequestMapping("/api/guides")
22+
class GuideController(
23+
private val guideService: GuideService,
24+
) {
25+
@Operation(summary = "가이드 목록 조회")
26+
@GetMapping
27+
fun getAllGuides(): ResponseEntity<ApiResponse<List<GuideResponse>>> {
28+
val guides = guideService.getAllGuides()
29+
return ResponseEntity.ok(ApiResponse("전체 가이드 목록을 조회했습니다.", guides))
30+
}
31+
32+
@Operation(summary = "가이드 단건 조회")
33+
@GetMapping("/{guideId}")
34+
fun getGuideById(
35+
@PathVariable guideId: Long,
36+
): ResponseEntity<ApiResponse<GuideResponse>> {
37+
val guide = guideService.getGuideById(guideId)
38+
return ResponseEntity.ok(ApiResponse("가이드 정보를 성공적으로 조회했습니다.", guide))
39+
}
40+
41+
@Operation(summary = "가이드 프로필 수정")
42+
@PreAuthorize("hasRole('GUIDE')")
43+
@PatchMapping("/me")
44+
fun updateMyGuideProfile(
45+
@AuthenticationPrincipal guideId: Long,
46+
@RequestBody request: GuideUpdateRequest,
47+
): ResponseEntity<ApiResponse<GuideResponse>> {
48+
val updatedGuideProfile = guideService.updateGuideProfile(guideId, request)
49+
return ResponseEntity.ok(ApiResponse("가이드 정보가 성공적으로 수정되었습니다.", updatedGuideProfile))
50+
}
51+
}
Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,49 @@
11
package com.back.koreaTravelGuide.domain.user.controller
22

3-
// TODO: 사용자 컨트롤러 - 사용자 관련 API 엔드포인트 (향후 구현)
4-
class UserController
3+
import com.back.koreaTravelGuide.common.ApiResponse
4+
import com.back.koreaTravelGuide.domain.user.dto.request.UserUpdateRequest
5+
import com.back.koreaTravelGuide.domain.user.dto.response.UserResponse
6+
import com.back.koreaTravelGuide.domain.user.service.UserService
7+
import io.swagger.v3.oas.annotations.Operation
8+
import org.springframework.http.ResponseEntity
9+
import org.springframework.security.core.annotation.AuthenticationPrincipal
10+
import org.springframework.web.bind.annotation.DeleteMapping
11+
import org.springframework.web.bind.annotation.GetMapping
12+
import org.springframework.web.bind.annotation.PatchMapping
13+
import org.springframework.web.bind.annotation.RequestBody
14+
import org.springframework.web.bind.annotation.RequestMapping
15+
import org.springframework.web.bind.annotation.RestController
16+
17+
@RestController
18+
@RequestMapping("/api/users")
19+
class UserController(
20+
private val userService: UserService,
21+
) {
22+
@Operation(summary = "내 정보 조회")
23+
@GetMapping("/me")
24+
fun getMyProfile(
25+
@AuthenticationPrincipal userId: Long,
26+
): ResponseEntity<ApiResponse<UserResponse>> {
27+
val userProfile = userService.getUserProfileById(userId)
28+
return ResponseEntity.ok(ApiResponse("내 정보를 성공적으로 조회했습니다.", userProfile))
29+
}
30+
31+
@Operation(summary = "내 프로필 수정")
32+
@PatchMapping("/me")
33+
fun updateMyProfile(
34+
@AuthenticationPrincipal userId: Long,
35+
@RequestBody request: UserUpdateRequest,
36+
): ResponseEntity<ApiResponse<UserResponse>> {
37+
val updatedProfile = userService.updateUserProfile(userId, request)
38+
return ResponseEntity.ok(ApiResponse("정보가 성공적으로 수정되었습니다.", updatedProfile))
39+
}
40+
41+
@Operation(summary = "회원 탈퇴")
42+
@DeleteMapping("/me")
43+
fun deleteMe(
44+
@AuthenticationPrincipal userId: Long,
45+
): ResponseEntity<ApiResponse<Unit>> {
46+
userService.deleteUser(userId)
47+
return ResponseEntity.ok(ApiResponse("회원 탈퇴가 완료되었습니다."))
48+
}
49+
}

src/main/kotlin/com/back/koreaTravelGuide/domain/user/dto/UserRequest.kt

Lines changed: 0 additions & 7 deletions
This file was deleted.

src/main/kotlin/com/back/koreaTravelGuide/domain/user/dto/UserResponse.kt

Lines changed: 0 additions & 8 deletions
This file was deleted.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.back.koreaTravelGuide.domain.user.dto.request
2+
3+
data class GuideUpdateRequest(
4+
val nickname: String?,
5+
val profileImageUrl: String?,
6+
val location: String?,
7+
val description: String?,
8+
)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.back.koreaTravelGuide.domain.user.dto.request
2+
3+
data class UserUpdateRequest(
4+
val nickname: String?,
5+
val profileImageUrl: String?,
6+
)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.back.koreaTravelGuide.domain.user.dto.response
2+
3+
import com.back.koreaTravelGuide.domain.user.entity.User
4+
import com.back.koreaTravelGuide.domain.user.enums.UserRole
5+
6+
data class GuideResponse(
7+
val id: Long,
8+
val email: String,
9+
val nickname: String,
10+
val profileImageUrl: String?,
11+
val role: UserRole,
12+
val location: String?,
13+
val description: String?,
14+
) {
15+
companion object {
16+
fun from(user: User): GuideResponse {
17+
return GuideResponse(
18+
id = user.id!!,
19+
email = user.email,
20+
nickname = user.nickname,
21+
profileImageUrl = user.profileImageUrl,
22+
role = user.role,
23+
location = user.location,
24+
description = user.description,
25+
)
26+
}
27+
}
28+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.back.koreaTravelGuide.domain.user.dto.response
2+
3+
import com.back.koreaTravelGuide.domain.user.entity.User
4+
import com.back.koreaTravelGuide.domain.user.enums.UserRole
5+
6+
data class UserResponse(
7+
val id: Long,
8+
val email: String,
9+
val nickname: String,
10+
val profileImageUrl: String?,
11+
val role: UserRole,
12+
) {
13+
companion object {
14+
fun from(user: User): UserResponse {
15+
return UserResponse(
16+
id = user.id!!,
17+
email = user.email,
18+
nickname = user.nickname,
19+
profileImageUrl = user.profileImageUrl,
20+
role = user.role,
21+
)
22+
}
23+
}
24+
}
Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,48 @@
11
package com.back.koreaTravelGuide.domain.user.entity
22

3-
// TODO: 사용자 엔티티 - 사용자 정보 저장 (향후 구현)
4-
class User
3+
import com.back.koreaTravelGuide.domain.user.enums.UserRole
4+
import jakarta.persistence.Column
5+
import jakarta.persistence.Entity
6+
import jakarta.persistence.EntityListeners
7+
import jakarta.persistence.EnumType
8+
import jakarta.persistence.Enumerated
9+
import jakarta.persistence.GeneratedValue
10+
import jakarta.persistence.GenerationType
11+
import jakarta.persistence.Id
12+
import jakarta.persistence.Table
13+
import org.springframework.data.annotation.CreatedDate
14+
import org.springframework.data.annotation.LastModifiedDate
15+
import org.springframework.data.jpa.domain.support.AuditingEntityListener
16+
import java.time.LocalDateTime
17+
18+
@Entity
19+
@Table(name = "users")
20+
@EntityListeners(AuditingEntityListener::class)
21+
class User(
22+
@Id
23+
@GeneratedValue(strategy = GenerationType.IDENTITY)
24+
val id: Long? = null,
25+
@Column(name = "oauth_provider", nullable = false)
26+
val oauthProvider: String,
27+
@Column(name = "oauth_id", nullable = false)
28+
val oauthId: String,
29+
@Column(unique = true, nullable = false)
30+
val email: String,
31+
@Column(nullable = false)
32+
var nickname: String,
33+
@Column(name = "profile_image_url")
34+
var profileImageUrl: String? = null,
35+
@Enumerated(EnumType.STRING)
36+
@Column(nullable = false)
37+
var role: UserRole = UserRole.USER,
38+
@Column
39+
var location: String? = null,
40+
@Column(columnDefinition = "TEXT")
41+
var description: String? = null,
42+
@CreatedDate
43+
@Column(name = "created_at", nullable = false, updatable = false)
44+
val createdAt: LocalDateTime = LocalDateTime.now(),
45+
@LastModifiedDate
46+
@Column(name = "last_login_at")
47+
var lastLoginAt: LocalDateTime = LocalDateTime.now(),
48+
)

0 commit comments

Comments
 (0)