diff --git a/README.md b/README.md index daacef6..e5e38df 100644 --- a/README.md +++ b/README.md @@ -42,15 +42,15 @@ Your domain on the other hand will always be there. should be modified following strong consistency principle (oppose to domain events and eventual consistency for cross aggregation root changes). - +## Use cases +### 1. Communication between layers +On this demo we'll try to execute a simple business case of submitting an order +which will be initially handled by the infrastructure layer and then passed +to domain layer to be processed (Where business happens), then return the result +back to infrastructure layer. ## Deployment notes - -Environment Variables: -* host -* keycloak.credentials.secret - - - +This project uses embedded DB: [h2-console](http://localhost:8081/h2-console). +You can test via requests found on this [postman collections file](ddd.postman_collection.json). ## Authors [![Linkedin](https://img.shields.io/badge/LinkedIn-0077B5?style=for-the-badge&logo=linkedin&logoColor=white&label=Muhammad%20Ali)](https://linkedin.com/in/zatribune) diff --git a/backend-api-definition/HELP.md b/backend-api-definition/HELP.md deleted file mode 100644 index 79bc4de..0000000 --- a/backend-api-definition/HELP.md +++ /dev/null @@ -1,10 +0,0 @@ -# Getting Started - -### Reference Documentation - -For further reference, please consider the following sections: - -* [Official Apache Maven documentation](https://maven.apache.org/guides/index.html) -* [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/2.6.7/maven-plugin/reference/html/) -* [Create an OCI image](https://docs.spring.io/spring-boot/docs/2.6.7/maven-plugin/reference/html/#build-image) - diff --git a/backend-api-definition/pom.xml b/backend-api-definition/pom.xml deleted file mode 100644 index abfdd7a..0000000 --- a/backend-api-definition/pom.xml +++ /dev/null @@ -1,101 +0,0 @@ - - - 4.0.0 - - com.tribune - backend - 0.0.1-SNAPSHOT - - - backend-api-definition - - - 1.6.6 - 1.0.0 - 2.9.2 - 2.6.7 - 2.6.7 - 0.2.2 - - - - - io.swagger - swagger-annotations - ${swagger-annotations-version} - - - - org.springframework.boot - spring-boot-starter-validation - - - - org.springframework.boot - spring-boot-starter-test - test - - - org.junit.vintage - junit-vintage-engine - - - - - org.springframework.boot - spring-boot-starter-web - ${spring-boot-starter-web-version} - - - org.openapitools - jackson-databind-nullable - ${jackson-databind-nullable} - - - - - - - org.openapitools - openapi-generator-maven-plugin - 4.3.1 - - - - generate - - - - ${project.basedir}/src/main/resources/tribune/reporting-service.yml - - spring - com.tribune.backend.infrastructure.api - - - com.tribune.backend.infrastructure.model - - - ApiUtil.java - - - true - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.8.1 - - 1.8 - 1.8 - none - - - - - - diff --git a/backend-api-definition/src/main/resources/tribune/reporting-service.yml b/backend-api-definition/src/main/resources/tribune/reporting-service.yml deleted file mode 100644 index de216c0..0000000 --- a/backend-api-definition/src/main/resources/tribune/reporting-service.yml +++ /dev/null @@ -1,22 +0,0 @@ -openapi: "3.0.3" -info: - title: "reporting API" - description: "reporting API" - version: "1.0.0" -servers: - - url: "https://reporting" -paths: - /reporting/generate/{type}: - post: - summary: "POST reporting/generate/{type}" - operationId: "generate" - parameters: - - name: "type" - in: "path" - required: true - schema: - type: string - example: "PDF" - responses: - "200": - description: "OK" \ No newline at end of file diff --git a/backend-application/src/local/README.md b/backend-application/src/local/README.md deleted file mode 100644 index 9466bad..0000000 --- a/backend-application/src/local/README.md +++ /dev/null @@ -1,19 +0,0 @@ -## Notes regarding keycloak deployment - -### Database -* Keycloak is integrated with the main postgres instance of our backend, but connected to a different database. -* Keycloak can access this database via a dedicated user. -* Both Keycloak's user and database are initialized within this script file [create_keycloak_db](create_keycloak_db.sh) and mounted on start. -* Scripts in `/docker-entrypoint-initdb.d` are only run if you start -the container with a data directory that is empty; any pre-existing database -will be left untouched on container startup. -* One common problem is that if one of your `/docker-entrypoint-initdb.d` -scripts fails (which will cause the entrypoint script to exit) and your orchestrator restarts the container with the already initialized data directory, it will not continue on with your scripts. - -* Any `*.sql` files will be executed by `POSTGRES_USER`, which defaults to the postgres **superuser**. So it is recommended that any `psql` commands that are run inside a `*.sh` script be executed -as `POSTGRES_USER` by using the `--username "$POSTGRES_USER"` flag. -* This newly created user is supposed to be able to connect without a password due to the presence of -trust authentication for Unix socket connections made inside the container (**tested and failed -> needs a password on user creation**). - -### Initial Configuration -* This file [realm-export.json](keycloak-init/realm-export.json) is used as a backup for realm configuration. It can be loaded from the admin console. \ No newline at end of file diff --git a/backend-application/src/local/create_keycloak_db.sh b/backend-application/src/local/create_keycloak_db.sh deleted file mode 100644 index 3c92ca5..0000000 --- a/backend-application/src/local/create_keycloak_db.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -set -e - -psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL - CREATE USER keycloak WITH ENCRYPTED PASSWORD 'keycloak'; - CREATE DATABASE keycloak_db; - GRANT ALL PRIVILEGES ON DATABASE keycloak_db TO keycloak; -EOSQL \ No newline at end of file diff --git a/backend-application/src/local/docker-compose.yml b/backend-application/src/local/docker-compose.yml deleted file mode 100644 index 40b102c..0000000 --- a/backend-application/src/local/docker-compose.yml +++ /dev/null @@ -1,72 +0,0 @@ -version: '3.8' - -networks: - tribune-network: - name: tribune-network - -services: - app: - image: 'tribune-backend:latest' - build: - context: ../../../../.. - dockerfile: ./infrastructure/docker/dev/Dockerfile - container_name: app - depends_on: - - db - ports: - - '8880:8880' - environment: - - SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/tribune_db_docker - - SPRING_DATASOURCE_USERNAME=tribune_db_user - - SPRING_DATASOURCE_PASSWORD=password - labels: - collect_logs_with_filebeat: 'true' - decode_log_event_to_json_object: 'true' - networks: - - tribune-network - - db: - image: 'postgres:13.1-alpine' - restart: unless-stopped - container_name: db - environment: - #default superuser - POSTGRES_USER: tribune_db_user - ##default superuser password - POSTGRES_PASSWORD: password - ##default database - POSTGRES_DB: tribune_db_docker - ports: - - '5432:5432' - volumes: - - ./db:/var/lib/postgresql/data - - ./create_keycloak_db.sh:/docker-entrypoint-initdb.d/create_keycloak_db.sh - labels: - collect_logs_with_filebeat: 'true' - decode_log_event_to_json_object: 'true' - networks: - - tribune-network - - keycloak: - image: bitnami/keycloak:18 - container_name: keycloak - environment: - DB_VENDOR: POSTGRES - #by service name - DB_ADDR: db - #database name - DB_DATABASE: keycloak_db - DB_USER: keycloak - DB_PASSWORD: keycloak - KEYCLOAK_USER: admin - KEYCLOAK_PASSWORD: Pass@1234 - # Uncomment the line below if you want to specify JDBC parameters. The parameter below is just an example, and it shouldn't be used in production without knowledge. It is highly recommended that you read the PostgreSQL JDBC driver documentation in order to use it. - #JDBC_PARAMS: "ssl=true" - ports: - - "8080:8080" - depends_on: - - db - networks: - - tribune-network - - diff --git a/backend-application/src/local/keycloak-init/realm-export.json b/backend-application/src/local/keycloak-init/realm-export.json deleted file mode 100644 index 84dc203..0000000 --- a/backend-application/src/local/keycloak-init/realm-export.json +++ /dev/null @@ -1,2351 +0,0 @@ -{ - "id": "tribune", - "realm": "tribune", - "displayName": "Pay With tribune", - "notBefore": 0, - "defaultSignatureAlgorithm": "RS256", - "revokeRefreshToken": false, - "refreshTokenMaxReuse": 0, - "accessTokenLifespan": 300, - "accessTokenLifespanForImplicitFlow": 900, - "ssoSessionIdleTimeout": 1800, - "ssoSessionMaxLifespan": 36000, - "ssoSessionIdleTimeoutRememberMe": 0, - "ssoSessionMaxLifespanRememberMe": 0, - "offlineSessionIdleTimeout": 2592000, - "offlineSessionMaxLifespanEnabled": false, - "offlineSessionMaxLifespan": 5184000, - "clientSessionIdleTimeout": 0, - "clientSessionMaxLifespan": 0, - "clientOfflineSessionIdleTimeout": 0, - "clientOfflineSessionMaxLifespan": 0, - "accessCodeLifespan": 60, - "accessCodeLifespanUserAction": 300, - "accessCodeLifespanLogin": 1800, - "actionTokenGeneratedByAdminLifespan": 43200, - "actionTokenGeneratedByUserLifespan": 300, - "oauth2DeviceCodeLifespan": 600, - "oauth2DevicePollingInterval": 5, - "enabled": true, - "sslRequired": "external", - "registrationAllowed": false, - "registrationEmailAsUsername": false, - "rememberMe": false, - "verifyEmail": false, - "loginWithEmailAllowed": true, - "duplicateEmailsAllowed": false, - "resetPasswordAllowed": false, - "editUsernameAllowed": false, - "bruteForceProtected": false, - "permanentLockout": false, - "maxFailureWaitSeconds": 900, - "minimumQuickLoginWaitSeconds": 60, - "waitIncrementSeconds": 60, - "quickLoginCheckMilliSeconds": 1000, - "maxDeltaTimeSeconds": 43200, - "failureFactor": 30, - "roles": { - "realm": [ - { - "id": "e82e3073-eb5d-4d51-a124-c217a461e46e", - "name": "offline_access", - "description": "${role_offline-access}", - "composite": false, - "clientRole": false, - "containerId": "tribune", - "attributes": {} - }, - { - "id": "bb08772e-3722-4921-a781-9933c1446305", - "name": "uma_authorization", - "description": "${role_uma_authorization}", - "composite": false, - "clientRole": false, - "containerId": "tribune", - "attributes": {} - }, - { - "id": "5fa6ce4f-1d6d-4ae9-88ee-adcd1345b1b8", - "name": "default-roles-tribune", - "description": "${role_default-roles}", - "composite": true, - "composites": { - "realm": [ - "offline_access", - "uma_authorization" - ], - "client": { - "account": [ - "view-profile", - "manage-account" - ] - } - }, - "clientRole": false, - "containerId": "tribune", - "attributes": {} - } - ], - "client": { - "realm-management": [ - { - "id": "a04108fd-d06c-47d0-91e7-80dcd90e9999", - "name": "query-groups", - "description": "${role_query-groups}", - "composite": false, - "clientRole": true, - "containerId": "7a63afd2-e648-4aec-a7c2-14eda643f1e5", - "attributes": {} - }, - { - "id": "e1dc8e8a-566e-4d8a-a508-51caf7b3f1b2", - "name": "create-client", - "description": "${role_create-client}", - "composite": false, - "clientRole": true, - "containerId": "7a63afd2-e648-4aec-a7c2-14eda643f1e5", - "attributes": {} - }, - { - "id": "a630bdcb-5a5d-402e-a484-63008150e3c1", - "name": "manage-users", - "description": "${role_manage-users}", - "composite": false, - "clientRole": true, - "containerId": "7a63afd2-e648-4aec-a7c2-14eda643f1e5", - "attributes": {} - }, - { - "id": "726b6236-893d-4e5f-ad92-dbf83dc1d19c", - "name": "view-clients", - "description": "${role_view-clients}", - "composite": true, - "composites": { - "client": { - "realm-management": [ - "query-clients" - ] - } - }, - "clientRole": true, - "containerId": "7a63afd2-e648-4aec-a7c2-14eda643f1e5", - "attributes": {} - }, - { - "id": "0784f0cb-fb55-43ee-8d00-0f8670d6ecd5", - "name": "view-events", - "description": "${role_view-events}", - "composite": false, - "clientRole": true, - "containerId": "7a63afd2-e648-4aec-a7c2-14eda643f1e5", - "attributes": {} - }, - { - "id": "8e8bbf2f-fedc-4052-bf7a-00e2efefbc8a", - "name": "realm-admin", - "description": "${role_realm-admin}", - "composite": true, - "composites": { - "client": { - "realm-management": [ - "query-groups", - "create-client", - "manage-users", - "view-clients", - "view-events", - "manage-authorization", - "manage-events", - "query-users", - "view-authorization", - "view-users", - "view-realm", - "manage-clients", - "manage-identity-providers", - "manage-realm", - "impersonation", - "query-clients", - "view-identity-providers", - "query-realms" - ] - } - }, - "clientRole": true, - "containerId": "7a63afd2-e648-4aec-a7c2-14eda643f1e5", - "attributes": {} - }, - { - "id": "a5f5bbe9-4595-46dc-b8df-b198b171a1c3", - "name": "manage-authorization", - "description": "${role_manage-authorization}", - "composite": false, - "clientRole": true, - "containerId": "7a63afd2-e648-4aec-a7c2-14eda643f1e5", - "attributes": {} - }, - { - "id": "43a30c79-5da1-44a4-99e7-ab7d88b57f17", - "name": "manage-events", - "description": "${role_manage-events}", - "composite": false, - "clientRole": true, - "containerId": "7a63afd2-e648-4aec-a7c2-14eda643f1e5", - "attributes": {} - }, - { - "id": "92b3aa4d-eccd-42c2-9737-94ced153a4cb", - "name": "query-users", - "description": "${role_query-users}", - "composite": false, - "clientRole": true, - "containerId": "7a63afd2-e648-4aec-a7c2-14eda643f1e5", - "attributes": {} - }, - { - "id": "2a170305-0637-410c-91a9-58651426f900", - "name": "view-authorization", - "description": "${role_view-authorization}", - "composite": false, - "clientRole": true, - "containerId": "7a63afd2-e648-4aec-a7c2-14eda643f1e5", - "attributes": {} - }, - { - "id": "35664862-ba80-46e8-9692-89389be0c0c1", - "name": "view-users", - "description": "${role_view-users}", - "composite": true, - "composites": { - "client": { - "realm-management": [ - "query-groups", - "query-users" - ] - } - }, - "clientRole": true, - "containerId": "7a63afd2-e648-4aec-a7c2-14eda643f1e5", - "attributes": {} - }, - { - "id": "05056816-dcd1-43cc-be19-e1bcee295377", - "name": "view-realm", - "description": "${role_view-realm}", - "composite": false, - "clientRole": true, - "containerId": "7a63afd2-e648-4aec-a7c2-14eda643f1e5", - "attributes": {} - }, - { - "id": "4ea0050b-ffb4-4e20-a7a3-4608b65a75af", - "name": "manage-clients", - "description": "${role_manage-clients}", - "composite": false, - "clientRole": true, - "containerId": "7a63afd2-e648-4aec-a7c2-14eda643f1e5", - "attributes": {} - }, - { - "id": "692203d7-59c4-4c58-a504-7d37d5967889", - "name": "manage-identity-providers", - "description": "${role_manage-identity-providers}", - "composite": false, - "clientRole": true, - "containerId": "7a63afd2-e648-4aec-a7c2-14eda643f1e5", - "attributes": {} - }, - { - "id": "da8f32c1-a3c2-4214-b16b-20a0da236085", - "name": "manage-realm", - "description": "${role_manage-realm}", - "composite": false, - "clientRole": true, - "containerId": "7a63afd2-e648-4aec-a7c2-14eda643f1e5", - "attributes": {} - }, - { - "id": "0f65a0db-7d0e-410f-9436-4f7507784b0e", - "name": "impersonation", - "description": "${role_impersonation}", - "composite": false, - "clientRole": true, - "containerId": "7a63afd2-e648-4aec-a7c2-14eda643f1e5", - "attributes": {} - }, - { - "id": "ad41530a-e127-4748-beee-5d1637215f68", - "name": "query-clients", - "description": "${role_query-clients}", - "composite": false, - "clientRole": true, - "containerId": "7a63afd2-e648-4aec-a7c2-14eda643f1e5", - "attributes": {} - }, - { - "id": "1ac0b3e9-8e10-4f37-94a8-5a6337502601", - "name": "view-identity-providers", - "description": "${role_view-identity-providers}", - "composite": false, - "clientRole": true, - "containerId": "7a63afd2-e648-4aec-a7c2-14eda643f1e5", - "attributes": {} - }, - { - "id": "3c8a5bca-e17d-445f-98aa-4d15592ef95c", - "name": "query-realms", - "description": "${role_query-realms}", - "composite": false, - "clientRole": true, - "containerId": "7a63afd2-e648-4aec-a7c2-14eda643f1e5", - "attributes": {} - } - ], - "tribune-user-management": [], - "security-admin-console": [], - "admin-cli": [], - "account-console": [], - "broker": [ - { - "id": "e712e2e7-c62c-419c-99a3-e6a0381a06c4", - "name": "read-token", - "description": "${role_read-token}", - "composite": false, - "clientRole": true, - "containerId": "fe5b4e8c-5b43-4e08-841b-66f9b6e35020", - "attributes": {} - } - ], - "account": [ - { - "id": "7275076e-23f3-4704-860f-e137fb7e85d9", - "name": "manage-consent", - "description": "${role_manage-consent}", - "composite": true, - "composites": { - "client": { - "account": [ - "view-consent" - ] - } - }, - "clientRole": true, - "containerId": "dfb9a4ca-b2e9-443f-94f2-609ef373bdbc", - "attributes": {} - }, - { - "id": "a799612e-5d9a-4fcd-9222-37b75cf2395f", - "name": "view-profile", - "description": "${role_view-profile}", - "composite": false, - "clientRole": true, - "containerId": "dfb9a4ca-b2e9-443f-94f2-609ef373bdbc", - "attributes": {} - }, - { - "id": "e3d9ba83-df4a-4dc3-bd01-eec458c80812", - "name": "view-consent", - "description": "${role_view-consent}", - "composite": false, - "clientRole": true, - "containerId": "dfb9a4ca-b2e9-443f-94f2-609ef373bdbc", - "attributes": {} - }, - { - "id": "8c18ff05-cccf-4c36-aec0-9f028f531082", - "name": "view-applications", - "description": "${role_view-applications}", - "composite": false, - "clientRole": true, - "containerId": "dfb9a4ca-b2e9-443f-94f2-609ef373bdbc", - "attributes": {} - }, - { - "id": "abeb2352-916d-47ae-a25d-6f65db6a1eb6", - "name": "manage-account", - "description": "${role_manage-account}", - "composite": true, - "composites": { - "client": { - "account": [ - "manage-account-links" - ] - } - }, - "clientRole": true, - "containerId": "dfb9a4ca-b2e9-443f-94f2-609ef373bdbc", - "attributes": {} - }, - { - "id": "1283bd27-beb0-4cbe-a79e-3dcad6b2d581", - "name": "delete-account", - "description": "${role_delete-account}", - "composite": false, - "clientRole": true, - "containerId": "dfb9a4ca-b2e9-443f-94f2-609ef373bdbc", - "attributes": {} - }, - { - "id": "93c09c68-ece5-42c1-8c2f-c500d3a985e5", - "name": "manage-account-links", - "description": "${role_manage-account-links}", - "composite": false, - "clientRole": true, - "containerId": "dfb9a4ca-b2e9-443f-94f2-609ef373bdbc", - "attributes": {} - } - ], - "tribune-user": [ - { - "id": "ea993cae-419b-4c90-bbfd-9007fda87a2c", - "name": "merchant", - "composite": false, - "clientRole": true, - "containerId": "b94ce53e-0df9-4e5e-bf34-b45df7c478de", - "attributes": {} - }, - { - "id": "620b4716-70e6-4b35-b632-353b1435c31f", - "name": "user", - "composite": false, - "clientRole": true, - "containerId": "b94ce53e-0df9-4e5e-bf34-b45df7c478de", - "attributes": {} - } - ] - } - }, - "groups": [], - "defaultRole": { - "id": "5fa6ce4f-1d6d-4ae9-88ee-adcd1345b1b8", - "name": "default-roles-tribune", - "description": "${role_default-roles}", - "composite": true, - "clientRole": false, - "containerId": "tribune" - }, - "requiredCredentials": [ - "password" - ], - "otpPolicyType": "totp", - "otpPolicyAlgorithm": "HmacSHA1", - "otpPolicyInitialCounter": 0, - "otpPolicyDigits": 6, - "otpPolicyLookAheadWindow": 1, - "otpPolicyPeriod": 30, - "otpSupportedApplications": [ - "FreeOTP", - "Google Authenticator" - ], - "webAuthnPolicyRpEntityName": "keycloak", - "webAuthnPolicySignatureAlgorithms": [ - "ES256" - ], - "webAuthnPolicyRpId": "", - "webAuthnPolicyAttestationConveyancePreference": "not specified", - "webAuthnPolicyAuthenticatorAttachment": "not specified", - "webAuthnPolicyRequireResidentKey": "not specified", - "webAuthnPolicyUserVerificationRequirement": "not specified", - "webAuthnPolicyCreateTimeout": 0, - "webAuthnPolicyAvoidSameAuthenticatorRegister": false, - "webAuthnPolicyAcceptableAaguids": [], - "webAuthnPolicyPasswordlessRpEntityName": "keycloak", - "webAuthnPolicyPasswordlessSignatureAlgorithms": [ - "ES256" - ], - "webAuthnPolicyPasswordlessRpId": "", - "webAuthnPolicyPasswordlessAttestationConveyancePreference": "not specified", - "webAuthnPolicyPasswordlessAuthenticatorAttachment": "not specified", - "webAuthnPolicyPasswordlessRequireResidentKey": "not specified", - "webAuthnPolicyPasswordlessUserVerificationRequirement": "not specified", - "webAuthnPolicyPasswordlessCreateTimeout": 0, - "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister": false, - "webAuthnPolicyPasswordlessAcceptableAaguids": [], - "scopeMappings": [ - { - "clientScope": "offline_access", - "roles": [ - "offline_access" - ] - } - ], - "clientScopeMappings": { - "account": [ - { - "client": "account-console", - "roles": [ - "manage-account" - ] - } - ] - }, - "clients": [ - { - "id": "dfb9a4ca-b2e9-443f-94f2-609ef373bdbc", - "clientId": "account", - "name": "${client_account}", - "rootUrl": "${authBaseUrl}", - "baseUrl": "/realms/tribune/account/", - "surrogateAuthRequired": false, - "enabled": true, - "alwaysDisplayInConsole": false, - "clientAuthenticatorType": "client-secret", - "redirectUris": [ - "/realms/tribune/account/*" - ], - "webOrigins": [], - "notBefore": 0, - "bearerOnly": false, - "consentRequired": false, - "standardFlowEnabled": true, - "implicitFlowEnabled": false, - "directAccessGrantsEnabled": false, - "serviceAccountsEnabled": false, - "publicClient": true, - "frontchannelLogout": false, - "protocol": "openid-connect", - "attributes": {}, - "authenticationFlowBindingOverrides": {}, - "fullScopeAllowed": false, - "nodeReRegistrationTimeout": 0, - "defaultClientScopes": [ - "web-origins", - "acr", - "roles", - "profile", - "email" - ], - "optionalClientScopes": [ - "address", - "phone", - "offline_access", - "microprofile-jwt" - ] - }, - { - "id": "193424f3-4a60-4268-af7e-e46a154a8b3c", - "clientId": "account-console", - "name": "${client_account-console}", - "rootUrl": "${authBaseUrl}", - "baseUrl": "/realms/tribune/account/", - "surrogateAuthRequired": false, - "enabled": true, - "alwaysDisplayInConsole": false, - "clientAuthenticatorType": "client-secret", - "redirectUris": [ - "/realms/tribune/account/*" - ], - "webOrigins": [], - "notBefore": 0, - "bearerOnly": false, - "consentRequired": false, - "standardFlowEnabled": true, - "implicitFlowEnabled": false, - "directAccessGrantsEnabled": false, - "serviceAccountsEnabled": false, - "publicClient": true, - "frontchannelLogout": false, - "protocol": "openid-connect", - "attributes": { - "pkce.code.challenge.method": "S256" - }, - "authenticationFlowBindingOverrides": {}, - "fullScopeAllowed": false, - "nodeReRegistrationTimeout": 0, - "protocolMappers": [ - { - "id": "411a9c82-3c02-420d-ab3f-1ac36f2ef228", - "name": "audience resolve", - "protocol": "openid-connect", - "protocolMapper": "oidc-audience-resolve-mapper", - "consentRequired": false, - "config": {} - } - ], - "defaultClientScopes": [ - "web-origins", - "acr", - "roles", - "profile", - "email" - ], - "optionalClientScopes": [ - "address", - "phone", - "offline_access", - "microprofile-jwt" - ] - }, - { - "id": "dd7148d7-91c7-4a10-b932-a339339c137f", - "clientId": "admin-cli", - "name": "${client_admin-cli}", - "surrogateAuthRequired": false, - "enabled": true, - "alwaysDisplayInConsole": false, - "clientAuthenticatorType": "client-secret", - "redirectUris": [], - "webOrigins": [], - "notBefore": 0, - "bearerOnly": false, - "consentRequired": false, - "standardFlowEnabled": false, - "implicitFlowEnabled": false, - "directAccessGrantsEnabled": true, - "serviceAccountsEnabled": false, - "publicClient": true, - "frontchannelLogout": false, - "protocol": "openid-connect", - "attributes": {}, - "authenticationFlowBindingOverrides": {}, - "fullScopeAllowed": false, - "nodeReRegistrationTimeout": 0, - "defaultClientScopes": [ - "web-origins", - "acr", - "roles", - "profile", - "email" - ], - "optionalClientScopes": [ - "address", - "phone", - "offline_access", - "microprofile-jwt" - ] - }, - { - "id": "b94ce53e-0df9-4e5e-bf34-b45df7c478de", - "clientId": "tribune-user", - "rootUrl": "https://localhost:8880/", - "baseUrl": "https://localhost:8880/", - "surrogateAuthRequired": false, - "enabled": true, - "alwaysDisplayInConsole": false, - "clientAuthenticatorType": "client-secret", - "secret": "**********", - "redirectUris": [ - "https://localhost:8880/*" - ], - "webOrigins": [ - "https://localhost:8880/*", - "+" - ], - "notBefore": 0, - "bearerOnly": false, - "consentRequired": false, - "standardFlowEnabled": true, - "implicitFlowEnabled": false, - "directAccessGrantsEnabled": true, - "serviceAccountsEnabled": false, - "publicClient": false, - "frontchannelLogout": false, - "protocol": "openid-connect", - "attributes": { - "saml.multivalued.roles": "false", - "saml.force.post.binding": "false", - "frontchannel.logout.session.required": "false", - "oauth2.device.authorization.grant.enabled": "false", - "backchannel.logout.revoke.offline.tokens": "false", - "saml.server.signature.keyinfo.ext": "false", - "use.refresh.tokens": "true", - "oidc.ciba.grant.enabled": "false", - "backchannel.logout.session.required": "true", - "client_credentials.use_refresh_token": "false", - "saml.client.signature": "false", - "require.pushed.authorization.requests": "false", - "saml.allow.ecp.flow": "false", - "saml.assertion.signature": "false", - "id.token.as.detached.signature": "false", - "client.secret.creation.time": "1652478755", - "saml.encrypt": "false", - "saml.server.signature": "false", - "exclude.session.state.from.auth.response": "false", - "saml.artifact.binding": "false", - "saml_force_name_id_format": "false", - "tls.client.certificate.bound.access.tokens": "false", - "acr.loa.map": "{}", - "saml.authnstatement": "false", - "display.on.consent.screen": "false", - "token.response.type.bearer.lower-case": "false", - "saml.onetimeuse.condition": "false" - }, - "authenticationFlowBindingOverrides": {}, - "fullScopeAllowed": true, - "nodeReRegistrationTimeout": -1, - "protocolMappers": [ - { - "id": "3928aa67-5ccd-4f52-a9c6-8a67821bbe74", - "name": "Client Host", - "protocol": "openid-connect", - "protocolMapper": "oidc-usersessionmodel-note-mapper", - "consentRequired": false, - "config": { - "user.session.note": "clientHost", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "clientHost", - "jsonType.label": "String" - } - }, - { - "id": "9091ee89-4ab4-45c7-8ea7-ec2fc6bfae35", - "name": "Client ID", - "protocol": "openid-connect", - "protocolMapper": "oidc-usersessionmodel-note-mapper", - "consentRequired": false, - "config": { - "user.session.note": "clientId", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "clientId", - "jsonType.label": "String" - } - }, - { - "id": "acd0f49f-b098-4eb4-920b-a773f382b725", - "name": "Client IP Address", - "protocol": "openid-connect", - "protocolMapper": "oidc-usersessionmodel-note-mapper", - "consentRequired": false, - "config": { - "user.session.note": "clientAddress", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "clientAddress", - "jsonType.label": "String" - } - } - ], - "defaultClientScopes": [ - "web-origins", - "acr", - "roles", - "profile", - "email" - ], - "optionalClientScopes": [ - "address", - "phone", - "offline_access", - "microprofile-jwt" - ] - }, - { - "id": "b38a3282-1e8a-4fa6-ad05-8d40e18bbe57", - "clientId": "tribune-user-management", - "name": "User Management Client", - "description": "Provides User Management to tribune Backend Application.", - "surrogateAuthRequired": false, - "enabled": true, - "alwaysDisplayInConsole": false, - "clientAuthenticatorType": "client-secret", - "secret": "**********", - "redirectUris": [ - "http://localhost:8880/*" - ], - "webOrigins": [ - "+" - ], - "notBefore": 0, - "bearerOnly": false, - "consentRequired": false, - "standardFlowEnabled": true, - "implicitFlowEnabled": false, - "directAccessGrantsEnabled": true, - "serviceAccountsEnabled": false, - "publicClient": false, - "frontchannelLogout": false, - "protocol": "openid-connect", - "attributes": { - "saml.multivalued.roles": "false", - "saml.force.post.binding": "false", - "frontchannel.logout.session.required": "false", - "oauth2.device.authorization.grant.enabled": "false", - "backchannel.logout.revoke.offline.tokens": "false", - "saml.server.signature.keyinfo.ext": "false", - "use.refresh.tokens": "true", - "oidc.ciba.grant.enabled": "false", - "backchannel.logout.session.required": "true", - "client_credentials.use_refresh_token": "false", - "saml.client.signature": "false", - "require.pushed.authorization.requests": "false", - "saml.allow.ecp.flow": "false", - "saml.assertion.signature": "false", - "id.token.as.detached.signature": "false", - "client.secret.creation.time": "1652476352", - "saml.encrypt": "false", - "saml.server.signature": "false", - "exclude.session.state.from.auth.response": "false", - "saml.artifact.binding": "false", - "saml_force_name_id_format": "false", - "tls.client.certificate.bound.access.tokens": "false", - "acr.loa.map": "{}", - "saml.authnstatement": "false", - "display.on.consent.screen": "false", - "token.response.type.bearer.lower-case": "false", - "saml.onetimeuse.condition": "false" - }, - "authenticationFlowBindingOverrides": {}, - "fullScopeAllowed": true, - "nodeReRegistrationTimeout": -1, - "defaultClientScopes": [ - "web-origins", - "acr", - "roles", - "profile", - "email" - ], - "optionalClientScopes": [ - "address", - "phone", - "offline_access", - "microprofile-jwt" - ] - }, - { - "id": "fe5b4e8c-5b43-4e08-841b-66f9b6e35020", - "clientId": "broker", - "name": "${client_broker}", - "surrogateAuthRequired": false, - "enabled": true, - "alwaysDisplayInConsole": false, - "clientAuthenticatorType": "client-secret", - "redirectUris": [], - "webOrigins": [], - "notBefore": 0, - "bearerOnly": true, - "consentRequired": false, - "standardFlowEnabled": true, - "implicitFlowEnabled": false, - "directAccessGrantsEnabled": false, - "serviceAccountsEnabled": false, - "publicClient": false, - "frontchannelLogout": false, - "protocol": "openid-connect", - "attributes": {}, - "authenticationFlowBindingOverrides": {}, - "fullScopeAllowed": false, - "nodeReRegistrationTimeout": 0, - "defaultClientScopes": [ - "web-origins", - "acr", - "roles", - "profile", - "email" - ], - "optionalClientScopes": [ - "address", - "phone", - "offline_access", - "microprofile-jwt" - ] - }, - { - "id": "7a63afd2-e648-4aec-a7c2-14eda643f1e5", - "clientId": "realm-management", - "name": "${client_realm-management}", - "surrogateAuthRequired": false, - "enabled": true, - "alwaysDisplayInConsole": false, - "clientAuthenticatorType": "client-secret", - "secret": "**********", - "redirectUris": [], - "webOrigins": [], - "notBefore": 0, - "bearerOnly": true, - "consentRequired": false, - "standardFlowEnabled": true, - "implicitFlowEnabled": false, - "directAccessGrantsEnabled": false, - "serviceAccountsEnabled": false, - "publicClient": false, - "frontchannelLogout": false, - "protocol": "openid-connect", - "attributes": { - "client.secret.creation.time": "1652468991" - }, - "authenticationFlowBindingOverrides": {}, - "fullScopeAllowed": false, - "nodeReRegistrationTimeout": 0, - "defaultClientScopes": [ - "web-origins", - "acr", - "roles", - "profile", - "email" - ], - "optionalClientScopes": [ - "address", - "phone", - "offline_access", - "microprofile-jwt" - ] - }, - { - "id": "ace722d9-3d3e-4310-a2e1-7b78f2ddb84d", - "clientId": "security-admin-console", - "name": "${client_security-admin-console}", - "rootUrl": "${authAdminUrl}", - "baseUrl": "/admin/tribune/console/", - "surrogateAuthRequired": false, - "enabled": true, - "alwaysDisplayInConsole": false, - "clientAuthenticatorType": "client-secret", - "redirectUris": [ - "/admin/tribune/console/*" - ], - "webOrigins": [ - "+" - ], - "notBefore": 0, - "bearerOnly": false, - "consentRequired": false, - "standardFlowEnabled": true, - "implicitFlowEnabled": false, - "directAccessGrantsEnabled": false, - "serviceAccountsEnabled": false, - "publicClient": true, - "frontchannelLogout": false, - "protocol": "openid-connect", - "attributes": { - "pkce.code.challenge.method": "S256" - }, - "authenticationFlowBindingOverrides": {}, - "fullScopeAllowed": false, - "nodeReRegistrationTimeout": 0, - "protocolMappers": [ - { - "id": "2cb48511-1ddf-4ee6-9e2c-eecd9a2eba17", - "name": "locale", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "locale", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "locale", - "jsonType.label": "String" - } - } - ], - "defaultClientScopes": [ - "web-origins", - "acr", - "roles", - "profile", - "email" - ], - "optionalClientScopes": [ - "address", - "phone", - "offline_access", - "microprofile-jwt" - ] - } - ], - "clientScopes": [ - { - "id": "706a47f0-c290-4ba8-8058-2729d56032ff", - "name": "acr", - "description": "OpenID Connect scope for add acr (authentication context class reference) to the token", - "protocol": "openid-connect", - "attributes": { - "include.in.token.scope": "false", - "display.on.consent.screen": "false" - }, - "protocolMappers": [ - { - "id": "4df24425-f3bb-4302-88ee-d816fc0bb593", - "name": "acr loa level", - "protocol": "openid-connect", - "protocolMapper": "oidc-acr-mapper", - "consentRequired": false, - "config": { - "id.token.claim": "true", - "access.token.claim": "true", - "userinfo.token.claim": "true" - } - } - ] - }, - { - "id": "e1a38d46-5aee-44e9-92d5-c891bbe6ddcb", - "name": "web-origins", - "description": "OpenID Connect scope for add allowed web origins to the access token", - "protocol": "openid-connect", - "attributes": { - "include.in.token.scope": "false", - "display.on.consent.screen": "false", - "consent.screen.text": "" - }, - "protocolMappers": [ - { - "id": "416e50de-18cf-4617-a235-5e5a5cac6ebf", - "name": "allowed web origins", - "protocol": "openid-connect", - "protocolMapper": "oidc-allowed-origins-mapper", - "consentRequired": false, - "config": {} - } - ] - }, - { - "id": "3bac6854-2647-4001-9230-7b9dae5921f3", - "name": "offline_access", - "description": "OpenID Connect built-in scope: offline_access", - "protocol": "openid-connect", - "attributes": { - "consent.screen.text": "${offlineAccessScopeConsentText}", - "display.on.consent.screen": "true" - } - }, - { - "id": "ccf5da0d-70e0-4c65-9e43-a5d49e3ef4d7", - "name": "phone", - "description": "OpenID Connect built-in scope: phone", - "protocol": "openid-connect", - "attributes": { - "include.in.token.scope": "true", - "display.on.consent.screen": "true", - "consent.screen.text": "${phoneScopeConsentText}" - }, - "protocolMappers": [ - { - "id": "86997019-b143-494a-bc6e-22d2fe65bdbf", - "name": "phone number verified", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "phoneNumberVerified", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "phone_number_verified", - "jsonType.label": "boolean" - } - }, - { - "id": "128f2343-18d5-4e67-9d97-4c7e1e6c5672", - "name": "phone number", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "phoneNumber", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "phone_number", - "jsonType.label": "String" - } - } - ] - }, - { - "id": "afe6f782-29e5-4458-85e3-853abfea20c0", - "name": "microprofile-jwt", - "description": "Microprofile - JWT built-in scope", - "protocol": "openid-connect", - "attributes": { - "include.in.token.scope": "true", - "display.on.consent.screen": "false" - }, - "protocolMappers": [ - { - "id": "df104de1-4ac1-4fbc-ad79-751b7b3abdce", - "name": "groups", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-realm-role-mapper", - "consentRequired": false, - "config": { - "multivalued": "true", - "userinfo.token.claim": "true", - "user.attribute": "foo", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "groups", - "jsonType.label": "String" - } - }, - { - "id": "19d75c81-4279-4546-a3d6-0039504939bb", - "name": "upn", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-property-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "username", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "upn", - "jsonType.label": "String" - } - } - ] - }, - { - "id": "66051b84-b881-4dfc-a09e-dee035410209", - "name": "roles", - "description": "OpenID Connect scope for add user roles to the access token", - "protocol": "openid-connect", - "attributes": { - "include.in.token.scope": "false", - "display.on.consent.screen": "true", - "consent.screen.text": "${rolesScopeConsentText}" - }, - "protocolMappers": [ - { - "id": "55c02a19-578a-4d92-acd5-b1912fd5a2ef", - "name": "audience resolve", - "protocol": "openid-connect", - "protocolMapper": "oidc-audience-resolve-mapper", - "consentRequired": false, - "config": {} - }, - { - "id": "9fa34f9a-d6c9-4b8a-bf68-fd4b981a1d56", - "name": "client roles", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-client-role-mapper", - "consentRequired": false, - "config": { - "user.attribute": "foo", - "access.token.claim": "true", - "claim.name": "resource_access.${client_id}.roles", - "jsonType.label": "String", - "multivalued": "true" - } - }, - { - "id": "6376ac17-3fee-4ba6-b98d-20d1966e5c69", - "name": "realm roles", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-realm-role-mapper", - "consentRequired": false, - "config": { - "user.attribute": "foo", - "access.token.claim": "true", - "claim.name": "realm_access.roles", - "jsonType.label": "String", - "multivalued": "true" - } - } - ] - }, - { - "id": "d2ad4fc5-a0ea-4ba6-b110-f66156db1671", - "name": "role_list", - "description": "SAML role list", - "protocol": "saml", - "attributes": { - "consent.screen.text": "${samlRoleListScopeConsentText}", - "display.on.consent.screen": "true" - }, - "protocolMappers": [ - { - "id": "e7e0b6bc-73a5-4362-9e5f-ae29cf8b02ac", - "name": "role list", - "protocol": "saml", - "protocolMapper": "saml-role-list-mapper", - "consentRequired": false, - "config": { - "single": "false", - "attribute.nameformat": "Basic", - "attribute.name": "Role" - } - } - ] - }, - { - "id": "9df17a50-4da4-4521-8611-99aac810042d", - "name": "profile", - "description": "OpenID Connect built-in scope: profile", - "protocol": "openid-connect", - "attributes": { - "include.in.token.scope": "true", - "display.on.consent.screen": "true", - "consent.screen.text": "${profileScopeConsentText}" - }, - "protocolMappers": [ - { - "id": "2fd5bb1e-1f0d-4da8-b191-17b2dce33853", - "name": "gender", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "gender", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "gender", - "jsonType.label": "String" - } - }, - { - "id": "2be77055-3967-42f6-ba98-8467457f3265", - "name": "picture", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "picture", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "picture", - "jsonType.label": "String" - } - }, - { - "id": "f41a7953-2ead-4f53-bbae-168428d32541", - "name": "middle name", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "middleName", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "middle_name", - "jsonType.label": "String" - } - }, - { - "id": "387a5476-808e-4046-bcb6-a6ab794aaaaa", - "name": "birthdate", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "birthdate", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "birthdate", - "jsonType.label": "String" - } - }, - { - "id": "c1bbf010-17dd-498d-abc6-339937abbee7", - "name": "nickname", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "nickname", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "nickname", - "jsonType.label": "String" - } - }, - { - "id": "162fcdcd-7197-4429-9a80-8c288d515035", - "name": "family name", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-property-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "lastName", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "family_name", - "jsonType.label": "String" - } - }, - { - "id": "aa4c4704-ae6e-4905-899b-1252f65a0c94", - "name": "profile", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "profile", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "profile", - "jsonType.label": "String" - } - }, - { - "id": "5a5faeee-2c47-40a0-94fd-fb644a8ac663", - "name": "updated at", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "updatedAt", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "updated_at", - "jsonType.label": "long" - } - }, - { - "id": "132b635b-ad8c-477f-8c4c-6c3797b24319", - "name": "full name", - "protocol": "openid-connect", - "protocolMapper": "oidc-full-name-mapper", - "consentRequired": false, - "config": { - "id.token.claim": "true", - "access.token.claim": "true", - "userinfo.token.claim": "true" - } - }, - { - "id": "a61eea8c-95de-4d99-98d0-bbd96f748580", - "name": "locale", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "locale", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "locale", - "jsonType.label": "String" - } - }, - { - "id": "6dc55f42-3e6b-42a3-ae9c-3bb63fe2869a", - "name": "username", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-property-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "username", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "preferred_username", - "jsonType.label": "String" - } - }, - { - "id": "1ff337a0-afa3-4951-b17f-20d803dc0b57", - "name": "zoneinfo", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "zoneinfo", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "zoneinfo", - "jsonType.label": "String" - } - }, - { - "id": "0800a94b-b25a-4f33-9cd9-c6a6bb714696", - "name": "given name", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-property-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "firstName", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "given_name", - "jsonType.label": "String" - } - }, - { - "id": "03f5c878-75dc-4699-b70c-002575f5b794", - "name": "website", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "website", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "website", - "jsonType.label": "String" - } - } - ] - }, - { - "id": "640a0774-7849-4aa3-b3df-cc85f50421fe", - "name": "address", - "description": "OpenID Connect built-in scope: address", - "protocol": "openid-connect", - "attributes": { - "include.in.token.scope": "true", - "display.on.consent.screen": "true", - "consent.screen.text": "${addressScopeConsentText}" - }, - "protocolMappers": [ - { - "id": "b4944c8c-7d66-45b1-90cd-c9a5cd32e82c", - "name": "address", - "protocol": "openid-connect", - "protocolMapper": "oidc-address-mapper", - "consentRequired": false, - "config": { - "user.attribute.formatted": "formatted", - "user.attribute.country": "country", - "user.attribute.postal_code": "postal_code", - "userinfo.token.claim": "true", - "user.attribute.street": "street", - "id.token.claim": "true", - "user.attribute.region": "region", - "access.token.claim": "true", - "user.attribute.locality": "locality" - } - } - ] - }, - { - "id": "08499463-28e9-4a76-a3d7-728c8681a1ec", - "name": "email", - "description": "OpenID Connect built-in scope: email", - "protocol": "openid-connect", - "attributes": { - "include.in.token.scope": "true", - "display.on.consent.screen": "true", - "consent.screen.text": "${emailScopeConsentText}" - }, - "protocolMappers": [ - { - "id": "45d595dd-e0d0-4349-a1b9-68b5685ee98d", - "name": "email verified", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-property-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "emailVerified", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "email_verified", - "jsonType.label": "boolean" - } - }, - { - "id": "c9308331-3ed9-4832-a8e7-1c60d25fd69a", - "name": "email", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-property-mapper", - "consentRequired": false, - "config": { - "userinfo.token.claim": "true", - "user.attribute": "email", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "email", - "jsonType.label": "String" - } - } - ] - } - ], - "defaultDefaultClientScopes": [ - "role_list", - "profile", - "email", - "roles", - "web-origins", - "acr" - ], - "defaultOptionalClientScopes": [ - "offline_access", - "address", - "phone", - "microprofile-jwt" - ], - "browserSecurityHeaders": { - "contentSecurityPolicyReportOnly": "", - "xContentTypeOptions": "nosniff", - "xRobotsTag": "none", - "xFrameOptions": "SAMEORIGIN", - "contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", - "xXSSProtection": "1; mode=block", - "strictTransportSecurity": "max-age=31536000; includeSubDomains" - }, - "smtpServer": {}, - "eventsEnabled": false, - "eventsListeners": [ - "jboss-logging" - ], - "enabledEventTypes": [], - "adminEventsEnabled": false, - "adminEventsDetailsEnabled": false, - "identityProviders": [], - "identityProviderMappers": [], - "components": { - "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [ - { - "id": "ef5934cf-ab2a-4c30-b329-7204e6219385", - "name": "Consent Required", - "providerId": "consent-required", - "subType": "anonymous", - "subComponents": {}, - "config": {} - }, - { - "id": "10b18ea2-f9b0-4159-9ce7-5e69f9e20ec0", - "name": "Max Clients Limit", - "providerId": "max-clients", - "subType": "anonymous", - "subComponents": {}, - "config": { - "max-clients": [ - "200" - ] - } - }, - { - "id": "06f0fcda-3e37-4467-be55-87e215adc22c", - "name": "Trusted Hosts", - "providerId": "trusted-hosts", - "subType": "anonymous", - "subComponents": {}, - "config": { - "host-sending-registration-request-must-match": [ - "true" - ], - "client-uris-must-match": [ - "true" - ] - } - }, - { - "id": "063923e6-9120-458f-b34c-2cdf75e6407d", - "name": "Allowed Client Scopes", - "providerId": "allowed-client-templates", - "subType": "authenticated", - "subComponents": {}, - "config": { - "allow-default-scopes": [ - "true" - ] - } - }, - { - "id": "1f5b9a9d-4275-4556-ac2d-356d10134dd3", - "name": "Full Scope Disabled", - "providerId": "scope", - "subType": "anonymous", - "subComponents": {}, - "config": {} - }, - { - "id": "90fa77a3-4978-4633-a232-0dd3ee71a20d", - "name": "Allowed Protocol Mapper Types", - "providerId": "allowed-protocol-mappers", - "subType": "anonymous", - "subComponents": {}, - "config": { - "allowed-protocol-mapper-types": [ - "saml-role-list-mapper", - "oidc-address-mapper", - "saml-user-property-mapper", - "oidc-usermodel-attribute-mapper", - "saml-user-attribute-mapper", - "oidc-sha256-pairwise-sub-mapper", - "oidc-full-name-mapper", - "oidc-usermodel-property-mapper" - ] - } - }, - { - "id": "222e7076-0596-42ee-b2d6-bffaa8792dbb", - "name": "Allowed Client Scopes", - "providerId": "allowed-client-templates", - "subType": "anonymous", - "subComponents": {}, - "config": { - "allow-default-scopes": [ - "true" - ] - } - }, - { - "id": "be7b229c-744d-4d68-9a41-e0b86ab3ff89", - "name": "Allowed Protocol Mapper Types", - "providerId": "allowed-protocol-mappers", - "subType": "authenticated", - "subComponents": {}, - "config": { - "allowed-protocol-mapper-types": [ - "oidc-usermodel-property-mapper", - "oidc-sha256-pairwise-sub-mapper", - "saml-role-list-mapper", - "oidc-usermodel-attribute-mapper", - "oidc-address-mapper", - "saml-user-property-mapper", - "oidc-full-name-mapper", - "saml-user-attribute-mapper" - ] - } - } - ], - "org.keycloak.userprofile.UserProfileProvider": [ - { - "id": "9d1bdff4-c182-43cc-8d73-833c46693012", - "providerId": "declarative-user-profile", - "subComponents": {}, - "config": {} - } - ], - "org.keycloak.keys.KeyProvider": [ - { - "id": "928bd179-bdc7-429e-bd97-ebee3e028a7b", - "name": "rsa-enc-generated", - "providerId": "rsa-enc-generated", - "subComponents": {}, - "config": { - "priority": [ - "100" - ], - "algorithm": [ - "RSA-OAEP" - ] - } - }, - { - "id": "24714de3-f299-4713-b404-7b5d1a5239b9", - "name": "aes-generated", - "providerId": "aes-generated", - "subComponents": {}, - "config": { - "priority": [ - "100" - ] - } - }, - { - "id": "1e737846-40eb-4c23-9879-e64f81f07e92", - "name": "hmac-generated", - "providerId": "hmac-generated", - "subComponents": {}, - "config": { - "priority": [ - "100" - ], - "algorithm": [ - "HS256" - ] - } - }, - { - "id": "82a2c589-cd52-49d5-8489-d8173b252946", - "name": "rsa-generated", - "providerId": "rsa-generated", - "subComponents": {}, - "config": { - "priority": [ - "100" - ] - } - } - ] - }, - "internationalizationEnabled": false, - "supportedLocales": [], - "authenticationFlows": [ - { - "id": "a6e804cc-41cd-48fa-889e-7e3481bdab5f", - "alias": "Account verification options", - "description": "Method with which to verity the existing account", - "providerId": "basic-flow", - "topLevel": false, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "idp-email-verification", - "authenticatorFlow": false, - "requirement": "ALTERNATIVE", - "priority": 10, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticatorFlow": true, - "requirement": "ALTERNATIVE", - "priority": 20, - "autheticatorFlow": true, - "flowAlias": "Verify Existing Account by Re-authentication", - "userSetupAllowed": false - } - ] - }, - { - "id": "86b84d34-e3b5-4655-8d58-67a09e1c4df7", - "alias": "Authentication Options", - "description": "Authentication options.", - "providerId": "basic-flow", - "topLevel": false, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "basic-auth", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 10, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticator": "basic-auth-otp", - "authenticatorFlow": false, - "requirement": "DISABLED", - "priority": 20, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticator": "auth-spnego", - "authenticatorFlow": false, - "requirement": "DISABLED", - "priority": 30, - "autheticatorFlow": false, - "userSetupAllowed": false - } - ] - }, - { - "id": "7d36ec96-afae-4852-b7a0-645de55bc20e", - "alias": "Browser - Conditional OTP", - "description": "Flow to determine if the OTP is required for the authentication", - "providerId": "basic-flow", - "topLevel": false, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "conditional-user-configured", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 10, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticator": "auth-otp-form", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 20, - "autheticatorFlow": false, - "userSetupAllowed": false - } - ] - }, - { - "id": "dd713267-2034-43d2-bc16-2824cbc43839", - "alias": "Direct Grant - Conditional OTP", - "description": "Flow to determine if the OTP is required for the authentication", - "providerId": "basic-flow", - "topLevel": false, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "conditional-user-configured", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 10, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticator": "direct-grant-validate-otp", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 20, - "autheticatorFlow": false, - "userSetupAllowed": false - } - ] - }, - { - "id": "b0a32ff0-bae4-4ef2-add4-b18d138e57c8", - "alias": "First broker login - Conditional OTP", - "description": "Flow to determine if the OTP is required for the authentication", - "providerId": "basic-flow", - "topLevel": false, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "conditional-user-configured", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 10, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticator": "auth-otp-form", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 20, - "autheticatorFlow": false, - "userSetupAllowed": false - } - ] - }, - { - "id": "59ae23fd-eaea-4fca-b370-abd9aade92d8", - "alias": "Handle Existing Account", - "description": "Handle what to do if there is existing account with same email/username like authenticated identity provider", - "providerId": "basic-flow", - "topLevel": false, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "idp-confirm-link", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 10, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticatorFlow": true, - "requirement": "REQUIRED", - "priority": 20, - "autheticatorFlow": true, - "flowAlias": "Account verification options", - "userSetupAllowed": false - } - ] - }, - { - "id": "a7f93a2e-7814-4fc7-9ac2-2babcd3b9ea8", - "alias": "Reset - Conditional OTP", - "description": "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", - "providerId": "basic-flow", - "topLevel": false, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "conditional-user-configured", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 10, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticator": "reset-otp", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 20, - "autheticatorFlow": false, - "userSetupAllowed": false - } - ] - }, - { - "id": "07b5934e-6531-4e98-9b90-acf4239aafc9", - "alias": "User creation or linking", - "description": "Flow for the existing/non-existing user alternatives", - "providerId": "basic-flow", - "topLevel": false, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticatorConfig": "create unique user config", - "authenticator": "idp-create-user-if-unique", - "authenticatorFlow": false, - "requirement": "ALTERNATIVE", - "priority": 10, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticatorFlow": true, - "requirement": "ALTERNATIVE", - "priority": 20, - "autheticatorFlow": true, - "flowAlias": "Handle Existing Account", - "userSetupAllowed": false - } - ] - }, - { - "id": "9f1e5e63-8f23-4aa4-93b0-1342ab9f7457", - "alias": "Verify Existing Account by Re-authentication", - "description": "Reauthentication of existing account", - "providerId": "basic-flow", - "topLevel": false, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "idp-username-password-form", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 10, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticatorFlow": true, - "requirement": "CONDITIONAL", - "priority": 20, - "autheticatorFlow": true, - "flowAlias": "First broker login - Conditional OTP", - "userSetupAllowed": false - } - ] - }, - { - "id": "2a2a57e7-5d9b-4fc8-b19d-49c1d7139066", - "alias": "browser", - "description": "browser based authentication", - "providerId": "basic-flow", - "topLevel": true, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "auth-cookie", - "authenticatorFlow": false, - "requirement": "ALTERNATIVE", - "priority": 10, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticator": "auth-spnego", - "authenticatorFlow": false, - "requirement": "DISABLED", - "priority": 20, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticator": "identity-provider-redirector", - "authenticatorFlow": false, - "requirement": "ALTERNATIVE", - "priority": 25, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticatorFlow": true, - "requirement": "ALTERNATIVE", - "priority": 30, - "autheticatorFlow": true, - "flowAlias": "forms", - "userSetupAllowed": false - } - ] - }, - { - "id": "e88cef7f-d4a1-4440-a106-7e0fbdd00645", - "alias": "clients", - "description": "Base authentication for clients", - "providerId": "client-flow", - "topLevel": true, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "client-secret", - "authenticatorFlow": false, - "requirement": "ALTERNATIVE", - "priority": 10, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticator": "client-jwt", - "authenticatorFlow": false, - "requirement": "ALTERNATIVE", - "priority": 20, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticator": "client-secret-jwt", - "authenticatorFlow": false, - "requirement": "ALTERNATIVE", - "priority": 30, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticator": "client-x509", - "authenticatorFlow": false, - "requirement": "ALTERNATIVE", - "priority": 40, - "autheticatorFlow": false, - "userSetupAllowed": false - } - ] - }, - { - "id": "8f82ec0f-c500-4b9d-949e-dd150da96a7c", - "alias": "direct grant", - "description": "OpenID Connect Resource Owner Grant", - "providerId": "basic-flow", - "topLevel": true, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "direct-grant-validate-username", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 10, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticator": "direct-grant-validate-password", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 20, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticatorFlow": true, - "requirement": "CONDITIONAL", - "priority": 30, - "autheticatorFlow": true, - "flowAlias": "Direct Grant - Conditional OTP", - "userSetupAllowed": false - } - ] - }, - { - "id": "3748c4de-cef7-4468-909d-8a313dfb431e", - "alias": "docker auth", - "description": "Used by Docker clients to authenticate against the IDP", - "providerId": "basic-flow", - "topLevel": true, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "docker-http-basic-authenticator", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 10, - "autheticatorFlow": false, - "userSetupAllowed": false - } - ] - }, - { - "id": "ff3038f8-973f-4b25-8d6b-ccef01436c1f", - "alias": "first broker login", - "description": "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", - "providerId": "basic-flow", - "topLevel": true, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticatorConfig": "review profile config", - "authenticator": "idp-review-profile", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 10, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticatorFlow": true, - "requirement": "REQUIRED", - "priority": 20, - "autheticatorFlow": true, - "flowAlias": "User creation or linking", - "userSetupAllowed": false - } - ] - }, - { - "id": "b9901ad9-de60-4706-bc65-d42dedeebe72", - "alias": "forms", - "description": "Username, password, otp and other auth forms.", - "providerId": "basic-flow", - "topLevel": false, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "auth-username-password-form", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 10, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticatorFlow": true, - "requirement": "CONDITIONAL", - "priority": 20, - "autheticatorFlow": true, - "flowAlias": "Browser - Conditional OTP", - "userSetupAllowed": false - } - ] - }, - { - "id": "785d3b56-c43c-4847-9f8d-21b17c836db6", - "alias": "http challenge", - "description": "An authentication flow based on challenge-response HTTP Authentication Schemes", - "providerId": "basic-flow", - "topLevel": true, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "no-cookie-redirect", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 10, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticatorFlow": true, - "requirement": "REQUIRED", - "priority": 20, - "autheticatorFlow": true, - "flowAlias": "Authentication Options", - "userSetupAllowed": false - } - ] - }, - { - "id": "76d827a5-aa26-465d-b6e7-e4d50c2c8411", - "alias": "registration", - "description": "registration flow", - "providerId": "basic-flow", - "topLevel": true, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "registration-page-form", - "authenticatorFlow": true, - "requirement": "REQUIRED", - "priority": 10, - "autheticatorFlow": true, - "flowAlias": "registration form", - "userSetupAllowed": false - } - ] - }, - { - "id": "7cae6704-c7f9-4b23-aadd-d284212e59c2", - "alias": "registration form", - "description": "registration form", - "providerId": "form-flow", - "topLevel": false, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "registration-user-creation", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 20, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticator": "registration-profile-action", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 40, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticator": "registration-password-action", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 50, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticator": "registration-recaptcha-action", - "authenticatorFlow": false, - "requirement": "DISABLED", - "priority": 60, - "autheticatorFlow": false, - "userSetupAllowed": false - } - ] - }, - { - "id": "044f6d18-da73-4e57-8630-9b59574f37d5", - "alias": "reset credentials", - "description": "Reset credentials for a user if they forgot their password or something", - "providerId": "basic-flow", - "topLevel": true, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "reset-credentials-choose-user", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 10, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticator": "reset-credential-email", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 20, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticator": "reset-password", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 30, - "autheticatorFlow": false, - "userSetupAllowed": false - }, - { - "authenticatorFlow": true, - "requirement": "CONDITIONAL", - "priority": 40, - "autheticatorFlow": true, - "flowAlias": "Reset - Conditional OTP", - "userSetupAllowed": false - } - ] - }, - { - "id": "60a2f447-7adc-4435-af35-09d0ae1ecc74", - "alias": "saml ecp", - "description": "SAML ECP Profile Authentication Flow", - "providerId": "basic-flow", - "topLevel": true, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "http-basic-authenticator", - "authenticatorFlow": false, - "requirement": "REQUIRED", - "priority": 10, - "autheticatorFlow": false, - "userSetupAllowed": false - } - ] - } - ], - "authenticatorConfig": [ - { - "id": "a99dfea2-6b1e-40ca-a9dc-9d8774b5fbc9", - "alias": "create unique user config", - "config": { - "require.password.update.after.registration": "false" - } - }, - { - "id": "6ae86ffc-aa86-413c-b62a-3f976ad9f312", - "alias": "review profile config", - "config": { - "update.profile.on.first.login": "missing" - } - } - ], - "requiredActions": [ - { - "alias": "CONFIGURE_TOTP", - "name": "Configure OTP", - "providerId": "CONFIGURE_TOTP", - "enabled": true, - "defaultAction": false, - "priority": 10, - "config": {} - }, - { - "alias": "terms_and_conditions", - "name": "Terms and Conditions", - "providerId": "terms_and_conditions", - "enabled": false, - "defaultAction": false, - "priority": 20, - "config": {} - }, - { - "alias": "UPDATE_PASSWORD", - "name": "Update Password", - "providerId": "UPDATE_PASSWORD", - "enabled": true, - "defaultAction": false, - "priority": 30, - "config": {} - }, - { - "alias": "UPDATE_PROFILE", - "name": "Update Profile", - "providerId": "UPDATE_PROFILE", - "enabled": true, - "defaultAction": false, - "priority": 40, - "config": {} - }, - { - "alias": "VERIFY_EMAIL", - "name": "Verify Email", - "providerId": "VERIFY_EMAIL", - "enabled": true, - "defaultAction": false, - "priority": 50, - "config": {} - }, - { - "alias": "delete_account", - "name": "Delete Account", - "providerId": "delete_account", - "enabled": false, - "defaultAction": false, - "priority": 60, - "config": {} - }, - { - "alias": "update_user_locale", - "name": "Update User Locale", - "providerId": "update_user_locale", - "enabled": true, - "defaultAction": false, - "priority": 1000, - "config": {} - } - ], - "browserFlow": "browser", - "registrationFlow": "registration", - "directGrantFlow": "direct grant", - "resetCredentialsFlow": "reset credentials", - "clientAuthenticationFlow": "clients", - "dockerAuthenticationFlow": "docker auth", - "attributes": { - "cibaBackchannelTokenDeliveryMode": "poll", - "cibaExpiresIn": "120", - "cibaAuthRequestedUserHint": "login_hint", - "oauth2DeviceCodeLifespan": "600", - "clientOfflineSessionMaxLifespan": "0", - "oauth2DevicePollingInterval": "5", - "clientSessionIdleTimeout": "0", - "userProfileEnabled": "false", - "parRequestUriLifespan": "60", - "clientSessionMaxLifespan": "0", - "clientOfflineSessionIdleTimeout": "0", - "cibaInterval": "5" - }, - "keycloakVersion": "18.0.0", - "userManagedAccessAllowed": false, - "clientProfiles": { - "profiles": [] - }, - "clientPolicies": { - "policies": [] - } -} \ No newline at end of file diff --git a/backend-application/src/main/resources/application-local.yml b/backend-application/src/main/resources/application-local.yml deleted file mode 100644 index fc76ea1..0000000 --- a/backend-application/src/main/resources/application-local.yml +++ /dev/null @@ -1,22 +0,0 @@ - -## Spring embedded webserver -server: - port: 9090 - error: - whitelabel: - enabled: false - -spring: - ## Spring datasource config - datasource: - url: jdbc:h2:mem:testdb - username: admin - password: - # H2 specific - h2: - console: - enabled: true - jpa: - hibernate: - ddl-auto: create-drop - open-in-view: false \ No newline at end of file diff --git a/backend-application/src/main/resources/application.yml b/backend-application/src/main/resources/application.yml index b8eda29..24fb03a 100644 --- a/backend-application/src/main/resources/application.yml +++ b/backend-application/src/main/resources/application.yml @@ -1,46 +1,23 @@ +server: + port: 8081 spring: application: - name: tribune - mvc: - throw-exception-if-no-handler-found: true - -management: - endpoints: - web: - exposure: - include: * - -#keycloak user client properties -keycloak: - auth-server-url: http://${host}:8080/auth/ - realm: tribune - resource: tribune-user - credentials: - secret: ${keycloak.credentials.secret} - ssl-required: external - principal-attribute: preferred_username - use-resource-role-mappings: true - bearer-only: true - -#keycloak.policy-enforcer-config.enforcement-mode=ENFORCING - -#keycloak admin client properties -tribune: - keycloak: - client: - user-management: - resource: tribune-user-management - client-secret: oT9cm9JhbJH5owI444FxS4DPKLdIpKel - username: users.admin@paywithtribune.com - password: 1234 -#app.cors.allowed-origins=https://localhost:8880 - -#if needed for any reason by frontend -#app.cors.allowed-origins: http://localhost:port -logging: - level: - org: - keycloak: DEBUG - springframework: - security: DEBUG -#spring.jackson.serialization.fail-on-empty-beans=false \ No newline at end of file + name: ddd-application + ## Spring datasource config + datasource: + url: jdbc:h2:mem:testdb + username: admin + password: + driver-class-name: org.h2.Driver + h2: + console: + enabled: true + jpa: + hibernate: + ddl-auto: create-drop + properties: + hibernate: + dialect: org.hibernate.dialect.H2Dialect + format_sql: true + show-sql: true + open-in-view: false \ No newline at end of file diff --git a/backend-domain/pom.xml b/backend-domain/pom.xml index d058f60..ef29427 100644 --- a/backend-domain/pom.xml +++ b/backend-domain/pom.xml @@ -2,23 +2,24 @@ 4.0.0 + + backend-domain + + + UTF-8 + UTF-8 + + 11 + 11 + com.tribune backend 0.0.1-SNAPSHOT - backend-domain - - - 11 - - - org.projectlombok - lombok - org.apache.commons commons-lang3 @@ -40,6 +41,16 @@ commons-codec commons-codec + + + org.mapstruct + mapstruct + + + org.mapstruct + mapstruct-processor + + org.junit.jupiter junit-jupiter-params @@ -52,6 +63,26 @@ org.apache.maven.plugins maven-jar-plugin + + org.apache.maven.plugins + maven-compiler-plugin + + ${maven.compiler.source} + ${maven.compiler.target} + + + org.mapstruct + mapstruct-processor + ${mapstruct.version} + + + org.projectlombok + lombok + ${lombok.version} + + + + diff --git a/backend-domain/src/main/java/com/tribune/backend/domain/DomainObject.java b/backend-domain/src/main/java/com/tribune/backend/domain/DomainObject.java deleted file mode 100644 index 136061d..0000000 --- a/backend-domain/src/main/java/com/tribune/backend/domain/DomainObject.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.tribune.backend.domain; - -/** - * Indicates any movable object that somehow relates to the domain model. - * Top-level marker interface for all domain objects. - */ -public interface DomainObject { -} diff --git a/backend-domain/src/main/java/com/tribune/backend/domain/context/CustomerOrder.java b/backend-domain/src/main/java/com/tribune/backend/domain/context/CustomerOrder.java index f384e15..574977d 100644 --- a/backend-domain/src/main/java/com/tribune/backend/domain/context/CustomerOrder.java +++ b/backend-domain/src/main/java/com/tribune/backend/domain/context/CustomerOrder.java @@ -1,12 +1,14 @@ package com.tribune.backend.domain.context; -import com.tribune.backend.domain.AggregateRoot; -import com.tribune.backend.domain.dto.customer.Customer; -import com.tribune.backend.domain.dto.order.Order; +import com.tribune.backend.domain.element.AggregateRoot; +import com.tribune.backend.domain.element.customer.Customer; +import com.tribune.backend.domain.element.order.Order; +import com.tribune.backend.domain.element.order.lineitem.product.Product; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.experimental.SuperBuilder; +import java.util.List; import java.util.UUID; @Data @@ -17,4 +19,6 @@ public class CustomerOrder extends AggregateRoot { private Customer customer; private Order order; + + private Listproducts; } diff --git a/backend-domain/src/main/java/com/tribune/backend/domain/dto/SingleOrderResponse.java b/backend-domain/src/main/java/com/tribune/backend/domain/dto/SingleOrderResponse.java index 6317ca6..b861a4d 100644 --- a/backend-domain/src/main/java/com/tribune/backend/domain/dto/SingleOrderResponse.java +++ b/backend-domain/src/main/java/com/tribune/backend/domain/dto/SingleOrderResponse.java @@ -1,27 +1,22 @@ package com.tribune.backend.domain.dto; -import com.tribune.backend.domain.enums.BlogStatus; +import com.tribune.backend.domain.element.order.Order; +import com.tribune.backend.domain.element.order.lineitem.product.Product; import lombok.Builder; import lombok.Data; -import java.time.LocalDateTime; +import java.math.BigDecimal; +import java.util.List; @Data @Builder public class SingleOrderResponse { - private String id; + private Order order; - private String title; + private BigDecimal totalCost; - private String content; + private List products; - private BlogStatus status; - - private String appUser; - - private LocalDateTime creationTimestamp; - - private LocalDateTime updateTimestamp; } diff --git a/backend-domain/src/main/java/com/tribune/backend/domain/dto/PlaceOrderRequest.java b/backend-domain/src/main/java/com/tribune/backend/domain/dto/SubmitOrderRequest.java similarity index 52% rename from backend-domain/src/main/java/com/tribune/backend/domain/dto/PlaceOrderRequest.java rename to backend-domain/src/main/java/com/tribune/backend/domain/dto/SubmitOrderRequest.java index 5c219e2..3090dee 100644 --- a/backend-domain/src/main/java/com/tribune/backend/domain/dto/PlaceOrderRequest.java +++ b/backend-domain/src/main/java/com/tribune/backend/domain/dto/SubmitOrderRequest.java @@ -1,10 +1,9 @@ package com.tribune.backend.domain.dto; +import com.tribune.backend.domain.element.order.Order; import lombok.*; -import javax.validation.constraints.Min; import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; @Data @@ -12,15 +11,15 @@ import javax.validation.constraints.NotNull; @NoArgsConstructor @AllArgsConstructor @ToString -public class PlaceOrderRequest { +public class SubmitOrderRequest { - @NotNull(message = "Content is missing.") - @Min(value = 20) + @NotBlank(message = "Content is missing.") private String content; @NotNull - @NotEmpty - @NotBlank - private String user; + private Long user; + + @NotNull + private Order order; } diff --git a/backend-domain/src/main/java/com/tribune/backend/domain/dto/customer/Customer.java b/backend-domain/src/main/java/com/tribune/backend/domain/dto/customer/Customer.java deleted file mode 100644 index 5aac310..0000000 --- a/backend-domain/src/main/java/com/tribune/backend/domain/dto/customer/Customer.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.tribune.backend.domain.dto.customer; - - -import com.tribune.backend.domain.Entity; -import com.tribune.backend.domain.dto.customer.address.Address; -import com.tribune.backend.domain.dto.customer.payment.Payment; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.Setter; -import lombok.experimental.SuperBuilder; - -import java.util.List; -import java.util.UUID; - -@Getter -@Setter -@SuperBuilder -@EqualsAndHashCode(callSuper = true, onlyExplicitlyIncluded = true) -public class Customer extends Entity { - - - private UUID id; - - private String displayName; - - private String firstName; - - private String lastName; - - private CustomerState state; - - private CustomerType type; - - //todo: like Address - private List paymentList; - - private List
addressList; -} diff --git a/backend-domain/src/main/java/com/tribune/backend/domain/dto/customer/invoice/Invoice.java b/backend-domain/src/main/java/com/tribune/backend/domain/dto/customer/invoice/Invoice.java deleted file mode 100644 index e104ff3..0000000 --- a/backend-domain/src/main/java/com/tribune/backend/domain/dto/customer/invoice/Invoice.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.tribune.backend.domain.dto.customer.invoice; - - -import com.tribune.backend.domain.dto.customer.Customer; -import lombok.*; - -import java.util.UUID; - -@Setter -@Getter -@NoArgsConstructor -@AllArgsConstructor -@Builder -public class Invoice { - - private UUID id; - - private Customer customer; -} diff --git a/backend-domain/src/main/java/com/tribune/backend/domain/dto/order/Order.java b/backend-domain/src/main/java/com/tribune/backend/domain/dto/order/Order.java deleted file mode 100644 index c623a06..0000000 --- a/backend-domain/src/main/java/com/tribune/backend/domain/dto/order/Order.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.tribune.backend.domain.dto.order; - - -import com.tribune.backend.domain.Entity; -import com.tribune.backend.domain.dto.order.lineitem.LineItem; -import com.tribune.backend.domain.enums.OrderStatus; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.Setter; -import lombok.experimental.SuperBuilder; - -import java.util.List; -import java.util.UUID; - -@Setter -@Getter -@SuperBuilder -@EqualsAndHashCode(callSuper = true, onlyExplicitlyIncluded = true) -public class Order extends Entity { - - private UUID id; - - private OrderStatus status; - - private List lineItemEntities; -} diff --git a/backend-domain/src/main/java/com/tribune/backend/domain/dto/order/lineitem/LineItem.java b/backend-domain/src/main/java/com/tribune/backend/domain/dto/order/lineitem/LineItem.java deleted file mode 100644 index 55ec5db..0000000 --- a/backend-domain/src/main/java/com/tribune/backend/domain/dto/order/lineitem/LineItem.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.tribune.backend.domain.dto.order.lineitem; - - -import com.tribune.backend.domain.dto.order.Order; -import com.tribune.backend.domain.dto.order.lineitem.product.Product; -import lombok.*; - -import java.util.UUID; - -@Setter -@Getter -@NoArgsConstructor -@AllArgsConstructor -@Builder -public class LineItem { - - private UUID id; - - private Order order; - - private Product product; -} diff --git a/backend-domain/src/main/java/com/tribune/backend/domain/dto/order/lineitem/product/Product.java b/backend-domain/src/main/java/com/tribune/backend/domain/dto/order/lineitem/product/Product.java deleted file mode 100644 index c1d4a86..0000000 --- a/backend-domain/src/main/java/com/tribune/backend/domain/dto/order/lineitem/product/Product.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.tribune.backend.domain.dto.order.lineitem.product; - - -import lombok.*; - -import java.util.UUID; - -@Setter -@Getter -@NoArgsConstructor -@AllArgsConstructor -@Builder -public class Product { - - private UUID id; -} diff --git a/backend-domain/src/main/java/com/tribune/backend/domain/AggregateRoot.java b/backend-domain/src/main/java/com/tribune/backend/domain/element/AggregateRoot.java similarity index 92% rename from backend-domain/src/main/java/com/tribune/backend/domain/AggregateRoot.java rename to backend-domain/src/main/java/com/tribune/backend/domain/element/AggregateRoot.java index 7e758cb..dcd0f39 100644 --- a/backend-domain/src/main/java/com/tribune/backend/domain/AggregateRoot.java +++ b/backend-domain/src/main/java/com/tribune/backend/domain/element/AggregateRoot.java @@ -1,4 +1,4 @@ -package com.tribune.backend.domain; +package com.tribune.backend.domain.element; import lombok.experimental.SuperBuilder; diff --git a/backend-domain/src/main/java/com/tribune/backend/domain/element/DomainObject.java b/backend-domain/src/main/java/com/tribune/backend/domain/element/DomainObject.java new file mode 100644 index 0000000..6e3c901 --- /dev/null +++ b/backend-domain/src/main/java/com/tribune/backend/domain/element/DomainObject.java @@ -0,0 +1,9 @@ +package com.tribune.backend.domain.element; + +/** + * Indicates any movable element that somehow relates to the domain model. + * Top-level marker interface for all domain element. + */ +public interface DomainObject { + +} diff --git a/backend-domain/src/main/java/com/tribune/backend/domain/Entity.java b/backend-domain/src/main/java/com/tribune/backend/domain/element/Entity.java similarity index 93% rename from backend-domain/src/main/java/com/tribune/backend/domain/Entity.java rename to backend-domain/src/main/java/com/tribune/backend/domain/element/Entity.java index dddf770..bceb80f 100644 --- a/backend-domain/src/main/java/com/tribune/backend/domain/Entity.java +++ b/backend-domain/src/main/java/com/tribune/backend/domain/element/Entity.java @@ -1,6 +1,7 @@ -package com.tribune.backend.domain; +package com.tribune.backend.domain.element; import com.tribune.backend.domain.error.DomainException; +import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; import java.util.ArrayList; @@ -12,10 +13,10 @@ import java.util.Objects; * Abstract representation of Domain Entities * @param - type of identifier (use wrapper on top of primitive types) */ +@NoArgsConstructor @SuperBuilder public abstract class Entity implements IdentifiableDomainObject { - private final List domainEvents = new ArrayList<>(); private ID id; @Override @@ -23,6 +24,9 @@ public abstract class Entity implements IdentifiableDomainObject { return id; } + + private final List domainEvents = new ArrayList<>(); + public void setId(ID id) { this.id = id; } diff --git a/backend-domain/src/main/java/com/tribune/backend/domain/IdentifiableDomainObject.java b/backend-domain/src/main/java/com/tribune/backend/domain/element/IdentifiableDomainObject.java similarity index 64% rename from backend-domain/src/main/java/com/tribune/backend/domain/IdentifiableDomainObject.java rename to backend-domain/src/main/java/com/tribune/backend/domain/element/IdentifiableDomainObject.java index 217b771..cdcae7b 100644 --- a/backend-domain/src/main/java/com/tribune/backend/domain/IdentifiableDomainObject.java +++ b/backend-domain/src/main/java/com/tribune/backend/domain/element/IdentifiableDomainObject.java @@ -1,7 +1,7 @@ -package com.tribune.backend.domain; +package com.tribune.backend.domain.element; /** - * Interface for all domain objects that can be uniquely identified in some context + * Interface for all domain element that can be uniquely identified in some context * @param - type of identifier (use wrapper on top of primitive types) */ public interface IdentifiableDomainObject extends DomainObject { diff --git a/backend-domain/src/main/java/com/tribune/backend/domain/LocalEntity.java b/backend-domain/src/main/java/com/tribune/backend/domain/element/LocalEntity.java similarity index 84% rename from backend-domain/src/main/java/com/tribune/backend/domain/LocalEntity.java rename to backend-domain/src/main/java/com/tribune/backend/domain/element/LocalEntity.java index 8952d75..7ab55cf 100644 --- a/backend-domain/src/main/java/com/tribune/backend/domain/LocalEntity.java +++ b/backend-domain/src/main/java/com/tribune/backend/domain/element/LocalEntity.java @@ -1,4 +1,4 @@ -package com.tribune.backend.domain; +package com.tribune.backend.domain.element; import lombok.experimental.SuperBuilder; diff --git a/backend-domain/src/main/java/com/tribune/backend/domain/ValueObject.java b/backend-domain/src/main/java/com/tribune/backend/domain/element/ValueObject.java similarity index 66% rename from backend-domain/src/main/java/com/tribune/backend/domain/ValueObject.java rename to backend-domain/src/main/java/com/tribune/backend/domain/element/ValueObject.java index d46a3f7..d4a023c 100644 --- a/backend-domain/src/main/java/com/tribune/backend/domain/ValueObject.java +++ b/backend-domain/src/main/java/com/tribune/backend/domain/element/ValueObject.java @@ -1,7 +1,7 @@ -package com.tribune.backend.domain; +package com.tribune.backend.domain.element; /** - * Marker interface for all value objects. + * Marker interface for all value element. * Implementations of this interface are required to be immutable and * implement equals() and hashCode(). */ diff --git a/backend-domain/src/main/java/com/tribune/backend/domain/element/customer/Customer.java b/backend-domain/src/main/java/com/tribune/backend/domain/element/customer/Customer.java new file mode 100644 index 0000000..627c5d5 --- /dev/null +++ b/backend-domain/src/main/java/com/tribune/backend/domain/element/customer/Customer.java @@ -0,0 +1,63 @@ +package com.tribune.backend.domain.element.customer; + + +import com.tribune.backend.domain.element.Entity; +import com.tribune.backend.domain.element.customer.address.Address; +import com.tribune.backend.domain.element.customer.payment.Payment; +import lombok.*; +import lombok.experimental.SuperBuilder; + +import java.util.List; + + +@Getter +@Setter +@NoArgsConstructor +@SuperBuilder +@EqualsAndHashCode(callSuper = true, onlyExplicitlyIncluded = true) +public class Customer extends Entity { + + + private String id; + + + private String displayName; + + + + private String firstName; + + + + private String lastName; + + + private CustomerState state; + + + private CustomerType type; + + //todo: like Address + + + private List paymentList; + + + private List
addressList; + + @Override + public String toString() { + + return "Customer{" + + "id=" + id + + ", displayName='" + displayName + '\'' + + ", firstName='" + firstName + '\'' + + ", lastName='" + lastName + '\'' + + ", state=" + state + + ", type=" + type + + ", paymentList=" + paymentList + + ", addressList=" + addressList + + '}'; + } + +} diff --git a/backend-domain/src/main/java/com/tribune/backend/domain/dto/customer/CustomerState.java b/backend-domain/src/main/java/com/tribune/backend/domain/element/customer/CustomerState.java similarity index 73% rename from backend-domain/src/main/java/com/tribune/backend/domain/dto/customer/CustomerState.java rename to backend-domain/src/main/java/com/tribune/backend/domain/element/customer/CustomerState.java index 8c59c07..19b0206 100644 --- a/backend-domain/src/main/java/com/tribune/backend/domain/dto/customer/CustomerState.java +++ b/backend-domain/src/main/java/com/tribune/backend/domain/element/customer/CustomerState.java @@ -1,4 +1,4 @@ -package com.tribune.backend.domain.dto.customer; +package com.tribune.backend.domain.element.customer; public enum CustomerState { CREATED, diff --git a/backend-domain/src/main/java/com/tribune/backend/domain/dto/customer/CustomerType.java b/backend-domain/src/main/java/com/tribune/backend/domain/element/customer/CustomerType.java similarity index 52% rename from backend-domain/src/main/java/com/tribune/backend/domain/dto/customer/CustomerType.java rename to backend-domain/src/main/java/com/tribune/backend/domain/element/customer/CustomerType.java index 65debca..af6958c 100644 --- a/backend-domain/src/main/java/com/tribune/backend/domain/dto/customer/CustomerType.java +++ b/backend-domain/src/main/java/com/tribune/backend/domain/element/customer/CustomerType.java @@ -1,4 +1,4 @@ -package com.tribune.backend.domain.dto.customer; +package com.tribune.backend.domain.element.customer; public enum CustomerType { TRADITIONAL, diff --git a/backend-domain/src/main/java/com/tribune/backend/domain/dto/customer/address/Address.java b/backend-domain/src/main/java/com/tribune/backend/domain/element/customer/address/Address.java similarity index 60% rename from backend-domain/src/main/java/com/tribune/backend/domain/dto/customer/address/Address.java rename to backend-domain/src/main/java/com/tribune/backend/domain/element/customer/address/Address.java index 77df6a7..3531b67 100644 --- a/backend-domain/src/main/java/com/tribune/backend/domain/dto/customer/address/Address.java +++ b/backend-domain/src/main/java/com/tribune/backend/domain/element/customer/address/Address.java @@ -1,7 +1,7 @@ -package com.tribune.backend.domain.dto.customer.address; +package com.tribune.backend.domain.element.customer.address; -import com.tribune.backend.domain.ValueObject; -import com.tribune.backend.domain.dto.customer.common.Country; +import com.tribune.backend.domain.element.ValueObject; +import com.tribune.backend.domain.element.customer.common.Country; import lombok.Builder; import lombok.NonNull; import lombok.Value; diff --git a/backend-domain/src/main/java/com/tribune/backend/domain/dto/customer/address/PostalCode.java b/backend-domain/src/main/java/com/tribune/backend/domain/element/customer/address/PostalCode.java similarity index 75% rename from backend-domain/src/main/java/com/tribune/backend/domain/dto/customer/address/PostalCode.java rename to backend-domain/src/main/java/com/tribune/backend/domain/element/customer/address/PostalCode.java index cd5ab96..617405d 100644 --- a/backend-domain/src/main/java/com/tribune/backend/domain/dto/customer/address/PostalCode.java +++ b/backend-domain/src/main/java/com/tribune/backend/domain/element/customer/address/PostalCode.java @@ -1,4 +1,4 @@ -package com.tribune.backend.domain.dto.customer.address; +package com.tribune.backend.domain.element.customer.address; import lombok.NonNull; import lombok.Value; diff --git a/backend-domain/src/main/java/com/tribune/backend/domain/dto/customer/address/Street.java b/backend-domain/src/main/java/com/tribune/backend/domain/element/customer/address/Street.java similarity index 67% rename from backend-domain/src/main/java/com/tribune/backend/domain/dto/customer/address/Street.java rename to backend-domain/src/main/java/com/tribune/backend/domain/element/customer/address/Street.java index c870eca..bbec36d 100644 --- a/backend-domain/src/main/java/com/tribune/backend/domain/dto/customer/address/Street.java +++ b/backend-domain/src/main/java/com/tribune/backend/domain/element/customer/address/Street.java @@ -1,4 +1,4 @@ -package com.tribune.backend.domain.dto.customer.address; +package com.tribune.backend.domain.element.customer.address; import lombok.NonNull; import lombok.Value; diff --git a/backend-domain/src/main/java/com/tribune/backend/domain/dto/customer/common/Country.java b/backend-domain/src/main/java/com/tribune/backend/domain/element/customer/common/Country.java similarity index 70% rename from backend-domain/src/main/java/com/tribune/backend/domain/dto/customer/common/Country.java rename to backend-domain/src/main/java/com/tribune/backend/domain/element/customer/common/Country.java index f337564..b865eab 100644 --- a/backend-domain/src/main/java/com/tribune/backend/domain/dto/customer/common/Country.java +++ b/backend-domain/src/main/java/com/tribune/backend/domain/element/customer/common/Country.java @@ -1,6 +1,6 @@ -package com.tribune.backend.domain.dto.customer.common; +package com.tribune.backend.domain.element.customer.common; -import com.tribune.backend.domain.ValueObject; +import com.tribune.backend.domain.element.ValueObject; import lombok.NonNull; import lombok.Value; diff --git a/backend-domain/src/main/java/com/tribune/backend/domain/dto/customer/common/Profession.java b/backend-domain/src/main/java/com/tribune/backend/domain/element/customer/common/Profession.java similarity index 95% rename from backend-domain/src/main/java/com/tribune/backend/domain/dto/customer/common/Profession.java rename to backend-domain/src/main/java/com/tribune/backend/domain/element/customer/common/Profession.java index 4042d35..f3e6d55 100644 --- a/backend-domain/src/main/java/com/tribune/backend/domain/dto/customer/common/Profession.java +++ b/backend-domain/src/main/java/com/tribune/backend/domain/element/customer/common/Profession.java @@ -1,4 +1,4 @@ -package com.tribune.backend.domain.dto.customer.common; +package com.tribune.backend.domain.element.customer.common; public enum Profession { diff --git a/backend-domain/src/main/java/com/tribune/backend/domain/element/customer/invoice/Invoice.java b/backend-domain/src/main/java/com/tribune/backend/domain/element/customer/invoice/Invoice.java new file mode 100644 index 0000000..01cc0ed --- /dev/null +++ b/backend-domain/src/main/java/com/tribune/backend/domain/element/customer/invoice/Invoice.java @@ -0,0 +1,18 @@ +package com.tribune.backend.domain.element.customer.invoice; + + +import com.tribune.backend.domain.element.customer.Customer; +import lombok.*; + + +@Setter +@Getter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class Invoice { + + private Long id; + + private Customer customer; +} diff --git a/backend-domain/src/main/java/com/tribune/backend/domain/dto/customer/payment/Payment.java b/backend-domain/src/main/java/com/tribune/backend/domain/element/customer/payment/Payment.java similarity index 51% rename from backend-domain/src/main/java/com/tribune/backend/domain/dto/customer/payment/Payment.java rename to backend-domain/src/main/java/com/tribune/backend/domain/element/customer/payment/Payment.java index ebf43c6..b474ea7 100644 --- a/backend-domain/src/main/java/com/tribune/backend/domain/dto/customer/payment/Payment.java +++ b/backend-domain/src/main/java/com/tribune/backend/domain/element/customer/payment/Payment.java @@ -1,20 +1,20 @@ -package com.tribune.backend.domain.dto.customer.payment; +package com.tribune.backend.domain.element.customer.payment; -import com.tribune.backend.domain.LocalEntity; +import com.tribune.backend.domain.element.LocalEntity; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.experimental.SuperBuilder; -import java.util.UUID; + @Data @SuperBuilder @EqualsAndHashCode(callSuper = true, onlyExplicitlyIncluded = true) -public class Payment extends LocalEntity{ +public class Payment extends LocalEntity{ private String note; - private UUID customerId; + private Long customerId; } diff --git a/backend-domain/src/main/java/com/tribune/backend/domain/element/order/Order.java b/backend-domain/src/main/java/com/tribune/backend/domain/element/order/Order.java new file mode 100644 index 0000000..8b2aedd --- /dev/null +++ b/backend-domain/src/main/java/com/tribune/backend/domain/element/order/Order.java @@ -0,0 +1,30 @@ +package com.tribune.backend.domain.element.order; + + +import com.tribune.backend.domain.element.Entity; +import com.tribune.backend.domain.element.order.lineitem.LineItem; +import com.tribune.backend.domain.enums.OrderStatus; +import lombok.*; +import lombok.experimental.SuperBuilder; + +import javax.validation.constraints.Size; +import java.math.BigDecimal; +import java.util.List; + +@Setter +@Getter +@ToString +@SuperBuilder +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true, onlyExplicitlyIncluded = true) +public class Order extends Entity { + + private Long id; + + private OrderStatus status; + + @Size(min = 1) + private List lineItems; + + private BigDecimal payment; +} diff --git a/backend-domain/src/main/java/com/tribune/backend/domain/element/order/lineitem/LineItem.java b/backend-domain/src/main/java/com/tribune/backend/domain/element/order/lineitem/LineItem.java new file mode 100644 index 0000000..154fcbf --- /dev/null +++ b/backend-domain/src/main/java/com/tribune/backend/domain/element/order/lineitem/LineItem.java @@ -0,0 +1,21 @@ +package com.tribune.backend.domain.element.order.lineitem; + + +import lombok.*; + +@Setter +@Getter +@ToString +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class LineItem { + + private Long id; + + private Long order; + + private Long product; + + private Integer quantity; +} diff --git a/backend-domain/src/main/java/com/tribune/backend/domain/element/order/lineitem/product/Product.java b/backend-domain/src/main/java/com/tribune/backend/domain/element/order/lineitem/product/Product.java new file mode 100644 index 0000000..6df6b3e --- /dev/null +++ b/backend-domain/src/main/java/com/tribune/backend/domain/element/order/lineitem/product/Product.java @@ -0,0 +1,25 @@ +package com.tribune.backend.domain.element.order.lineitem.product; + + +import lombok.*; + +import java.math.BigDecimal; + +@Setter +@Getter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class Product { + + private Long id; + + private String name; + + private String company; + + private Integer quantity; + + private BigDecimal price; + +} diff --git a/backend-domain/src/main/java/com/tribune/backend/domain/enums/BlogStatus.java b/backend-domain/src/main/java/com/tribune/backend/domain/enums/BlogStatus.java deleted file mode 100644 index 11ad88c..0000000 --- a/backend-domain/src/main/java/com/tribune/backend/domain/enums/BlogStatus.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.tribune.backend.domain.enums; - -public enum BlogStatus { - CREATED,APPROVED,DECLINED,SETTLED; -} diff --git a/backend-domain/src/main/java/com/tribune/backend/domain/error/CustomerInvalidStateException.java b/backend-domain/src/main/java/com/tribune/backend/domain/error/CustomerInvalidStateException.java new file mode 100644 index 0000000..28ea671 --- /dev/null +++ b/backend-domain/src/main/java/com/tribune/backend/domain/error/CustomerInvalidStateException.java @@ -0,0 +1,8 @@ +package com.tribune.backend.domain.error; + +public class CustomerInvalidStateException extends RuntimeException{ + + public CustomerInvalidStateException(String message) { + super(message); + } +} diff --git a/backend-domain/src/main/java/com/tribune/backend/domain/error/ProductNotAvailableException.java b/backend-domain/src/main/java/com/tribune/backend/domain/error/ProductNotAvailableException.java new file mode 100644 index 0000000..7978e1c --- /dev/null +++ b/backend-domain/src/main/java/com/tribune/backend/domain/error/ProductNotAvailableException.java @@ -0,0 +1,8 @@ +package com.tribune.backend.domain.error; + +public class ProductNotAvailableException extends RuntimeException{ + + public ProductNotAvailableException(String message) { + super(message); + } +} diff --git a/backend-domain/src/main/java/com/tribune/backend/domain/error/QuantityNotPermittedException.java b/backend-domain/src/main/java/com/tribune/backend/domain/error/QuantityNotPermittedException.java new file mode 100644 index 0000000..632ee31 --- /dev/null +++ b/backend-domain/src/main/java/com/tribune/backend/domain/error/QuantityNotPermittedException.java @@ -0,0 +1,8 @@ +package com.tribune.backend.domain.error; + +public class QuantityNotPermittedException extends RuntimeException{ + + public QuantityNotPermittedException(String message) { + super(message); + } +} diff --git a/backend-domain/src/main/java/com/tribune/backend/domain/service/CustomerRepositoryAdapter.java b/backend-domain/src/main/java/com/tribune/backend/domain/service/CustomerRepositoryAdapter.java index 0d42dfb..d8962ba 100644 --- a/backend-domain/src/main/java/com/tribune/backend/domain/service/CustomerRepositoryAdapter.java +++ b/backend-domain/src/main/java/com/tribune/backend/domain/service/CustomerRepositoryAdapter.java @@ -1,13 +1,13 @@ package com.tribune.backend.domain.service; -import com.tribune.backend.domain.dto.customer.Customer; +import com.tribune.backend.domain.element.customer.Customer; import java.util.List; import java.util.UUID; /** * Please note that adapter implementation should NOT contain any business logic. - * All operations with Domain objects should be initiated and encapsulated only in domain module + * All operations with Domain element should be initiated and encapsulated only in domain module */ public interface CustomerRepositoryAdapter { diff --git a/backend-domain/src/main/java/com/tribune/backend/domain/service/PlaceOrderAdapter.java b/backend-domain/src/main/java/com/tribune/backend/domain/service/PlaceOrderAdapter.java new file mode 100644 index 0000000..c522f86 --- /dev/null +++ b/backend-domain/src/main/java/com/tribune/backend/domain/service/PlaceOrderAdapter.java @@ -0,0 +1,10 @@ +package com.tribune.backend.domain.service; + +import com.tribune.backend.domain.context.CustomerOrder; +import com.tribune.backend.domain.dto.SingleOrderResponse; + +public interface PlaceOrderAdapter { + + + SingleOrderResponse validateOrder(CustomerOrder customerOrder); +} diff --git a/backend-domain/src/main/java/com/tribune/backend/domain/service/PlaceOrderAdapterImpl.java b/backend-domain/src/main/java/com/tribune/backend/domain/service/PlaceOrderAdapterImpl.java new file mode 100644 index 0000000..0fcb79d --- /dev/null +++ b/backend-domain/src/main/java/com/tribune/backend/domain/service/PlaceOrderAdapterImpl.java @@ -0,0 +1,83 @@ +package com.tribune.backend.domain.service; + + +import com.tribune.backend.domain.context.CustomerOrder; +import com.tribune.backend.domain.dto.SingleOrderResponse; +import com.tribune.backend.domain.element.customer.Customer; +import com.tribune.backend.domain.element.customer.CustomerState; +import com.tribune.backend.domain.element.order.Order; +import com.tribune.backend.domain.element.order.lineitem.LineItem; +import com.tribune.backend.domain.element.order.lineitem.product.Product; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; +import org.springframework.web.server.ResponseStatusException; + +import java.math.BigDecimal; +import java.util.List; + + +@Slf4j +@Service +public class PlaceOrderAdapterImpl implements PlaceOrderAdapter { + + + //execute a business case + @Override + public SingleOrderResponse validateOrder(CustomerOrder customerOrder) { + + log.info("validating CustomerOrder - {}", customerOrder); + List products = customerOrder.getProducts(); + + Order order = customerOrder.getOrder(); + + validateCustomer(customerOrder.getCustomer()); + + double totalCost = 0.0; + + + + + for (LineItem lineItem : order.getLineItems()) { + + Product product = products.stream().filter(p -> p.getId().equals(lineItem.getProduct())) + .findFirst().orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST, + String.format("No product available with this id [%s].", lineItem.getProduct()))); + //calculate costs + totalCost += product.getPrice().doubleValue() * lineItem.getQuantity(); + + //check for requested quantities + if (lineItem.getQuantity() <= product.getQuantity()) { + //subtract the quantity + product.setQuantity(product.getQuantity() - lineItem.getQuantity()); + + } else { + String error = String.format("Available quantity for product [%s] is %d, requested quantity was %d." + , product.getName(), product.getQuantity(), lineItem.getQuantity()); + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, error); + } + } + + //process payment + + if (order.getPayment().doubleValue() < totalCost) { + String error = String.format("Total cost for order is %s, provided payment was %s." + , totalCost, order.getPayment()); + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, error); + } + + return SingleOrderResponse.builder() + .order(order) + .totalCost(BigDecimal.valueOf(totalCost)) + .products(products) + .build(); + } + + private void validateCustomer(Customer customer) { + if (!customer.getState().equals(CustomerState.ACTIVE)) { + throw new ResponseStatusException(HttpStatus.FORBIDDEN, String.format("Customer state invalid - %s", customer.getState())); + } + } + + +} diff --git a/backend-infrastructure/pom.xml b/backend-infrastructure/pom.xml index 440dee8..599585c 100644 --- a/backend-infrastructure/pom.xml +++ b/backend-infrastructure/pom.xml @@ -58,28 +58,12 @@ org.springframework.boot spring-boot-starter-data-jpa - - org.postgresql - postgresql - runtime - - - org.springframework.boot - spring-boot-starter-security + com.h2database + h2 + compile - - org.keycloak - keycloak-spring-boot-starter - - - org.keycloak - keycloak-admin-client - - - - @@ -93,22 +77,6 @@ - - - - - - - - - - - - - - - - ${project.groupId} diff --git a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/config/AppConfig.java b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/config/AppConfig.java deleted file mode 100644 index 7123d4c..0000000 --- a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/config/AppConfig.java +++ /dev/null @@ -1,80 +0,0 @@ -package com.tribune.backend.infrastructure.config; - -import com.tribune.backend.domain.dto.GenericResponse; -import com.tribune.backend.infrastructure.config.security.SecurityConfig; -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.JsonSerializer; -import com.fasterxml.jackson.databind.SerializerProvider; -import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver; -import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import javax.ws.rs.core.Response; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import static javax.ws.rs.core.Response.Status.Family.SUCCESSFUL; - -/** - * top tier config file : a config for configs - * can log responses as following: - * - * ObjectMapper mapper=new ObjectMapper(); - * mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS,false); - * - * ... mapper.writeValueAsString(value) - **/ -@Configuration -public class AppConfig { - - /** - * Fix cycle dependency formed by {@link org.keycloak.adapters.KeycloakConfigResolver} - * if specified within {@link SecurityConfig} - **/ - @Bean - public KeycloakSpringBootConfigResolver keycloakConfigResolver() { - return new KeycloakSpringBootConfigResolver(); - } - - @Bean - public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() { - - return builder -> { - JsonSerializer jsonSerializer = new JsonSerializer<>() { - @Override - public void serialize(Response value, JsonGenerator gen, SerializerProvider serializers) throws IOException { - - String message = value.getStatusInfo().getFamily().equals(SUCCESSFUL) ? "Success" : "Error"; - List reason = new ArrayList<>(); - Object data = null; - switch (value.getStatusInfo().getStatusCode()) { - case 409: - reason.add("Email/username already exists!"); - break; - case 201: - //returns as a result of newly generated resources - //returns a URL that ends with the newly created resource id - //"http://localhost:8080/auth/admin/realms/tribune/users/b61adfce-ffe6-4d68-9169-0c476ae11179" - data = value.getLocation(); - break; - } - reason.add(value.getStatusInfo().getReasonPhrase()); - - GenericResponse response = GenericResponse.builder() - .data(data) - .code(value.getStatus()) - .message(message) - .reason(reason) - .build(); - - gen.writePOJO(response); - - } - }; - - builder.serializerByType(Response.class, jsonSerializer); - }; - } -} diff --git a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/config/security/CorsConfig.java b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/config/security/CorsConfig.java deleted file mode 100644 index e40565a..0000000 --- a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/config/security/CorsConfig.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.tribune.backend.infrastructure.config.security; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.cors.CorsConfiguration; -import org.springframework.web.cors.UrlBasedCorsConfigurationSource; -import org.springframework.web.filter.CorsFilter; - -import java.util.Collections; -import java.util.List; - -@Configuration -public class CorsConfig { - -// @Value("${app.cors.allowed-origins}") -// private List allowedOrigins; -// -// @Bean -// CorsFilter corsFilter() { -// UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); -// CorsConfiguration config = new CorsConfiguration(); -// config.setAllowCredentials(true); -// config.setAllowedOrigins(allowedOrigins); -// config.setAllowedMethods(Collections.singletonList("*")); -// config.setAllowedHeaders(Collections.singletonList("*")); -// source.registerCorsConfiguration("/**", config); -// return new CorsFilter(source); -// } -} \ No newline at end of file diff --git a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/config/security/CredentialsUtils.java b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/config/security/CredentialsUtils.java deleted file mode 100644 index 2cff08f..0000000 --- a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/config/security/CredentialsUtils.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.tribune.backend.infrastructure.config.security; - -import org.keycloak.representations.idm.CredentialRepresentation; - -public class CredentialsUtils { - - private CredentialsUtils(){} - - public static CredentialRepresentation createPasswordCredentials(String password) { - CredentialRepresentation passwordCredentials = new CredentialRepresentation(); - passwordCredentials.setTemporary(false); - passwordCredentials.setType(CredentialRepresentation.PASSWORD); - passwordCredentials.setValue(password); - return passwordCredentials; - } -} diff --git a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/config/security/CustomFilter.java b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/config/security/CustomFilter.java deleted file mode 100644 index 6f13c84..0000000 --- a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/config/security/CustomFilter.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.tribune.backend.infrastructure.config.security; - -import lombok.extern.slf4j.Slf4j; -import org.springframework.web.filter.GenericFilterBean; - -import javax.servlet.*; -import java.io.IOException; - - -@Slf4j -public class CustomFilter extends GenericFilterBean { - - @Override - public void doFilter( - ServletRequest request, - ServletResponse response, - FilterChain chain) throws IOException, ServletException { - log.error("XXX"); - chain.doFilter(request, response); - } -} diff --git a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/config/security/KeycloakConfigProperties.java b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/config/security/KeycloakConfigProperties.java deleted file mode 100644 index bd1e808..0000000 --- a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/config/security/KeycloakConfigProperties.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.tribune.backend.infrastructure.config.security; - - -import lombok.Getter; -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; -import org.jboss.resteasy.client.jaxrs.ResteasyClient; -import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder; -import org.keycloak.OAuth2Constants; -import org.keycloak.admin.client.KeycloakBuilder; -import org.keycloak.admin.client.resource.UsersResource; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.context.properties.ConfigurationProperties; - -@Slf4j -@Getter -@Setter -@ConfigurationProperties(prefix = "tribune.keycloak.client.user-management") -public class KeycloakConfigProperties { - - @Value("${keycloak.auth-server-url}") - private String authServerUrl; - @Value("${keycloak.realm}") - private String realm; - private String resource; - private String clientSecret; - private String username; - private String password; - - public UsersResource getInstance(){ - ResteasyClient resteasyClient=new ResteasyClientBuilder() - .connectionPoolSize(10) - .build(); - return KeycloakBuilder.builder() - .serverUrl(authServerUrl) - .realm(realm) - .grantType(OAuth2Constants.PASSWORD) - .username(username) - .password(password) - .clientId(resource) - .clientSecret(clientSecret) - .resteasyClient(resteasyClient) - .build().realm(realm).users(); - } -} diff --git a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/config/security/SecurityConfig.java b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/config/security/SecurityConfig.java deleted file mode 100644 index dbd34f5..0000000 --- a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/config/security/SecurityConfig.java +++ /dev/null @@ -1,94 +0,0 @@ -package com.tribune.backend.infrastructure.config.security; - -import lombok.extern.slf4j.Slf4j; -import org.keycloak.adapters.springsecurity.KeycloakConfiguration; -import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider; -import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter; -import org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.core.Ordered; -import org.springframework.core.annotation.Order; -import org.springframework.http.HttpMethod; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.http.SessionCreationPolicy; -import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper; -import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy; -import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy; - -/** - * The {@link EnableGlobalMethodSecurity} enables direct config of role-based access - * to our controllers. See the following example: - *
{@code
- * @PreAuthorize("hasRole('USER')")
- * @GetMapping("/title)
- * public ResponseEntitygetTitle(){
- *      //
- *      return title;
- * }
- * }
- */ -@Slf4j -@Order(Ordered.HIGHEST_PRECEDENCE) -@KeycloakConfiguration -//@EnableGlobalMethodSecurity(prePostEnabled = true) -public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter { - - @Autowired - public void configureGlobal(AuthenticationManagerBuilder auth) { - KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider(); - keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper()); - auth.authenticationProvider(keycloakAuthenticationProvider); - } - - /** - * The other way around - * return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl()); - * */ - @Bean - @Override - protected SessionAuthenticationStrategy sessionAuthenticationStrategy() { - return new NullAuthenticatedSessionStrategy(); - } - - @Override - protected void configure(HttpSecurity http) throws Exception { - - super.configure(http); - // Enable CORS and disable CSRF - http - .cors() - .and() - .csrf().disable() - // Set session management to stateless - .sessionManagement() - .sessionCreationPolicy(SessionCreationPolicy.STATELESS) - .and() - .authorizeRequests() - .antMatchers(HttpMethod.GET, "/v1/transaction/status/**").hasRole(MERCHANT) - .antMatchers(HttpMethod.POST, "/v1/transaction/**").hasRole(MERCHANT) - .antMatchers(HttpMethod.POST, "/v1/users/**").anonymous() - .antMatchers(HttpMethod.GET, "/api/user-data/me", "/actuator/**").permitAll() - .antMatchers(HttpMethod.GET, "/v1/dummy/**").permitAll() - .antMatchers("/swagger-ui.html", "/swagger-ui/**", "/v3/api-docs", "/v3/api-docs/**").permitAll() - .anyRequest().fullyAuthenticated(); - } - - /** - * provided by keycloak to handle authentication failures. - * */ - @Bean - @Override - protected KeycloakAuthenticationProcessingFilter keycloakAuthenticationProcessingFilter() throws Exception { - KeycloakAuthenticationProcessingFilter filter = new KeycloakAuthenticationProcessingFilter(this.authenticationManagerBean()); - filter.setSessionAuthenticationStrategy(this.sessionAuthenticationStrategy()); - filter.setAuthenticationFailureHandler(new TribuneKeycloakAuthenticationFailureHandler()); - return filter; - } - - public static final String MERCHANT = "merchant"; - public static final String USER = "user"; - public static final String MANAGE_USERS = "manage-users"; -} \ No newline at end of file diff --git a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/config/security/TribuneKeycloakAuthenticationFailureHandler.java b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/config/security/TribuneKeycloakAuthenticationFailureHandler.java deleted file mode 100644 index 9028164..0000000 --- a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/config/security/TribuneKeycloakAuthenticationFailureHandler.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.tribune.backend.infrastructure.config.security; - -import com.tribune.backend.domain.dto.GenericResponse; -import lombok.AllArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.web.authentication.AuthenticationFailureHandler; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; - -import static org.keycloak.util.JsonSerialization.mapper; - -@Slf4j -@AllArgsConstructor -public class TribuneKeycloakAuthenticationFailureHandler implements AuthenticationFailureHandler { - - @Override - public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException ex) throws IOException { - ex.printStackTrace(); - log.error("Authentication Error: {}", ex.getMessage()); - response.setContentType(MediaType.APPLICATION_JSON_VALUE); - response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); - - //todo:check removal of WWW_AUTHENTICATE header from response - GenericResponse genericResponse = GenericResponse.builder() - .message(ex.getMessage()) - .reason(response.getHeader(HttpHeaders.WWW_AUTHENTICATE)) - .code(response.getStatus()) - .build(); - response.getWriter().write(mapper.writeValueAsString(genericResponse)); - } -} \ No newline at end of file diff --git a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/config/security/UserDTO.java b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/config/security/UserDTO.java deleted file mode 100644 index f660e74..0000000 --- a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/config/security/UserDTO.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.tribune.backend.infrastructure.config.security; - -import lombok.*; - -import javax.validation.constraints.NotBlank; - -@Getter -@Setter -@AllArgsConstructor -@NoArgsConstructor -@Builder -public class UserDTO { - - @NotBlank - private String username; - @NotBlank - private String email; - @NotBlank - private String password; - @NotBlank - private String firstName; - @NotBlank - private String lastName; -} diff --git a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/config/security/UserLoginRequest.java b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/config/security/UserLoginRequest.java deleted file mode 100644 index c5c5732..0000000 --- a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/config/security/UserLoginRequest.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.tribune.backend.infrastructure.config.security; - -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.Setter; - -import javax.validation.constraints.NotBlank; - -@Getter -@Setter -@AllArgsConstructor -@Builder -public class UserLoginRequest { - - @NotBlank - private String username; - @NotBlank - private String password; -} diff --git a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/config/security/UserManagementService.java b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/config/security/UserManagementService.java deleted file mode 100644 index fa5de92..0000000 --- a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/config/security/UserManagementService.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.tribune.backend.infrastructure.config.security; - -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.tribune.backend.domain.dto.GenericResponse; -import org.keycloak.representations.idm.UserRepresentation; - -import javax.ws.rs.core.Response; -import java.util.List; - - -public interface UserManagementService { - - Response addUser(UserDTO userDTO); - - List getUser(String userName); - - void updateUser(String userId, UserDTO userDTO); - void deleteUser(String userId); - - void sendVerificationLink(String userId); - - void sendResetPassword(String userId); - - GenericResponse authenticate(UserLoginRequest userDTO); -} diff --git a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/config/security/UserManagementServiceImpl.java b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/config/security/UserManagementServiceImpl.java deleted file mode 100644 index f86e4cb..0000000 --- a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/config/security/UserManagementServiceImpl.java +++ /dev/null @@ -1,139 +0,0 @@ -package com.tribune.backend.infrastructure.config.security; - -import com.tribune.backend.domain.dto.GenericResponse; -import com.tribune.backend.infrastructure.error.BackendException; -import com.fasterxml.jackson.databind.node.ObjectNode; -import lombok.extern.slf4j.Slf4j; -import org.keycloak.representations.idm.CredentialRepresentation; -import org.keycloak.representations.idm.UserRepresentation; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.MediaType; -import org.springframework.http.client.reactive.ReactorClientHttpConnector; -import org.springframework.stereotype.Service; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; -import org.springframework.web.reactive.function.BodyInserters; -import org.springframework.web.reactive.function.client.WebClient; -import org.springframework.web.util.UriComponentsBuilder; -import reactor.netty.http.client.HttpClient; - -import javax.ws.rs.core.Response; -import java.net.URI; -import java.time.Duration; -import java.util.Collections; -import java.util.List; - - -@Slf4j -@Service -public class UserManagementServiceImpl implements UserManagementService { - @Value("${keycloak.resource}") - private String tribuneSpringbootClient; - - private final KeycloakConfigProperties properties; - - @Autowired - public UserManagementServiceImpl(KeycloakConfigProperties properties) { - this.properties = properties; - } - - @Override - public Response addUser(UserDTO userDTO) { - CredentialRepresentation credential = CredentialsUtils - .createPasswordCredentials(userDTO.getPassword()); - - UserRepresentation user = new UserRepresentation(); - - user.setUsername(userDTO.getUsername()); - user.setFirstName(userDTO.getFirstName()); - user.setLastName(userDTO.getLastName()); - user.setEmail(userDTO.getEmail()); - user.setCredentials(Collections.singletonList(credential)); - user.setEnabled(true); - - return properties.getInstance().create(user); - } - - @Override - public List getUser(String userName) { - return properties.getInstance().search(userName, true); - } - - @Override - public void updateUser(String userId, UserDTO userDTO) { - CredentialRepresentation credential = CredentialsUtils - .createPasswordCredentials(userDTO.getPassword()); - UserRepresentation user = new UserRepresentation(); - user.setUsername(userDTO.getUsername()); - user.setFirstName(userDTO.getFirstName()); - user.setLastName(userDTO.getLastName()); - user.setEmail(userDTO.getEmail()); - user.setCredentials(Collections.singletonList(credential)); - //todo:needs confirmation - properties.getInstance().get(userId).update(user); - } - - @Override - public void deleteUser(String userId) { - //todo:needs confirmation - properties.getInstance().get(userId) - .remove(); - } - - @Override - public void sendVerificationLink(String userId) { - //todo:needs confirmation - properties.getInstance().get(userId) - .sendVerifyEmail(); - } - - @Override - public void sendResetPassword(String userId) { - //todo:needs confirmation - properties.getInstance().get(userId) - .executeActionsEmail(List.of("UPDATE_PASSWORD")); - } - - @Override - public GenericResponse authenticate(UserLoginRequest userDTO) { - URI uri=UriComponentsBuilder.fromUriString( - String.format("%s/realms/%s/protocol/openid-connect/token", - properties.getAuthServerUrl(), properties.getRealm()) - ).build().toUri(); - - HttpClient httpClient = HttpClient.create() - .responseTimeout(Duration.ofSeconds(2)); - - MultiValueMap formData = new LinkedMultiValueMap<>(); - formData.add("username", userDTO.getUsername()); - formData.add("password", userDTO.getPassword()); - formData.add("client_id", tribuneSpringbootClient); - formData.add("grant_type", CredentialRepresentation.PASSWORD); - - ObjectNode node= WebClient.builder() - .clientConnector(new ReactorClientHttpConnector(httpClient)) - .build() - .post() - .uri(uri) - .body(BodyInserters.fromFormData(formData)) - .accept(MediaType.APPLICATION_JSON) - .exchangeToMono(clientResponse -> { - if (clientResponse.statusCode().is4xxClientError()) { - log.error("error"); - return clientResponse.bodyToMono(ObjectNode.class).map(val -> { - - throw new BackendException(val, clientResponse.statusCode()); - }); - } else - return clientResponse.bodyToMono(ObjectNode.class); - }) - .block(); - - return GenericResponse.builder() - .code(200) - .message("Success!") - .data(node) - .build(); - } -} diff --git a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/controller/OrdersController.java b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/controller/OrdersController.java index 4a885d0..9e3ffde 100644 --- a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/controller/OrdersController.java +++ b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/controller/OrdersController.java @@ -1,8 +1,9 @@ package com.tribune.backend.infrastructure.controller; -import com.tribune.backend.domain.dto.PlaceOrderRequest; +import com.tribune.backend.domain.dto.SubmitOrderRequest; import com.tribune.backend.domain.dto.GenericResponse; import com.tribune.backend.domain.dto.SingleOrderResponse; +import com.tribune.backend.infrastructure.error.NotFoundException; import com.tribune.backend.infrastructure.services.OrderService; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -18,13 +19,17 @@ public class OrdersController { private final OrderService orderService; - @PostMapping("/order") - public GenericResponse createBlog(@Valid @RequestBody PlaceOrderRequest createOrderRequest) { + @PostMapping("/submitOrder") + public GenericResponse placeOrder(@Valid @RequestBody SubmitOrderRequest createOrderRequest) throws NotFoundException { + + SingleOrderResponse orderResponse=orderService.processOrder(createOrderRequest); + return GenericResponse.builder() .code(201) - .data(orderService.placeOrder(createOrderRequest)) + .data(orderResponse) .message("Created!") .build(); } + } diff --git a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/controller/UserController.java b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/controller/UserController.java deleted file mode 100644 index 4649b68..0000000 --- a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/controller/UserController.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.tribune.backend.infrastructure.controller; - - -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.tribune.backend.domain.dto.GenericResponse; -import com.tribune.backend.infrastructure.config.security.UserDTO; -import com.tribune.backend.infrastructure.config.security.UserLoginRequest; -import com.tribune.backend.infrastructure.config.security.UserManagementService; -import lombok.AllArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.keycloak.representations.idm.UserRepresentation; -import org.springframework.web.bind.annotation.*; - -import javax.validation.Valid; -import javax.ws.rs.core.Response; -import java.util.List; - -@Slf4j -@AllArgsConstructor -@RestController -@RequestMapping(path = "/v1/users") -public class UserController { - private final UserManagementService service; - - - @PostMapping("/user/auth") - public GenericResponse authenticate(@Valid @RequestBody UserLoginRequest userDTO){ - return service.authenticate(userDTO); - } - - @PostMapping("/user") - public Response addUser(@Valid @RequestBody UserDTO userDTO){ - return service.addUser(userDTO); - } - - @GetMapping(path = "/user/{userName}") - public List getUser(@PathVariable("userName") String userName){ - return service.getUser(userName); - } - - @PutMapping(path = "/user/{userId}") - public String updateUser(@PathVariable("userId") String userId, @RequestBody UserDTO userDTO){ - service.updateUser(userId, userDTO); - return "User Details Updated Successfully."; - } - - @DeleteMapping(path = "/user/{userId}") - public String deleteUser(@PathVariable("userId") String userId){ - service.deleteUser(userId); - return "User Deleted Successfully."; - } - - @GetMapping(path = "/user/verify/{userId}") - public String sendVerificationLink(@PathVariable("userId") String userId){ - service.sendVerificationLink(userId); - return "Verification Link Send to Registered E-mail Id."; - } - - @GetMapping(path = "/user/reset-password/{userId}") - public String sendResetPasswordLink(@PathVariable("userId") String userId){ - service.sendResetPassword(userId); - return "Reset Password Link Send Successfully to Registered E-mail Id."; - } -} diff --git a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/db/DevBootstrap.java b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/db/DevBootstrap.java new file mode 100644 index 0000000..b734059 --- /dev/null +++ b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/db/DevBootstrap.java @@ -0,0 +1,87 @@ +package com.tribune.backend.infrastructure.db; + + +import com.tribune.backend.domain.element.customer.CustomerState; +import com.tribune.backend.domain.element.customer.CustomerType; +import com.tribune.backend.infrastructure.db.entities.CustomerEntity; +import com.tribune.backend.infrastructure.db.entities.ProductEntity; +import com.tribune.backend.infrastructure.db.repository.CustomerRepository; +import com.tribune.backend.infrastructure.db.repository.ProductRepository; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.CommandLineRunner; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.math.BigDecimal; +import java.util.List; + + +@Slf4j +@Transactional +@AllArgsConstructor +@Component +public class DevBootstrap implements CommandLineRunner { + + private CustomerRepository customerRepository; + private ProductRepository productRepository; + + + @Override + public void run(String... args) { + + initCustomers(); + initProducts(); + } + + public void initCustomers() { + customerRepository.deleteAll(); + CustomerEntity customer0 = CustomerEntity.builder() + .firstName("John") + .lastName("Doe") + .type(CustomerType.TRADITIONAL) + .displayName("Failure") + .state(CustomerState.ACTIVE) + .build(); + CustomerEntity customer1 = CustomerEntity.builder() + .firstName("Bill") + .lastName("Gates") + .type(CustomerType.TRADITIONAL) + .displayName("Billy the beast") + .state(CustomerState.DISABLED) + .build(); + + customerRepository.saveAll(List.of(customer0, customer1)); + } + + public void initProducts() { + productRepository.deleteAll(); + ProductEntity product0 = ProductEntity.builder() + .name("Samsung Galaxy S23") + .company("Samsung") + .price(BigDecimal.valueOf(3112.50)) + .quantity(15) + .build(); + ProductEntity product1 = ProductEntity.builder() + .name("Iphone 14 pro max") + .company("Apple") + .price(BigDecimal.valueOf(2000)) + .quantity(5) + .build(); + ProductEntity product2 = ProductEntity.builder() + .name("Xiaomi Note 11") + .company("Xiaomi") + .price(BigDecimal.valueOf(800)) + .quantity(22) + .build(); + ProductEntity product3 = ProductEntity.builder() + .name("Nokia whatever") + .company("Nokia") + .price(BigDecimal.valueOf(1500)) + .quantity(82) + .build(); + + productRepository.saveAll(List.of(product0, product1, product2, product3)); + + } +} diff --git a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/db/entities/AddressEntity.java b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/db/entities/AddressEntity.java index 44db402..9f1bddd 100644 --- a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/db/entities/AddressEntity.java +++ b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/db/entities/AddressEntity.java @@ -2,11 +2,11 @@ package com.tribune.backend.infrastructure.db.entities; import lombok.*; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; +import javax.persistence.*; +import java.time.LocalDateTime; import java.util.UUID; @@ -16,13 +16,21 @@ import java.util.UUID; @AllArgsConstructor @Builder @Entity +@Table(name ="ADDRESS") public class AddressEntity { @Id - private UUID id; + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name = "CUSTOMER") + private UUID customer; - @ManyToOne - @JoinColumn(name = "customer",referencedColumnName = "id") - private CustomerEntity customerEntity; + @CreationTimestamp + @Column(name = "CREATION_TIMESTAMP",nullable = false,updatable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP") + private LocalDateTime creationTimestamp; + + @UpdateTimestamp + @Column(name = "UPDATE_TIMESTAMP",nullable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP") + private LocalDateTime updateTimestamp; } diff --git a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/db/entities/CustomerEntity.java b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/db/entities/CustomerEntity.java index 74848cd..4fb4c9d 100644 --- a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/db/entities/CustomerEntity.java +++ b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/db/entities/CustomerEntity.java @@ -1,13 +1,15 @@ package com.tribune.backend.infrastructure.db.entities; -import com.tribune.backend.domain.dto.customer.CustomerState; -import com.tribune.backend.domain.dto.customer.CustomerType; +import com.tribune.backend.domain.element.customer.CustomerState; +import com.tribune.backend.domain.element.customer.CustomerType; import lombok.*; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; import javax.persistence.*; +import java.time.LocalDateTime; import java.util.List; -import java.util.UUID; @Setter @Getter @@ -15,10 +17,12 @@ import java.util.UUID; @AllArgsConstructor @Builder @Entity +@Table(name ="CUSTOMER") public class CustomerEntity { @Id - private UUID id; + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; private String displayName; @@ -32,9 +36,20 @@ public class CustomerEntity { @Enumerated(value = EnumType.STRING) private CustomerType type; - @OneToMany(mappedBy = "customerEntity", fetch = FetchType.LAZY) + @OneToMany(mappedBy = "customer", fetch = FetchType.LAZY) private List paymentEntityList; - @OneToMany(mappedBy = "customerEntity", fetch = FetchType.LAZY) + @OneToMany(mappedBy = "customer", fetch = FetchType.LAZY) private List addressEntityList; + + @OneToMany(mappedBy = "customer", fetch = FetchType.LAZY) + private List invoiceEntityList; + + @CreationTimestamp + @Column(name = "CREATION_TIMESTAMP",nullable = false,updatable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP") + private LocalDateTime creationTimestamp; + + @UpdateTimestamp + @Column(name = "UPDATE_TIMESTAMP",nullable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP") + private LocalDateTime updateTimestamp; } diff --git a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/db/entities/InvoiceEntity.java b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/db/entities/InvoiceEntity.java index f3544b5..f5d494f 100644 --- a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/db/entities/InvoiceEntity.java +++ b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/db/entities/InvoiceEntity.java @@ -2,10 +2,11 @@ package com.tribune.backend.infrastructure.db.entities; import lombok.*; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.ManyToOne; +import javax.persistence.*; +import java.time.LocalDateTime; import java.util.UUID; @Setter @@ -14,13 +15,23 @@ import java.util.UUID; @AllArgsConstructor @Builder @Entity +@Table(name = "INVOICE") public class InvoiceEntity { @Id - private UUID id; + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; - @ManyToOne - private CustomerEntity customerEntity; + @Column(name = "CUSTOMER") + private UUID customer; + + @CreationTimestamp + @Column(name = "CREATION_TIMESTAMP", nullable = false, updatable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP") + private LocalDateTime creationTimestamp; + + @UpdateTimestamp + @Column(name = "UPDATE_TIMESTAMP", nullable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP") + private LocalDateTime updateTimestamp; } diff --git a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/db/entities/LineItemEntity.java b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/db/entities/LineItemEntity.java index e3b686f..8bd830b 100644 --- a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/db/entities/LineItemEntity.java +++ b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/db/entities/LineItemEntity.java @@ -12,14 +12,21 @@ import java.util.UUID; @AllArgsConstructor @Builder @Entity +@Table(name ="LINE_ITEM") public class LineItemEntity { @Id - private UUID id; + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "customer_order") + private Long customerOrder; + + + @JoinColumn(name = "product",referencedColumnName = "id") @ManyToOne - private OrderEntity orderEntity; + private ProductEntity product; - @OneToOne - private ProductEntity productEntity; + private Integer quantity; } diff --git a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/db/entities/OrderEntity.java b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/db/entities/OrderEntity.java index 0197d65..34b3d77 100644 --- a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/db/entities/OrderEntity.java +++ b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/db/entities/OrderEntity.java @@ -3,26 +3,44 @@ package com.tribune.backend.infrastructure.db.entities; import com.tribune.backend.domain.enums.OrderStatus; import lombok.*; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.DynamicUpdate; +import org.hibernate.annotations.UpdateTimestamp; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.OneToMany; +import javax.persistence.*; +import java.math.BigDecimal; +import java.time.LocalDateTime; import java.util.List; -import java.util.UUID; @Setter @Getter @NoArgsConstructor @AllArgsConstructor @Builder +@DynamicUpdate @Entity +@Table(name = "CUSTOMER_ORDER") public class OrderEntity { @Id - private UUID id; + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Enumerated(value = EnumType.STRING) private OrderStatus status; - @OneToMany - private List lineItemEntities; + @OneToMany(mappedBy = "id") + private List lineItems; + + + private BigDecimal payment; + + @CreationTimestamp + @Column(name = "CREATION_TIMESTAMP",nullable = false,updatable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP") + private LocalDateTime creationTimestamp; + + @UpdateTimestamp + @Column(name = "UPDATE_TIMESTAMP",nullable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP") + private LocalDateTime updateTimestamp; } diff --git a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/db/entities/PaymentEntity.java b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/db/entities/PaymentEntity.java index 8fdf54d..83cc129 100644 --- a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/db/entities/PaymentEntity.java +++ b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/db/entities/PaymentEntity.java @@ -2,11 +2,11 @@ package com.tribune.backend.infrastructure.db.entities; import lombok.*; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; +import javax.persistence.*; +import java.time.LocalDateTime; import java.util.UUID; @Setter @@ -15,13 +15,20 @@ import java.util.UUID; @AllArgsConstructor @Builder @Entity +@Table(name ="PAYMENT") public class PaymentEntity { @Id - private UUID id; + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name = "CUSTOMER") + private UUID customer; + @CreationTimestamp + @Column(name = "CREATION_TIMESTAMP",nullable = false,updatable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP") + private LocalDateTime creationTimestamp; - @ManyToOne - @JoinColumn(name = "customer",referencedColumnName = "id") - private CustomerEntity customerEntity; + @UpdateTimestamp + @Column(name = "UPDATE_TIMESTAMP",nullable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP") + private LocalDateTime updateTimestamp; } diff --git a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/db/entities/ProductEntity.java b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/db/entities/ProductEntity.java index e0b6b18..3090a1d 100644 --- a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/db/entities/ProductEntity.java +++ b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/db/entities/ProductEntity.java @@ -2,19 +2,42 @@ package com.tribune.backend.infrastructure.db.entities; import lombok.*; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.DynamicUpdate; +import org.hibernate.annotations.UpdateTimestamp; -import javax.persistence.Entity; -import javax.persistence.Id; -import java.util.UUID; +import javax.persistence.*; +import java.math.BigDecimal; +import java.time.LocalDateTime; @Setter @Getter +@ToString @NoArgsConstructor @AllArgsConstructor @Builder +@DynamicUpdate @Entity +@Table(name ="PRODUCT") public class ProductEntity { @Id - private UUID id; + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String name; + + private String company; + + private Integer quantity; + + private BigDecimal price; + + @CreationTimestamp + @Column(name = "CREATION_TIMESTAMP",nullable = false,updatable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP") + private LocalDateTime creationTimestamp; + + @UpdateTimestamp + @Column(name = "UPDATE_TIMESTAMP",nullable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP") + private LocalDateTime updateTimestamp; } diff --git a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/db/repository/CustomerRepository.java b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/db/repository/CustomerRepository.java index 05c93c5..aa8be38 100644 --- a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/db/repository/CustomerRepository.java +++ b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/db/repository/CustomerRepository.java @@ -5,10 +5,8 @@ import com.tribune.backend.infrastructure.db.entities.CustomerEntity; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; -import java.util.UUID; - @Repository -public interface CustomerRepository extends JpaRepository { +public interface CustomerRepository extends JpaRepository { } diff --git a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/db/repository/ProductRepository.java b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/db/repository/ProductRepository.java new file mode 100644 index 0000000..d5f33f2 --- /dev/null +++ b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/db/repository/ProductRepository.java @@ -0,0 +1,15 @@ +package com.tribune.backend.infrastructure.db.repository; + + +import com.tribune.backend.infrastructure.db.entities.ProductEntity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface ProductRepository extends JpaRepository { + + List findByIdIn(List ids); +} + diff --git a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/error/ControllerAdvisor.java b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/error/ControllerAdvisor.java new file mode 100644 index 0000000..20d0b27 --- /dev/null +++ b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/error/ControllerAdvisor.java @@ -0,0 +1,71 @@ +package com.tribune.backend.infrastructure.error; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.tribune.backend.domain.dto.GenericResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.http.converter.HttpMessageNotReadableException; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.context.request.WebRequest; +import org.springframework.web.server.ResponseStatusException; +import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; + +@Slf4j +@RestControllerAdvice +public class ControllerAdvisor extends ResponseEntityExceptionHandler { + + + @ExceptionHandler(BackendException.class) + public ResponseEntity> handleException(BackendException e) { + log.error("status:{} --- error: {}", e.getStatus(), e.getError()); + GenericResponse response = GenericResponse.builder() + .message(e.getMessage()) + .code(e.getStatus().value()) + .data(e.getError()) + .build(); + return ResponseEntity.status(e.getStatus()).body(response); + } + + @ExceptionHandler(ResponseStatusException.class) + public ResponseEntity> handleException(ResponseStatusException e) { + log.error("status:{} --- error: {}", e.getStatus(), e.getMessage()); + GenericResponse response = GenericResponse.builder() + .message(e.getReason()) + .code(e.getStatus().value()) + .build(); + return ResponseEntity.status(e.getStatus()).body(response); + } + + @Override + protected ResponseEntity handleHttpMessageNotReadable(HttpMessageNotReadableException e, HttpHeaders headers, HttpStatus status, WebRequest request) { + GenericResponse response = GenericResponse.builder() + .message(e.getMessage()) + .code(HttpStatus.BAD_REQUEST.value()) + .build(); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response); + } + + @Override + protected ResponseEntity handleMethodArgumentNotValid(MethodArgumentNotValidException e, HttpHeaders headers, HttpStatus status, WebRequest request) { + + String message = "Error occurred!"; + FieldError fieldError = e.getFieldError(); + + if (fieldError != null) { + message = String.format("[%s] %s",fieldError.getField(),fieldError.getDefaultMessage()); + } + + GenericResponse response = GenericResponse.builder() + .message(message) + .code(HttpStatus.BAD_REQUEST.value()) + .build(); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response); + } + +} diff --git a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/error/TribuneAdvisor.java b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/error/TribuneAdvisor.java deleted file mode 100644 index 65ff4b1..0000000 --- a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/error/TribuneAdvisor.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.tribune.backend.infrastructure.error; - -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.tribune.backend.domain.dto.GenericResponse; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.RestControllerAdvice; -import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; - -@Slf4j -@RestControllerAdvice -public class TribuneAdvisor extends ResponseEntityExceptionHandler { - - - @ExceptionHandler(BackendException.class) - public ResponseEntity> handleException(BackendException e) { - log.error("status:{} --- error: {}",e.getStatus(),e.getError()); - GenericResponse response=GenericResponse.builder() - .message(e.getMessage()) - .code(e.getStatus().value()) - .data(e.getError()) - .build(); - return ResponseEntity.status(e.getStatus()).body(response); - } - -} diff --git a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/mappers/CustomerMapper.java b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/mappers/CustomerMapper.java new file mode 100644 index 0000000..14fceed --- /dev/null +++ b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/mappers/CustomerMapper.java @@ -0,0 +1,14 @@ +package com.tribune.backend.infrastructure.mappers; + + +import com.tribune.backend.domain.element.customer.Customer; +import com.tribune.backend.infrastructure.db.entities.CustomerEntity; +import org.mapstruct.Mapper; + +@Mapper(componentModel = "spring") +public interface CustomerMapper { + + Customer toCustomer(CustomerEntity entity); + CustomerEntity toCustomerEntity(Customer customer); + +} diff --git a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/mappers/LineItemMapper.java b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/mappers/LineItemMapper.java new file mode 100644 index 0000000..8f79fd5 --- /dev/null +++ b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/mappers/LineItemMapper.java @@ -0,0 +1,20 @@ +package com.tribune.backend.infrastructure.mappers; + + +import com.tribune.backend.domain.element.order.lineitem.LineItem; +import com.tribune.backend.infrastructure.db.entities.LineItemEntity; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +@Mapper(componentModel = "spring") +public interface LineItemMapper { + + @Mapping(source = "product.id", target = "product") + @Mapping(source = "customerOrder", target = "order") + LineItem toLineItem(LineItemEntity entity); + + @Mapping(source = "product", target = "product.id") + @Mapping(source = "order", target = "customerOrder") + LineItemEntity toLineItemEntity(LineItem lineItem); + +} diff --git a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/mappers/OrderMapper.java b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/mappers/OrderMapper.java new file mode 100644 index 0000000..0abed35 --- /dev/null +++ b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/mappers/OrderMapper.java @@ -0,0 +1,18 @@ +package com.tribune.backend.infrastructure.mappers; + + +import com.tribune.backend.domain.element.order.Order; +import com.tribune.backend.infrastructure.db.entities.OrderEntity; +import org.mapstruct.Mapper; + +@Mapper(componentModel = "spring", uses = LineItemMapper.class) +public interface OrderMapper { + + + Order toOrder(OrderEntity entity); + + + OrderEntity toOrderEntity(Order order); + + +} diff --git a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/mappers/ProductMapper.java b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/mappers/ProductMapper.java new file mode 100644 index 0000000..ad7d0f6 --- /dev/null +++ b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/mappers/ProductMapper.java @@ -0,0 +1,14 @@ +package com.tribune.backend.infrastructure.mappers; + + +import com.tribune.backend.domain.element.order.lineitem.product.Product; +import com.tribune.backend.infrastructure.db.entities.ProductEntity; +import org.mapstruct.Mapper; + +@Mapper(componentModel = "spring") +public interface ProductMapper { + + Product toProduct(ProductEntity entity); + + ProductEntity toProductEntity(Product product); +} diff --git a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/services/OrderService.java b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/services/OrderService.java index f31dac2..3a08cef 100644 --- a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/services/OrderService.java +++ b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/services/OrderService.java @@ -3,10 +3,12 @@ package com.tribune.backend.infrastructure.services; import com.tribune.backend.domain.dto.*; import com.tribune.backend.infrastructure.db.entities.OrderEntity; +import com.tribune.backend.infrastructure.error.NotFoundException; + public interface OrderService { OrderEntity getById(String id); - SingleOrderResponse placeOrder(PlaceOrderRequest placeOrderRequest); + SingleOrderResponse processOrder(SubmitOrderRequest submitOrderRequest) throws NotFoundException; OrderEntity updateOrder(String id, UpdateOrderRequest updateOrderRequest); diff --git a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/services/OrderServiceImpl.java b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/services/OrderServiceImpl.java index b05ff1d..2cf0fc2 100644 --- a/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/services/OrderServiceImpl.java +++ b/backend-infrastructure/src/main/java/com/tribune/backend/infrastructure/services/OrderServiceImpl.java @@ -1,15 +1,49 @@ package com.tribune.backend.infrastructure.services; + +import com.tribune.backend.domain.context.CustomerOrder; import com.tribune.backend.domain.dto.*; +import com.tribune.backend.domain.element.customer.Customer; +import com.tribune.backend.domain.element.order.lineitem.LineItem; +import com.tribune.backend.domain.enums.OrderStatus; +import com.tribune.backend.domain.service.PlaceOrderAdapter; +import com.tribune.backend.infrastructure.db.entities.CustomerEntity; import com.tribune.backend.infrastructure.db.entities.OrderEntity; +import com.tribune.backend.infrastructure.db.entities.ProductEntity; +import com.tribune.backend.infrastructure.db.repository.CustomerRepository; +import com.tribune.backend.infrastructure.db.repository.OrderRepository; +import com.tribune.backend.infrastructure.db.repository.ProductRepository; +import com.tribune.backend.infrastructure.error.NotFoundException; +import com.tribune.backend.infrastructure.mappers.CustomerMapperImpl; +import com.tribune.backend.infrastructure.mappers.OrderMapperImpl; +import com.tribune.backend.infrastructure.mappers.ProductMapperImpl; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import java.util.List; +import java.util.stream.Collectors; + @Slf4j +@RequiredArgsConstructor @Service public class OrderServiceImpl implements OrderService { + private final CustomerRepository customerRepository; + private final ProductRepository productRepository; + + private final OrderRepository orderRepository; + + private final PlaceOrderAdapter adapter; + + + private final CustomerMapperImpl customerMapper; + + private final OrderMapperImpl orderMapper; + + private final ProductMapperImpl productMapper; + @Override public OrderEntity getById(String id) { @@ -17,10 +51,61 @@ public class OrderServiceImpl implements OrderService { } @Override - public SingleOrderResponse placeOrder(PlaceOrderRequest placeOrderRequest) { - return null; + public SingleOrderResponse processOrder(SubmitOrderRequest submitOrderRequest) throws NotFoundException { + + log.info("Process order - {}", submitOrderRequest); + // now I'm on infrastructure + // I need to execute a business case + // Business is executed on domain + // how will I execute this business on domain? + // I need to obtain info about this business case and transform it to domain element encapsulated within a bounded context + // then be transferred to the domain + + CustomerEntity customerEntity = customerRepository.findById(submitOrderRequest.getUser()) + .orElseThrow(() -> new NotFoundException("No customer was found by the given id")); + + + // same with product list + List ids = submitOrderRequest.getOrder().getLineItems() + .stream().map(LineItem::getProduct).collect(Collectors.toList()); + log.info("product ids:{}", ids); + List productEntities = productRepository.findByIdIn(ids); + + log.info("products - {}", productEntities); + + Customer customer = customerMapper.toCustomer(customerEntity); + + OrderEntity orderEntity = orderMapper.toOrderEntity(submitOrderRequest.getOrder()); + + orderEntity.setStatus(OrderStatus.INITIALIZED); + orderRepository.saveAndFlush(orderEntity); + + + //map the customer and the order entity to domain element + //this way we provide input verification ___here's the result after persisting to db + CustomerOrder customerOrder = CustomerOrder.builder() + .customer(customer) + .order(orderMapper.toOrder(orderEntity)) + .products(productEntities.stream().map(productMapper::toProduct).collect(Collectors.toList())) + .build(); + + //after obtaining all info here now it's time to move them to domain to be executed + + SingleOrderResponse response = adapter.validateOrder(customerOrder); + + + //persist quantities + productRepository.saveAll(response.getProducts().stream().map(productMapper::toProductEntity).collect(Collectors.toList())); + + orderEntity.setStatus(OrderStatus.SUBMITTED); + + orderRepository.save(orderEntity); + + return response; } + + //here we can update the order status case success/failure of business @Override public OrderEntity updateOrder(String id, UpdateOrderRequest updateOrderRequest) { return null; diff --git a/pom.xml b/pom.xml index 94c4e3d..6d1dd5b 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,6 @@ backend-domain - backend-api-definition backend-infrastructure backend-application @@ -19,12 +18,17 @@ UTF-8 UTF-8 + 11 11 - 2.7.0 + + 2.7.9 3.2.0 + 3.9.0 + + 1.7 - 18.0.0 + 1.5.3.Final 1.18.12 ${project.version} @@ -36,10 +40,14 @@ - org.projectlombok - lombok - ${lombok.version} - compile + org.mapstruct + mapstruct + ${mapstruct.version} + + + org.mapstruct + mapstruct-processor + ${mapstruct.version} ${project.groupId} @@ -74,17 +82,6 @@ pom import - - - org.keycloak - keycloak-spring-boot-starter - ${keycloak-version} - - - org.keycloak - keycloak-admin-client - ${keycloak-version} - @@ -104,13 +101,22 @@ + + + org.projectlombok + lombok + ${lombok.version} + true + + + org.apache.maven.plugins maven-compiler-plugin - 3.9.0 + ${maven-compiler-plugin.version} org.springframework.boot @@ -156,7 +162,7 @@ gcr.io/distroless/java:11 - tribune.jfrog.io/tribune/tribune-blogs:${project.version} + tribune.jfrog.io/tribune/ddd-initiative:${project.version}