diff --git a/.github/workflows/_deploy-native.yml b/.github/workflows/_deploy-native.yml index 6c1703cf..dc58cdfc 100644 --- a/.github/workflows/_deploy-native.yml +++ b/.github/workflows/_deploy-native.yml @@ -3,7 +3,7 @@ name: deploy-native-template on: workflow_call: inputs: - ecr_repository: + ocir_repository: required: true type: string dockerfile: @@ -11,9 +11,11 @@ on: type: string description: 'Dockerfile path (e.g., api/Dockerfile-native)' secrets: - AWS_ACCESS_KEY_ID: + OCI_AUTH_TOKEN: required: true - AWS_SECRET_ACCESS_KEY: + DEPLOYER_APP_ID: + required: true + DEPLOYER_APP_PRIVATE_KEY: required: true jobs: @@ -24,43 +26,27 @@ jobs: env: IMAGE_TAG: ${{ github.run_number }} BUILD_NUMBER: ${{ github.run_number }} - ECR_REGISTRY: 405906814034.dkr.ecr.ap-northeast-2.amazonaws.com - ECR_REPOSITORY: ${{ inputs.ecr_repository }} + OCIR_REGISTRY: yny.ocir.io + OCIR_NAMESPACE: ax1dvc8vmenm + OCIR_REPOSITORY: ${{ inputs.ocir_repository }} steps: - name: Checkout uses: actions/checkout@v4 - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v4 - with: - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - aws-region: ap-northeast-2 - - - name: Login to ECR - id: login-ecr - uses: aws-actions/amazon-ecr-login@v2 + - name: Login to OCIR + run: echo "${{ secrets.OCI_AUTH_TOKEN }}" | docker login $OCIR_REGISTRY -u ax1dvc8vmenm/members/snutt-deployer --password-stdin - - name: Get and save Auth Token for CodeArtifact - id: get-save-codeartifact-auth-token - run: | - aws codeartifact get-authorization-token \ - --domain wafflestudio \ - --domain-owner 405906814034 \ - --query authorizationToken \ - --region ap-northeast-1 \ - --output text > .codeartifact_token - - - name: Docker build, tag, and push image to ECR + - name: Docker build, tag, and push image to OCIR id: build-push-image run: | + echo "${{ github.token }}" > .github_token docker build \ - --secret id=codeartifact_token,src=./.codeartifact_token \ + --secret id=github_token,src=./.github_token \ -f ${{ inputs.dockerfile }} \ - -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG \ + -t $OCIR_REGISTRY/$OCIR_NAMESPACE/$OCIR_REPOSITORY:$IMAGE_TAG \ . \ --platform linux/arm64 - docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG - echo "image=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT - + rm -f .github_token + docker push $OCIR_REGISTRY/$OCIR_NAMESPACE/$OCIR_REPOSITORY:$IMAGE_TAG + echo "image=$OCIR_REGISTRY/$OCIR_NAMESPACE/$OCIR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT diff --git a/.github/workflows/_deploy.yml b/.github/workflows/_deploy.yml index 976cb448..9bb79339 100644 --- a/.github/workflows/_deploy.yml +++ b/.github/workflows/_deploy.yml @@ -3,7 +3,7 @@ name: deploy-template on: workflow_call: inputs: - ecr_repository: + ocir_repository: required: true type: string dockerfile: @@ -11,9 +11,11 @@ on: type: string description: 'Dockerfile path (e.g., api/Dockerfile)' secrets: - AWS_ACCESS_KEY_ID: + OCI_AUTH_TOKEN: required: true - AWS_SECRET_ACCESS_KEY: + DEPLOYER_APP_ID: + required: true + DEPLOYER_APP_PRIVATE_KEY: required: true jobs: @@ -24,42 +26,27 @@ jobs: env: IMAGE_TAG: ${{ github.run_number }} BUILD_NUMBER: ${{ github.run_number }} - ECR_REGISTRY: 405906814034.dkr.ecr.ap-northeast-2.amazonaws.com - ECR_REPOSITORY: ${{ inputs.ecr_repository }} + OCIR_REGISTRY: yny.ocir.io + OCIR_NAMESPACE: ax1dvc8vmenm + OCIR_REPOSITORY: ${{ inputs.ocir_repository }} steps: - name: Checkout uses: actions/checkout@v4 - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v4 - with: - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - aws-region: ap-northeast-2 - - - name: Login to ECR - id: login-ecr - uses: aws-actions/amazon-ecr-login@v2 - - - name: Get and save Auth Token for CodeArtifact - id: get-save-codeartifact-auth-token - run: | - aws codeartifact get-authorization-token \ - --domain wafflestudio \ - --domain-owner 405906814034 \ - --query authorizationToken \ - --region ap-northeast-1 \ - --output text > .codeartifact_token + - name: Login to OCIR + run: echo "${{ secrets.OCI_AUTH_TOKEN }}" | docker login $OCIR_REGISTRY -u ax1dvc8vmenm/members/snutt-deployer --password-stdin - - name: Docker build, tag, and push image to ECR + - name: Docker build, tag, and push image to OCIR id: build-push-image run: | + echo "${{ github.token }}" > .github_token docker build \ - --secret id=codeartifact_token,src=./.codeartifact_token \ + --secret id=github_token,src=./.github_token \ -f ${{ inputs.dockerfile }} \ - -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG \ + -t $OCIR_REGISTRY/$OCIR_NAMESPACE/$OCIR_REPOSITORY:$IMAGE_TAG \ . \ --platform linux/arm64 - docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG - echo "image=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT + rm -f .github_token + docker push $OCIR_REGISTRY/$OCIR_NAMESPACE/$OCIR_REPOSITORY:$IMAGE_TAG + echo "image=$OCIR_REGISTRY/$OCIR_NAMESPACE/$OCIR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a3c2570a..2a1b721c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,13 +14,6 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v4 - with: - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - aws-region: ap-northeast-2 - - name: Set up JDK 25 uses: actions/setup-java@v4 with: @@ -28,5 +21,7 @@ jobs: distribution: 'temurin' - name: Run Tests + env: + GITHUB_TOKEN: ${{ github.token }} run: | ./gradlew clean test -x processAot -x processTestAot diff --git a/.github/workflows/deploy-api-dev-native.yml b/.github/workflows/deploy-api-dev-native.yml index 739e19e9..625f538f 100644 --- a/.github/workflows/deploy-api-dev-native.yml +++ b/.github/workflows/deploy-api-dev-native.yml @@ -8,8 +8,9 @@ jobs: deploy: uses: ./.github/workflows/_deploy-native.yml with: - ecr_repository: snutt-dev/snutt-timetable + ocir_repository: snutt-dev/snutt-timetable dockerfile: api/Dockerfile-native secrets: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + OCI_AUTH_TOKEN: ${{ secrets.OCI_AUTH_TOKEN }} + DEPLOYER_APP_ID: ${{ secrets.DEPLOYER_APP_ID }} + DEPLOYER_APP_PRIVATE_KEY: ${{ secrets.DEPLOYER_APP_PRIVATE_KEY }} diff --git a/.github/workflows/deploy-api-dev.yml b/.github/workflows/deploy-api-dev.yml index fd7362c5..93155625 100644 --- a/.github/workflows/deploy-api-dev.yml +++ b/.github/workflows/deploy-api-dev.yml @@ -8,8 +8,9 @@ jobs: deploy: uses: ./.github/workflows/_deploy.yml with: - ecr_repository: snutt-dev/snutt-timetable + ocir_repository: snutt-dev/snutt-timetable dockerfile: api/Dockerfile secrets: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + OCI_AUTH_TOKEN: ${{ secrets.OCI_AUTH_TOKEN }} + DEPLOYER_APP_ID: ${{ secrets.DEPLOYER_APP_ID }} + DEPLOYER_APP_PRIVATE_KEY: ${{ secrets.DEPLOYER_APP_PRIVATE_KEY }} diff --git a/.github/workflows/deploy-api-prod-native.yml b/.github/workflows/deploy-api-prod-native.yml index e9d322b9..28f96001 100644 --- a/.github/workflows/deploy-api-prod-native.yml +++ b/.github/workflows/deploy-api-prod-native.yml @@ -8,11 +8,12 @@ jobs: deploy: uses: ./.github/workflows/_deploy-native.yml with: - ecr_repository: snutt-prod/snutt-timetable + ocir_repository: snutt-prod/snutt-timetable dockerfile: api/Dockerfile-native secrets: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + OCI_AUTH_TOKEN: ${{ secrets.OCI_AUTH_TOKEN }} + DEPLOYER_APP_ID: ${{ secrets.DEPLOYER_APP_ID }} + DEPLOYER_APP_PRIVATE_KEY: ${{ secrets.DEPLOYER_APP_PRIVATE_KEY }} notify: needs: deploy diff --git a/.github/workflows/deploy-api-prod.yml b/.github/workflows/deploy-api-prod.yml index e84b126c..49ea59e0 100644 --- a/.github/workflows/deploy-api-prod.yml +++ b/.github/workflows/deploy-api-prod.yml @@ -8,11 +8,12 @@ jobs: deploy: uses: ./.github/workflows/_deploy.yml with: - ecr_repository: snutt-prod/snutt-timetable + ocir_repository: snutt-prod/snutt-timetable dockerfile: api/Dockerfile secrets: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + OCI_AUTH_TOKEN: ${{ secrets.OCI_AUTH_TOKEN }} + DEPLOYER_APP_ID: ${{ secrets.DEPLOYER_APP_ID }} + DEPLOYER_APP_PRIVATE_KEY: ${{ secrets.DEPLOYER_APP_PRIVATE_KEY }} notify: needs: deploy diff --git a/.github/workflows/deploy-batch-dev-native.yml b/.github/workflows/deploy-batch-dev-native.yml index a52efb03..d41fc66f 100644 --- a/.github/workflows/deploy-batch-dev-native.yml +++ b/.github/workflows/deploy-batch-dev-native.yml @@ -8,8 +8,9 @@ jobs: deploy: uses: ./.github/workflows/_deploy-native.yml with: - ecr_repository: snutt-dev/snutt-timetable-batch + ocir_repository: snutt-dev/snutt-timetable-batch dockerfile: batch/Dockerfile-native secrets: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + OCI_AUTH_TOKEN: ${{ secrets.OCI_AUTH_TOKEN }} + DEPLOYER_APP_ID: ${{ secrets.DEPLOYER_APP_ID }} + DEPLOYER_APP_PRIVATE_KEY: ${{ secrets.DEPLOYER_APP_PRIVATE_KEY }} diff --git a/.github/workflows/deploy-batch-dev.yml b/.github/workflows/deploy-batch-dev.yml index df0841ad..1abdbd9a 100644 --- a/.github/workflows/deploy-batch-dev.yml +++ b/.github/workflows/deploy-batch-dev.yml @@ -8,8 +8,9 @@ jobs: deploy: uses: ./.github/workflows/_deploy.yml with: - ecr_repository: snutt-dev/snutt-timetable-batch + ocir_repository: snutt-dev/snutt-timetable-batch dockerfile: batch/Dockerfile secrets: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + OCI_AUTH_TOKEN: ${{ secrets.OCI_AUTH_TOKEN }} + DEPLOYER_APP_ID: ${{ secrets.DEPLOYER_APP_ID }} + DEPLOYER_APP_PRIVATE_KEY: ${{ secrets.DEPLOYER_APP_PRIVATE_KEY }} diff --git a/.github/workflows/deploy-batch-prod-native.yml b/.github/workflows/deploy-batch-prod-native.yml index 0413702c..75587949 100644 --- a/.github/workflows/deploy-batch-prod-native.yml +++ b/.github/workflows/deploy-batch-prod-native.yml @@ -8,8 +8,9 @@ jobs: deploy: uses: ./.github/workflows/_deploy-native.yml with: - ecr_repository: snutt-prod/snutt-timetable-batch + ocir_repository: snutt-prod/snutt-timetable-batch dockerfile: batch/Dockerfile-native secrets: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + OCI_AUTH_TOKEN: ${{ secrets.OCI_AUTH_TOKEN }} + DEPLOYER_APP_ID: ${{ secrets.DEPLOYER_APP_ID }} + DEPLOYER_APP_PRIVATE_KEY: ${{ secrets.DEPLOYER_APP_PRIVATE_KEY }} diff --git a/.github/workflows/deploy-batch-prod.yml b/.github/workflows/deploy-batch-prod.yml index 62b0f65a..2d1162c5 100644 --- a/.github/workflows/deploy-batch-prod.yml +++ b/.github/workflows/deploy-batch-prod.yml @@ -8,8 +8,9 @@ jobs: deploy: uses: ./.github/workflows/_deploy.yml with: - ecr_repository: snutt-prod/snutt-timetable-batch + ocir_repository: snutt-prod/snutt-timetable-batch dockerfile: batch/Dockerfile secrets: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + OCI_AUTH_TOKEN: ${{ secrets.OCI_AUTH_TOKEN }} + DEPLOYER_APP_ID: ${{ secrets.DEPLOYER_APP_ID }} + DEPLOYER_APP_PRIVATE_KEY: ${{ secrets.DEPLOYER_APP_PRIVATE_KEY }} diff --git a/.github/workflows/deploy-manual-native.yml b/.github/workflows/deploy-manual-native.yml index f8881e92..ef80cf37 100644 --- a/.github/workflows/deploy-manual-native.yml +++ b/.github/workflows/deploy-manual-native.yml @@ -3,8 +3,8 @@ name: Deploy Manual Native on: workflow_dispatch: inputs: - ecr_repository: - description: 'ECR 리포지토리 (예: snutt-dev/snutt-timetable)' + ocir_repository: + description: 'OCIR 리포지토리 (예: snutt-dev/snutt-timetable)' required: true type: string dockerfile: @@ -16,9 +16,9 @@ jobs: deploy: uses: ./.github/workflows/_deploy-native.yml with: - ecr_repository: ${{ inputs.ecr_repository }} + ocir_repository: ${{ inputs.ocir_repository }} dockerfile: ${{ inputs.dockerfile }} secrets: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - + OCI_AUTH_TOKEN: ${{ secrets.OCI_AUTH_TOKEN }} + DEPLOYER_APP_ID: ${{ secrets.DEPLOYER_APP_ID }} + DEPLOYER_APP_PRIVATE_KEY: ${{ secrets.DEPLOYER_APP_PRIVATE_KEY }} diff --git a/.github/workflows/deploy-manual.yml b/.github/workflows/deploy-manual.yml index f1a7fa69..07f7bee2 100644 --- a/.github/workflows/deploy-manual.yml +++ b/.github/workflows/deploy-manual.yml @@ -3,8 +3,8 @@ name: Deploy Manual on: workflow_dispatch: inputs: - ecr_repository: - description: 'ECR 리포지토리 (예: snutt-dev/snutt-timetable)' + ocir_repository: + description: 'OCIR 리포지토리 (예: snutt-dev/snutt-timetable)' required: true type: string dockerfile: @@ -16,8 +16,9 @@ jobs: deploy: uses: ./.github/workflows/_deploy.yml with: - ecr_repository: ${{ inputs.ecr_repository }} + ocir_repository: ${{ inputs.ocir_repository }} dockerfile: ${{ inputs.dockerfile }} secrets: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + OCI_AUTH_TOKEN: ${{ secrets.OCI_AUTH_TOKEN }} + DEPLOYER_APP_ID: ${{ secrets.DEPLOYER_APP_ID }} + DEPLOYER_APP_PRIVATE_KEY: ${{ secrets.DEPLOYER_APP_PRIVATE_KEY }} diff --git a/api/Dockerfile b/api/Dockerfile index dffe9e2d..2095d4e8 100644 --- a/api/Dockerfile +++ b/api/Dockerfile @@ -2,6 +2,6 @@ FROM ghcr.io/graalvm/jdk-community:25 WORKDIR /app COPY . /app RUN microdnf install -y findutils --nodocs -RUN --mount=type=secret,id=codeartifact_token ./gradlew :api:bootJar -PcodeArtifactAuthToken=$(cat /run/secrets/codeartifact_token) +RUN --mount=type=secret,id=github_token GITHUB_TOKEN=$(cat /run/secrets/github_token) ./gradlew :api:bootJar EXPOSE 8080 ENTRYPOINT java $JAVA_OPTS -jar api/build/libs/snutt-api.jar diff --git a/api/Dockerfile-native b/api/Dockerfile-native index 2efc93ef..ac75859a 100644 --- a/api/Dockerfile-native +++ b/api/Dockerfile-native @@ -2,7 +2,7 @@ FROM container-registry.oracle.com/graalvm/native-image:25 AS builder WORKDIR /app COPY . /app -RUN --mount=type=secret,id=codeartifact_token ./gradlew :api:nativeCompile -PcodeArtifactAuthToken=$(cat /run/secrets/codeartifact_token) +RUN --mount=type=secret,id=github_token GITHUB_TOKEN=$(cat /run/secrets/github_token) ./gradlew :api:nativeCompile # Runtime stage FROM docker.io/debian:stable-slim diff --git a/api/build.gradle.kts b/api/build.gradle.kts index 732cd7fa..2bfce584 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -10,7 +10,7 @@ dependencies { implementation("io.jsonwebtoken:jjwt-api:0.13.0") implementation("io.jsonwebtoken:jjwt-impl:0.13.0") implementation("io.jsonwebtoken:jjwt-jackson:0.13.0") - implementation("org.springdoc:springdoc-openapi-starter-webflux-ui:3.0.0") + implementation("org.springdoc:springdoc-openapi-starter-webflux-ui:3.0.2") runtimeOnly("jakarta.xml.bind:jakarta.xml.bind-api:4.0.2") testImplementation(testFixtures(project(":core"))) diff --git a/api/src/main/kotlin/config/SwaggerConfig.kt b/api/src/main/kotlin/config/SwaggerConfig.kt index 8439c56a..77f7e173 100644 --- a/api/src/main/kotlin/config/SwaggerConfig.kt +++ b/api/src/main/kotlin/config/SwaggerConfig.kt @@ -6,8 +6,10 @@ import io.swagger.v3.oas.annotations.servers.Server import io.swagger.v3.oas.models.security.SecurityRequirement import io.swagger.v3.oas.models.security.SecurityScheme import org.springdoc.core.customizers.OpenApiCustomizer +import org.springframework.aot.hint.annotation.RegisterReflectionForBinding import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration +import tools.jackson.core.JsonParser @OpenAPIDefinition( servers = [Server(url = "/", description = "Local")], @@ -18,6 +20,7 @@ import org.springframework.context.annotation.Configuration ), ) @Configuration +@RegisterReflectionForBinding(JsonParser.NumberType::class) class SwaggerConfig { @Bean fun openApiCustomizer() = diff --git a/api/src/main/kotlin/controller/AdminController.kt b/api/src/main/kotlin/controller/AdminController.kt index 03e76887..07aee5cd 100644 --- a/api/src/main/kotlin/controller/AdminController.kt +++ b/api/src/main/kotlin/controller/AdminController.kt @@ -101,7 +101,11 @@ class AdminController( @PostMapping("/popups") suspend fun postPopup( @RequestBody body: PostPopupRequest, - ): PopupResponse = popupService.postPopup(body).let(::PopupResponse) + ): PopupResponse { + val popup = popupService.postPopup(body) + val imageUri = storageService.getFileUri(popup.imageOriginUri) + return PopupResponse(popup, imageUri) + } @DeleteMapping("/popups/{id}") suspend fun deletePopup( diff --git a/api/src/main/kotlin/controller/DiaryController.kt b/api/src/main/kotlin/controller/DiaryController.kt index 3415db74..00694f99 100644 --- a/api/src/main/kotlin/controller/DiaryController.kt +++ b/api/src/main/kotlin/controller/DiaryController.kt @@ -95,7 +95,7 @@ class DiaryController( @CurrentUser user: User, @PathVariable id: String, ): OkResponse { - diaryService.removeSubmission(user.id!!, id) + diaryService.removeSubmission(id, user.id!!) return OkResponse() } } diff --git a/api/src/main/kotlin/controller/PopupController.kt b/api/src/main/kotlin/controller/PopupController.kt index 85b082d0..415125e5 100644 --- a/api/src/main/kotlin/controller/PopupController.kt +++ b/api/src/main/kotlin/controller/PopupController.kt @@ -2,6 +2,7 @@ package com.wafflestudio.snutt.controller import com.wafflestudio.snutt.common.client.ClientInfo import com.wafflestudio.snutt.common.dto.ListResponse +import com.wafflestudio.snutt.common.storage.StorageService import com.wafflestudio.snutt.filter.SnuttNoAuthApiFilterTarget import com.wafflestudio.snutt.popup.dto.PopupResponse import com.wafflestudio.snutt.popup.service.PopupService @@ -20,14 +21,18 @@ import org.springframework.web.bind.annotation.RestController ) class PopupController( private val popupService: PopupService, + private val storageService: StorageService, ) { @GetMapping("") suspend fun getPopups( @RequestAttribute("clientInfo") clientInfo: ClientInfo, ): ListResponse { val popups = popupService.getPopups(clientInfo) + val imageUris = storageService.getFileUris(popups.map { it.imageOriginUri }) + val responses = popups.zip(imageUris) { popup, imageUri -> PopupResponse(popup, imageUri) } + return ListResponse( - content = popups.map(::PopupResponse), + content = responses, totalCount = popups.size, ) } diff --git a/api/src/main/resources/META-INF/native-image/org.springdoc/springdoc-openapi-core/reachability-metadata.json b/api/src/main/resources/META-INF/native-image/org.springdoc/springdoc-openapi-core/reachability-metadata.json deleted file mode 100644 index 3ca8d7f5..00000000 --- a/api/src/main/resources/META-INF/native-image/org.springdoc/springdoc-openapi-core/reachability-metadata.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "reflection": [ - { - "type": "org.springdoc.core.providers.SpringWebProvider$$SpringCGLIB$$0", - "fields": [ - { - "name": "CGLIB$FACTORY_DATA" - }, - { - "name": "CGLIB$CALLBACK_FILTER" - } - ] - }, - { - "type": "org.springdoc.core.providers.SpringWebProvider", - "methods": [ - { - "name": "findPathPrefix", - "parameterTypes": [ - "org.springdoc.core.properties.SpringDocConfigProperties" - ] - } - ] - } - ] -} diff --git a/api/src/test/kotlin/BaseIntegTest.kt b/api/src/test/kotlin/BaseIntegTest.kt index c6d4daaa..e7620881 100644 --- a/api/src/test/kotlin/BaseIntegTest.kt +++ b/api/src/test/kotlin/BaseIntegTest.kt @@ -1,3 +1,6 @@ +import com.ninjasquad.springmockk.MockkBean +import com.wafflestudio.snutt.common.mail.MailClient +import com.wafflestudio.snutt.common.storage.StorageClient import io.kotest.core.spec.style.WordSpec import mock.MockMongoDB import org.springframework.boot.test.context.SpringBootTest @@ -5,6 +8,7 @@ import org.springframework.context.annotation.Import @SpringBootTest @Import(MockMongoDB::class) +@MockkBean(types = [StorageClient::class, MailClient::class], relaxed = true) abstract class BaseIntegTest( body: BaseIntegTest.() -> Unit = {}, ) : WordSpec() { diff --git a/batch/Dockerfile b/batch/Dockerfile index 073c517e..8f5bab92 100644 --- a/batch/Dockerfile +++ b/batch/Dockerfile @@ -2,5 +2,5 @@ FROM ghcr.io/graalvm/jdk-community:25 WORKDIR /app COPY . /app RUN microdnf install -y findutils --nodocs -RUN --mount=type=secret,id=codeartifact_token ./gradlew :batch:bootJar -PcodeArtifactAuthToken=$(cat /run/secrets/codeartifact_token) +RUN --mount=type=secret,id=github_token GITHUB_TOKEN=$(cat /run/secrets/github_token) ./gradlew :batch:bootJar ENTRYPOINT java $JAVA_OPTS -jar batch/build/libs/snutt-batch.jar --job.name=${JOB_NAME} diff --git a/batch/Dockerfile-native b/batch/Dockerfile-native index beb4895b..6d00262f 100644 --- a/batch/Dockerfile-native +++ b/batch/Dockerfile-native @@ -2,7 +2,7 @@ FROM container-registry.oracle.com/graalvm/native-image:25 AS builder WORKDIR /app COPY . /app -RUN --mount=type=secret,id=codeartifact_token ./gradlew :batch:nativeCompile -PcodeArtifactAuthToken=$(cat /run/secrets/codeartifact_token) +RUN --mount=type=secret,id=github_token GITHUB_TOKEN=$(cat /run/secrets/github_token) ./gradlew :batch:nativeCompile # Runtime stage FROM docker.io/debian:stable-slim diff --git a/build.gradle.kts b/build.gradle.kts index afbb791b..25a0fc07 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,6 +1,5 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.jetbrains.kotlin.gradle.tasks.KotlinCompile -import java.io.ByteArrayOutputStream plugins { id("org.graalvm.buildtools.native") version "0.11.3" apply false @@ -17,7 +16,22 @@ version = "0.0.1-SNAPSHOT" allprojects { repositories { mavenCentral() - mavenCodeArtifact() + maven { + url = uri("https://maven.pkg.github.com/wafflestudio/spring-waffle") + credentials { + username = "wafflestudio" + password = findProperty("gpr.key") as String? + ?: System.getenv("GITHUB_TOKEN") + ?: runCatching { + ProcessBuilder("gh", "auth", "token") + .start() + .inputStream + .bufferedReader() + .readText() + .trim() + }.getOrDefault("") + } + } mavenLocal() } } @@ -66,43 +80,3 @@ subprojects { useJUnitPlatform() } } - -interface InjectedExecOps { - @get:Inject val execOps: ExecOperations -} - -fun RepositoryHandler.mavenCodeArtifact() { - val injected = project.objects.newInstance() - maven { - val authToken = - properties["codeArtifactAuthToken"] as String? ?: ByteArrayOutputStream().use { - runCatching { - injected.execOps.exec { - commandLine = - listOf( - "aws", - "codeartifact", - "get-authorization-token", - "--domain", - "wafflestudio", - "--domain-owner", - "405906814034", - "--query", - "authorizationToken", - "--region", - "ap-northeast-1", - "--output", - "text", - ) - standardOutput = it - } - } - it.toString() - } - url = uri("https://wafflestudio-405906814034.d.codeartifact.ap-northeast-1.amazonaws.com/maven/spring-waffle/") - credentials { - username = "aws" - password = authToken - } - } -} diff --git a/core/build.gradle.kts b/core/build.gradle.kts index f15bcb69..9dd47741 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -16,9 +16,11 @@ dependencies { api("org.springframework.boot:spring-boot-starter-data-redis") implementation("org.springframework.security:spring-security-crypto") - implementation("software.amazon.awssdk:s3:2.32.14") - implementation("software.amazon.awssdk:ses:2.32.14") - implementation("com.wafflestudio.spring:spring-boot-starter-waffle:2.0.0") + implementation("com.oracle.oci.sdk:oci-java-sdk-objectstorage:3.80.1") + implementation("com.oracle.oci.sdk:oci-java-sdk-emaildataplane:3.80.1") + implementation("com.oracle.oci.sdk:oci-java-sdk-common-httpclient-jersey3:3.80.1") + implementation("com.wafflestudio.spring:spring-boot-starter-waffle-oci-vault:2.1.0") + implementation("com.wafflestudio.spring.truffle:spring-boot-starter-truffle:2.1.0") implementation("com.google.firebase:firebase-admin:9.7.0") implementation("io.jsonwebtoken:jjwt-api:0.13.0") implementation("io.jsonwebtoken:jjwt-impl:0.13.0") diff --git a/core/src/main/kotlin/common/extension/OciAsyncExtensions.kt b/core/src/main/kotlin/common/extension/OciAsyncExtensions.kt new file mode 100644 index 00000000..82a07ce0 --- /dev/null +++ b/core/src/main/kotlin/common/extension/OciAsyncExtensions.kt @@ -0,0 +1,34 @@ +package com.wafflestudio.snutt.common.extension + +import com.oracle.bmc.responses.AsyncHandler +import kotlinx.coroutines.CancellableContinuation +import kotlinx.coroutines.suspendCancellableCoroutine +import java.util.concurrent.Future +import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException + +internal suspend fun awaitOciCall(execute: (AsyncHandler) -> Future): RESPONSE = + suspendCancellableCoroutine { continuation -> + val future = execute(OciAsyncHandler(continuation)) + continuation.invokeOnCancellation { + future.cancel(true) + } + } + +private class OciAsyncHandler( + private val continuation: CancellableContinuation, +) : AsyncHandler { + override fun onSuccess( + request: REQUEST, + response: RESPONSE, + ) { + continuation.resume(response) + } + + override fun onError( + request: REQUEST, + error: Throwable, + ) { + continuation.resumeWithException(error) + } +} diff --git a/core/src/main/kotlin/common/mail/MailClient.kt b/core/src/main/kotlin/common/mail/MailClient.kt index 7081c5e6..4527b022 100644 --- a/core/src/main/kotlin/common/mail/MailClient.kt +++ b/core/src/main/kotlin/common/mail/MailClient.kt @@ -1,18 +1,27 @@ package com.wafflestudio.snutt.common.mail -import kotlinx.coroutines.future.await +import com.oracle.bmc.auth.BasicAuthenticationDetailsProvider +import com.oracle.bmc.emaildataplane.EmailDPAsyncClient +import com.oracle.bmc.emaildataplane.model.EmailAddress +import com.oracle.bmc.emaildataplane.model.Recipients +import com.oracle.bmc.emaildataplane.model.Sender +import com.oracle.bmc.emaildataplane.model.SubmitEmailDetails +import com.oracle.bmc.emaildataplane.requests.SubmitEmailRequest +import com.wafflestudio.snutt.common.extension.awaitOciCall +import com.wafflestudio.snutt.config.OciConfig import org.springframework.stereotype.Component -import software.amazon.awssdk.regions.Region.AP_NORTHEAST_2 -import software.amazon.awssdk.services.ses.SesAsyncClient -import software.amazon.awssdk.services.ses.model.Body -import software.amazon.awssdk.services.ses.model.Content -import software.amazon.awssdk.services.ses.model.Destination -import software.amazon.awssdk.services.ses.model.Message -import software.amazon.awssdk.services.ses.model.SendEmailRequest @Component -class MailClient { - private val sesClient = SesAsyncClient.builder().region(AP_NORTHEAST_2).build() +class MailClient( + authProvider: BasicAuthenticationDetailsProvider, +) { + private val compartmentId = "ocid1.compartment.oc1..aaaaaaaaxzo4fga6br76o3e34rshtsl6alzripmgdh7f4lg4u4tzezosypaq" + private val emailClient = + EmailDPAsyncClient + .builder() + .region(OciConfig.REGION) + .build(authProvider) + val sourceEmail = "snutt@wafflestudio.com" suspend fun sendMail( @@ -20,20 +29,41 @@ class MailClient { subject: String, body: String, ) { - val dest = Destination.builder().toAddresses(to).build() - val message = - Message + val emailDetails = + SubmitEmailDetails .builder() - .subject(Content.builder().data(subject).build()) - .body(Body.builder().html(Content.builder().data(body).build()).build()) + .sender( + Sender + .builder() + .senderAddress( + EmailAddress + .builder() + .email(sourceEmail) + .name("SNUTT") + .build(), + ).compartmentId(compartmentId) + .build(), + ).recipients( + Recipients + .builder() + .to( + listOf( + EmailAddress + .builder() + .email(to) + .build(), + ), + ).build(), + ).subject(subject) + .bodyHtml(body) .build() + val request = - SendEmailRequest + SubmitEmailRequest .builder() - .destination(dest) - .message(message) - .source(sourceEmail) + .submitEmailDetails(emailDetails) .build() - sesClient.sendEmail(request).await() + + awaitOciCall { handler -> emailClient.submitEmail(request, handler) } } } diff --git a/core/src/main/kotlin/common/storage/StorageClient.kt b/core/src/main/kotlin/common/storage/StorageClient.kt index b9367099..ff993ac2 100644 --- a/core/src/main/kotlin/common/storage/StorageClient.kt +++ b/core/src/main/kotlin/common/storage/StorageClient.kt @@ -1,84 +1,108 @@ package com.wafflestudio.snutt.common.storage +import com.oracle.bmc.auth.BasicAuthenticationDetailsProvider +import com.oracle.bmc.objectstorage.ObjectStorageAsyncClient +import com.oracle.bmc.objectstorage.model.CreatePreauthenticatedRequestDetails +import com.oracle.bmc.objectstorage.model.CreatePreauthenticatedRequestDetails.AccessType +import com.oracle.bmc.objectstorage.requests.CreatePreauthenticatedRequestRequest +import com.oracle.bmc.objectstorage.requests.GetNamespaceRequest +import com.wafflestudio.snutt.common.extension.awaitOciCall +import com.wafflestudio.snutt.config.OciConfig import jakarta.annotation.PostConstruct +import kotlinx.coroutines.runBlocking import org.springframework.stereotype.Component -import software.amazon.awssdk.regions.Region.AP_NORTHEAST_2 -import software.amazon.awssdk.services.s3.internal.signing.DefaultS3Presigner -import software.amazon.awssdk.services.s3.model.GetObjectRequest -import software.amazon.awssdk.services.s3.model.PutObjectRequest -import software.amazon.awssdk.services.s3.presigner.model.GetObjectPresignRequest -import software.amazon.awssdk.services.s3.presigner.model.PutObjectPresignRequest import java.time.Duration +import java.time.Instant +import java.util.Date +import java.util.UUID @Component -class StorageClient { - private val presigner = DefaultS3Presigner.builder().region(AP_NORTHEAST_2).build() +class StorageClient( + authProvider: BasicAuthenticationDetailsProvider, +) { + private val objectStorageClient = + ObjectStorageAsyncClient + .builder() + .region(OciConfig.REGION) + .build(authProvider) - companion object { - lateinit var instance: StorageClient - private set + private lateinit var namespace: String + companion object { private val uploadDuration = Duration.ofMinutes(10) private val getDuration = Duration.ofHours(1) + private const val ENDPOINT = "https://objectstorage.ap-chuncheon-1.oraclecloud.com" } @PostConstruct - fun init() { - instance = this - } + fun initializeNamespace() = + runBlocking { + namespace = fetchNamespace() + } - suspend fun generatePutSignedUris( + suspend fun generatePutSignedUri( storageType: StorageType, key: String, - ): String { - val request = - PutObjectRequest - .builder() - .bucket(storageType.bucketName) - .key(key) - .build() - - val presignRequest = - PutObjectPresignRequest - .builder() - .signatureDuration(uploadDuration) - .putObjectRequest(request) - .build() + ): String = + createSignedUri( + bucketName = storageType.bucketName, + key = key, + accessType = AccessType.ObjectWrite, + expiresIn = uploadDuration, + namePrefix = "upload", + ) - return presigner.presignPutObject(presignRequest).url().toString() - } + suspend fun generateGetUri(originUri: String): String { + val withoutScheme = originUri.removePrefix("s3://") + val bucketName = withoutScheme.substringBefore("/") + val key = withoutScheme.substringAfter("/", missingDelimiterValue = "") - fun generateGetUri(originUri: String): String { - val bucketName = originUri.substringAfter("s3://").substringBefore("/") - val key = originUri.substringAfter(bucketName).substringAfter("/") - - if (StorageType.from(bucketName).acl == Acl.PUBLIC_READ) { - return "https://$bucketName.s3.${AP_NORTHEAST_2.id()}.amazonaws.com/$key" + return if (StorageType.from(bucketName).acl == Acl.PUBLIC_READ) { + "$ENDPOINT/n/$namespace/b/$bucketName/o/$key" + } else { + createSignedUri( + bucketName = bucketName, + key = key, + accessType = AccessType.ObjectRead, + expiresIn = getDuration, + namePrefix = "download", + ) } - - return generateGetSignedUri(bucketName, key) } - private fun generateGetSignedUri( + private suspend fun fetchNamespace(): String = + awaitOciCall { handler -> + objectStorageClient.getNamespace(GetNamespaceRequest.builder().build(), handler) + }.value + + private suspend fun createSignedUri( bucketName: String, key: String, + accessType: AccessType, + expiresIn: Duration, + namePrefix: String, ): String { - val request = - GetObjectRequest + val parDetails = + CreatePreauthenticatedRequestDetails .builder() - .bucket(bucketName) - .key(key) + .name("$namePrefix-${UUID.randomUUID()}") + .objectName(key) + .accessType(accessType) + .timeExpires(Date.from(Instant.now().plus(expiresIn))) .build() - val presignRequest = - GetObjectPresignRequest + val request = + CreatePreauthenticatedRequestRequest .builder() - .signatureDuration(getDuration) - .getObjectRequest(request) + .namespaceName(namespace) + .bucketName(bucketName) + .createPreauthenticatedRequestDetails(parDetails) .build() + val accessUri = + awaitOciCall { handler -> objectStorageClient.createPreauthenticatedRequest(request, handler) } + .preauthenticatedRequest + .accessUri - return presigner.presignGetObject(presignRequest).url().toString() + return "$ENDPOINT$accessUri" } } - -fun String.toGetUri(): String = StorageClient.instance.generateGetUri(this) diff --git a/core/src/main/kotlin/common/storage/StorageService.kt b/core/src/main/kotlin/common/storage/StorageService.kt index ed323646..df966de2 100644 --- a/core/src/main/kotlin/common/storage/StorageService.kt +++ b/core/src/main/kotlin/common/storage/StorageService.kt @@ -3,6 +3,9 @@ package com.wafflestudio.snutt.common.storage import com.wafflestudio.snutt.common.exception.TooManyFilesException import com.wafflestudio.snutt.common.storage.FileExtension.JPG import com.wafflestudio.snutt.common.storage.dto.FileUploadUriDto +import kotlinx.coroutines.async +import kotlinx.coroutines.awaitAll +import kotlinx.coroutines.coroutineScope import org.springframework.stereotype.Service import java.util.UUID @@ -23,18 +26,30 @@ class StorageService( val storageType = storageSource.storageType val path = storageSource.path?.let { "$it/" } ?: "" - return (1..count).map { - val key = "$path${UUID.randomUUID()}.${JPG.value}" - val uploadUri = storageClient.generatePutSignedUris(storageType, key) + return coroutineScope { + (1..count) + .map { + async { + val key = "$path${UUID.randomUUID()}.${JPG.value}" + val fileOriginUri = "s3://${storageType.bucketName}/$key" - val fileOriginUri = "s3://${storageType.bucketName}/$key" - val fileUri = storageClient.generateGetUri(fileOriginUri) + val uploadUriDeferred = async { storageClient.generatePutSignedUri(storageType, key) } + val fileUriDeferred = async { storageClient.generateGetUri(fileOriginUri) } - FileUploadUriDto( - uploadUri = uploadUri, - fileOriginUri = fileOriginUri, - fileUri = fileUri, - ) + FileUploadUriDto( + uploadUri = uploadUriDeferred.await(), + fileOriginUri = fileOriginUri, + fileUri = fileUriDeferred.await(), + ) + } + }.awaitAll() } } + + suspend fun getFileUri(originUri: String): String = storageClient.generateGetUri(originUri) + + suspend fun getFileUris(originUris: List): List = + coroutineScope { + originUris.map { originUri -> async { getFileUri(originUri) } }.awaitAll() + } } diff --git a/core/src/main/kotlin/config/OciConfig.kt b/core/src/main/kotlin/config/OciConfig.kt new file mode 100644 index 00000000..a141065e --- /dev/null +++ b/core/src/main/kotlin/config/OciConfig.kt @@ -0,0 +1,56 @@ +package com.wafflestudio.snutt.config + +import com.oracle.bmc.Region +import com.oracle.bmc.auth.BasicAuthenticationDetailsProvider +import com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider +import com.oracle.bmc.auth.InstancePrincipalsAuthenticationDetailsProvider +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Value +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.context.annotation.Profile + +@Configuration +@Profile("!test") +class OciConfig( + @param:Value("\${oci.auth.type:auto}") + private val authType: String, + @param:Value("\${oci.config.profile:DEFAULT}") + private val configProfile: String, +) { + companion object { + val REGION: Region = Region.AP_CHUNCHEON_1 + } + + @Bean + fun ociAuthProvider(): BasicAuthenticationDetailsProvider = + when (authType.trim().lowercase()) { + "auto" -> + try { + instancePrincipalAuth() + } catch (e: Exception) { + log.info( + "OCI instance principal auth failed; falling back to config file auth (oci.auth.type=auto): {}", + e.message, + ) + configFileAuth() + } + + "config" -> configFileAuth() + "instance_principal" -> instancePrincipalAuth() + else -> + throw IllegalArgumentException( + "Unsupported oci.auth.type='${authType.trim()}'. Supported: auto, config, instance_principal", + ) + } + + private val log = LoggerFactory.getLogger(javaClass) + + private fun instancePrincipalAuth(): BasicAuthenticationDetailsProvider = + InstancePrincipalsAuthenticationDetailsProvider.builder().build() + + private fun configFileAuth(): BasicAuthenticationDetailsProvider { + val profile = configProfile.trim().ifEmpty { "DEFAULT" } + return ConfigFileAuthenticationDetailsProvider(profile) + } +} diff --git a/core/src/main/kotlin/popup/dto/PopupResponse.kt b/core/src/main/kotlin/popup/dto/PopupResponse.kt index 9e2c022b..3dbcaad3 100644 --- a/core/src/main/kotlin/popup/dto/PopupResponse.kt +++ b/core/src/main/kotlin/popup/dto/PopupResponse.kt @@ -1,6 +1,5 @@ package com.wafflestudio.snutt.popup.dto -import com.wafflestudio.snutt.common.storage.toGetUri import com.wafflestudio.snutt.popup.data.Popup data class PopupResponse( @@ -16,12 +15,15 @@ data class PopupResponse( val hidden_days: Int?, ) -fun PopupResponse(popup: Popup): PopupResponse = +fun PopupResponse( + popup: Popup, + imageUri: String, +): PopupResponse = PopupResponse( id = popup.id!!, key = popup.key, - imageUri = popup.imageOriginUri.toGetUri(), - image_url = popup.imageOriginUri.toGetUri(), + imageUri = imageUri, + image_url = imageUri, linkUrl = popup.linkUrl, hiddenDays = popup.hiddenDays, hidden_days = popup.hiddenDays, diff --git a/core/src/main/resources/META-INF/native-image/com.oracle.oci.sdk/oci-java-sdk-common/resource-config.json b/core/src/main/resources/META-INF/native-image/com.oracle.oci.sdk/oci-java-sdk-common/resource-config.json new file mode 100644 index 00000000..1f017f74 --- /dev/null +++ b/core/src/main/resources/META-INF/native-image/com.oracle.oci.sdk/oci-java-sdk-common/resource-config.json @@ -0,0 +1,9 @@ +{ + "resources": { + "includes": [ + { + "pattern": "com/oracle/bmc/.*\\.properties$" + } + ] + } +} diff --git a/core/src/main/resources/META-INF/native-image/reflect-config.json b/core/src/main/resources/META-INF/native-image/kotlin-compat/reflect-config.json similarity index 99% rename from core/src/main/resources/META-INF/native-image/reflect-config.json rename to core/src/main/resources/META-INF/native-image/kotlin-compat/reflect-config.json index de72d579..7ea3d649 100644 --- a/core/src/main/resources/META-INF/native-image/reflect-config.json +++ b/core/src/main/resources/META-INF/native-image/kotlin-compat/reflect-config.json @@ -17,4 +17,4 @@ "allDeclaredMethods": true, "allDeclaredConstructors": true } -] \ No newline at end of file +] diff --git a/core/src/main/resources/META-INF/native-image/org.glassfish.jersey.inject/jersey-hk2/reflect-config.json b/core/src/main/resources/META-INF/native-image/org.glassfish.jersey.inject/jersey-hk2/reflect-config.json new file mode 100644 index 00000000..0f7742dd --- /dev/null +++ b/core/src/main/resources/META-INF/native-image/org.glassfish.jersey.inject/jersey-hk2/reflect-config.json @@ -0,0 +1,80 @@ +[ + { + "name": "org.glassfish.jersey.inject.hk2.JerseyClassAnalyzer", + "allDeclaredFields": true, + "allDeclaredMethods": true, + "allDeclaredConstructors": true + }, + { + "name": "org.glassfish.jersey.inject.hk2.JerseyClassAnalyzer$Binder", + "allDeclaredFields": true, + "allDeclaredMethods": true, + "allDeclaredConstructors": true + }, + { + "name": "org.glassfish.hk2.internal.PerThreadContext", + "allDeclaredFields": true, + "allDeclaredMethods": true, + "allDeclaredConstructors": true + }, + { + "name": "org.glassfish.hk2.osgiresourcelocator.ServiceLoader", + "methods": [{ "name":"lookupProviderClasses", "parameterTypes":["java.lang.Class"] }] + }, + { + "name":"org.glassfish.jersey.inject.hk2.ContextInjectionResolverImpl", + "allDeclaredFields":true, + "allDeclaredMethods":true, + "allDeclaredConstructors":true + }, + { + "name":"org.glassfish.jersey.inject.hk2.Hk2InjectionManagerFactory", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.glassfish.jersey.inject.hk2.Hk2RequestScope", + "allDeclaredFields":true, + "allDeclaredMethods":true, + "allDeclaredConstructors":true + }, + { + "name":"org.glassfish.jersey.inject.hk2.InstanceSupplierFactoryBridge", + "methods":[{"name":"provide","parameterTypes":[] }] + }, + { + "name":"org.glassfish.jersey.inject.hk2.JerseyErrorService", + "allDeclaredFields":true, + "allDeclaredMethods":true, + "allDeclaredConstructors":true + }, + { + "name":"org.glassfish.jersey.inject.hk2.RequestContext", + "allDeclaredFields":true, + "allDeclaredMethods":true, + "allDeclaredConstructors":true + }, + { + "name":"org.jvnet.hk2.internal.ProxyUtilities$4", + "allDeclaredFields":true, + "allDeclaredMethods":true, + "allDeclaredConstructors":true + }, + { + "name":"org.jvnet.hk2.internal.ProxyUtilities", + "allDeclaredFields":true, + "allDeclaredMethods":true, + "allDeclaredConstructors":true + }, + { + "name":"org.jvnet.hk2.internal.DynamicConfigurationServiceImpl", + "allDeclaredFields":true, + "allDeclaredMethods":true, + "allDeclaredConstructors":true + }, + { + "name":"org.jvnet.hk2.internal.ServiceLocatorRuntimeImpl", + "allDeclaredFields":true, + "allDeclaredMethods":true, + "allDeclaredConstructors":true + } +] diff --git a/core/src/main/resources/application-common.yml b/core/src/main/resources/application-common.yml index e36507a5..ab0d37db 100644 --- a/core/src/main/resources/application-common.yml +++ b/core/src/main/resources/application-common.yml @@ -3,6 +3,7 @@ spring: default: local mongodb: uri: + auto-index-creation: true data: redis: repositories: @@ -29,6 +30,12 @@ google: bundle-id: app-store-id: +oci: + email: + compartment-id: ocid1.compartment.oc1..aaaaaaaaxzo4fga6br76o3e34rshtsl6alzripmgdh7f4lg4u4tzezosypaq + vault: + secret-ids: ocid1.vaultsecret.oc1.ap-chuncheon-1.amaaaaaat2m5lbqahycrebaagkzrbtah3mvjtsyrhfw6aoeaarw4iansbkra + oidc: facebook: app-id: @@ -50,26 +57,24 @@ api: snuttev: base-url: http://snutt-ev-api-dev.wafflestudio.com -secret-names: dev/snutt-timetable - --- - spring: config: activate: on-profile: local logging: config: classpath:logback/local.xml +oci: + auth: + type: config --- - spring: config: activate: on-profile: dev mongodb: uri: - auto-index-creation: true data: redis: host: @@ -102,7 +107,6 @@ logging: org.springframework.data.mongodb.core.ReactiveMongoTemplate: DEBUG --- - spring: config: activate: @@ -136,4 +140,6 @@ api: base-url: http://snutt-ev.snutt-prod.svc.cluster.local read-timeout: 5000 -secret-names: prod/snutt-timetable +oci: + vault: + secret-ids: ocid1.vaultsecret.oc1.ap-chuncheon-1.amaaaaaat2m5lbqawhuzi5tw7l3zaqqmfqlorwfqi4kr3uhrlc6r2fio7a3a