From 04c1b1646875bf14958fc25d0bebf37b2c115f44 Mon Sep 17 00:00:00 2001 From: Matt Wright Date: Fri, 8 Dec 2023 13:50:03 -0500 Subject: [PATCH] polish --- .vscode/settings.json | 5 -- .../JooqAppointmentAggregateRepository.kt | 8 +- .../data/JooqClientAggregateRepository.kt | 8 +- .../data/JooqPracticeAggregateRepository.kt | 8 +- .../JooqPractitionerAggregateRepository.kt | 8 +- acme-data/acme-data-sql/build.gradle.kts | 9 +- .../src/main/resources/db/changelog.yaml | 2 +- .../web-server/changelog.000001.sql | 86 ------------------- .../db/migrations/web/changelog.000001.sql | 86 +++++++++++++++++++ .../test/StandaloneAcmeWebServerExtension.kt | 12 +-- .../src/test/resources/application.conf | 2 +- .../ktor => }/AuthenticationConfiguration.kt | 4 +- .../ktor => }/DataSourceConfiguration.kt | 2 +- .../api/{core/ktor => }/KetoConfiguration.kt | 2 +- .../api/{core/ktor => }/MainConfiguration.kt | 2 +- .../kotlin/com/acme/web/api/core/ktor/auth.kt | 9 -- .../web/api/{core/ktor => }/errorhandlers.kt | 2 +- .../kotlin/com/acme/web/api/{core => }/etc.kt | 9 +- .../acme/web/api/{core/ktor => }/factory.kt | 3 +- .../com/acme/web/api/{core/ktor => }/json.kt | 3 +- .../acme/web/api/{core/ktor => }/plugins.kt | 2 +- .../scheduling/data/JooqSchedulingWebViews.kt | 29 ++++--- .../data/SchedulingWebViewService.kt | 39 --------- .../acme/web/api/scheduling/data/events.kt | 18 ++-- .../acme/web/api/scheduling/ktor/commands.kt | 4 +- .../acme/web/api/scheduling/ktor/module.kt | 8 +- .../acme/web/api/scheduling/ktor/queries.kt | 2 +- .../{ktor => }/HeaderAuthConfiguration.kt | 3 +- .../HeaderAuthenticationProvider.kt | 2 +- .../web/api/security/{ktor => }/Headers.kt | 2 +- .../KtorOryKetoAccessControlService.kt | 9 +- .../keto/{ktor => }/KtorOryKetoClient.kt | 7 +- .../api/security/keto/{ktor => }/defaults.kt | 2 +- .../acme/web/api/{core/ktor => }/static.kt | 2 +- ...estBodyValidationExceptionExtensionTest.kt | 1 + .../kotlin/com/acme/web/api/scheduling/etc.kt | 2 +- acme-web/acme-web-app/application.conf | 2 +- 37 files changed, 178 insertions(+), 226 deletions(-) delete mode 100644 .vscode/settings.json delete mode 100644 acme-data/acme-data-sql/src/main/resources/db/migrations/web-server/changelog.000001.sql create mode 100644 acme-data/acme-data-sql/src/main/resources/db/migrations/web/changelog.000001.sql rename acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/{core/ktor => }/AuthenticationConfiguration.kt (82%) rename acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/{core/ktor => }/DataSourceConfiguration.kt (92%) rename acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/{core/ktor => }/KetoConfiguration.kt (90%) rename acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/{core/ktor => }/MainConfiguration.kt (93%) delete mode 100644 acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/core/ktor/auth.kt rename acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/{core/ktor => }/errorhandlers.kt (98%) rename acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/{core => }/etc.kt (64%) rename acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/{core/ktor => }/factory.kt (95%) rename acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/{core/ktor => }/json.kt (96%) rename acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/{core/ktor => }/plugins.kt (99%) delete mode 100644 acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/scheduling/data/SchedulingWebViewService.kt rename acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/{ktor => }/HeaderAuthConfiguration.kt (93%) rename acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/{ktor => }/HeaderAuthenticationProvider.kt (97%) rename acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/{ktor => }/Headers.kt (88%) rename acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/{ktor => }/KtorOryKetoAccessControlService.kt (55%) rename acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/keto/{ktor => }/KtorOryKetoClient.kt (92%) rename acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/keto/{ktor => }/defaults.kt (95%) rename acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/{core/ktor => }/static.kt (90%) diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 2a2c421..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "yaml.schemas": { - "https://taskfile.dev/schema.json": "etc/tasks/*" - } -} diff --git a/acme-data/acme-data-scheduling/src/main/kotlin/com/acme/scheduling/data/JooqAppointmentAggregateRepository.kt b/acme-data/acme-data-scheduling/src/main/kotlin/com/acme/scheduling/data/JooqAppointmentAggregateRepository.kt index b43b4dd..8a2dafd 100644 --- a/acme-data/acme-data-scheduling/src/main/kotlin/com/acme/scheduling/data/JooqAppointmentAggregateRepository.kt +++ b/acme-data/acme-data-scheduling/src/main/kotlin/com/acme/scheduling/data/JooqAppointmentAggregateRepository.kt @@ -27,11 +27,11 @@ class JooqAppointmentAggregateRepository( .where(APPOINTMENTS.ID.eq(id.value)) .awaitFirstOrNull()?.let { PersistedAggregate( - aggregate = Json.decodeFromString(it.aggregate!!.data()), + aggregate = Json.decodeFromString(it.aggregate.data()), metaData = PersistenceMetaData( - createdAt = it.createdAt!!, - updatedAt = it.updatedAt!!, - revision = it.revision!!, + createdAt = it.createdAt, + updatedAt = it.updatedAt, + revision = it.revision, ) ) } diff --git a/acme-data/acme-data-scheduling/src/main/kotlin/com/acme/scheduling/data/JooqClientAggregateRepository.kt b/acme-data/acme-data-scheduling/src/main/kotlin/com/acme/scheduling/data/JooqClientAggregateRepository.kt index fe4a8a3..b19338f 100644 --- a/acme-data/acme-data-scheduling/src/main/kotlin/com/acme/scheduling/data/JooqClientAggregateRepository.kt +++ b/acme-data/acme-data-scheduling/src/main/kotlin/com/acme/scheduling/data/JooqClientAggregateRepository.kt @@ -25,11 +25,11 @@ class JooqClientAggregateRepository( .where(CLIENTS.ID.eq(id.value)) .awaitFirstOrNull()?.let { PersistedAggregate( - aggregate = Json.decodeFromString(it.aggregate!!.data()), + aggregate = Json.decodeFromString(it.aggregate.data()), metaData = PersistenceMetaData( - createdAt = it.createdAt!!, - updatedAt = it.updatedAt!!, - revision = it.revision!!, + createdAt = it.createdAt, + updatedAt = it.updatedAt, + revision = it.revision, ) ) } diff --git a/acme-data/acme-data-scheduling/src/main/kotlin/com/acme/scheduling/data/JooqPracticeAggregateRepository.kt b/acme-data/acme-data-scheduling/src/main/kotlin/com/acme/scheduling/data/JooqPracticeAggregateRepository.kt index 90a3f47..9d3f72b 100644 --- a/acme-data/acme-data-scheduling/src/main/kotlin/com/acme/scheduling/data/JooqPracticeAggregateRepository.kt +++ b/acme-data/acme-data-scheduling/src/main/kotlin/com/acme/scheduling/data/JooqPracticeAggregateRepository.kt @@ -25,11 +25,11 @@ class JooqPracticeAggregateRepository( .where(PRACTICES.ID.eq(id.value)) .awaitFirstOrNull()?.let { PersistedAggregate( - aggregate = Json.decodeFromString(it.aggregate!!.data()), + aggregate = Json.decodeFromString(it.aggregate.data()), metaData = PersistenceMetaData( - createdAt = it.createdAt!!, - updatedAt = it.updatedAt!!, - revision = it.revision!!, + createdAt = it.createdAt, + updatedAt = it.updatedAt, + revision = it.revision, ) ) } diff --git a/acme-data/acme-data-scheduling/src/main/kotlin/com/acme/scheduling/data/JooqPractitionerAggregateRepository.kt b/acme-data/acme-data-scheduling/src/main/kotlin/com/acme/scheduling/data/JooqPractitionerAggregateRepository.kt index fc22a7f..f0d3f15 100644 --- a/acme-data/acme-data-scheduling/src/main/kotlin/com/acme/scheduling/data/JooqPractitionerAggregateRepository.kt +++ b/acme-data/acme-data-scheduling/src/main/kotlin/com/acme/scheduling/data/JooqPractitionerAggregateRepository.kt @@ -25,11 +25,11 @@ class JooqPractitionerAggregateRepository( .where(PRACTITIONERS.ID.eq(id.value)) .awaitFirstOrNull()?.let { PersistedAggregate( - aggregate = Json.decodeFromString(it.aggregate!!.data()), + aggregate = Json.decodeFromString(it.aggregate.data()), metaData = PersistenceMetaData( - createdAt = it.createdAt!!, - updatedAt = it.updatedAt!!, - revision = it.revision!!, + createdAt = it.createdAt, + updatedAt = it.updatedAt, + revision = it.revision, ) ) } diff --git a/acme-data/acme-data-sql/build.gradle.kts b/acme-data/acme-data-sql/build.gradle.kts index 1807775..953e561 100644 --- a/acme-data/acme-data-sql/build.gradle.kts +++ b/acme-data/acme-data-sql/build.gradle.kts @@ -38,7 +38,7 @@ java { } jooq { - version.set("3.17.4") + version.set("3.18.4") edition.set(JooqEdition.OSS) configurations { create("main") { @@ -47,7 +47,7 @@ jooq { jdbc.apply { driver = "org.testcontainers.jdbc.ContainerDatabaseDriver" url = - "jdbc:tc:postgresql:11.5:///test?TC_INITFUNCTION=com.acme.liquibase.LiquibaseTestContainerInitializerKt::update" + "jdbc:tc:postgresql:15.5:///test?TC_INITFUNCTION=com.acme.liquibase.LiquibaseTestContainerInitializerKt::update" } generator.apply { name = "org.jooq.codegen.KotlinGenerator" @@ -59,6 +59,11 @@ jooq { target.apply { packageName = "com.acme.sql" } + generate.apply { + isKotlinNotNullPojoAttributes = true + isKotlinNotNullRecordAttributes = true + isKotlinNotNullInterfaceAttributes = true + } strategy.name = "org.jooq.codegen.DefaultGeneratorStrategy" } } diff --git a/acme-data/acme-data-sql/src/main/resources/db/changelog.yaml b/acme-data/acme-data-sql/src/main/resources/db/changelog.yaml index e20054c..e2315f4 100644 --- a/acme-data/acme-data-sql/src/main/resources/db/changelog.yaml +++ b/acme-data/acme-data-sql/src/main/resources/db/changelog.yaml @@ -6,5 +6,5 @@ databaseChangeLog: file: migrations/scheduling/changelog.000001.sql relativeToChangelogFile: true - include: - file: migrations/web-server/changelog.000001.sql + file: migrations/web/changelog.000001.sql relativeToChangelogFile: true diff --git a/acme-data/acme-data-sql/src/main/resources/db/migrations/web-server/changelog.000001.sql b/acme-data/acme-data-sql/src/main/resources/db/migrations/web-server/changelog.000001.sql deleted file mode 100644 index 69d1808..0000000 --- a/acme-data/acme-data-sql/src/main/resources/db/migrations/web-server/changelog.000001.sql +++ /dev/null @@ -1,86 +0,0 @@ ---liquibase formatted sql ---changeset author:mwright - -create schema web_server; - -create table web_server.practices -( - id text primary key, - name text -); - -create table web_server.practice_contact_points -( - practice_id text references web_server.practices(id), - system text, - value text, - verified_at timestamp -); - -create table web_server.practitioners -( - id text primary key, - gender text -); - -create table web_server.practitioner_names -( - practitioner_id text references web_server.practitioners(id), - given text, - family text, - prefix text, - suffix text, - period_start timestamp, - period_end timestamp -); - -create table web_server.practitioner_contact_points -( - practitioner_id text references web_server.practitioners(id), - system text, - value text, - verified_at timestamp -); - -create table web_server.practice_memberships -( - practice_id text references web_server.practices(id), - practitioner_id text references web_server.practitioners(id), - role text -); - -create table web_server.clients -( - id text primary key, - gender text -); - -create table web_server.client_names -( - client_id text references web_server.clients(id), - given text, - family text, - prefix text, - suffix text, - period_start timestamp, - period_end timestamp -); - -create table web_server.client_contact_points -( - client_id text references web_server.clients(id), - system text, - value text, - verified_at timestamp -); - -create table web_server.appointments -( - id text primary key, - practitioner_id text references web_server.practitioners(id), - client_id text references web_server.clients(id), - practice_id text references web_server.practices(id), - state varchar, - period_start timestamp, - period_end timestamp -); diff --git a/acme-data/acme-data-sql/src/main/resources/db/migrations/web/changelog.000001.sql b/acme-data/acme-data-sql/src/main/resources/db/migrations/web/changelog.000001.sql new file mode 100644 index 0000000..c7a8bc7 --- /dev/null +++ b/acme-data/acme-data-sql/src/main/resources/db/migrations/web/changelog.000001.sql @@ -0,0 +1,86 @@ +--liquibase formatted sql +--changeset author:mwright + +create schema web; + +create table web.practices +( + id text primary key, + name text not null +); + +create table web.practice_contact_points +( + practice_id text references web.practices(id), + system text not null, + value text not null, + verified_at timestamp +); + +create table web.practitioners +( + id text primary key, + gender text not null +); + +create table web.practitioner_names +( + practitioner_id text references web.practitioners(id), + given text not null, + family text not null, + prefix text not null, + suffix text not null, + period_start timestamp, + period_end timestamp +); + +create table web.practitioner_contact_points +( + practitioner_id text references web.practitioners(id), + system text not null, + value text not null, + verified_at timestamp +); + +create table web.practice_memberships +( + practice_id text references web.practices(id), + practitioner_id text references web.practitioners(id), + role text not null +); + +create table web.clients +( + id text primary key, + gender text not null +); + +create table web.client_names +( + client_id text references web.clients(id), + given text not null, + family text not null, + prefix text not null, + suffix text not null, + period_start timestamp, + period_end timestamp +); + +create table web.client_contact_points +( + client_id text references web.clients(id), + system text not null, + value text not null, + verified_at timestamp +); + +create table web.appointments +( + id text primary key, + practitioner_id text references web.practitioners(id), + client_id text references web.clients(id), + practice_id text references web.practices(id), + state varchar not null, + period_start timestamp not null, + period_end timestamp +); diff --git a/acme-web/acme-web-api-test/src/test/kotlin/com/acme/web/api/test/StandaloneAcmeWebServerExtension.kt b/acme-web/acme-web-api-test/src/test/kotlin/com/acme/web/api/test/StandaloneAcmeWebServerExtension.kt index fdf1d4a..7ec5ce3 100644 --- a/acme-web/acme-web-api-test/src/test/kotlin/com/acme/web/api/test/StandaloneAcmeWebServerExtension.kt +++ b/acme-web/acme-web-api-test/src/test/kotlin/com/acme/web/api/test/StandaloneAcmeWebServerExtension.kt @@ -1,12 +1,12 @@ package com.acme.web.api.test import com.acme.liquibase.update -import com.acme.web.api.core.ktor.AuthenticationConfiguration -import com.acme.web.api.core.ktor.DataSourceConfiguration -import com.acme.web.api.core.ktor.KetoConfiguration -import com.acme.web.api.core.ktor.MainConfiguration -import com.acme.web.api.core.ktor.main -import com.acme.web.api.security.ktor.HeaderAuthConfiguration +import com.acme.web.api.AuthenticationConfiguration +import com.acme.web.api.DataSourceConfiguration +import com.acme.web.api.KetoConfiguration +import com.acme.web.api.MainConfiguration +import com.acme.web.api.main +import com.acme.web.api.security.HeaderAuthConfiguration import com.zaxxer.hikari.HikariConfig import com.zaxxer.hikari.HikariDataSource import io.kotest.core.listeners.ProjectListener diff --git a/acme-web/acme-web-api-test/src/test/resources/application.conf b/acme-web/acme-web-api-test/src/test/resources/application.conf index 5d4815c..6337e1c 100644 --- a/acme-web/acme-web-api-test/src/test/resources/application.conf +++ b/acme-web/acme-web-api-test/src/test/resources/application.conf @@ -1,5 +1,5 @@ datasource { - jdbcUrl = "jdbc:tc:postgresql:11.5:///test?TC_INITFUNCTION=com.acme.liquibase.LiquibaseTestContainerInitializerKt::update" + jdbcUrl = "jdbc:tc:postgresql:15.5:///test?TC_INITFUNCTION=com.acme.liquibase.LiquibaseTestContainerInitializerKt::update" } diff --git a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/core/ktor/AuthenticationConfiguration.kt b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/AuthenticationConfiguration.kt similarity index 82% rename from acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/core/ktor/AuthenticationConfiguration.kt rename to acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/AuthenticationConfiguration.kt index 8fda3dc..3ae9c19 100644 --- a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/core/ktor/AuthenticationConfiguration.kt +++ b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/AuthenticationConfiguration.kt @@ -1,6 +1,6 @@ -package com.acme.web.api.core.ktor +package com.acme.web.api -import com.acme.web.api.security.ktor.HeaderAuthConfiguration +import com.acme.web.api.security.HeaderAuthConfiguration import io.ktor.server.auth.AuthenticationConfig import io.ktor.server.config.ApplicationConfig diff --git a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/core/ktor/DataSourceConfiguration.kt b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/DataSourceConfiguration.kt similarity index 92% rename from acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/core/ktor/DataSourceConfiguration.kt rename to acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/DataSourceConfiguration.kt index 4e7600a..3886941 100644 --- a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/core/ktor/DataSourceConfiguration.kt +++ b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/DataSourceConfiguration.kt @@ -1,4 +1,4 @@ -package com.acme.web.api.core.ktor +package com.acme.web.api import io.ktor.server.config.ApplicationConfig diff --git a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/core/ktor/KetoConfiguration.kt b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/KetoConfiguration.kt similarity index 90% rename from acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/core/ktor/KetoConfiguration.kt rename to acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/KetoConfiguration.kt index 7a8656f..8dee570 100644 --- a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/core/ktor/KetoConfiguration.kt +++ b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/KetoConfiguration.kt @@ -1,4 +1,4 @@ -package com.acme.web.api.core.ktor +package com.acme.web.api import io.ktor.server.config.ApplicationConfig diff --git a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/core/ktor/MainConfiguration.kt b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/MainConfiguration.kt similarity index 93% rename from acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/core/ktor/MainConfiguration.kt rename to acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/MainConfiguration.kt index f1a4f90..bf97299 100644 --- a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/core/ktor/MainConfiguration.kt +++ b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/MainConfiguration.kt @@ -1,4 +1,4 @@ -package com.acme.web.api.core.ktor +package com.acme.web.api import io.ktor.server.config.ApplicationConfig diff --git a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/core/ktor/auth.kt b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/core/ktor/auth.kt deleted file mode 100644 index c8b176d..0000000 --- a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/core/ktor/auth.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.acme.web.api.core.ktor - -import com.acme.web.api.security.AcmeWebUserPrincipal -import com.acme.web.api.security.PrincipalNotFoundException -import io.ktor.server.application.ApplicationCall -import io.ktor.server.auth.authentication - -fun ApplicationCall.authenticatedUser(): AcmeWebUserPrincipal = - authentication.principal() ?: throw PrincipalNotFoundException() diff --git a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/core/ktor/errorhandlers.kt b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/errorhandlers.kt similarity index 98% rename from acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/core/ktor/errorhandlers.kt rename to acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/errorhandlers.kt index d28d51a..76320a6 100644 --- a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/core/ktor/errorhandlers.kt +++ b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/errorhandlers.kt @@ -1,4 +1,4 @@ -package com.acme.web.api.core.ktor +package com.acme.web.api import com.acme.core.CommandValidationException import com.acme.ktor.server.logging.logger diff --git a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/core/etc.kt b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/etc.kt similarity index 64% rename from acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/core/etc.kt rename to acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/etc.kt index 7c479f0..81c8c26 100644 --- a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/core/etc.kt +++ b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/etc.kt @@ -1,13 +1,20 @@ @file:OptIn(ExperimentalSerializationApi::class) -package com.acme.web.api.core +package com.acme.web.api import am.ik.timeflake.Timeflake +import com.acme.web.api.security.AcmeWebUserPrincipal +import com.acme.web.api.security.PrincipalNotFoundException +import io.ktor.server.application.ApplicationCall +import io.ktor.server.auth.authentication import jakarta.validation.ElementKind import jakarta.validation.Path import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.json.Json +fun ApplicationCall.authenticatedUser(): AcmeWebUserPrincipal = + authentication.principal() ?: throw PrincipalNotFoundException() + val defaultIdGenerator: () -> String = { Timeflake.generate().base62() } val defaultJson = Json { diff --git a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/core/ktor/factory.kt b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/factory.kt similarity index 95% rename from acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/core/ktor/factory.kt rename to acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/factory.kt index 934e077..2c12291 100644 --- a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/core/ktor/factory.kt +++ b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/factory.kt @@ -1,7 +1,6 @@ -package com.acme.web.api.core.ktor +package com.acme.web.api import com.acme.ktor.server.logging.logger -import com.acme.web.api.core.defaultJson import com.acme.web.api.scheduling.ktor.scheduling import io.ktor.http.ContentType import io.ktor.server.application.Application diff --git a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/core/ktor/json.kt b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/json.kt similarity index 96% rename from acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/core/ktor/json.kt rename to acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/json.kt index 09cbc6a..9e678dd 100644 --- a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/core/ktor/json.kt +++ b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/json.kt @@ -1,7 +1,6 @@ -package com.acme.web.api.core.ktor +package com.acme.web.api import com.acme.ktor.server.validation.RequestBodyValidationException -import com.acme.web.api.core.toJsonPointer import com.acme.web.api.json.hal.VndError import io.ktor.http.ContentType import io.ktor.http.HttpStatusCode diff --git a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/core/ktor/plugins.kt b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/plugins.kt similarity index 99% rename from acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/core/ktor/plugins.kt rename to acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/plugins.kt index 69bb2a1..8ac874e 100644 --- a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/core/ktor/plugins.kt +++ b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/plugins.kt @@ -1,6 +1,6 @@ @file:OptIn(KtorExperimentalLocationsAPI::class) -package com.acme.web.api.core.ktor +package com.acme.web.api import com.acme.core.CommandValidationException import com.acme.ktor.server.i18n.I18N diff --git a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/scheduling/data/JooqSchedulingWebViews.kt b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/scheduling/data/JooqSchedulingWebViews.kt index 3ed0195..48ef22e 100644 --- a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/scheduling/data/JooqSchedulingWebViews.kt +++ b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/scheduling/data/JooqSchedulingWebViews.kt @@ -1,14 +1,14 @@ package com.acme.web.api.scheduling.data -import com.acme.sql.web_server.tables.references.APPOINTMENTS -import com.acme.sql.web_server.tables.references.CLIENTS -import com.acme.sql.web_server.tables.references.CLIENT_CONTACT_POINTS -import com.acme.sql.web_server.tables.references.CLIENT_NAMES -import com.acme.sql.web_server.tables.references.PRACTICES -import com.acme.sql.web_server.tables.references.PRACTICE_CONTACT_POINTS -import com.acme.sql.web_server.tables.references.PRACTITIONERS -import com.acme.sql.web_server.tables.references.PRACTITIONER_CONTACT_POINTS -import com.acme.sql.web_server.tables.references.PRACTITIONER_NAMES +import com.acme.sql.web.tables.references.APPOINTMENTS +import com.acme.sql.web.tables.references.CLIENTS +import com.acme.sql.web.tables.references.CLIENT_CONTACT_POINTS +import com.acme.sql.web.tables.references.CLIENT_NAMES +import com.acme.sql.web.tables.references.PRACTICES +import com.acme.sql.web.tables.references.PRACTICE_CONTACT_POINTS +import com.acme.sql.web.tables.references.PRACTITIONERS +import com.acme.sql.web.tables.references.PRACTITIONER_CONTACT_POINTS +import com.acme.sql.web.tables.references.PRACTITIONER_NAMES import kotlinx.coroutines.reactive.awaitFirstOrNull import org.jooq.Configuration import org.jooq.DSLContext @@ -70,7 +70,7 @@ class JooqSchedulingWebViews(private val dsl: DSLContext) : SchedulingWebViews { PracticeRecord( id = it[PRACTICES.ID]!!, name = it[PRACTICES.NAME]!!, - contactPoints = (it["contactPoints"] as List) + contactPoints = it[it.field3()] ) } @@ -121,8 +121,8 @@ class JooqSchedulingWebViews(private val dsl: DSLContext) : SchedulingWebViews { ClientRecord( id = it[CLIENTS.ID]!!, gender = it[CLIENTS.GENDER]!!, - names = (it["names"] as List), - contactPoints = (it["contactPoints"] as List) + names = it[it.field3()], + contactPoints = it[it.field4()] ) } @@ -170,11 +170,12 @@ class JooqSchedulingWebViews(private val dsl: DSLContext) : SchedulingWebViews { .from(PRACTITIONERS) .where(PRACTITIONERS.ID.eq(id)) .awaitFirstOrNull()?.let { + PractitionerRecord( id = it[PRACTITIONERS.ID]!!, gender = it[PRACTITIONERS.GENDER]!!, - names = it["names"] as List, - contactPoints = (it["contactPoints"] as List) + contactPoints = it[it.field3()], + names = it[it.field4()], ) } diff --git a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/scheduling/data/SchedulingWebViewService.kt b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/scheduling/data/SchedulingWebViewService.kt deleted file mode 100644 index 0018a78..0000000 --- a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/scheduling/data/SchedulingWebViewService.kt +++ /dev/null @@ -1,39 +0,0 @@ -package com.acme.web.api.scheduling.data - -import com.acme.scheduling.PractitionerCreatedEvent -import java.time.ZoneOffset - -interface SchedulingWebViewService { - fun insertPractitioner(event: PractitionerCreatedEvent) -} - -class InMemorySchedulingWebViewService( - private val practitioners: MutableMap = mutableMapOf() -) : SchedulingWebViewService { - - override fun insertPractitioner(event: PractitionerCreatedEvent) { - val id = event.practitioner.id.value - practitioners[id] = PractitionerRecord( - id = id, - names = event.practitioner.names.map { - val (start, end) = it.period.getTimeValues() - HumanNameRecord( - given = it.given.value, - family = it.family.value, - suffix = it.suffix.value, - prefix = it.prefix.value, - periodStart = start?.toInstant(ZoneOffset.UTC), - periodEnd = end?.toInstant(ZoneOffset.UTC) - ) - }, - gender = event.practitioner.gender.name, - contactPoints = event.practitioner.contactPoints.map { - ContactPointRecord( - value = it.value, - system = it.toSystemString(), - verifiedAt = it.getVerifiedAtValue()?.toInstant(ZoneOffset.UTC) - ) - } - ) - } -} diff --git a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/scheduling/data/events.kt b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/scheduling/data/events.kt index b869d4b..4d302f3 100644 --- a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/scheduling/data/events.kt +++ b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/scheduling/data/events.kt @@ -12,15 +12,15 @@ import com.acme.scheduling.Period import com.acme.scheduling.PracticeCreatedEvent import com.acme.scheduling.PractitionerCreatedEvent import com.acme.scheduling.data.SchedulingJooqUnitOfWork -import com.acme.sql.web_server.tables.references.APPOINTMENTS -import com.acme.sql.web_server.tables.references.CLIENTS -import com.acme.sql.web_server.tables.references.CLIENT_CONTACT_POINTS -import com.acme.sql.web_server.tables.references.CLIENT_NAMES -import com.acme.sql.web_server.tables.references.PRACTICES -import com.acme.sql.web_server.tables.references.PRACTICE_CONTACT_POINTS -import com.acme.sql.web_server.tables.references.PRACTITIONERS -import com.acme.sql.web_server.tables.references.PRACTITIONER_CONTACT_POINTS -import com.acme.sql.web_server.tables.references.PRACTITIONER_NAMES +import com.acme.sql.web.tables.references.APPOINTMENTS +import com.acme.sql.web.tables.references.CLIENTS +import com.acme.sql.web.tables.references.CLIENT_CONTACT_POINTS +import com.acme.sql.web.tables.references.CLIENT_NAMES +import com.acme.sql.web.tables.references.PRACTICES +import com.acme.sql.web.tables.references.PRACTICE_CONTACT_POINTS +import com.acme.sql.web.tables.references.PRACTITIONERS +import com.acme.sql.web.tables.references.PRACTITIONER_CONTACT_POINTS +import com.acme.sql.web.tables.references.PRACTITIONER_NAMES import kotlinx.coroutines.reactive.awaitFirst import java.time.LocalDateTime diff --git a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/scheduling/ktor/commands.kt b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/scheduling/ktor/commands.kt index 0eeb185..8d00425 100644 --- a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/scheduling/ktor/commands.kt +++ b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/scheduling/ktor/commands.kt @@ -7,8 +7,8 @@ import com.acme.scheduling.CancelAppointmentCommand import com.acme.scheduling.MarkAppointmentAttendedCommand import com.acme.scheduling.MarkAppointmentUnattendedCommand import com.acme.scheduling.SchedulingUnitOfWork -import com.acme.web.api.core.defaultIdGenerator -import com.acme.web.api.core.ktor.authenticatedUser +import com.acme.web.api.authenticatedUser +import com.acme.web.api.defaultIdGenerator import com.acme.web.api.scheduling.CreateAppointmentCommandRequest import com.acme.web.api.scheduling.CreateClientCommandRequest import com.acme.web.api.scheduling.CreatePracticeCommandRequest diff --git a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/scheduling/ktor/module.kt b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/scheduling/ktor/module.kt index f97276f..3f00e26 100644 --- a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/scheduling/ktor/module.kt +++ b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/scheduling/ktor/module.kt @@ -3,13 +3,13 @@ package com.acme.web.api.scheduling.ktor import com.acme.scheduling.data.SchedulingJooqUnitOfWork -import com.acme.web.api.core.ktor.KetoConfiguration +import com.acme.web.api.KetoConfiguration import com.acme.web.api.scheduling.data.JooqSchedulingWebViews import com.acme.web.api.scheduling.schedulingMessageBus import com.acme.web.api.security.AccessControlService -import com.acme.web.api.security.keto.ktor.KtorOryKetoClient -import com.acme.web.api.security.keto.ktor.defaultOryKetoClientConfiguration -import com.acme.web.api.security.ktor.KtorOryKetoAccessControlService +import com.acme.web.api.security.KtorOryKetoAccessControlService +import com.acme.web.api.security.keto.KtorOryKetoClient +import com.acme.web.api.security.keto.defaultOryKetoClientConfiguration import io.ktor.client.HttpClient import io.ktor.server.auth.authenticate import io.ktor.server.locations.KtorExperimentalLocationsAPI diff --git a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/scheduling/ktor/queries.kt b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/scheduling/ktor/queries.kt index b25d444..cc2c78c 100644 --- a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/scheduling/ktor/queries.kt +++ b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/scheduling/ktor/queries.kt @@ -2,7 +2,7 @@ package com.acme.web.api.scheduling.ktor -import com.acme.web.api.core.ktor.authenticatedUser +import com.acme.web.api.authenticatedUser import com.acme.web.api.json.hal.HalLink import com.acme.web.api.scheduling.data.SchedulingWebViews import com.acme.web.api.scheduling.json.AppointmentResource diff --git a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/ktor/HeaderAuthConfiguration.kt b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/HeaderAuthConfiguration.kt similarity index 93% rename from acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/ktor/HeaderAuthConfiguration.kt rename to acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/HeaderAuthConfiguration.kt index d07198b..26f85bf 100644 --- a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/ktor/HeaderAuthConfiguration.kt +++ b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/HeaderAuthConfiguration.kt @@ -1,6 +1,5 @@ -package com.acme.web.api.security.ktor +package com.acme.web.api.security -import com.acme.web.api.security.AcmeWebUserPrincipal import io.ktor.server.auth.AuthenticationConfig import io.ktor.server.auth.Principal import io.ktor.server.config.ApplicationConfig diff --git a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/ktor/HeaderAuthenticationProvider.kt b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/HeaderAuthenticationProvider.kt similarity index 97% rename from acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/ktor/HeaderAuthenticationProvider.kt rename to acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/HeaderAuthenticationProvider.kt index a3b7a6a..8352207 100644 --- a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/ktor/HeaderAuthenticationProvider.kt +++ b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/HeaderAuthenticationProvider.kt @@ -1,4 +1,4 @@ -package com.acme.web.api.security.ktor +package com.acme.web.api.security import io.ktor.server.application.ApplicationCall import io.ktor.server.auth.AuthenticationContext diff --git a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/ktor/Headers.kt b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/Headers.kt similarity index 88% rename from acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/ktor/Headers.kt rename to acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/Headers.kt index 7c50877..5e5b3fe 100644 --- a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/ktor/Headers.kt +++ b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/Headers.kt @@ -1,4 +1,4 @@ -package com.acme.web.api.security.ktor +package com.acme.web.api.security import io.ktor.server.auth.AuthenticationConfig diff --git a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/ktor/KtorOryKetoAccessControlService.kt b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/KtorOryKetoAccessControlService.kt similarity index 55% rename from acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/ktor/KtorOryKetoAccessControlService.kt rename to acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/KtorOryKetoAccessControlService.kt index 43af1ff..5e60736 100644 --- a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/ktor/KtorOryKetoAccessControlService.kt +++ b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/KtorOryKetoAccessControlService.kt @@ -1,10 +1,9 @@ -package com.acme.web.api.security.ktor +package com.acme.web.api.security -import com.acme.web.api.security.OryKetoAccessControlService +import com.acme.web.api.security.keto.KtorOryKetoClient import com.acme.web.api.security.keto.OryKetoClient -import com.acme.web.api.security.keto.ktor.KtorOryKetoClient -import com.acme.web.api.security.keto.ktor.defaultOryKetoReadClient -import com.acme.web.api.security.keto.ktor.defaultOryKetoWriteClient +import com.acme.web.api.security.keto.defaultOryKetoReadClient +import com.acme.web.api.security.keto.defaultOryKetoWriteClient class KtorOryKetoAccessControlService(namespace: String, client: OryKetoClient) : OryKetoAccessControlService(namespace, client) { diff --git a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/keto/ktor/KtorOryKetoClient.kt b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/keto/KtorOryKetoClient.kt similarity index 92% rename from acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/keto/ktor/KtorOryKetoClient.kt rename to acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/keto/KtorOryKetoClient.kt index a49f2e9..d0b2be3 100644 --- a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/keto/ktor/KtorOryKetoClient.kt +++ b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/keto/KtorOryKetoClient.kt @@ -1,13 +1,8 @@ -package com.acme.web.api.security.keto.ktor +package com.acme.web.api.security.keto -import com.acme.web.api.security.keto.CheckResponse -import com.acme.web.api.security.keto.ExpandTree -import com.acme.web.api.security.keto.OryKetoClient import com.acme.web.api.security.keto.OryKetoClient.Companion.CHECK_URL import com.acme.web.api.security.keto.OryKetoClient.Companion.EXPAND_URL import com.acme.web.api.security.keto.OryKetoClient.Companion.TUPLES_COLLECTION_URL -import com.acme.web.api.security.keto.RelationTuple -import com.acme.web.api.security.keto.RelationTuplesCollection import io.ktor.client.HttpClient import io.ktor.client.call.body import io.ktor.client.request.delete diff --git a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/keto/ktor/defaults.kt b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/keto/defaults.kt similarity index 95% rename from acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/keto/ktor/defaults.kt rename to acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/keto/defaults.kt index e3faaae..a5023e6 100644 --- a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/keto/ktor/defaults.kt +++ b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/security/keto/defaults.kt @@ -1,6 +1,6 @@ @file:OptIn(ExperimentalSerializationApi::class) -package com.acme.web.api.security.keto.ktor +package com.acme.web.api.security.keto import io.ktor.client.HttpClient import io.ktor.client.HttpClientConfig diff --git a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/core/ktor/static.kt b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/static.kt similarity index 90% rename from acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/core/ktor/static.kt rename to acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/static.kt index 0144622..6c80d05 100644 --- a/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/core/ktor/static.kt +++ b/acme-web/acme-web-api/src/main/kotlin/com/acme/web/api/static.kt @@ -1,4 +1,4 @@ -package com.acme.web.api.core.ktor +package com.acme.web.api import io.ktor.server.http.content.defaultResource import io.ktor.server.http.content.resources diff --git a/acme-web/acme-web-api/src/test/kotlin/com/acme/web/api/core/ktor/RequestBodyValidationExceptionExtensionTest.kt b/acme-web/acme-web-api/src/test/kotlin/com/acme/web/api/core/ktor/RequestBodyValidationExceptionExtensionTest.kt index d4ecde2..23b92f5 100644 --- a/acme-web/acme-web-api/src/test/kotlin/com/acme/web/api/core/ktor/RequestBodyValidationExceptionExtensionTest.kt +++ b/acme-web/acme-web-api/src/test/kotlin/com/acme/web/api/core/ktor/RequestBodyValidationExceptionExtensionTest.kt @@ -3,6 +3,7 @@ package com.acme.web.api.core.ktor import com.acme.ktor.server.validation.RequestBodyValidationException import com.acme.web.api.json.hal.VndError import com.acme.web.api.scheduling.constraintValidator +import com.acme.web.api.toVndError import io.kotest.core.spec.style.ShouldSpec import io.kotest.matchers.shouldBe import jakarta.validation.constraints.NotBlank diff --git a/acme-web/acme-web-api/src/test/kotlin/com/acme/web/api/scheduling/etc.kt b/acme-web/acme-web-api/src/test/kotlin/com/acme/web/api/scheduling/etc.kt index bc1f7bd..b5e1702 100644 --- a/acme-web/acme-web-api/src/test/kotlin/com/acme/web/api/scheduling/etc.kt +++ b/acme-web/acme-web-api/src/test/kotlin/com/acme/web/api/scheduling/etc.kt @@ -1,6 +1,6 @@ package com.acme.web.api.scheduling -import com.acme.web.api.core.toJsonPointer +import com.acme.web.api.toJsonPointer import io.kotest.core.Tag import jakarta.validation.ConstraintViolation import jakarta.validation.Validation diff --git a/acme-web/acme-web-app/application.conf b/acme-web/acme-web-app/application.conf index 3563a81..cd60cd2 100644 --- a/acme-web/acme-web-app/application.conf +++ b/acme-web/acme-web-app/application.conf @@ -3,5 +3,5 @@ ktor { } datasource { - jdbcUrl = "jdbc:tc:postgresql:11.5:///acme?TC_INITFUNCTION=com.acme.liquibase.LiquibaseTestContainerInitializerKt::update" + jdbcUrl = "jdbc:tc:postgresql:15.5:///acme?TC_INITFUNCTION=com.acme.liquibase.LiquibaseTestContainerInitializerKt::update" }