Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ variables:
value: postgres:15.15-alpine
description: Image de la base de données
PROJECT_VERSION:
value: 2.53.1
value: 2.53.1-rc1
description: Version du projet à déployer
SERVER_ENV_INT:
value: int-rapportnav-appli01
Expand Down
55 changes: 27 additions & 28 deletions backend/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import java.lang.System.getenv

group = "fr.gouv.dgampa"
// x-release-please-start-version
version = "2.53.1"
version = "2.53.1-rc1"
// x-release-please-end
description = "RapportNav"

val kotlinVersion by extra("2.3.0")
val serializationVersion by extra("1.6.2")
val springVersion by extra("3.5.9")
val springVersion by extra("4.0.1")
val testcontainersVersion by extra("1.19.3")
val flywayVersion by extra("11.20.0")

Expand All @@ -20,10 +20,11 @@ plugins {
kotlin("jvm") version "2.3.0"
kotlin("plugin.spring") version "2.3.0"
kotlin("plugin.jpa") version "2.3.0"
id("org.springframework.boot") version "3.5.9"
id("io.spring.dependency-management") version "1.1.4"
id("org.springframework.boot") version "4.0.1"
id("io.spring.dependency-management") version "1.1.7"
id("org.owasp.dependencycheck") version "12.1.0"
id("org.flywaydb.flyway") version "11.20.0"
// id("io.sentry.jvm.gradle") version "5.12.2"
jacoco
}

Expand Down Expand Up @@ -60,45 +61,43 @@ dependencyManagement {
dependencies {
developmentOnly("org.springframework.boot:spring-boot-devtools")
implementation("org.postgresql:postgresql:42.7.8")
implementation("org.springframework.boot:spring-boot-starter-data-jpa:$springVersion")
implementation("org.springframework.boot:spring-boot-starter-data-rest:$springVersion")
implementation("org.springframework.boot:spring-boot-starter-web:$springVersion")
implementation("org.springframework.boot:spring-boot-starter-graphql:$springVersion")
implementation("org.springframework.boot:spring-boot-autoconfigure:$springVersion")
implementation("org.springframework.boot:spring-boot-starter-log4j2:$springVersion")
implementation("org.springframework.boot:spring-boot-starter-security:$springVersion")
implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server:$springVersion")
implementation("org.springframework.boot:spring-boot-starter-cache:$springVersion")
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-data-rest")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-graphql")
implementation("org.springframework.boot:spring-boot-starter-log4j2")
implementation("org.springframework.boot:spring-boot-starter-security")
implementation("org.springframework.boot:spring-boot-starter-security-oauth2-resource-server")
implementation("org.springframework.boot:spring-boot-starter-cache")
implementation("com.github.ben-manes.caffeine:caffeine:3.2.3")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib")
implementation("org.flywaydb:flyway-core:$flywayVersion")
implementation("org.flywaydb:flyway-database-postgresql:$flywayVersion")
implementation("org.n52.jackson:jackson-datatype-jts:1.2.10") {
exclude(group = "org.locationtech.jts", module = "jts-core")
}
implementation("tools.jackson.module:jackson-module-kotlin")
implementation("io.jsonwebtoken:jjwt-api:0.12.7")
implementation("javax.xml.bind:jaxb-api:2.3.1")
implementation("org.springframework.security:spring-security-oauth2-jose:6.5.7")
implementation("jakarta.xml.bind:jakarta.xml.bind-api")
implementation("org.locationtech.jts:jts-core:1.20.0")
implementation("io.sentry:sentry-spring-boot-starter-jakarta:7.1.0")
implementation("io.sentry:sentry-log4j2:7.0.0")
// the two following apoche poi dependencies should have the same version
implementation("org.locationtech.jts.io:jts-io-common:1.20.0")
// sentry
implementation(platform("io.sentry:sentry-bom:8.29.0"))
implementation("io.sentry:sentry-spring-boot-4")
// apache poi for xml and docs
// the two following apache poi dependencies should have the same version
implementation("org.apache.poi:poi:5.4.1")
implementation("org.apache.poi:poi-ooxml:5.4.1")
implementation("org.apache.commons:commons-text:1.14.0")
implementation("org.jodconverter:jodconverter-local-lo:4.4.11")
implementation("com.neovisionaries:nv-i18n:1.29")
implementation("org.wiremock:wiremock-standalone:4.0.0-beta.15")
implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.9")
testImplementation("org.springframework.boot:spring-boot-starter-test:$springVersion")
testImplementation("org.springframework:spring-webflux:6.2.12")
testImplementation("org.springframework.graphql:spring-graphql-test:1.4.3")
implementation("org.wiremock:wiremock-standalone:4.0.0-beta.24")
implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:3.0.1")
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.springframework.boot:spring-boot-starter-webmvc-test")
testImplementation("org.springframework.boot:spring-boot-starter-jackson-test")
testImplementation("org.springframework.security:spring-security-test")
testImplementation("org.testcontainers:testcontainers")
testImplementation("org.testcontainers:junit-jupiter")
testImplementation("org.testcontainers:postgresql")
testImplementation("org.springframework.security:spring-security-test:6.5.6")
testImplementation("org.mockito.kotlin:mockito-kotlin:5.4.0")
}

Expand Down
2 changes: 1 addition & 1 deletion backend/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,12 @@ package fr.gouv.dgampa.rapportnav

import com.github.tomakehurst.wiremock.WireMockServer
import fr.gouv.dgampa.rapportnav.config.WireMockConfig
import io.sentry.Sentry
import io.sentry.SentryOptions
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
import org.springframework.boot.runApplication
import org.springframework.cache.annotation.EnableCaching


@SpringBootApplication(exclude = [SecurityAutoConfiguration::class])
@SpringBootApplication
@EnableCaching
open class RapportNavApplication

Expand All @@ -30,20 +27,4 @@ fun main(args: Array<String>) {
println("WireMock server stopped")
})
}

val isSentryEnabled: String? = ctx.environment.getProperty("sentry.enabled")
val sentryDsn: String? = System.getenv("SENTRY_DSN")

if (isSentryEnabled == "true") {
Sentry.init { options ->
options.environment = System.getenv("ENV_PROFILE")
options.dsn = sentryDsn
options.proxy = SentryOptions.Proxy(
System.getenv("PROXY_HOST"),
System.getenv("PROXY_PORT"),
)
options.tracesSampleRate = 1.0
}
}

Comment on lines -33 to -48
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

J'ai viré ce code là.
Il suffit de mettre ces propriétés dans application-propertioes.yml et ca s'occupe de tout tout seul

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package fr.gouv.dgampa.rapportnav.config

import com.fasterxml.jackson.databind.ObjectMapper
import fr.gouv.dgampa.rapportnav.domain.use_cases.apikey.RateLimitException
import fr.gouv.dgampa.rapportnav.domain.use_cases.apikey.ValidateApiKey
import jakarta.servlet.FilterChain
Expand All @@ -14,12 +13,13 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.stereotype.Component
import org.springframework.web.filter.OncePerRequestFilter
import tools.jackson.databind.json.JsonMapper
import java.time.Instant

@Component
class ApiKeyAuthenticationFilter(
private val validateApiKey: ValidateApiKey,
private val objectMapper: ObjectMapper
private val objectMapper: JsonMapper
) : OncePerRequestFilter() {

private val logger = LoggerFactory.getLogger(ApiKeyAuthenticationFilter::class.java)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,44 +1,27 @@
package fr.gouv.dgampa.rapportnav.config

import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.PropertyNamingStrategies
import com.fasterxml.jackson.databind.SerializationFeature
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
import com.fasterxml.jackson.module.kotlin.KotlinModule
import org.n52.jackson.datatype.jts.JtsModule
import org.springframework.boot.jackson.autoconfigure.JsonMapperBuilderCustomizer
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Primary
import tools.jackson.databind.DeserializationFeature
import tools.jackson.databind.PropertyNamingStrategies
import tools.jackson.databind.cfg.DateTimeFeature
import tools.jackson.module.kotlin.KotlinModule

@Configuration
class JacksonConfig {

@Bean
@Primary
fun objectMapper(): ObjectMapper {
return ObjectMapper().apply {
// Register Kotlin module for better Kotlin support
registerModule(KotlinModule.Builder().build())

// Register JavaTimeModule for Java 8 date/time types
// This handles Instant, ZonedDateTime, LocalDate automatically
registerModule(JavaTimeModule())

// Register JTS module for geometry types
registerModule(JtsModule())

// Configure to serialize dates as ISO-8601 strings (not timestamps)
disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)

// Don't throw on unrecognised fields
// Very common for us as we're not always notified by the Monitor apps about changes in their modelds
disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
@Bean
fun jsonMapperBuilderCustomizer(): JsonMapperBuilderCustomizer {
return JsonMapperBuilderCustomizer { builder ->
builder.addModule(KotlinModule.Builder().build())

// Include null values in serialization (equivalent to gson.serializeNulls())
setSerializationInclusion(com.fasterxml.jackson.annotation.JsonInclude.Include.ALWAYS)
builder.disable(DateTimeFeature.WRITE_DATES_AS_TIMESTAMPS)
builder.disable(DateTimeFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE)
builder.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)

propertyNamingStrategy = PropertyNamingStrategies.LOWER_CAMEL_CASE
builder.propertyNamingStrategy(PropertyNamingStrategies.LOWER_CAMEL_CASE)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package fr.gouv.dgampa.rapportnav.config

import org.locationtech.jts.geom.Geometry
import org.locationtech.jts.geom.GeometryFactory
import org.locationtech.jts.geom.MultiPolygon
import org.locationtech.jts.geom.Polygon
import org.locationtech.jts.io.ParseException
import org.locationtech.jts.io.geojson.GeoJsonReader
import org.locationtech.jts.io.geojson.GeoJsonWriter
import tools.jackson.core.JsonGenerator
import tools.jackson.core.JsonParser
import tools.jackson.core.JsonToken
import tools.jackson.databind.DeserializationContext
import tools.jackson.databind.JsonNode
import tools.jackson.databind.SerializationContext
import tools.jackson.databind.deser.std.StdDeserializer
import tools.jackson.databind.ser.std.StdSerializer
import java.io.IOException

class JtsGeometryDeserializer(
private val reader: GeoJsonReader = GeoJsonReader()
) : StdDeserializer<Geometry>(Geometry::class.java) {

override fun deserialize(p: JsonParser, ctxt: DeserializationContext): Geometry {
val geoJson: String = when (p.currentToken()) {
JsonToken.VALUE_STRING -> p.text
else -> (p.readValueAsTree<JsonNode>()).toString() // <-- no codec needed
}

try {
return reader.read(geoJson)
} catch (e: ParseException) {
throw IOException("Invalid GeoJSON Geometry", e)
}
}
}

class JtsGeometrySerializer(
private val writer: GeoJsonWriter = GeoJsonWriter()
) : StdSerializer<Geometry>(Geometry::class.java) {

override fun serialize(
value: Geometry?,
gen: JsonGenerator?,
provider: SerializationContext?
) {
gen?.writeRawValue(writer.write(value))
}
}

class JtsMultiPolygonDeserializer(
private val reader: GeoJsonReader = GeoJsonReader(),
private val gf: GeometryFactory = GeometryFactory()
) : StdDeserializer<MultiPolygon>(MultiPolygon::class.java) {

override fun deserialize(p: JsonParser, ctxt: DeserializationContext): MultiPolygon {
val geoJson: String = when (p.currentToken()) {
JsonToken.VALUE_STRING -> p.text
else -> p.readValueAsTree<JsonNode>().toString()
}

val g: Geometry = try {
reader.read(geoJson) // returns a JTS Geometry
} catch (e: ParseException) {
throw IOException("Invalid GeoJSON geometry", e)
}

return when (g) {
is MultiPolygon -> g
is Polygon -> gf.createMultiPolygon(arrayOf(g)) // promote Polygon -> MultiPolygon
else -> throw IOException("Expected Polygon or MultiPolygon but got ${g.geometryType}")
}
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
package fr.gouv.dgampa.rapportnav.domain.entities.mission.env.envActions

import com.fasterxml.jackson.annotation.JsonProperty
import fr.gouv.dgampa.rapportnav.config.JtsGeometryDeserializer
import fr.gouv.dgampa.rapportnav.config.JtsGeometrySerializer
import fr.gouv.dgampa.rapportnav.domain.entities.mission.env.ActionCompletionEnum
import fr.gouv.dgampa.rapportnav.domain.entities.mission.env.tags.TagEntity
import fr.gouv.dgampa.rapportnav.domain.entities.mission.env.themes.ThemeEntity
import org.locationtech.jts.geom.Geometry
import tools.jackson.databind.annotation.JsonDeserialize
import tools.jackson.databind.annotation.JsonSerialize
import java.time.Instant
import java.util.*

Expand All @@ -14,6 +19,9 @@ data class EnvActionControlEntity(
override val completedBy: String? = null,
override val completion: ActionCompletionEnum? = null,
override val controlPlans: List<EnvActionControlPlanEntity>? = listOf(),
@param:JsonProperty("geom")
@param:JsonDeserialize(using = JtsGeometryDeserializer::class)
@get:JsonSerialize(using = JtsGeometrySerializer::class)
override val geom: Geometry? = null,
override val facade: String? = null,
override val department: String? = null,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package fr.gouv.dgampa.rapportnav.domain.entities.mission.env.envActions

import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.annotation.JsonSubTypes
import com.fasterxml.jackson.annotation.JsonTypeInfo
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
import fr.gouv.dgampa.rapportnav.config.JtsGeometryDeserializer
import fr.gouv.dgampa.rapportnav.config.JtsGeometrySerializer
import fr.gouv.dgampa.rapportnav.domain.entities.mission.env.ActionCompletionEnum
import fr.gouv.dgampa.rapportnav.domain.entities.mission.env.tags.TagEntity
import fr.gouv.dgampa.rapportnav.domain.entities.mission.env.themes.ThemeEntity
import org.locationtech.jts.geom.Geometry
import org.n52.jackson.datatype.jts.GeometryDeserializer
import tools.jackson.databind.annotation.JsonDeserialize
import tools.jackson.databind.annotation.JsonSerialize
import java.time.Instant
import java.util.*

Expand All @@ -32,7 +35,10 @@ abstract class EnvActionEntity(
open val completedBy: String? = null,
open val completion: ActionCompletionEnum? = null,
open val controlPlans: List<EnvActionControlPlanEntity>? = listOf(),
@field:JsonDeserialize(using = GeometryDeserializer::class) open val geom: Geometry? = null,
@param:JsonProperty("geom")
@param:JsonDeserialize(using = JtsGeometryDeserializer::class)
@get:JsonSerialize(using = JtsGeometrySerializer::class)
open val geom: Geometry? = null,
Comment on lines +38 to +41
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Faut répéter ça partout pour ce champ maintenant, il faut spécifier quels serializer/deserializer et dans le cas de Geometry, voilà lesquels il faut utiliser

open val isAdministrativeControl: Boolean? = null,
open val isComplianceWithWaterRegulationsControl: Boolean? = null,
open val isSafetyEquipmentAndStandardsComplianceControl: Boolean? = null,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
package fr.gouv.dgampa.rapportnav.domain.entities.mission.env.envActions

import com.fasterxml.jackson.annotation.JsonProperty
import fr.gouv.dgampa.rapportnav.config.JtsGeometrySerializer
import fr.gouv.dgampa.rapportnav.config.JtsMultiPolygonDeserializer
import fr.gouv.dgampa.rapportnav.domain.entities.mission.env.ActionCompletionEnum
import fr.gouv.dgampa.rapportnav.domain.entities.mission.env.tags.TagEntity
import fr.gouv.dgampa.rapportnav.domain.entities.mission.env.themes.ThemeEntity
import org.locationtech.jts.geom.Geometry
import tools.jackson.databind.annotation.JsonDeserialize
import tools.jackson.databind.annotation.JsonSerialize
import java.time.Instant
import java.util.*

data class EnvActionSurveillanceEntity(
override val id: UUID,
override val actionStartDateTimeUtc: Instant? = null,
override val actionEndDateTimeUtc: Instant? = null,
@param:JsonProperty("geom")
@param:JsonDeserialize(using = JtsMultiPolygonDeserializer::class)
@get:JsonSerialize(using = JtsGeometrySerializer::class)
Comment on lines +19 to +21
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mais parfois, c'est des MultiPolygon donc le deserializer en MultiPolygon mais le serializewr en Geometry, c'est suffisant

override val geom: Geometry? = null,
override val facade: String? = null,
override val department: String? = null,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package fr.gouv.dgampa.rapportnav.domain.entities.user

import com.fasterxml.jackson.databind.ObjectMapper
import fr.gouv.dgampa.rapportnav.infrastructure.database.model.user.UserModel
import java.time.Instant

Expand Down
Loading
Loading