ddd-ts-kit 0.14.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -1
- package/dist/check/explain/tenancy-docs.d.ts.map +1 -1
- package/dist/check/explain/tenancy-docs.js +3 -1
- package/dist/check/explain/tenancy-docs.js.map +1 -1
- package/dist/check/fixtures/tenancy-fixtures.d.ts.map +1 -1
- package/dist/check/fixtures/tenancy-fixtures.js +28 -0
- package/dist/check/fixtures/tenancy-fixtures.js.map +1 -1
- package/dist/check/tenancy/knex-unscoped.d.ts +6 -1
- package/dist/check/tenancy/knex-unscoped.d.ts.map +1 -1
- package/dist/check/tenancy/knex-unscoped.js +19 -6
- package/dist/check/tenancy/knex-unscoped.js.map +1 -1
- package/dist/check/tenancy/raw-reaches-rows.d.ts +8 -0
- package/dist/check/tenancy/raw-reaches-rows.d.ts.map +1 -0
- package/dist/check/tenancy/raw-reaches-rows.js +91 -0
- package/dist/check/tenancy/raw-reaches-rows.js.map +1 -0
- package/dist/check/tenancy/raw-sql-text.d.ts +9 -0
- package/dist/check/tenancy/raw-sql-text.d.ts.map +1 -0
- package/dist/check/tenancy/raw-sql-text.js +29 -0
- package/dist/check/tenancy/raw-sql-text.js.map +1 -0
- package/dist/commands/generate.js +2 -0
- package/dist/commands/generate.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +11 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/declared/injection/laid-out-calls.d.ts +7 -0
- package/dist/declared/injection/laid-out-calls.d.ts.map +1 -0
- package/dist/declared/injection/laid-out-calls.js +14 -0
- package/dist/declared/injection/laid-out-calls.js.map +1 -0
- package/dist/declared/render-barrel.d.ts.map +1 -1
- package/dist/declared/render-barrel.js +2 -1
- package/dist/declared/render-barrel.js.map +1 -1
- package/dist/declared/render-dependencies-file.d.ts.map +1 -1
- package/dist/declared/render-dependencies-file.js +2 -1
- package/dist/declared/render-dependencies-file.js.map +1 -1
- package/dist/generate/kind.d.ts +2 -0
- package/dist/generate/kind.d.ts.map +1 -1
- package/dist/generate/kinds/context-kind.d.ts.map +1 -1
- package/dist/generate/kinds/context-kind.js +13 -6
- package/dist/generate/kinds/context-kind.js.map +1 -1
- package/dist/generate/kinds/next-adr-number.d.ts +4 -0
- package/dist/generate/kinds/next-adr-number.d.ts.map +1 -0
- package/dist/generate/kinds/next-adr-number.js +7 -0
- package/dist/generate/kinds/next-adr-number.js.map +1 -0
- package/dist/generate/kinds/write-adr.js +3 -6
- package/dist/generate/kinds/write-adr.js.map +1 -1
- package/dist/help/usage.d.ts +1 -1
- package/dist/help/usage.d.ts.map +1 -1
- package/dist/help/usage.js +1 -1
- package/dist/init/manifest/versions.js +24 -24
- package/dist/init/run-init.d.ts +2 -0
- package/dist/init/run-init.d.ts.map +1 -1
- package/dist/init/run-init.js +15 -1
- package/dist/init/run-init.js.map +1 -1
- package/dist/presets/apply-preset.d.ts +15 -0
- package/dist/presets/apply-preset.d.ts.map +1 -0
- package/dist/presets/apply-preset.js +94 -0
- package/dist/presets/apply-preset.js.map +1 -0
- package/dist/presets/grant-to-signed-in.d.ts +9 -0
- package/dist/presets/grant-to-signed-in.d.ts.map +1 -0
- package/dist/presets/grant-to-signed-in.js +61 -0
- package/dist/presets/grant-to-signed-in.js.map +1 -0
- package/dist/presets/identity-preset.d.ts +9 -0
- package/dist/presets/identity-preset.d.ts.map +1 -0
- package/dist/presets/identity-preset.js +44 -0
- package/dist/presets/identity-preset.js.map +1 -0
- package/dist/presets/identity-refusal.d.ts +5 -0
- package/dist/presets/identity-refusal.d.ts.map +1 -0
- package/dist/presets/identity-refusal.js +29 -0
- package/dist/presets/identity-refusal.js.map +1 -0
- package/dist/presets/identity-terms.d.ts +4 -0
- package/dist/presets/identity-terms.d.ts.map +1 -0
- package/dist/presets/identity-terms.js +57 -0
- package/dist/presets/identity-terms.js.map +1 -0
- package/dist/presets/no-flags.d.ts +4 -0
- package/dist/presets/no-flags.d.ts.map +1 -0
- package/dist/presets/no-flags.js +18 -0
- package/dist/presets/no-flags.js.map +1 -0
- package/dist/presets/organisations-as-tenants.d.ts +9 -0
- package/dist/presets/organisations-as-tenants.d.ts.map +1 -0
- package/dist/presets/organisations-as-tenants.js +43 -0
- package/dist/presets/organisations-as-tenants.js.map +1 -0
- package/dist/presets/preset-decision.d.ts +8 -0
- package/dist/presets/preset-decision.d.ts.map +1 -0
- package/dist/presets/preset-decision.js +19 -0
- package/dist/presets/preset-decision.js.map +1 -0
- package/dist/presets/preset-file.d.ts +13 -0
- package/dist/presets/preset-file.d.ts.map +1 -0
- package/dist/presets/preset-file.js +2 -0
- package/dist/presets/preset-file.js.map +1 -0
- package/dist/presets/preset-files.d.ts +9 -0
- package/dist/presets/preset-files.d.ts.map +1 -0
- package/dist/presets/preset-files.js +34 -0
- package/dist/presets/preset-files.js.map +1 -0
- package/dist/presets/preset-named.d.ts +3 -0
- package/dist/presets/preset-named.d.ts.map +1 -0
- package/dist/presets/preset-named.js +12 -0
- package/dist/presets/preset-named.js.map +1 -0
- package/dist/presets/preset-refusal.d.ts +6 -0
- package/dist/presets/preset-refusal.d.ts.map +1 -0
- package/dist/presets/preset-refusal.js +2 -0
- package/dist/presets/preset-refusal.js.map +1 -0
- package/dist/presets/preset-step.d.ts +8 -0
- package/dist/presets/preset-step.d.ts.map +1 -0
- package/dist/presets/preset-step.js +2 -0
- package/dist/presets/preset-step.js.map +1 -0
- package/dist/presets/preset.d.ts +36 -0
- package/dist/presets/preset.d.ts.map +1 -0
- package/dist/presets/preset.js +2 -0
- package/dist/presets/preset.js.map +1 -0
- package/dist/presets/with-authorizer-import.d.ts +6 -0
- package/dist/presets/with-authorizer-import.d.ts.map +1 -0
- package/dist/presets/with-authorizer-import.js +27 -0
- package/dist/presets/with-authorizer-import.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/workspace/workspace.d.ts +2 -0
- package/dist/workspace/workspace.d.ts.map +1 -1
- package/dist/workspace/workspace.js +4 -0
- package/dist/workspace/workspace.js.map +1 -1
- package/package.json +2 -2
- package/templates/pipeline/package-scripts.json +1 -1
- package/templates/presets/identity/context/application/authorization/__context__.permissions.ts.tpl +23 -0
- package/templates/presets/identity/context/application/authorization/change-member-roles.policy.ts.tpl +17 -0
- package/templates/presets/identity/context/application/authorization/grant-delegations.policy.ts.tpl +17 -0
- package/templates/presets/identity/context/application/authorization/invite-members.policy.ts.tpl +17 -0
- package/templates/presets/identity/context/application/authorization/read-members.policy.ts.tpl +17 -0
- package/templates/presets/identity/context/application/authorization/remove-members.policy.ts.tpl +17 -0
- package/templates/presets/identity/context/application/authorization/revoke-delegations.policy.ts.tpl +17 -0
- package/templates/presets/identity/context/application/authorization/revoke-invitations.policy.ts.tpl +17 -0
- package/templates/presets/identity/context/application/commands/accept-invitation/accept-invitation.command.ts.tpl +14 -0
- package/templates/presets/identity/context/application/commands/accept-invitation/accept-invitation.handler.ts.tpl +56 -0
- package/templates/presets/identity/context/application/commands/change-member-role/change-member-role.command.ts.tpl +17 -0
- package/templates/presets/identity/context/application/commands/change-member-role/change-member-role.handler.ts.tpl +82 -0
- package/templates/presets/identity/context/application/commands/deactivate-account/deactivate-account.command.ts.tpl +7 -0
- package/templates/presets/identity/context/application/commands/deactivate-account/deactivate-account.handler.ts.tpl +69 -0
- package/templates/presets/identity/context/application/commands/decline-invitation/decline-invitation.command.ts.tpl +14 -0
- package/templates/presets/identity/context/application/commands/decline-invitation/decline-invitation.handler.ts.tpl +36 -0
- package/templates/presets/identity/context/application/commands/grant-delegation/grant-delegation.command.ts.tpl +21 -0
- package/templates/presets/identity/context/application/commands/grant-delegation/grant-delegation.handler.ts.tpl +43 -0
- package/templates/presets/identity/context/application/commands/invite-member/invite-member.command.ts.tpl +16 -0
- package/templates/presets/identity/context/application/commands/invite-member/invite-member.handler.ts.tpl +53 -0
- package/templates/presets/identity/context/application/commands/open-organisation/open-organisation.command.ts.tpl +14 -0
- package/templates/presets/identity/context/application/commands/open-organisation/open-organisation.handler.ts.tpl +50 -0
- package/templates/presets/identity/context/application/commands/provision-account/provision-account.command.ts.tpl +14 -0
- package/templates/presets/identity/context/application/commands/provision-account/provision-account.handler.ts.tpl +41 -0
- package/templates/presets/identity/context/application/commands/remove-member/remove-member.command.ts.tpl +15 -0
- package/templates/presets/identity/context/application/commands/remove-member/remove-member.handler.ts.tpl +79 -0
- package/templates/presets/identity/context/application/commands/revoke-delegation/revoke-delegation.command.ts.tpl +15 -0
- package/templates/presets/identity/context/application/commands/revoke-delegation/revoke-delegation.handler.ts.tpl +39 -0
- package/templates/presets/identity/context/application/commands/revoke-invitation/revoke-invitation.command.ts.tpl +15 -0
- package/templates/presets/identity/context/application/commands/revoke-invitation/revoke-invitation.handler.ts.tpl +42 -0
- package/templates/presets/identity/context/application/integration/handlers/account-deactivated.integration-handler.ts.tpl +19 -0
- package/templates/presets/identity/context/application/integration/handlers/member-joined.integration-handler.ts.tpl +33 -0
- package/templates/presets/identity/context/application/integration/handlers/member-removed.integration-handler.ts.tpl +30 -0
- package/templates/presets/identity/context/application/integration/handlers/organisation-opened.integration-handler.ts.tpl +19 -0
- package/templates/presets/identity/context/application/integration/publishers/account-deactivated.publisher.ts.tpl +24 -0
- package/templates/presets/identity/context/application/integration/publishers/delegation-granted.publisher.ts.tpl +36 -0
- package/templates/presets/identity/context/application/integration/publishers/delegation-revoked.publisher.ts.tpl +33 -0
- package/templates/presets/identity/context/application/integration/publishers/member-joined.publisher.ts.tpl +33 -0
- package/templates/presets/identity/context/application/integration/publishers/member-removed.publisher.ts.tpl +33 -0
- package/templates/presets/identity/context/application/integration/publishers/member-role-changed.publisher.ts.tpl +35 -0
- package/templates/presets/identity/context/application/integration/publishers/organisation-opened.publisher.ts.tpl +32 -0
- package/templates/presets/identity/context/application/ports/identity-provider-admin.port.ts.tpl +17 -0
- package/templates/presets/identity/context/application/ports/identity-provider-connection.port.ts.tpl +14 -0
- package/templates/presets/identity/context/application/ports/invitation-tokens.port.ts.tpl +7 -0
- package/templates/presets/identity/context/application/ports/search-members-reader.port.ts.tpl +10 -0
- package/templates/presets/identity/context/application/queries/search-members/search-members.handler.ts.tpl +33 -0
- package/templates/presets/identity/context/application/queries/search-members/search-members.query.ts.tpl +19 -0
- package/templates/presets/identity/context/application/queries/search-members/search-members.result.ts.tpl +17 -0
- package/templates/presets/identity/context/domain/aggregates/account.aggregate.ts.tpl +92 -0
- package/templates/presets/identity/context/domain/aggregates/delegation.aggregate.ts.tpl +117 -0
- package/templates/presets/identity/context/domain/aggregates/invitation.aggregate.ts.tpl +128 -0
- package/templates/presets/identity/context/domain/aggregates/member.aggregate.ts.tpl +149 -0
- package/templates/presets/identity/context/domain/aggregates/organisation.aggregate.ts.tpl +52 -0
- package/templates/presets/identity/context/domain/errors/account.error.ts.tpl +40 -0
- package/templates/presets/identity/context/domain/errors/delegation.error.ts.tpl +45 -0
- package/templates/presets/identity/context/domain/errors/invitation.error.ts.tpl +30 -0
- package/templates/presets/identity/context/domain/errors/member.error.ts.tpl +50 -0
- package/templates/presets/identity/context/domain/errors/organisation.error.ts.tpl +32 -0
- package/templates/presets/identity/context/domain/events/account-deactivated.event.ts.tpl +13 -0
- package/templates/presets/identity/context/domain/events/account-provisioned.event.ts.tpl +17 -0
- package/templates/presets/identity/context/domain/events/delegation-granted.event.ts.tpl +22 -0
- package/templates/presets/identity/context/domain/events/delegation-revoked.event.ts.tpl +18 -0
- package/templates/presets/identity/context/domain/events/invitation-accepted.event.ts.tpl +17 -0
- package/templates/presets/identity/context/domain/events/invitation-declined.event.ts.tpl +16 -0
- package/templates/presets/identity/context/domain/events/invitation-issued.event.ts.tpl +22 -0
- package/templates/presets/identity/context/domain/events/invitation-revoked.event.ts.tpl +16 -0
- package/templates/presets/identity/context/domain/events/member-joined.event.ts.tpl +19 -0
- package/templates/presets/identity/context/domain/events/member-removed.event.ts.tpl +19 -0
- package/templates/presets/identity/context/domain/events/member-role-changed.event.ts.tpl +22 -0
- package/templates/presets/identity/context/domain/events/organisation-opened.event.ts.tpl +17 -0
- package/templates/presets/identity/context/domain/repositories/account.repository.ts.tpl +5 -0
- package/templates/presets/identity/context/domain/repositories/delegation.repository.ts.tpl +10 -0
- package/templates/presets/identity/context/domain/repositories/invitation.repository.ts.tpl +7 -0
- package/templates/presets/identity/context/domain/repositories/member.repository.ts.tpl +13 -0
- package/templates/presets/identity/context/domain/repositories/organisation.repository.ts.tpl +5 -0
- package/templates/presets/identity/context/domain/services/role-rights.service.ts.tpl +59 -0
- package/templates/presets/identity/context/domain/value-objects/delegation-period.vo.ts.tpl +42 -0
- package/templates/presets/identity/context/domain/value-objects/display-name.vo.ts.tpl +29 -0
- package/templates/presets/identity/context/domain/value-objects/email-address.vo.ts.tpl +31 -0
- package/templates/presets/identity/context/domain/value-objects/organisation-name.vo.ts.tpl +29 -0
- package/templates/presets/identity/context/domain/value-objects/organisation-rights.vo.ts.tpl +43 -0
- package/templates/presets/identity/context/domain/value-objects/organisation-slug.vo.ts.tpl +30 -0
- package/templates/presets/identity/context/domain/vocabularies/account-status.vocabulary.ts.tpl +7 -0
- package/templates/presets/identity/context/domain/vocabularies/invitation-status.vocabulary.ts.tpl +9 -0
- package/templates/presets/identity/context/domain/vocabularies/member-right.vocabulary.ts.tpl +9 -0
- package/templates/presets/identity/context/domain/vocabularies/member-role.vocabulary.ts.tpl +8 -0
- package/templates/presets/identity/context/infrastructure/external/crypto-invitation-tokens.adapter.ts.tpl +20 -0
- package/templates/presets/identity/context/infrastructure/external/environment-identity-provider-connection.adapter.ts.tpl +37 -0
- package/templates/presets/identity/context/infrastructure/external/keycloak-identity-provider-admin.adapter.ts.tpl +149 -0
- package/templates/presets/identity/context/infrastructure/persistence/__context__.schema.drizzle.ts.tpl +102 -0
- package/templates/presets/identity/context/infrastructure/persistence/account-row.schema.knex.ts.tpl +15 -0
- package/templates/presets/identity/context/infrastructure/persistence/account.mapper.drizzle.ts.tpl +38 -0
- package/templates/presets/identity/context/infrastructure/persistence/account.mapper.knex.ts.tpl +33 -0
- package/templates/presets/identity/context/infrastructure/persistence/create-__context__-tables.schema.knex.ts.tpl +107 -0
- package/templates/presets/identity/context/infrastructure/persistence/delegation-row.schema.knex.ts.tpl +17 -0
- package/templates/presets/identity/context/infrastructure/persistence/delegation.mapper.drizzle.ts.tpl +50 -0
- package/templates/presets/identity/context/infrastructure/persistence/delegation.mapper.knex.ts.tpl +45 -0
- package/templates/presets/identity/context/infrastructure/persistence/drizzle-account.repository.drizzle.ts.tpl +59 -0
- package/templates/presets/identity/context/infrastructure/persistence/drizzle-delegation.repository.drizzle.ts.tpl +77 -0
- package/templates/presets/identity/context/infrastructure/persistence/drizzle-invitation.repository.drizzle.ts.tpl +65 -0
- package/templates/presets/identity/context/infrastructure/persistence/drizzle-member.repository.drizzle.ts.tpl +84 -0
- package/templates/presets/identity/context/infrastructure/persistence/drizzle-organisation.repository.drizzle.ts.tpl +59 -0
- package/templates/presets/identity/context/infrastructure/persistence/drizzle-search-members-reader.repository.drizzle.ts.tpl +53 -0
- package/templates/presets/identity/context/infrastructure/persistence/invitation-row.schema.knex.ts.tpl +20 -0
- package/templates/presets/identity/context/infrastructure/persistence/invitation.mapper.drizzle.ts.tpl +45 -0
- package/templates/presets/identity/context/infrastructure/persistence/invitation.mapper.knex.ts.tpl +40 -0
- package/templates/presets/identity/context/infrastructure/persistence/knex-account.repository.knex.ts.tpl +61 -0
- package/templates/presets/identity/context/infrastructure/persistence/knex-delegation.repository.knex.ts.tpl +80 -0
- package/templates/presets/identity/context/infrastructure/persistence/knex-invitation.repository.knex.ts.tpl +67 -0
- package/templates/presets/identity/context/infrastructure/persistence/knex-member.repository.knex.ts.tpl +82 -0
- package/templates/presets/identity/context/infrastructure/persistence/knex-organisation.repository.knex.ts.tpl +61 -0
- package/templates/presets/identity/context/infrastructure/persistence/knex-search-members-reader.repository.knex.ts.tpl +77 -0
- package/templates/presets/identity/context/infrastructure/persistence/member-row.schema.knex.ts.tpl +15 -0
- package/templates/presets/identity/context/infrastructure/persistence/member.mapper.drizzle.ts.tpl +36 -0
- package/templates/presets/identity/context/infrastructure/persistence/member.mapper.knex.ts.tpl +31 -0
- package/templates/presets/identity/context/infrastructure/persistence/organisation-row.schema.knex.ts.tpl +12 -0
- package/templates/presets/identity/context/infrastructure/persistence/organisation.mapper.drizzle.ts.tpl +28 -0
- package/templates/presets/identity/context/infrastructure/persistence/organisation.mapper.knex.ts.tpl +26 -0
- package/templates/presets/identity/context/presentation/http/accounts/deactivate-account/deactivate-account.accepted.class-validator.per-route.ts.tpl +6 -0
- package/templates/presets/identity/context/presentation/http/accounts/deactivate-account/deactivate-account.controller.ts.tpl +71 -0
- package/templates/presets/identity/context/presentation/http/accounts/provision-account/provision-account.accepted.class-validator.per-route.ts.tpl +6 -0
- package/templates/presets/identity/context/presentation/http/accounts/provision-account/provision-account.body.class-validator.ts.tpl +9 -0
- package/templates/presets/identity/context/presentation/http/accounts/provision-account/provision-account.controller.ts.tpl +85 -0
- package/templates/presets/identity/context/presentation/http/accounts.routes.ts.tpl +5 -0
- package/templates/presets/identity/context/presentation/http/invitations/accept-invitation/accept-invitation.accepted.class-validator.per-route.ts.tpl +6 -0
- package/templates/presets/identity/context/presentation/http/invitations/accept-invitation/accept-invitation.body.class-validator.per-route.ts.tpl +8 -0
- package/templates/presets/identity/context/presentation/http/invitations/accept-invitation/accept-invitation.controller.ts.tpl +100 -0
- package/templates/presets/identity/context/presentation/http/invitations/decline-invitation/decline-invitation.accepted.class-validator.per-route.ts.tpl +6 -0
- package/templates/presets/identity/context/presentation/http/invitations/decline-invitation/decline-invitation.body.class-validator.per-route.ts.tpl +8 -0
- package/templates/presets/identity/context/presentation/http/invitations/decline-invitation/decline-invitation.controller.ts.tpl +98 -0
- package/templates/presets/identity/context/presentation/http/invitations.routes.ts.tpl +5 -0
- package/templates/presets/identity/context/presentation/http/organisations/change-member-role/change-member-role.accepted.class-validator.per-route.ts.tpl +6 -0
- package/templates/presets/identity/context/presentation/http/organisations/change-member-role/change-member-role.body.class-validator.ts.tpl +7 -0
- package/templates/presets/identity/context/presentation/http/organisations/change-member-role/change-member-role.controller.ts.tpl +83 -0
- package/templates/presets/identity/context/presentation/http/organisations/change-member-role/change-member-role.params.class-validator.ts.tpl +11 -0
- package/templates/presets/identity/context/presentation/http/organisations/grant-delegation/grant-delegation.accepted.class-validator.per-route.ts.tpl +6 -0
- package/templates/presets/identity/context/presentation/http/organisations/grant-delegation/grant-delegation.body.class-validator.ts.tpl +18 -0
- package/templates/presets/identity/context/presentation/http/organisations/grant-delegation/grant-delegation.controller.ts.tpl +103 -0
- package/templates/presets/identity/context/presentation/http/organisations/grant-delegation/grant-delegation.params.class-validator.ts.tpl +7 -0
- package/templates/presets/identity/context/presentation/http/organisations/invite-member/invite-member.accepted.class-validator.ts.tpl +10 -0
- package/templates/presets/identity/context/presentation/http/organisations/invite-member/invite-member.body.class-validator.ts.tpl +10 -0
- package/templates/presets/identity/context/presentation/http/organisations/invite-member/invite-member.controller.ts.tpl +65 -0
- package/templates/presets/identity/context/presentation/http/organisations/invite-member/invite-member.params.class-validator.ts.tpl +7 -0
- package/templates/presets/identity/context/presentation/http/organisations/open-organisation/open-organisation.accepted.class-validator.per-route.ts.tpl +6 -0
- package/templates/presets/identity/context/presentation/http/organisations/open-organisation/open-organisation.body.class-validator.ts.tpl +12 -0
- package/templates/presets/identity/context/presentation/http/organisations/open-organisation/open-organisation.controller.ts.tpl +79 -0
- package/templates/presets/identity/context/presentation/http/organisations/remove-member/remove-member.accepted.class-validator.per-route.ts.tpl +6 -0
- package/templates/presets/identity/context/presentation/http/organisations/remove-member/remove-member.controller.ts.tpl +73 -0
- package/templates/presets/identity/context/presentation/http/organisations/remove-member/remove-member.params.class-validator.ts.tpl +11 -0
- package/templates/presets/identity/context/presentation/http/organisations/revoke-delegation/revoke-delegation.accepted.class-validator.per-route.ts.tpl +6 -0
- package/templates/presets/identity/context/presentation/http/organisations/revoke-delegation/revoke-delegation.controller.ts.tpl +73 -0
- package/templates/presets/identity/context/presentation/http/organisations/revoke-delegation/revoke-delegation.params.class-validator.ts.tpl +11 -0
- package/templates/presets/identity/context/presentation/http/organisations/revoke-invitation/revoke-invitation.accepted.class-validator.per-route.ts.tpl +6 -0
- package/templates/presets/identity/context/presentation/http/organisations/revoke-invitation/revoke-invitation.controller.ts.tpl +73 -0
- package/templates/presets/identity/context/presentation/http/organisations/revoke-invitation/revoke-invitation.params.class-validator.ts.tpl +11 -0
- package/templates/presets/identity/context/presentation/http/organisations/search-members/search-members.controller.ts.tpl +86 -0
- package/templates/presets/identity/context/presentation/http/organisations/search-members/search-members.line.class-validator.ts.tpl +22 -0
- package/templates/presets/identity/context/presentation/http/organisations/search-members/search-members.params.class-validator.ts.tpl +7 -0
- package/templates/presets/identity/context/presentation/http/organisations.routes.ts.tpl +5 -0
- package/templates/presets/identity/context/presentation/http/shared/invitation-token.schema.class-validator.shared.ts.tpl +9 -0
- package/templates/presets/identity/context/presentation/http/shared/invitation-token.schema.zod.shared.ts.tpl +9 -0
- package/templates/presets/identity/context/published-language/account-deactivated.v1.integration-event.ts.tpl +33 -0
- package/templates/presets/identity/context/published-language/account-deactivated.v1.payload.class-validator.ts.tpl +7 -0
- package/templates/presets/identity/context/published-language/delegation-granted.v1.integration-event.ts.tpl +39 -0
- package/templates/presets/identity/context/published-language/delegation-granted.v1.payload.class-validator.ts.tpl +28 -0
- package/templates/presets/identity/context/published-language/delegation-revoked.v1.integration-event.ts.tpl +36 -0
- package/templates/presets/identity/context/published-language/delegation-revoked.v1.payload.class-validator.ts.tpl +16 -0
- package/templates/presets/identity/context/published-language/member-joined.v1.integration-event.ts.tpl +36 -0
- package/templates/presets/identity/context/published-language/member-joined.v1.payload.class-validator.ts.tpl +16 -0
- package/templates/presets/identity/context/published-language/member-removed.v1.integration-event.ts.tpl +36 -0
- package/templates/presets/identity/context/published-language/member-removed.v1.payload.class-validator.ts.tpl +18 -0
- package/templates/presets/identity/context/published-language/member-role-changed.v1.integration-event.ts.tpl +38 -0
- package/templates/presets/identity/context/published-language/member-role-changed.v1.payload.class-validator.ts.tpl +24 -0
- package/templates/presets/identity/context/published-language/organisation-opened.v1.integration-event.ts.tpl +35 -0
- package/templates/presets/identity/context/published-language/organisation-opened.v1.payload.class-validator.ts.tpl +13 -0
- package/templates/presets/identity/context/test/builders/account.builder.ts.tpl +59 -0
- package/templates/presets/identity/context/test/builders/delegation.builder.ts.tpl +67 -0
- package/templates/presets/identity/context/test/builders/invitation.builder.ts.tpl +60 -0
- package/templates/presets/identity/context/test/builders/member.builder.ts.tpl +59 -0
- package/templates/presets/identity/context/test/builders/organisation.builder.ts.tpl +44 -0
- package/templates/presets/identity/context/test/fakes/account.repository.fake.ts.tpl +10 -0
- package/templates/presets/identity/context/test/fakes/delegation.repository.fake.ts.tpl +26 -0
- package/templates/presets/identity/context/test/fakes/identity-provider-admin.fake.ts.tpl +41 -0
- package/templates/presets/identity/context/test/fakes/invitation-tokens.fake.ts.tpl +18 -0
- package/templates/presets/identity/context/test/fakes/invitation.repository.fake.ts.tpl +14 -0
- package/templates/presets/identity/context/test/fakes/member.repository.fake.ts.tpl +29 -0
- package/templates/presets/identity/context/test/fakes/organisation.repository.fake.ts.tpl +10 -0
- package/templates/presets/identity/context/test/fakes/search-members-reader.fake.ts.tpl +25 -0
- package/templates/presets/identity/context/test/integration/account.repository.contract.spec.ts.tpl +48 -0
- package/templates/presets/identity/context/test/integration/delegation.repository.contract.spec.ts.tpl +84 -0
- package/templates/presets/identity/context/test/integration/invitation.repository.contract.spec.ts.tpl +76 -0
- package/templates/presets/identity/context/test/integration/keycloak-identity-provider-admin.adapter.spec.ts.tpl +123 -0
- package/templates/presets/identity/context/test/integration/member.repository.contract.spec.ts.tpl +92 -0
- package/templates/presets/identity/context/test/integration/organisation.repository.contract.spec.ts.tpl +46 -0
- package/templates/presets/identity/context/test/integration/search-members-reader.spec.ts.tpl +86 -0
- package/templates/presets/identity/context/test/unit/accept-invitation.controller.spec.ts.tpl +57 -0
- package/templates/presets/identity/context/test/unit/accept-invitation.handler.spec.ts.tpl +69 -0
- package/templates/presets/identity/context/test/unit/account-deactivated.integration-handler.spec.ts.tpl +24 -0
- package/templates/presets/identity/context/test/unit/account-deactivated.publisher.spec.ts.tpl +25 -0
- package/templates/presets/identity/context/test/unit/account.aggregate.spec.ts.tpl +72 -0
- package/templates/presets/identity/context/test/unit/change-member-role.controller.spec.ts.tpl +57 -0
- package/templates/presets/identity/context/test/unit/change-member-role.handler.spec.ts.tpl +135 -0
- package/templates/presets/identity/context/test/unit/crypto-invitation-tokens.adapter.spec.ts.tpl +15 -0
- package/templates/presets/identity/context/test/unit/deactivate-account.controller.spec.ts.tpl +44 -0
- package/templates/presets/identity/context/test/unit/deactivate-account.handler.spec.ts.tpl +106 -0
- package/templates/presets/identity/context/test/unit/decline-invitation.controller.spec.ts.tpl +57 -0
- package/templates/presets/identity/context/test/unit/decline-invitation.handler.spec.ts.tpl +40 -0
- package/templates/presets/identity/context/test/unit/delegation-granted.publisher.spec.ts.tpl +36 -0
- package/templates/presets/identity/context/test/unit/delegation-period.vo.spec.ts.tpl +32 -0
- package/templates/presets/identity/context/test/unit/delegation-revoked.publisher.spec.ts.tpl +35 -0
- package/templates/presets/identity/context/test/unit/delegation.aggregate.spec.ts.tpl +111 -0
- package/templates/presets/identity/context/test/unit/display-name.vo.spec.ts.tpl +13 -0
- package/templates/presets/identity/context/test/unit/email-address.vo.spec.ts.tpl +24 -0
- package/templates/presets/identity/context/test/unit/environment-identity-provider-connection.adapter.spec.ts.tpl +41 -0
- package/templates/presets/identity/context/test/unit/grant-delegation.controller.spec.ts.tpl +57 -0
- package/templates/presets/identity/context/test/unit/grant-delegation.handler.spec.ts.tpl +66 -0
- package/templates/presets/identity/context/test/unit/identity-application.ts.tpl +79 -0
- package/templates/presets/identity/context/test/unit/invitation.aggregate.spec.ts.tpl +118 -0
- package/templates/presets/identity/context/test/unit/invite-member.controller.spec.ts.tpl +57 -0
- package/templates/presets/identity/context/test/unit/invite-member.handler.spec.ts.tpl +110 -0
- package/templates/presets/identity/context/test/unit/member-joined.integration-handler.spec.ts.tpl +38 -0
- package/templates/presets/identity/context/test/unit/member-joined.publisher.spec.ts.tpl +36 -0
- package/templates/presets/identity/context/test/unit/member-removed.integration-handler.spec.ts.tpl +45 -0
- package/templates/presets/identity/context/test/unit/member-removed.publisher.spec.ts.tpl +35 -0
- package/templates/presets/identity/context/test/unit/member-role-changed.publisher.spec.ts.tpl +36 -0
- package/templates/presets/identity/context/test/unit/member.aggregate.spec.ts.tpl +142 -0
- package/templates/presets/identity/context/test/unit/open-organisation.controller.spec.ts.tpl +57 -0
- package/templates/presets/identity/context/test/unit/open-organisation.handler.spec.ts.tpl +52 -0
- package/templates/presets/identity/context/test/unit/organisation-name.vo.spec.ts.tpl +13 -0
- package/templates/presets/identity/context/test/unit/organisation-opened.integration-handler.spec.ts.tpl +24 -0
- package/templates/presets/identity/context/test/unit/organisation-opened.publisher.spec.ts.tpl +35 -0
- package/templates/presets/identity/context/test/unit/organisation-rights.vo.spec.ts.tpl +23 -0
- package/templates/presets/identity/context/test/unit/organisation-slug.vo.spec.ts.tpl +17 -0
- package/templates/presets/identity/context/test/unit/organisation.aggregate.spec.ts.tpl +33 -0
- package/templates/presets/identity/context/test/unit/provision-account.controller.spec.ts.tpl +73 -0
- package/templates/presets/identity/context/test/unit/provision-account.handler.spec.ts.tpl +65 -0
- package/templates/presets/identity/context/test/unit/remove-member.controller.spec.ts.tpl +44 -0
- package/templates/presets/identity/context/test/unit/remove-member.handler.spec.ts.tpl +125 -0
- package/templates/presets/identity/context/test/unit/revoke-delegation.controller.spec.ts.tpl +44 -0
- package/templates/presets/identity/context/test/unit/revoke-delegation.handler.spec.ts.tpl +51 -0
- package/templates/presets/identity/context/test/unit/revoke-invitation.controller.spec.ts.tpl +44 -0
- package/templates/presets/identity/context/test/unit/revoke-invitation.handler.spec.ts.tpl +44 -0
- package/templates/presets/identity/context/test/unit/role-rights.service.spec.ts.tpl +54 -0
- package/templates/presets/identity/context/test/unit/search-members.controller.spec.ts.tpl +43 -0
- package/templates/presets/identity/context/test/unit/search-members.handler.spec.ts.tpl +38 -0
- package/templates/presets/identity/decision.md.tpl +37 -0
- package/templates/presets/identity/design.md.tpl +71 -0
- package/templates/presets/signed-in-grants.ts.tpl +12 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { Clock, IdGenerator } from '@ddd-ts-kit/kernel';
|
|
2
|
+
import { CommandHandler } from '@ddd-ts-kit/kernel/declarations';
|
|
3
|
+
import { Member } from '{{alias.context}}/domain/aggregates/member.aggregate{{alias.ext}}';
|
|
4
|
+
import { Organisation } from '{{alias.context}}/domain/aggregates/organisation.aggregate{{alias.ext}}';
|
|
5
|
+
import { AccountError } from '{{alias.context}}/domain/errors/account.error{{alias.ext}}';
|
|
6
|
+
import { OrganisationError } from '{{alias.context}}/domain/errors/organisation.error{{alias.ext}}';
|
|
7
|
+
import type { AccountRepository } from '{{alias.context}}/domain/repositories/account.repository{{alias.ext}}';
|
|
8
|
+
import type { MemberRepository } from '{{alias.context}}/domain/repositories/member.repository{{alias.ext}}';
|
|
9
|
+
import type { OrganisationRepository } from '{{alias.context}}/domain/repositories/organisation.repository{{alias.ext}}';
|
|
10
|
+
import { OrganisationName } from '{{alias.context}}/domain/value-objects/organisation-name.vo{{alias.ext}}';
|
|
11
|
+
import { OrganisationSlug } from '{{alias.context}}/domain/value-objects/organisation-slug.vo{{alias.ext}}';
|
|
12
|
+
import { MemberRole } from '{{alias.context}}/domain/vocabularies/member-role.vocabulary{{alias.ext}}';
|
|
13
|
+
import { OpenOrganisationCommand } from '{{alias.context}}/application/commands/open-organisation/open-organisation.command{{alias.ext}}';
|
|
14
|
+
|
|
15
|
+
@CommandHandler(OpenOrganisationCommand)
|
|
16
|
+
export class OpenOrganisationHandler implements CommandHandler<OpenOrganisationCommand> {
|
|
17
|
+
constructor(
|
|
18
|
+
private readonly organisationRepository: OrganisationRepository,
|
|
19
|
+
private readonly memberRepository: MemberRepository,
|
|
20
|
+
private readonly accountRepository: AccountRepository,
|
|
21
|
+
private readonly ids: IdGenerator,
|
|
22
|
+
private readonly clock: Clock,
|
|
23
|
+
) {}
|
|
24
|
+
|
|
25
|
+
/** The account that opens the organisation is its first owner, in the same unit of work. */
|
|
26
|
+
async execute({ actor, organisation }: OpenOrganisationCommand): Promise<string> {
|
|
27
|
+
const slug = OrganisationSlug.create(organisation.slug);
|
|
28
|
+
const name = OrganisationName.create(organisation.name);
|
|
29
|
+
const opener = await this.accountRepository.findById(actor.id);
|
|
30
|
+
|
|
31
|
+
if (opener === undefined) {
|
|
32
|
+
throw AccountError.notFound(actor.id);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
opener.assertActive();
|
|
36
|
+
|
|
37
|
+
if ((await this.organisationRepository.findById(slug.value)) !== undefined) {
|
|
38
|
+
throw OrganisationError.slugTaken(slug.value);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const now = this.clock.now();
|
|
42
|
+
const opened = Organisation.open(slug, { name, openedBy: opener.id }, now);
|
|
43
|
+
const owner = Member.join(this.ids.next(), { organisationId: opened.id, accountId: opener.id, role: MemberRole.Owner }, now);
|
|
44
|
+
|
|
45
|
+
await this.organisationRepository.save(opened);
|
|
46
|
+
await this.memberRepository.save(owner);
|
|
47
|
+
|
|
48
|
+
return opened.id;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { AuthorizedCommand, type Actor } from '@ddd-ts-kit/kernel';
|
|
2
|
+
import { Requires } from '@ddd-ts-kit/kernel/declarations';
|
|
3
|
+
import { {{context.camel}}Permissions } from '{{alias.context}}/application/authorization/{{context.kebab}}.permissions{{alias.ext}}';
|
|
4
|
+
|
|
5
|
+
/** Provisions the account of the person who signs in, from what their token says of them, or refreshes it at a later sign-in. */
|
|
6
|
+
@Requires({{context.camel}}Permissions['account.provision'], { resource: () => ({ type: 'context', id: '{{context.kebab}}' }) })
|
|
7
|
+
export class ProvisionAccountCommand extends AuthorizedCommand<string> {
|
|
8
|
+
constructor(
|
|
9
|
+
actor: Actor,
|
|
10
|
+
readonly profile: { readonly email: string; readonly emailVerified: boolean; readonly displayName: string },
|
|
11
|
+
) {
|
|
12
|
+
super(actor);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Clock } from '@ddd-ts-kit/kernel';
|
|
2
|
+
import { CommandHandler } from '@ddd-ts-kit/kernel/declarations';
|
|
3
|
+
import { Account } from '{{alias.context}}/domain/aggregates/account.aggregate{{alias.ext}}';
|
|
4
|
+
import { AccountError } from '{{alias.context}}/domain/errors/account.error{{alias.ext}}';
|
|
5
|
+
import type { AccountRepository } from '{{alias.context}}/domain/repositories/account.repository{{alias.ext}}';
|
|
6
|
+
import { DisplayName } from '{{alias.context}}/domain/value-objects/display-name.vo{{alias.ext}}';
|
|
7
|
+
import { EmailAddress } from '{{alias.context}}/domain/value-objects/email-address.vo{{alias.ext}}';
|
|
8
|
+
import { ProvisionAccountCommand } from '{{alias.context}}/application/commands/provision-account/provision-account.command{{alias.ext}}';
|
|
9
|
+
|
|
10
|
+
@CommandHandler(ProvisionAccountCommand)
|
|
11
|
+
export class ProvisionAccountHandler implements CommandHandler<ProvisionAccountCommand> {
|
|
12
|
+
constructor(
|
|
13
|
+
private readonly accountRepository: AccountRepository,
|
|
14
|
+
private readonly clock: Clock,
|
|
15
|
+
) {}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* The actor is the person the provider authenticated: their subject names the account, at the
|
|
19
|
+
* first sign-in as at the next ones. The address must be one the provider verified, since the
|
|
20
|
+
* invitations of the organisations are answered by whoever holds it.
|
|
21
|
+
*/
|
|
22
|
+
async execute({ actor, profile }: ProvisionAccountCommand): Promise<string> {
|
|
23
|
+
if (!profile.emailVerified) {
|
|
24
|
+
throw AccountError.emailNotVerified(actor.id);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const current = { email: EmailAddress.create(profile.email), displayName: DisplayName.create(profile.displayName) };
|
|
28
|
+
const known = await this.accountRepository.findById(actor.id);
|
|
29
|
+
|
|
30
|
+
if (known === undefined) {
|
|
31
|
+
await this.accountRepository.save(Account.provision(actor.id, current, this.clock.now()));
|
|
32
|
+
|
|
33
|
+
return actor.id;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
known.refreshProfile(current);
|
|
37
|
+
await this.accountRepository.save(known);
|
|
38
|
+
|
|
39
|
+
return known.id;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { AuthorizedCommand, type Actor } from '@ddd-ts-kit/kernel';
|
|
2
|
+
import { Requires } from '@ddd-ts-kit/kernel/declarations';
|
|
3
|
+
import { {{context.camel}}Permissions } from '{{alias.context}}/application/authorization/{{context.kebab}}.permissions{{alias.ext}}';
|
|
4
|
+
|
|
5
|
+
/** Removes a member from an organisation. */
|
|
6
|
+
@Requires({{context.camel}}Permissions['member.remove'], { resource: () => ({ type: 'context', id: '{{context.kebab}}' }) })
|
|
7
|
+
export class RemoveMemberCommand extends AuthorizedCommand<string> {
|
|
8
|
+
constructor(
|
|
9
|
+
actor: Actor,
|
|
10
|
+
readonly organisationId: string,
|
|
11
|
+
readonly accountId: string,
|
|
12
|
+
) {
|
|
13
|
+
super(actor);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { Access } from '@ddd-ts-kit/auth';
|
|
2
|
+
import type { Clock } from '@ddd-ts-kit/kernel';
|
|
3
|
+
import { CommandHandler } from '@ddd-ts-kit/kernel/declarations';
|
|
4
|
+
import type { Member } from '{{alias.context}}/domain/aggregates/member.aggregate{{alias.ext}}';
|
|
5
|
+
import type { Organisation } from '{{alias.context}}/domain/aggregates/organisation.aggregate{{alias.ext}}';
|
|
6
|
+
import { MemberError } from '{{alias.context}}/domain/errors/member.error{{alias.ext}}';
|
|
7
|
+
import { OrganisationError } from '{{alias.context}}/domain/errors/organisation.error{{alias.ext}}';
|
|
8
|
+
import type { DelegationRepository } from '{{alias.context}}/domain/repositories/delegation.repository{{alias.ext}}';
|
|
9
|
+
import type { MemberRepository } from '{{alias.context}}/domain/repositories/member.repository{{alias.ext}}';
|
|
10
|
+
import type { OrganisationRepository } from '{{alias.context}}/domain/repositories/organisation.repository{{alias.ext}}';
|
|
11
|
+
import { RoleRightsService, type HeldRights } from '{{alias.context}}/domain/services/role-rights.service{{alias.ext}}';
|
|
12
|
+
import { MemberRight } from '{{alias.context}}/domain/vocabularies/member-right.vocabulary{{alias.ext}}';
|
|
13
|
+
import { MemberRole } from '{{alias.context}}/domain/vocabularies/member-role.vocabulary{{alias.ext}}';
|
|
14
|
+
import { {{context.camel}}Permissions } from '{{alias.context}}/application/authorization/{{context.kebab}}.permissions{{alias.ext}}';
|
|
15
|
+
import { RemoveMemberCommand } from '{{alias.context}}/application/commands/remove-member/remove-member.command{{alias.ext}}';
|
|
16
|
+
|
|
17
|
+
@CommandHandler(RemoveMemberCommand)
|
|
18
|
+
export class RemoveMemberHandler implements CommandHandler<RemoveMemberCommand> {
|
|
19
|
+
constructor(
|
|
20
|
+
private readonly organisationRepository: OrganisationRepository,
|
|
21
|
+
private readonly memberRepository: MemberRepository,
|
|
22
|
+
private readonly delegationRepository: DelegationRepository,
|
|
23
|
+
private readonly access: Access,
|
|
24
|
+
private readonly clock: Clock,
|
|
25
|
+
) {}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Within the role of who decides; the organisation is saved with the removal, unchanged, so that
|
|
29
|
+
* its version orders the changes of its owners. Every delegation the member gave or received in
|
|
30
|
+
* the organisation ends with the membership.
|
|
31
|
+
*/
|
|
32
|
+
async execute({ actor, organisationId, accountId }: RemoveMemberCommand): Promise<string> {
|
|
33
|
+
const now = this.clock.now();
|
|
34
|
+
const held = await this.heldBy(organisationId, actor.id, now);
|
|
35
|
+
const rights = new RoleRightsService();
|
|
36
|
+
|
|
37
|
+
await this.access.authorize(actor, {{context.camel}}Permissions['member.remove'], rights.rightsIn(organisationId, actor.id, held));
|
|
38
|
+
|
|
39
|
+
const { organisation, member } = await this.membershipIn(organisationId, accountId);
|
|
40
|
+
const delegationId = rights.delegationUsedFor(MemberRight.ManageMembers, held);
|
|
41
|
+
const owners = await this.memberRepository.countOwners(organisationId);
|
|
42
|
+
|
|
43
|
+
member.remove({ by: held.member?.role ?? MemberRole.Member, byAccount: actor.id, delegationId, owners }, now);
|
|
44
|
+
await this.organisationRepository.save(organisation);
|
|
45
|
+
await this.memberRepository.save(member);
|
|
46
|
+
await this.endDelegationsInvolving(organisationId, accountId, now);
|
|
47
|
+
|
|
48
|
+
return member.id;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
private async heldBy(organisationId: string, accountId: string, now: Date): Promise<HeldRights> {
|
|
52
|
+
const member = await this.memberRepository.findOf(organisationId, accountId);
|
|
53
|
+
|
|
54
|
+
return { member, lent: await this.delegationRepository.findUnendedTo(organisationId, accountId), now };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** The organisation, to be saved with the change, and the membership the change is about. */
|
|
58
|
+
private async membershipIn(organisationId: string, accountId: string): Promise<{ organisation: Organisation; member: Member }> {
|
|
59
|
+
const organisation = await this.organisationRepository.findById(organisationId);
|
|
60
|
+
const member = await this.memberRepository.findOf(organisationId, accountId);
|
|
61
|
+
|
|
62
|
+
if (organisation === undefined) {
|
|
63
|
+
throw OrganisationError.notFound(organisationId);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (member === undefined) {
|
|
67
|
+
throw MemberError.notFound(organisationId, accountId);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return { organisation, member };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
private async endDelegationsInvolving(organisationId: string, accountId: string, now: Date): Promise<void> {
|
|
74
|
+
for (const delegation of await this.delegationRepository.findUnendedInvolving(organisationId, accountId)) {
|
|
75
|
+
delegation.end(now);
|
|
76
|
+
await this.delegationRepository.save(delegation);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { AuthorizedCommand, type Actor } from '@ddd-ts-kit/kernel';
|
|
2
|
+
import { Requires } from '@ddd-ts-kit/kernel/declarations';
|
|
3
|
+
import { {{context.camel}}Permissions } from '{{alias.context}}/application/authorization/{{context.kebab}}.permissions{{alias.ext}}';
|
|
4
|
+
|
|
5
|
+
/** Ends a delegation of an organisation before its period. */
|
|
6
|
+
@Requires({{context.camel}}Permissions['delegation.revoke'], { resource: () => ({ type: 'context', id: '{{context.kebab}}' }) })
|
|
7
|
+
export class RevokeDelegationCommand extends AuthorizedCommand<string> {
|
|
8
|
+
constructor(
|
|
9
|
+
actor: Actor,
|
|
10
|
+
readonly organisationId: string,
|
|
11
|
+
readonly delegationId: string,
|
|
12
|
+
) {
|
|
13
|
+
super(actor);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Access } from '@ddd-ts-kit/auth';
|
|
2
|
+
import type { Clock } from '@ddd-ts-kit/kernel';
|
|
3
|
+
import { CommandHandler } from '@ddd-ts-kit/kernel/declarations';
|
|
4
|
+
import { DelegationError } from '{{alias.context}}/domain/errors/delegation.error{{alias.ext}}';
|
|
5
|
+
import type { DelegationRepository } from '{{alias.context}}/domain/repositories/delegation.repository{{alias.ext}}';
|
|
6
|
+
import type { MemberRepository } from '{{alias.context}}/domain/repositories/member.repository{{alias.ext}}';
|
|
7
|
+
import { RoleRightsService } from '{{alias.context}}/domain/services/role-rights.service{{alias.ext}}';
|
|
8
|
+
import { {{context.camel}}Permissions } from '{{alias.context}}/application/authorization/{{context.kebab}}.permissions{{alias.ext}}';
|
|
9
|
+
import { RevokeDelegationCommand } from '{{alias.context}}/application/commands/revoke-delegation/revoke-delegation.command{{alias.ext}}';
|
|
10
|
+
|
|
11
|
+
@CommandHandler(RevokeDelegationCommand)
|
|
12
|
+
export class RevokeDelegationHandler implements CommandHandler<RevokeDelegationCommand> {
|
|
13
|
+
constructor(
|
|
14
|
+
private readonly delegationRepository: DelegationRepository,
|
|
15
|
+
private readonly memberRepository: MemberRepository,
|
|
16
|
+
private readonly access: Access,
|
|
17
|
+
private readonly clock: Clock,
|
|
18
|
+
) {}
|
|
19
|
+
|
|
20
|
+
/** Whoever may grant delegations in the organisation revokes them; one of another organisation is not found here. */
|
|
21
|
+
async execute({ actor, organisationId, delegationId }: RevokeDelegationCommand): Promise<string> {
|
|
22
|
+
const now = this.clock.now();
|
|
23
|
+
const member = await this.memberRepository.findOf(organisationId, actor.id);
|
|
24
|
+
const rights = new RoleRightsService().rightsIn(organisationId, actor.id, { member, lent: [], now });
|
|
25
|
+
|
|
26
|
+
await this.access.authorize(actor, {{context.camel}}Permissions['delegation.revoke'], rights);
|
|
27
|
+
|
|
28
|
+
const delegation = await this.delegationRepository.findById(delegationId);
|
|
29
|
+
|
|
30
|
+
if (delegation?.organisationId !== organisationId) {
|
|
31
|
+
throw DelegationError.notFound(delegationId);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
delegation.revoke(now);
|
|
35
|
+
await this.delegationRepository.save(delegation);
|
|
36
|
+
|
|
37
|
+
return delegation.id;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { AuthorizedCommand, type Actor } from '@ddd-ts-kit/kernel';
|
|
2
|
+
import { Requires } from '@ddd-ts-kit/kernel/declarations';
|
|
3
|
+
import { {{context.camel}}Permissions } from '{{alias.context}}/application/authorization/{{context.kebab}}.permissions{{alias.ext}}';
|
|
4
|
+
|
|
5
|
+
/** Takes back an invitation of an organisation that was not answered. */
|
|
6
|
+
@Requires({{context.camel}}Permissions['invitation.revoke'], { resource: () => ({ type: 'context', id: '{{context.kebab}}' }) })
|
|
7
|
+
export class RevokeInvitationCommand extends AuthorizedCommand<string> {
|
|
8
|
+
constructor(
|
|
9
|
+
actor: Actor,
|
|
10
|
+
readonly organisationId: string,
|
|
11
|
+
readonly invitationId: string,
|
|
12
|
+
) {
|
|
13
|
+
super(actor);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { Access } from '@ddd-ts-kit/auth';
|
|
2
|
+
import type { Clock } from '@ddd-ts-kit/kernel';
|
|
3
|
+
import { CommandHandler } from '@ddd-ts-kit/kernel/declarations';
|
|
4
|
+
import { InvitationError } from '{{alias.context}}/domain/errors/invitation.error{{alias.ext}}';
|
|
5
|
+
import type { DelegationRepository } from '{{alias.context}}/domain/repositories/delegation.repository{{alias.ext}}';
|
|
6
|
+
import type { InvitationRepository } from '{{alias.context}}/domain/repositories/invitation.repository{{alias.ext}}';
|
|
7
|
+
import type { MemberRepository } from '{{alias.context}}/domain/repositories/member.repository{{alias.ext}}';
|
|
8
|
+
import { RoleRightsService } from '{{alias.context}}/domain/services/role-rights.service{{alias.ext}}';
|
|
9
|
+
import { {{context.camel}}Permissions } from '{{alias.context}}/application/authorization/{{context.kebab}}.permissions{{alias.ext}}';
|
|
10
|
+
import { RevokeInvitationCommand } from '{{alias.context}}/application/commands/revoke-invitation/revoke-invitation.command{{alias.ext}}';
|
|
11
|
+
|
|
12
|
+
@CommandHandler(RevokeInvitationCommand)
|
|
13
|
+
export class RevokeInvitationHandler implements CommandHandler<RevokeInvitationCommand> {
|
|
14
|
+
constructor(
|
|
15
|
+
private readonly invitationRepository: InvitationRepository,
|
|
16
|
+
private readonly memberRepository: MemberRepository,
|
|
17
|
+
private readonly delegationRepository: DelegationRepository,
|
|
18
|
+
private readonly access: Access,
|
|
19
|
+
private readonly clock: Clock,
|
|
20
|
+
) {}
|
|
21
|
+
|
|
22
|
+
/** Whoever may invite in the organisation takes back its invitations: an invitation of another organisation is not found here. */
|
|
23
|
+
async execute({ actor, organisationId, invitationId }: RevokeInvitationCommand): Promise<string> {
|
|
24
|
+
const now = this.clock.now();
|
|
25
|
+
const member = await this.memberRepository.findOf(organisationId, actor.id);
|
|
26
|
+
const lent = await this.delegationRepository.findUnendedTo(organisationId, actor.id);
|
|
27
|
+
const rights = new RoleRightsService().rightsIn(organisationId, actor.id, { member, lent, now });
|
|
28
|
+
|
|
29
|
+
await this.access.authorize(actor, {{context.camel}}Permissions['invitation.revoke'], rights);
|
|
30
|
+
|
|
31
|
+
const invitation = await this.invitationRepository.findById(invitationId);
|
|
32
|
+
|
|
33
|
+
if (invitation?.organisationId !== organisationId) {
|
|
34
|
+
throw InvitationError.notFound();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
invitation.revoke(now);
|
|
38
|
+
await this.invitationRepository.save(invitation);
|
|
39
|
+
|
|
40
|
+
return invitation.id;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { IntegrationEventHandler } from '@ddd-ts-kit/kernel/declarations';
|
|
2
|
+
import { accountDeactivatedV1, type AccountDeactivatedV1 } from '{{alias.context}}/published-language/account-deactivated.v1.integration-event{{alias.ext}}';
|
|
3
|
+
import type { IdentityProviderAdmin } from '{{alias.context}}/application/ports/identity-provider-admin.port{{alias.ext}}';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The provider disables the person: they sign in no more. Delivered at least once through the
|
|
7
|
+
* outbox, so a provider down at the time of the deactivation is asked again until it answers;
|
|
8
|
+
* disabling twice changes nothing.
|
|
9
|
+
*/
|
|
10
|
+
@IntegrationEventHandler(accountDeactivatedV1, { consumer: '{{context.kebab}}.provider-disables-account' })
|
|
11
|
+
export class AccountDeactivatedIntegrationHandler {
|
|
12
|
+
static readonly eventType = accountDeactivatedV1.type;
|
|
13
|
+
|
|
14
|
+
constructor(private readonly identityProvider: IdentityProviderAdmin) {}
|
|
15
|
+
|
|
16
|
+
async handle(event: AccountDeactivatedV1): Promise<void> {
|
|
17
|
+
await this.identityProvider.disableAccount(event.payload.accountId);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { IntegrationEventHandler } from '@ddd-ts-kit/kernel/declarations';
|
|
2
|
+
import type { MemberRepository } from '{{alias.context}}/domain/repositories/member.repository{{alias.ext}}';
|
|
3
|
+
import { memberJoinedV1, type MemberJoinedV1 } from '{{alias.context}}/published-language/member-joined.v1.integration-event{{alias.ext}}';
|
|
4
|
+
import type { IdentityProviderAdmin } from '{{alias.context}}/application/ports/identity-provider-admin.port{{alias.ext}}';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The provider follows the membership: delivered at least once and in no guaranteed order, so the
|
|
8
|
+
* handler brings the provider in line with what the context holds now rather than with the fact
|
|
9
|
+
* alone. A membership already ended (removed, or its account deactivated) is taken out again,
|
|
10
|
+
* so that a late retry of this fact never gives a removed person back their organisation.
|
|
11
|
+
*/
|
|
12
|
+
@IntegrationEventHandler(memberJoinedV1, { consumer: '{{context.kebab}}.provider-follows-joined-member' })
|
|
13
|
+
export class MemberJoinedIntegrationHandler {
|
|
14
|
+
static readonly eventType = memberJoinedV1.type;
|
|
15
|
+
|
|
16
|
+
constructor(
|
|
17
|
+
private readonly memberRepository: MemberRepository,
|
|
18
|
+
private readonly identityProvider: IdentityProviderAdmin,
|
|
19
|
+
) {}
|
|
20
|
+
|
|
21
|
+
async handle(event: MemberJoinedV1): Promise<void> {
|
|
22
|
+
const { organisationId, accountId } = event.payload;
|
|
23
|
+
const current = await this.memberRepository.findOf(organisationId, accountId);
|
|
24
|
+
|
|
25
|
+
if (current === undefined) {
|
|
26
|
+
await this.identityProvider.removeMember(organisationId, accountId);
|
|
27
|
+
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
await this.identityProvider.addMember(organisationId, accountId);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { IntegrationEventHandler } from '@ddd-ts-kit/kernel/declarations';
|
|
2
|
+
import type { MemberRepository } from '{{alias.context}}/domain/repositories/member.repository{{alias.ext}}';
|
|
3
|
+
import { memberRemovedV1, type MemberRemovedV1 } from '{{alias.context}}/published-language/member-removed.v1.integration-event{{alias.ext}}';
|
|
4
|
+
import type { IdentityProviderAdmin } from '{{alias.context}}/application/ports/identity-provider-admin.port{{alias.ext}}';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The provider takes the person out of the organisation: their next token no longer names it,
|
|
8
|
+
* and with tenants they reach its data no more. Delivered at least once through the outbox, so a
|
|
9
|
+
* provider down at the time of the removal is asked again until it answers; a person who joined
|
|
10
|
+
* again since is left in, the context holding the membership now.
|
|
11
|
+
*/
|
|
12
|
+
@IntegrationEventHandler(memberRemovedV1, { consumer: '{{context.kebab}}.provider-follows-removed-member' })
|
|
13
|
+
export class MemberRemovedIntegrationHandler {
|
|
14
|
+
static readonly eventType = memberRemovedV1.type;
|
|
15
|
+
|
|
16
|
+
constructor(
|
|
17
|
+
private readonly memberRepository: MemberRepository,
|
|
18
|
+
private readonly identityProvider: IdentityProviderAdmin,
|
|
19
|
+
) {}
|
|
20
|
+
|
|
21
|
+
async handle(event: MemberRemovedV1): Promise<void> {
|
|
22
|
+
const { organisationId, accountId } = event.payload;
|
|
23
|
+
|
|
24
|
+
if ((await this.memberRepository.findOf(organisationId, accountId)) !== undefined) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
await this.identityProvider.removeMember(organisationId, accountId);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { IntegrationEventHandler } from '@ddd-ts-kit/kernel/declarations';
|
|
2
|
+
import { organisationOpenedV1, type OrganisationOpenedV1 } from '{{alias.context}}/published-language/organisation-opened.v1.integration-event{{alias.ext}}';
|
|
3
|
+
import type { IdentityProviderAdmin } from '{{alias.context}}/application/ports/identity-provider-admin.port{{alias.ext}}';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The provider learns the organisation under its slug, so that its tokens can name it. Driven by
|
|
7
|
+
* the fact the context published through its outbox, so delivered at least once: a provider that
|
|
8
|
+
* fails is asked again until it answers, and asking twice changes nothing (the adapter is idempotent).
|
|
9
|
+
*/
|
|
10
|
+
@IntegrationEventHandler(organisationOpenedV1, { consumer: '{{context.kebab}}.provider-opens-organisation' })
|
|
11
|
+
export class OrganisationOpenedIntegrationHandler {
|
|
12
|
+
static readonly eventType = organisationOpenedV1.type;
|
|
13
|
+
|
|
14
|
+
constructor(private readonly identityProvider: IdentityProviderAdmin) {}
|
|
15
|
+
|
|
16
|
+
async handle(event: OrganisationOpenedV1): Promise<void> {
|
|
17
|
+
await this.identityProvider.openOrganisation({ id: event.payload.organisationId, name: event.payload.name });
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { IdGenerator, IntegrationEventPublisher } from '@ddd-ts-kit/kernel';
|
|
2
|
+
import { DomainEventHandler } from '@ddd-ts-kit/kernel/declarations';
|
|
3
|
+
import { AccountDeactivated } from '{{alias.context}}/domain/events/account-deactivated.event{{alias.ext}}';
|
|
4
|
+
import { accountDeactivatedV1 } from '{{alias.context}}/published-language/account-deactivated.v1.integration-event{{alias.ext}}';
|
|
5
|
+
|
|
6
|
+
/** Tells the other contexts, through the outbox, in the transaction of the fact. */
|
|
7
|
+
@DomainEventHandler(AccountDeactivated, { name: AccountDeactivated.eventName })
|
|
8
|
+
export class AccountDeactivatedPublisher implements DomainEventHandler<AccountDeactivated> {
|
|
9
|
+
constructor(
|
|
10
|
+
private readonly publisher: IntegrationEventPublisher,
|
|
11
|
+
private readonly ids: IdGenerator,
|
|
12
|
+
) {}
|
|
13
|
+
|
|
14
|
+
async handle(event: AccountDeactivated): Promise<void> {
|
|
15
|
+
const published = accountDeactivatedV1.create(
|
|
16
|
+
{
|
|
17
|
+
accountId: event.aggregateId,
|
|
18
|
+
},
|
|
19
|
+
{ id: this.ids.next(), occurredAt: event.occurredAt },
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
await this.publisher.publish([published]);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { IdGenerator, IntegrationEventPublisher } from '@ddd-ts-kit/kernel';
|
|
2
|
+
import { DomainEventHandler } from '@ddd-ts-kit/kernel/declarations';
|
|
3
|
+
import { DelegationGranted } from '{{alias.context}}/domain/events/delegation-granted.event{{alias.ext}}';
|
|
4
|
+
import { delegationGrantedV1 } from '{{alias.context}}/published-language/delegation-granted.v1.integration-event{{alias.ext}}';
|
|
5
|
+
|
|
6
|
+
/** Tells the other contexts, through the outbox, in the transaction of the fact. */
|
|
7
|
+
@DomainEventHandler(DelegationGranted, { name: DelegationGranted.eventName })
|
|
8
|
+
export class DelegationGrantedPublisher implements DomainEventHandler<DelegationGranted> {
|
|
9
|
+
constructor(
|
|
10
|
+
private readonly publisher: IntegrationEventPublisher,
|
|
11
|
+
private readonly ids: IdGenerator,
|
|
12
|
+
) {}
|
|
13
|
+
|
|
14
|
+
async handle(event: DelegationGranted): Promise<void> {
|
|
15
|
+
const published = delegationGrantedV1.create(
|
|
16
|
+
{
|
|
17
|
+
delegationId: event.aggregateId,
|
|
18
|
+
organisationId: event.facts.organisationId,
|
|
19
|
+
delegatorId: event.facts.delegatorId,
|
|
20
|
+
delegateId: event.facts.delegateId,
|
|
21
|
+
rights: [...event.facts.rights],
|
|
22
|
+
startsAt: event.facts.startsAt.toISOString(),
|
|
23
|
+
endsAt: event.facts.endsAt.toISOString(),
|
|
24
|
+
},
|
|
25
|
+
{ id: this.ids.next(), occurredAt: event.occurredAt },
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
{{#if tenancy.any}}
|
|
29
|
+
// The organisation is the tenant of the fact: its consumers run in it, whoever acted.
|
|
30
|
+
await this.publisher.publish([{ ...published, tenantId: event.facts.organisationId }]);
|
|
31
|
+
{{/if}}
|
|
32
|
+
{{#unless tenancy.any}}
|
|
33
|
+
await this.publisher.publish([published]);
|
|
34
|
+
{{/unless}}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { IdGenerator, IntegrationEventPublisher } from '@ddd-ts-kit/kernel';
|
|
2
|
+
import { DomainEventHandler } from '@ddd-ts-kit/kernel/declarations';
|
|
3
|
+
import { DelegationRevoked } from '{{alias.context}}/domain/events/delegation-revoked.event{{alias.ext}}';
|
|
4
|
+
import { delegationRevokedV1 } from '{{alias.context}}/published-language/delegation-revoked.v1.integration-event{{alias.ext}}';
|
|
5
|
+
|
|
6
|
+
/** Tells the other contexts, through the outbox, in the transaction of the fact. */
|
|
7
|
+
@DomainEventHandler(DelegationRevoked, { name: DelegationRevoked.eventName })
|
|
8
|
+
export class DelegationRevokedPublisher implements DomainEventHandler<DelegationRevoked> {
|
|
9
|
+
constructor(
|
|
10
|
+
private readonly publisher: IntegrationEventPublisher,
|
|
11
|
+
private readonly ids: IdGenerator,
|
|
12
|
+
) {}
|
|
13
|
+
|
|
14
|
+
async handle(event: DelegationRevoked): Promise<void> {
|
|
15
|
+
const published = delegationRevokedV1.create(
|
|
16
|
+
{
|
|
17
|
+
delegationId: event.aggregateId,
|
|
18
|
+
organisationId: event.facts.organisationId,
|
|
19
|
+
delegatorId: event.facts.delegatorId,
|
|
20
|
+
delegateId: event.facts.delegateId,
|
|
21
|
+
},
|
|
22
|
+
{ id: this.ids.next(), occurredAt: event.occurredAt },
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
{{#if tenancy.any}}
|
|
26
|
+
// The organisation is the tenant of the fact: its consumers run in it, whoever acted.
|
|
27
|
+
await this.publisher.publish([{ ...published, tenantId: event.facts.organisationId }]);
|
|
28
|
+
{{/if}}
|
|
29
|
+
{{#unless tenancy.any}}
|
|
30
|
+
await this.publisher.publish([published]);
|
|
31
|
+
{{/unless}}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { IdGenerator, IntegrationEventPublisher } from '@ddd-ts-kit/kernel';
|
|
2
|
+
import { DomainEventHandler } from '@ddd-ts-kit/kernel/declarations';
|
|
3
|
+
import { MemberJoined } from '{{alias.context}}/domain/events/member-joined.event{{alias.ext}}';
|
|
4
|
+
import { memberJoinedV1 } from '{{alias.context}}/published-language/member-joined.v1.integration-event{{alias.ext}}';
|
|
5
|
+
|
|
6
|
+
/** Tells the other contexts, through the outbox, in the transaction of the fact. */
|
|
7
|
+
@DomainEventHandler(MemberJoined, { name: MemberJoined.eventName })
|
|
8
|
+
export class MemberJoinedPublisher implements DomainEventHandler<MemberJoined> {
|
|
9
|
+
constructor(
|
|
10
|
+
private readonly publisher: IntegrationEventPublisher,
|
|
11
|
+
private readonly ids: IdGenerator,
|
|
12
|
+
) {}
|
|
13
|
+
|
|
14
|
+
async handle(event: MemberJoined): Promise<void> {
|
|
15
|
+
const published = memberJoinedV1.create(
|
|
16
|
+
{
|
|
17
|
+
memberId: event.aggregateId,
|
|
18
|
+
organisationId: event.facts.organisationId,
|
|
19
|
+
accountId: event.facts.accountId,
|
|
20
|
+
role: event.facts.role,
|
|
21
|
+
},
|
|
22
|
+
{ id: this.ids.next(), occurredAt: event.occurredAt },
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
{{#if tenancy.any}}
|
|
26
|
+
// The organisation is the tenant of the fact: its consumers run in it, whoever acted.
|
|
27
|
+
await this.publisher.publish([{ ...published, tenantId: event.facts.organisationId }]);
|
|
28
|
+
{{/if}}
|
|
29
|
+
{{#unless tenancy.any}}
|
|
30
|
+
await this.publisher.publish([published]);
|
|
31
|
+
{{/unless}}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { IdGenerator, IntegrationEventPublisher } from '@ddd-ts-kit/kernel';
|
|
2
|
+
import { DomainEventHandler } from '@ddd-ts-kit/kernel/declarations';
|
|
3
|
+
import { MemberRemoved } from '{{alias.context}}/domain/events/member-removed.event{{alias.ext}}';
|
|
4
|
+
import { memberRemovedV1 } from '{{alias.context}}/published-language/member-removed.v1.integration-event{{alias.ext}}';
|
|
5
|
+
|
|
6
|
+
/** Tells the other contexts, through the outbox, in the transaction of the fact. */
|
|
7
|
+
@DomainEventHandler(MemberRemoved, { name: MemberRemoved.eventName })
|
|
8
|
+
export class MemberRemovedPublisher implements DomainEventHandler<MemberRemoved> {
|
|
9
|
+
constructor(
|
|
10
|
+
private readonly publisher: IntegrationEventPublisher,
|
|
11
|
+
private readonly ids: IdGenerator,
|
|
12
|
+
) {}
|
|
13
|
+
|
|
14
|
+
async handle(event: MemberRemoved): Promise<void> {
|
|
15
|
+
const published = memberRemovedV1.create(
|
|
16
|
+
{
|
|
17
|
+
memberId: event.aggregateId,
|
|
18
|
+
organisationId: event.facts.organisationId,
|
|
19
|
+
accountId: event.facts.accountId,
|
|
20
|
+
...(event.facts.delegationId === undefined ? {} : { delegationId: event.facts.delegationId }),
|
|
21
|
+
},
|
|
22
|
+
{ id: this.ids.next(), occurredAt: event.occurredAt },
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
{{#if tenancy.any}}
|
|
26
|
+
// The organisation is the tenant of the fact: its consumers run in it, whoever acted.
|
|
27
|
+
await this.publisher.publish([{ ...published, tenantId: event.facts.organisationId }]);
|
|
28
|
+
{{/if}}
|
|
29
|
+
{{#unless tenancy.any}}
|
|
30
|
+
await this.publisher.publish([published]);
|
|
31
|
+
{{/unless}}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { IdGenerator, IntegrationEventPublisher } from '@ddd-ts-kit/kernel';
|
|
2
|
+
import { DomainEventHandler } from '@ddd-ts-kit/kernel/declarations';
|
|
3
|
+
import { MemberRoleChanged } from '{{alias.context}}/domain/events/member-role-changed.event{{alias.ext}}';
|
|
4
|
+
import { memberRoleChangedV1 } from '{{alias.context}}/published-language/member-role-changed.v1.integration-event{{alias.ext}}';
|
|
5
|
+
|
|
6
|
+
/** Tells the other contexts, through the outbox, in the transaction of the fact. */
|
|
7
|
+
@DomainEventHandler(MemberRoleChanged, { name: MemberRoleChanged.eventName })
|
|
8
|
+
export class MemberRoleChangedPublisher implements DomainEventHandler<MemberRoleChanged> {
|
|
9
|
+
constructor(
|
|
10
|
+
private readonly publisher: IntegrationEventPublisher,
|
|
11
|
+
private readonly ids: IdGenerator,
|
|
12
|
+
) {}
|
|
13
|
+
|
|
14
|
+
async handle(event: MemberRoleChanged): Promise<void> {
|
|
15
|
+
const published = memberRoleChangedV1.create(
|
|
16
|
+
{
|
|
17
|
+
memberId: event.aggregateId,
|
|
18
|
+
organisationId: event.facts.organisationId,
|
|
19
|
+
accountId: event.facts.accountId,
|
|
20
|
+
from: event.facts.from,
|
|
21
|
+
to: event.facts.to,
|
|
22
|
+
...(event.facts.delegationId === undefined ? {} : { delegationId: event.facts.delegationId }),
|
|
23
|
+
},
|
|
24
|
+
{ id: this.ids.next(), occurredAt: event.occurredAt },
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
{{#if tenancy.any}}
|
|
28
|
+
// The organisation is the tenant of the fact: its consumers run in it, whoever acted.
|
|
29
|
+
await this.publisher.publish([{ ...published, tenantId: event.facts.organisationId }]);
|
|
30
|
+
{{/if}}
|
|
31
|
+
{{#unless tenancy.any}}
|
|
32
|
+
await this.publisher.publish([published]);
|
|
33
|
+
{{/unless}}
|
|
34
|
+
}
|
|
35
|
+
}
|