Skip to content

Commit

Permalink
Merge branch 'main' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
jombidev authored Sep 11, 2024
2 parents 0029f91 + 51cf9a0 commit 243a1bb
Show file tree
Hide file tree
Showing 32 changed files with 495 additions and 399 deletions.
33 changes: 22 additions & 11 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on: [ push ]

jobs:
build:
runs-on: self-hosted
runs-on: ubuntu-latest

permissions:
contents: read
Expand All @@ -19,7 +19,7 @@ jobs:
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'zulu'
distribution: 'corretto'

- name: Create secured configurations
run: |
Expand All @@ -34,18 +34,29 @@ jobs:
chmod +x gradlew
./gradlew build
- name: Upload built image
run: |
echo '${{ secrets.DOCKER_PASSWORD }}' | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
docker build --file Dockerfile -t ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_NAME }}:latest .
docker push ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_NAME }}:latest
publish:
if: ${{ always() && contains(join(needs.*.result, ','), 'success') && github.ref == 'refs/heads/main' }}
needs: [build]
runs-on: self-hosted

permissions:
contents: read
runs-on: ubuntu-latest

steps:
- name: Add to Docker
run: |
docker container rm route -f
docker rmi palette_route -f
docker build --file Dockerfile -t palette_route .
docker run -d -p 8080:8080 --name route palette_route
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USERNAME }}
key: ${{ secrets.SSH_KEY }}
port: ${{ secrets.SSH_PORT }}
script: |
docker stop $(docker ps -aq -f 'ancestor=${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_NAME }}')
docker rm $(docker ps -aq -f 'ancestor=${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_NAME }}')
docker pull ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_NAME }}:latest
docker run -d -p 8080:8080 --name route ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_NAME }}
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
FROM openjdk:17
FROM amazoncorretto:17
COPY build/libs/palette-0.0.1-SNAPSHOT.jar palette.jar
ENTRYPOINT ["java", "-jar", "palette.jar"]
ENTRYPOINT ["java", "-jar", "palette.jar"]
2 changes: 2 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ dependencies {
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.springdoc:springdoc-openapi-starter-webflux-api:2.5.0")
implementation("org.springdoc:springdoc-openapi-starter-webflux-ui:2.5.0")
implementation("io.projectreactor.kotlin:reactor-kotlin-extensions")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor")
}
dependencyManagement {
imports {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.teamapi.palette.annotations

import io.swagger.v3.oas.annotations.security.SecurityRequirement

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
@SecurityRequirement(name = "X-AUTH-Token")
annotation class SwaggerRequireAuthorize
23 changes: 11 additions & 12 deletions src/main/kotlin/com/teamapi/palette/config/SecurityConfig.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.teamapi.palette.config

import com.fasterxml.jackson.databind.ObjectMapper
import com.teamapi.palette.entity.consts.UserState
import com.teamapi.palette.response.ErrorCode
import com.teamapi.palette.response.Response
import com.teamapi.palette.response.exception.ErrorResponse
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.Ordered
Expand Down Expand Up @@ -40,33 +42,30 @@ class SecurityConfig(private val objectMapper: ObjectMapper) {
return res.writeWith(Flux.just(res.bufferFactory().wrap(objectMapper.writeValueAsBytes(data))))
}


@Bean
@Order(Ordered.HIGHEST_PRECEDENCE + 3)
fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
return http
.authorizeExchange {
it
.pathMatchers("/auth/login", "/auth/register").permitAll()
.pathMatchers("/v3/api-docs/**", "/webjars/swagger-ui/**").permitAll()
.anyExchange().authenticated()
.pathMatchers("/v3/api-docs/**", "/external/**", "swagger").permitAll()
.pathMatchers("/auth/resign", "/auth/session", "/auth/logout").authenticated()
.pathMatchers("/auth/verify", "/auth/resend").hasRole(UserState.CREATED.name)
.anyExchange().hasRole(UserState.ACTIVE.name)
}
.exceptionHandling {
it.authenticationEntryPoint { exchange, ex ->
it.authenticationEntryPoint { exchange, _ ->
json(
exchange,
Response(
ErrorCode.INVALID_SESSION.statusCode.value(),
ErrorCode.INVALID_SESSION.message
)
ErrorResponse.ofRaw(ErrorCode.INVALID_SESSION)
)
}
.accessDeniedHandler { exchange, denied ->
.accessDeniedHandler { exchange, _ ->
json(
exchange,
Response(
ErrorCode.ENDPOINT_NOT_FOUND.statusCode.value(),
ErrorCode.ENDPOINT_NOT_FOUND.message
)
ErrorResponse.ofRaw(ErrorCode.FORBIDDEN, exchange.request.path.value())
)
}
}
Expand Down
22 changes: 22 additions & 0 deletions src/main/kotlin/com/teamapi/palette/config/SwaggerConfig.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.teamapi.palette.config

import io.swagger.v3.oas.annotations.enums.SecuritySchemeIn
import io.swagger.v3.oas.annotations.enums.SecuritySchemeType
import io.swagger.v3.oas.annotations.security.SecurityScheme
import io.swagger.v3.oas.models.OpenAPI
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration


@Configuration
@SecurityScheme(
name = "X-AUTH-Token",
type = SecuritySchemeType.APIKEY,
`in` = SecuritySchemeIn.HEADER,
)
class SwaggerConfig {
@Bean
fun customOpenAPI(): OpenAPI {
return OpenAPI()
}
}
63 changes: 38 additions & 25 deletions src/main/kotlin/com/teamapi/palette/controller/AuthController.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.teamapi.palette.controller

import com.teamapi.palette.annotations.SwaggerRequireAuthorize
import com.teamapi.palette.dto.auth.EmailVerifyRequest
import com.teamapi.palette.dto.auth.LoginRequest
import com.teamapi.palette.dto.auth.RegisterRequest
Expand All @@ -8,9 +9,10 @@ import com.teamapi.palette.response.Response
import com.teamapi.palette.service.AuthService
import com.teamapi.palette.service.SessionHolder
import jakarta.validation.Valid
import kotlinx.coroutines.reactor.awaitSingleOrNull
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*
import org.springframework.web.server.WebSession
import reactor.core.publisher.Mono

@RestController
@RequestMapping("/auth")
Expand All @@ -19,42 +21,53 @@ class AuthController(
private val sessionHolder: SessionHolder
) {
@PostMapping("/register")
fun register(@RequestBody @Valid request: Mono<RegisterRequest>) = request
.flatMap { authService.register(it) }
.thenReturn(Response.ok("회원가입 성공"))
suspend fun register(@RequestBody @Valid request: RegisterRequest): ResponseEntity<Response> {
authService.register(request)
return Response.ok("회원가입 성공")
}

@PostMapping("/login")
fun login(@RequestBody @Valid request: Mono<LoginRequest>) = request
.flatMap { authService.authenticate(it.email, it.password) }
.thenReturn(Response.ok("로그인 성공"))
suspend fun login(@RequestBody @Valid request: LoginRequest): ResponseEntity<Response> {
authService.authenticate(request.email, request.password)
return Response.ok("로그인 성공")
}

@PostMapping("/resend")
fun resendCode() = authService
.resendVerifyCode()
.thenReturn(Response.ok("이메일 코드 재전송 성공"))
@SwaggerRequireAuthorize
suspend fun resendCode(): ResponseEntity<Response> {
authService.resendVerifyCode()
return Response.ok("이메일 코드 재전송 성공")
}

@PostMapping("/verify")
fun verify(@RequestBody @Valid request: Mono<EmailVerifyRequest>) = request
.flatMap {
authService.verifyEmail(it.code)
}
.thenReturn(Response.ok("이메일 인증 성공"))
@SwaggerRequireAuthorize
suspend fun verify(@RequestBody @Valid request: EmailVerifyRequest): ResponseEntity<Response> {
authService.verifyEmail(request.code)
return Response.ok("이메일 인증 성공")
}

@PostMapping("/logout")
fun logout() = sessionHolder.getWebSession()
.flatMap { it.invalidate() }
.thenReturn(Response.ok("로그아웃 성공"))
@SwaggerRequireAuthorize
suspend fun logout(): ResponseEntity<Response> {
sessionHolder.getWebSession().invalidate().awaitSingleOrNull()
return Response.ok("로그아웃 성공")
}

@GetMapping("/session")
fun updateCurrentSession() = Mono.just(Response.ok("세션 갱신 성공"))
@SwaggerRequireAuthorize
suspend fun updateCurrentSession() = Response.ok("세션 갱신 성공")

@PatchMapping("/password")
fun passwordUpdate(@RequestBody @Valid request: PasswordUpdateRequest) = authService
.passwordUpdate(request)
.thenReturn(Response.ok("비밀번호 변경 성공. 다시 로그인 해 주세요."))
@SwaggerRequireAuthorize
suspend fun passwordUpdate(@RequestBody @Valid request: PasswordUpdateRequest): ResponseEntity<Response> {
authService.passwordUpdate(request)
return Response.ok("비밀번호 변경 성공. 다시 로그인 해 주세요.")
}

@DeleteMapping("/resign")
fun resign(webSession: WebSession) = authService
.resign(webSession)
.thenReturn(Response.ok("회원탈퇴 성공"))
@SwaggerRequireAuthorize
suspend fun resign(webSession: WebSession): ResponseEntity<Response> {
authService.resign()
return Response.ok("회원탈퇴 성공")
}
}
37 changes: 27 additions & 10 deletions src/main/kotlin/com/teamapi/palette/controller/ChatController.kt
Original file line number Diff line number Diff line change
@@ -1,27 +1,44 @@
package com.teamapi.palette.controller

import com.teamapi.palette.annotations.SwaggerRequireAuthorize
import com.teamapi.palette.dto.chat.ChatResponse
import com.teamapi.palette.dto.chat.ChatUpdateResponse
import com.teamapi.palette.dto.chat.CreateChatRequest
import com.teamapi.palette.dto.default.DefaultPageRequest
import com.teamapi.palette.response.ResponseBody
import com.teamapi.palette.service.ChatService
import io.swagger.v3.oas.annotations.Parameter
import org.springdoc.core.converters.models.PageableAsQueryParam
import org.springframework.data.domain.PageRequest
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*

@RestController
@RequestMapping("/chat")
@SwaggerRequireAuthorize
class ChatController(
private val chatService: ChatService,
) {
@PostMapping
fun createChat(@RequestBody request: CreateChatRequest) = chatService
.createChat(request)
.map { ResponseBody.ok("답변 생성 성공", it) }
// .thenReturn(Response.ok("채팅 생성 성공"))
suspend fun createChat(
@RequestBody request: CreateChatRequest,
@RequestParam("roomId") roomId: Long
): ResponseEntity<ResponseBody<ChatUpdateResponse>> {
val data = chatService.createChat(roomId, request.message)
return ResponseBody.ok("답변 생성 성공", data)
}

@GetMapping("/{roomId}")
fun getChatList(@PathVariable("roomId") roomId: Long) = chatService
.getChatList(roomId)
.map {
ResponseBody.ok("채팅 조회 성공", it)
}
@PageableAsQueryParam
suspend fun getChatList(
@PathVariable("roomId") roomId: Long,
@Parameter(hidden = true) pageRequest: DefaultPageRequest
): ResponseEntity<ResponseBody<List<ChatResponse>>> {
val data = chatService.getChatList(
roomId = roomId,
pageable = PageRequest.of(pageRequest.page, pageRequest.size)
)
return ResponseBody.ok("채팅 조회 성공", data)
}

@GetMapping("/my-image")
fun getMyImage(@RequestParam pageNumber: Int, @RequestParam pageSize: Int) = chatService
Expand Down
24 changes: 14 additions & 10 deletions src/main/kotlin/com/teamapi/palette/controller/InfoController.kt
Original file line number Diff line number Diff line change
@@ -1,27 +1,31 @@
package com.teamapi.palette.controller

import com.teamapi.palette.annotations.SwaggerRequireAuthorize
import com.teamapi.palette.dto.user.UpdateRequest
import com.teamapi.palette.dto.user.UserResponse
import com.teamapi.palette.response.Response
import com.teamapi.palette.response.ResponseBody
import com.teamapi.palette.service.UserService
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PatchMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*

@RestController
@RequestMapping("/info")
@SwaggerRequireAuthorize
class InfoController(
private val userService: UserService
) {
@GetMapping("/me")
fun myInfo() = userService.me()
.map { ResponseBody.ok("유저 조회 성공", it) }
suspend fun myInfo(): ResponseEntity<ResponseBody<UserResponse>> {
val data = userService.me()
return ResponseBody.ok("유저 조회 성공", data)
}

@PatchMapping("/me")
fun updateInfo(
suspend fun updateInfo(
@RequestBody request: UpdateRequest
) = userService.update(request)
.thenReturn(Response.ok("유저 수정 성공"))
): ResponseEntity<Response> {
userService.update(request)
return Response.ok("유저 수정 성공")
}
}
Loading

0 comments on commit 243a1bb

Please sign in to comment.