Skip to content

Commit

Permalink
Merge branch 'main' into release
Browse files Browse the repository at this point in the history
  • Loading branch information
dojinyou authored Mar 3, 2024
2 parents c19ef3b + 40aeda5 commit 5a6aa3d
Show file tree
Hide file tree
Showing 54 changed files with 1,664 additions and 197 deletions.
6 changes: 6 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,16 @@ jobs:
# Gradle test를 실행
- name: Test with Gradle
run: ./gradlew clean testCoverage --no-daemon
env:
S3_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }}
S3_SECRET_KEY: ${{ secrets.S3_SECRET_KEY }}
S3_BUCKET: ${{ secrets.S3_TEST_BUCKET }}

# Report upload
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v3
with:
flags: '!**/s3/*'
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
file: ./build/reports/jacoco/test/jacocoTestReport.xml
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -175,3 +175,5 @@ gradle-app.setting
*.hprof

redis/

.run
6 changes: 6 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,18 @@ ARG PROFILE=prod
ARG DB_URL
ARG DB_USERNAME
ARG DB_PASSWORD
ARG S3_ACCESS_KEY
ARG S3_SECRET_KEY
ARG S3_BUCKET

COPY ${JAR_FILE} app.jar

ENV PROFILE=${PROFILE}
ENV DB_URL=${DB_URL}
ENV DB_USERNAME=${DB_USERNAME}
ENV DB_PASSWORD=${DB_PASSWORD}
ENV S3_ACCESS_KEY=${S3_ACCESS_KEY}
ENV S3_SECRET_KEY=${S3_SECRET_KEY}
ENV S3_BUCKET=${S3_BUCKET}

ENTRYPOINT ["java", "-jar", "-Dspring.profiles.active=${PROFILE}", "-Djava.security.egd=file:/dev/./urandom", "/app.jar"]
6 changes: 5 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ dependencies {
jooqGenerator("org.jooq:jooq-meta-extensions-liquibase")
jooqGenerator("org.liquibase:liquibase-core")

// aws
implementation("software.amazon.awssdk:s3:2.22.12")

// test
testImplementation("org.testcontainers:postgresql")
testImplementation("org.testcontainers:testcontainers:$testContainerVersion")
Expand Down Expand Up @@ -194,7 +197,8 @@ tasks.jacocoTestCoverageVerification {
"*.dto.*",
"com.mjucow.eatda.jooq.*",
"*.Companion",
"*.popularstore.*" // FIXME: redis 이슈 해결 후 제거'[
"*.s3.*",
"*.popularstore.*" // FIXME: redis 이슈 해결 후 제거
)
}
}
Expand Down
6 changes: 3 additions & 3 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ applicationVersion=0.1.8-RELEASE
### Project configs ###
projectGroup="com.mjucow"

### Project depdency versions ###
### Project dependency versions ###
kotlinVersion=1.9.10
javaVersion=17

### Plugin depdency versions ###
### Plugin dependency versions ###
asciidoctorConvertVersion=3.3.2
ktlintVersion=11.6.0
jacocoVersion=0.8.9
Expand All @@ -17,7 +17,7 @@ jacocoVersion=0.8.9
springBootVersion=3.1.6
springDependencyManagementVersion=1.1.3

### DB depedency versions ###
### DB dependency versions ###
jooqPluginVersion=8.2
jooqVersion="3.18.4"

Expand Down
29 changes: 29 additions & 0 deletions src/main/kotlin/com/mjucow/eatda/common/config/S3Config.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.mjucow.eatda.common.config

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
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials
import software.amazon.awssdk.regions.Region
import software.amazon.awssdk.services.s3.presigner.S3Presigner

@Configuration
@Profile("prod")
class S3Config(
@Value("\${aws.s3.credentials.access-key}")
private val accessKey: String,
@Value("\${aws.s3.credentials.secret-key}")
private val secretKey: String,
) {

@Bean
fun s3Presigner(): S3Presigner {
val credential = AwsBasicCredentials.create(accessKey, secretKey)

return S3Presigner.builder()
.region(Region.AP_NORTHEAST_2)
.credentialsProvider { credential }
.build()
}
}
20 changes: 20 additions & 0 deletions src/main/kotlin/com/mjucow/eatda/common/vo/Latitude.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.mjucow.eatda.common.vo

import com.fasterxml.jackson.annotation.JsonProperty

@JvmInline
value class Latitude(
@JsonProperty(value = "latitude")
val value: Double,
) {
init {
if (LATITUDE_MIN > value || LATITUDE_MAX < value) {
throw IllegalArgumentException()
}
}

companion object {
const val LATITUDE_MIN = 33.0
const val LATITUDE_MAX = 43.0
}
}
20 changes: 20 additions & 0 deletions src/main/kotlin/com/mjucow/eatda/common/vo/Longitude.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.mjucow.eatda.common.vo

import com.fasterxml.jackson.annotation.JsonProperty

@JvmInline
value class Longitude(
@JsonProperty(value = "longitude")
val value: Double,
) {
init {
if (LONGITUDE_MIN > value || LONGITUDE_MAX < value) {
throw IllegalArgumentException()
}
}

companion object {
const val LONGITUDE_MIN = 124.0
const val LONGITUDE_MAX = 132.0
}
}
8 changes: 2 additions & 6 deletions src/main/kotlin/com/mjucow/eatda/common/vo/Point.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,6 @@ import jakarta.persistence.Embeddable
example = """{"latitude": 37.5802219, "longitude": 126.9226047}"""
)
data class Point(

@Column(name = "location_latitude")
val latitude: Double,

@Column(name = "location_longitude")
val longitude: Double,
@Column(name = "location_latitude") val latitude: Latitude,
@Column(name = "location_longitude") val longitude: Longitude,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package com.mjucow.eatda.domain.curation.entity

import com.mjucow.eatda.domain.common.BaseEntity
import com.mjucow.eatda.domain.store.entity.Store
import jakarta.persistence.CascadeType
import jakarta.persistence.Column
import jakarta.persistence.Entity
import jakarta.persistence.FetchType
import jakarta.persistence.JoinColumn
import jakarta.persistence.JoinTable
import jakarta.persistence.ManyToMany
import jakarta.persistence.Table

@Entity
@Table(name = "curation")
class Curation() : BaseEntity() {
constructor(
title: String,
description: String,
imageAddress: String,
) : this() {
this.title = title
this.description = description
this.imageAddress = imageAddress
}

@Column(nullable = false)
var title: String = ""
set(value) {
validateTitle(value)
field = value
}

@Column(nullable = false)
var description: String = ""
set(value) {
validateDescription(value)
field = value
}

@Column(nullable = false)
var imageAddress: String = ""

@ManyToMany(fetch = FetchType.LAZY, cascade = [CascadeType.PERSIST, CascadeType.MERGE])
@JoinTable(
name = "curation_store",
joinColumns = [JoinColumn(name = "curation_id")],
inverseJoinColumns = [JoinColumn(name = "store_id")]
)
val mutableStores: MutableSet<Store> = mutableSetOf()

fun getStores(): Set<Store> = mutableStores.toSet()

fun addStore(store: Store) {
mutableStores.add(store)
}

private fun validateTitle(title: String) {
require(title.isNotBlank() && title.length <= MAX_TITLE_LENGTH)
}

private fun validateDescription(description: String) {
require(description.isNotBlank() && description.length <= MAX_DESCRIPTION_LENGTH)
}

companion object {
const val MAX_TITLE_LENGTH = 255
const val MAX_DESCRIPTION_LENGTH = 255
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.mjucow.eatda.domain.curation.service.command

import com.mjucow.eatda.domain.curation.entity.Curation
import com.mjucow.eatda.domain.curation.service.command.dto.AddStoreCommand
import com.mjucow.eatda.domain.curation.service.command.dto.CreateCurationCommand
import com.mjucow.eatda.domain.curation.service.command.dto.UpdateCurationCommand
import com.mjucow.eatda.persistence.curation.CurationRepository
import com.mjucow.eatda.persistence.store.StoreRepository
import org.springframework.data.repository.findByIdOrNull
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

@Service
@Transactional
class CurationCommandService(
private val repository: CurationRepository,
private val storeRepository: StoreRepository,

) {
fun create(command: CreateCurationCommand): Long {
return repository.save(Curation(command.title, command.description, command.imageAddress)).id
}

fun update(id: Long, command: UpdateCurationCommand) {
val (newTitle, newDescription, newImageAddress) = command
val updatedCuration = repository.getReferenceById(id).apply {
title = newTitle
description = newDescription
imageAddress = newImageAddress
}

repository.save(updatedCuration)
}

fun delete(id: Long) {
val curation = repository.findByIdOrNull(id) ?: return

repository.delete(curation)
}

fun addStore(id: Long, command: AddStoreCommand): Long {
val (storeId) = command
val curation = repository.getReferenceById(id)
val store = storeRepository.getReferenceById(storeId)

curation.addStore(store)

return repository.save(curation).id
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.mjucow.eatda.domain.curation.service.command.dto

import io.swagger.v3.oas.annotations.media.Schema

data class AddStoreCommand(
@Schema(name = "storeId", example = "1")
val storeId: Long,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.mjucow.eatda.domain.curation.service.command.dto

import io.swagger.v3.oas.annotations.media.Schema

data class CreateCurationCommand(
@Schema(name = "title", example = "큐레이션 제목")
val title: String,
@Schema(name = "description", example = "큐레이션 설명")
val description: String,
@Schema(name = "imageAddress", example = "store/232D8241-C6A9-4AD9-B0EA-56F6DD24BADF.png")
val imageAddress: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.mjucow.eatda.domain.curation.service.command.dto

import io.swagger.v3.oas.annotations.media.Schema

data class UpdateCurationCommand(
@Schema(name = "title", example = "수정할 큐레이션 제목")
val title: String,
@Schema(name = "description", example = "수정할 큐레이션 설명")
val description: String,
@Schema(name = "imageAddress", example = "store/232D8241-C6A9-4AD9-B0EA-56F6DD24BADF.png")
val imageAddress: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.mjucow.eatda.domain.curation.service.query

import com.mjucow.eatda.domain.curation.service.query.dto.CurationDto
import com.mjucow.eatda.domain.curation.service.query.dto.Curations
import com.mjucow.eatda.persistence.curation.CurationRepository
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

@Service
@Transactional(readOnly = true)
class CurationQueryService(
private val repository: CurationRepository,
) {
fun findAll(): Curations {
return Curations(repository.findAll().map(CurationDto::from))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.mjucow.eatda.domain.curation.service.query.dto

import com.fasterxml.jackson.annotation.JsonUnwrapped
import com.mjucow.eatda.domain.curation.entity.Curation
import com.mjucow.eatda.domain.store.service.query.dto.StoreDto
import com.mjucow.eatda.domain.store.service.query.dto.Stores
import io.swagger.v3.oas.annotations.media.Schema

data class CurationDto(
@Schema(name = "id", example = "1")
val id: Long,
@Schema(name = "title", example = "명지대 점심 특선")
val title: String,
@Schema(name = "description", example = "점심 특선 메뉴를 판매하는 음식점들이에요.")
val description: String,
@Schema(name = "imageAddress", example = "store/232D8241-C6A9-4AD9-B0EA-56F6DD24BADF.png")
val imageAddress: String,
@JsonUnwrapped val stores: Stores? = null,
) {

companion object {
fun from(domain: Curation): CurationDto {
return CurationDto(
id = domain.id,
title = domain.title,
description = domain.description,
imageAddress = domain.imageAddress,
stores = Stores(domain.getStores().map(StoreDto::from))
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.mjucow.eatda.domain.curation.service.query.dto

data class Curations(
val curationList: List<CurationDto>,
) : ArrayList<CurationDto>(curationList)
14 changes: 14 additions & 0 deletions src/main/kotlin/com/mjucow/eatda/domain/s3/dto/PresignedUrlDto.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.mjucow.eatda.domain.s3.dto

import java.net.URL

data class PresignedUrlDto(
val url: URL,
) {

companion object {
fun from(url: URL): PresignedUrlDto {
return PresignedUrlDto(url)
}
}
}
Loading

0 comments on commit 5a6aa3d

Please sign in to comment.