From 644f5b15ac11f3cef0de42aaf256d876e89b3002 Mon Sep 17 00:00:00 2001 From: John Melati Date: Thu, 19 Dec 2024 13:56:23 +0100 Subject: [PATCH] feat: implement Trust Mark Definitions --- .../TrustMarkDefinitionController.kt | 60 ++++++ .../com/sphereon/oid/fed/openapi/openapi.yaml | 188 ++++++++++++++++++ .../oid/fed/persistence/Persistence.kt | 2 + .../sphereon/oid/fed/persistence/models/1.sqm | 1 + .../oid/fed/persistence/models/10.sqm | 7 + .../oid/fed/persistence/models/11.sqm | 20 +- .../sphereon/oid/fed/persistence/models/3.sqm | 14 +- .../oid/fed/persistence/models/Account.sq | 24 ++- .../fed/persistence/models/AuthorityHint.sq | 29 ++- .../oid/fed/persistence/models/Crit.sq | 30 ++- .../models/EntityConfigurationMetadata.sq | 25 ++- .../models/EntityConfigurationStatement.sq | 15 +- .../oid/fed/persistence/models/Key.sq | 20 +- .../oid/fed/persistence/models/Subordinate.sq | 34 +++- .../fed/persistence/models/SubordinateJwk.sq | 19 +- .../persistence/models/SubordinateMetadata.sq | 38 ++-- .../models/SubordinateStatement.sq | 16 -- .../persistence/models/TrustMarkDefinition.sq | 30 +++ .../Persistence.jvm.kt | 3 + .../oid/fed/services/AccountService.kt | 23 ++- .../oid/fed/services/TrustMarkService.kt | 71 +++++++ .../extensions/TrustMarkExtensions.kt | 15 ++ 22 files changed, 583 insertions(+), 101 deletions(-) create mode 100644 modules/admin-server/src/main/kotlin/com/sphereon/oid/fed/server/admin/controllers/TrustMarkDefinitionController.kt create mode 100644 modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/TrustMarkDefinition.sq create mode 100644 modules/services/src/commonMain/kotlin/com/sphereon/oid/fed/services/TrustMarkService.kt create mode 100644 modules/services/src/commonMain/kotlin/com/sphereon/oid/fed/services/extensions/TrustMarkExtensions.kt diff --git a/modules/admin-server/src/main/kotlin/com/sphereon/oid/fed/server/admin/controllers/TrustMarkDefinitionController.kt b/modules/admin-server/src/main/kotlin/com/sphereon/oid/fed/server/admin/controllers/TrustMarkDefinitionController.kt new file mode 100644 index 00000000..2e23809a --- /dev/null +++ b/modules/admin-server/src/main/kotlin/com/sphereon/oid/fed/server/admin/controllers/TrustMarkDefinitionController.kt @@ -0,0 +1,60 @@ +package com.sphereon.oid.fed.server.admin.controllers + +import com.sphereon.oid.fed.openapi.models.CreateTrustMarkDefinitionDTO +import com.sphereon.oid.fed.openapi.models.TrustMarkDefinitionDTO +import com.sphereon.oid.fed.openapi.models.UpdateTrustMarkDefinitionDTO +import com.sphereon.oid.fed.services.AccountService +import com.sphereon.oid.fed.services.TrustMarkService +import org.springframework.web.bind.annotation.DeleteMapping +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.PutMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController + +@RestController +@RequestMapping("/accounts/{username}/trust-mark-definitions") +class TrustMarkDefinitionController { + private val accountService = AccountService() + private val trustMarkService = TrustMarkService() + + @GetMapping + fun getTrustMarkDefinitions(@PathVariable username: String): List { + return trustMarkService.findAllByAccount(accountService.usernameToAccountId(username)) + } + + @PostMapping + fun createTrustMarkDefinition( + @PathVariable username: String, + @RequestBody createDto: CreateTrustMarkDefinitionDTO + ): TrustMarkDefinitionDTO { + return trustMarkService.createTrustMarkDefinition(accountService.usernameToAccountId(username), createDto) + } + + @GetMapping("/{id}") + fun getTrustMarkDefinitionById( + @PathVariable username: String, + @PathVariable id: Int + ): TrustMarkDefinitionDTO { + return trustMarkService.findById(accountService.usernameToAccountId(username), id) + } + + @PutMapping("/{id}") + fun updateTrustMarkDefinition( + @PathVariable username: String, + @PathVariable id: Int, + @RequestBody updateDto: UpdateTrustMarkDefinitionDTO + ): TrustMarkDefinitionDTO { + return trustMarkService.updateTrustMarkDefinition(accountService.usernameToAccountId(username), id, updateDto) + } + + @DeleteMapping("/{id}") + fun deleteTrustMarkDefinition( + @PathVariable username: String, + @PathVariable id: Int + ): TrustMarkDefinitionDTO { + return trustMarkService.deleteTrustMarkDefinition(accountService.usernameToAccountId(username), id) + } +} diff --git a/modules/openapi/src/commonMain/kotlin/com/sphereon/oid/fed/openapi/openapi.yaml b/modules/openapi/src/commonMain/kotlin/com/sphereon/oid/fed/openapi/openapi.yaml index 423b0407..f6f8b8c5 100644 --- a/modules/openapi/src/commonMain/kotlin/com/sphereon/oid/fed/openapi/openapi.yaml +++ b/modules/openapi/src/commonMain/kotlin/com/sphereon/oid/fed/openapi/openapi.yaml @@ -1441,6 +1441,123 @@ paths: application/json: schema: $ref: '#/components/schemas/ErrorResponse' + '/accounts/{username}/trust-mark-definitions': + get: + summary: Get all Trust Mark Definitions + tags: + - admin + parameters: + - name: username + in: path + required: true + schema: + type: string + description: The username of the tenant account. + responses: + '200': + description: List of trust mark definitions + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/TrustMarkDefinitionDTO' + + post: + summary: Create a Trust Mark Definition + tags: + - admin + parameters: + - name: username + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CreateTrustMarkDefinitionDTO' + responses: + '201': + description: Trust mark definition created + content: + application/json: + schema: + $ref: '#/components/schemas/TrustMarkDefinitionDTO' + + '/accounts/{username}/trust-mark-definitions/{id}': + get: + summary: Get a Trust Mark Definition by ID + tags: + - admin + parameters: + - name: username + in: path + required: true + schema: + type: string + - name: id + in: path + required: true + schema: + type: integer + responses: + '200': + description: Trust mark definition details + content: + application/json: + schema: + $ref: '#/components/schemas/TrustMarkDefinitionDTO' + put: + summary: Update a Trust Mark Definition + tags: + - admin + parameters: + - name: username + in: path + required: true + schema: + type: string + - name: id + in: path + required: true + schema: + type: integer + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CreateTrustMarkDefinitionDTO' + responses: + '200': + description: Trust mark definition updated + content: + application/json: + schema: + $ref: '#/components/schemas/TrustMarkDefinitionDTO' + + delete: + summary: Delete a Trust Mark Definition + tags: + - admin + parameters: + - name: username + in: path + required: true + schema: + type: string + - name: id + in: path + required: true + schema: + type: integer + responses: + '204': + description: Trust mark definition deleted + '/accounts/{username}/trust-marks': post: tags: @@ -3713,3 +3830,74 @@ components: description: The identifier of the authority hint. required: - identifier + CreateTrustMarkDefinitionDTO: + type: object + x-tags: + - federation + properties: + identifier: + type: string + description: The unique identifier for the Trust Mark Definition. + example: "example-identifier" + name: + type: string + description: A human-readable name for the Trust Mark Definition. + example: "Example Trust Mark" + description: + type: string + description: A detailed description of the Trust Mark Definition. + example: "This is a trust mark for demonstrating compliance with XYZ standards." + required: + - identifier + - name + UpdateTrustMarkDefinitionDTO: + type: object + x-tags: + - federation + properties: + name: + type: string + description: A human-readable name for the Trust Mark Definition. + example: "Example Trust Mark" + description: + type: string + description: A detailed description of the Trust Mark Definition. + example: "This is a trust mark for demonstrating compliance with XYZ standards." + TrustMarkDefinitionDTO: + type: object + x-tags: + - federation + properties: + id: + type: integer + description: The unique identifier of the Trust Mark Definition. + example: 123 + identifier: + type: string + description: The unique identifier for the Trust Mark Definition. + example: "https://www.example.com/oidf/trustmark/underageSafetyVerified" + name: + type: string + description: A human-readable name for the Trust Mark Definition. + example: "Example Trust Mark" + description: + type: string + description: A detailed description of the Trust Mark Definition. + example: "This is a trust mark for demonstrating compliance with XYZ standards." + createdAt: + type: string + format: date-time + description: The timestamp when the Trust Mark Definition was created. + example: "2024-12-01T12:00:00Z" + updatedAt: + type: string + format: date-time + description: The timestamp when the Trust Mark Definition was last updated. + example: "2024-12-15T15:30:00Z" + nullable: true + required: + - id + - identifier + - name + - issuerPolicy + - createdAt diff --git a/modules/persistence/src/commonMain/kotlin/com/sphereon/oid/fed/persistence/Persistence.kt b/modules/persistence/src/commonMain/kotlin/com/sphereon/oid/fed/persistence/Persistence.kt index aae2a79f..0066440b 100644 --- a/modules/persistence/src/commonMain/kotlin/com/sphereon/oid/fed/persistence/Persistence.kt +++ b/modules/persistence/src/commonMain/kotlin/com/sphereon/oid/fed/persistence/Persistence.kt @@ -10,6 +10,7 @@ import com.sphereon.oid.fed.persistence.models.SubordinateJwkQueries import com.sphereon.oid.fed.persistence.models.SubordinateMetadataQueries import com.sphereon.oid.fed.persistence.models.SubordinateQueries import com.sphereon.oid.fed.persistence.models.SubordinateStatementQueries +import com.sphereon.oid.fed.persistence.models.TrustMarkDefinitionQueries expect object Persistence { val entityConfigurationStatementQueries: EntityConfigurationStatementQueries @@ -22,4 +23,5 @@ expect object Persistence { val subordinateStatementQueries: SubordinateStatementQueries val subordinateJwkQueries: SubordinateJwkQueries val subordinateMetadataQueries: SubordinateMetadataQueries + val trustMarkDefinitionQueries: TrustMarkDefinitionQueries } diff --git a/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/1.sqm b/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/1.sqm index 238043d3..f1f0a042 100644 --- a/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/1.sqm +++ b/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/1.sqm @@ -1,6 +1,7 @@ CREATE TABLE Account ( id SERIAL PRIMARY KEY, username VARCHAR(255) UNIQUE NOT NULL, + identifier TEXT, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, deleted_at TIMESTAMP diff --git a/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/10.sqm b/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/10.sqm index f7ee6b70..3bb19e19 100644 --- a/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/10.sqm +++ b/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/10.sqm @@ -10,3 +10,10 @@ CREATE TABLE SubordinateMetadata ( ); CREATE INDEX subordinate_metadata_account_id_index ON SubordinateMetadata (account_id); +CREATE INDEX subordinate_metadata_subordinate_id_index ON SubordinateMetadata (subordinate_id); +CREATE INDEX subordinate_metadata_account_id_subordinate_id_deleted_at_index +ON SubordinateMetadata (account_id, subordinate_id, deleted_at); + +CREATE UNIQUE INDEX unique_account_subordinate_key_active +ON SubordinateMetadata (account_id, subordinate_id, key) +WHERE deleted_at IS NULL; diff --git a/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/11.sqm b/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/11.sqm index 0b5bd44d..b5284c0e 100644 --- a/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/11.sqm +++ b/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/11.sqm @@ -1 +1,19 @@ -ALTER TABLE Account ADD COLUMN identifier VARCHAR(255) NULL; +CREATE TABLE TrustMarkDefinition ( + id SERIAL PRIMARY KEY, + account_id INT NOT NULL, + identifier TEXT NOT NULL, + name TEXT NOT NULL, + description TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMP, + CONSTRAINT FK_AccountTrustMarkDefinition FOREIGN KEY (account_id) REFERENCES Account (id) ON DELETE CASCADE +); + +CREATE UNIQUE INDEX unique_account_identifier_active +ON TrustMarkDefinition (account_id, identifier) +WHERE deleted_at IS NULL; + +CREATE INDEX idx_trustmarkdefinitions_account_id ON TrustMarkDefinition (account_id); + +CREATE INDEX idx_trustmarkdefinitions_deleted_at ON TrustMarkDefinition (deleted_at); diff --git a/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/3.sqm b/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/3.sqm index b33e53e9..1b629e98 100644 --- a/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/3.sqm +++ b/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/3.sqm @@ -4,9 +4,15 @@ CREATE TABLE Subordinate ( identifier TEXT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, deleted_at TIMESTAMP, - CONSTRAINT FK_ParentSubordinate FOREIGN KEY (account_id) REFERENCES Account (id), - UNIQUE (account_id, identifier) + CONSTRAINT FK_ParentSubordinate FOREIGN KEY (account_id) REFERENCES Account (id) ); -CREATE INDEX subordinate_account_id_index ON Subordinate (account_id); -CREATE INDEX subordinate_account_id_subordinate_identifier_index ON Subordinate (account_id, identifier); +CREATE INDEX subordinate_account_id_index +ON Subordinate (account_id); + +CREATE UNIQUE INDEX unique_account_id_identifier_active +ON Subordinate (account_id, identifier) +WHERE deleted_at IS NULL; + +CREATE INDEX subordinate_account_id_deleted_at_index +ON Subordinate (account_id, deleted_at); diff --git a/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/Account.sq b/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/Account.sq index 1a71530e..1480d013 100644 --- a/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/Account.sq +++ b/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/Account.sq @@ -1,17 +1,21 @@ findAll: -SELECT * FROM Account WHERE deleted_at IS NULL; +SELECT * +FROM Account +WHERE deleted_at IS NULL; create: -INSERT INTO Account (username, identifier) VALUES (?, ?) RETURNING *; +INSERT INTO Account (username, identifier) +VALUES (?, ?) +RETURNING *; delete: -UPDATE Account SET deleted_at = CURRENT_TIMESTAMP WHERE id = ? RETURNING *; +UPDATE Account +SET deleted_at = CURRENT_TIMESTAMP +WHERE id = ? +RETURNING *; findByUsername: -SELECT * FROM Account WHERE username = ? AND deleted_at IS NULL; - -findById: -SELECT * FROM Account WHERE id = ? AND deleted_at IS NULL; - -update: -UPDATE Account SET username = ? WHERE id = ? AND deleted_at IS NULL RETURNING *; +SELECT * +FROM Account +WHERE username = ? +AND deleted_at IS NULL; diff --git a/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/AuthorityHint.sq b/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/AuthorityHint.sq index 649e2f6f..58dab856 100644 --- a/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/AuthorityHint.sq +++ b/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/AuthorityHint.sq @@ -2,19 +2,32 @@ create: INSERT INTO AuthorityHint ( account_id, identifier -) VALUES ( ?, ?) RETURNING *; +) VALUES (?, ?) +RETURNING *; delete: -UPDATE AuthorityHint SET deleted_at = CURRENT_TIMESTAMP WHERE id = ? AND deleted_at IS NULL RETURNING *; +UPDATE AuthorityHint +SET deleted_at = CURRENT_TIMESTAMP +WHERE id = ? +AND deleted_at IS NULL +RETURNING *; findByAccountId: -SELECT * FROM AuthorityHint WHERE account_id = ? AND deleted_at IS NULL; - -findById: -SELECT * FROM AuthorityHint WHERE id = ? AND deleted_at IS NULL; +SELECT * +FROM AuthorityHint +WHERE account_id = ? +AND deleted_at IS NULL; findByAccountIdAndId: -SELECT * FROM AuthorityHint WHERE account_id = ? AND id = ? AND deleted_at IS NULL; +SELECT * +FROM AuthorityHint +WHERE account_id = ? +AND id = ? +AND deleted_at IS NULL; findByAccountIdAndIdentifier: -SELECT * FROM AuthorityHint WHERE account_id = ? AND identifier = ? AND deleted_at IS NULL; +SELECT * +FROM AuthorityHint +WHERE account_id = ? +AND identifier = ? +AND deleted_at IS NULL; diff --git a/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/Crit.sq b/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/Crit.sq index f9151f3f..5cc76fa6 100644 --- a/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/Crit.sq +++ b/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/Crit.sq @@ -1,17 +1,27 @@ findByAccountId: -SELECT * FROM Crit WHERE account_id = ? AND deleted_at IS NULL; +SELECT * +FROM Crit +WHERE account_id = ? +AND deleted_at IS NULL; findByAccountIdAndClaim: -SELECT * FROM Crit WHERE account_id = ? AND claim = ? AND deleted_at IS NULL; +SELECT * +FROM Crit +WHERE account_id = ? +AND claim = ? +AND deleted_at IS NULL; deleteByAccountIdAndId: -UPDATE Crit SET deleted_at = CURRENT_TIMESTAMP WHERE account_id = ? AND id = ? AND deleted_at IS NULL RETURNING *; - -deleteById: -UPDATE Crit SET deleted_at = CURRENT_TIMESTAMP WHERE id = ? RETURNING *; +UPDATE Crit +SET deleted_at = CURRENT_TIMESTAMP +WHERE account_id = ? +AND id = ? +AND deleted_at IS NULL +RETURNING *; create: -INSERT INTO Crit (account_id, claim) VALUES (?, ?) RETURNING *; - -findByAccountIdAndId: -SELECT * FROM Crit WHERE account_id = ? AND id = ? AND deleted_at IS NULL; +INSERT INTO Crit ( + account_id, + claim +) VALUES (?, ?) +RETURNING *; diff --git a/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/EntityConfigurationMetadata.sq b/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/EntityConfigurationMetadata.sq index bd083732..c9088e33 100644 --- a/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/EntityConfigurationMetadata.sq +++ b/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/EntityConfigurationMetadata.sq @@ -3,16 +3,31 @@ INSERT INTO EntityConfigurationMetadata ( account_id, key, metadata -) VALUES (?, ?, ?) RETURNING *; +) VALUES (?, ?, ?) +RETURNING *; delete: -UPDATE EntityConfigurationMetadata SET deleted_at = CURRENT_TIMESTAMP WHERE id = ? AND deleted_at IS NULL RETURNING *; +UPDATE EntityConfigurationMetadata +SET deleted_at = CURRENT_TIMESTAMP +WHERE id = ? +AND deleted_at IS NULL +RETURNING *; findByAccountId: -SELECT * FROM EntityConfigurationMetadata WHERE account_id = ? AND deleted_at IS NULL; +SELECT * +FROM EntityConfigurationMetadata +WHERE account_id = ? +AND deleted_at IS NULL; findByAccountIdAndKey: -SELECT * FROM EntityConfigurationMetadata WHERE account_id = ? AND key = ? AND deleted_at IS NULL; +SELECT * +FROM EntityConfigurationMetadata +WHERE account_id = ? +AND key = ? +AND deleted_at IS NULL; findById: -SELECT * FROM EntityConfigurationMetadata WHERE id = ? AND deleted_at IS NULL; +SELECT * +FROM EntityConfigurationMetadata +WHERE id = ? +AND deleted_at IS NULL; diff --git a/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/EntityConfigurationStatement.sq b/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/EntityConfigurationStatement.sq index 639646fd..74d94296 100644 --- a/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/EntityConfigurationStatement.sq +++ b/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/EntityConfigurationStatement.sq @@ -1,15 +1,14 @@ -findByAccountId: -SELECT * FROM EntityConfigurationStatement WHERE account_id = ?; - -findById: -SELECT * FROM EntityConfigurationStatement WHERE id = ?; - create: INSERT INTO EntityConfigurationStatement ( account_id, statement, expires_at -) VALUES (?, ?, ?) RETURNING *; +) VALUES (?, ?, ?) +RETURNING *; findLatestByAccountId: -SELECT * FROM EntityConfigurationStatement WHERE account_id = ? ORDER BY id DESC LIMIT 1; +SELECT * +FROM EntityConfigurationStatement +WHERE account_id = ? +ORDER BY id DESC +LIMIT 1; diff --git a/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/Key.sq b/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/Key.sq index 108a8dc0..23ffa133 100644 --- a/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/Key.sq +++ b/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/Key.sq @@ -3,13 +3,25 @@ INSERT INTO Jwk ( account_id, kid, key -) VALUES (?, ?, ?) RETURNING *; +) VALUES (?, ?, ?) +RETURNING *; revoke: -UPDATE Jwk SET (revoked_at, revoked_reason) = (CURRENT_TIMESTAMP, ?) WHERE id = ?; +UPDATE Jwk +SET revoked_at = CURRENT_TIMESTAMP, + revoked_reason = ? +WHERE id = ? +AND revoked_at IS NULL +RETURNING *; findByAccountId: -SELECT * FROM Jwk WHERE account_id = ? AND revoked_at IS NULL ORDER BY created_at DESC; +SELECT * +FROM Jwk +WHERE account_id = ? +AND revoked_at IS NULL +ORDER BY created_at DESC; findById: -SELECT * FROM Jwk WHERE id = ?; +SELECT * +FROM Jwk +WHERE id = ?; diff --git a/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/Subordinate.sq b/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/Subordinate.sq index 9461ef10..1b329086 100644 --- a/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/Subordinate.sq +++ b/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/Subordinate.sq @@ -2,22 +2,38 @@ create: INSERT INTO Subordinate ( account_id, identifier -) VALUES (?, ?) RETURNING *; +) VALUES (?, ?) +RETURNING *; delete: -UPDATE Subordinate SET deleted_at = CURRENT_TIMESTAMP WHERE id = ? AND deleted_at IS NULL RETURNING *; +UPDATE Subordinate +SET deleted_at = CURRENT_TIMESTAMP +WHERE id = ? +AND deleted_at IS NULL +RETURNING *; findByAccountId: -SELECT * FROM Subordinate WHERE account_id = ? AND deleted_at IS NULL; +SELECT * +FROM Subordinate +WHERE account_id = ? +AND deleted_at IS NULL; findByAccountIdAndSubordinateId: -SELECT * FROM Subordinate WHERE account_id = ? AND id = ? AND deleted_at IS NULL; +SELECT * +FROM Subordinate +WHERE account_id = ? +AND id = ? +AND deleted_at IS NULL; findByAccountIdAndIdentifier: -SELECT * FROM Subordinate WHERE account_id = ? AND identifier = ? AND deleted_at IS NULL; - -findPublishedByAccountIdAndIdentifier: -SELECT * FROM Subordinate WHERE account_id = ? AND identifier = ? AND deleted_at IS NULL; +SELECT * +FROM Subordinate +WHERE account_id = ? +AND identifier = ? +AND deleted_at IS NULL; findById: -SELECT * FROM Subordinate WHERE id = ? AND deleted_at IS NULL; +SELECT * +FROM Subordinate +WHERE id = ? +AND deleted_at IS NULL; diff --git a/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/SubordinateJwk.sq b/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/SubordinateJwk.sq index 8e32e971..61e36c6c 100644 --- a/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/SubordinateJwk.sq +++ b/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/SubordinateJwk.sq @@ -1,14 +1,25 @@ findBySubordinateId: -SELECT * FROM SubordinateJwk WHERE subordinate_id = ? AND deleted_at IS NULL; +SELECT * +FROM SubordinateJwk +WHERE subordinate_id = ? +AND deleted_at IS NULL; findById: -SELECT * FROM SubordinateJwk WHERE id = ? AND deleted_at IS NULL; +SELECT * +FROM SubordinateJwk +WHERE id = ? +AND deleted_at IS NULL; create: INSERT INTO SubordinateJwk ( subordinate_id, key -) VALUES (?, ?) RETURNING *; +) VALUES (?, ?) +RETURNING *; delete: -UPDATE SubordinateJwk SET deleted_at = CURRENT_TIMESTAMP WHERE id = ? RETURNING *; +UPDATE SubordinateJwk +SET deleted_at = CURRENT_TIMESTAMP +WHERE id = ? +AND deleted_at IS NULL +RETURNING *; diff --git a/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/SubordinateMetadata.sq b/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/SubordinateMetadata.sq index 3795f766..1a0b1bdb 100644 --- a/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/SubordinateMetadata.sq +++ b/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/SubordinateMetadata.sq @@ -4,25 +4,35 @@ INSERT INTO SubordinateMetadata ( subordinate_id, key, metadata -) VALUES (?, ?, ?, ?) RETURNING *; +) VALUES (?, ?, ?, ?) +RETURNING *; delete: -UPDATE SubordinateMetadata SET deleted_at = CURRENT_TIMESTAMP WHERE id = ? AND deleted_at IS NULL RETURNING *; - -findByAccountId: -SELECT * FROM SubordinateMetadata WHERE account_id = ? AND deleted_at IS NULL; +UPDATE SubordinateMetadata +SET deleted_at = CURRENT_TIMESTAMP +WHERE id = ? +AND deleted_at IS NULL +RETURNING *; findByAccountIdAndSubordinateId: -SELECT * FROM SubordinateMetadata WHERE account_id = ? AND subordinate_id = ? AND deleted_at IS NULL; +SELECT * +FROM SubordinateMetadata +WHERE account_id = ? +AND subordinate_id = ? +AND deleted_at IS NULL; findByAccountIdAndSubordinateIdAndKey: -SELECT * FROM SubordinateMetadata WHERE account_id = ? AND subordinate_id = ? AND key = ? AND deleted_at IS NULL; +SELECT * +FROM SubordinateMetadata +WHERE account_id = ? +AND subordinate_id = ? +AND key = ? +AND deleted_at IS NULL; findByAccountIdAndSubordinateIdAndId: -SELECT * FROM SubordinateMetadata WHERE account_id = ? AND subordinate_id = ? AND id = ? AND deleted_at IS NULL; - -findByAccountIdAndKey: -SELECT * FROM SubordinateMetadata WHERE account_id = ? AND key = ? AND deleted_at IS NULL; - -findById: -SELECT * FROM SubordinateMetadata WHERE id = ? AND deleted_at IS NULL; +SELECT * +FROM SubordinateMetadata +WHERE account_id = ? +AND subordinate_id = ? +AND id = ? +AND deleted_at IS NULL; diff --git a/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/SubordinateStatement.sq b/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/SubordinateStatement.sq index 3b78cc23..b8fc4c21 100644 --- a/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/SubordinateStatement.sq +++ b/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/SubordinateStatement.sq @@ -1,9 +1,3 @@ -findBySubordinateId: -SELECT * FROM SubordinateStatement WHERE subordinate_id = ?; - -findById: -SELECT * FROM SubordinateStatement WHERE id = ?; - create: INSERT INTO SubordinateStatement ( subordinate_id, @@ -13,15 +7,5 @@ INSERT INTO SubordinateStatement ( expires_at ) VALUES (?, ?, ?, ?, ?) RETURNING *; -findLatestBySubordinateId: -SELECT * FROM SubordinateStatement WHERE subordinate_id = ? ORDER BY id DESC LIMIT 1; - -findPublishedByAccountId: -SELECT s.* -FROM Subordinate s -JOIN SubordinateStatement ss ON ss.subordinate_id = s.id -WHERE s.account_id = ? - AND s.deleted_at IS NULL; - findByIssAndSub: SELECT * FROM SubordinateStatement WHERE iss = ? AND sub = ? ORDER BY id DESC LIMIT 1; diff --git a/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/TrustMarkDefinition.sq b/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/TrustMarkDefinition.sq new file mode 100644 index 00000000..de4c52d7 --- /dev/null +++ b/modules/persistence/src/commonMain/sqldelight/com/sphereon/oid/fed/persistence/models/TrustMarkDefinition.sq @@ -0,0 +1,30 @@ +create: +INSERT INTO TrustMarkDefinition (identifier, name, description, account_id) +VALUES (:identifier, :name, :description, :account_id) +RETURNING *; + +findByAccountId: +SELECT * FROM TrustMarkDefinition WHERE account_id = :account_id AND deleted_at IS NULL; + +findByAccountIdAndId: +SELECT * FROM TrustMarkDefinition +WHERE account_id = :account_id AND id = :id AND deleted_at IS NULL; + +findByAccountIdAndIdentifier: +SELECT * FROM TrustMarkDefinition +WHERE account_id = :account_id AND identifier = :identifier AND deleted_at IS NULL; + +update: +UPDATE TrustMarkDefinition +SET + name = COALESCE(:name, name), + description = COALESCE(:description, description), + updated_at = CURRENT_TIMESTAMP +WHERE id = :id AND deleted_at IS NULL +RETURNING *; + +delete: +UPDATE TrustMarkDefinition +SET deleted_at = CURRENT_TIMESTAMP +WHERE id = :id AND deleted_at IS NULL +RETURNING *; diff --git a/modules/persistence/src/jvmMain/kotlin/com.sphereon.oid.fed.persistence/Persistence.jvm.kt b/modules/persistence/src/jvmMain/kotlin/com.sphereon.oid.fed.persistence/Persistence.jvm.kt index f41f5aec..1c20ed22 100644 --- a/modules/persistence/src/jvmMain/kotlin/com.sphereon.oid.fed.persistence/Persistence.jvm.kt +++ b/modules/persistence/src/jvmMain/kotlin/com.sphereon.oid.fed.persistence/Persistence.jvm.kt @@ -14,6 +14,7 @@ import com.sphereon.oid.fed.persistence.models.SubordinateJwkQueries import com.sphereon.oid.fed.persistence.models.SubordinateMetadataQueries import com.sphereon.oid.fed.persistence.models.SubordinateQueries import com.sphereon.oid.fed.persistence.models.SubordinateStatementQueries +import com.sphereon.oid.fed.persistence.models.TrustMarkDefinitionQueries actual object Persistence { actual val entityConfigurationStatementQueries: EntityConfigurationStatementQueries @@ -26,6 +27,7 @@ actual object Persistence { actual val subordinateStatementQueries: SubordinateStatementQueries actual val subordinateJwkQueries: SubordinateJwkQueries actual val subordinateMetadataQueries: SubordinateMetadataQueries + actual val trustMarkDefinitionQueries: TrustMarkDefinitionQueries init { val driver = getDriver() @@ -42,6 +44,7 @@ actual object Persistence { subordinateStatementQueries = database.subordinateStatementQueries subordinateJwkQueries = database.subordinateJwkQueries subordinateMetadataQueries = database.subordinateMetadataQueries + trustMarkDefinitionQueries = database.trustMarkDefinitionQueries } private fun getDriver(): SqlDriver { diff --git a/modules/services/src/commonMain/kotlin/com/sphereon/oid/fed/services/AccountService.kt b/modules/services/src/commonMain/kotlin/com/sphereon/oid/fed/services/AccountService.kt index 9b41a5f2..658dbd61 100644 --- a/modules/services/src/commonMain/kotlin/com/sphereon/oid/fed/services/AccountService.kt +++ b/modules/services/src/commonMain/kotlin/com/sphereon/oid/fed/services/AccountService.kt @@ -28,8 +28,8 @@ class AccountService() { return accountQueries.findAll().executeAsList().map { it.toAccountDTO() } } - fun getAccountIdentifier(accountUsername: String): String { - val account = accountQueries.findByUsername(accountUsername).executeAsOneOrNull() + fun getAccountIdentifier(username: String): String { + val account = accountQueries.findByUsername(username).executeAsOneOrNull() ?: throw NotFoundException(Constants.ACCOUNT_NOT_FOUND) val identifier = account.identifier @@ -41,22 +41,29 @@ class AccountService() { val rootIdentifier = System.getenv("ROOT_IDENTIFIER") ?: throw NotFoundException(Constants.ROOT_IDENTIFIER_NOT_SET) - if (accountUsername == "root") { + if (username == "root") { return rootIdentifier } - return "$rootIdentifier/$accountUsername" + return "$rootIdentifier/$username" } - fun getAccountByUsername(accountUsername: String): Account { - return accountQueries.findByUsername(accountUsername).executeAsOneOrNull() + fun getAccountByUsername(username: String): Account { + return accountQueries.findByUsername(username).executeAsOneOrNull() ?: throw NotFoundException(Constants.ACCOUNT_NOT_FOUND) } - fun deleteAccount(accountUsername: String): Account { - val account = accountQueries.findByUsername(accountUsername).executeAsOneOrNull() + fun deleteAccount(username: String): Account { + val account = accountQueries.findByUsername(username).executeAsOneOrNull() ?: throw NotFoundException(Constants.ACCOUNT_NOT_FOUND) return accountQueries.delete(account.id).executeAsOne() } + + fun usernameToAccountId(username: String): Int { + val account = accountQueries.findByUsername(username).executeAsOneOrNull() + ?: throw NotFoundException(Constants.ACCOUNT_NOT_FOUND) + + return account.id + } } diff --git a/modules/services/src/commonMain/kotlin/com/sphereon/oid/fed/services/TrustMarkService.kt b/modules/services/src/commonMain/kotlin/com/sphereon/oid/fed/services/TrustMarkService.kt new file mode 100644 index 00000000..e4a471c2 --- /dev/null +++ b/modules/services/src/commonMain/kotlin/com/sphereon/oid/fed/services/TrustMarkService.kt @@ -0,0 +1,71 @@ +package com.sphereon.oid.fed.services + +import com.sphereon.oid.fed.common.exceptions.EntityAlreadyExistsException +import com.sphereon.oid.fed.common.exceptions.NotFoundException +import com.sphereon.oid.fed.openapi.models.CreateTrustMarkDefinitionDTO +import com.sphereon.oid.fed.openapi.models.TrustMarkDefinitionDTO +import com.sphereon.oid.fed.openapi.models.UpdateTrustMarkDefinitionDTO +import com.sphereon.oid.fed.persistence.Persistence +import com.sphereon.oid.fed.services.extensions.toTrustMarkDefinitionDTO + +class TrustMarkService { + private val trustMarkQueries = Persistence.trustMarkDefinitionQueries + + fun createTrustMarkDefinition(accountId: Int, createDto: CreateTrustMarkDefinitionDTO): TrustMarkDefinitionDTO { + val existingDefinition = + trustMarkQueries.findByAccountIdAndIdentifier(accountId, createDto.identifier).executeAsOneOrNull() + if (existingDefinition != null) { + throw EntityAlreadyExistsException("A trust mark definition with the given identifier already exists for this account.") + } + + val createdDefinition = trustMarkQueries.create( + account_id = accountId, + identifier = createDto.identifier, + name = createDto.name, + description = createDto.description + ).executeAsOne() + + return createdDefinition.toTrustMarkDefinitionDTO() + } + + fun findAllByAccount(accountId: Int): List { + return trustMarkQueries.findByAccountId(accountId).executeAsList().map { it.toTrustMarkDefinitionDTO() } + } + + fun findById(accountId: Int, id: Int): TrustMarkDefinitionDTO { + val definition = trustMarkQueries.findByAccountIdAndId(accountId, id).executeAsOneOrNull() + ?: throw NotFoundException("Trust mark definition with ID $id not found for account $accountId.") + return definition.toTrustMarkDefinitionDTO() + } + + fun findByIdentifier(accountId: Int, identifier: String): TrustMarkDefinitionDTO { + val definition = trustMarkQueries.findByAccountIdAndIdentifier(accountId, identifier).executeAsOneOrNull() + ?: throw NotFoundException("Trust mark definition with identifier $identifier not found for account $accountId.") + return definition.toTrustMarkDefinitionDTO() + } + + fun updateTrustMarkDefinition( + accountId: Int, + id: Int, + updateDto: UpdateTrustMarkDefinitionDTO + ): TrustMarkDefinitionDTO { + val existingDefinition = trustMarkQueries.findByAccountIdAndId(accountId, id).executeAsOneOrNull() + ?: throw NotFoundException("Trust mark definition with ID $id not found for account $accountId.") + + val updatedDefinition = trustMarkQueries.update( + name = updateDto.name ?: existingDefinition.name, + description = updateDto.description ?: existingDefinition.description, + id = id + ).executeAsOne() + + return updatedDefinition.toTrustMarkDefinitionDTO() + } + + fun deleteTrustMarkDefinition(accountId: Int, id: Int): TrustMarkDefinitionDTO { + val definition = trustMarkQueries.findByAccountIdAndId(accountId, id).executeAsOneOrNull() + ?: throw NotFoundException("Trust mark definition with ID $id not found for account $accountId.") + + val deletedDefinition = trustMarkQueries.delete(id).executeAsOne() + return deletedDefinition.toTrustMarkDefinitionDTO() + } +} diff --git a/modules/services/src/commonMain/kotlin/com/sphereon/oid/fed/services/extensions/TrustMarkExtensions.kt b/modules/services/src/commonMain/kotlin/com/sphereon/oid/fed/services/extensions/TrustMarkExtensions.kt new file mode 100644 index 00000000..d695652a --- /dev/null +++ b/modules/services/src/commonMain/kotlin/com/sphereon/oid/fed/services/extensions/TrustMarkExtensions.kt @@ -0,0 +1,15 @@ +package com.sphereon.oid.fed.services.extensions + +import com.sphereon.oid.fed.openapi.models.TrustMarkDefinitionDTO +import com.sphereon.oid.fed.persistence.models.TrustMarkDefinition + +fun TrustMarkDefinition.toTrustMarkDefinitionDTO(): TrustMarkDefinitionDTO { + return TrustMarkDefinitionDTO( + id = this.id, + identifier = this.identifier, + name = this.name, + description = this.description, + createdAt = this.created_at.toString(), + updatedAt = this.updated_at?.toString() + ) +}