diff --git a/.gitignore b/.gitignore
index 634ca2aee9..1fe6ace8cc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -44,4 +44,5 @@ tmp/
console/src/app/proto/generated/
pkg/grpc/*/*.pb.*
+pkg/grpc/*/mock/*.mock.go
pkg/grpc/*/*.swagger.json
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
index 261eeb9e9f..a1ea99bb88 100644
--- a/LICENSE
+++ b/LICENSE
@@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
- Copyright [yyyy] [name of copyright owner]
+ Copyright 2020 CAOS AG
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/cmd/zitadel/caos_local.sh b/cmd/zitadel/caos_local.sh
index 817761d14d..3c323dcb64 100755
--- a/cmd/zitadel/caos_local.sh
+++ b/cmd/zitadel/caos_local.sh
@@ -67,7 +67,7 @@ export ZITADEL_SHORT_CACHE_SHARED_MAXAGE=15m
export ZITADEL_CONSOLE_ENV_DIR=../../console/src/assets/
#Org
-export ZITADEL_DEFAULT_DOMAIN=zitadel.ch
+export ZITADEL_DEFAULT_DOMAIN=localhost
#Setup
diff --git a/cmd/zitadel/setup.yaml b/cmd/zitadel/setup.yaml
index e761c2315d..df2cc6c8fb 100644
--- a/cmd/zitadel/setup.yaml
+++ b/cmd/zitadel/setup.yaml
@@ -98,4 +98,6 @@ SetUp:
Step7:
DefaultSecondFactor: 1 #SecondFactorTypeOTP
Step8:
- DefaultSecondFactor: 2 #SecondFactorTypeU2F
\ No newline at end of file
+ DefaultSecondFactor: 2 #SecondFactorTypeU2F
+ Step9:
+ Passwordless: true
\ No newline at end of file
diff --git a/cmd/zitadel/startup.yaml b/cmd/zitadel/startup.yaml
index 88f5a5e1c9..8e92800397 100644
--- a/cmd/zitadel/startup.yaml
+++ b/cmd/zitadel/startup.yaml
@@ -49,11 +49,11 @@ AuthZ:
Key: $CR_AUTHZ_KEY
Spooler:
ConcurrentWorkers: 1
- BulkLimit: 100
+ BulkLimit: 10000
FailureCountUntilSkip: 5
Auth:
- SearchLimit: 100
+ SearchLimit: 1000
Domain: $ZITADEL_DEFAULT_DOMAIN
Eventstore:
ServiceName: 'authAPI'
@@ -98,7 +98,7 @@ Auth:
Key: $CR_AUTH_KEY
Spooler:
ConcurrentWorkers: 1
- BulkLimit: 100
+ BulkLimit: 10000
FailureCountUntilSkip: 5
KeyConfig:
Size: 2048
@@ -109,7 +109,7 @@ Auth:
SigningKeyRotation: 10s
Admin:
- SearchLimit: 100
+ SearchLimit: 1000
Domain: $ZITADEL_DEFAULT_DOMAIN
Eventstore:
ServiceName: 'Admin'
@@ -142,11 +142,11 @@ Admin:
Key: $CR_ADMINAPI_KEY
Spooler:
ConcurrentWorkers: 1
- BulkLimit: 100
+ BulkLimit: 10000
FailureCountUntilSkip: 5
Mgmt:
- SearchLimit: 100
+ SearchLimit: 1000
Domain: $ZITADEL_DEFAULT_DOMAIN
Eventstore:
ServiceName: 'ManagementAPI'
@@ -179,7 +179,7 @@ Mgmt:
Key: $CR_MANAGEMENT_KEY
Spooler:
ConcurrentWorkers: 1
- BulkLimit: 100
+ BulkLimit: 10000
FailureCountUntilSkip: 5
API:
@@ -292,10 +292,6 @@ Notification:
Key: $CR_NOTIFICATION_KEY
Spooler:
ConcurrentWorkers: 1
- BulkLimit: 100
+ BulkLimit: 10000
FailureCountUntilSkip: 5
- Handlers:
- Notification:
- MinimumCycleDuration: 5s
- User:
- MinimumCycleDuration: 5s
\ No newline at end of file
+ Handlers:
\ No newline at end of file
diff --git a/cmd/zitadel/system-defaults.yaml b/cmd/zitadel/system-defaults.yaml
index 54a41bb068..1f22bf6185 100644
--- a/cmd/zitadel/system-defaults.yaml
+++ b/cmd/zitadel/system-defaults.yaml
@@ -126,7 +126,7 @@ SystemDefaults:
Text: 'DomainClaimed.Text'
ButtonText: 'DomainClaimed.ButtonText'
WebAuthN:
- ID: $ZITADEL_COOKIE_DOMAIN
+ ID: $ZITADEL_DEFAULT_DOMAIN
OriginLogin: $ZITADEL_ACCOUNTS
OriginConsole: $ZITADEL_CONSOLE
DisplayName: ZITADEL
\ No newline at end of file
diff --git a/console/package-lock.json b/console/package-lock.json
index af9edec84d..dcef7a1c80 100644
--- a/console/package-lock.json
+++ b/console/package-lock.json
@@ -4,26 +4,16 @@
"lockfileVersion": 1,
"requires": true,
"dependencies": {
- "@angular-devkit/architect": {
- "version": "0.1100.3",
- "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1100.3.tgz",
- "integrity": "sha512-PF4PlGOIVW8eYAObP7B/vfk8TaHBEWzr2NOb+kHsIJJmx11iivkHRWzzQmTUlhwnRslCcg5ngwx0IBPDzNVeTg==",
- "dev": true,
- "requires": {
- "@angular-devkit/core": "11.0.3",
- "rxjs": "6.6.3"
- }
- },
"@angular-devkit/build-angular": {
- "version": "0.1100.3",
- "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-0.1100.3.tgz",
- "integrity": "sha512-4Zng6I+QOPFx6uAdNxgKDYXeHYvowU2bANtsG0KFDxc5RN64FyqK2lZlTUPS6SejX14hOyj81/f4MIl25r7Xgg==",
+ "version": "0.1100.4",
+ "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-0.1100.4.tgz",
+ "integrity": "sha512-qVkMbtOwlo+k8fvOBOwwfKWMx06k4I1qrdjpRYAoZCt3cdje4EBepSciLrHnTB+ouIqWxpEDfEXTYBS98tXbBg==",
"dev": true,
"requires": {
- "@angular-devkit/architect": "0.1100.3",
- "@angular-devkit/build-optimizer": "0.1100.3",
- "@angular-devkit/build-webpack": "0.1100.3",
- "@angular-devkit/core": "11.0.3",
+ "@angular-devkit/architect": "0.1100.4",
+ "@angular-devkit/build-optimizer": "0.1100.4",
+ "@angular-devkit/build-webpack": "0.1100.4",
+ "@angular-devkit/core": "11.0.4",
"@babel/core": "7.12.3",
"@babel/generator": "7.12.1",
"@babel/plugin-transform-runtime": "7.12.1",
@@ -31,7 +21,7 @@
"@babel/runtime": "7.12.1",
"@babel/template": "7.10.4",
"@jsdevtools/coverage-istanbul-loader": "3.0.5",
- "@ngtools/webpack": "11.0.3",
+ "@ngtools/webpack": "11.0.4",
"ansi-colors": "4.1.1",
"autoprefixer": "9.8.6",
"babel-loader": "8.1.0",
@@ -77,7 +67,7 @@
"speed-measure-webpack-plugin": "1.3.3",
"style-loader": "2.0.0",
"stylus": "0.54.8",
- "stylus-loader": "4.1.1",
+ "stylus-loader": "4.3.1",
"terser": "5.3.7",
"terser-webpack-plugin": "4.2.3",
"text-table": "0.2.0",
@@ -91,6 +81,29 @@
"worker-plugin": "5.0.0"
},
"dependencies": {
+ "@angular-devkit/architect": {
+ "version": "0.1100.4",
+ "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1100.4.tgz",
+ "integrity": "sha512-hzTfcSUwM0jsSt9HvvSFyaoAhX9k73L7y4kmkghzIFhKhIKOp/7o3n7hAFwN/jWKKmVQpPKnYmqzm9H9OveaCQ==",
+ "dev": true,
+ "requires": {
+ "@angular-devkit/core": "11.0.4",
+ "rxjs": "6.6.3"
+ }
+ },
+ "@angular-devkit/core": {
+ "version": "11.0.4",
+ "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-11.0.4.tgz",
+ "integrity": "sha512-LgTvhZ3Ycz0QvNAH/zO1rpQQDn2JN8u9/Awy1gW/XeCC3FYmxeOj/2JCFzlKah3wJv16nMqro5WTppHt8Y++PA==",
+ "dev": true,
+ "requires": {
+ "ajv": "6.12.6",
+ "fast-json-stable-stringify": "2.1.0",
+ "magic-string": "0.25.7",
+ "rxjs": "6.6.3",
+ "source-map": "0.7.3"
+ }
+ },
"@babel/code-frame": {
"version": "7.10.4",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz",
@@ -245,9 +258,9 @@
}
},
"@babel/parser": {
- "version": "7.12.7",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.7.tgz",
- "integrity": "sha512-oWR02Ubp4xTLCAqPRiNIuMVgNO5Aif/xpXtabhzW2HWUD47XJsAB4Zd/Rg30+XeQA3juXigV7hlquOTmwqLiwg==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.10.tgz",
+ "integrity": "sha512-PJdRPwyoOqFAWfLytxrWwGrAxghCgh/yTNCYciOz8QgjflA7aZhECPZAa2VUedKg2+QMWkI0L9lynh2SNmNEgA==",
"dev": true
},
"@babel/template": {
@@ -262,29 +275,29 @@
}
},
"@babel/traverse": {
- "version": "7.12.9",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.9.tgz",
- "integrity": "sha512-iX9ajqnLdoU1s1nHt36JDI9KG4k+vmI8WgjK5d+aDTwQbL2fUnzedNedssA645Ede3PM2ma1n8Q4h2ohwXgMXw==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.10.tgz",
+ "integrity": "sha512-6aEtf0IeRgbYWzta29lePeYSk+YAFIC3kyqESeft8o5CkFlYIMX+EQDDWEiAQ9LHOA3d0oHdgrSsID/CKqXJlg==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.10.4",
- "@babel/generator": "^7.12.5",
+ "@babel/generator": "^7.12.10",
"@babel/helper-function-name": "^7.10.4",
"@babel/helper-split-export-declaration": "^7.11.0",
- "@babel/parser": "^7.12.7",
- "@babel/types": "^7.12.7",
+ "@babel/parser": "^7.12.10",
+ "@babel/types": "^7.12.10",
"debug": "^4.1.0",
"globals": "^11.1.0",
"lodash": "^4.17.19"
},
"dependencies": {
"@babel/generator": {
- "version": "7.12.5",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.5.tgz",
- "integrity": "sha512-m16TQQJ8hPt7E+OS/XVQg/7U184MLXtvuGbCdA7na61vha+ImkyyNM/9DDA0unYCVZn3ZOhng+qz48/KBOT96A==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.10.tgz",
+ "integrity": "sha512-6mCdfhWgmqLdtTkhXjnIz0LcdVCd26wS2JXRtj2XY0u5klDsXBREA/pG5NVOuVnF2LUrBGNFtQkIqqTbblg0ww==",
"dev": true,
"requires": {
- "@babel/types": "^7.12.5",
+ "@babel/types": "^7.12.10",
"jsesc": "^2.5.1",
"source-map": "^0.5.0"
}
@@ -298,9 +311,9 @@
}
},
"@babel/types": {
- "version": "7.12.7",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.7.tgz",
- "integrity": "sha512-MNyI92qZq6jrQkXvtIiykvl4WtoRrVV9MPn+ZfsoEENjiWcBQ3ZSHrkxnJWgWtLX3XXqX5hrSQ+X69wkmesXuQ==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.10.tgz",
+ "integrity": "sha512-sf6wboJV5mGyip2hIpDSKsr80RszPinEFjsHTalMxZAZkoQ2/2yQzxlcFN52SJqsyPfLtPmenL4g2KB3KJXPDw==",
"dev": true,
"requires": {
"@babel/helper-validator-identifier": "^7.10.4",
@@ -308,6 +321,18 @@
"to-fast-properties": "^2.0.0"
}
},
+ "ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "requires": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
"debug": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
@@ -341,9 +366,9 @@
}
},
"@angular-devkit/build-optimizer": {
- "version": "0.1100.3",
- "resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.1100.3.tgz",
- "integrity": "sha512-ACvi4W8iDqWJOqHZA7LLI1lldbjrouANxOb1wxgFyr6krKypU6kDXOF2ZWNdrsgDvW0zwJPKeDNFzYyvqQpe/w==",
+ "version": "0.1100.4",
+ "resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.1100.4.tgz",
+ "integrity": "sha512-C05y4qMb05PWR7l1gZwRQKiB6KIDq+p72r8Yr6jm0UO6raOtMM72R8nHnioMnGJcFtZDEAYXEF+X7soI3MMlfw==",
"dev": true,
"requires": {
"loader-utils": "2.0.0",
@@ -362,29 +387,39 @@
}
},
"@angular-devkit/build-webpack": {
- "version": "0.1100.3",
- "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1100.3.tgz",
- "integrity": "sha512-X26Vplgu8x88AMSaMOdR28XIENAHYIAW98HloFOMIuqAubZYeoxaNIYleVO5haowU3YOLsD/FijmRKNXWUnYXg==",
+ "version": "0.1100.4",
+ "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1100.4.tgz",
+ "integrity": "sha512-uxe8gNSej3KF1FgqNtJmuRDbbINh3yLtXanXhRxFQLUj8IiNR8IciIVvy6RfXC5gqxcWwy1cOefJLLnuN9AOxQ==",
"dev": true,
"requires": {
- "@angular-devkit/architect": "0.1100.3",
- "@angular-devkit/core": "11.0.3",
+ "@angular-devkit/architect": "0.1100.4",
+ "@angular-devkit/core": "11.0.4",
"rxjs": "6.6.3"
- }
- },
- "@angular-devkit/core": {
- "version": "11.0.3",
- "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-11.0.3.tgz",
- "integrity": "sha512-gJRiBj0gWDR2VtIvLvwwc/GM2MZvg1xw69ZbBJ1VuUgDqPBHdC8q3UMW3B82wdhxK+RBYa7ZOJxtIVggaHkm9g==",
- "dev": true,
- "requires": {
- "ajv": "6.12.6",
- "fast-json-stable-stringify": "2.1.0",
- "magic-string": "0.25.7",
- "rxjs": "6.6.3",
- "source-map": "0.7.3"
},
"dependencies": {
+ "@angular-devkit/architect": {
+ "version": "0.1100.4",
+ "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1100.4.tgz",
+ "integrity": "sha512-hzTfcSUwM0jsSt9HvvSFyaoAhX9k73L7y4kmkghzIFhKhIKOp/7o3n7hAFwN/jWKKmVQpPKnYmqzm9H9OveaCQ==",
+ "dev": true,
+ "requires": {
+ "@angular-devkit/core": "11.0.4",
+ "rxjs": "6.6.3"
+ }
+ },
+ "@angular-devkit/core": {
+ "version": "11.0.4",
+ "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-11.0.4.tgz",
+ "integrity": "sha512-LgTvhZ3Ycz0QvNAH/zO1rpQQDn2JN8u9/Awy1gW/XeCC3FYmxeOj/2JCFzlKah3wJv16nMqro5WTppHt8Y++PA==",
+ "dev": true,
+ "requires": {
+ "ajv": "6.12.6",
+ "fast-json-stable-stringify": "2.1.0",
+ "magic-string": "0.25.7",
+ "rxjs": "6.6.3",
+ "source-map": "0.7.3"
+ }
+ },
"ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@@ -405,50 +440,6 @@
}
}
},
- "@angular-devkit/core": {
- "version": "11.0.3",
- "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-11.0.3.tgz",
- "integrity": "sha512-gJRiBj0gWDR2VtIvLvwwc/GM2MZvg1xw69ZbBJ1VuUgDqPBHdC8q3UMW3B82wdhxK+RBYa7ZOJxtIVggaHkm9g==",
- "dev": true,
- "requires": {
- "ajv": "6.12.6",
- "fast-json-stable-stringify": "2.1.0",
- "magic-string": "0.25.7",
- "rxjs": "6.6.3",
- "source-map": "0.7.3"
- },
- "dependencies": {
- "ajv": {
- "version": "6.12.6",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
- "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
- "dev": true,
- "requires": {
- "fast-deep-equal": "^3.1.1",
- "fast-json-stable-stringify": "^2.0.0",
- "json-schema-traverse": "^0.4.1",
- "uri-js": "^4.2.2"
- }
- },
- "source-map": {
- "version": "0.7.3",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
- "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
- "dev": true
- }
- }
- },
- "@angular-devkit/schematics": {
- "version": "11.0.3",
- "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-11.0.3.tgz",
- "integrity": "sha512-VZnqgnnfyzyMluIDvGp+ZlDU2P9BnjrhacBOdqBS/jNQ7oxyE0AWrUApGXcejOJ13Z7pEf31E64P3bImcjwP+A==",
- "dev": true,
- "requires": {
- "@angular-devkit/core": "11.0.3",
- "ora": "5.1.0",
- "rxjs": "6.6.3"
- }
- },
"@angular/animations": {
"version": "11.0.0",
"resolved": "https://registry.npmjs.org/@angular/animations/-/animations-11.0.0.tgz",
@@ -467,16 +458,16 @@
}
},
"@angular/cli": {
- "version": "11.0.3",
- "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-11.0.3.tgz",
- "integrity": "sha512-ytYVvALJ1YRDZYoqNoUcE4SLyNcMyt2V+Youaasj+C43V0h1GzHZ4J6G4X9sKaaiNAGV4GKjB9r7jzCymaiq+A==",
+ "version": "11.0.4",
+ "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-11.0.4.tgz",
+ "integrity": "sha512-VkE/gx6P80EJHg13fG+gkZfd2DJmRaDAtnamcCGM4AThzoUN9XBdxc24uMLEzBb0/mJ4vpMK9+WTNIdMmzl+Tg==",
"dev": true,
"requires": {
- "@angular-devkit/architect": "0.1100.3",
- "@angular-devkit/core": "11.0.3",
- "@angular-devkit/schematics": "11.0.3",
- "@schematics/angular": "11.0.3",
- "@schematics/update": "0.1100.3",
+ "@angular-devkit/architect": "0.1100.4",
+ "@angular-devkit/core": "11.0.4",
+ "@angular-devkit/schematics": "11.0.4",
+ "@schematics/angular": "11.0.4",
+ "@schematics/update": "0.1100.4",
"@yarnpkg/lockfile": "1.1.0",
"ansi-colors": "4.1.1",
"debug": "4.2.0",
@@ -494,6 +485,52 @@
"uuid": "8.3.1"
},
"dependencies": {
+ "@angular-devkit/architect": {
+ "version": "0.1100.4",
+ "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1100.4.tgz",
+ "integrity": "sha512-hzTfcSUwM0jsSt9HvvSFyaoAhX9k73L7y4kmkghzIFhKhIKOp/7o3n7hAFwN/jWKKmVQpPKnYmqzm9H9OveaCQ==",
+ "dev": true,
+ "requires": {
+ "@angular-devkit/core": "11.0.4",
+ "rxjs": "6.6.3"
+ }
+ },
+ "@angular-devkit/core": {
+ "version": "11.0.4",
+ "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-11.0.4.tgz",
+ "integrity": "sha512-LgTvhZ3Ycz0QvNAH/zO1rpQQDn2JN8u9/Awy1gW/XeCC3FYmxeOj/2JCFzlKah3wJv16nMqro5WTppHt8Y++PA==",
+ "dev": true,
+ "requires": {
+ "ajv": "6.12.6",
+ "fast-json-stable-stringify": "2.1.0",
+ "magic-string": "0.25.7",
+ "rxjs": "6.6.3",
+ "source-map": "0.7.3"
+ }
+ },
+ "@angular-devkit/schematics": {
+ "version": "11.0.4",
+ "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-11.0.4.tgz",
+ "integrity": "sha512-fFC7qW9A1bFAZgpCfkezBA4WCRzfVFgOzwPpyt65rgSrzw0+EeHjcrUIcXlhyOXAFrTHtA9oLCfEeSjSx5HBEA==",
+ "dev": true,
+ "requires": {
+ "@angular-devkit/core": "11.0.4",
+ "ora": "5.1.0",
+ "rxjs": "6.6.3"
+ }
+ },
+ "ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "requires": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
"debug": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz",
@@ -527,6 +564,18 @@
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
"integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==",
"dev": true
+ },
+ "source-map": {
+ "version": "0.7.3",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
+ "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
+ "dev": true
+ },
+ "uuid": {
+ "version": "8.3.1",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz",
+ "integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==",
+ "dev": true
}
}
},
@@ -729,9 +778,9 @@
}
},
"@angular/language-service": {
- "version": "11.0.3",
- "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-11.0.3.tgz",
- "integrity": "sha512-9tCPCiFwXco3QJhVIAFBjUGD3RS3SBOoaUsNAB0mGTGT6xOgayo37Z5UuOOHKHdlEpTlCFVLnSVm8DMZ4ehYpw==",
+ "version": "11.0.4",
+ "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-11.0.4.tgz",
+ "integrity": "sha512-KtQxVSlZi3SwZEN4E56KHkNTFEYa3FPZfLJFm6WD1dSobFyMwJgvztO08GWSaT4S0ht0NNRD2IRt0XzBYuZkag==",
"dev": true
},
"@angular/material": {
@@ -859,12 +908,25 @@
}
},
"@babel/helper-annotate-as-pure": {
- "version": "7.10.4",
- "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz",
- "integrity": "sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.10.tgz",
+ "integrity": "sha512-XplmVbC1n+KY6jL8/fgLVXXUauDIB+lD5+GsQEh6F6GBF1dq1qy4DP4yXWzDKcoqXB3X58t61e85Fitoww4JVQ==",
"dev": true,
"requires": {
- "@babel/types": "^7.10.4"
+ "@babel/types": "^7.12.10"
+ },
+ "dependencies": {
+ "@babel/types": {
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.10.tgz",
+ "integrity": "sha512-sf6wboJV5mGyip2hIpDSKsr80RszPinEFjsHTalMxZAZkoQ2/2yQzxlcFN52SJqsyPfLtPmenL4g2KB3KJXPDw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-validator-identifier": "^7.10.4",
+ "lodash": "^4.17.19",
+ "to-fast-properties": "^2.0.0"
+ }
+ }
}
},
"@babel/helper-builder-binary-assignment-operator-visitor": {
@@ -890,14 +952,14 @@
},
"dependencies": {
"browserslist": {
- "version": "4.15.0",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.15.0.tgz",
- "integrity": "sha512-IJ1iysdMkGmjjYeRlDU8PQejVwxvVO5QOfXH7ylW31GO6LwNRSmm/SgRXtNsEXqMLl2e+2H5eEJ7sfynF8TCaQ==",
+ "version": "4.16.0",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.0.tgz",
+ "integrity": "sha512-/j6k8R0p3nxOC6kx5JGAxsnhc9ixaWJfYc+TNTzxg6+ARaESAvQGV7h0uNOB4t+pLQJZWzcrMxXOxjgsCj3dqQ==",
"dev": true,
"requires": {
- "caniuse-lite": "^1.0.30001164",
+ "caniuse-lite": "^1.0.30001165",
"colorette": "^1.2.1",
- "electron-to-chromium": "^1.3.612",
+ "electron-to-chromium": "^1.3.621",
"escalade": "^3.1.1",
"node-releases": "^1.1.67"
}
@@ -909,9 +971,9 @@
"dev": true
},
"electron-to-chromium": {
- "version": "1.3.616",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.616.tgz",
- "integrity": "sha512-CI8L38UN2BEnqXw3/oRIQTmde0LiSeqWSRlPA42ZTYgJQ8fYenzAM2Z3ni+jtILTcrs5aiXZCGJ96Pm+3/yGyQ==",
+ "version": "1.3.625",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.625.tgz",
+ "integrity": "sha512-CsLk/r0C9dAzVPa9QF74HIXduxaucsaRfqiOYvIv2PRhvyC6EOqc/KbpgToQuDVgPf3sNAFZi3iBu4vpGOwGag==",
"dev": true
},
"escalade": {
@@ -951,12 +1013,12 @@
}
},
"@babel/generator": {
- "version": "7.12.5",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.5.tgz",
- "integrity": "sha512-m16TQQJ8hPt7E+OS/XVQg/7U184MLXtvuGbCdA7na61vha+ImkyyNM/9DDA0unYCVZn3ZOhng+qz48/KBOT96A==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.10.tgz",
+ "integrity": "sha512-6mCdfhWgmqLdtTkhXjnIz0LcdVCd26wS2JXRtj2XY0u5klDsXBREA/pG5NVOuVnF2LUrBGNFtQkIqqTbblg0ww==",
"dev": true,
"requires": {
- "@babel/types": "^7.12.5",
+ "@babel/types": "^7.12.10",
"jsesc": "^2.5.1",
"source-map": "^0.5.0"
}
@@ -994,23 +1056,23 @@
}
},
"@babel/parser": {
- "version": "7.12.7",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.7.tgz",
- "integrity": "sha512-oWR02Ubp4xTLCAqPRiNIuMVgNO5Aif/xpXtabhzW2HWUD47XJsAB4Zd/Rg30+XeQA3juXigV7hlquOTmwqLiwg==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.10.tgz",
+ "integrity": "sha512-PJdRPwyoOqFAWfLytxrWwGrAxghCgh/yTNCYciOz8QgjflA7aZhECPZAa2VUedKg2+QMWkI0L9lynh2SNmNEgA==",
"dev": true
},
"@babel/traverse": {
- "version": "7.12.9",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.9.tgz",
- "integrity": "sha512-iX9ajqnLdoU1s1nHt36JDI9KG4k+vmI8WgjK5d+aDTwQbL2fUnzedNedssA645Ede3PM2ma1n8Q4h2ohwXgMXw==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.10.tgz",
+ "integrity": "sha512-6aEtf0IeRgbYWzta29lePeYSk+YAFIC3kyqESeft8o5CkFlYIMX+EQDDWEiAQ9LHOA3d0oHdgrSsID/CKqXJlg==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.10.4",
- "@babel/generator": "^7.12.5",
+ "@babel/generator": "^7.12.10",
"@babel/helper-function-name": "^7.10.4",
"@babel/helper-split-export-declaration": "^7.11.0",
- "@babel/parser": "^7.12.7",
- "@babel/types": "^7.12.7",
+ "@babel/parser": "^7.12.10",
+ "@babel/types": "^7.12.10",
"debug": "^4.1.0",
"globals": "^11.1.0",
"lodash": "^4.17.19"
@@ -1028,9 +1090,9 @@
}
},
"@babel/types": {
- "version": "7.12.7",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.7.tgz",
- "integrity": "sha512-MNyI92qZq6jrQkXvtIiykvl4WtoRrVV9MPn+ZfsoEENjiWcBQ3ZSHrkxnJWgWtLX3XXqX5hrSQ+X69wkmesXuQ==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.10.tgz",
+ "integrity": "sha512-sf6wboJV5mGyip2hIpDSKsr80RszPinEFjsHTalMxZAZkoQ2/2yQzxlcFN52SJqsyPfLtPmenL4g2KB3KJXPDw==",
"dev": true,
"requires": {
"@babel/helper-validator-identifier": "^7.10.4",
@@ -1086,9 +1148,9 @@
},
"dependencies": {
"@babel/types": {
- "version": "7.12.7",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.7.tgz",
- "integrity": "sha512-MNyI92qZq6jrQkXvtIiykvl4WtoRrVV9MPn+ZfsoEENjiWcBQ3ZSHrkxnJWgWtLX3XXqX5hrSQ+X69wkmesXuQ==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.10.tgz",
+ "integrity": "sha512-sf6wboJV5mGyip2hIpDSKsr80RszPinEFjsHTalMxZAZkoQ2/2yQzxlcFN52SJqsyPfLtPmenL4g2KB3KJXPDw==",
"dev": true,
"requires": {
"@babel/helper-validator-identifier": "^7.10.4",
@@ -1253,9 +1315,9 @@
},
"dependencies": {
"@babel/types": {
- "version": "7.12.7",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.7.tgz",
- "integrity": "sha512-MNyI92qZq6jrQkXvtIiykvl4WtoRrVV9MPn+ZfsoEENjiWcBQ3ZSHrkxnJWgWtLX3XXqX5hrSQ+X69wkmesXuQ==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.10.tgz",
+ "integrity": "sha512-sf6wboJV5mGyip2hIpDSKsr80RszPinEFjsHTalMxZAZkoQ2/2yQzxlcFN52SJqsyPfLtPmenL4g2KB3KJXPDw==",
"dev": true,
"requires": {
"@babel/helper-validator-identifier": "^7.10.4",
@@ -1330,9 +1392,9 @@
},
"dependencies": {
"@babel/types": {
- "version": "7.12.7",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.7.tgz",
- "integrity": "sha512-MNyI92qZq6jrQkXvtIiykvl4WtoRrVV9MPn+ZfsoEENjiWcBQ3ZSHrkxnJWgWtLX3XXqX5hrSQ+X69wkmesXuQ==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.10.tgz",
+ "integrity": "sha512-sf6wboJV5mGyip2hIpDSKsr80RszPinEFjsHTalMxZAZkoQ2/2yQzxlcFN52SJqsyPfLtPmenL4g2KB3KJXPDw==",
"dev": true,
"requires": {
"@babel/helper-validator-identifier": "^7.10.4",
@@ -1396,9 +1458,9 @@
}
},
"@babel/parser": {
- "version": "7.12.7",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.7.tgz",
- "integrity": "sha512-oWR02Ubp4xTLCAqPRiNIuMVgNO5Aif/xpXtabhzW2HWUD47XJsAB4Zd/Rg30+XeQA3juXigV7hlquOTmwqLiwg==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.10.tgz",
+ "integrity": "sha512-PJdRPwyoOqFAWfLytxrWwGrAxghCgh/yTNCYciOz8QgjflA7aZhECPZAa2VUedKg2+QMWkI0L9lynh2SNmNEgA==",
"dev": true
},
"@babel/template": {
@@ -1413,9 +1475,9 @@
},
"dependencies": {
"@babel/types": {
- "version": "7.12.7",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.7.tgz",
- "integrity": "sha512-MNyI92qZq6jrQkXvtIiykvl4WtoRrVV9MPn+ZfsoEENjiWcBQ3ZSHrkxnJWgWtLX3XXqX5hrSQ+X69wkmesXuQ==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.10.tgz",
+ "integrity": "sha512-sf6wboJV5mGyip2hIpDSKsr80RszPinEFjsHTalMxZAZkoQ2/2yQzxlcFN52SJqsyPfLtPmenL4g2KB3KJXPDw==",
"dev": true,
"requires": {
"@babel/helper-validator-identifier": "^7.10.4",
@@ -1759,9 +1821,9 @@
}
},
"@babel/types": {
- "version": "7.12.7",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.7.tgz",
- "integrity": "sha512-MNyI92qZq6jrQkXvtIiykvl4WtoRrVV9MPn+ZfsoEENjiWcBQ3ZSHrkxnJWgWtLX3XXqX5hrSQ+X69wkmesXuQ==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.10.tgz",
+ "integrity": "sha512-sf6wboJV5mGyip2hIpDSKsr80RszPinEFjsHTalMxZAZkoQ2/2yQzxlcFN52SJqsyPfLtPmenL4g2KB3KJXPDw==",
"dev": true,
"requires": {
"@babel/helper-validator-identifier": "^7.10.4",
@@ -1815,12 +1877,12 @@
}
},
"@babel/generator": {
- "version": "7.12.5",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.5.tgz",
- "integrity": "sha512-m16TQQJ8hPt7E+OS/XVQg/7U184MLXtvuGbCdA7na61vha+ImkyyNM/9DDA0unYCVZn3ZOhng+qz48/KBOT96A==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.10.tgz",
+ "integrity": "sha512-6mCdfhWgmqLdtTkhXjnIz0LcdVCd26wS2JXRtj2XY0u5klDsXBREA/pG5NVOuVnF2LUrBGNFtQkIqqTbblg0ww==",
"dev": true,
"requires": {
- "@babel/types": "^7.12.5",
+ "@babel/types": "^7.12.10",
"jsesc": "^2.5.1",
"source-map": "^0.5.0"
}
@@ -1858,23 +1920,23 @@
}
},
"@babel/parser": {
- "version": "7.12.7",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.7.tgz",
- "integrity": "sha512-oWR02Ubp4xTLCAqPRiNIuMVgNO5Aif/xpXtabhzW2HWUD47XJsAB4Zd/Rg30+XeQA3juXigV7hlquOTmwqLiwg==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.10.tgz",
+ "integrity": "sha512-PJdRPwyoOqFAWfLytxrWwGrAxghCgh/yTNCYciOz8QgjflA7aZhECPZAa2VUedKg2+QMWkI0L9lynh2SNmNEgA==",
"dev": true
},
"@babel/traverse": {
- "version": "7.12.9",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.9.tgz",
- "integrity": "sha512-iX9ajqnLdoU1s1nHt36JDI9KG4k+vmI8WgjK5d+aDTwQbL2fUnzedNedssA645Ede3PM2ma1n8Q4h2ohwXgMXw==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.10.tgz",
+ "integrity": "sha512-6aEtf0IeRgbYWzta29lePeYSk+YAFIC3kyqESeft8o5CkFlYIMX+EQDDWEiAQ9LHOA3d0oHdgrSsID/CKqXJlg==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.10.4",
- "@babel/generator": "^7.12.5",
+ "@babel/generator": "^7.12.10",
"@babel/helper-function-name": "^7.10.4",
"@babel/helper-split-export-declaration": "^7.11.0",
- "@babel/parser": "^7.12.7",
- "@babel/types": "^7.12.7",
+ "@babel/parser": "^7.12.10",
+ "@babel/types": "^7.12.10",
"debug": "^4.1.0",
"globals": "^11.1.0",
"lodash": "^4.17.19"
@@ -1892,9 +1954,9 @@
}
},
"@babel/types": {
- "version": "7.12.7",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.7.tgz",
- "integrity": "sha512-MNyI92qZq6jrQkXvtIiykvl4WtoRrVV9MPn+ZfsoEENjiWcBQ3ZSHrkxnJWgWtLX3XXqX5hrSQ+X69wkmesXuQ==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.10.tgz",
+ "integrity": "sha512-sf6wboJV5mGyip2hIpDSKsr80RszPinEFjsHTalMxZAZkoQ2/2yQzxlcFN52SJqsyPfLtPmenL4g2KB3KJXPDw==",
"dev": true,
"requires": {
"@babel/helper-validator-identifier": "^7.10.4",
@@ -2024,12 +2086,12 @@
}
},
"@babel/generator": {
- "version": "7.12.5",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.5.tgz",
- "integrity": "sha512-m16TQQJ8hPt7E+OS/XVQg/7U184MLXtvuGbCdA7na61vha+ImkyyNM/9DDA0unYCVZn3ZOhng+qz48/KBOT96A==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.10.tgz",
+ "integrity": "sha512-6mCdfhWgmqLdtTkhXjnIz0LcdVCd26wS2JXRtj2XY0u5klDsXBREA/pG5NVOuVnF2LUrBGNFtQkIqqTbblg0ww==",
"dev": true,
"requires": {
- "@babel/types": "^7.12.5",
+ "@babel/types": "^7.12.10",
"jsesc": "^2.5.1",
"source-map": "^0.5.0"
}
@@ -2111,9 +2173,9 @@
}
},
"@babel/parser": {
- "version": "7.12.7",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.7.tgz",
- "integrity": "sha512-oWR02Ubp4xTLCAqPRiNIuMVgNO5Aif/xpXtabhzW2HWUD47XJsAB4Zd/Rg30+XeQA3juXigV7hlquOTmwqLiwg==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.10.tgz",
+ "integrity": "sha512-PJdRPwyoOqFAWfLytxrWwGrAxghCgh/yTNCYciOz8QgjflA7aZhECPZAa2VUedKg2+QMWkI0L9lynh2SNmNEgA==",
"dev": true
},
"@babel/template": {
@@ -2128,26 +2190,26 @@
}
},
"@babel/traverse": {
- "version": "7.12.9",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.9.tgz",
- "integrity": "sha512-iX9ajqnLdoU1s1nHt36JDI9KG4k+vmI8WgjK5d+aDTwQbL2fUnzedNedssA645Ede3PM2ma1n8Q4h2ohwXgMXw==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.10.tgz",
+ "integrity": "sha512-6aEtf0IeRgbYWzta29lePeYSk+YAFIC3kyqESeft8o5CkFlYIMX+EQDDWEiAQ9LHOA3d0oHdgrSsID/CKqXJlg==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.10.4",
- "@babel/generator": "^7.12.5",
+ "@babel/generator": "^7.12.10",
"@babel/helper-function-name": "^7.10.4",
"@babel/helper-split-export-declaration": "^7.11.0",
- "@babel/parser": "^7.12.7",
- "@babel/types": "^7.12.7",
+ "@babel/parser": "^7.12.10",
+ "@babel/types": "^7.12.10",
"debug": "^4.1.0",
"globals": "^11.1.0",
"lodash": "^4.17.19"
}
},
"@babel/types": {
- "version": "7.12.7",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.7.tgz",
- "integrity": "sha512-MNyI92qZq6jrQkXvtIiykvl4WtoRrVV9MPn+ZfsoEENjiWcBQ3ZSHrkxnJWgWtLX3XXqX5hrSQ+X69wkmesXuQ==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.10.tgz",
+ "integrity": "sha512-sf6wboJV5mGyip2hIpDSKsr80RszPinEFjsHTalMxZAZkoQ2/2yQzxlcFN52SJqsyPfLtPmenL4g2KB3KJXPDw==",
"dev": true,
"requires": {
"@babel/helper-validator-identifier": "^7.10.4",
@@ -2194,12 +2256,12 @@
}
},
"@babel/generator": {
- "version": "7.12.5",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.5.tgz",
- "integrity": "sha512-m16TQQJ8hPt7E+OS/XVQg/7U184MLXtvuGbCdA7na61vha+ImkyyNM/9DDA0unYCVZn3ZOhng+qz48/KBOT96A==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.10.tgz",
+ "integrity": "sha512-6mCdfhWgmqLdtTkhXjnIz0LcdVCd26wS2JXRtj2XY0u5klDsXBREA/pG5NVOuVnF2LUrBGNFtQkIqqTbblg0ww==",
"dev": true,
"requires": {
- "@babel/types": "^7.12.5",
+ "@babel/types": "^7.12.10",
"jsesc": "^2.5.1",
"source-map": "^0.5.0"
}
@@ -2281,9 +2343,9 @@
}
},
"@babel/parser": {
- "version": "7.12.7",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.7.tgz",
- "integrity": "sha512-oWR02Ubp4xTLCAqPRiNIuMVgNO5Aif/xpXtabhzW2HWUD47XJsAB4Zd/Rg30+XeQA3juXigV7hlquOTmwqLiwg==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.10.tgz",
+ "integrity": "sha512-PJdRPwyoOqFAWfLytxrWwGrAxghCgh/yTNCYciOz8QgjflA7aZhECPZAa2VUedKg2+QMWkI0L9lynh2SNmNEgA==",
"dev": true
},
"@babel/template": {
@@ -2298,26 +2360,26 @@
}
},
"@babel/traverse": {
- "version": "7.12.9",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.9.tgz",
- "integrity": "sha512-iX9ajqnLdoU1s1nHt36JDI9KG4k+vmI8WgjK5d+aDTwQbL2fUnzedNedssA645Ede3PM2ma1n8Q4h2ohwXgMXw==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.10.tgz",
+ "integrity": "sha512-6aEtf0IeRgbYWzta29lePeYSk+YAFIC3kyqESeft8o5CkFlYIMX+EQDDWEiAQ9LHOA3d0oHdgrSsID/CKqXJlg==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.10.4",
- "@babel/generator": "^7.12.5",
+ "@babel/generator": "^7.12.10",
"@babel/helper-function-name": "^7.10.4",
"@babel/helper-split-export-declaration": "^7.11.0",
- "@babel/parser": "^7.12.7",
- "@babel/types": "^7.12.7",
+ "@babel/parser": "^7.12.10",
+ "@babel/types": "^7.12.10",
"debug": "^4.1.0",
"globals": "^11.1.0",
"lodash": "^4.17.19"
}
},
"@babel/types": {
- "version": "7.12.7",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.7.tgz",
- "integrity": "sha512-MNyI92qZq6jrQkXvtIiykvl4WtoRrVV9MPn+ZfsoEENjiWcBQ3ZSHrkxnJWgWtLX3XXqX5hrSQ+X69wkmesXuQ==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.10.tgz",
+ "integrity": "sha512-sf6wboJV5mGyip2hIpDSKsr80RszPinEFjsHTalMxZAZkoQ2/2yQzxlcFN52SJqsyPfLtPmenL4g2KB3KJXPDw==",
"dev": true,
"requires": {
"@babel/helper-validator-identifier": "^7.10.4",
@@ -2365,12 +2427,12 @@
}
},
"@babel/generator": {
- "version": "7.12.5",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.5.tgz",
- "integrity": "sha512-m16TQQJ8hPt7E+OS/XVQg/7U184MLXtvuGbCdA7na61vha+ImkyyNM/9DDA0unYCVZn3ZOhng+qz48/KBOT96A==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.10.tgz",
+ "integrity": "sha512-6mCdfhWgmqLdtTkhXjnIz0LcdVCd26wS2JXRtj2XY0u5klDsXBREA/pG5NVOuVnF2LUrBGNFtQkIqqTbblg0ww==",
"dev": true,
"requires": {
- "@babel/types": "^7.12.5",
+ "@babel/types": "^7.12.10",
"jsesc": "^2.5.1",
"source-map": "^0.5.0"
}
@@ -2452,9 +2514,9 @@
}
},
"@babel/parser": {
- "version": "7.12.7",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.7.tgz",
- "integrity": "sha512-oWR02Ubp4xTLCAqPRiNIuMVgNO5Aif/xpXtabhzW2HWUD47XJsAB4Zd/Rg30+XeQA3juXigV7hlquOTmwqLiwg==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.10.tgz",
+ "integrity": "sha512-PJdRPwyoOqFAWfLytxrWwGrAxghCgh/yTNCYciOz8QgjflA7aZhECPZAa2VUedKg2+QMWkI0L9lynh2SNmNEgA==",
"dev": true
},
"@babel/template": {
@@ -2469,26 +2531,26 @@
}
},
"@babel/traverse": {
- "version": "7.12.9",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.9.tgz",
- "integrity": "sha512-iX9ajqnLdoU1s1nHt36JDI9KG4k+vmI8WgjK5d+aDTwQbL2fUnzedNedssA645Ede3PM2ma1n8Q4h2ohwXgMXw==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.10.tgz",
+ "integrity": "sha512-6aEtf0IeRgbYWzta29lePeYSk+YAFIC3kyqESeft8o5CkFlYIMX+EQDDWEiAQ9LHOA3d0oHdgrSsID/CKqXJlg==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.10.4",
- "@babel/generator": "^7.12.5",
+ "@babel/generator": "^7.12.10",
"@babel/helper-function-name": "^7.10.4",
"@babel/helper-split-export-declaration": "^7.11.0",
- "@babel/parser": "^7.12.7",
- "@babel/types": "^7.12.7",
+ "@babel/parser": "^7.12.10",
+ "@babel/types": "^7.12.10",
"debug": "^4.1.0",
"globals": "^11.1.0",
"lodash": "^4.17.19"
}
},
"@babel/types": {
- "version": "7.12.7",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.7.tgz",
- "integrity": "sha512-MNyI92qZq6jrQkXvtIiykvl4WtoRrVV9MPn+ZfsoEENjiWcBQ3ZSHrkxnJWgWtLX3XXqX5hrSQ+X69wkmesXuQ==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.10.tgz",
+ "integrity": "sha512-sf6wboJV5mGyip2hIpDSKsr80RszPinEFjsHTalMxZAZkoQ2/2yQzxlcFN52SJqsyPfLtPmenL4g2KB3KJXPDw==",
"dev": true,
"requires": {
"@babel/helper-validator-identifier": "^7.10.4",
@@ -2533,12 +2595,12 @@
}
},
"@babel/generator": {
- "version": "7.12.5",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.5.tgz",
- "integrity": "sha512-m16TQQJ8hPt7E+OS/XVQg/7U184MLXtvuGbCdA7na61vha+ImkyyNM/9DDA0unYCVZn3ZOhng+qz48/KBOT96A==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.10.tgz",
+ "integrity": "sha512-6mCdfhWgmqLdtTkhXjnIz0LcdVCd26wS2JXRtj2XY0u5klDsXBREA/pG5NVOuVnF2LUrBGNFtQkIqqTbblg0ww==",
"dev": true,
"requires": {
- "@babel/types": "^7.12.5",
+ "@babel/types": "^7.12.10",
"jsesc": "^2.5.1",
"source-map": "^0.5.0"
}
@@ -2620,9 +2682,9 @@
}
},
"@babel/parser": {
- "version": "7.12.7",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.7.tgz",
- "integrity": "sha512-oWR02Ubp4xTLCAqPRiNIuMVgNO5Aif/xpXtabhzW2HWUD47XJsAB4Zd/Rg30+XeQA3juXigV7hlquOTmwqLiwg==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.10.tgz",
+ "integrity": "sha512-PJdRPwyoOqFAWfLytxrWwGrAxghCgh/yTNCYciOz8QgjflA7aZhECPZAa2VUedKg2+QMWkI0L9lynh2SNmNEgA==",
"dev": true
},
"@babel/template": {
@@ -2637,26 +2699,26 @@
}
},
"@babel/traverse": {
- "version": "7.12.9",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.9.tgz",
- "integrity": "sha512-iX9ajqnLdoU1s1nHt36JDI9KG4k+vmI8WgjK5d+aDTwQbL2fUnzedNedssA645Ede3PM2ma1n8Q4h2ohwXgMXw==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.10.tgz",
+ "integrity": "sha512-6aEtf0IeRgbYWzta29lePeYSk+YAFIC3kyqESeft8o5CkFlYIMX+EQDDWEiAQ9LHOA3d0oHdgrSsID/CKqXJlg==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.10.4",
- "@babel/generator": "^7.12.5",
+ "@babel/generator": "^7.12.10",
"@babel/helper-function-name": "^7.10.4",
"@babel/helper-split-export-declaration": "^7.11.0",
- "@babel/parser": "^7.12.7",
- "@babel/types": "^7.12.7",
+ "@babel/parser": "^7.12.10",
+ "@babel/types": "^7.12.10",
"debug": "^4.1.0",
"globals": "^11.1.0",
"lodash": "^4.17.19"
}
},
"@babel/types": {
- "version": "7.12.7",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.7.tgz",
- "integrity": "sha512-MNyI92qZq6jrQkXvtIiykvl4WtoRrVV9MPn+ZfsoEENjiWcBQ3ZSHrkxnJWgWtLX3XXqX5hrSQ+X69wkmesXuQ==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.10.tgz",
+ "integrity": "sha512-sf6wboJV5mGyip2hIpDSKsr80RszPinEFjsHTalMxZAZkoQ2/2yQzxlcFN52SJqsyPfLtPmenL4g2KB3KJXPDw==",
"dev": true,
"requires": {
"@babel/helper-validator-identifier": "^7.10.4",
@@ -2719,12 +2781,12 @@
}
},
"@babel/generator": {
- "version": "7.12.5",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.5.tgz",
- "integrity": "sha512-m16TQQJ8hPt7E+OS/XVQg/7U184MLXtvuGbCdA7na61vha+ImkyyNM/9DDA0unYCVZn3ZOhng+qz48/KBOT96A==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.10.tgz",
+ "integrity": "sha512-6mCdfhWgmqLdtTkhXjnIz0LcdVCd26wS2JXRtj2XY0u5klDsXBREA/pG5NVOuVnF2LUrBGNFtQkIqqTbblg0ww==",
"dev": true,
"requires": {
- "@babel/types": "^7.12.5",
+ "@babel/types": "^7.12.10",
"jsesc": "^2.5.1",
"source-map": "^0.5.0"
}
@@ -2771,32 +2833,32 @@
}
},
"@babel/parser": {
- "version": "7.12.7",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.7.tgz",
- "integrity": "sha512-oWR02Ubp4xTLCAqPRiNIuMVgNO5Aif/xpXtabhzW2HWUD47XJsAB4Zd/Rg30+XeQA3juXigV7hlquOTmwqLiwg==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.10.tgz",
+ "integrity": "sha512-PJdRPwyoOqFAWfLytxrWwGrAxghCgh/yTNCYciOz8QgjflA7aZhECPZAa2VUedKg2+QMWkI0L9lynh2SNmNEgA==",
"dev": true
},
"@babel/traverse": {
- "version": "7.12.9",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.9.tgz",
- "integrity": "sha512-iX9ajqnLdoU1s1nHt36JDI9KG4k+vmI8WgjK5d+aDTwQbL2fUnzedNedssA645Ede3PM2ma1n8Q4h2ohwXgMXw==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.10.tgz",
+ "integrity": "sha512-6aEtf0IeRgbYWzta29lePeYSk+YAFIC3kyqESeft8o5CkFlYIMX+EQDDWEiAQ9LHOA3d0oHdgrSsID/CKqXJlg==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.10.4",
- "@babel/generator": "^7.12.5",
+ "@babel/generator": "^7.12.10",
"@babel/helper-function-name": "^7.10.4",
"@babel/helper-split-export-declaration": "^7.11.0",
- "@babel/parser": "^7.12.7",
- "@babel/types": "^7.12.7",
+ "@babel/parser": "^7.12.10",
+ "@babel/types": "^7.12.10",
"debug": "^4.1.0",
"globals": "^11.1.0",
"lodash": "^4.17.19"
}
},
"@babel/types": {
- "version": "7.12.7",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.7.tgz",
- "integrity": "sha512-MNyI92qZq6jrQkXvtIiykvl4WtoRrVV9MPn+ZfsoEENjiWcBQ3ZSHrkxnJWgWtLX3XXqX5hrSQ+X69wkmesXuQ==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.10.tgz",
+ "integrity": "sha512-sf6wboJV5mGyip2hIpDSKsr80RszPinEFjsHTalMxZAZkoQ2/2yQzxlcFN52SJqsyPfLtPmenL4g2KB3KJXPDw==",
"dev": true,
"requires": {
"@babel/helper-validator-identifier": "^7.10.4",
@@ -2879,9 +2941,9 @@
}
},
"@babel/types": {
- "version": "7.12.7",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.7.tgz",
- "integrity": "sha512-MNyI92qZq6jrQkXvtIiykvl4WtoRrVV9MPn+ZfsoEENjiWcBQ3ZSHrkxnJWgWtLX3XXqX5hrSQ+X69wkmesXuQ==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.10.tgz",
+ "integrity": "sha512-sf6wboJV5mGyip2hIpDSKsr80RszPinEFjsHTalMxZAZkoQ2/2yQzxlcFN52SJqsyPfLtPmenL4g2KB3KJXPDw==",
"dev": true,
"requires": {
"@babel/helper-validator-identifier": "^7.10.4",
@@ -2929,9 +2991,9 @@
}
},
"@babel/plugin-transform-typeof-symbol": {
- "version": "7.12.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.1.tgz",
- "integrity": "sha512-EPGgpGy+O5Kg5pJFNDKuxt9RdmTgj5sgrus2XVeMp/ZIbOESadgILUbm50SNpghOh3/6yrbsH+NB5+WJTmsA7Q==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.10.tgz",
+ "integrity": "sha512-JQ6H8Rnsogh//ijxspCjc21YPd3VLVoYtAwv3zQmqAt8YGYUtdo5usNhdl4b9/Vir2kPFZl6n1h0PfUz4hJhaA==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.10.4"
@@ -3040,9 +3102,9 @@
}
},
"@babel/types": {
- "version": "7.12.7",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.7.tgz",
- "integrity": "sha512-MNyI92qZq6jrQkXvtIiykvl4WtoRrVV9MPn+ZfsoEENjiWcBQ3ZSHrkxnJWgWtLX3XXqX5hrSQ+X69wkmesXuQ==",
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.10.tgz",
+ "integrity": "sha512-sf6wboJV5mGyip2hIpDSKsr80RszPinEFjsHTalMxZAZkoQ2/2yQzxlcFN52SJqsyPfLtPmenL4g2KB3KJXPDw==",
"dev": true,
"requires": {
"@babel/helper-validator-identifier": "^7.10.4",
@@ -3181,14 +3243,47 @@
}
},
"@ngtools/webpack": {
- "version": "11.0.3",
- "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-11.0.3.tgz",
- "integrity": "sha512-TbWharROiFA88HOLvchtSwJfnFJEgn8HcdXRDX7EL2efDYC8UVZfXms58MCEQUk66ZjikNeIHPQml5rStSqPKQ==",
+ "version": "11.0.4",
+ "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-11.0.4.tgz",
+ "integrity": "sha512-MAV7inQmsMISTnDcXwyRX5oJZx8F7K/tZRLJciQwkM0DqZyq8fI9KDRwBcmYeQ+J0mSJV9LUVdExmpulpkywqw==",
"dev": true,
"requires": {
- "@angular-devkit/core": "11.0.3",
+ "@angular-devkit/core": "11.0.4",
"enhanced-resolve": "5.3.1",
"webpack-sources": "2.0.1"
+ },
+ "dependencies": {
+ "@angular-devkit/core": {
+ "version": "11.0.4",
+ "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-11.0.4.tgz",
+ "integrity": "sha512-LgTvhZ3Ycz0QvNAH/zO1rpQQDn2JN8u9/Awy1gW/XeCC3FYmxeOj/2JCFzlKah3wJv16nMqro5WTppHt8Y++PA==",
+ "dev": true,
+ "requires": {
+ "ajv": "6.12.6",
+ "fast-json-stable-stringify": "2.1.0",
+ "magic-string": "0.25.7",
+ "rxjs": "6.6.3",
+ "source-map": "0.7.3"
+ }
+ },
+ "ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "requires": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "source-map": {
+ "version": "0.7.3",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
+ "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
+ "dev": true
+ }
}
},
"@ngx-translate/core": {
@@ -3305,24 +3400,68 @@
"integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA="
},
"@schematics/angular": {
- "version": "11.0.3",
- "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-11.0.3.tgz",
- "integrity": "sha512-H+rWJOafl8OXrC/GMJihWYTFsR2K49tWM6AyJLBxja6qyZwwL184SLPvvkPsz3+LDs+fxfOzQ1K+sIpuZLqizw==",
+ "version": "11.0.4",
+ "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-11.0.4.tgz",
+ "integrity": "sha512-LwBD9TIoLy9XqqInJvlN4BHtPyJExyeorNiOp6rXb/wafuDbvZ+9kY9GWZTY1auVo5PNKqErfxr74ydA3FFb9g==",
"dev": true,
"requires": {
- "@angular-devkit/core": "11.0.3",
- "@angular-devkit/schematics": "11.0.3",
+ "@angular-devkit/core": "11.0.4",
+ "@angular-devkit/schematics": "11.0.4",
"jsonc-parser": "2.3.1"
+ },
+ "dependencies": {
+ "@angular-devkit/core": {
+ "version": "11.0.4",
+ "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-11.0.4.tgz",
+ "integrity": "sha512-LgTvhZ3Ycz0QvNAH/zO1rpQQDn2JN8u9/Awy1gW/XeCC3FYmxeOj/2JCFzlKah3wJv16nMqro5WTppHt8Y++PA==",
+ "dev": true,
+ "requires": {
+ "ajv": "6.12.6",
+ "fast-json-stable-stringify": "2.1.0",
+ "magic-string": "0.25.7",
+ "rxjs": "6.6.3",
+ "source-map": "0.7.3"
+ }
+ },
+ "@angular-devkit/schematics": {
+ "version": "11.0.4",
+ "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-11.0.4.tgz",
+ "integrity": "sha512-fFC7qW9A1bFAZgpCfkezBA4WCRzfVFgOzwPpyt65rgSrzw0+EeHjcrUIcXlhyOXAFrTHtA9oLCfEeSjSx5HBEA==",
+ "dev": true,
+ "requires": {
+ "@angular-devkit/core": "11.0.4",
+ "ora": "5.1.0",
+ "rxjs": "6.6.3"
+ }
+ },
+ "ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "requires": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "source-map": {
+ "version": "0.7.3",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
+ "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
+ "dev": true
+ }
}
},
"@schematics/update": {
- "version": "0.1100.3",
- "resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.1100.3.tgz",
- "integrity": "sha512-Hp+RVuVLYkJhGYzLY3kwSqk8nh9zC9F9AAR4QuwSXQv+pQxRbv48fdU3iVuKu/mVhz17RZJhTNoA/2uNMeGH2g==",
+ "version": "0.1100.4",
+ "resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.1100.4.tgz",
+ "integrity": "sha512-YwFtgxCQQkYC89IC7dfshyGr0roE6bpp5HgpQLdS/AOjHeZKo7/SPdM0W4ddB+Fml1Fo6v4eFG/Ia9oR7qNv1A==",
"dev": true,
"requires": {
- "@angular-devkit/core": "11.0.3",
- "@angular-devkit/schematics": "11.0.3",
+ "@angular-devkit/core": "11.0.4",
+ "@angular-devkit/schematics": "11.0.4",
"@yarnpkg/lockfile": "1.1.0",
"ini": "1.3.5",
"npm-package-arg": "^8.0.0",
@@ -3331,11 +3470,53 @@
"semver-intersect": "1.4.0"
},
"dependencies": {
+ "@angular-devkit/core": {
+ "version": "11.0.4",
+ "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-11.0.4.tgz",
+ "integrity": "sha512-LgTvhZ3Ycz0QvNAH/zO1rpQQDn2JN8u9/Awy1gW/XeCC3FYmxeOj/2JCFzlKah3wJv16nMqro5WTppHt8Y++PA==",
+ "dev": true,
+ "requires": {
+ "ajv": "6.12.6",
+ "fast-json-stable-stringify": "2.1.0",
+ "magic-string": "0.25.7",
+ "rxjs": "6.6.3",
+ "source-map": "0.7.3"
+ }
+ },
+ "@angular-devkit/schematics": {
+ "version": "11.0.4",
+ "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-11.0.4.tgz",
+ "integrity": "sha512-fFC7qW9A1bFAZgpCfkezBA4WCRzfVFgOzwPpyt65rgSrzw0+EeHjcrUIcXlhyOXAFrTHtA9oLCfEeSjSx5HBEA==",
+ "dev": true,
+ "requires": {
+ "@angular-devkit/core": "11.0.4",
+ "ora": "5.1.0",
+ "rxjs": "6.6.3"
+ }
+ },
+ "ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "requires": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
"semver": {
"version": "7.3.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
"integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==",
"dev": true
+ },
+ "source-map": {
+ "version": "0.7.3",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
+ "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
+ "dev": true
}
}
},
@@ -3441,9 +3622,9 @@
"dev": true
},
"@types/node": {
- "version": "14.14.10",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.10.tgz",
- "integrity": "sha512-J32dgx2hw8vXrSbu4ZlVhn1Nm3GbeCFNw2FWL8S5QKucHGY0cyNwjdQdO+KMBZ4wpmC7KhLCiNsdk1RFRIYUQQ=="
+ "version": "14.14.13",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.13.tgz",
+ "integrity": "sha512-vbxr0VZ8exFMMAjCW8rJwaya0dMCDyYW2ZRdTyjtrCvJoENMpdUHOT/eTzvgyA5ZnqRZ/sI0NwqAxNHKYokLJQ=="
},
"@types/normalize-package-data": {
"version": "2.4.0",
@@ -5481,14 +5662,14 @@
},
"dependencies": {
"browserslist": {
- "version": "4.15.0",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.15.0.tgz",
- "integrity": "sha512-IJ1iysdMkGmjjYeRlDU8PQejVwxvVO5QOfXH7ylW31GO6LwNRSmm/SgRXtNsEXqMLl2e+2H5eEJ7sfynF8TCaQ==",
+ "version": "4.16.0",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.0.tgz",
+ "integrity": "sha512-/j6k8R0p3nxOC6kx5JGAxsnhc9ixaWJfYc+TNTzxg6+ARaESAvQGV7h0uNOB4t+pLQJZWzcrMxXOxjgsCj3dqQ==",
"dev": true,
"requires": {
- "caniuse-lite": "^1.0.30001164",
+ "caniuse-lite": "^1.0.30001165",
"colorette": "^1.2.1",
- "electron-to-chromium": "^1.3.612",
+ "electron-to-chromium": "^1.3.621",
"escalade": "^3.1.1",
"node-releases": "^1.1.67"
}
@@ -5500,9 +5681,9 @@
"dev": true
},
"electron-to-chromium": {
- "version": "1.3.616",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.616.tgz",
- "integrity": "sha512-CI8L38UN2BEnqXw3/oRIQTmde0LiSeqWSRlPA42ZTYgJQ8fYenzAM2Z3ni+jtILTcrs5aiXZCGJ96Pm+3/yGyQ==",
+ "version": "1.3.625",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.625.tgz",
+ "integrity": "sha512-CsLk/r0C9dAzVPa9QF74HIXduxaucsaRfqiOYvIv2PRhvyC6EOqc/KbpgToQuDVgPf3sNAFZi3iBu4vpGOwGag==",
"dev": true
},
"escalade": {
@@ -8067,9 +8248,9 @@
"dev": true
},
"html-entities": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.3.1.tgz",
- "integrity": "sha512-rhE/4Z3hIhzHAUKbW8jVcCyuT5oJCXXqhN/6mXXVCpzTmvJnoH2HL/bt3EZ6p55jbFJBeAe1ZNpL5BugLujxNA==",
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.3.3.tgz",
+ "integrity": "sha512-/VulV3SYni1taM7a4RMdceqzJWR39gpZHjBwUnsCFKWV/GJkD14CJ5F7eWcZozmHJK0/f/H5U3b3SiPkuvxMgg==",
"dev": true
},
"html-escaper": {
@@ -15450,9 +15631,9 @@
}
},
"stylus-loader": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/stylus-loader/-/stylus-loader-4.1.1.tgz",
- "integrity": "sha512-Vnm7J/nIs/P6swIrdwJW/dflhsCOiFmb1U3PeQ6phRtg1soPLN4uKnnL7AtGIJDe173elbtYIXVzmCyF493CfA==",
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/stylus-loader/-/stylus-loader-4.3.1.tgz",
+ "integrity": "sha512-apDYJEM5ZpOAWbWInWcsbtI8gHNr/XYVcSY/tWqOUPt7M5tqhtwXVsAkgyiVjhuvw2Yrjq474a9H+g4d047Ebw==",
"dev": true,
"requires": {
"fast-glob": "^3.2.4",
@@ -15910,9 +16091,9 @@
"dev": true
},
"ts-node": {
- "version": "9.1.0",
- "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.0.tgz",
- "integrity": "sha512-0yqcL4sgruCvM+w64LiAfNJo6+lHfCYc5Ajj4yiLNkJ9oZ2HWaa+Kso7htYOOxVQ7+csAjdUjffOe9PIqC4pMg==",
+ "version": "9.1.1",
+ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz",
+ "integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==",
"dev": true,
"requires": {
"arg": "^4.1.0",
@@ -16415,9 +16596,9 @@
"dev": true
},
"uuid": {
- "version": "8.3.1",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz",
- "integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg=="
+ "version": "8.3.2",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+ "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
},
"v8-compile-cache": {
"version": "2.2.0",
diff --git a/console/package.json b/console/package.json
index 07bdb78cba..a53f385b39 100644
--- a/console/package.json
+++ b/console/package.json
@@ -40,17 +40,17 @@
"rxjs": "~6.6.3",
"ts-protoc-gen": "^0.13.0",
"tslib": "^2.0.0",
- "uuid": "^8.3.1",
+ "uuid": "^8.3.2",
"zone.js": "~0.11.3"
},
"devDependencies": {
- "@angular-devkit/build-angular": "~0.1100.3",
- "@angular/cli": "~11.0.3",
+ "@angular-devkit/build-angular": "~0.1100.4",
+ "@angular/cli": "~11.0.4",
"@angular/compiler-cli": "~11.0.0",
"@types/jasmine": "~3.6.2",
- "@angular/language-service": "~11.0.3",
+ "@angular/language-service": "~11.0.4",
"@types/jasminewd2": "~2.0.3",
- "@types/node": "^14.14.10",
+ "@types/node": "^14.14.13",
"codelyzer": "^6.0.0",
"jasmine-core": "~3.6.0",
"jasmine-spec-reporter": "~6.0.0",
@@ -64,7 +64,7 @@
"stylelint": "^13.8.0",
"stylelint-config-standard": "^20.0.0",
"stylelint-scss": "^3.18.0",
- "ts-node": "~9.1.0",
+ "ts-node": "~9.1.1",
"tslint": "~6.1.3",
"typescript": "^4.0.5"
}
diff --git a/console/src/app/modules/changes/changes.component.ts b/console/src/app/modules/changes/changes.component.ts
index eeee5de055..58001fd7ae 100644
--- a/console/src/app/modules/changes/changes.component.ts
+++ b/console/src/app/modules/changes/changes.component.ts
@@ -42,7 +42,6 @@ export class ChangesComponent implements OnInit, OnDestroy {
this.init();
if (this.refresh) {
this.refresh.pipe(takeUntil(this.destroyed$), debounceTime(2000)).subscribe(() => {
- console.log('asdf');
this.init();
});
}
diff --git a/console/src/app/modules/mfa-table/dialog-add-type/dialog-add-type.component.html b/console/src/app/modules/mfa-table/dialog-add-type/dialog-add-type.component.html
new file mode 100644
index 0000000000..8d56ad9489
--- /dev/null
+++ b/console/src/app/modules/mfa-table/dialog-add-type/dialog-add-type.component.html
@@ -0,0 +1,19 @@
+
{{data.title | translate}}
+
+
{{data.desc | translate}}
+
+
+ {{'MFA.TYPE' | translate}}
+
+
+ {{(data.componentType == LoginMethodComponentType.SecondFactor ? 'MFA.SECONDFACTORTYPES.': LoginMethodComponentType.MultiFactor ? 'MFA.MULTIFACTORTYPES.': '')+mfa | translate}}
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/console/src/app/modules/mfa-table/dialog-add-type/dialog-add-type.component.scss b/console/src/app/modules/mfa-table/dialog-add-type/dialog-add-type.component.scss
new file mode 100644
index 0000000000..2a10cfe140
--- /dev/null
+++ b/console/src/app/modules/mfa-table/dialog-add-type/dialog-add-type.component.scss
@@ -0,0 +1,22 @@
+.title {
+ font-size: 1.5rem;
+}
+
+.desc {
+ font-size: 14px;
+ color: var(--grey);
+}
+
+.form-field {
+ width: 100%;
+}
+
+.action {
+ display: flex;
+ justify-content: flex-end;
+
+ button {
+ margin-left: .5rem;
+ border-radius: .5rem;
+ }
+}
diff --git a/console/src/app/modules/mfa-table/dialog-add-type/dialog-add-type.component.ts b/console/src/app/modules/mfa-table/dialog-add-type/dialog-add-type.component.ts
new file mode 100644
index 0000000000..befb157abf
--- /dev/null
+++ b/console/src/app/modules/mfa-table/dialog-add-type/dialog-add-type.component.ts
@@ -0,0 +1,33 @@
+import { Component, Inject } from '@angular/core';
+import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
+
+import { MultiFactorType as AdminMultiFactorType } from 'src/app/proto/generated/admin_pb';
+import { MultiFactorType as MgmtMultiFactorType } from 'src/app/proto/generated/management_pb';
+
+enum LoginMethodComponentType {
+ MultiFactor = 1,
+ SecondFactor = 2,
+}
+
+@Component({
+ selector: 'app-dialog-add-type',
+ templateUrl: './dialog-add-type.component.html',
+ styleUrls: ['./dialog-add-type.component.scss'],
+})
+export class DialogAddTypeComponent {
+ public LoginMethodComponentType: any = LoginMethodComponentType;
+ public newMfaType!: AdminMultiFactorType | MgmtMultiFactorType;
+ public availableMfaTypes: Array = [];
+ constructor(public dialogRef: MatDialogRef,
+ @Inject(MAT_DIALOG_DATA) public data: any) {
+ this.availableMfaTypes = data.types;
+ }
+
+ public closeDialog(): void {
+ this.dialogRef.close();
+ }
+
+ public closeDialogWithCode(): void {
+ this.dialogRef.close(this.newMfaType);
+ }
+}
diff --git a/console/src/app/modules/mfa-table/mfa-table.component.html b/console/src/app/modules/mfa-table/mfa-table.component.html
new file mode 100644
index 0000000000..3d45e4c2f5
--- /dev/null
+++ b/console/src/app/modules/mfa-table/mfa-table.component.html
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+ {{(componentType == LoginMethodComponentType.SecondFactor ? 'MFA.SECONDFACTORTYPES.': LoginMethodComponentType.MultiFactor ? 'MFA.MULTIFACTORTYPES.': '')+mfa | translate}}
+
+
+ add
+
+
\ No newline at end of file
diff --git a/console/src/app/modules/mfa-table/mfa-table.component.scss b/console/src/app/modules/mfa-table/mfa-table.component.scss
new file mode 100644
index 0000000000..f0fe7e80a7
--- /dev/null
+++ b/console/src/app/modules/mfa-table/mfa-table.component.scss
@@ -0,0 +1,42 @@
+
+.t .sp_wrapper {
+ display: block;
+}
+
+.mfa-list {
+ display: flex;
+ flex-wrap: wrap;
+ margin: 0 -.5rem;
+
+ .mfa {
+ border: 1px solid var(--grey);
+ border-radius: .5rem;
+ display: grid;
+ align-items: center;
+ justify-content: center;
+ margin: .5rem;
+ padding: 10px;
+ cursor: pointer;
+ position: relative;
+ min-height: 70px;
+ min-width: 150px;
+
+ .rm {
+ position: absolute;
+ top: 0;
+ left: 0;
+ transform: translateX(-50%) translateY(-50%);
+ cursor: pointer;
+
+ &[disabled] {
+ display: none;
+ }
+ }
+
+ &:not(.disabled) {
+ &:hover {
+ background-color: #ffffff10;
+ }
+ }
+ }
+}
diff --git a/console/src/app/modules/mfa-table/mfa-table.component.spec.ts b/console/src/app/modules/mfa-table/mfa-table.component.spec.ts
new file mode 100644
index 0000000000..24992ccaff
--- /dev/null
+++ b/console/src/app/modules/mfa-table/mfa-table.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
+
+import { MfaTableComponent } from './mfa-table.component';
+
+describe('MfaTableComponent', () => {
+ let component: MfaTableComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(waitForAsync(() => {
+ TestBed.configureTestingModule({
+ declarations: [MfaTableComponent],
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(MfaTableComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/console/src/app/modules/mfa-table/mfa-table.component.ts b/console/src/app/modules/mfa-table/mfa-table.component.ts
new file mode 100644
index 0000000000..a8c425b705
--- /dev/null
+++ b/console/src/app/modules/mfa-table/mfa-table.component.ts
@@ -0,0 +1,232 @@
+import { Component, Input, OnInit, ViewChild } from '@angular/core';
+import { MatDialog } from '@angular/material/dialog';
+import { MatPaginator } from '@angular/material/paginator';
+import { TranslateService } from '@ngx-translate/core';
+import { BehaviorSubject, Observable } from 'rxjs';
+import {
+ MultiFactor as AdminMultiFactor,
+ MultiFactorType as AdminMultiFactorType,
+ SecondFactor as AdminSecondFactor,
+ SecondFactorType as AdminSecondFactorType,
+} from 'src/app/proto/generated/admin_pb';
+import {
+ MultiFactor as MgmtMultiFactor,
+ MultiFactorType as MgmtMultiFactorType,
+ SecondFactor as MgmtSecondFactor,
+ SecondFactorType as MgmtSecondFactorType,
+} from 'src/app/proto/generated/management_pb';
+import { AdminService } from 'src/app/services/admin.service';
+import { ManagementService } from 'src/app/services/mgmt.service';
+import { ToastService } from 'src/app/services/toast.service';
+
+import { PolicyComponentServiceType } from '../policies/policy-component-types.enum';
+import { WarnDialogComponent } from '../warn-dialog/warn-dialog.component';
+import { DialogAddTypeComponent } from './dialog-add-type/dialog-add-type.component';
+
+export enum LoginMethodComponentType {
+ MultiFactor = 1,
+ SecondFactor = 2,
+}
+
+@Component({
+ selector: 'app-mfa-table',
+ templateUrl: './mfa-table.component.html',
+ styleUrls: ['./mfa-table.component.scss'],
+})
+export class MfaTableComponent implements OnInit {
+ public LoginMethodComponentType: any = LoginMethodComponentType;
+ @Input() componentType!: LoginMethodComponentType;
+ @Input() public serviceType!: PolicyComponentServiceType;
+ @Input() service!: AdminService | ManagementService;
+ @Input() disabled: boolean = false;
+ @ViewChild(MatPaginator) public paginator!: MatPaginator;
+ public mfas: Array = [];
+
+ private loadingSubject: BehaviorSubject = new BehaviorSubject(false);
+ public loading$: Observable = this.loadingSubject.asObservable();
+
+ public PolicyComponentServiceType: any = PolicyComponentServiceType;
+
+ constructor(public translate: TranslateService, private toast: ToastService, private dialog: MatDialog) { }
+
+ public ngOnInit(): void {
+ this.getData();
+ }
+
+ public removeMfa(type: MgmtMultiFactorType | AdminMultiFactorType | MgmtSecondFactorType | AdminSecondFactorType): void {
+ const dialogRef = this.dialog.open(WarnDialogComponent, {
+ data: {
+ confirmKey: 'ACTIONS.DELETE',
+ cancelKey: 'ACTIONS.CANCEL',
+ titleKey: 'MFA.DELETE.TITLE',
+ descriptionKey: 'MFA.DELETE.DESCRIPTION',
+ },
+ width: '400px',
+ });
+
+ dialogRef.afterClosed().subscribe(resp => {
+ if (resp) {
+ if (this.serviceType === PolicyComponentServiceType.MGMT) {
+ if (this.componentType === LoginMethodComponentType.MultiFactor) {
+ const req = new MgmtMultiFactor();
+ req.setMultiFactor(type as MgmtMultiFactorType);
+ (this.service as ManagementService).RemoveMultiFactorFromLoginPolicy(req).then(() => {
+ this.toast.showInfo('MFA.TOAST.DELETED', true);
+ this.refreshPageAfterTimout(2000);
+ });
+ } else if (this.componentType === LoginMethodComponentType.SecondFactor) {
+ const req = new MgmtSecondFactor();
+ req.setSecondFactor(type as MgmtSecondFactorType);
+ (this.service as ManagementService).RemoveSecondFactorFromLoginPolicy(req).then(() => {
+ this.toast.showInfo('MFA.TOAST.DELETED', true);
+ this.refreshPageAfterTimout(2000);
+ });
+ }
+ } else if (this.serviceType === PolicyComponentServiceType.ADMIN) {
+ if (this.componentType === LoginMethodComponentType.MultiFactor) {
+ const req = new AdminMultiFactor();
+ req.setMultiFactor(type as AdminMultiFactorType);
+ (this.service as AdminService).RemoveMultiFactorFromDefaultLoginPolicy(req).then(() => {
+ this.toast.showInfo('MFA.TOAST.DELETED', true);
+ this.refreshPageAfterTimout(2000);
+ });
+ } else if (this.componentType === LoginMethodComponentType.SecondFactor) {
+ const req = new AdminSecondFactor();
+ req.setSecondFactor(type as AdminSecondFactorType);
+ (this.service as AdminService).RemoveSecondFactorFromDefaultLoginPolicy(req).then(() => {
+ this.toast.showInfo('MFA.TOAST.DELETED', true);
+ this.refreshPageAfterTimout(2000);
+ });
+ }
+ }
+ }
+ });
+ }
+
+ public addMfa(): void {
+
+ let selection: any[] = [];
+
+ if (this.componentType === LoginMethodComponentType.MultiFactor) {
+ selection = this.serviceType === PolicyComponentServiceType.MGMT ?
+ [MgmtMultiFactorType.MULTIFACTORTYPE_U2F_WITH_PIN] :
+ this.serviceType === PolicyComponentServiceType.ADMIN ?
+ [AdminMultiFactorType.MULTIFACTORTYPE_U2F_WITH_PIN] :
+ [];
+ } else if (this.componentType === LoginMethodComponentType.SecondFactor) {
+ selection = this.serviceType === PolicyComponentServiceType.MGMT ?
+ [MgmtSecondFactorType.SECONDFACTORTYPE_U2F, MgmtSecondFactorType.SECONDFACTORTYPE_OTP] :
+ this.serviceType === PolicyComponentServiceType.ADMIN ?
+ [AdminSecondFactorType.SECONDFACTORTYPE_OTP, AdminSecondFactorType.SECONDFACTORTYPE_U2F] :
+ [];
+ }
+
+ this.mfas.forEach(mfa => {
+ const index = selection.findIndex(sel => sel === mfa);
+ if (index > -1) {
+ selection.splice(index, 1);
+ }
+ });
+
+ const dialogRef = this.dialog.open(DialogAddTypeComponent, {
+ data: {
+ title: 'MFA.CREATE.TITLE',
+ desc: 'MFA.CREATE.DESCRIPTION',
+ componentType: this.componentType,
+ types: selection,
+ },
+ width: '400px',
+ });
+
+ dialogRef.afterClosed().subscribe((mfaType: AdminMultiFactorType | MgmtMultiFactorType |
+ AdminSecondFactorType | MgmtSecondFactorType) => {
+ if (mfaType) {
+ if (this.serviceType === PolicyComponentServiceType.MGMT) {
+ if (this.componentType === LoginMethodComponentType.MultiFactor) {
+ const req = new MgmtMultiFactor();
+ req.setMultiFactor(mfaType as MgmtMultiFactorType);
+ (this.service as ManagementService).AddMultiFactorToLoginPolicy(req).then(() => {
+ this.refreshPageAfterTimout(2000);
+ }).catch(error => {
+ this.toast.showError(error);
+ });
+ } else if (this.componentType === LoginMethodComponentType.SecondFactor) {
+ const req = new MgmtSecondFactor();
+ req.setSecondFactor(mfaType as MgmtSecondFactorType);
+ (this.service as ManagementService).AddSecondFactorToLoginPolicy(req).then(() => {
+ this.refreshPageAfterTimout(2000);
+ }).catch(error => {
+ this.toast.showError(error);
+ });
+ }
+ } else if (this.serviceType === PolicyComponentServiceType.ADMIN) {
+ if (this.componentType === LoginMethodComponentType.MultiFactor) {
+ const req = new AdminMultiFactor();
+ req.setMultiFactor(mfaType as AdminMultiFactorType);
+ (this.service as AdminService).addMultiFactorToDefaultLoginPolicy(req).then(() => {
+ this.refreshPageAfterTimout(2000);
+ }).catch(error => {
+ this.toast.showError(error);
+ });
+ } else if (this.componentType === LoginMethodComponentType.SecondFactor) {
+ const req = new AdminSecondFactor();
+ req.setSecondFactor(mfaType as AdminSecondFactorType);
+ (this.service as AdminService).AddSecondFactorToDefaultLoginPolicy(req).then(() => {
+ this.refreshPageAfterTimout(2000);
+ }).catch(error => {
+ this.toast.showError(error);
+ });
+ }
+ }
+ }
+ });
+ }
+
+ private async getData(): Promise {
+ this.loadingSubject.next(true);
+
+ if (this.serviceType === PolicyComponentServiceType.MGMT) {
+ if (this.componentType === LoginMethodComponentType.MultiFactor) {
+ (this.service as ManagementService).GetLoginPolicyMultiFactors().then(resp => {
+ this.mfas = resp.toObject().multiFactorsList;
+ this.loadingSubject.next(false);
+ }).catch(error => {
+ this.toast.showError(error);
+ this.loadingSubject.next(false);
+ });
+ } else if (this.componentType === LoginMethodComponentType.SecondFactor) {
+ (this.service as ManagementService).GetLoginPolicySecondFactors().then(resp => {
+ this.mfas = resp.toObject().secondFactorsList;
+ this.loadingSubject.next(false);
+ }).catch(error => {
+ this.toast.showError(error);
+ this.loadingSubject.next(false);
+ });
+ }
+ } else if (this.serviceType === PolicyComponentServiceType.ADMIN) {
+ if (this.componentType === LoginMethodComponentType.MultiFactor) {
+ (this.service as AdminService).getDefaultLoginPolicyMultiFactors().then(resp => {
+ this.mfas = resp.toObject().multiFactorsList;
+ this.loadingSubject.next(false);
+ }).catch(error => {
+ this.toast.showError(error);
+ this.loadingSubject.next(false);
+ });
+ } else if (this.componentType === LoginMethodComponentType.SecondFactor) {
+ (this.service as AdminService).GetDefaultLoginPolicySecondFactors().then(resp => {
+ this.mfas = resp.toObject().secondFactorsList;
+ this.loadingSubject.next(false);
+ }).catch(error => {
+ this.toast.showError(error);
+ this.loadingSubject.next(false);
+ });
+ }
+ }
+ }
+
+ public refreshPageAfterTimout(to: number): void {
+ setTimeout(() => {
+ this.getData();
+ }, to);
+ }
+}
diff --git a/console/src/app/modules/mfa-table/mfa-table.module.ts b/console/src/app/modules/mfa-table/mfa-table.module.ts
new file mode 100644
index 0000000000..8db0c2cf9d
--- /dev/null
+++ b/console/src/app/modules/mfa-table/mfa-table.module.ts
@@ -0,0 +1,44 @@
+import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { MatButtonModule } from '@angular/material/button';
+import { MatCheckboxModule } from '@angular/material/checkbox';
+import { MatIconModule } from '@angular/material/icon';
+import { MatPaginatorModule } from '@angular/material/paginator';
+import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
+import { MatTableModule } from '@angular/material/table';
+import { MatTooltipModule } from '@angular/material/tooltip';
+import { RouterModule } from '@angular/router';
+import { TranslateModule } from '@ngx-translate/core';
+import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
+import { RefreshTableModule } from 'src/app/modules/refresh-table/refresh-table.module';
+import { LocalizedDatePipeModule } from 'src/app/pipes/localized-date-pipe/localized-date-pipe.module';
+import { TimestampToDatePipeModule } from 'src/app/pipes/timestamp-to-date-pipe/timestamp-to-date-pipe.module';
+import { TruncatePipeModule } from 'src/app/pipes/truncate-pipe/truncate-pipe.module';
+
+import { MfaTableComponent } from './mfa-table.component';
+import { DialogAddTypeComponent } from './dialog-add-type/dialog-add-type.component';
+import { InputModule } from '../input/input.module';
+import { MatSelectModule } from '@angular/material/select';
+
+@NgModule({
+ declarations: [MfaTableComponent, DialogAddTypeComponent],
+ imports: [
+ CommonModule,
+ FormsModule,
+ ReactiveFormsModule,
+ MatButtonModule,
+ MatIconModule,
+ InputModule,
+ MatSelectModule,
+ MatTooltipModule,
+ TranslateModule,
+ TimestampToDatePipeModule,
+ HasRoleModule,
+ MatProgressSpinnerModule,
+ ],
+ exports: [
+ MfaTableComponent,
+ ],
+})
+export class MfaTableModule { }
diff --git a/console/src/app/modules/policies/login-policy/login-policy.component.html b/console/src/app/modules/policies/login-policy/login-policy.component.html
index dcd843ab65..e88404bf39 100644
--- a/console/src/app/modules/policies/login-policy/login-policy.component.html
+++ b/console/src/app/modules/policies/login-policy/login-policy.component.html
@@ -44,8 +44,46 @@
{{'POLICY.DATA.ALLOWEXTERNALIDP_DESC' | translate}}
+
+
+ {{'POLICY.DATA.FORCEMFA' | translate}}
+
+
{{'POLICY.DATA.FORCEMFA_DESC' | translate}}
+
+
+
+ {{'LOGINPOLICY.PASSWORDLESS' | translate}}
+
+
+ {{'LOGINPOLICY.PASSWORDLESSTYPE.'+pt | translate}}
+
+
+
+
+
+
+
+
+
+
+ {{ 'MFA.LIST.MULTIFACTORDESCRIPTION' | translate }}
+
+
+
+
+ {{ 'MFA.LIST.SECONDFACTORDESCRIPTION' | translate }}
+
+
+
+
@@ -63,9 +101,6 @@
-
-
{{ 'IDP.LIST.TITLE' | translate }}
{{ 'IDP.LIST.DESCRIPTION' | translate }}
diff --git a/console/src/app/modules/policies/login-policy/login-policy.component.scss b/console/src/app/modules/policies/login-policy/login-policy.component.scss
index ea690233c2..5d2b27fbc2 100644
--- a/console/src/app/modules/policies/login-policy/login-policy.component.scss
+++ b/console/src/app/modules/policies/login-policy/login-policy.component.scss
@@ -37,6 +37,11 @@
width: 100%;
}
+.subdesc {
+ color: var(--grey);
+ font-size: 14px;
+}
+
.idps {
display: flex;
margin: 0 -.5rem;
@@ -93,3 +98,10 @@
}
}
}
+
+.divider {
+ width: 100%;
+ height: 1px;
+ background-color: var(--grey);
+ margin: 1rem 0;
+}
diff --git a/console/src/app/modules/policies/login-policy/login-policy.component.ts b/console/src/app/modules/policies/login-policy/login-policy.component.ts
index 119a251433..9bb05c39a5 100644
--- a/console/src/app/modules/policies/login-policy/login-policy.component.ts
+++ b/console/src/app/modules/policies/login-policy/login-policy.component.ts
@@ -3,18 +3,23 @@ import { MatDialog } from '@angular/material/dialog';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs';
import { switchMap } from 'rxjs/operators';
+import { LoginMethodComponentType } from 'src/app/modules/mfa-table/mfa-table.component';
import {
DefaultLoginPolicy,
+ DefaultLoginPolicyRequest,
DefaultLoginPolicyView,
IdpProviderView as AdminIdpProviderView,
IdpView as AdminIdpView,
+ PasswordlessType as AdminPasswordlessType,
} from 'src/app/proto/generated/admin_pb';
import {
IdpProviderType,
IdpProviderView as MgmtIdpProviderView,
IdpView as MgmtIdpView,
LoginPolicy,
+ LoginPolicyRequest,
LoginPolicyView,
+ PasswordlessType as MgmtPasswordlessType,
} from 'src/app/proto/generated/management_pb';
import { AdminService } from 'src/app/services/admin.service';
import { ManagementService } from 'src/app/services/mgmt.service';
@@ -29,6 +34,8 @@ import { AddIdpDialogComponent } from './add-idp-dialog/add-idp-dialog.component
styleUrls: ['./login-policy.component.scss'],
})
export class LoginPolicyComponent implements OnDestroy {
+ public LoginMethodComponentType: any = LoginMethodComponentType;
+ public passwordlessTypes: Array = [];
public loginData!: LoginPolicyView.AsObject | DefaultLoginPolicyView.AsObject;
private sub: Subscription = new Subscription();
@@ -50,9 +57,13 @@ export class LoginPolicyComponent implements OnDestroy {
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
this.service = this.injector.get(ManagementService as Type);
+ this.passwordlessTypes = [MgmtPasswordlessType.PASSWORDLESSTYPE_ALLOWED,
+ MgmtPasswordlessType.PASSWORDLESSTYPE_NOT_ALLOWED];
break;
case PolicyComponentServiceType.ADMIN:
this.service = this.injector.get(AdminService as Type);
+ this.passwordlessTypes = [AdminPasswordlessType.PASSWORDLESSTYPE_ALLOWED,
+ AdminPasswordlessType.PASSWORDLESSTYPE_NOT_ALLOWED];
break;
}
@@ -108,20 +119,28 @@ export class LoginPolicyComponent implements OnDestroy {
Promise {
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
- const mgmtreq = new LoginPolicy();
+ const mgmtreq = new LoginPolicyRequest();
mgmtreq.setAllowExternalIdp(this.loginData.allowExternalIdp);
mgmtreq.setAllowRegister(this.loginData.allowRegister);
mgmtreq.setAllowUsernamePassword(this.loginData.allowUsernamePassword);
+ mgmtreq.setForceMfa(this.loginData.forceMfa);
+ mgmtreq.setPasswordlessType(this.loginData.passwordlessType);
+ // console.log(mgmtreq.toObject());
if ((this.loginData as LoginPolicyView.AsObject).pb_default) {
return (this.service as ManagementService).CreateLoginPolicy(mgmtreq);
} else {
return (this.service as ManagementService).UpdateLoginPolicy(mgmtreq);
}
case PolicyComponentServiceType.ADMIN:
- const adminreq = new DefaultLoginPolicy();
+ const adminreq = new DefaultLoginPolicyRequest();
adminreq.setAllowExternalIdp(this.loginData.allowExternalIdp);
adminreq.setAllowRegister(this.loginData.allowRegister);
adminreq.setAllowUsernamePassword(this.loginData.allowUsernamePassword);
+ adminreq.setForceMfa(this.loginData.forceMfa);
+ adminreq.setPasswordlessType(this.loginData.passwordlessType);
+
+ // console.log(adminreq.toObject());
+
return (this.service as AdminService).UpdateDefaultLoginPolicy(adminreq);
}
}
diff --git a/console/src/app/modules/policies/login-policy/login-policy.module.ts b/console/src/app/modules/policies/login-policy/login-policy.module.ts
index 8ea3fe5a67..a53e209629 100644
--- a/console/src/app/modules/policies/login-policy/login-policy.module.ts
+++ b/console/src/app/modules/policies/login-policy/login-policy.module.ts
@@ -4,6 +4,7 @@ import { FormsModule } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
+import { MatSelectModule } from '@angular/material/select';
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
import { MatTooltipModule } from '@angular/material/tooltip';
import { TranslateModule } from '@ngx-translate/core';
@@ -12,6 +13,7 @@ import { CardModule } from 'src/app/modules/card/card.module';
import { DetailLayoutModule } from 'src/app/modules/detail-layout/detail-layout.module';
import { IdpTableModule } from 'src/app/modules/idp-table/idp-table.module';
import { InputModule } from 'src/app/modules/input/input.module';
+import { MfaTableModule } from 'src/app/modules/mfa-table/mfa-table.module';
import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module';
import { AddIdpDialogModule } from './add-idp-dialog/add-idp-dialog.module';
@@ -36,7 +38,9 @@ import { LoginPolicyComponent } from './login-policy.component';
DetailLayoutModule,
AddIdpDialogModule,
IdpTableModule,
+ MfaTableModule,
MatProgressSpinnerModule,
+ MatSelectModule,
],
})
export class LoginPolicyModule { }
diff --git a/console/src/app/pages/projects/apps/app-detail/app-detail.component.html b/console/src/app/pages/projects/apps/app-detail/app-detail.component.html
index 726a157dce..ab1aee6ef9 100644
--- a/console/src/app/pages/projects/apps/app-detail/app-detail.component.html
+++ b/console/src/app/pages/projects/apps/app-detail/app-detail.component.html
@@ -127,6 +127,22 @@
{{'APP.OIDC.IDTOKENROLEASSERTION_DESCRIPTION' | translate}}
+
+ {{'APP.OIDC.IDTOKENUSERINFOASSERTION' | translate}}
+
+ {{'APP.OIDC.IDTOKENUSERINFOASSERTION_DESCRIPTION' | translate}}
+
+
+ ClockSkew
+
+
+
+ {{'APP.OIDC.CLOCKSKEW' | translate}}
+
+
+
{{'APP.OIDC.REDIRECTSECTIONTITLE' | translate}}
diff --git a/console/src/app/pages/projects/apps/app-detail/app-detail.component.scss b/console/src/app/pages/projects/apps/app-detail/app-detail.component.scss
index 615b10b2fe..db7946ac71 100644
--- a/console/src/app/pages/projects/apps/app-detail/app-detail.component.scss
+++ b/console/src/app/pages/projects/apps/app-detail/app-detail.component.scss
@@ -128,6 +128,17 @@
margin-right: .5rem;
}
+ .clockskew-title {
+ font-size: 14px;
+ color: var(--grey);
+ margin: 1rem .5rem 0 .5rem;
+ }
+
+ .clockskew-slider {
+ width: 100%;
+ margin: 0 .5rem;
+ }
+
.desc {
color: var(--grey);
font-size: 14px;
diff --git a/console/src/app/pages/projects/apps/app-detail/app-detail.component.ts b/console/src/app/pages/projects/apps/app-detail/app-detail.component.ts
index 719a4e4c8c..2e4cf4a1cb 100644
--- a/console/src/app/pages/projects/apps/app-detail/app-detail.component.ts
+++ b/console/src/app/pages/projects/apps/app-detail/app-detail.component.ts
@@ -6,6 +6,7 @@ import { MatButtonToggleChange } from '@angular/material/button-toggle';
import { MatDialog } from '@angular/material/dialog';
import { ActivatedRoute, Params } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
+import { Duration } from 'google-protobuf/google/protobuf/duration_pb';
import { Subscription } from 'rxjs';
import { take } from 'rxjs/operators';
import { ChangeType } from 'src/app/modules/changes/changes.component';
@@ -15,6 +16,7 @@ import {
OIDCApplicationType,
OIDCAuthMethodType,
OIDCConfig,
+ OIDCConfigUpdate,
OIDCGrantType,
OIDCResponseType,
OIDCTokenType,
@@ -116,9 +118,15 @@ export class AppDetailComponent implements OnInit, OnDestroy {
accessTokenType: [{ value: '', disabled: true }],
accessTokenRoleAssertion: [{ value: false, disabled: true }],
idTokenRoleAssertion: [{ value: false, disabled: true }],
+ idTokenUserinfoAssertion: [{ value: false, disabled: true }],
+ clockSkewSeconds: [{ value: 0, disabled: true }],
});
}
+ public formatClockSkewLabel(seconds: number): string {
+ return seconds + 's';
+ }
+
public ngOnInit(): void {
this.subscription = this.route.params.subscribe(params => this.getData(params));
}
@@ -132,11 +140,12 @@ export class AppDetailComponent implements OnInit, OnDestroy {
this.mgmtService.GetIam().then(iam => {
this.isZitadel = iam.toObject().iamProjectId === this.projectId;
});
- this.authService.isAllowed(['project.app.write$', 'project.app.write:' + id]).pipe(take(1)).subscribe((allowed) => {
+ this.authService.isAllowed(['project.app.write$', 'project.app.write:' + projectid]).pipe(take(1)).subscribe((allowed) => {
this.canWrite = allowed;
this.mgmtService.GetApplicationById(projectid, id).then(app => {
this.app = app.toObject();
this.appNameForm.patchValue(this.app);
+ console.log(this.app);
if (allowed) {
this.appNameForm.enable();
this.appForm.enable();
@@ -150,6 +159,11 @@ export class AppDetailComponent implements OnInit, OnDestroy {
if (this.app.oidcConfig?.postLogoutRedirectUrisList) {
this.postLogoutRedirectUrisList = this.app.oidcConfig.postLogoutRedirectUrisList;
}
+ if (this.app.oidcConfig?.clockSkew) {
+ const inSecs = this.app.oidcConfig?.clockSkew.seconds + this.app.oidcConfig?.clockSkew.nanos / 100000;
+ console.log(inSecs);
+ this.appForm.controls['clockSkewSeconds'].setValue(inSecs);
+ }
if (this.app.oidcConfig) {
this.appForm.patchValue(this.app.oidcConfig);
}
@@ -159,8 +173,6 @@ export class AppDetailComponent implements OnInit, OnDestroy {
this.errorMessage = error.message;
});
});
-
-
this.docs = (await this.mgmtService.GetZitadelDocs()).toObject();
}
@@ -247,9 +259,32 @@ export class AppDetailComponent implements OnInit, OnDestroy {
this.app.oidcConfig.accessTokenType = this.accessTokenType?.value;
this.app.oidcConfig.accessTokenRoleAssertion = this.accessTokenRoleAssertion?.value;
this.app.oidcConfig.idTokenRoleAssertion = this.idTokenRoleAssertion?.value;
+ this.app.oidcConfig.idTokenUserinfoAssertion = this.idTokenUserinfoAssertion?.value;
+
+ const req = new OIDCConfigUpdate();
+ req.setProjectId(this.projectId);
+ req.setApplicationId(this.app.id);
+ req.setRedirectUrisList(this.app.oidcConfig.redirectUrisList);
+ req.setResponseTypesList(this.app.oidcConfig.responseTypesList);
+ req.setAuthMethodType(this.app.oidcConfig.authMethodType);
+ req.setPostLogoutRedirectUrisList(this.app.oidcConfig.postLogoutRedirectUrisList);
+ req.setGrantTypesList(this.app.oidcConfig.grantTypesList);
+ req.setApplicationType(this.app.oidcConfig.applicationType);
+ req.setDevMode(this.app.oidcConfig.devMode);
+ req.setAccessTokenType(this.app.oidcConfig.accessTokenType);
+ req.setAccessTokenRoleAssertion(this.app.oidcConfig.accessTokenRoleAssertion);
+ req.setIdTokenRoleAssertion(this.app.oidcConfig.idTokenRoleAssertion);
+ req.setIdTokenUserinfoAssertion(this.app.oidcConfig.idTokenUserinfoAssertion);
+ if (this.clockSkewSeconds?.value) {
+ const dur = new Duration();
+ dur.setSeconds(Math.floor(this.clockSkewSeconds?.value));
+ dur.setNanos((Math.floor(this.clockSkewSeconds?.value % 1) * 10000));
+ req.setClockSkew(dur);
+ }
+ console.log(req.toObject());
this.mgmtService
- .UpdateOIDCAppConfig(this.projectId, this.app.id, this.app.oidcConfig)
+ .UpdateOIDCAppConfig(req)
.then(() => {
this.toast.showInfo('APP.TOAST.OIDCUPDATED', true);
})
@@ -319,4 +354,12 @@ export class AppDetailComponent implements OnInit, OnDestroy {
public get accessTokenRoleAssertion(): AbstractControl | null {
return this.appForm.get('accessTokenRoleAssertion');
}
+
+ public get idTokenUserinfoAssertion(): AbstractControl | null {
+ return this.appForm.get('idTokenUserinfoAssertion');
+ }
+
+ public get clockSkewSeconds(): AbstractControl | null {
+ return this.appForm.get('clockSkewSeconds');
+ }
}
diff --git a/console/src/app/pages/projects/apps/apps.module.ts b/console/src/app/pages/projects/apps/apps.module.ts
index 81559e7168..ff7fd7c0af 100644
--- a/console/src/app/pages/projects/apps/apps.module.ts
+++ b/console/src/app/pages/projects/apps/apps.module.ts
@@ -13,6 +13,7 @@ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatRadioModule } from '@angular/material/radio';
import { MatSelectModule } from '@angular/material/select';
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
+import { MatSliderModule } from '@angular/material/slider';
import { MatStepperModule } from '@angular/material/stepper';
import { MatTooltipModule } from '@angular/material/tooltip';
import { TranslateModule } from '@ngx-translate/core';
@@ -61,6 +62,7 @@ import { AppsRoutingModule } from './apps-routing.module';
MatSlideToggleModule,
InputModule,
MetaLayoutModule,
+ MatSliderModule,
ChangesModule,
InfoSectionModule,
],
diff --git a/console/src/app/pages/users/user-detail/auth-user-detail/auth-passwordless/auth-passwordless.component.html b/console/src/app/pages/users/user-detail/auth-user-detail/auth-passwordless/auth-passwordless.component.html
new file mode 100644
index 0000000000..d5e79db8b1
--- /dev/null
+++ b/console/src/app/pages/users/user-detail/auth-user-detail/auth-passwordless/auth-passwordless.component.html
@@ -0,0 +1,50 @@
+
+
+
+
+ {{ 'USER.PASSWORDLESS.NAME' | translate }} |
+
+ {{ mfa?.name }}
+
+ |
+
+
+
+ {{ 'USER.PASSWORDLESS.TABLESTATE' | translate }} |
+
+ {{'USER.PASSWORDLESS.STATE.'+ mfa.state | translate}}
+
+
+ |
+
+
+
+ {{ 'USER.PASSWORDLESS.TABLEACTIONS' | translate }} |
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/console/src/app/pages/users/user-detail/auth-user-detail/auth-passwordless/auth-passwordless.component.scss b/console/src/app/pages/users/user-detail/auth-user-detail/auth-passwordless/auth-passwordless.component.scss
new file mode 100644
index 0000000000..3f9facae7c
--- /dev/null
+++ b/console/src/app/pages/users/user-detail/auth-user-detail/auth-passwordless/auth-passwordless.component.scss
@@ -0,0 +1,41 @@
+
+.add-row {
+ display: flex;
+ margin: -.5rem;
+ flex-wrap: wrap;
+
+ .button {
+ margin: .5rem;
+ margin-top: 1rem;
+
+ .icon {
+ margin-right: .5rem;
+ }
+ }
+}
+
+.centered {
+ display: flex;
+ align-items: center;
+
+ i {
+ margin-left: 1rem;
+ color: var(--color-main);
+ }
+}
+
+.table {
+ width: 100%;
+
+ td,
+ th {
+ &:first-child {
+ padding-left: 0;
+ padding-right: 1rem;
+ }
+
+ &:last-child {
+ padding-right: 0;
+ }
+ }
+}
diff --git a/console/src/app/pages/users/user-detail/auth-user-detail/auth-passwordless/auth-passwordless.component.spec.ts b/console/src/app/pages/users/user-detail/auth-user-detail/auth-passwordless/auth-passwordless.component.spec.ts
new file mode 100644
index 0000000000..fbee4d4c7f
--- /dev/null
+++ b/console/src/app/pages/users/user-detail/auth-user-detail/auth-passwordless/auth-passwordless.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
+
+import { AuthPasswordlessComponent } from './auth-passwordless.component';
+
+describe('AuthPasswordlessComponent', () => {
+ let component: AuthPasswordlessComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(waitForAsync(() => {
+ TestBed.configureTestingModule({
+ declarations: [AuthPasswordlessComponent],
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(AuthPasswordlessComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/console/src/app/pages/users/user-detail/auth-user-detail/auth-passwordless/auth-passwordless.component.ts b/console/src/app/pages/users/user-detail/auth-user-detail/auth-passwordless/auth-passwordless.component.ts
new file mode 100644
index 0000000000..eefdb0efe1
--- /dev/null
+++ b/console/src/app/pages/users/user-detail/auth-user-detail/auth-passwordless/auth-passwordless.component.ts
@@ -0,0 +1,121 @@
+import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
+import { MatDialog } from '@angular/material/dialog';
+import { MatSort } from '@angular/material/sort';
+import { MatTable, MatTableDataSource } from '@angular/material/table';
+import { BehaviorSubject, Observable } from 'rxjs';
+import { WarnDialogComponent } from 'src/app/modules/warn-dialog/warn-dialog.component';
+import { MFAState, WebAuthNResponse, WebAuthNToken } from 'src/app/proto/generated/auth_pb';
+import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
+import { ToastService } from 'src/app/services/toast.service';
+
+import { _base64ToArrayBuffer } from '../../u2f-util';
+import { DialogU2FComponent, U2FComponentDestination } from '../dialog-u2f/dialog-u2f.component';
+
+export interface WebAuthNOptions {
+ challenge: string;
+ rp: { name: string, id: string; };
+ user: { name: string, id: string, displayName: string; };
+ pubKeyCredParams: any;
+ authenticatorSelection: { userVerification: string; };
+ timeout: number;
+ attestation: string;
+}
+
+@Component({
+ selector: 'app-auth-passwordless',
+ templateUrl: './auth-passwordless.component.html',
+ styleUrls: ['./auth-passwordless.component.scss'],
+})
+export class AuthPasswordlessComponent implements OnInit, OnDestroy {
+ public displayedColumns: string[] = ['name', 'state', 'actions'];
+ private loadingSubject: BehaviorSubject = new BehaviorSubject(false);
+ public loading$: Observable = this.loadingSubject.asObservable();
+
+ @ViewChild(MatTable) public table!: MatTable;
+ @ViewChild(MatSort) public sort!: MatSort;
+ public dataSource!: MatTableDataSource;
+
+ public MFAState: any = MFAState;
+ public error: string = '';
+
+ constructor(private service: GrpcAuthService,
+ private toast: ToastService,
+ private dialog: MatDialog) { }
+
+ public ngOnInit(): void {
+ this.getPasswordless();
+ }
+
+ public ngOnDestroy(): void {
+ this.loadingSubject.complete();
+ }
+
+ public addPasswordless(): void {
+ this.service.AddMyPasswordless().then((u2fresp) => {
+ const webauthn: WebAuthNResponse.AsObject = u2fresp.toObject();
+ const credOptions: CredentialCreationOptions = JSON.parse(atob(webauthn.publicKey as string));
+
+ if (credOptions.publicKey?.challenge) {
+ credOptions.publicKey.challenge = _base64ToArrayBuffer(credOptions.publicKey.challenge as any);
+ credOptions.publicKey.user.id = _base64ToArrayBuffer(credOptions.publicKey.user.id as any);
+ if (credOptions.publicKey.excludeCredentials) {
+ credOptions.publicKey.excludeCredentials.map(cred => {
+ cred.id = _base64ToArrayBuffer(cred.id as any);
+ return cred;
+ });
+ }
+ console.log(credOptions);
+ const dialogRef = this.dialog.open(DialogU2FComponent, {
+ width: '400px',
+ data: {
+ credOptions,
+ type: U2FComponentDestination.PASSWORDLESS,
+ },
+ });
+
+ dialogRef.afterClosed().subscribe(done => {
+ if (done) {
+ this.getPasswordless();
+ } else {
+ this.getPasswordless();
+ }
+ });
+ }
+
+ }, error => {
+ this.toast.showError(error);
+ });
+ }
+
+ public getPasswordless(): void {
+ this.service.GetMyPasswordless().then(passwordless => {
+ this.dataSource = new MatTableDataSource(passwordless.toObject().tokensList);
+ this.dataSource.sort = this.sort;
+ }).catch(error => {
+ this.error = error.message;
+ });
+ }
+
+ public deletePasswordless(id?: string): void {
+ const dialogRef = this.dialog.open(WarnDialogComponent, {
+ data: {
+ confirmKey: 'ACTIONS.DELETE',
+ cancelKey: 'ACTIONS.CANCEL',
+ titleKey: 'USER.PASSWORDLESS.DIALOG.DELETE_TITLE',
+ descriptionKey: 'USER.PASSWORDLESS.DIALOG.DELETE_DESCRIPTION',
+ },
+ width: '400px',
+ });
+
+ dialogRef.afterClosed().subscribe(resp => {
+ if (resp && id) {
+ this.service.RemoveMyPasswordless(id).then(() => {
+ this.toast.showInfo('USER.TOAST.PASSWORDLESSREMOVED', true);
+ this.getPasswordless();
+ }).catch(error => {
+ this.toast.showError(error);
+ });
+ }
+ });
+ }
+}
diff --git a/console/src/app/pages/users/user-detail/auth-user-detail/auth-user-detail.component.html b/console/src/app/pages/users/user-detail/auth-user-detail/auth-user-detail.component.html
index 4f65a79667..e28affdae5 100644
--- a/console/src/app/pages/users/user-detail/auth-user-detail/auth-user-detail.component.html
+++ b/console/src/app/pages/users/user-detail/auth-user-detail/auth-user-detail.component.html
@@ -51,6 +51,8 @@
+
+
-
+
{{ 'USER.MFA.TABLETYPE' | translate }} |
{{'USER.MFA.TYPE.'+ mfa.type | translate}} |
+
+ {{ 'USER.MFA.ATTRIBUTE' | translate }} |
+
+ {{ mfa?.attribute }}
+
+ |
+
+
{{ 'USER.MFA.TABLESTATE' | translate }} |
@@ -20,7 +28,7 @@
| {{ 'USER.MFA.TABLEACTIONS' | translate }} |
|
@@ -35,6 +43,11 @@
matTooltip="{{'ACTIONS.NEW' | translate}}">
{{'USER.MFA.OTP' | translate}}
+
diff --git a/console/src/app/pages/users/user-detail/auth-user-detail/auth-user-mfa/auth-user-mfa.component.scss b/console/src/app/pages/users/user-detail/auth-user-detail/auth-user-mfa/auth-user-mfa.component.scss
index 411f391e2f..3f9facae7c 100644
--- a/console/src/app/pages/users/user-detail/auth-user-detail/auth-user-mfa/auth-user-mfa.component.scss
+++ b/console/src/app/pages/users/user-detail/auth-user-detail/auth-user-mfa/auth-user-mfa.component.scss
@@ -2,6 +2,7 @@
.add-row {
display: flex;
margin: -.5rem;
+ flex-wrap: wrap;
.button {
margin: .5rem;
diff --git a/console/src/app/pages/users/user-detail/auth-user-detail/auth-user-mfa/auth-user-mfa.component.ts b/console/src/app/pages/users/user-detail/auth-user-detail/auth-user-mfa/auth-user-mfa.component.ts
index ea9baa7253..972d7172ae 100644
--- a/console/src/app/pages/users/user-detail/auth-user-detail/auth-user-mfa/auth-user-mfa.component.ts
+++ b/console/src/app/pages/users/user-detail/auth-user-detail/auth-user-mfa/auth-user-mfa.component.ts
@@ -4,11 +4,23 @@ import { MatSort } from '@angular/material/sort';
import { MatTable, MatTableDataSource } from '@angular/material/table';
import { BehaviorSubject, Observable } from 'rxjs';
import { WarnDialogComponent } from 'src/app/modules/warn-dialog/warn-dialog.component';
-import { MfaOtpResponse, MFAState, MfaType, MultiFactor } from 'src/app/proto/generated/auth_pb';
+import { MfaOtpResponse, MFAState, MfaType, MultiFactor, WebAuthNResponse } from 'src/app/proto/generated/auth_pb';
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
import { ToastService } from 'src/app/services/toast.service';
+import { _base64ToArrayBuffer } from '../../u2f-util';
import { DialogOtpComponent } from '../dialog-otp/dialog-otp.component';
+import { DialogU2FComponent, U2FComponentDestination } from '../dialog-u2f/dialog-u2f.component';
+
+export interface WebAuthNOptions {
+ challenge: string;
+ rp: { name: string, id: string; };
+ user: { name: string, id: string, displayName: string; };
+ pubKeyCredParams: any;
+ authenticatorSelection: { userVerification: string; };
+ timeout: number;
+ attestation: string;
+}
@Component({
selector: 'app-auth-user-mfa',
@@ -16,7 +28,7 @@ import { DialogOtpComponent } from '../dialog-otp/dialog-otp.component';
styleUrls: ['./auth-user-mfa.component.scss'],
})
export class AuthUserMfaComponent implements OnInit, OnDestroy {
- public displayedColumns: string[] = ['type', 'state', 'actions'];
+ public displayedColumns: string[] = ['type', 'attr', 'state', 'actions'];
private loadingSubject: BehaviorSubject
= new BehaviorSubject(false);
public loading$: Observable = this.loadingSubject.asObservable();
@@ -29,10 +41,13 @@ export class AuthUserMfaComponent implements OnInit, OnDestroy {
public error: string = '';
public otpAvailable: boolean = false;
- constructor(private service: GrpcAuthService, private toast: ToastService, private dialog: MatDialog) { }
+
+ constructor(private service: GrpcAuthService,
+ private toast: ToastService,
+ private dialog: MatDialog) { }
public ngOnInit(): void {
- this.getOTP();
+ this.getMFAs();
}
public ngOnDestroy(): void {
@@ -50,7 +65,7 @@ export class AuthUserMfaComponent implements OnInit, OnDestroy {
dialogRef.afterClosed().subscribe((code) => {
if (code) {
this.service.VerifyMfaOTP(code).then(() => {
- this.getOTP();
+ this.getMFAs();
});
}
});
@@ -59,7 +74,44 @@ export class AuthUserMfaComponent implements OnInit, OnDestroy {
});
}
- public getOTP(): void {
+ public addU2F(): void {
+ this.service.AddMyMfaU2F().then((u2fresp) => {
+ const webauthn: WebAuthNResponse.AsObject = u2fresp.toObject();
+ const credOptions: CredentialCreationOptions = JSON.parse(atob(webauthn.publicKey as string));
+
+ if (credOptions.publicKey?.challenge) {
+ credOptions.publicKey.challenge = _base64ToArrayBuffer(credOptions.publicKey.challenge as any);
+ credOptions.publicKey.user.id = _base64ToArrayBuffer(credOptions.publicKey.user.id as any);
+ if (credOptions.publicKey.excludeCredentials) {
+ credOptions.publicKey.excludeCredentials.map(cred => {
+ cred.id = _base64ToArrayBuffer(cred.id as any);
+ return cred;
+ });
+ }
+ console.log(credOptions);
+ const dialogRef = this.dialog.open(DialogU2FComponent, {
+ width: '400px',
+ data: {
+ credOptions,
+ type: U2FComponentDestination.MFA,
+ },
+ });
+
+ dialogRef.afterClosed().subscribe(done => {
+ if (done) {
+ this.getMFAs();
+ } else {
+ this.getMFAs();
+ }
+ });
+ }
+
+ }, error => {
+ this.toast.showError(error);
+ });
+ }
+
+ public getMFAs(): void {
this.service.GetMyMfas().then(mfas => {
this.dataSource = new MatTableDataSource(mfas.toObject().mfasList);
this.dataSource.sort = this.sort;
@@ -73,13 +125,13 @@ export class AuthUserMfaComponent implements OnInit, OnDestroy {
});
}
- public deleteMFA(type: MfaType): void {
+ public deleteMFA(type: MfaType, id?: string): void {
const dialogRef = this.dialog.open(WarnDialogComponent, {
data: {
confirmKey: 'ACTIONS.DELETE',
cancelKey: 'ACTIONS.CANCEL',
- titleKey: 'USER.MFA.DIALOG.OTP_DELETE_TITLE',
- descriptionKey: 'USER.MFA.DIALOG.OTP_DELETE_DESCRIPTION',
+ titleKey: 'USER.MFA.DIALOG.MFA_DELETE_TITLE',
+ descriptionKey: 'USER.MFA.DIALOG.MFA_DELETE_DESCRIPTION',
},
width: '400px',
});
@@ -94,7 +146,19 @@ export class AuthUserMfaComponent implements OnInit, OnDestroy {
if (index > -1) {
this.dataSource.data.splice(index, 1);
}
- this.getOTP();
+ this.getMFAs();
+ }).catch(error => {
+ this.toast.showError(error);
+ });
+ } else if (type === MfaType.MFATYPE_U2F && id) {
+ this.service.RemoveMyMfaU2F(id).then(() => {
+ this.toast.showInfo('USER.TOAST.U2FREMOVED', true);
+
+ const index = this.dataSource.data.findIndex(mfa => mfa.type === type);
+ if (index > -1) {
+ this.dataSource.data.splice(index, 1);
+ }
+ this.getMFAs();
}).catch(error => {
this.toast.showError(error);
});
@@ -102,4 +166,6 @@ export class AuthUserMfaComponent implements OnInit, OnDestroy {
}
});
}
+
+
}
diff --git a/console/src/app/pages/users/user-detail/auth-user-detail/dialog-otp/dialog-otp.component.html b/console/src/app/pages/users/user-detail/auth-user-detail/dialog-otp/dialog-otp.component.html
index 9a4eb065e1..0d5aa2426b 100644
--- a/console/src/app/pages/users/user-detail/auth-user-detail/dialog-otp/dialog-otp.component.html
+++ b/console/src/app/pages/users/user-detail/auth-user-detail/dialog-otp/dialog-otp.component.html
@@ -1,6 +1,6 @@
{{'USER.MFA.OTP_DIALOG_TITLE' | translate}}
-
{{'USER.MFA.OTP_DIALOG_DESCRIPTION' | translate}}
+
{{'USER.MFA.OTP_DIALOG_DESCRIPTION' | translate}}
@@ -15,4 +15,4 @@
-
\ No newline at end of file
+
diff --git a/console/src/app/pages/users/user-detail/auth-user-detail/dialog-u2f/dialog-u2f.component.html b/console/src/app/pages/users/user-detail/auth-user-detail/dialog-u2f/dialog-u2f.component.html
new file mode 100644
index 0000000000..fa9a136f1e
--- /dev/null
+++ b/console/src/app/pages/users/user-detail/auth-user-detail/dialog-u2f/dialog-u2f.component.html
@@ -0,0 +1,19 @@
+
{{'USER.MFA.U2F_DIALOG_TITLE' | translate}}
+
+
{{'USER.MFA.U2F_DIALOG_DESCRIPTION' | translate}}
+
+
+ {{'USER.MFA.U2F_NAME' | translate}}
+
+
+
+
+
+
{{error}}
+
+
+
+
+
\ No newline at end of file
diff --git a/console/src/app/pages/users/user-detail/auth-user-detail/dialog-u2f/dialog-u2f.component.scss b/console/src/app/pages/users/user-detail/auth-user-detail/dialog-u2f/dialog-u2f.component.scss
new file mode 100644
index 0000000000..94688b0fb8
--- /dev/null
+++ b/console/src/app/pages/users/user-detail/auth-user-detail/dialog-u2f/dialog-u2f.component.scss
@@ -0,0 +1,27 @@
+.qrcode-wrapper {
+ display: flex;
+ align-content: center;
+
+ .qrcode {
+ margin: 1rem auto;
+ }
+}
+
+.form-field {
+ width: 100%;
+}
+
+.error {
+ color: #f44336;
+ font-size: 14px;
+}
+
+.action {
+ display: flex;
+ justify-content: flex-end;
+
+ button {
+ margin-left: .5rem;
+ border-radius: .5rem;
+ }
+}
diff --git a/console/src/app/pages/users/user-detail/auth-user-detail/dialog-u2f/dialog-u2f.component.ts b/console/src/app/pages/users/user-detail/auth-user-detail/dialog-u2f/dialog-u2f.component.ts
new file mode 100644
index 0000000000..cee3116522
--- /dev/null
+++ b/console/src/app/pages/users/user-detail/auth-user-detail/dialog-u2f/dialog-u2f.component.ts
@@ -0,0 +1,110 @@
+import { Component, Inject } from '@angular/core';
+import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
+import { TranslateService } from '@ngx-translate/core';
+import { take } from 'rxjs/operators';
+import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
+import { ToastService } from 'src/app/services/toast.service';
+
+export function _arrayBufferToBase64(buffer: any): string {
+ let binary = '';
+ const bytes = new Uint8Array(buffer);
+ const len = bytes.byteLength;
+ for (let i = 0; i < len; i++) {
+ binary += String.fromCharCode(bytes[i]);
+ }
+ return btoa(binary).replace(/\+/g, '-')
+ .replace(/\//g, '_')
+ .replace(/=/g, '');
+}
+
+export enum U2FComponentDestination {
+ MFA = 'mfa',
+ PASSWORDLESS = 'passwordless',
+}
+
+@Component({
+ selector: 'app-dialog-u2f',
+ templateUrl: './dialog-u2f.component.html',
+ styleUrls: ['./dialog-u2f.component.scss'],
+})
+export class DialogU2FComponent {
+ private type!: U2FComponentDestination;
+ public name: string = '';
+ public error: string = '';
+ public loading: boolean = false;
+
+ constructor(public dialogRef: MatDialogRef
,
+ @Inject(MAT_DIALOG_DATA) public data: { credOptions: any; type: U2FComponentDestination; },
+ private service: GrpcAuthService, private translate: TranslateService, private toast: ToastService) {
+ this.type = data.type;
+ }
+
+ public closeDialog(): void {
+ this.dialogRef.close();
+ }
+
+ public closeDialogWithCode(): void {
+ this.error = '';
+ this.loading = true;
+ if (this.name && this.data.credOptions.publicKey) {
+ // this.data.credOptions.publicKey.rp.id = 'localhost';
+ navigator.credentials.create(this.data.credOptions).then((resp) => {
+ if (resp &&
+ (resp as any).response.attestationObject &&
+ (resp as any).response.clientDataJSON &&
+ (resp as any).rawId) {
+
+ const attestationObject = (resp as any).response.attestationObject;
+ const clientDataJSON = (resp as any).response.clientDataJSON;
+ const rawId = (resp as any).rawId;
+
+ const data = JSON.stringify({
+ id: resp.id,
+ rawId: _arrayBufferToBase64(rawId),
+ type: resp.type,
+ response: {
+ attestationObject: _arrayBufferToBase64(attestationObject),
+ clientDataJSON: _arrayBufferToBase64(clientDataJSON),
+ },
+ });
+
+ const base64 = btoa(data);
+ if (this.type === U2FComponentDestination.MFA) {
+ this.service.VerifyMyMfaU2F(base64, this.name).then(() => {
+ this.translate.get('USER.MFA.U2F_SUCCESS').pipe(take(1)).subscribe(msg => {
+ this.toast.showInfo(msg);
+ });
+ this.dialogRef.close(true);
+ this.loading = false;
+ }).catch(error => {
+ this.loading = false;
+ this.toast.showError(error);
+ });
+ } else if (this.type === U2FComponentDestination.PASSWORDLESS) {
+ this.service.verifyMyPasswordless(base64, this.name).then(() => {
+ this.translate.get('USER.PASSWORDLESS.U2F_SUCCESS').pipe(take(1)).subscribe(msg => {
+ this.toast.showInfo(msg);
+ });
+ this.dialogRef.close(true);
+ this.loading = false;
+ }).catch(error => {
+ this.loading = false;
+ this.toast.showError(error);
+ });
+ }
+ } else {
+ this.loading = false;
+ this.translate.get('USER.MFA.U2F_ERROR').pipe(take(1)).subscribe(msg => {
+ this.toast.showInfo(msg);
+ });
+ this.dialogRef.close(true);
+ }
+ }).catch(error => {
+ this.loading = false;
+ this.error = error;
+ this.toast.showInfo(error.message);
+ });
+ }
+
+ }
+}
diff --git a/console/src/app/pages/users/user-detail/auth-user-detail/edit-dialog/edit-dialog.component.html b/console/src/app/pages/users/user-detail/auth-user-detail/edit-dialog/edit-dialog.component.html
index 37056e74fe..81ded0f7ef 100644
--- a/console/src/app/pages/users/user-detail/auth-user-detail/edit-dialog/edit-dialog.component.html
+++ b/console/src/app/pages/users/user-detail/auth-user-detail/edit-dialog/edit-dialog.component.html
@@ -5,7 +5,7 @@
{{data.labelKey | translate }}
-
+
diff --git a/console/src/app/pages/users/user-detail/u2f-util.ts b/console/src/app/pages/users/user-detail/u2f-util.ts
new file mode 100644
index 0000000000..02e61dfa5c
--- /dev/null
+++ b/console/src/app/pages/users/user-detail/u2f-util.ts
@@ -0,0 +1,10 @@
+
+export function _base64ToArrayBuffer(base64: string): any {
+ const binaryString = atob(base64);
+ const len = binaryString.length;
+ const bytes = new Uint8Array(len);
+ for (let i = 0; i < len; i++) {
+ bytes[i] = binaryString.charCodeAt(i);
+ }
+ return bytes.buffer;
+}
diff --git a/console/src/app/pages/users/user-detail/user-detail.module.ts b/console/src/app/pages/users/user-detail/user-detail.module.ts
index a217c0e7b8..cab3739fbb 100644
--- a/console/src/app/pages/users/user-detail/user-detail.module.ts
+++ b/console/src/app/pages/users/user-detail/user-detail.module.ts
@@ -29,10 +29,12 @@ import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.mod
import { LocalizedDatePipeModule } from 'src/app/pipes/localized-date-pipe/localized-date-pipe.module';
import { TimestampToDatePipeModule } from 'src/app/pipes/timestamp-to-date-pipe/timestamp-to-date-pipe.module';
+import { AuthPasswordlessComponent } from './auth-user-detail/auth-passwordless/auth-passwordless.component';
import { AuthUserDetailComponent } from './auth-user-detail/auth-user-detail.component';
import { AuthUserMfaComponent } from './auth-user-detail/auth-user-mfa/auth-user-mfa.component';
import { CodeDialogComponent } from './auth-user-detail/code-dialog/code-dialog.component';
import { DialogOtpComponent } from './auth-user-detail/dialog-otp/dialog-otp.component';
+import { DialogU2FComponent } from './auth-user-detail/dialog-u2f/dialog-u2f.component';
import { EditDialogComponent } from './auth-user-detail/edit-dialog/edit-dialog.component';
import { ResendEmailDialogComponent } from './auth-user-detail/resend-email-dialog/resend-email-dialog.component';
import { ThemeSettingComponent } from './auth-user-detail/theme-setting/theme-setting.component';
@@ -46,6 +48,7 @@ import { ShowKeyDialogModule } from './machine-keys/show-key-dialog/show-key-dia
import { MembershipsComponent } from './memberships/memberships.component';
import { PasswordComponent } from './password/password.component';
import { UserDetailRoutingModule } from './user-detail-routing.module';
+import { PasswordlessComponent } from './user-detail/passwordless/passwordless.component';
import { UserDetailComponent } from './user-detail/user-detail.component';
import { UserMfaComponent } from './user-detail/user-mfa/user-mfa.component';
@@ -56,7 +59,9 @@ import { UserMfaComponent } from './user-detail/user-mfa/user-mfa.component';
DialogOtpComponent,
EditDialogComponent,
AuthUserMfaComponent,
+ AuthPasswordlessComponent,
UserMfaComponent,
+ PasswordlessComponent,
ThemeSettingComponent,
PasswordComponent,
CodeDialogComponent,
@@ -65,6 +70,7 @@ import { UserMfaComponent } from './user-detail/user-mfa/user-mfa.component';
ExternalIdpsComponent,
ContactComponent,
ResendEmailDialogComponent,
+ DialogU2FComponent,
],
imports: [
UserDetailRoutingModule,
diff --git a/console/src/app/pages/users/user-detail/user-detail/passwordless/passwordless.component.html b/console/src/app/pages/users/user-detail/user-detail/passwordless/passwordless.component.html
new file mode 100644
index 0000000000..6f6f40f267
--- /dev/null
+++ b/console/src/app/pages/users/user-detail/user-detail/passwordless/passwordless.component.html
@@ -0,0 +1,43 @@
+
+
+
+
+ {{ 'USER.PASSWORDLESS.NAME' | translate }} |
+
+ {{ mfa?.name }}
+
+ |
+
+
+
+ {{ 'USER.PASSWORDLESS.TABLESTATE' | translate }} |
+
+ {{'USER.PASSWORDLESS.STATE.'+ mfa.state | translate}}
+
+
+ |
+
+
+
+ {{ 'USER.PASSWORDLESS.TABLEACTIONS' | translate }} |
+
+
+ |
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/console/src/app/pages/users/user-detail/user-detail/passwordless/passwordless.component.scss b/console/src/app/pages/users/user-detail/user-detail/passwordless/passwordless.component.scss
new file mode 100644
index 0000000000..0c317899c6
--- /dev/null
+++ b/console/src/app/pages/users/user-detail/user-detail/passwordless/passwordless.component.scss
@@ -0,0 +1,26 @@
+
+.centered {
+ display: flex;
+ align-items: center;
+
+ i {
+ margin-left: 1rem;
+ color: var(--color-main);
+ }
+}
+
+.table {
+ width: 100%;
+
+ td,
+ th {
+ &:first-child {
+ padding-left: 0;
+ padding-right: 1rem;
+ }
+
+ &:last-child {
+ padding-right: 0;
+ }
+ }
+}
diff --git a/console/src/app/pages/users/user-detail/user-detail/passwordless/passwordless.component.spec.ts b/console/src/app/pages/users/user-detail/user-detail/passwordless/passwordless.component.spec.ts
new file mode 100644
index 0000000000..fbee4d4c7f
--- /dev/null
+++ b/console/src/app/pages/users/user-detail/user-detail/passwordless/passwordless.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
+
+import { AuthPasswordlessComponent } from './auth-passwordless.component';
+
+describe('AuthPasswordlessComponent', () => {
+ let component: AuthPasswordlessComponent;
+ let fixture: ComponentFixture
;
+
+ beforeEach(waitForAsync(() => {
+ TestBed.configureTestingModule({
+ declarations: [AuthPasswordlessComponent],
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(AuthPasswordlessComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/console/src/app/pages/users/user-detail/user-detail/passwordless/passwordless.component.ts b/console/src/app/pages/users/user-detail/user-detail/passwordless/passwordless.component.ts
new file mode 100644
index 0000000000..2312bff049
--- /dev/null
+++ b/console/src/app/pages/users/user-detail/user-detail/passwordless/passwordless.component.ts
@@ -0,0 +1,84 @@
+import { Component, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
+import { MatDialog } from '@angular/material/dialog';
+import { MatSort } from '@angular/material/sort';
+import { MatTable, MatTableDataSource } from '@angular/material/table';
+import { BehaviorSubject, Observable } from 'rxjs';
+import { WarnDialogComponent } from 'src/app/modules/warn-dialog/warn-dialog.component';
+import { MFAState, WebAuthNToken } from 'src/app/proto/generated/auth_pb';
+import { UserView } from 'src/app/proto/generated/management_pb';
+import { ManagementService } from 'src/app/services/mgmt.service';
+import { ToastService } from 'src/app/services/toast.service';
+
+export interface WebAuthNOptions {
+ challenge: string;
+ rp: { name: string, id: string; };
+ user: { name: string, id: string, displayName: string; };
+ pubKeyCredParams: any;
+ authenticatorSelection: { userVerification: string; };
+ timeout: number;
+ attestation: string;
+}
+
+@Component({
+ selector: 'app-passwordless',
+ templateUrl: './passwordless.component.html',
+ styleUrls: ['./passwordless.component.scss'],
+})
+export class PasswordlessComponent implements OnInit, OnDestroy {
+ @Input() private user!: UserView.AsObject;
+ public displayedColumns: string[] = ['name', 'state', 'actions'];
+ private loadingSubject: BehaviorSubject = new BehaviorSubject(false);
+ public loading$: Observable = this.loadingSubject.asObservable();
+
+ @ViewChild(MatTable) public table!: MatTable;
+ @ViewChild(MatSort) public sort!: MatSort;
+ public dataSource!: MatTableDataSource;
+
+ public MFAState: any = MFAState;
+ public error: string = '';
+
+ constructor(private service: ManagementService,
+ private toast: ToastService,
+ private dialog: MatDialog) { }
+
+ public ngOnInit(): void {
+ this.getPasswordless();
+ }
+
+ public ngOnDestroy(): void {
+ this.loadingSubject.complete();
+ }
+
+ public getPasswordless(): void {
+ this.service.GetPasswordless(this.user.id).then(passwordless => {
+ console.log(passwordless.toObject().tokensList);
+ this.dataSource = new MatTableDataSource(passwordless.toObject().tokensList);
+ this.dataSource.sort = this.sort;
+ }).catch(error => {
+ this.error = error.message;
+ });
+ }
+
+ public deletePasswordless(id?: string): void {
+ const dialogRef = this.dialog.open(WarnDialogComponent, {
+ data: {
+ confirmKey: 'ACTIONS.DELETE',
+ cancelKey: 'ACTIONS.CANCEL',
+ titleKey: 'USER.PASSWORDLESS.DIALOG.DELETE_TITLE',
+ descriptionKey: 'USER.PASSWORDLESS.DIALOG.DELETE_DESCRIPTION',
+ },
+ width: '400px',
+ });
+
+ dialogRef.afterClosed().subscribe(resp => {
+ if (resp && id) {
+ this.service.RemovePasswordless(id, this.user.id).then(() => {
+ this.toast.showInfo('USER.TOAST.PASSWORDLESSREMOVED', true);
+ this.getPasswordless();
+ }).catch(error => {
+ this.toast.showError(error);
+ });
+ }
+ });
+ }
+}
diff --git a/console/src/app/pages/users/user-detail/user-detail/user-detail.component.html b/console/src/app/pages/users/user-detail/user-detail/user-detail.component.html
index b430a4d878..61b915c0d3 100644
--- a/console/src/app/pages/users/user-detail/user-detail/user-detail.component.html
+++ b/console/src/app/pages/users/user-detail/user-detail/user-detail.component.html
@@ -84,6 +84,8 @@
+
+
-
+
{{ 'USER.MFA.TABLETYPE' | translate }} |
{{'USER.MFA.TYPE.'+ mfa.type | translate}} |
+
+ {{ 'USER.MFA.ATTRIBUTE' | translate }} |
+
+ {{ mfa.attribute }}
+
+ |
+
+
{{ 'USER.MFA.TABLESTATE' | translate }} |
@@ -21,7 +29,7 @@
| {{ 'USER.MFA.TABLEACTIONS' | translate }} |
|
diff --git a/console/src/app/pages/users/user-detail/user-detail/user-mfa/user-mfa.component.ts b/console/src/app/pages/users/user-detail/user-detail/user-mfa/user-mfa.component.ts
index e91c170d77..e06e324a21 100644
--- a/console/src/app/pages/users/user-detail/user-detail/user-mfa/user-mfa.component.ts
+++ b/console/src/app/pages/users/user-detail/user-detail/user-mfa/user-mfa.component.ts
@@ -20,7 +20,7 @@ export interface MFAItem {
styleUrls: ['./user-mfa.component.scss'],
})
export class UserMfaComponent implements OnInit, OnDestroy {
- public displayedColumns: string[] = ['type', 'state', 'actions'];
+ public displayedColumns: string[] = ['type', 'attr', 'state', 'actions'];
@Input() private user!: UserView.AsObject;
public mfaSubject: BehaviorSubject = new BehaviorSubject([]);
private loadingSubject: BehaviorSubject = new BehaviorSubject(false);
@@ -37,7 +37,7 @@ export class UserMfaComponent implements OnInit, OnDestroy {
constructor(private mgmtUserService: ManagementService, private dialog: MatDialog, private toast: ToastService) { }
public ngOnInit(): void {
- this.getOTP();
+ this.getMFAs();
}
public ngOnDestroy(): void {
@@ -45,8 +45,9 @@ export class UserMfaComponent implements OnInit, OnDestroy {
this.loadingSubject.complete();
}
- public getOTP(): void {
+ public getMFAs(): void {
this.mgmtUserService.getUserMfas(this.user.id).then(mfas => {
+ console.log(mfas.toObject().mfasList);
this.dataSource = new MatTableDataSource(mfas.toObject().mfasList);
this.dataSource.sort = this.sort;
}).catch(error => {
@@ -54,13 +55,14 @@ export class UserMfaComponent implements OnInit, OnDestroy {
});
}
- public deleteMFA(type: MfaType): void {
+ public deleteMFA(type: MfaType, id?: string): void {
+ console.log(type, id);
const dialogRef = this.dialog.open(WarnDialogComponent, {
data: {
confirmKey: 'ACTIONS.DELETE',
cancelKey: 'ACTIONS.CANCEL',
- titleKey: 'USER.MFA.DIALOG.OTP_DELETE_TITLE',
- descriptionKey: 'USER.MFA.DIALOG.OTP_DELETE_DESCRIPTION',
+ titleKey: 'USER.MFA.DIALOG.MFA_DELETE_TITLE',
+ descriptionKey: 'USER.MFA.DIALOG.MFA_DELETE_DESCRIPTION',
},
width: '400px',
});
@@ -75,7 +77,20 @@ export class UserMfaComponent implements OnInit, OnDestroy {
if (index > -1) {
this.dataSource.data.splice(index, 1);
}
- this.getOTP();
+ this.getMFAs();
+ }).catch(error => {
+ this.toast.showError(error);
+ });
+ } else if (type === MfaType.MFATYPE_U2F && id) {
+ console.log(this.user.id, id);
+ this.mgmtUserService.RemoveMfaU2F(this.user.id, id).then(() => {
+ this.toast.showInfo('USER.TOAST.U2FREMOVED', true);
+
+ const index = this.dataSource.data.findIndex(mfa => mfa.type === type);
+ if (index > -1) {
+ this.dataSource.data.splice(index, 1);
+ }
+ this.getMFAs();
}).catch(error => {
this.toast.showError(error);
});
diff --git a/console/src/app/pages/users/user-list/user-table/user-table.component.html b/console/src/app/pages/users/user-list/user-table/user-table.component.html
index a508c5d858..74d0cad53e 100644
--- a/console/src/app/pages/users/user-list/user-table/user-table.component.html
+++ b/console/src/app/pages/users/user-list/user-table/user-table.component.html
@@ -1,4 +1,4 @@
-
diff --git a/console/src/app/services/admin.service.ts b/console/src/app/services/admin.service.ts
index adad72a275..3e4f5cc167 100644
--- a/console/src/app/services/admin.service.ts
+++ b/console/src/app/services/admin.service.ts
@@ -11,6 +11,7 @@ import {
DefaultLabelPolicyUpdate,
DefaultLabelPolicyView,
DefaultLoginPolicy,
+ DefaultLoginPolicyRequest,
DefaultLoginPolicyView,
DefaultPasswordAgePolicyRequest,
DefaultPasswordAgePolicyView,
@@ -36,6 +37,8 @@ import {
IdpSearchRequest,
IdpSearchResponse,
IdpView,
+ MultiFactor,
+ MultiFactorsResult,
OidcIdpConfig,
OidcIdpConfigCreate,
OidcIdpConfigUpdate,
@@ -46,6 +49,8 @@ import {
OrgSetUpRequest,
OrgSetUpResponse,
RemoveIamMemberRequest,
+ SecondFactor,
+ SecondFactorsResult,
ViewID,
Views,
} from '../proto/generated/admin_pb';
@@ -73,6 +78,32 @@ export class AdminService {
return this.grpcService.admin.setUpOrg(req);
}
+ public getDefaultLoginPolicyMultiFactors(): Promise {
+ const req = new Empty();
+ return this.grpcService.admin.getDefaultLoginPolicyMultiFactors(req);
+ }
+
+ public addMultiFactorToDefaultLoginPolicy(req: MultiFactor): Promise {
+ return this.grpcService.admin.addMultiFactorToDefaultLoginPolicy(req);
+ }
+
+ public RemoveMultiFactorFromDefaultLoginPolicy(req: MultiFactor): Promise {
+ return this.grpcService.admin.removeMultiFactorFromDefaultLoginPolicy(req);
+ }
+
+ public GetDefaultLoginPolicySecondFactors(): Promise {
+ const req = new Empty();
+ return this.grpcService.admin.getDefaultLoginPolicySecondFactors(req);
+ }
+
+ public AddSecondFactorToDefaultLoginPolicy(req: SecondFactor): Promise {
+ return this.grpcService.admin.addSecondFactorToDefaultLoginPolicy(req);
+ }
+
+ public RemoveSecondFactorFromDefaultLoginPolicy(req: SecondFactor): Promise {
+ return this.grpcService.admin.removeSecondFactorFromDefaultLoginPolicy(req);
+ }
+
public GetIamMemberRoles(): Promise {
const req = new Empty();
return this.grpcService.admin.getIamMemberRoles(req);
@@ -184,7 +215,7 @@ export class AdminService {
return this.grpcService.admin.getDefaultLoginPolicy(req);
}
- public UpdateDefaultLoginPolicy(req: DefaultLoginPolicy): Promise {
+ public UpdateDefaultLoginPolicy(req: DefaultLoginPolicyRequest): Promise {
return this.grpcService.admin.updateDefaultLoginPolicy(req);
}
diff --git a/console/src/app/services/grpc-auth.service.ts b/console/src/app/services/grpc-auth.service.ts
index 67d5f4def4..0022c24126 100644
--- a/console/src/app/services/grpc-auth.service.ts
+++ b/console/src/app/services/grpc-auth.service.ts
@@ -33,6 +33,10 @@ import {
UserView,
VerifyMfaOtp,
VerifyUserPhoneRequest,
+ VerifyWebAuthN,
+ WebAuthNResponse,
+ WebAuthNTokenID,
+ WebAuthNTokens,
} from '../proto/generated/auth_pb';
import { GrpcService } from './grpc.service';
import { StorageKey, StorageService } from './storage.service';
@@ -328,6 +332,56 @@ export class GrpcAuthService {
);
}
+ public AddMyMfaU2F(): Promise {
+ return this.grpcService.auth.addMyMfaU2F(
+ new Empty(),
+ );
+ }
+
+ public RemoveMyMfaU2F(id: string): Promise {
+ const req = new WebAuthNTokenID();
+ req.setId(id);
+ return this.grpcService.auth.removeMyMfaU2F(req);
+ }
+
+ public VerifyMyMfaU2F(credential: string, tokenname: string): Promise {
+ const req = new VerifyWebAuthN();
+ req.setPublicKeyCredential(credential);
+ req.setTokenName(tokenname);
+
+ return this.grpcService.auth.verifyMyMfaU2F(
+ req,
+ );
+ }
+
+ public GetMyPasswordless(): Promise {
+ return this.grpcService.auth.getMyPasswordless(
+ new Empty(),
+ );
+ }
+
+ public AddMyPasswordless(): Promise {
+ return this.grpcService.auth.addMyPasswordless(
+ new Empty(),
+ );
+ }
+
+ public RemoveMyPasswordless(id: string): Promise {
+ const req = new WebAuthNTokenID();
+ req.setId(id);
+ return this.grpcService.auth.removeMyPasswordless(req);
+ }
+
+ public verifyMyPasswordless(credential: string, tokenname: string): Promise {
+ const req = new VerifyWebAuthN();
+ req.setPublicKeyCredential(credential);
+ req.setTokenName(tokenname);
+
+ return this.grpcService.auth.verifyMyPasswordless(
+ req,
+ );
+ }
+
public RemoveMfaOTP(): Promise {
return this.grpcService.auth.removeMfaOTP(
new Empty(),
diff --git a/console/src/app/services/mgmt.service.ts b/console/src/app/services/mgmt.service.ts
index 31fef046a0..f76b8f5cc8 100644
--- a/console/src/app/services/mgmt.service.ts
+++ b/console/src/app/services/mgmt.service.ts
@@ -3,6 +3,7 @@ import { Empty } from 'google-protobuf/google/protobuf/empty_pb';
import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb';
import { BehaviorSubject } from 'rxjs';
+import { MultiFactorsResult } from '../proto/generated/admin_pb';
import {
AddMachineKeyRequest,
AddMachineKeyResponse,
@@ -50,6 +51,7 @@ import {
MachineKeySearchResponse,
MachineKeyType,
MachineResponse,
+ MultiFactor,
NotificationType,
OIDCApplicationCreate,
OIDCConfig,
@@ -122,6 +124,8 @@ import {
ProjectView,
RemoveOrgDomainRequest,
RemoveOrgMemberRequest,
+ SecondFactor,
+ SecondFactorsResult,
SetPasswordNotificationRequest,
UpdateMachineRequest,
UpdateUserAddressRequest,
@@ -152,6 +156,8 @@ import {
UserSearchResponse,
UserView,
ValidateOrgDomainRequest,
+ WebAuthNTokenID,
+ WebAuthNTokens,
ZitadelDocs,
} from '../proto/generated/management_pb';
import { GrpcService } from './grpc.service';
@@ -185,6 +191,45 @@ export class ManagementService {
return this.grpcService.mgmt.searchIdps(req);
}
+ public GetPasswordless(userId: string): Promise {
+ const req = new UserID();
+ req.setId(userId);
+ return this.grpcService.mgmt.getPasswordless(req);
+ }
+
+ public RemovePasswordless(id: string, userId: string): Promise {
+ const req = new WebAuthNTokenID();
+ req.setId(id);
+ req.setUserId(userId);
+ return this.grpcService.mgmt.removePasswordless(req);
+ }
+
+ public GetLoginPolicyMultiFactors(): Promise {
+ const req = new Empty();
+ return this.grpcService.mgmt.getLoginPolicyMultiFactors(req);
+ }
+
+ public AddMultiFactorToLoginPolicy(req: MultiFactor): Promise {
+ return this.grpcService.mgmt.addMultiFactorToLoginPolicy(req);
+ }
+
+ public RemoveMultiFactorFromLoginPolicy(req: MultiFactor): Promise {
+ return this.grpcService.mgmt.removeMultiFactorFromLoginPolicy(req);
+ }
+
+ public GetLoginPolicySecondFactors(): Promise {
+ const req = new Empty();
+ return this.grpcService.mgmt.getLoginPolicySecondFactors(req);
+ }
+
+ public AddSecondFactorToLoginPolicy(req: SecondFactor): Promise {
+ return this.grpcService.mgmt.addSecondFactorToLoginPolicy(req);
+ }
+
+ public RemoveSecondFactorFromLoginPolicy(req: SecondFactor): Promise {
+ return this.grpcService.mgmt.removeSecondFactorFromLoginPolicy(req);
+ }
+
public GetLoginPolicy(): Promise {
const req = new Empty();
return this.grpcService.mgmt.getLoginPolicy(req);
@@ -683,6 +728,13 @@ export class ManagementService {
return this.grpcService.mgmt.removeMfaOTP(req);
}
+ public RemoveMfaU2F(userid: string, id: string): Promise {
+ const req = new WebAuthNTokenID();
+ req.setId(id);
+ req.setUserId(userid);
+ return this.grpcService.mgmt.removeMfaU2F(req);
+ }
+
public SaveUserProfile(
id: string,
firstName?: string,
@@ -1307,21 +1359,7 @@ export class ManagementService {
return this.grpcService.mgmt.updateApplication(req);
}
- public UpdateOIDCAppConfig(projectId: string,
- appId: string, oidcConfig: OIDCConfig.AsObject): Promise {
- const req = new OIDCConfigUpdate();
- req.setProjectId(projectId);
- req.setApplicationId(appId);
- req.setRedirectUrisList(oidcConfig.redirectUrisList);
- req.setResponseTypesList(oidcConfig.responseTypesList);
- req.setAuthMethodType(oidcConfig.authMethodType);
- req.setPostLogoutRedirectUrisList(oidcConfig.postLogoutRedirectUrisList);
- req.setGrantTypesList(oidcConfig.grantTypesList);
- req.setApplicationType(oidcConfig.applicationType);
- req.setDevMode(oidcConfig.devMode);
- req.setAccessTokenType(oidcConfig.accessTokenType);
- req.setAccessTokenRoleAssertion(oidcConfig.accessTokenRoleAssertion);
- req.setIdTokenRoleAssertion(oidcConfig.idTokenRoleAssertion);
+ public UpdateOIDCAppConfig(req: OIDCConfigUpdate): Promise {
return this.grpcService.mgmt.updateApplicationOIDCConfig(req);
}
}
diff --git a/console/src/assets/i18n/de.json b/console/src/assets/i18n/de.json
index a003ec328b..7f12d7b93f 100644
--- a/console/src/assets/i18n/de.json
+++ b/console/src/assets/i18n/de.json
@@ -152,16 +152,20 @@
},
"EMPTY":"Keine Einträge"
},
- "MFA": {
+ "PASSWORDLESS": {
"TABLETYPE":"Typ",
"TABLESTATE":"Status",
+ "NAME":"Name",
"TABLEACTIONS":"Aktionen",
- "TITLE": "Multifaktor-Authentisierung",
- "DESCRIPTION": "Füge einen zusätzlichen Faktor hinzu, um Dein Konto optimal zu schützen.",
+ "TITLE": "Passwortlose Authentifizierungsmethoden",
+ "DESCRIPTION": "Füge WebAuthn kompatible Authentifikatoren hinzu um dich passwortlos anzumelden.",
"MANAGE_DESCRIPTION": "Verwalte die Multifaktor-Merkmale Deiner Benutzer.",
- "OTP": "OTP konfigurieren",
- "OTP_DIALOG_TITLE": "OTP hinzufügen",
- "OTP_DIALOG_DESCRIPTION": "Scanne den QR-Code mit einer Authenticator App und verifiziere den erhaltenen Code, um OTP zu aktivieren.",
+ "U2F":"Authentifikator hinzufügen",
+ "U2F_DIALOG_TITLE": "Authentifikator hinzufügen",
+ "U2F_DIALOG_DESCRIPTION": "Gib einen Namen für den von dir verwendeten Login an.",
+ "U2F_SUCCESS":"Passwordless erfolgreich erstellt!",
+ "U2F_ERROR":"Ein Fehler ist aufgetreten!",
+ "U2F_NAME":"Authentifikator Name",
"TYPE": {
"0":"Keine MFA definiert",
"1":"OTP",
@@ -174,8 +178,41 @@
"3": "Gelöscht"
},
"DIALOG": {
- "OTP_DELETE_TITLE":"OTP Faktor entfernen",
- "OTP_DELETE_DESCRIPTION":"Sie sind im Begriff OTP als Zweitfaktormethode zu entfernen. Sind sie sicher?"
+ "DELETE_TITLE":"Passwordless entfernen",
+ "DELETE_DESCRIPTION":"Sie sind im Begriff eine Passwortlose Authentifizierungsmethode zu entfernen. Sind sie sicher?"
+ }
+ },
+ "MFA": {
+ "TABLETYPE":"Typ",
+ "TABLESTATE":"Status",
+ "ATTRIBUTE":"Attribut",
+ "TABLEACTIONS":"Aktionen",
+ "TITLE": "Multifaktor-Authentisierung",
+ "DESCRIPTION": "Füge einen zusätzlichen Faktor hinzu, um Dein Konto optimal zu schützen.",
+ "MANAGE_DESCRIPTION": "Verwalte die Multifaktor-Merkmale Deiner Benutzer.",
+ "OTP": "OTP konfigurieren",
+ "OTP_DIALOG_TITLE": "OTP hinzufügen",
+ "OTP_DIALOG_DESCRIPTION": "Scanne den QR-Code mit einer Authenticator App und verifiziere den erhaltenen Code, um OTP zu aktivieren.",
+ "U2F":"U2F hinzufügen",
+ "U2F_DIALOG_TITLE": "U2F hinzufügen",
+ "U2F_DIALOG_DESCRIPTION": "Gib einen Namen für den von dir verwendeten Universellen Multifaktor an.",
+ "U2F_SUCCESS":"U2F erfolgreich erstellt!",
+ "U2F_ERROR":"Ein Fehler ist aufgetreten!",
+ "U2F_NAME":"U2F Name",
+ "TYPE": {
+ "0":"Keine MFA definiert",
+ "1":"OTP",
+ "2":"U2F"
+ },
+ "STATE": {
+ "0": "Kein Status",
+ "1": "Nicht bereit",
+ "2": "Bereit",
+ "3": "Gelöscht"
+ },
+ "DIALOG": {
+ "MFA_DELETE_TITLE":"Zweiten Faktor entfernen",
+ "MFA_DELETE_DESCRIPTION":"Sie sind im Begriff eine Zweitfaktormethode zu entfernen. Sind sie sicher?"
}
},
"EXTERNALIDP": {
@@ -345,6 +382,8 @@
"PHONEVERIFICATIONSENT":"Bestätigungscode per Telefonnummer gesendet.",
"EMAILVERIFICATIONSENT":"Bestätigungscode per E-Mail gesendet.",
"OTPREMOVED":"OTP entfernt.",
+ "U2FREMOVED":"U2F entfernt.",
+ "PASSWORDLESSREMOVED":"Passwordless entfernt.",
"INITIALPASSWORDSET":"Initiales Passwort gesetzt.",
"PASSWORDNOTIFICATIONSENT":"Passwortänderung mittgeteilt.",
"PASSWORDCHANGED":"Passwort geändert.",
@@ -551,7 +590,9 @@
"ALLOWREGISTER":"Registrieren erlaubt",
"ALLOWUSERNAMEPASSWORD_DESC":"Der konventionelle Login mit Benutzername und Passwort wird erlaubt.",
"ALLOWEXTERNALIDP_DESC":"Der Login wird für die darunter liegenden Identity Provider erlaubt.",
- "ALLOWREGISTER_DESC":"Ist die Option gewählt, erscheint im Login ein zusätzlicher Schritt zum Registrieren eines Benutzers."
+ "ALLOWREGISTER_DESC":"Ist die Option gewählt, erscheint im Login ein zusätzlicher Schritt zum Registrieren eines Benutzers.",
+ "FORCEMFA":"Mfa erzwingen",
+ "FORCEMFA_DESC":"Ist die Option gewählt, müssen Benutzer einen zweiten Faktor für den Login verwenden."
},
"RESET":"Richtlinie zurücksetzen",
"CREATECUSTOM":"Benutzerdefinierte Richtlinie erstellen",
@@ -763,7 +804,7 @@
},
"IDP":{
"LIST": {
- "TITLE":"Identitäts Providers",
+ "TITLE":"Identitäts Provider",
"DESCRIPTION":"Definieren Sie hier Ihre zusätzlichen Idps, die sie für die Authentifizierung in Ihren Organisationen verwenden können."
},
"CREATE": {
@@ -826,6 +867,37 @@
"DELETED":"Idp erfolgreich gelöscht!"
}
},
+ "MFA":{
+ "LIST": {
+ "MULTIFACTORTITLE":"Multifaktoren",
+ "MULTIFACTORDESCRIPTION":"Definieren Sie hier Ihre Multifaktoren, die sie für die Authentifizierung verwenden können.",
+ "SECONDFACTORTITLE":"Zweitfaktoren",
+ "SECONDFACTORDESCRIPTION":"Definieren Sie hier Ihre Zweitfaktoren, die sie für die Authentifizierung verwenden können."
+ },
+ "CREATE": {
+ "TITLE":"Neuer Faktor",
+ "DESCRIPTION":"Definieren Sie hier den gewünschten Typ."
+ },
+ "DELETE": {
+ "TITLE":"Faktor löschen",
+ "DESCRIPTION":"Sie sind im Begriff einen Faktor zu löschen. Die daruch hervorgerufenen Änderungen sind unwiederruflich. Wollen Sie dies wirklich tun?"
+ },
+ "TOAST": {
+ "ADDED":"Erfolgreich hinzugefügt.",
+ "SAVED": "Erfolgreich gespeichert.",
+ "DELETED":"Mfa erfolgreich gelöscht!"
+ },
+ "TYPE":"Typ",
+ "MULTIFACTORTYPES": {
+ "0":"Unknown",
+ "1":"U2F with Pin"
+ },
+ "SECONDFACTORTYPES": {
+ "0":"Unknown",
+ "1":"OTP",
+ "2":"U2F"
+ }
+ },
"LOGINPOLICY": {
"CREATE": {
"TITLE":"Login Policy",
@@ -836,6 +908,11 @@
"TITLE":"Identity Provider hinzufügen",
"DESCRIPTION":"Sie können vordefinierte oder selbsterstellten Provider auswählen",
"SELECTIDPS":"Identity Provider"
+ },
+ "PASSWORDLESS":"Passwordloser Login",
+ "PASSWORDLESSTYPE": {
+ "0":"Nicht erlaubt",
+ "1":"Erlaubt"
}
},
"APP": {
@@ -910,8 +987,11 @@
"OVERVIEWTITLE":"Deine Konfiguration ist bereit. Du kannst sie hier nochmals prüfen.",
"ACCESSTOKENROLEASSERTION":"Benutzerrollen dem Access Token hinzufügen",
"ACCESSTOKENROLEASSERTION_DESCRIPTION":"Bei Auswahl werden dem Access Token die Rollen des Authentifizierten Benutzers hinzugefügt.",
- "IDTOKENROLEASSERTION":"Benutzerrollen dem Id Token hinzufügen",
- "IDTOKENROLEASSERTION_DESCRIPTION":"Bei Auswahl werden dem Id Token die Rollen des Authentifizierten Benutzers hinzugefügt."
+ "IDTOKENROLEASSERTION":"Benutzerrollen im ID Token",
+ "IDTOKENROLEASSERTION_DESCRIPTION":"Bei Auswahl werden dem Id Token die Rollen des Authentifizierten Benutzers hinzugefügt.",
+ "IDTOKENUSERINFOASSERTION":"User Info im ID Token",
+ "IDTOKENUSERINFOASSERTION_DESCRIPTION":"Ermöglich OIDC clients claims von profile, email, phone und address direkt vom ID Token zu beziehen.",
+ "CLOCKSKEW":"ermöglicht Clients, den Taktversatz von OP und Client zu verarbeiten. Die Dauer (0-5s) wird der exp addiert und von iats, auth_time und nbf abgezogen."
},
"TOAST": {
"REACTIVATED":"Anwendung reaktiviert.",
diff --git a/console/src/assets/i18n/en.json b/console/src/assets/i18n/en.json
index b4f01ba663..ee90a3b6c8 100644
--- a/console/src/assets/i18n/en.json
+++ b/console/src/assets/i18n/en.json
@@ -152,16 +152,20 @@
},
"EMPTY":"No entries"
},
- "MFA": {
+ "PASSWORDLESS": {
"TABLETYPE":"Type",
"TABLESTATE":"Status",
+ "NAME":"Name",
"TABLEACTIONS":"Actions",
- "TITLE": "Multifactor Authentication",
- "DESCRIPTION": "Add a second factor to ensure optimal security for your account.",
+ "TITLE": "Passwordless Authentication",
+ "DESCRIPTION": "Add WebAuthn based Authentication Methods to log onto ZITADEL passwordless.",
"MANAGE_DESCRIPTION": "Manage the second factor methods of your users.",
- "OTP": "Configure OTP",
- "OTP_DIALOG_TITLE": "Add OTP",
- "OTP_DIALOG_DESCRIPTION": "Scan the QR code with an authenticator app and enter the code below to verify and activate the OTP method.",
+ "U2F":"Add authenticator",
+ "U2F_DIALOG_TITLE": "Verify authenticator",
+ "U2F_DIALOG_DESCRIPTION": "Enter a name for your used passwordless Login",
+ "U2F_SUCCESS":"Passwordless Auth created successfully!",
+ "U2F_ERROR":"An error during U2F setup occurred!",
+ "U2F_NAME":"Authenticator Name",
"TYPE": {
"0": "No MFA defined",
"1": "OTP",
@@ -174,8 +178,41 @@
"3": "Deleted"
},
"DIALOG": {
- "OTP_DELETE_TITLE":"Remove OTP Factor",
- "OTP_DELETE_DESCRIPTION":"You are about to delete OTP as second factor. Are you sure?"
+ "DELETE_TITLE":"Remove Passwordless Authentication Method",
+ "DELETE_DESCRIPTION":"You are about to delete a passwordless Authentication method. Are you sure?"
+ }
+ },
+ "MFA": {
+ "TABLETYPE":"Type",
+ "TABLESTATE":"Status",
+ "ATTRIBUTE":"Attribut",
+ "TABLEACTIONS":"Actions",
+ "TITLE": "Multifactor Authentication",
+ "DESCRIPTION": "Add a second factor to ensure optimal security for your account.",
+ "MANAGE_DESCRIPTION": "Manage the second factor methods of your users.",
+ "OTP": "Configure OTP",
+ "OTP_DIALOG_TITLE": "Add OTP",
+ "OTP_DIALOG_DESCRIPTION": "Scan the QR code with an authenticator app and enter the code below to verify and activate the OTP method.",
+ "U2F":"Add U2F",
+ "U2F_DIALOG_TITLE": "Verify U2F",
+ "U2F_DIALOG_DESCRIPTION": "Enter a name for your used universal Multifactor.",
+ "U2F_SUCCESS":"U2F created successfully!",
+ "U2F_ERROR":"An error during U2F setup occurred!",
+ "U2F_NAME":"U2F Name",
+ "TYPE": {
+ "0": "No MFA defined",
+ "1": "OTP",
+ "2": "U2F"
+ },
+ "STATE": {
+ "0": "No State",
+ "1": "Not Ready",
+ "2": "Ready",
+ "3": "Deleted"
+ },
+ "DIALOG": {
+ "MFA_DELETE_TITLE":"Remove Secondfactor",
+ "MFA_DELETE_DESCRIPTION":"You are about to delete a second factor. Are you sure?"
}
},
"EXTERNALIDP": {
@@ -345,6 +382,8 @@
"PHONEVERIFICATIONSENT":"Phone verification code sent.",
"EMAILVERIFICATIONSENT":"E-mail verification code sent.",
"OTPREMOVED":"OTP removed.",
+ "U2FREMOVED":"U2F removed.",
+ "PASSWORDLESSREMOVED":"Passwordless removed.",
"INITIALPASSWORDSET":"Initial password set.",
"PASSWORDNOTIFICATIONSENT":"Password change notification sent.",
"PASSWORDCHANGED":"Password changed successfully.",
@@ -551,7 +590,9 @@
"ALLOWREGISTER":"Register allowed",
"ALLOWUSERNAMEPASSWORD_DESC":"The conventional login with user name and password is allowed.",
"ALLOWEXTERNALIDP_DESC":"The login is allowed for the underlying identity providers",
- "ALLOWREGISTER_DESC":"If the option is selected, an additional step for registering a user appears in the login."
+ "ALLOWREGISTER_DESC":"If the option is selected, an additional step for registering a user appears in the login.",
+ "FORCEMFA":"Force MFA",
+ "FORCEMFA_DESC":"If the option is selected, users have to configure a second factor for login."
},
"RESET":"Reset Policy",
"CREATECUSTOM":"Create Custom Policy",
@@ -826,6 +867,37 @@
"DELETED":"Idp removed successfully!"
}
},
+ "MFA":{
+ "LIST": {
+ "MULTIFACTORTITLE":"Multifactors",
+ "MULTIFACTORDESCRIPTION":"Define your Multifactors for Authentication here.",
+ "SECONDFACTORTITLE":"Secondfactors",
+ "SECONDFACTORDESCRIPTION":"Define your Secondfactors for Authentication here."
+ },
+ "CREATE": {
+ "TITLE":"New Factor",
+ "DESCRIPTION":"Select your new Factor type."
+ },
+ "DELETE": {
+ "TITLE":"Delete Factor",
+ "DESCRIPTION":"You are about to delete a Factor from Login Policy. Are you sure?"
+ },
+ "TOAST": {
+ "ADDED":"Added successfully.",
+ "SAVED": "Saved successfully.",
+ "DELETED":"Removed successfully"
+ },
+ "TYPE":"Type",
+ "MULTIFACTORTYPES": {
+ "0":"Unknown",
+ "1":"U2F with Pin"
+ },
+ "SECONDFACTORTYPES": {
+ "0":"Unknown",
+ "1":"OTP",
+ "2":"U2F"
+ }
+ },
"LOGINPOLICY": {
"CREATE": {
"TITLE":"Login Policy",
@@ -836,6 +908,11 @@
"TITLE":"Add Identity Provider",
"DESCRIPTION":"You can select predefined or selfcreated providers for authentication.",
"SELECTIDPS":"Identity providers"
+ },
+ "PASSWORDLESS":"Passwordless Login",
+ "PASSWORDLESSTYPE": {
+ "0":"Not allowed",
+ "1":"Allowed"
}
},
"APP": {
@@ -910,8 +987,11 @@
"OVERVIEWTITLE":"You are now done. Review your configuration.",
"ACCESSTOKENROLEASSERTION":"Add user roles to the access token",
"ACCESSTOKENROLEASSERTION_DESCRIPTION":"If selected, the roles of the authenticated user are added to the access token.",
- "IDTOKENROLEASSERTION":"Add user roles to the id token",
- "IDTOKENROLEASSERTION_DESCRIPTION":"If selected, the roles of the authenticated user are added to the id token."
+ "IDTOKENROLEASSERTION":"User roles inside ID Token",
+ "IDTOKENROLEASSERTION_DESCRIPTION":"If selected, the roles of the authenticated user are added to the ID token.",
+ "IDTOKENUSERINFOASSERTION":"User Info inside ID Token",
+ "IDTOKENUSERINFOASSERTION_DESCRIPTION":"Enables clients to retrieve profile, email, phone and address claims from ID token.",
+ "CLOCKSKEW":"Enables clients to handle clock skew of OP and client. The duration (0-5s) will be added to exp claim and subtracted from iats, auth_time and nbf."
},
"TOAST": {
"REACTIVATED":"Application reactivated.",
diff --git a/go.mod b/go.mod
index 88c19e2625..5e829050b7 100644
--- a/go.mod
+++ b/go.mod
@@ -15,8 +15,8 @@ require (
github.com/allegro/bigcache v1.2.1
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc
github.com/caos/logging v0.0.2
- github.com/caos/oidc v0.13.1
- github.com/cockroachdb/cockroach-go/v2 v2.0.8
+ github.com/caos/oidc v0.13.2
+ github.com/cockroachdb/cockroach-go/v2 v2.1.0
github.com/duo-labs/webauthn v0.0.0-20200714211715-1daaee874e43
github.com/envoyproxy/protoc-gen-validate v0.4.1
github.com/ghodss/yaml v1.0.0
@@ -40,9 +40,8 @@ require (
github.com/kevinburke/rest v0.0.0-20200429221318-0d2892b400f8 // indirect
github.com/kevinburke/twilio-go v0.0.0-20200810163702-320748330fac
github.com/kr/text v0.2.0 // indirect
- github.com/lib/pq v1.8.0
+ github.com/lib/pq v1.9.0
github.com/mattn/go-colorable v0.1.8 // indirect
- github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect
github.com/mitchellh/copystructure v1.0.0 // indirect
github.com/mitchellh/reflectwalk v1.0.1 // indirect
github.com/nicksnyder/go-i18n/v2 v2.1.1
@@ -69,7 +68,7 @@ require (
golang.org/x/tools v0.0.0-20201103235415-b653051172e4
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20201103154000-415bd0cd5df6
- google.golang.org/grpc v1.33.1
+ google.golang.org/grpc v1.34.0
google.golang.org/protobuf v1.25.0
gopkg.in/square/go-jose.v2 v2.5.1
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect
diff --git a/go.sum b/go.sum
index d47d213d09..cfe27d1e96 100644
--- a/go.sum
+++ b/go.sum
@@ -110,8 +110,8 @@ github.com/caos/logging v0.0.2 h1:ebg5C/HN0ludYR+WkvnFjwSExF4wvyiWPyWGcKMYsoo=
github.com/caos/logging v0.0.2 h1:ebg5C/HN0ludYR+WkvnFjwSExF4wvyiWPyWGcKMYsoo=
github.com/caos/logging v0.0.2/go.mod h1:9LKiDE2ChuGv6CHYif/kiugrfEXu9AwDiFWSreX7Wp0=
github.com/caos/logging v0.0.2/go.mod h1:9LKiDE2ChuGv6CHYif/kiugrfEXu9AwDiFWSreX7Wp0=
-github.com/caos/oidc v0.13.1 h1:8890xd3XJpev5xuU4Dn2l49c1lCA3Qd1xu4KsPSVo38=
-github.com/caos/oidc v0.13.1/go.mod h1:dLvfYUiAt9ORfl77L/KkcWuR/N0ll8Ry1nD2ERsamDY=
+github.com/caos/oidc v0.13.2 h1:52oP3KB1UrZuwraBTLuwM9ItRIhJQMYOm1J5uQ0sYXw=
+github.com/caos/oidc v0.13.2/go.mod h1:dLvfYUiAt9ORfl77L/KkcWuR/N0ll8Ry1nD2ERsamDY=
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk=
@@ -132,10 +132,11 @@ github.com/cloudflare/cfssl v0.0.0-20190726000631-633726f6bcb7 h1:Puu1hUwfps3+1C
github.com/cloudflare/cfssl v0.0.0-20190726000631-633726f6bcb7/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f h1:WBZRG4aNOuI15bLRrCgN8fCq8E5Xuty6jGbmSNEvSsU=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
-github.com/cockroachdb/cockroach-go/v2 v2.0.8 h1:50C/7ptrrfdxDccCjDU0xsdeBca+S0/AYW4Mo8RyzFE=
-github.com/cockroachdb/cockroach-go/v2 v2.0.8/go.mod h1:nkf7rUmgPdawp3EwRjXIumihI2AYg9usGNWbJ2hsJqI=
+github.com/cockroachdb/cockroach-go/v2 v2.1.0 h1:zicZlBhWZu6wfK7Ezg4Owdc3HamLpRdBllPTT9tb+2k=
+github.com/cockroachdb/cockroach-go/v2 v2.1.0/go.mod h1:ilhrLnPDDwGHL+iK2UxQhp1UzUhst8sfItSAgCYwAyg=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
@@ -169,6 +170,7 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4 h1:rEvIZUSZ3fx39WIi3JkQqQBitGwpELBIYWeBVh6wn+E=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/envoyproxy/protoc-gen-validate v0.4.1 h1:7dLaJvASGRD7X49jSCSXXHwKPm0ZN9r9kJD+p+vS7dM=
@@ -199,7 +201,6 @@ github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80n
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
-github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
@@ -378,8 +379,12 @@ github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgO
github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
+github.com/jackc/pgconn v1.4.0/go.mod h1:Y2O3ZDF0q4mMacyWV3AstPJpeHXWGEetiFttmq5lahk=
github.com/jackc/pgconn v1.5.0 h1:oFSOilzIZkyg787M1fEmyMfOUUvwj0daqYMfaWwNL4o=
github.com/jackc/pgconn v1.5.0/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI=
+github.com/jackc/pgconn v1.5.1-0.20200601181101-fa742c524853/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI=
+github.com/jackc/pgconn v1.7.0/go.mod h1:sF/lPpNEMEOp+IYhyQGdAvrG20gWf6A1tKlr0v7JMeA=
+github.com/jackc/pgconn v1.7.2/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2 h1:JVX6jT/XfzNqIjye4717ITLaNwV9mWbJx0dLCpcRzdA=
@@ -394,31 +399,41 @@ github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvW
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.1 h1:Rdjp4NFjwHnEslx2b66FfCI2S0LhO4itac3hXz6WX9M=
github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
+github.com/jackc/pgproto3/v2 v2.0.5/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
+github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8 h1:Q3tB+ExeflWUW7AFcAhXqk40s9mnNYLk1nOkKNZ5GnU=
github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
+github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
-github.com/jackc/pgtype v1.3.0 h1:l8JvKrby3RI7Kg3bYEeU9TA4vqC38QDpFCfcrC7KuN0=
-github.com/jackc/pgtype v1.3.0/go.mod h1:b0JqxHvPmljG+HQ5IsvQ0yqeSi4nGcDTVjFoiLDb0Ik=
-github.com/jackc/pgx v3.6.2+incompatible h1:2zP5OD7kiyR3xzRYMhOcXVvkDZsImVXfj+yIyTQf3/o=
-github.com/jackc/pgx v3.6.2+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
+github.com/jackc/pgtype v1.2.0/go.mod h1:5m2OfMh1wTK7x+Fk952IDmI4nw3nPrvtQdM0ZT4WpC0=
+github.com/jackc/pgtype v1.3.1-0.20200510190516-8cd94a14c75a/go.mod h1:vaogEUkALtxZMCH411K+tKzNpwzCKU+AnPzBKZ+I+Po=
+github.com/jackc/pgtype v1.3.1-0.20200606141011-f6355165a91c/go.mod h1:cvk9Bgu/VzJ9/lxTO5R5sf80p0DiucVtN7ZxvaC4GmQ=
+github.com/jackc/pgtype v1.5.0/go.mod h1:JCULISAZBFGrHaOXIIFiyfzW5VY0GRitRr8NeJsrdig=
+github.com/jackc/pgtype v1.6.1/go.mod h1:JCULISAZBFGrHaOXIIFiyfzW5VY0GRitRr8NeJsrdig=
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
-github.com/jackc/pgx/v4 v4.6.0 h1:Fh0O9GdlG4gYpjpwOqjdEodJUQM9jzN3Hdv7PN0xmm0=
-github.com/jackc/pgx/v4 v4.6.0/go.mod h1:vPh43ZzxijXUVJ+t/EmXBtFmbFVO72cuneCT9oAlxAg=
+github.com/jackc/pgx/v4 v4.5.0/go.mod h1:EpAKPLdnTorwmPUUsqrPxy5fphV18j9q3wrfRXgo+kA=
+github.com/jackc/pgx/v4 v4.6.1-0.20200510190926-94ba730bb1e9/go.mod h1:t3/cdRQl6fOLDxqtlyhe9UWgfIi9R8+8v8GKV5TRA/o=
+github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg=
+github.com/jackc/pgx/v4 v4.9.0/go.mod h1:MNGWmViCgqbZck9ujOOBN63gK9XVGILXWCvKLGKmnms=
+github.com/jackc/pgx/v4 v4.9.2/go.mod h1:Jt/xJDqjUDUOMSv8VMWPQlCObVgF2XOgqKsW8S4ROYA=
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.0 h1:musOWczZC/rSbqut475Vfcczg7jJsdUQf0D6oKPLgNU=
github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
-github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs=
+github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
+github.com/jackc/puddle v1.1.2/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o=
github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M=
github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
+github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E=
+github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA=
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
@@ -466,9 +481,10 @@ github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.4.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
-github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg=
-github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/lib/pq v1.9.0 h1:L8nSXQQzAYByakOFMTwpjRoHsMJklur4Gi59b6VivR8=
+github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
github.com/lyft/protoc-gen-star v0.5.1/go.mod h1:9toiA3cC7z5uVbODF7kEQ91Xn7XNFkVUl+SrEe+ZORU=
@@ -476,6 +492,7 @@ github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0Q
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
+github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
@@ -489,7 +506,6 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
-github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
@@ -611,6 +627,7 @@ github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
+github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shopspring/decimal v0.0.0-20200419222939-1884f454f8ea h1:jaXWVFZ98/ihXniiDzqNXQgMSgklX4kjfDWZTE3ZtdU=
github.com/shopspring/decimal v0.0.0-20200419222939-1884f454f8ea/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
@@ -699,9 +716,11 @@ go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
+go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM=
@@ -718,6 +737,7 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@@ -1076,6 +1096,8 @@ google.golang.org/grpc v1.32.0 h1:zWTV+LMdc3kaiJMSTOFz2UgSBgx8RNQoTGiZu3fR9S0=
google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.33.1 h1:DGeFlSan2f+WEtCERJ4J9GJWk15TxUi8QGagfI87Xyc=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
+google.golang.org/grpc v1.34.0 h1:raiipEjMOIC/TO2AvyTxP25XFdLxNIBwzDh3FM3XztI=
+google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -1123,6 +1145,9 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gorm.io/driver/postgres v1.0.5/go.mod h1:qrD92UurYzNctBMVCJ8C3VQEjffEuphycXtxOudXNCA=
+gorm.io/gorm v1.20.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
+gorm.io/gorm v1.20.6/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
diff --git a/internal/admin/repository/eventsourcing/eventstore/administrator.go b/internal/admin/repository/eventsourcing/eventstore/administrator.go
index 52ab002cac..b36717481e 100644
--- a/internal/admin/repository/eventsourcing/eventstore/administrator.go
+++ b/internal/admin/repository/eventsourcing/eventstore/administrator.go
@@ -2,10 +2,11 @@ package eventstore
import (
"context"
+ "time"
+
"github.com/caos/zitadel/internal/admin/repository/eventsourcing/view"
view_model "github.com/caos/zitadel/internal/view/model"
"github.com/caos/zitadel/internal/view/repository"
- "time"
)
var dbList = []string{"management", "auth", "authz", "adminapi", "notification"}
@@ -47,7 +48,7 @@ func (repo *AdministratorRepo) GetViews() ([]*view_model.View, error) {
}
func (repo *AdministratorRepo) GetSpoolerDiv(database, view string) int64 {
- sequence, err := repo.View.GetCurrentSequence(database, view)
+ sequence, err := repo.View.GetCurrentSequence(database, view, "")
if err != nil {
return 0
diff --git a/internal/admin/repository/eventsourcing/eventstore/iam.go b/internal/admin/repository/eventsourcing/eventstore/iam.go
index 1904998a13..a35046b606 100644
--- a/internal/admin/repository/eventsourcing/eventstore/iam.go
+++ b/internal/admin/repository/eventsourcing/eventstore/iam.go
@@ -69,7 +69,7 @@ func (repo *IAMRepository) RemoveIAMMember(ctx context.Context, userID string) e
func (repo *IAMRepository) SearchIAMMembers(ctx context.Context, request *iam_model.IAMMemberSearchRequest) (*iam_model.IAMMemberSearchResponse, error) {
request.EnsureLimit(repo.SearchLimit)
- sequence, err := repo.View.GetLatestIAMMemberSequence()
+ sequence, err := repo.View.GetLatestIAMMemberSequence("")
logging.Log("EVENT-Slkci").OnError(err).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Warn("could not read latest iam sequence")
members, count, err := repo.View.SearchIAMMembers(request)
if err != nil {
@@ -194,7 +194,7 @@ func (repo *IAMRepository) ChangeOidcIDPConfig(ctx context.Context, oidcConfig *
func (repo *IAMRepository) SearchIDPConfigs(ctx context.Context, request *iam_model.IDPConfigSearchRequest) (*iam_model.IDPConfigSearchResponse, error) {
request.EnsureLimit(repo.SearchLimit)
- sequence, err := repo.View.GetLatestIDPConfigSequence()
+ sequence, err := repo.View.GetLatestIDPConfigSequence("")
logging.Log("EVENT-Dk8si").OnError(err).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Warn("could not read latest idp config sequence")
idps, count, err := repo.View.SearchIDPConfigs(request)
if err != nil {
@@ -298,7 +298,7 @@ func (repo *IAMRepository) ChangeDefaultLoginPolicy(ctx context.Context, policy
func (repo *IAMRepository) SearchDefaultIDPProviders(ctx context.Context, request *iam_model.IDPProviderSearchRequest) (*iam_model.IDPProviderSearchResponse, error) {
request.EnsureLimit(repo.SearchLimit)
request.AppendAggregateIDQuery(repo.SystemDefaults.IamID)
- sequence, err := repo.View.GetLatestIDPProviderSequence()
+ sequence, err := repo.View.GetLatestIDPProviderSequence("")
logging.Log("EVENT-Tuiks").OnError(err).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Warn("could not read latest iam sequence")
providers, count, err := repo.View.SearchIDPProviders(request)
if err != nil {
diff --git a/internal/admin/repository/eventsourcing/eventstore/org.go b/internal/admin/repository/eventsourcing/eventstore/org.go
index 78400eae29..59718f45be 100644
--- a/internal/admin/repository/eventsourcing/eventstore/org.go
+++ b/internal/admin/repository/eventsourcing/eventstore/org.go
@@ -87,7 +87,7 @@ func (repo *OrgRepo) OrgByID(ctx context.Context, id string) (*org_model.Org, er
func (repo *OrgRepo) SearchOrgs(ctx context.Context, query *org_model.OrgSearchRequest) (*org_model.OrgSearchResult, error) {
query.EnsureLimit(repo.SearchLimit)
- sequence, err := repo.View.GetLatestOrgSequence()
+ sequence, err := repo.View.GetLatestOrgSequence("")
logging.Log("EVENT-LXo9w").OnError(err).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Warn("could not read latest iam sequence")
orgs, count, err := repo.View.SearchOrgs(query)
if err != nil {
diff --git a/internal/admin/repository/eventsourcing/handler/handler.go b/internal/admin/repository/eventsourcing/handler/handler.go
index 25f3b69223..ed0e60f6ed 100644
--- a/internal/admin/repository/eventsourcing/handler/handler.go
+++ b/internal/admin/repository/eventsourcing/handler/handler.go
@@ -3,13 +3,12 @@ package handler
import (
"time"
- "github.com/caos/zitadel/internal/config/systemdefaults"
- iam_event "github.com/caos/zitadel/internal/iam/repository/eventsourcing"
-
"github.com/caos/zitadel/internal/admin/repository/eventsourcing/view"
+ "github.com/caos/zitadel/internal/config/systemdefaults"
"github.com/caos/zitadel/internal/config/types"
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/query"
+ iam_event "github.com/caos/zitadel/internal/iam/repository/eventsourcing"
org_event "github.com/caos/zitadel/internal/org/repository/eventsourcing"
usr_event "github.com/caos/zitadel/internal/user/repository/eventsourcing"
)
@@ -25,6 +24,12 @@ type handler struct {
bulkLimit uint64
cycleDuration time.Duration
errorCountUntilSkip uint64
+
+ es eventstore.Eventstore
+}
+
+func (h *handler) Eventstore() eventstore.Eventstore {
+ return h.es
}
type EventstoreRepos struct {
@@ -33,31 +38,49 @@ type EventstoreRepos struct {
OrgEvents *org_event.OrgEventstore
}
-func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, eventstore eventstore.Eventstore, repos EventstoreRepos, defaults systemdefaults.SystemDefaults) []query.Handler {
+func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es eventstore.Eventstore, repos EventstoreRepos, defaults systemdefaults.SystemDefaults) []query.Handler {
return []query.Handler{
- &Org{handler: handler{view, bulkLimit, configs.cycleDuration("Org"), errorCount}},
- &IamMember{handler: handler{view, bulkLimit, configs.cycleDuration("IamMember"), errorCount},
- userEvents: repos.UserEvents},
- &IDPConfig{handler: handler{view, bulkLimit, configs.cycleDuration("IDPConfig"), errorCount}},
- &LabelPolicy{handler: handler{view, bulkLimit, configs.cycleDuration("LabelPolicy"), errorCount}},
- &LoginPolicy{handler: handler{view, bulkLimit, configs.cycleDuration("LoginPolicy"), errorCount}},
- &IDPProvider{handler: handler{view, bulkLimit, configs.cycleDuration("IDPProvider"), errorCount},
- systemDefaults: defaults, iamEvents: repos.IamEvents, orgEvents: repos.OrgEvents},
- &User{handler: handler{view, bulkLimit, configs.cycleDuration("User"), errorCount},
- eventstore: eventstore, orgEvents: repos.OrgEvents, iamEvents: repos.IamEvents, systemDefaults: defaults},
- &PasswordComplexityPolicy{handler: handler{view, bulkLimit, configs.cycleDuration("PasswordComplexityPolicy"), errorCount}},
- &PasswordAgePolicy{handler: handler{view, bulkLimit, configs.cycleDuration("PasswordAgePolicy"), errorCount}},
- &PasswordLockoutPolicy{handler: handler{view, bulkLimit, configs.cycleDuration("PasswordLockoutPolicy"), errorCount}},
- &OrgIAMPolicy{handler: handler{view, bulkLimit, configs.cycleDuration("OrgIAMPolicy"), errorCount}},
- &ExternalIDP{handler: handler{view, bulkLimit, configs.cycleDuration("ExternalIDP"), errorCount},
- orgEvents: repos.OrgEvents, iamEvents: repos.IamEvents, systemDefaults: defaults},
+ newOrg(
+ handler{view, bulkLimit, configs.cycleDuration("Org"), errorCount, es}),
+ newIAMMember(
+ handler{view, bulkLimit, configs.cycleDuration("IamMember"), errorCount, es},
+ repos.UserEvents),
+ newIDPConfig(
+ handler{view, bulkLimit, configs.cycleDuration("IDPConfig"), errorCount, es}),
+ newLabelPolicy(
+ handler{view, bulkLimit, configs.cycleDuration("LabelPolicy"), errorCount, es}),
+ newLoginPolicy(
+ handler{view, bulkLimit, configs.cycleDuration("LoginPolicy"), errorCount, es}),
+ newIDPProvider(
+ handler{view, bulkLimit, configs.cycleDuration("IDPProvider"), errorCount, es},
+ defaults,
+ repos.IamEvents,
+ repos.OrgEvents),
+ newUser(
+ handler{view, bulkLimit, configs.cycleDuration("User"), errorCount, es},
+ repos.OrgEvents,
+ repos.IamEvents,
+ defaults),
+ newPasswordComplexityPolicy(
+ handler{view, bulkLimit, configs.cycleDuration("PasswordComplexityPolicy"), errorCount, es}),
+ newPasswordAgePolicy(
+ handler{view, bulkLimit, configs.cycleDuration("PasswordAgePolicy"), errorCount, es}),
+ newPasswordLockoutPolicy(
+ handler{view, bulkLimit, configs.cycleDuration("PasswordLockoutPolicy"), errorCount, es}),
+ newOrgIAMPolicy(
+ handler{view, bulkLimit, configs.cycleDuration("OrgIAMPolicy"), errorCount, es}),
+ newExternalIDP(
+ handler{view, bulkLimit, configs.cycleDuration("ExternalIDP"), errorCount, es},
+ defaults,
+ repos.IamEvents,
+ repos.OrgEvents),
}
}
func (configs Configs) cycleDuration(viewModel string) time.Duration {
c, ok := configs[viewModel]
if !ok {
- return 1 * time.Second
+ return 3 * time.Minute
}
return c.MinimumCycleDuration.Duration
}
@@ -66,6 +89,10 @@ func (h *handler) MinimumCycleDuration() time.Duration {
return h.cycleDuration
}
+func (h *handler) LockDuration() time.Duration {
+ return h.cycleDuration / 3
+}
+
func (h *handler) QueryLimit() uint64 {
return h.bulkLimit
}
diff --git a/internal/admin/repository/eventsourcing/handler/iam_member.go b/internal/admin/repository/eventsourcing/handler/iam_member.go
index d3c9b77bb6..79aafcf055 100644
--- a/internal/admin/repository/eventsourcing/handler/iam_member.go
+++ b/internal/admin/repository/eventsourcing/handler/iam_member.go
@@ -4,9 +4,9 @@ import (
"context"
"github.com/caos/logging"
-
- "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
"github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
iam_model "github.com/caos/zitadel/internal/iam/repository/view/model"
@@ -15,40 +15,73 @@ import (
usr_es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
)
-type IamMember struct {
- handler
- userEvents *usr_event.UserEventstore
-}
-
const (
iamMemberTable = "adminapi.iam_members"
)
-func (m *IamMember) ViewModel() string {
+type IAMMember struct {
+ handler
+ userEvents *usr_event.UserEventstore
+ subscription *eventstore.Subscription
+}
+
+func newIAMMember(handler handler, userEvents *usr_event.UserEventstore) *IAMMember {
+ iamMember := &IAMMember{
+ handler: handler,
+ userEvents: userEvents,
+ }
+
+ iamMember.subscribe()
+
+ return iamMember
+}
+
+func (m *IAMMember) subscribe() {
+ m.subscription = m.es.Subscribe(m.AggregateTypes()...)
+ go func() {
+ for event := range m.subscription.Events {
+ query.ReduceEvent(m, event)
+ }
+ }()
+}
+
+func (m *IAMMember) CurrentSequence(event *es_models.Event) (uint64, error) {
+ sequence, err := m.view.GetLatestIAMMemberSequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
+func (m *IAMMember) ViewModel() string {
return iamMemberTable
}
-func (m *IamMember) EventQuery() (*models.SearchQuery, error) {
- sequence, err := m.view.GetLatestIAMMemberSequence()
+func (m *IAMMember) AggregateTypes() []es_models.AggregateType {
+ return []es_models.AggregateType{model.IAMAggregate, usr_es_model.UserAggregate}
+}
+
+func (m *IAMMember) EventQuery() (*es_models.SearchQuery, error) {
+ sequence, err := m.view.GetLatestIAMMemberSequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(model.IAMAggregate, usr_es_model.UserAggregate).
+ AggregateTypeFilter(m.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
-func (m *IamMember) Reduce(event *models.Event) (err error) {
+func (m *IAMMember) Reduce(event *es_models.Event) (err error) {
switch event.AggregateType {
case model.IAMAggregate:
- err = m.processIamMember(event)
+ err = m.processIAMMember(event)
case usr_es_model.UserAggregate:
err = m.processUser(event)
}
return err
}
-func (m *IamMember) processIamMember(event *models.Event) (err error) {
+func (m *IAMMember) processIAMMember(event *es_models.Event) (err error) {
member := new(iam_model.IAMMemberView)
switch event.Type {
case model.IAMMemberAdded:
@@ -72,17 +105,17 @@ func (m *IamMember) processIamMember(event *models.Event) (err error) {
if err != nil {
return err
}
- return m.view.DeleteIAMMember(event.AggregateID, member.UserID, event.Sequence, event.CreationDate)
+ return m.view.DeleteIAMMember(event.AggregateID, member.UserID, event)
default:
- return m.view.ProcessedIAMMemberSequence(event.Sequence, event.CreationDate)
+ return m.view.ProcessedIAMMemberSequence(event)
}
if err != nil {
return err
}
- return m.view.PutIAMMember(member, member.Sequence, event.CreationDate)
+ return m.view.PutIAMMember(member, event)
}
-func (m *IamMember) processUser(event *models.Event) (err error) {
+func (m *IAMMember) processUser(event *es_models.Event) (err error) {
switch event.Type {
case usr_es_model.UserProfileChanged,
usr_es_model.UserEmailChanged,
@@ -94,7 +127,7 @@ func (m *IamMember) processUser(event *models.Event) (err error) {
return err
}
if len(members) == 0 {
- return m.view.ProcessedIAMMemberSequence(event.Sequence, event.CreationDate)
+ return m.view.ProcessedIAMMemberSequence(event)
}
user, err := m.userEvents.UserByID(context.Background(), event.AggregateID)
if err != nil {
@@ -103,16 +136,15 @@ func (m *IamMember) processUser(event *models.Event) (err error) {
for _, member := range members {
m.fillUserData(member, user)
}
- return m.view.PutIAMMembers(members, event.Sequence, event.CreationDate)
+ return m.view.PutIAMMembers(members, event)
case usr_es_model.UserRemoved:
- return m.view.DeleteIAMMembersByUserID(event.AggregateID, event.Sequence, event.CreationDate)
+ return m.view.DeleteIAMMembersByUserID(event.AggregateID, event)
default:
- return m.view.ProcessedIAMMemberSequence(event.Sequence, event.CreationDate)
+ return m.view.ProcessedIAMMemberSequence(event)
}
- return nil
}
-func (m *IamMember) fillData(member *iam_model.IAMMemberView) (err error) {
+func (m *IAMMember) fillData(member *iam_model.IAMMemberView) (err error) {
user, err := m.userEvents.UserByID(context.Background(), member.UserID)
if err != nil {
return err
@@ -121,7 +153,7 @@ func (m *IamMember) fillData(member *iam_model.IAMMemberView) (err error) {
return nil
}
-func (m *IamMember) fillUserData(member *iam_model.IAMMemberView, user *usr_model.User) {
+func (m *IAMMember) fillUserData(member *iam_model.IAMMemberView, user *usr_model.User) {
member.UserName = user.UserName
if user.Human != nil {
member.FirstName = user.FirstName
@@ -133,11 +165,11 @@ func (m *IamMember) fillUserData(member *iam_model.IAMMemberView, user *usr_mode
member.DisplayName = user.Machine.Name
}
}
-func (m *IamMember) OnError(event *models.Event, err error) error {
+func (m *IAMMember) OnError(event *es_models.Event, err error) error {
logging.LogWithFields("SPOOL-Ld9ow", "id", event.AggregateID).WithError(err).Warn("something went wrong in iammember handler")
return spooler.HandleError(event, err, m.view.GetLatestIAMMemberFailedEvent, m.view.ProcessedIAMMemberFailedEvent, m.view.ProcessedIAMMemberSequence, m.errorCountUntilSkip)
}
-func (m *IamMember) OnSuccess() error {
+func (m *IAMMember) OnSuccess() error {
return spooler.HandleSuccess(m.view.UpdateIAMMemberSpoolerRunTimestamp)
}
diff --git a/internal/admin/repository/eventsourcing/handler/idp_config.go b/internal/admin/repository/eventsourcing/handler/idp_config.go
index be8d43d7dc..bf0dc97104 100644
--- a/internal/admin/repository/eventsourcing/handler/idp_config.go
+++ b/internal/admin/repository/eventsourcing/handler/idp_config.go
@@ -2,38 +2,70 @@ package handler
import (
"github.com/caos/logging"
- iam_model "github.com/caos/zitadel/internal/iam/model"
-
- "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
+ iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
iam_view_model "github.com/caos/zitadel/internal/iam/repository/view/model"
)
-type IDPConfig struct {
- handler
-}
-
const (
idpConfigTable = "adminapi.idp_configs"
)
+type IDPConfig struct {
+ handler
+ subscription *eventstore.Subscription
+}
+
+func newIDPConfig(handler handler) *IDPConfig {
+ h := &IDPConfig{
+ handler: handler,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (i *IDPConfig) subscribe() {
+ i.subscription = i.es.Subscribe(i.AggregateTypes()...)
+ go func() {
+ for event := range i.subscription.Events {
+ query.ReduceEvent(i, event)
+ }
+ }()
+}
+
func (i *IDPConfig) ViewModel() string {
return idpConfigTable
}
-func (i *IDPConfig) EventQuery() (*models.SearchQuery, error) {
- sequence, err := i.view.GetLatestIDPConfigSequence()
+func (i *IDPConfig) AggregateTypes() []es_models.AggregateType {
+ return []es_models.AggregateType{model.IAMAggregate}
+}
+
+func (i *IDPConfig) CurrentSequence(event *es_models.Event) (uint64, error) {
+ sequence, err := i.view.GetLatestIDPConfigSequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
+func (i *IDPConfig) EventQuery() (*es_models.SearchQuery, error) {
+ sequence, err := i.view.GetLatestIDPConfigSequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(model.IAMAggregate).
+ AggregateTypeFilter(i.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
-func (i *IDPConfig) Reduce(event *models.Event) (err error) {
+func (i *IDPConfig) Reduce(event *es_models.Event) (err error) {
switch event.AggregateType {
case model.IAMAggregate:
err = i.processIDPConfig(event)
@@ -41,7 +73,7 @@ func (i *IDPConfig) Reduce(event *models.Event) (err error) {
return err
}
-func (i *IDPConfig) processIDPConfig(event *models.Event) (err error) {
+func (i *IDPConfig) processIDPConfig(event *es_models.Event) (err error) {
idp := new(iam_view_model.IDPConfigView)
switch event.Type {
case model.IDPConfigAdded:
@@ -63,17 +95,17 @@ func (i *IDPConfig) processIDPConfig(event *models.Event) (err error) {
if err != nil {
return err
}
- return i.view.DeleteIDPConfig(idp.IDPConfigID, event.Sequence, event.CreationDate)
+ return i.view.DeleteIDPConfig(idp.IDPConfigID, event)
default:
- return i.view.ProcessedIDPConfigSequence(event.Sequence, event.CreationDate)
+ return i.view.ProcessedIDPConfigSequence(event)
}
if err != nil {
return err
}
- return i.view.PutIDPConfig(idp, idp.Sequence, event.CreationDate)
+ return i.view.PutIDPConfig(idp, event)
}
-func (i *IDPConfig) OnError(event *models.Event, err error) error {
+func (i *IDPConfig) OnError(event *es_models.Event, err error) error {
logging.LogWithFields("SPOOL-Mslo9", "id", event.AggregateID).WithError(err).Warn("something went wrong in idp config handler")
return spooler.HandleError(event, err, i.view.GetLatestIDPConfigFailedEvent, i.view.ProcessedIDPConfigFailedEvent, i.view.ProcessedIDPConfigSequence, i.errorCountUntilSkip)
}
diff --git a/internal/admin/repository/eventsourcing/handler/idp_providers.go b/internal/admin/repository/eventsourcing/handler/idp_providers.go
index 0e27ee11ec..06c44c4c0a 100644
--- a/internal/admin/repository/eventsourcing/handler/idp_providers.go
+++ b/internal/admin/repository/eventsourcing/handler/idp_providers.go
@@ -2,18 +2,23 @@ package handler
import (
"context"
+
"github.com/caos/logging"
"github.com/caos/zitadel/internal/config/systemdefaults"
- "github.com/caos/zitadel/internal/iam/repository/eventsourcing"
- org_events "github.com/caos/zitadel/internal/org/repository/eventsourcing"
- org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
-
- "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
iam_model "github.com/caos/zitadel/internal/iam/model"
+ "github.com/caos/zitadel/internal/iam/repository/eventsourcing"
"github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
iam_view_model "github.com/caos/zitadel/internal/iam/repository/view/model"
+ org_events "github.com/caos/zitadel/internal/org/repository/eventsourcing"
+ org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
+)
+
+const (
+ idpProviderTable = "adminapi.idp_providers"
)
type IDPProvider struct {
@@ -21,27 +26,63 @@ type IDPProvider struct {
systemDefaults systemdefaults.SystemDefaults
iamEvents *eventsourcing.IAMEventstore
orgEvents *org_events.OrgEventstore
+ subscription *eventstore.Subscription
}
-const (
- idpProviderTable = "adminapi.idp_providers"
-)
+func newIDPProvider(
+ handler handler,
+ systemDefaults systemdefaults.SystemDefaults,
+ iamEvents *eventsourcing.IAMEventstore,
+ orgEvents *org_events.OrgEventstore,
+) *IDPProvider {
+ h := &IDPProvider{
+ handler: handler,
+ systemDefaults: systemDefaults,
+ iamEvents: iamEvents,
+ orgEvents: orgEvents,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (i *IDPProvider) subscribe() {
+ i.subscription = i.es.Subscribe(i.AggregateTypes()...)
+ go func() {
+ for event := range i.subscription.Events {
+ query.ReduceEvent(i, event)
+ }
+ }()
+}
func (i *IDPProvider) ViewModel() string {
return idpProviderTable
}
-func (i *IDPProvider) EventQuery() (*models.SearchQuery, error) {
- sequence, err := i.view.GetLatestIDPProviderSequence()
+func (i *IDPProvider) AggregateTypes() []es_models.AggregateType {
+ return []es_models.AggregateType{model.IAMAggregate, org_es_model.OrgAggregate}
+}
+
+func (i *IDPProvider) CurrentSequence(event *es_models.Event) (uint64, error) {
+ sequence, err := i.view.GetLatestIDPProviderSequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
+func (i *IDPProvider) EventQuery() (*es_models.SearchQuery, error) {
+ sequence, err := i.view.GetLatestIDPProviderSequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(model.IAMAggregate, org_es_model.OrgAggregate).
+ AggregateTypeFilter(i.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
-func (i *IDPProvider) Reduce(event *models.Event) (err error) {
+func (i *IDPProvider) Reduce(event *es_models.Event) (err error) {
switch event.AggregateType {
case model.IAMAggregate, org_es_model.OrgAggregate:
err = i.processIdpProvider(event)
@@ -49,7 +90,7 @@ func (i *IDPProvider) Reduce(event *models.Event) (err error) {
return err
}
-func (i *IDPProvider) processIdpProvider(event *models.Event) (err error) {
+func (i *IDPProvider) processIdpProvider(event *es_models.Event) (err error) {
provider := new(iam_view_model.IDPProviderView)
switch event.Type {
case model.LoginPolicyIDPProviderAdded, org_es_model.LoginPolicyIDPProviderAdded:
@@ -64,7 +105,7 @@ func (i *IDPProvider) processIdpProvider(event *models.Event) (err error) {
if err != nil {
return err
}
- return i.view.DeleteIDPProvider(event.AggregateID, provider.IDPConfigID, event.Sequence, event.CreationDate)
+ return i.view.DeleteIDPProvider(event.AggregateID, provider.IDPConfigID, event)
case model.IDPConfigChanged, org_es_model.IDPConfigChanged:
esConfig := new(iam_view_model.IDPConfigView)
providerType := iam_model.IDPProviderTypeSystem
@@ -83,14 +124,14 @@ func (i *IDPProvider) processIdpProvider(event *models.Event) (err error) {
for _, provider := range providers {
i.fillConfigData(provider, config)
}
- return i.view.PutIDPProviders(event.Sequence, event.CreationDate, providers...)
+ return i.view.PutIDPProviders(event, providers...)
default:
- return i.view.ProcessedIDPProviderSequence(event.Sequence, event.CreationDate)
+ return i.view.ProcessedIDPProviderSequence(event)
}
if err != nil {
return err
}
- return i.view.PutIDPProvider(provider, provider.Sequence, event.CreationDate)
+ return i.view.PutIDPProvider(provider, event)
}
func (i *IDPProvider) fillData(provider *iam_view_model.IDPProviderView) (err error) {
@@ -114,7 +155,7 @@ func (i *IDPProvider) fillConfigData(provider *iam_view_model.IDPProviderView, c
provider.IDPState = int32(config.State)
}
-func (i *IDPProvider) OnError(event *models.Event, err error) error {
+func (i *IDPProvider) OnError(event *es_models.Event, err error) error {
logging.LogWithFields("SPOOL-Msj8c", "id", event.AggregateID).WithError(err).Warn("something went wrong in idp provider handler")
return spooler.HandleError(event, err, i.view.GetLatestIDPProviderFailedEvent, i.view.ProcessedIDPProviderFailedEvent, i.view.ProcessedIDPProviderSequence, i.errorCountUntilSkip)
}
diff --git a/internal/admin/repository/eventsourcing/handler/label_policy.go b/internal/admin/repository/eventsourcing/handler/label_policy.go
index 3f81c0060d..c1604fba69 100644
--- a/internal/admin/repository/eventsourcing/handler/label_policy.go
+++ b/internal/admin/repository/eventsourcing/handler/label_policy.go
@@ -2,37 +2,69 @@ package handler
import (
"github.com/caos/logging"
-
- "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
"github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
iam_model "github.com/caos/zitadel/internal/iam/repository/view/model"
)
-type LabelPolicy struct {
- handler
-}
-
const (
labelPolicyTable = "adminapi.label_policies"
)
+type LabelPolicy struct {
+ handler
+ subscription *eventstore.Subscription
+}
+
+func newLabelPolicy(handler handler) *LabelPolicy {
+ h := &LabelPolicy{
+ handler: handler,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (p *LabelPolicy) subscribe() {
+ p.subscription = p.es.Subscribe(p.AggregateTypes()...)
+ go func() {
+ for event := range p.subscription.Events {
+ query.ReduceEvent(p, event)
+ }
+ }()
+}
+
func (p *LabelPolicy) ViewModel() string {
return labelPolicyTable
}
-func (p *LabelPolicy) EventQuery() (*models.SearchQuery, error) {
- sequence, err := p.view.GetLatestLabelPolicySequence()
+func (p *LabelPolicy) AggregateTypes() []es_models.AggregateType {
+ return []es_models.AggregateType{model.IAMAggregate}
+}
+
+func (p *LabelPolicy) EventQuery() (*es_models.SearchQuery, error) {
+ sequence, err := p.view.GetLatestLabelPolicySequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(model.IAMAggregate).
+ AggregateTypeFilter(p.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
-func (p *LabelPolicy) Reduce(event *models.Event) (err error) {
+func (p *LabelPolicy) CurrentSequence(event *es_models.Event) (uint64, error) {
+ sequence, err := p.view.GetLatestLabelPolicySequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
+func (p *LabelPolicy) Reduce(event *es_models.Event) (err error) {
switch event.AggregateType {
case model.IAMAggregate:
err = p.processLabelPolicy(event)
@@ -40,7 +72,7 @@ func (p *LabelPolicy) Reduce(event *models.Event) (err error) {
return err
}
-func (p *LabelPolicy) processLabelPolicy(event *models.Event) (err error) {
+func (p *LabelPolicy) processLabelPolicy(event *es_models.Event) (err error) {
policy := new(iam_model.LabelPolicyView)
switch event.Type {
case model.LabelPolicyAdded:
@@ -52,15 +84,15 @@ func (p *LabelPolicy) processLabelPolicy(event *models.Event) (err error) {
}
err = policy.AppendEvent(event)
default:
- return p.view.ProcessedLabelPolicySequence(event.Sequence, event.CreationDate)
+ return p.view.ProcessedLabelPolicySequence(event)
}
if err != nil {
return err
}
- return p.view.PutLabelPolicy(policy, policy.Sequence, event.CreationDate)
+ return p.view.PutLabelPolicy(policy, event)
}
-func (p *LabelPolicy) OnError(event *models.Event, err error) error {
+func (p *LabelPolicy) OnError(event *es_models.Event, err error) error {
logging.LogWithFields("SPOOL-Wj8sf", "id", event.AggregateID).WithError(err).Warn("something went wrong in label policy handler")
return spooler.HandleError(event, err, p.view.GetLatestLabelPolicyFailedEvent, p.view.ProcessedLabelPolicyFailedEvent, p.view.ProcessedLabelPolicySequence, p.errorCountUntilSkip)
}
diff --git a/internal/admin/repository/eventsourcing/handler/login_policy.go b/internal/admin/repository/eventsourcing/handler/login_policy.go
index c24100ca69..032f2a4349 100644
--- a/internal/admin/repository/eventsourcing/handler/login_policy.go
+++ b/internal/admin/repository/eventsourcing/handler/login_policy.go
@@ -2,36 +2,69 @@ package handler
import (
"github.com/caos/logging"
-
+ "github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
"github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
iam_model "github.com/caos/zitadel/internal/iam/repository/view/model"
)
-type LoginPolicy struct {
- handler
-}
-
const (
loginPolicyTable = "adminapi.login_policies"
)
+type LoginPolicy struct {
+ handler
+ subscription *eventstore.Subscription
+}
+
+func newLoginPolicy(handler handler) *LoginPolicy {
+ h := &LoginPolicy{
+ handler: handler,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (p *LoginPolicy) subscribe() {
+ p.subscription = p.es.Subscribe(p.AggregateTypes()...)
+ go func() {
+ for event := range p.subscription.Events {
+ query.ReduceEvent(p, event)
+ }
+ }()
+}
+
func (p *LoginPolicy) ViewModel() string {
return loginPolicyTable
}
+func (p *LoginPolicy) AggregateTypes() []models.AggregateType {
+ return []models.AggregateType{model.IAMAggregate}
+}
+
func (p *LoginPolicy) EventQuery() (*models.SearchQuery, error) {
- sequence, err := p.view.GetLatestLoginPolicySequence()
+ sequence, err := p.view.GetLatestLoginPolicySequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(model.IAMAggregate).
+ AggregateTypeFilter(p.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
+func (p *LoginPolicy) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := p.view.GetLatestLoginPolicySequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (p *LoginPolicy) Reduce(event *models.Event) (err error) {
switch event.AggregateType {
case model.IAMAggregate:
@@ -56,12 +89,12 @@ func (p *LoginPolicy) processLoginPolicy(event *models.Event) (err error) {
}
err = policy.AppendEvent(event)
default:
- return p.view.ProcessedLoginPolicySequence(event.Sequence, event.CreationDate)
+ return p.view.ProcessedLoginPolicySequence(event)
}
if err != nil {
return err
}
- return p.view.PutLoginPolicy(policy, policy.Sequence, event.CreationDate)
+ return p.view.PutLoginPolicy(policy, event)
}
func (p *LoginPolicy) OnError(event *models.Event, err error) error {
diff --git a/internal/admin/repository/eventsourcing/handler/org.go b/internal/admin/repository/eventsourcing/handler/org.go
index eb64e60ea7..02ace32943 100644
--- a/internal/admin/repository/eventsourcing/handler/org.go
+++ b/internal/admin/repository/eventsourcing/handler/org.go
@@ -3,33 +3,67 @@ package handler
import (
"github.com/caos/logging"
+ "github.com/caos/zitadel/internal/eventstore"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
"github.com/caos/zitadel/internal/org/repository/eventsourcing"
"github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
org_model "github.com/caos/zitadel/internal/org/repository/view/model"
)
-type Org struct {
- handler
-}
-
const (
orgTable = "adminapi.orgs"
)
+type Org struct {
+ handler
+ subscription *eventstore.Subscription
+}
+
+func newOrg(handler handler) *Org {
+ h := &Org{
+ handler: handler,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (o *Org) subscribe() {
+ o.subscription = o.es.Subscribe(o.AggregateTypes()...)
+ go func() {
+ for event := range o.subscription.Events {
+ query.ReduceEvent(o, event)
+ }
+ }()
+}
+
func (o *Org) ViewModel() string {
return orgTable
}
+func (o *Org) AggregateTypes() []es_models.AggregateType {
+ return []es_models.AggregateType{model.OrgAggregate}
+}
+
func (o *Org) EventQuery() (*es_models.SearchQuery, error) {
- sequence, err := o.view.GetLatestOrgSequence()
+ sequence, err := o.view.GetLatestOrgSequence("")
if err != nil {
return nil, err
}
return eventsourcing.OrgQuery(sequence.CurrentSequence), nil
}
+func (o *Org) CurrentSequence(event *es_models.Event) (uint64, error) {
+ sequence, err := o.view.GetLatestOrgSequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (o *Org) Reduce(event *es_models.Event) error {
org := new(org_model.OrgView)
@@ -53,10 +87,10 @@ func (o *Org) Reduce(event *es_models.Event) error {
return err
}
default:
- return o.view.ProcessedOrgSequence(event.Sequence, event.CreationDate)
+ return o.view.ProcessedOrgSequence(event)
}
- return o.view.PutOrg(org, event.CreationDate)
+ return o.view.PutOrg(org, event)
}
func (o *Org) OnError(event *es_models.Event, spoolerErr error) error {
diff --git a/internal/admin/repository/eventsourcing/handler/org_iam_policy.go b/internal/admin/repository/eventsourcing/handler/org_iam_policy.go
index 99c01e73e1..a98db79c09 100644
--- a/internal/admin/repository/eventsourcing/handler/org_iam_policy.go
+++ b/internal/admin/repository/eventsourcing/handler/org_iam_policy.go
@@ -2,38 +2,70 @@ package handler
import (
"github.com/caos/logging"
- iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
-
- "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
+ iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
iam_model "github.com/caos/zitadel/internal/iam/repository/view/model"
"github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
)
-type OrgIAMPolicy struct {
- handler
-}
-
const (
orgIAMPolicyTable = "adminapi.org_iam_policies"
)
+type OrgIAMPolicy struct {
+ handler
+ subscription *eventstore.Subscription
+}
+
+func newOrgIAMPolicy(handler handler) *OrgIAMPolicy {
+ h := &OrgIAMPolicy{
+ handler: handler,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (p *OrgIAMPolicy) subscribe() {
+ p.subscription = p.es.Subscribe(p.AggregateTypes()...)
+ go func() {
+ for event := range p.subscription.Events {
+ query.ReduceEvent(p, event)
+ }
+ }()
+}
+
func (p *OrgIAMPolicy) ViewModel() string {
return orgIAMPolicyTable
}
-func (p *OrgIAMPolicy) EventQuery() (*models.SearchQuery, error) {
- sequence, err := p.view.GetLatestOrgIAMPolicySequence()
+func (p *OrgIAMPolicy) AggregateTypes() []es_models.AggregateType {
+ return []es_models.AggregateType{model.OrgAggregate, iam_es_model.IAMAggregate}
+}
+
+func (p *OrgIAMPolicy) EventQuery() (*es_models.SearchQuery, error) {
+ sequence, err := p.view.GetLatestOrgIAMPolicySequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(model.OrgAggregate, iam_es_model.IAMAggregate).
+ AggregateTypeFilter(p.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
-func (p *OrgIAMPolicy) Reduce(event *models.Event) (err error) {
+func (p *OrgIAMPolicy) CurrentSequence(event *es_models.Event) (uint64, error) {
+ sequence, err := p.view.GetLatestOrgIAMPolicySequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
+func (p *OrgIAMPolicy) Reduce(event *es_models.Event) (err error) {
switch event.AggregateType {
case model.OrgAggregate, iam_es_model.IAMAggregate:
err = p.processOrgIAMPolicy(event)
@@ -41,7 +73,7 @@ func (p *OrgIAMPolicy) Reduce(event *models.Event) (err error) {
return err
}
-func (p *OrgIAMPolicy) processOrgIAMPolicy(event *models.Event) (err error) {
+func (p *OrgIAMPolicy) processOrgIAMPolicy(event *es_models.Event) (err error) {
policy := new(iam_model.OrgIAMPolicyView)
switch event.Type {
case iam_es_model.OrgIAMPolicyAdded, model.OrgIAMPolicyAdded:
@@ -53,17 +85,17 @@ func (p *OrgIAMPolicy) processOrgIAMPolicy(event *models.Event) (err error) {
}
err = policy.AppendEvent(event)
case model.OrgIAMPolicyRemoved:
- return p.view.DeleteOrgIAMPolicy(event.AggregateID, event.Sequence, event.CreationDate)
+ return p.view.DeleteOrgIAMPolicy(event.AggregateID, event)
default:
- return p.view.ProcessedOrgIAMPolicySequence(event.Sequence, event.CreationDate)
+ return p.view.ProcessedOrgIAMPolicySequence(event)
}
if err != nil {
return err
}
- return p.view.PutOrgIAMPolicy(policy, policy.Sequence, event.CreationDate)
+ return p.view.PutOrgIAMPolicy(policy, event)
}
-func (p *OrgIAMPolicy) OnError(event *models.Event, err error) error {
+func (p *OrgIAMPolicy) OnError(event *es_models.Event, err error) error {
logging.LogWithFields("SPOOL-Wm8fs", "id", event.AggregateID).WithError(err).Warn("something went wrong in orgIAM policy handler")
return spooler.HandleError(event, err, p.view.GetLatestOrgIAMPolicyFailedEvent, p.view.ProcessedOrgIAMPolicyFailedEvent, p.view.ProcessedOrgIAMPolicySequence, p.errorCountUntilSkip)
}
diff --git a/internal/admin/repository/eventsourcing/handler/password_age_policy.go b/internal/admin/repository/eventsourcing/handler/password_age_policy.go
index 3608ec446e..7cfa1b2bb2 100644
--- a/internal/admin/repository/eventsourcing/handler/password_age_policy.go
+++ b/internal/admin/repository/eventsourcing/handler/password_age_policy.go
@@ -2,34 +2,68 @@ package handler
import (
"github.com/caos/logging"
+ "github.com/caos/zitadel/internal/eventstore"
iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
iam_model "github.com/caos/zitadel/internal/iam/repository/view/model"
"github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
)
-type PasswordAgePolicy struct {
- handler
-}
-
const (
passwordAgePolicyTable = "adminapi.password_age_policies"
)
+type PasswordAgePolicy struct {
+ handler
+ subscription *eventstore.Subscription
+}
+
+func newPasswordAgePolicy(handler handler) *PasswordAgePolicy {
+ h := &PasswordAgePolicy{
+ handler: handler,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (p *PasswordAgePolicy) subscribe() {
+ p.subscription = p.es.Subscribe(p.AggregateTypes()...)
+ go func() {
+ for event := range p.subscription.Events {
+ query.ReduceEvent(p, event)
+ }
+ }()
+}
+
func (p *PasswordAgePolicy) ViewModel() string {
return passwordAgePolicyTable
}
+func (p *PasswordAgePolicy) AggregateTypes() []models.AggregateType {
+ return []models.AggregateType{model.OrgAggregate, iam_es_model.IAMAggregate}
+}
+
+func (p *PasswordAgePolicy) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := p.view.GetLatestPasswordAgePolicySequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (p *PasswordAgePolicy) EventQuery() (*models.SearchQuery, error) {
- sequence, err := p.view.GetLatestPasswordAgePolicySequence()
+ sequence, err := p.view.GetLatestPasswordAgePolicySequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(model.OrgAggregate, iam_es_model.IAMAggregate).
+ AggregateTypeFilter(p.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
@@ -53,14 +87,14 @@ func (p *PasswordAgePolicy) processPasswordAgePolicy(event *models.Event) (err e
}
err = policy.AppendEvent(event)
case model.PasswordAgePolicyRemoved:
- return p.view.DeletePasswordAgePolicy(event.AggregateID, event.Sequence, event.CreationDate)
+ return p.view.DeletePasswordAgePolicy(event.AggregateID, event)
default:
- return p.view.ProcessedPasswordAgePolicySequence(event.Sequence, event.CreationDate)
+ return p.view.ProcessedPasswordAgePolicySequence(event)
}
if err != nil {
return err
}
- return p.view.PutPasswordAgePolicy(policy, policy.Sequence, event.CreationDate)
+ return p.view.PutPasswordAgePolicy(policy, event)
}
func (p *PasswordAgePolicy) OnError(event *models.Event, err error) error {
diff --git a/internal/admin/repository/eventsourcing/handler/password_complexity_policy.go b/internal/admin/repository/eventsourcing/handler/password_complexity_policy.go
index f1d2898218..edab685d23 100644
--- a/internal/admin/repository/eventsourcing/handler/password_complexity_policy.go
+++ b/internal/admin/repository/eventsourcing/handler/password_complexity_policy.go
@@ -2,34 +2,68 @@ package handler
import (
"github.com/caos/logging"
+ "github.com/caos/zitadel/internal/eventstore"
iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
iam_model "github.com/caos/zitadel/internal/iam/repository/view/model"
"github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
)
-type PasswordComplexityPolicy struct {
- handler
-}
-
const (
passwordComplexityPolicyTable = "adminapi.password_complexity_policies"
)
+type PasswordComplexityPolicy struct {
+ handler
+ subscription *eventstore.Subscription
+}
+
+func newPasswordComplexityPolicy(handler handler) *PasswordComplexityPolicy {
+ h := &PasswordComplexityPolicy{
+ handler: handler,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (p *PasswordComplexityPolicy) subscribe() {
+ p.subscription = p.es.Subscribe(p.AggregateTypes()...)
+ go func() {
+ for event := range p.subscription.Events {
+ query.ReduceEvent(p, event)
+ }
+ }()
+}
+
func (p *PasswordComplexityPolicy) ViewModel() string {
return passwordComplexityPolicyTable
}
+func (p *PasswordComplexityPolicy) AggregateTypes() []models.AggregateType {
+ return []models.AggregateType{model.OrgAggregate, iam_es_model.IAMAggregate}
+}
+
+func (p *PasswordComplexityPolicy) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := p.view.GetLatestPasswordComplexityPolicySequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (p *PasswordComplexityPolicy) EventQuery() (*models.SearchQuery, error) {
- sequence, err := p.view.GetLatestPasswordComplexityPolicySequence()
+ sequence, err := p.view.GetLatestPasswordComplexityPolicySequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(model.OrgAggregate, iam_es_model.IAMAggregate).
+ AggregateTypeFilter(p.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
@@ -53,14 +87,14 @@ func (p *PasswordComplexityPolicy) processPasswordComplexityPolicy(event *models
}
err = policy.AppendEvent(event)
case model.PasswordComplexityPolicyRemoved:
- return p.view.DeletePasswordComplexityPolicy(event.AggregateID, event.Sequence, event.CreationDate)
+ return p.view.DeletePasswordComplexityPolicy(event.AggregateID, event)
default:
- return p.view.ProcessedPasswordComplexityPolicySequence(event.Sequence, event.CreationDate)
+ return p.view.ProcessedPasswordComplexityPolicySequence(event)
}
if err != nil {
return err
}
- return p.view.PutPasswordComplexityPolicy(policy, policy.Sequence, event.CreationDate)
+ return p.view.PutPasswordComplexityPolicy(policy, event)
}
func (p *PasswordComplexityPolicy) OnError(event *models.Event, err error) error {
diff --git a/internal/admin/repository/eventsourcing/handler/password_lockout_policy.go b/internal/admin/repository/eventsourcing/handler/password_lockout_policy.go
index fd087adda7..99a8393cb8 100644
--- a/internal/admin/repository/eventsourcing/handler/password_lockout_policy.go
+++ b/internal/admin/repository/eventsourcing/handler/password_lockout_policy.go
@@ -2,34 +2,68 @@ package handler
import (
"github.com/caos/logging"
+ "github.com/caos/zitadel/internal/eventstore"
iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
iam_model "github.com/caos/zitadel/internal/iam/repository/view/model"
"github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
)
-type PasswordLockoutPolicy struct {
- handler
-}
-
const (
passwordLockoutPolicyTable = "adminapi.password_lockout_policies"
)
+type PasswordLockoutPolicy struct {
+ handler
+ subscription *eventstore.Subscription
+}
+
+func newPasswordLockoutPolicy(handler handler) *PasswordLockoutPolicy {
+ h := &PasswordLockoutPolicy{
+ handler: handler,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (p *PasswordLockoutPolicy) subscribe() {
+ p.subscription = p.es.Subscribe(p.AggregateTypes()...)
+ go func() {
+ for event := range p.subscription.Events {
+ query.ReduceEvent(p, event)
+ }
+ }()
+}
+
func (p *PasswordLockoutPolicy) ViewModel() string {
return passwordLockoutPolicyTable
}
+func (p *PasswordLockoutPolicy) AggregateTypes() []models.AggregateType {
+ return []models.AggregateType{model.OrgAggregate, iam_es_model.IAMAggregate}
+}
+
+func (p *PasswordLockoutPolicy) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := p.view.GetLatestPasswordLockoutPolicySequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (p *PasswordLockoutPolicy) EventQuery() (*models.SearchQuery, error) {
- sequence, err := p.view.GetLatestPasswordLockoutPolicySequence()
+ sequence, err := p.view.GetLatestPasswordLockoutPolicySequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(model.OrgAggregate, iam_es_model.IAMAggregate).
+ AggregateTypeFilter(p.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
@@ -53,14 +87,14 @@ func (p *PasswordLockoutPolicy) processPasswordLockoutPolicy(event *models.Event
}
err = policy.AppendEvent(event)
case model.PasswordLockoutPolicyRemoved:
- return p.view.DeletePasswordLockoutPolicy(event.AggregateID, event.Sequence, event.CreationDate)
+ return p.view.DeletePasswordLockoutPolicy(event.AggregateID, event)
default:
- return p.view.ProcessedPasswordLockoutPolicySequence(event.Sequence, event.CreationDate)
+ return p.view.ProcessedPasswordLockoutPolicySequence(event)
}
if err != nil {
return err
}
- return p.view.PutPasswordLockoutPolicy(policy, policy.Sequence, event.CreationDate)
+ return p.view.PutPasswordLockoutPolicy(policy, event)
}
func (p *PasswordLockoutPolicy) OnError(event *models.Event, err error) error {
diff --git a/internal/admin/repository/eventsourcing/handler/user.go b/internal/admin/repository/eventsourcing/handler/user.go
index f0f26afc4f..eb3a4bd83f 100644
--- a/internal/admin/repository/eventsourcing/handler/user.go
+++ b/internal/admin/repository/eventsourcing/handler/user.go
@@ -2,6 +2,7 @@ package handler
import (
"context"
+
"github.com/caos/zitadel/internal/config/systemdefaults"
iam_es "github.com/caos/zitadel/internal/iam/repository/eventsourcing"
@@ -10,6 +11,7 @@ import (
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
org_model "github.com/caos/zitadel/internal/org/model"
org_events "github.com/caos/zitadel/internal/org/repository/eventsourcing"
@@ -18,29 +20,69 @@ import (
view_model "github.com/caos/zitadel/internal/user/repository/view/model"
)
+const (
+ userTable = "adminapi.users"
+)
+
type User struct {
handler
eventstore eventstore.Eventstore
orgEvents *org_events.OrgEventstore
iamEvents *iam_es.IAMEventstore
systemDefaults systemdefaults.SystemDefaults
+ subscription *eventstore.Subscription
}
-const (
- userTable = "adminapi.users"
-)
+func newUser(
+ handler handler,
+ orgEvents *org_events.OrgEventstore,
+ iamEvents *iam_es.IAMEventstore,
+ systemDefaults systemdefaults.SystemDefaults,
+) *User {
+ h := &User{
+ handler: handler,
+ orgEvents: orgEvents,
+ iamEvents: iamEvents,
+ systemDefaults: systemDefaults,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (u *User) subscribe() {
+ u.subscription = u.es.Subscribe(u.AggregateTypes()...)
+ go func() {
+ for event := range u.subscription.Events {
+ query.ReduceEvent(u, event)
+ }
+ }()
+}
func (u *User) ViewModel() string {
return userTable
}
+func (u *User) AggregateTypes() []models.AggregateType {
+ return []models.AggregateType{es_model.UserAggregate, org_es_model.OrgAggregate}
+}
+
+func (u *User) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := u.view.GetLatestUserSequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (u *User) EventQuery() (*models.SearchQuery, error) {
- sequence, err := u.view.GetLatestUserSequence()
+ sequence, err := u.view.GetLatestUserSequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(es_model.UserAggregate, org_es_model.OrgAggregate).
+ AggregateTypeFilter(u.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
@@ -116,14 +158,14 @@ func (u *User) ProcessUser(event *models.Event) (err error) {
}
err = u.fillLoginNames(user)
case es_model.UserRemoved:
- return u.view.DeleteUser(event.AggregateID, event.Sequence, event.CreationDate)
+ return u.view.DeleteUser(event.AggregateID, event)
default:
- return u.view.ProcessedUserSequence(event.Sequence, event.CreationDate)
+ return u.view.ProcessedUserSequence(event)
}
if err != nil {
return err
}
- return u.view.PutUser(user, user.Sequence, event.CreationDate)
+ return u.view.PutUser(user, event)
}
func (u *User) ProcessOrg(event *models.Event) (err error) {
@@ -137,7 +179,7 @@ func (u *User) ProcessOrg(event *models.Event) (err error) {
case org_es_model.OrgDomainPrimarySet:
return u.fillPreferredLoginNamesOnOrgUsers(event)
default:
- return u.view.ProcessedUserSequence(event.Sequence, event.CreationDate)
+ return u.view.ProcessedUserSequence(event)
}
}
@@ -160,7 +202,7 @@ func (u *User) fillLoginNamesOnOrgUsers(event *models.Event) error {
for _, user := range users {
user.SetLoginNames(policy, org.Domains)
}
- return u.view.PutUsers(users, event.Sequence, event.CreationDate)
+ return u.view.PutUsers(users, event)
}
func (u *User) fillPreferredLoginNamesOnOrgUsers(event *models.Event) error {
@@ -185,7 +227,7 @@ func (u *User) fillPreferredLoginNamesOnOrgUsers(event *models.Event) error {
for _, user := range users {
user.PreferredLoginName = user.GenerateLoginName(org.GetPrimaryDomain().Domain, policy.UserLoginMustBeDomain)
}
- return u.view.PutUsers(users, event.Sequence, event.CreationDate)
+ return u.view.PutUsers(users, event)
}
func (u *User) fillLoginNames(user *view_model.UserView) (err error) {
diff --git a/internal/admin/repository/eventsourcing/handler/user_external_idps.go b/internal/admin/repository/eventsourcing/handler/user_external_idps.go
index cc4d979dc3..f7719e601b 100644
--- a/internal/admin/repository/eventsourcing/handler/user_external_idps.go
+++ b/internal/admin/repository/eventsourcing/handler/user_external_idps.go
@@ -2,9 +2,11 @@ package handler
import (
"context"
+
"github.com/caos/logging"
"github.com/caos/zitadel/internal/config/systemdefaults"
caos_errs "github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/iam/repository/eventsourcing"
iam_view_model "github.com/caos/zitadel/internal/iam/repository/view/model"
org_es "github.com/caos/zitadel/internal/org/repository/eventsourcing"
@@ -14,33 +16,74 @@ import (
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
iam_model "github.com/caos/zitadel/internal/iam/model"
iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
)
+const (
+ externalIDPTable = "adminapi.user_external_idps"
+)
+
type ExternalIDP struct {
handler
systemDefaults systemdefaults.SystemDefaults
iamEvents *eventsourcing.IAMEventstore
orgEvents *org_es.OrgEventstore
+ subscription *eventstore.Subscription
}
-const (
- externalIDPTable = "adminapi.user_external_idps"
-)
+func newExternalIDP(
+ handler handler,
+ systemDefaults systemdefaults.SystemDefaults,
+ iamEvents *eventsourcing.IAMEventstore,
+ orgEvents *org_es.OrgEventstore,
+) *ExternalIDP {
+ h := &ExternalIDP{
+ handler: handler,
+ systemDefaults: systemDefaults,
+ iamEvents: iamEvents,
+ orgEvents: orgEvents,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (i *ExternalIDP) subscribe() {
+ i.subscription = i.es.Subscribe(i.AggregateTypes()...)
+ go func() {
+ for event := range i.subscription.Events {
+ query.ReduceEvent(i, event)
+ }
+ }()
+}
func (i *ExternalIDP) ViewModel() string {
return externalIDPTable
}
+func (i *ExternalIDP) AggregateTypes() []models.AggregateType {
+ return []models.AggregateType{model.UserAggregate, iam_es_model.IAMAggregate, org_es_model.OrgAggregate}
+}
+
+func (i *ExternalIDP) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := i.view.GetLatestExternalIDPSequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (i *ExternalIDP) EventQuery() (*models.SearchQuery, error) {
- sequence, err := i.view.GetLatestExternalIDPSequence()
+ sequence, err := i.view.GetLatestExternalIDPSequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(model.UserAggregate, iam_es_model.IAMAggregate, org_es_model.OrgAggregate).
+ AggregateTypeFilter(i.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
@@ -68,16 +111,16 @@ func (i *ExternalIDP) processUser(event *models.Event) (err error) {
if err != nil {
return err
}
- return i.view.DeleteExternalIDP(externalIDP.ExternalUserID, externalIDP.IDPConfigID, event.Sequence, event.CreationDate)
+ return i.view.DeleteExternalIDP(externalIDP.ExternalUserID, externalIDP.IDPConfigID, event)
case model.UserRemoved:
- return i.view.DeleteExternalIDPsByUserID(event.AggregateID, event.Sequence, event.CreationDate)
+ return i.view.DeleteExternalIDPsByUserID(event.AggregateID, event)
default:
- return i.view.ProcessedExternalIDPSequence(event.Sequence, event.CreationDate)
+ return i.view.ProcessedExternalIDPSequence(event)
}
if err != nil {
return err
}
- return i.view.PutExternalIDP(externalIDP, externalIDP.Sequence, event.CreationDate)
+ return i.view.PutExternalIDP(externalIDP, event)
}
func (i *ExternalIDP) processIdpConfig(event *models.Event) (err error) {
@@ -105,11 +148,10 @@ func (i *ExternalIDP) processIdpConfig(event *models.Event) (err error) {
for _, provider := range exterinalIDPs {
i.fillConfigData(provider, config)
}
- return i.view.PutExternalIDPs(event.Sequence, event.CreationDate, exterinalIDPs...)
+ return i.view.PutExternalIDPs(event, exterinalIDPs...)
default:
- return i.view.ProcessedExternalIDPSequence(event.Sequence, event.CreationDate)
+ return i.view.ProcessedExternalIDPSequence(event)
}
- return nil
}
func (i *ExternalIDP) fillData(externalIDP *usr_view_model.ExternalIDPView) error {
diff --git a/internal/admin/repository/eventsourcing/spooler/lock.go b/internal/admin/repository/eventsourcing/spooler/lock.go
index 76317dc700..f07b190c1c 100644
--- a/internal/admin/repository/eventsourcing/spooler/lock.go
+++ b/internal/admin/repository/eventsourcing/spooler/lock.go
@@ -2,28 +2,18 @@ package spooler
import (
"database/sql"
- "time"
-
es_locker "github.com/caos/zitadel/internal/eventstore/locker"
+ "time"
)
const (
- lockTable = "adminapi.locks"
- lockedUntilKey = "locked_until"
- lockerIDKey = "locker_id"
- objectTypeKey = "object_type"
+ lockTable = "adminapi.locks"
)
type locker struct {
dbClient *sql.DB
}
-type lock struct {
- LockerID string `gorm:"column:locker_id;primary_key"`
- LockedUntil time.Time `gorm:"column:locked_until"`
- ViewName string `gorm:"column:object_type;primary_key"`
-}
-
func (l *locker) Renew(lockerID, viewModel string, waitTime time.Duration) error {
return es_locker.Renew(l.dbClient, lockTable, lockerID, viewModel, waitTime)
}
diff --git a/internal/admin/repository/eventsourcing/view/external_idps.go b/internal/admin/repository/eventsourcing/view/external_idps.go
index 8f21e7de86..384c1d81d0 100644
--- a/internal/admin/repository/eventsourcing/view/external_idps.go
+++ b/internal/admin/repository/eventsourcing/view/external_idps.go
@@ -2,11 +2,11 @@ package view
import (
"github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
usr_model "github.com/caos/zitadel/internal/user/model"
"github.com/caos/zitadel/internal/user/repository/view"
"github.com/caos/zitadel/internal/user/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -33,44 +33,44 @@ func (v *View) SearchExternalIDPs(request *usr_model.ExternalIDPSearchRequest) (
return view.SearchExternalIDPs(v.Db, externalIDPTable, request)
}
-func (v *View) PutExternalIDP(externalIDP *model.ExternalIDPView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutExternalIDP(externalIDP *model.ExternalIDPView, event *models.Event) error {
err := view.PutExternalIDP(v.Db, externalIDPTable, externalIDP)
if err != nil {
return err
}
- return v.ProcessedExternalIDPSequence(sequence, eventTimestamp)
+ return v.ProcessedExternalIDPSequence(event)
}
-func (v *View) PutExternalIDPs(sequence uint64, eventTimestamp time.Time, externalIDPs ...*model.ExternalIDPView) error {
+func (v *View) PutExternalIDPs(event *models.Event, externalIDPs ...*model.ExternalIDPView) error {
err := view.PutExternalIDPs(v.Db, externalIDPTable, externalIDPs...)
if err != nil {
return err
}
- return v.ProcessedExternalIDPSequence(sequence, eventTimestamp)
+ return v.ProcessedExternalIDPSequence(event)
}
-func (v *View) DeleteExternalIDP(externalUserID, idpConfigID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteExternalIDP(externalUserID, idpConfigID string, event *models.Event) error {
err := view.DeleteExternalIDP(v.Db, externalIDPTable, externalUserID, idpConfigID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedExternalIDPSequence(eventSequence, eventTimestamp)
+ return v.ProcessedExternalIDPSequence(event)
}
-func (v *View) DeleteExternalIDPsByUserID(userID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteExternalIDPsByUserID(userID string, event *models.Event) error {
err := view.DeleteExternalIDPsByUserID(v.Db, externalIDPTable, userID)
if err != nil {
return err
}
- return v.ProcessedExternalIDPSequence(eventSequence, eventTimestamp)
+ return v.ProcessedExternalIDPSequence(event)
}
-func (v *View) GetLatestExternalIDPSequence() (*global_view.CurrentSequence, error) {
- return v.latestSequence(externalIDPTable)
+func (v *View) GetLatestExternalIDPSequence(aggregateType string) (*global_view.CurrentSequence, error) {
+ return v.latestSequence(externalIDPTable, aggregateType)
}
-func (v *View) ProcessedExternalIDPSequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(externalIDPTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedExternalIDPSequence(event *models.Event) error {
+ return v.saveCurrentSequence(externalIDPTable, event)
}
func (v *View) UpdateExternalIDPSpoolerRunTimestamp() error {
diff --git a/internal/admin/repository/eventsourcing/view/iam_member.go b/internal/admin/repository/eventsourcing/view/iam_member.go
index 250a0042fa..d215ca0b5b 100644
--- a/internal/admin/repository/eventsourcing/view/iam_member.go
+++ b/internal/admin/repository/eventsourcing/view/iam_member.go
@@ -2,11 +2,11 @@ package view
import (
"github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -25,44 +25,44 @@ func (v *View) IAMMembersByUserID(userID string) ([]*model.IAMMemberView, error)
return view.IAMMembersByUserID(v.Db, iamMemberTable, userID)
}
-func (v *View) PutIAMMember(org *model.IAMMemberView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutIAMMember(org *model.IAMMemberView, event *models.Event) error {
err := view.PutIAMMember(v.Db, iamMemberTable, org)
if err != nil {
return err
}
- return v.ProcessedIAMMemberSequence(sequence, eventTimestamp)
+ return v.ProcessedIAMMemberSequence(event)
}
-func (v *View) PutIAMMembers(members []*model.IAMMemberView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutIAMMembers(members []*model.IAMMemberView, event *models.Event) error {
err := view.PutIAMMembers(v.Db, iamMemberTable, members...)
if err != nil {
return err
}
- return v.ProcessedIAMMemberSequence(sequence, eventTimestamp)
+ return v.ProcessedIAMMemberSequence(event)
}
-func (v *View) DeleteIAMMember(iamID, userID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteIAMMember(iamID, userID string, event *models.Event) error {
err := view.DeleteIAMMember(v.Db, iamMemberTable, iamID, userID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedIAMMemberSequence(eventSequence, eventTimestamp)
+ return v.ProcessedIAMMemberSequence(event)
}
-func (v *View) DeleteIAMMembersByUserID(userID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteIAMMembersByUserID(userID string, event *models.Event) error {
err := view.DeleteIAMMembersByUserID(v.Db, iamMemberTable, userID)
if err != nil {
return err
}
- return v.ProcessedIAMMemberSequence(eventSequence, eventTimestamp)
+ return v.ProcessedIAMMemberSequence(event)
}
-func (v *View) GetLatestIAMMemberSequence() (*global_view.CurrentSequence, error) {
- return v.latestSequence(iamMemberTable)
+func (v *View) GetLatestIAMMemberSequence(aggregateType string) (*global_view.CurrentSequence, error) {
+ return v.latestSequence(iamMemberTable, aggregateType)
}
-func (v *View) ProcessedIAMMemberSequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(iamMemberTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedIAMMemberSequence(event *models.Event) error {
+ return v.saveCurrentSequence(iamMemberTable, event)
}
func (v *View) UpdateIAMMemberSpoolerRunTimestamp() error {
diff --git a/internal/admin/repository/eventsourcing/view/idp_configs.go b/internal/admin/repository/eventsourcing/view/idp_configs.go
index 197c37d09b..5a120de265 100644
--- a/internal/admin/repository/eventsourcing/view/idp_configs.go
+++ b/internal/admin/repository/eventsourcing/view/idp_configs.go
@@ -2,11 +2,11 @@ package view
import (
"github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -21,28 +21,28 @@ func (v *View) SearchIDPConfigs(request *iam_model.IDPConfigSearchRequest) ([]*m
return view.SearchIDPs(v.Db, idpConfigTable, request)
}
-func (v *View) PutIDPConfig(idp *model.IDPConfigView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutIDPConfig(idp *model.IDPConfigView, event *models.Event) error {
err := view.PutIDP(v.Db, idpConfigTable, idp)
if err != nil {
return err
}
- return v.ProcessedIDPConfigSequence(sequence, eventTimestamp)
+ return v.ProcessedIDPConfigSequence(event)
}
-func (v *View) DeleteIDPConfig(idpID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteIDPConfig(idpID string, event *models.Event) error {
err := view.DeleteIDP(v.Db, idpConfigTable, idpID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedIDPConfigSequence(eventSequence, eventTimestamp)
+ return v.ProcessedIDPConfigSequence(event)
}
-func (v *View) GetLatestIDPConfigSequence() (*global_view.CurrentSequence, error) {
- return v.latestSequence(idpConfigTable)
+func (v *View) GetLatestIDPConfigSequence(aggregateType string) (*global_view.CurrentSequence, error) {
+ return v.latestSequence(idpConfigTable, aggregateType)
}
-func (v *View) ProcessedIDPConfigSequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(idpConfigTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedIDPConfigSequence(event *models.Event) error {
+ return v.saveCurrentSequence(idpConfigTable, event)
}
func (v *View) UpdateIDPConfigSpoolerRunTimestamp() error {
diff --git a/internal/admin/repository/eventsourcing/view/idp_providers.go b/internal/admin/repository/eventsourcing/view/idp_providers.go
index 10b5886945..26a682379d 100644
--- a/internal/admin/repository/eventsourcing/view/idp_providers.go
+++ b/internal/admin/repository/eventsourcing/view/idp_providers.go
@@ -2,11 +2,11 @@ package view
import (
"github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -25,36 +25,36 @@ func (v *View) SearchIDPProviders(request *iam_model.IDPProviderSearchRequest) (
return view.SearchIDPProviders(v.Db, idpProviderTable, request)
}
-func (v *View) PutIDPProvider(provider *model.IDPProviderView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutIDPProvider(provider *model.IDPProviderView, event *models.Event) error {
err := view.PutIDPProvider(v.Db, idpProviderTable, provider)
if err != nil {
return err
}
- return v.ProcessedIDPProviderSequence(sequence, eventTimestamp)
+ return v.ProcessedIDPProviderSequence(event)
}
-func (v *View) PutIDPProviders(sequence uint64, eventTimestamp time.Time, providers ...*model.IDPProviderView) error {
+func (v *View) PutIDPProviders(event *models.Event, providers ...*model.IDPProviderView) error {
err := view.PutIDPProviders(v.Db, idpProviderTable, providers...)
if err != nil {
return err
}
- return v.ProcessedIDPProviderSequence(sequence, eventTimestamp)
+ return v.ProcessedIDPProviderSequence(event)
}
-func (v *View) DeleteIDPProvider(aggregateID, idpConfigID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteIDPProvider(aggregateID, idpConfigID string, event *models.Event) error {
err := view.DeleteIDPProvider(v.Db, idpProviderTable, aggregateID, idpConfigID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedIDPProviderSequence(eventSequence, eventTimestamp)
+ return v.ProcessedIDPProviderSequence(event)
}
-func (v *View) GetLatestIDPProviderSequence() (*global_view.CurrentSequence, error) {
- return v.latestSequence(idpProviderTable)
+func (v *View) GetLatestIDPProviderSequence(aggregateType string) (*global_view.CurrentSequence, error) {
+ return v.latestSequence(idpProviderTable, aggregateType)
}
-func (v *View) ProcessedIDPProviderSequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(idpProviderTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedIDPProviderSequence(event *models.Event) error {
+ return v.saveCurrentSequence(idpProviderTable, event)
}
func (v *View) UpdateIDPProviderSpoolerRunTimestamp() error {
diff --git a/internal/admin/repository/eventsourcing/view/label_policies.go b/internal/admin/repository/eventsourcing/view/label_policies.go
index f4e921ac1c..9b1a46cee1 100644
--- a/internal/admin/repository/eventsourcing/view/label_policies.go
+++ b/internal/admin/repository/eventsourcing/view/label_policies.go
@@ -1,10 +1,10 @@
package view
import (
+ "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -15,20 +15,20 @@ func (v *View) LabelPolicyByAggregateID(aggregateID string) (*model.LabelPolicyV
return view.GetLabelPolicyByAggregateID(v.Db, labelPolicyTable, aggregateID)
}
-func (v *View) PutLabelPolicy(policy *model.LabelPolicyView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutLabelPolicy(policy *model.LabelPolicyView, event *models.Event) error {
err := view.PutLabelPolicy(v.Db, labelPolicyTable, policy)
if err != nil {
return err
}
- return v.ProcessedLabelPolicySequence(sequence, eventTimestamp)
+ return v.ProcessedLabelPolicySequence(event)
}
-func (v *View) GetLatestLabelPolicySequence() (*global_view.CurrentSequence, error) {
- return v.latestSequence(labelPolicyTable)
+func (v *View) GetLatestLabelPolicySequence(aggregateType string) (*global_view.CurrentSequence, error) {
+ return v.latestSequence(labelPolicyTable, aggregateType)
}
-func (v *View) ProcessedLabelPolicySequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(labelPolicyTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedLabelPolicySequence(event *models.Event) error {
+ return v.saveCurrentSequence(labelPolicyTable, event)
}
func (v *View) UpdateLabelPolicySpoolerRunTimestamp() error {
diff --git a/internal/admin/repository/eventsourcing/view/login_policies.go b/internal/admin/repository/eventsourcing/view/login_policies.go
index 03e4451ffb..7e71983724 100644
--- a/internal/admin/repository/eventsourcing/view/login_policies.go
+++ b/internal/admin/repository/eventsourcing/view/login_policies.go
@@ -2,10 +2,10 @@ package view
import (
"github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -16,28 +16,28 @@ func (v *View) LoginPolicyByAggregateID(aggregateID string) (*model.LoginPolicyV
return view.GetLoginPolicyByAggregateID(v.Db, loginPolicyTable, aggregateID)
}
-func (v *View) PutLoginPolicy(policy *model.LoginPolicyView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutLoginPolicy(policy *model.LoginPolicyView, event *models.Event) error {
err := view.PutLoginPolicy(v.Db, loginPolicyTable, policy)
if err != nil {
return err
}
- return v.ProcessedLoginPolicySequence(sequence, eventTimestamp)
+ return v.ProcessedLoginPolicySequence(event)
}
-func (v *View) DeleteLoginPolicy(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteLoginPolicy(aggregateID string, event *models.Event) error {
err := view.DeleteLoginPolicy(v.Db, loginPolicyTable, aggregateID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedLoginPolicySequence(eventSequence, eventTimestamp)
+ return v.ProcessedLoginPolicySequence(event)
}
-func (v *View) GetLatestLoginPolicySequence() (*global_view.CurrentSequence, error) {
- return v.latestSequence(loginPolicyTable)
+func (v *View) GetLatestLoginPolicySequence(aggregateType string) (*global_view.CurrentSequence, error) {
+ return v.latestSequence(loginPolicyTable, aggregateType)
}
-func (v *View) ProcessedLoginPolicySequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(loginPolicyTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedLoginPolicySequence(event *models.Event) error {
+ return v.saveCurrentSequence(loginPolicyTable, event)
}
func (v *View) UpdateLoginPolicySpoolerRunTimestamp() error {
diff --git a/internal/admin/repository/eventsourcing/view/org.go b/internal/admin/repository/eventsourcing/view/org.go
index ee9f9fb113..b5d104a7ed 100644
--- a/internal/admin/repository/eventsourcing/view/org.go
+++ b/internal/admin/repository/eventsourcing/view/org.go
@@ -1,11 +1,11 @@
package view
import (
+ "github.com/caos/zitadel/internal/eventstore/models"
org_model "github.com/caos/zitadel/internal/org/model"
org_view "github.com/caos/zitadel/internal/org/repository/view"
"github.com/caos/zitadel/internal/org/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -20,12 +20,12 @@ func (v *View) SearchOrgs(query *org_model.OrgSearchRequest) ([]*model.OrgView,
return org_view.SearchOrgs(v.Db, orgTable, query)
}
-func (v *View) PutOrg(org *model.OrgView, eventTimestamp time.Time) error {
+func (v *View) PutOrg(org *model.OrgView, event *models.Event) error {
err := org_view.PutOrg(v.Db, orgTable, org)
if err != nil {
return err
}
- return v.ProcessedOrgSequence(org.Sequence, eventTimestamp)
+ return v.ProcessedOrgSequence(event)
}
func (v *View) GetLatestOrgFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
@@ -40,10 +40,10 @@ func (v *View) UpdateOrgSpoolerRunTimestamp() error {
return v.updateSpoolerRunSequence(orgTable)
}
-func (v *View) GetLatestOrgSequence() (*repository.CurrentSequence, error) {
- return v.latestSequence(orgTable)
+func (v *View) GetLatestOrgSequence(aggregateType string) (*repository.CurrentSequence, error) {
+ return v.latestSequence(orgTable, aggregateType)
}
-func (v *View) ProcessedOrgSequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(orgTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedOrgSequence(event *models.Event) error {
+ return v.saveCurrentSequence(orgTable, event)
}
diff --git a/internal/admin/repository/eventsourcing/view/org_iam_policy.go b/internal/admin/repository/eventsourcing/view/org_iam_policy.go
index 3168a78152..5d13779e48 100644
--- a/internal/admin/repository/eventsourcing/view/org_iam_policy.go
+++ b/internal/admin/repository/eventsourcing/view/org_iam_policy.go
@@ -2,10 +2,10 @@ package view
import (
"github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -16,28 +16,28 @@ func (v *View) OrgIAMPolicyByAggregateID(aggregateID string) (*model.OrgIAMPolic
return view.GetOrgIAMPolicyByAggregateID(v.Db, orgIAMPolicyTable, aggregateID)
}
-func (v *View) PutOrgIAMPolicy(policy *model.OrgIAMPolicyView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutOrgIAMPolicy(policy *model.OrgIAMPolicyView, event *models.Event) error {
err := view.PutOrgIAMPolicy(v.Db, orgIAMPolicyTable, policy)
if err != nil {
return err
}
- return v.ProcessedOrgIAMPolicySequence(sequence, eventTimestamp)
+ return v.ProcessedOrgIAMPolicySequence(event)
}
-func (v *View) DeleteOrgIAMPolicy(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteOrgIAMPolicy(aggregateID string, event *models.Event) error {
err := view.DeleteOrgIAMPolicy(v.Db, orgIAMPolicyTable, aggregateID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedOrgIAMPolicySequence(eventSequence, eventTimestamp)
+ return v.ProcessedOrgIAMPolicySequence(event)
}
-func (v *View) GetLatestOrgIAMPolicySequence() (*global_view.CurrentSequence, error) {
- return v.latestSequence(orgIAMPolicyTable)
+func (v *View) GetLatestOrgIAMPolicySequence(aggregateType string) (*global_view.CurrentSequence, error) {
+ return v.latestSequence(orgIAMPolicyTable, aggregateType)
}
-func (v *View) ProcessedOrgIAMPolicySequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(orgIAMPolicyTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedOrgIAMPolicySequence(event *models.Event) error {
+ return v.saveCurrentSequence(orgIAMPolicyTable, event)
}
func (v *View) UpdateOrgIAMPolicySpoolerRunTimestamp() error {
diff --git a/internal/admin/repository/eventsourcing/view/password_age_policy.go b/internal/admin/repository/eventsourcing/view/password_age_policy.go
index 419b537830..b1cbe535c4 100644
--- a/internal/admin/repository/eventsourcing/view/password_age_policy.go
+++ b/internal/admin/repository/eventsourcing/view/password_age_policy.go
@@ -2,10 +2,10 @@ package view
import (
"github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -16,28 +16,28 @@ func (v *View) PasswordAgePolicyByAggregateID(aggregateID string) (*model.Passwo
return view.GetPasswordAgePolicyByAggregateID(v.Db, passwordAgePolicyTable, aggregateID)
}
-func (v *View) PutPasswordAgePolicy(policy *model.PasswordAgePolicyView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutPasswordAgePolicy(policy *model.PasswordAgePolicyView, event *models.Event) error {
err := view.PutPasswordAgePolicy(v.Db, passwordAgePolicyTable, policy)
if err != nil {
return err
}
- return v.ProcessedPasswordAgePolicySequence(sequence, eventTimestamp)
+ return v.ProcessedPasswordAgePolicySequence(event)
}
-func (v *View) DeletePasswordAgePolicy(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeletePasswordAgePolicy(aggregateID string, event *models.Event) error {
err := view.DeletePasswordAgePolicy(v.Db, passwordAgePolicyTable, aggregateID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedPasswordAgePolicySequence(eventSequence, eventTimestamp)
+ return v.ProcessedPasswordAgePolicySequence(event)
}
-func (v *View) GetLatestPasswordAgePolicySequence() (*global_view.CurrentSequence, error) {
- return v.latestSequence(passwordAgePolicyTable)
+func (v *View) GetLatestPasswordAgePolicySequence(aggregateType string) (*global_view.CurrentSequence, error) {
+ return v.latestSequence(passwordAgePolicyTable, aggregateType)
}
-func (v *View) ProcessedPasswordAgePolicySequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(passwordAgePolicyTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedPasswordAgePolicySequence(event *models.Event) error {
+ return v.saveCurrentSequence(passwordAgePolicyTable, event)
}
func (v *View) UpdateProcessedPasswordAgePolicySpoolerRunTimestamp() error {
diff --git a/internal/admin/repository/eventsourcing/view/password_complexity_policy.go b/internal/admin/repository/eventsourcing/view/password_complexity_policy.go
index 2b1af7d375..44315b9666 100644
--- a/internal/admin/repository/eventsourcing/view/password_complexity_policy.go
+++ b/internal/admin/repository/eventsourcing/view/password_complexity_policy.go
@@ -2,10 +2,10 @@ package view
import (
"github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -16,28 +16,28 @@ func (v *View) PasswordComplexityPolicyByAggregateID(aggregateID string) (*model
return view.GetPasswordComplexityPolicyByAggregateID(v.Db, passwordComplexityPolicyTable, aggregateID)
}
-func (v *View) PutPasswordComplexityPolicy(policy *model.PasswordComplexityPolicyView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutPasswordComplexityPolicy(policy *model.PasswordComplexityPolicyView, event *models.Event) error {
err := view.PutPasswordComplexityPolicy(v.Db, passwordComplexityPolicyTable, policy)
if err != nil {
return err
}
- return v.ProcessedPasswordComplexityPolicySequence(sequence, eventTimestamp)
+ return v.ProcessedPasswordComplexityPolicySequence(event)
}
-func (v *View) DeletePasswordComplexityPolicy(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeletePasswordComplexityPolicy(aggregateID string, event *models.Event) error {
err := view.DeletePasswordComplexityPolicy(v.Db, passwordComplexityPolicyTable, aggregateID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedPasswordComplexityPolicySequence(eventSequence, eventTimestamp)
+ return v.ProcessedPasswordComplexityPolicySequence(event)
}
-func (v *View) GetLatestPasswordComplexityPolicySequence() (*global_view.CurrentSequence, error) {
- return v.latestSequence(passwordComplexityPolicyTable)
+func (v *View) GetLatestPasswordComplexityPolicySequence(aggregateType string) (*global_view.CurrentSequence, error) {
+ return v.latestSequence(passwordComplexityPolicyTable, aggregateType)
}
-func (v *View) ProcessedPasswordComplexityPolicySequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(passwordComplexityPolicyTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedPasswordComplexityPolicySequence(event *models.Event) error {
+ return v.saveCurrentSequence(passwordComplexityPolicyTable, event)
}
func (v *View) UpdatePasswordComplexityPolicySpoolerRunTimestamp() error {
diff --git a/internal/admin/repository/eventsourcing/view/password_lockout_policy.go b/internal/admin/repository/eventsourcing/view/password_lockout_policy.go
index d20643d37c..805aab3fc3 100644
--- a/internal/admin/repository/eventsourcing/view/password_lockout_policy.go
+++ b/internal/admin/repository/eventsourcing/view/password_lockout_policy.go
@@ -2,10 +2,10 @@ package view
import (
"github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -16,28 +16,28 @@ func (v *View) PasswordLockoutPolicyByAggregateID(aggregateID string) (*model.Pa
return view.GetPasswordLockoutPolicyByAggregateID(v.Db, passwordLockoutPolicyTable, aggregateID)
}
-func (v *View) PutPasswordLockoutPolicy(policy *model.PasswordLockoutPolicyView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutPasswordLockoutPolicy(policy *model.PasswordLockoutPolicyView, event *models.Event) error {
err := view.PutPasswordLockoutPolicy(v.Db, passwordLockoutPolicyTable, policy)
if err != nil {
return err
}
- return v.ProcessedPasswordLockoutPolicySequence(sequence, eventTimestamp)
+ return v.ProcessedPasswordLockoutPolicySequence(event)
}
-func (v *View) DeletePasswordLockoutPolicy(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeletePasswordLockoutPolicy(aggregateID string, event *models.Event) error {
err := view.DeletePasswordLockoutPolicy(v.Db, passwordLockoutPolicyTable, aggregateID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedPasswordLockoutPolicySequence(eventSequence, eventTimestamp)
+ return v.ProcessedPasswordLockoutPolicySequence(event)
}
-func (v *View) GetLatestPasswordLockoutPolicySequence() (*global_view.CurrentSequence, error) {
- return v.latestSequence(passwordLockoutPolicyTable)
+func (v *View) GetLatestPasswordLockoutPolicySequence(aggregateType string) (*global_view.CurrentSequence, error) {
+ return v.latestSequence(passwordLockoutPolicyTable, aggregateType)
}
-func (v *View) ProcessedPasswordLockoutPolicySequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(passwordLockoutPolicyTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedPasswordLockoutPolicySequence(event *models.Event) error {
+ return v.saveCurrentSequence(passwordLockoutPolicyTable, event)
}
func (v *View) UpdatePasswordLockoutPolicySpoolerRunTimestamp() error {
diff --git a/internal/admin/repository/eventsourcing/view/sequence.go b/internal/admin/repository/eventsourcing/view/sequence.go
index cda4580a6b..5915da9b56 100644
--- a/internal/admin/repository/eventsourcing/view/sequence.go
+++ b/internal/admin/repository/eventsourcing/view/sequence.go
@@ -1,20 +1,22 @@
package view
import (
- "github.com/caos/zitadel/internal/view/repository"
"time"
+
+ "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/view/repository"
)
const (
sequencesTable = "adminapi.current_sequences"
)
-func (v *View) saveCurrentSequence(viewName string, sequence uint64, eventTimeStamp time.Time) error {
- return repository.SaveCurrentSequence(v.Db, sequencesTable, viewName, sequence, eventTimeStamp)
+func (v *View) saveCurrentSequence(viewName string, event *models.Event) error {
+ return repository.SaveCurrentSequence(v.Db, sequencesTable, viewName, string(event.AggregateType), event.Sequence, event.CreationDate)
}
-func (v *View) latestSequence(viewName string) (*repository.CurrentSequence, error) {
- return repository.LatestSequence(v.Db, sequencesTable, viewName)
+func (v *View) latestSequence(viewName, aggregateType string) (*repository.CurrentSequence, error) {
+ return repository.LatestSequence(v.Db, sequencesTable, viewName, aggregateType)
}
func (v *View) AllCurrentSequences(db string) ([]*repository.CurrentSequence, error) {
@@ -22,7 +24,7 @@ func (v *View) AllCurrentSequences(db string) ([]*repository.CurrentSequence, er
}
func (v *View) updateSpoolerRunSequence(viewName string) error {
- currentSequence, err := repository.LatestSequence(v.Db, sequencesTable, viewName)
+ currentSequence, err := repository.LatestSequence(v.Db, sequencesTable, viewName, "")
if err != nil {
return err
}
@@ -30,13 +32,16 @@ func (v *View) updateSpoolerRunSequence(viewName string) error {
currentSequence.ViewName = viewName
}
currentSequence.LastSuccessfulSpoolerRun = time.Now()
+ //update all aggregate types
+ //TODO: not sure if all scenarios work as expected
+ currentSequence.AggregateType = ""
return repository.UpdateCurrentSequence(v.Db, sequencesTable, currentSequence)
}
-func (v *View) GetCurrentSequence(db, viewName string) (*repository.CurrentSequence, error) {
+func (v *View) GetCurrentSequence(db, viewName, aggregateType string) (*repository.CurrentSequence, error) {
sequenceTable := db + ".current_sequences"
fullView := db + "." + viewName
- return repository.LatestSequence(v.Db, sequenceTable, fullView)
+ return repository.LatestSequence(v.Db, sequenceTable, fullView, aggregateType)
}
func (v *View) ClearView(db, viewName string) error {
diff --git a/internal/admin/repository/eventsourcing/view/user.go b/internal/admin/repository/eventsourcing/view/user.go
index 3de68472cf..9694b41f78 100644
--- a/internal/admin/repository/eventsourcing/view/user.go
+++ b/internal/admin/repository/eventsourcing/view/user.go
@@ -1,11 +1,12 @@
package view
import (
+ "github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
usr_model "github.com/caos/zitadel/internal/user/model"
"github.com/caos/zitadel/internal/user/repository/view"
"github.com/caos/zitadel/internal/user/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -40,39 +41,36 @@ func (v *View) UserMFAs(userID string) ([]*usr_model.MultiFactor, error) {
return view.UserMFAs(v.Db, userTable, userID)
}
-func (v *View) PutUsers(user []*model.UserView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutUsers(user []*model.UserView, event *models.Event) error {
err := view.PutUsers(v.Db, userTable, user...)
if err != nil {
return err
}
- return v.ProcessedUserSequence(sequence, eventTimestamp)
+ return v.ProcessedUserSequence(event)
}
-func (v *View) PutUser(user *model.UserView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutUser(user *model.UserView, event *models.Event) error {
err := view.PutUser(v.Db, userTable, user)
if err != nil {
return err
}
- if sequence != 0 {
- return v.ProcessedUserSequence(sequence, eventTimestamp)
- }
- return nil
+ return v.ProcessedUserSequence(event)
}
-func (v *View) DeleteUser(userID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteUser(userID string, event *models.Event) error {
err := view.DeleteUser(v.Db, userTable, userID)
- if err != nil {
- return nil
+ if err != nil && !errors.IsNotFound(err) {
+ return err
}
- return v.ProcessedUserSequence(eventSequence, eventTimestamp)
+ return v.ProcessedUserSequence(event)
}
-func (v *View) GetLatestUserSequence() (*repository.CurrentSequence, error) {
- return v.latestSequence(userTable)
+func (v *View) GetLatestUserSequence(aggregateType string) (*repository.CurrentSequence, error) {
+ return v.latestSequence(userTable, aggregateType)
}
-func (v *View) ProcessedUserSequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(userTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedUserSequence(event *models.Event) error {
+ return v.saveCurrentSequence(userTable, event)
}
func (v *View) UpdateUserSpoolerRunTimestamp() error {
diff --git a/internal/api/authz/authorization.go b/internal/api/authz/authorization.go
index 7ae5e838f4..36b17e5cd8 100644
--- a/internal/api/authz/authorization.go
+++ b/internal/api/authz/authorization.go
@@ -14,33 +14,39 @@ const (
authenticated = "authenticated"
)
-func CheckUserAuthorization(ctx context.Context, req interface{}, token, orgID string, verifier *TokenVerifier, authConfig Config, requiredAuthOption Option, method string) (_ context.Context, err error) {
+func CheckUserAuthorization(ctx context.Context, req interface{}, token, orgID string, verifier *TokenVerifier, authConfig Config, requiredAuthOption Option, method string) (ctxSetter func(context.Context) context.Context, err error) {
ctx, span := tracing.NewServerInterceptorSpan(ctx)
defer func() { span.EndWithError(err) }()
- ctx, err = VerifyTokenAndWriteCtxData(ctx, token, orgID, verifier, method)
+ ctxData, err := VerifyTokenAndCreateCtxData(ctx, token, orgID, verifier, method)
if err != nil {
return nil, err
}
- var perms []string
if requiredAuthOption.Permission == authenticated {
- return ctx, nil
+ return func(parent context.Context) context.Context {
+ return context.WithValue(parent, dataKey, ctxData)
+ }, nil
}
- ctx, perms, err = getUserMethodPermissions(ctx, verifier, requiredAuthOption.Permission, authConfig)
+ requestedPermissions, allPermissions, err := getUserMethodPermissions(ctx, verifier, requiredAuthOption.Permission, authConfig, ctxData)
if err != nil {
return nil, err
}
ctx, userPermissionSpan := tracing.NewNamedSpan(ctx, "checkUserPermissions")
- err = checkUserPermissions(req, perms, requiredAuthOption)
+ err = checkUserPermissions(req, requestedPermissions, requiredAuthOption)
userPermissionSpan.EndWithError(err)
if err != nil {
return nil, err
}
- return ctx, nil
+ return func(parent context.Context) context.Context {
+ parent = context.WithValue(parent, dataKey, ctxData)
+ parent = context.WithValue(parent, allPermissionsKey, allPermissions)
+ parent = context.WithValue(parent, requestPermissionsKey, requestedPermissions)
+ return parent
+ }, nil
}
func checkUserPermissions(req interface{}, userPerms []string, authOpt Option) error {
diff --git a/internal/api/authz/context.go b/internal/api/authz/context.go
index 4880a7373e..374ef0c571 100644
--- a/internal/api/authz/context.go
+++ b/internal/api/authz/context.go
@@ -36,29 +36,36 @@ type Grant struct {
Roles []string
}
-func VerifyTokenAndWriteCtxData(ctx context.Context, token, orgID string, t *TokenVerifier, method string) (_ context.Context, err error) {
+func VerifyTokenAndCreateCtxData(ctx context.Context, token, orgID string, t *TokenVerifier, method string) (_ CtxData, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
if orgID != "" {
err = t.ExistsOrg(ctx, orgID)
if err != nil {
- return nil, errors.ThrowPermissionDenied(nil, "AUTH-Bs7Ds", "Organisation doesn't exist")
+ return CtxData{}, errors.ThrowPermissionDenied(nil, "AUTH-Bs7Ds", "Organisation doesn't exist")
}
}
userID, clientID, agentID, prefLang, err := verifyAccessToken(ctx, token, t, method)
if err != nil {
- return nil, err
+ return CtxData{}, err
}
projectID, origins, err := t.ProjectIDAndOriginsByClientID(ctx, clientID)
if err != nil {
- return nil, errors.ThrowPermissionDenied(err, "AUTH-GHpw2", "could not read projectid by clientid")
+ return CtxData{}, errors.ThrowPermissionDenied(err, "AUTH-GHpw2", "could not read projectid by clientid")
}
if err := checkOrigin(ctx, origins); err != nil {
- return nil, err
+ return CtxData{}, err
}
- return context.WithValue(ctx, dataKey, CtxData{UserID: userID, OrgID: orgID, ProjectID: projectID, AgentID: agentID, PreferredLanguage: prefLang}), nil
+ return CtxData{
+ UserID: userID,
+ OrgID: orgID,
+ ProjectID: projectID,
+ AgentID: agentID,
+ PreferredLanguage: prefLang,
+ }, nil
+
}
func SetCtxData(ctx context.Context, ctxData CtxData) context.Context {
diff --git a/internal/api/authz/permissions.go b/internal/api/authz/permissions.go
index 8023152ca9..6423f80fd7 100644
--- a/internal/api/authz/permissions.go
+++ b/internal/api/authz/permissions.go
@@ -7,29 +7,29 @@ import (
"github.com/caos/zitadel/internal/telemetry/tracing"
)
-func getUserMethodPermissions(ctx context.Context, t *TokenVerifier, requiredPerm string, authConfig Config) (_ context.Context, _ []string, err error) {
+func getUserMethodPermissions(ctx context.Context, t *TokenVerifier, requiredPerm string, authConfig Config, ctxData CtxData) (requestedPermissions, allPermissions []string, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
- ctxData := GetCtxData(ctx)
if ctxData.IsZero() {
return nil, nil, errors.ThrowUnauthenticated(nil, "AUTH-rKLWEH", "context missing")
}
+
+ ctx = context.WithValue(ctx, dataKey, ctxData)
grant, err := t.ResolveGrant(ctx)
if err != nil {
return nil, nil, err
}
if grant == nil {
- return context.WithValue(ctx, requestPermissionsKey, []string{}), []string{}, nil
+ return requestedPermissions, nil, nil
}
- requestPermissions, allPermissions := mapGrantToPermissions(requiredPerm, grant, authConfig)
- ctx = context.WithValue(ctx, allPermissionsKey, allPermissions)
- return context.WithValue(ctx, requestPermissionsKey, requestPermissions), requestPermissions, nil
+ requestedPermissions, allPermissions = mapGrantToPermissions(requiredPerm, grant, authConfig)
+ return requestedPermissions, allPermissions, nil
}
-func mapGrantToPermissions(requiredPerm string, grant *Grant, authConfig Config) ([]string, []string) {
- requestPermissions := make([]string, 0)
- allPermissions := make([]string, 0)
+func mapGrantToPermissions(requiredPerm string, grant *Grant, authConfig Config) (requestPermissions, allPermissions []string) {
+ requestPermissions = make([]string, 0)
+ allPermissions = make([]string, 0)
for _, role := range grant.Roles {
requestPermissions, allPermissions = mapRoleToPerm(requiredPerm, role, authConfig, requestPermissions, allPermissions)
}
diff --git a/internal/api/authz/permissions_test.go b/internal/api/authz/permissions_test.go
index 92e4407706..69877fd4cb 100644
--- a/internal/api/authz/permissions_test.go
+++ b/internal/api/authz/permissions_test.go
@@ -49,7 +49,7 @@ func equalStringArray(a, b []string) bool {
func Test_GetUserMethodPermissions(t *testing.T) {
type args struct {
- ctx context.Context
+ ctxData CtxData
verifier *TokenVerifier
requiredPerm string
authConfig Config
@@ -64,7 +64,7 @@ func Test_GetUserMethodPermissions(t *testing.T) {
{
name: "Empty Context",
args: args{
- ctx: getTestCtx("", ""),
+ ctxData: CtxData{},
verifier: Start(&testVerifier{grant: &Grant{
Roles: []string{"ORG_OWNER"},
}}),
@@ -89,7 +89,7 @@ func Test_GetUserMethodPermissions(t *testing.T) {
{
name: "No Grants",
args: args{
- ctx: getTestCtx("", ""),
+ ctxData: CtxData{},
verifier: Start(&testVerifier{grant: &Grant{}}),
requiredPerm: "project.read",
authConfig: Config{
@@ -110,9 +110,9 @@ func Test_GetUserMethodPermissions(t *testing.T) {
{
name: "Get Permissions",
args: args{
- ctx: getTestCtx("userID", "orgID"),
+ ctxData: CtxData{UserID: "userID", OrgID: "orgID"},
verifier: Start(&testVerifier{grant: &Grant{
- Roles: []string{"ORG_OWNER"},
+ Roles: []string{"IAM_OWNER"},
}}),
requiredPerm: "project.read",
authConfig: Config{
@@ -133,7 +133,7 @@ func Test_GetUserMethodPermissions(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- _, perms, err := getUserMethodPermissions(tt.args.ctx, tt.args.verifier, tt.args.requiredPerm, tt.args.authConfig)
+ _, perms, err := getUserMethodPermissions(context.Background(), tt.args.verifier, tt.args.requiredPerm, tt.args.authConfig, tt.args.ctxData)
if tt.wantErr && err == nil {
t.Errorf("got wrong result, should get err: actual: %v ", err)
diff --git a/internal/api/grpc/admin/administrator_converter.go b/internal/api/grpc/admin/administrator_converter.go
index 1f93d2496c..edd1691eaa 100644
--- a/internal/api/grpc/admin/administrator_converter.go
+++ b/internal/api/grpc/admin/administrator_converter.go
@@ -28,8 +28,8 @@ func failedEventsFromModel(failedEvents []*view_model.FailedEvent) []*admin.Fail
func viewFromModel(view *view_model.View) *admin.View {
eventTimestamp, err := ptypes.TimestampProto(view.EventTimestamp)
logging.Log("GRPC-KSo03").OnError(err).Debug("unable to parse timestamp")
- lastSpool, err := ptypes.TimestampProto(view.EventTimestamp)
- logging.Log("GRPC-KSo03").OnError(err).Debug("unable to parse timestamp")
+ lastSpool, err := ptypes.TimestampProto(view.LastSuccessfulSpoolerRun)
+ logging.Log("GRPC-0oP87").OnError(err).Debug("unable to parse timestamp")
return &admin.View{
Database: view.Database,
diff --git a/internal/api/grpc/auth/user.go b/internal/api/grpc/auth/user.go
index e2d94e9d47..f00ef7f872 100644
--- a/internal/api/grpc/auth/user.go
+++ b/internal/api/grpc/auth/user.go
@@ -2,6 +2,7 @@ package auth
import (
"context"
+
"github.com/golang/protobuf/ptypes/empty"
"github.com/caos/zitadel/pkg/grpc/auth"
@@ -162,6 +163,9 @@ func (s *Server) RemoveMfaOTP(ctx context.Context, _ *empty.Empty) (_ *empty.Emp
func (s *Server) AddMyMfaU2F(ctx context.Context, _ *empty.Empty) (_ *auth.WebAuthNResponse, err error) {
u2f, err := s.repo.AddMyMFAU2F(ctx)
+ if err != nil {
+ return nil, err
+ }
return verifyWebAuthNFromModel(u2f), err
}
@@ -175,8 +179,19 @@ func (s *Server) RemoveMyMfaU2F(ctx context.Context, id *auth.WebAuthNTokenID) (
return &empty.Empty{}, err
}
+func (s *Server) GetMyPasswordless(ctx context.Context, _ *empty.Empty) (_ *auth.WebAuthNTokens, err error) {
+ tokens, err := s.repo.GetMyPasswordless(ctx)
+ if err != nil {
+ return nil, err
+ }
+ return webAuthNTokensFromModel(tokens), err
+}
+
func (s *Server) AddMyPasswordless(ctx context.Context, _ *empty.Empty) (_ *auth.WebAuthNResponse, err error) {
u2f, err := s.repo.AddMyPasswordless(ctx)
+ if err != nil {
+ return nil, err
+ }
return verifyWebAuthNFromModel(u2f), err
}
diff --git a/internal/api/grpc/auth/user_converter.go b/internal/api/grpc/auth/user_converter.go
index 21e56f79fa..3251320201 100644
--- a/internal/api/grpc/auth/user_converter.go
+++ b/internal/api/grpc/auth/user_converter.go
@@ -436,3 +436,19 @@ func verifyWebAuthNFromModel(u2f *usr_model.WebAuthNToken) *auth.WebAuthNRespons
State: mfaStateFromModel(u2f.State),
}
}
+
+func webAuthNTokensFromModel(tokens []*usr_model.WebAuthNToken) *auth.WebAuthNTokens {
+ result := make([]*auth.WebAuthNToken, len(tokens))
+ for i, token := range tokens {
+ result[i] = webAuthNTokenFromModel(token)
+ }
+ return &auth.WebAuthNTokens{Tokens: result}
+}
+
+func webAuthNTokenFromModel(token *usr_model.WebAuthNToken) *auth.WebAuthNToken {
+ return &auth.WebAuthNToken{
+ Id: token.WebAuthNTokenID,
+ Name: token.WebAuthNTokenName,
+ State: mfaStateFromModel(token.State),
+ }
+}
diff --git a/internal/api/grpc/management/user.go b/internal/api/grpc/management/user.go
index 031503118c..b7151f070d 100644
--- a/internal/api/grpc/management/user.go
+++ b/internal/api/grpc/management/user.go
@@ -2,9 +2,11 @@ package management
import (
"context"
+
+ "github.com/golang/protobuf/ptypes/empty"
+
"github.com/caos/zitadel/internal/api/authz"
"github.com/caos/zitadel/pkg/grpc/management"
- "github.com/golang/protobuf/ptypes/empty"
)
func (s *Server) GetUserByID(ctx context.Context, id *management.UserID) (*management.UserView, error) {
@@ -226,6 +228,24 @@ func (s *Server) RemoveMfaOTP(ctx context.Context, userID *management.UserID) (*
return &empty.Empty{}, err
}
+func (s *Server) RemoveMfaU2F(ctx context.Context, webAuthNTokenID *management.WebAuthNTokenID) (*empty.Empty, error) {
+ err := s.user.RemoveU2F(ctx, webAuthNTokenID.UserId, webAuthNTokenID.Id)
+ return &empty.Empty{}, err
+}
+
+func (s *Server) GetPasswordless(ctx context.Context, userID *management.UserID) (_ *management.WebAuthNTokens, err error) {
+ tokens, err := s.user.GetPasswordless(ctx, userID.Id)
+ if err != nil {
+ return nil, err
+ }
+ return webAuthNTokensFromModel(tokens), err
+}
+
+func (s *Server) RemovePasswordless(ctx context.Context, id *management.WebAuthNTokenID) (*empty.Empty, error) {
+ err := s.user.RemovePasswordless(ctx, id.UserId, id.Id)
+ return &empty.Empty{}, err
+}
+
func (s *Server) SearchUserMemberships(ctx context.Context, in *management.UserMembershipSearchRequest) (*management.UserMembershipSearchResponse, error) {
request := userMembershipSearchRequestsToModel(in)
request.AppendUserIDQuery(in.UserId)
diff --git a/internal/api/grpc/management/user_converter.go b/internal/api/grpc/management/user_converter.go
index 645a07c0ea..ced79f4948 100644
--- a/internal/api/grpc/management/user_converter.go
+++ b/internal/api/grpc/management/user_converter.go
@@ -2,14 +2,15 @@ package management
import (
"encoding/json"
+
"github.com/caos/logging"
- "github.com/caos/zitadel/internal/model"
"github.com/golang/protobuf/ptypes"
"golang.org/x/text/language"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/types/known/structpb"
"github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/model"
usr_model "github.com/caos/zitadel/internal/user/model"
"github.com/caos/zitadel/pkg/grpc/management"
"github.com/caos/zitadel/pkg/grpc/message"
@@ -504,6 +505,7 @@ func mfaFromModel(mfa *usr_model.MultiFactor) *management.UserMultiFactor {
State: mfaStateFromModel(mfa.State),
Type: mfaTypeFromModel(mfa.Type),
Attribute: mfa.Attribute,
+ Id: mfa.ID,
}
}
@@ -627,3 +629,19 @@ func userChangesToMgtAPI(changes *usr_model.UserChanges) (_ []*management.Change
return result
}
+
+func webAuthNTokensFromModel(tokens []*usr_model.WebAuthNToken) *management.WebAuthNTokens {
+ result := make([]*management.WebAuthNToken, len(tokens))
+ for i, token := range tokens {
+ result[i] = webAuthNTokenFromModel(token)
+ }
+ return &management.WebAuthNTokens{Tokens: result}
+}
+
+func webAuthNTokenFromModel(token *usr_model.WebAuthNToken) *management.WebAuthNToken {
+ return &management.WebAuthNToken{
+ Id: token.WebAuthNTokenID,
+ Name: token.WebAuthNTokenName,
+ State: mfaStateFromModel(token.State),
+ }
+}
diff --git a/internal/api/grpc/server/middleware/auth_interceptor.go b/internal/api/grpc/server/middleware/auth_interceptor.go
index 347e0b18f9..165be2a6f9 100644
--- a/internal/api/grpc/server/middleware/auth_interceptor.go
+++ b/internal/api/grpc/server/middleware/auth_interceptor.go
@@ -25,20 +25,20 @@ func authorize(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo,
return handler(ctx, req)
}
- ctx, span := tracing.NewServerInterceptorSpan(ctx)
+ authCtx, span := tracing.NewServerInterceptorSpan(ctx)
defer func() { span.EndWithError(err) }()
- authToken := grpc_util.GetAuthorizationHeader(ctx)
+ authToken := grpc_util.GetAuthorizationHeader(authCtx)
if authToken == "" {
return nil, status.Error(codes.Unauthenticated, "auth header missing")
}
- orgID := grpc_util.GetHeader(ctx, http.ZitadelOrgID)
+ orgID := grpc_util.GetHeader(authCtx, http.ZitadelOrgID)
- ctx, err = authz.CheckUserAuthorization(ctx, req, authToken, orgID, verifier, authConfig, authOpt, info.FullMethod)
+ ctxSetter, err := authz.CheckUserAuthorization(authCtx, req, authToken, orgID, verifier, authConfig, authOpt, info.FullMethod)
if err != nil {
return nil, err
}
span.End()
- return handler(ctx, req)
+ return handler(ctxSetter(ctx), req)
}
diff --git a/internal/api/oidc/client.go b/internal/api/oidc/client.go
index 760c8a007d..39fffdba0d 100644
--- a/internal/api/oidc/client.go
+++ b/internal/api/oidc/client.go
@@ -2,17 +2,16 @@ package oidc
import (
"context"
- "github.com/caos/zitadel/internal/auth_request/model"
"strings"
- "golang.org/x/text/language"
- "gopkg.in/square/go-jose.v2"
-
"github.com/caos/oidc/pkg/oidc"
"github.com/caos/oidc/pkg/op"
+ "golang.org/x/text/language"
+ "gopkg.in/square/go-jose.v2"
"github.com/caos/zitadel/internal/api/authz"
"github.com/caos/zitadel/internal/api/http"
+ "github.com/caos/zitadel/internal/auth_request/model"
"github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/errors"
proj_model "github.com/caos/zitadel/internal/project/model"
@@ -155,7 +154,7 @@ func (o *OPStorage) GetUserinfoFromScopes(ctx context.Context, userID, applicati
roles = append(roles, strings.TrimPrefix(scope, ScopeProjectRolePrefix))
}
if strings.HasPrefix(scope, model.OrgDomainPrimaryScope) {
- userInfo.AppendClaims(model.OrgDomainPrimaryScope, strings.TrimPrefix(scope, model.OrgDomainPrimaryScope))
+ userInfo.AppendClaims(model.OrgDomainPrimaryClaim, strings.TrimPrefix(scope, model.OrgDomainPrimaryScope))
}
}
}
@@ -180,7 +179,7 @@ func (o *OPStorage) GetPrivateClaimsFromScopes(ctx context.Context, userID, clie
if strings.HasPrefix(scope, ScopeProjectRolePrefix) {
roles = append(roles, strings.TrimPrefix(scope, ScopeProjectRolePrefix))
} else if strings.HasPrefix(scope, model.OrgDomainPrimaryScope) {
- claims = map[string]interface{}{model.OrgDomainPrimaryScope: strings.TrimPrefix(scope, model.OrgDomainPrimaryScope)}
+ claims = appendClaim(claims, model.OrgDomainPrimaryClaim, strings.TrimPrefix(scope, model.OrgDomainPrimaryScope))
}
}
if len(roles) == 0 || clientID == "" {
@@ -191,7 +190,7 @@ func (o *OPStorage) GetPrivateClaimsFromScopes(ctx context.Context, userID, clie
return nil, err
}
if len(projectRoles) > 0 {
- claims = map[string]interface{}{ClaimProjectRoles: projectRoles}
+ claims = appendClaim(claims, ClaimProjectRoles, projectRoles)
}
return claims, err
}
@@ -240,3 +239,11 @@ func getGender(gender user_model.Gender) string {
}
return ""
}
+
+func appendClaim(claims map[string]interface{}, claim string, value interface{}) map[string]interface{} {
+ if claims == nil {
+ claims = make(map[string]interface{})
+ }
+ claims[claim] = value
+ return claims
+}
diff --git a/internal/auth/repository/auth_request.go b/internal/auth/repository/auth_request.go
index 3aaab44596..8425c68a06 100644
--- a/internal/auth/repository/auth_request.go
+++ b/internal/auth/repository/auth_request.go
@@ -30,6 +30,4 @@ type AuthRequestRepository interface {
LinkExternalUsers(ctx context.Context, authReqID, userAgentID string, info *model.BrowserInfo) error
AutoRegisterExternalUser(ctx context.Context, user *user_model.User, externalIDP *user_model.ExternalIDP, member *org_model.OrgMember, authReqID, userAgentID, resourceOwner string, info *model.BrowserInfo) error
ResetLinkingUsers(ctx context.Context, authReqID, userAgentID string) error
-
- GetOrgByPrimaryDomain(primaryDomain string) (*org_model.OrgView, error)
}
diff --git a/internal/auth/repository/eventsourcing/eventstore/auth_request.go b/internal/auth/repository/eventsourcing/eventstore/auth_request.go
index 68189e5890..92ef6aada6 100644
--- a/internal/auth/repository/eventsourcing/eventstore/auth_request.go
+++ b/internal/auth/repository/eventsourcing/eventstore/auth_request.go
@@ -110,6 +110,9 @@ func (repo *AuthRequestRepo) CreateAuthRequest(ctx context.Context, request *mod
}
request.Audience = appIDs
request.AppendAudIfNotExisting(app.ProjectID)
+ if err := setOrgID(repo.OrgViewProvider, request); err != nil {
+ return nil, err
+ }
if request.LoginHint != "" {
err = repo.checkLoginName(ctx, request, request.LoginHint)
logging.LogWithFields("EVENT-aG311", "login name", request.LoginHint, "id", request.ID, "applicationID", request.ApplicationID, "traceID", tracing.TraceIDFromCtx(ctx)).OnError(err).Debug("login hint invalid")
@@ -238,6 +241,9 @@ func (repo *AuthRequestRepo) SelectUser(ctx context.Context, id, userID, userAge
if err != nil {
return err
}
+ if request.RequestedOrgID != "" && request.RequestedOrgID != user.ResourceOwner {
+ return errors.ThrowPreconditionFailed(nil, "EVENT-fJe2a", "Errors.User.NotAllowedOrg")
+ }
request.SetUserInfo(user.ID, user.PreferredLoginName, user.DisplayName, user.ResourceOwner)
return repo.AuthRequests.UpdateAuthRequest(ctx, request)
}
@@ -442,16 +448,9 @@ func (repo *AuthRequestRepo) getLoginPolicyAndIDPProviders(ctx context.Context,
}
func (repo *AuthRequestRepo) fillLoginPolicy(ctx context.Context, request *model.AuthRequest) error {
- orgID := request.UserOrgID
+ orgID := request.RequestedOrgID
if orgID == "" {
- primaryDomain := request.GetScopeOrgPrimaryDomain()
- if primaryDomain != "" {
- org, err := repo.GetOrgByPrimaryDomain(primaryDomain)
- if err != nil {
- return err
- }
- orgID = org.ID
- }
+ orgID = request.UserOrgID
}
if orgID == "" {
orgID = repo.IAMID
@@ -469,19 +468,9 @@ func (repo *AuthRequestRepo) fillLoginPolicy(ctx context.Context, request *model
}
func (repo *AuthRequestRepo) checkLoginName(ctx context.Context, request *model.AuthRequest, loginName string) (err error) {
- primaryDomain := request.GetScopeOrgPrimaryDomain()
- orgID := ""
- if primaryDomain != "" {
- org, err := repo.GetOrgByPrimaryDomain(primaryDomain)
- if err != nil {
- return err
- }
- orgID = org.ID
- }
-
user := new(user_view_model.UserView)
- if orgID != "" {
- user, err = repo.View.UserByLoginNameAndResourceOwner(loginName, orgID)
+ if request.RequestedOrgID != "" {
+ user, err = repo.View.UserByLoginNameAndResourceOwner(loginName, request.RequestedOrgID)
} else {
user, err = repo.View.UserByLoginName(loginName)
if err == nil {
@@ -499,14 +488,6 @@ func (repo *AuthRequestRepo) checkLoginName(ctx context.Context, request *model.
return nil
}
-func (repo AuthRequestRepo) GetOrgByPrimaryDomain(primaryDomain string) (*org_model.OrgView, error) {
- org, err := repo.OrgViewProvider.OrgByPrimaryDomain(primaryDomain)
- if err != nil {
- return nil, err
- }
- return org_view_model.OrgToModel(org), nil
-}
-
func (repo AuthRequestRepo) checkLoginPolicyWithResourceOwner(ctx context.Context, request *model.AuthRequest, user *user_view_model.UserView) error {
loginPolicy, idpProviders, err := repo.getLoginPolicyAndIDPProviders(ctx, user.ResourceOwner)
if err != nil {
@@ -537,15 +518,9 @@ func (repo *AuthRequestRepo) checkSelectedExternalIDP(request *model.AuthRequest
}
func (repo *AuthRequestRepo) checkExternalUserLogin(request *model.AuthRequest, idpConfigID, externalUserID string) (err error) {
- primaryDomain := request.GetScopeOrgPrimaryDomain()
externalIDP := new(user_view_model.ExternalIDPView)
- org := new(org_model.OrgView)
- if primaryDomain != "" {
- org, err = repo.GetOrgByPrimaryDomain(primaryDomain)
- if err != nil {
- return err
- }
- externalIDP, err = repo.View.ExternalIDPByExternalUserIDAndIDPConfigIDAndResourceOwner(externalUserID, idpConfigID, org.ID)
+ if request.RequestedOrgID != "" {
+ externalIDP, err = repo.View.ExternalIDPByExternalUserIDAndIDPConfigIDAndResourceOwner(externalUserID, idpConfigID, request.RequestedOrgID)
} else {
externalIDP, err = repo.View.ExternalIDPByExternalUserIDAndIDPConfigID(externalUserID, idpConfigID)
}
@@ -653,10 +628,11 @@ func (repo *AuthRequestRepo) usersForUserSelection(request *model.AuthRequest) (
users := make([]model.UserSelection, len(userSessions))
for i, session := range userSessions {
users[i] = model.UserSelection{
- UserID: session.UserID,
- DisplayName: session.DisplayName,
- LoginName: session.LoginName,
- UserSessionState: session.State,
+ UserID: session.UserID,
+ DisplayName: session.DisplayName,
+ LoginName: session.LoginName,
+ UserSessionState: session.State,
+ SelectionPossible: request.RequestedOrgID == "" || request.RequestedOrgID == session.ResourceOwner,
}
}
return users, nil
@@ -667,24 +643,28 @@ func (repo *AuthRequestRepo) firstFactorChecked(request *model.AuthRequest, user
return &model.InitUserStep{PasswordSet: user.PasswordSet}
}
- if user.IsPasswordlessReady() {
- if !checkVerificationTime(userSession.PasswordlessVerification, repo.MultiFactorCheckLifeTime) {
- return &model.PasswordlessStep{}
+ var step model.NextStep
+ if request.LoginPolicy.PasswordlessType != iam_model.PasswordlessTypeNotAllowed && user.IsPasswordlessReady() {
+ if checkVerificationTime(userSession.PasswordlessVerification, repo.MultiFactorCheckLifeTime) {
+ request.AuthTime = userSession.PasswordlessVerification
+ return nil
}
- request.AuthTime = userSession.PasswordlessVerification
- return nil
+ step = &model.PasswordlessStep{}
}
if !user.PasswordSet {
return &model.InitPasswordStep{}
}
- if !checkVerificationTime(userSession.PasswordVerification, repo.PasswordCheckLifeTime) {
- return &model.PasswordStep{}
+ if checkVerificationTime(userSession.PasswordVerification, repo.PasswordCheckLifeTime) {
+ request.PasswordVerified = true
+ request.AuthTime = userSession.PasswordVerification
+ return nil
}
- request.PasswordVerified = true
- request.AuthTime = userSession.PasswordVerification
- return nil
+ if step != nil {
+ return step
+ }
+ return &model.PasswordStep{}
}
func (repo *AuthRequestRepo) mfaChecked(userSession *user_model.UserSessionView, request *model.AuthRequest, user *user_model.UserView) (model.NextStep, bool, error) {
@@ -753,6 +733,21 @@ func (repo *AuthRequestRepo) getLoginPolicy(ctx context.Context, orgID string) (
return iam_es_model.LoginPolicyViewToModel(policy), err
}
+func setOrgID(orgViewProvider orgViewProvider, request *model.AuthRequest) error {
+ primaryDomain := request.GetScopeOrgPrimaryDomain()
+ if primaryDomain == "" {
+ return nil
+ }
+
+ org, err := orgViewProvider.OrgByPrimaryDomain(primaryDomain)
+ if err != nil {
+ return err
+ }
+ request.RequestedOrgID = org.ID
+ request.RequestedOrgName = org.Name
+ return nil
+}
+
func getLoginPolicyIDPProviders(provider idpProviderViewProvider, iamID, orgID string, defaultPolicy bool) ([]*iam_model.IDPProviderView, error) {
if defaultPolicy {
idpProviders, err := provider.IDPProvidersByAggregateIDAndState(iamID, iam_model.IDPConfigStateActive)
@@ -824,9 +819,8 @@ func userSessionByIDs(ctx context.Context, provider userSessionViewProvider, eve
case es_model.UserRemoved:
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dG2fe", "Errors.User.NotActive")
}
- if err := sessionCopy.AppendEvent(event); err != nil {
- return user_view_model.UserSessionToModel(&sessionCopy), nil
- }
+ err := sessionCopy.AppendEvent(event)
+ logging.Log("EVENT-qbhj3").OnError(err).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Warn("error appending event")
}
return user_view_model.UserSessionToModel(&sessionCopy), nil
}
diff --git a/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go b/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go
index c3de87ad30..f6085c1ebf 100644
--- a/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go
+++ b/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go
@@ -56,8 +56,9 @@ type mockViewUserSession struct {
}
type mockUser struct {
- UserID string
- LoginName string
+ UserID string
+ LoginName string
+ ResourceOwner string
}
func (m *mockViewUserSession) UserSessionByIDs(string, string) (*user_view_model.UserSessionView, error) {
@@ -74,8 +75,9 @@ func (m *mockViewUserSession) UserSessionsByAgentID(string) ([]*user_view_model.
sessions := make([]*user_view_model.UserSessionView, len(m.Users))
for i, user := range m.Users {
sessions[i] = &user_view_model.UserSessionView{
- UserID: user.UserID,
- LoginName: user.LoginName,
+ UserID: user.UserID,
+ LoginName: user.LoginName,
+ ResourceOwner: user.ResourceOwner,
}
}
return sessions, nil
@@ -270,10 +272,12 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
{
"id1",
"loginname1",
+ "orgID1",
},
{
"id2",
"loginname2",
+ "orgID2",
},
},
},
@@ -285,12 +289,52 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
&model.SelectUserStep{
Users: []model.UserSelection{
{
- UserID: "id1",
- LoginName: "loginname1",
+ UserID: "id1",
+ LoginName: "loginname1",
+ SelectionPossible: true,
},
{
- UserID: "id2",
- LoginName: "loginname2",
+ UserID: "id2",
+ LoginName: "loginname2",
+ SelectionPossible: true,
+ },
+ },
+ }},
+ nil,
+ },
+ {
+ "user not set, primary domain set, prompt select account, login and select account steps",
+ fields{
+ userSessionViewProvider: &mockViewUserSession{
+ Users: []mockUser{
+ {
+ "id1",
+ "loginname1",
+ "orgID1",
+ },
+ {
+ "id2",
+ "loginname2",
+ "orgID2",
+ },
+ },
+ },
+ userEventProvider: &mockEventUser{},
+ },
+ args{&model.AuthRequest{Prompt: model.PromptSelectAccount, RequestedOrgID: "orgID1"}, false},
+ []model.NextStep{
+ &model.LoginStep{},
+ &model.SelectUserStep{
+ Users: []model.UserSelection{
+ {
+ UserID: "id1",
+ LoginName: "loginname1",
+ SelectionPossible: true,
+ },
+ {
+ UserID: "id2",
+ LoginName: "loginname2",
+ SelectionPossible: false,
},
},
}},
@@ -386,7 +430,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
},
- args{&model.AuthRequest{UserID: "UserID"}, false},
+ args{&model.AuthRequest{UserID: "UserID", LoginPolicy: &iam_model.LoginPolicyView{}}, false},
[]model.NextStep{&model.PasswordStep{}},
nil,
},
@@ -431,7 +475,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
MultiFactorCheckLifeTime: 10 * time.Hour,
},
- args{&model.AuthRequest{UserID: "UserID"}, false},
+ args{&model.AuthRequest{UserID: "UserID", LoginPolicy: &iam_model.LoginPolicyView{PasswordlessType: iam_model.PasswordlessTypeAllowed}}, false},
[]model.NextStep{&model.PasswordlessStep{}},
nil,
},
@@ -456,7 +500,8 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
args{&model.AuthRequest{
UserID: "UserID",
LoginPolicy: &iam_model.LoginPolicyView{
- MultiFactors: []iam_model.MultiFactorType{iam_model.MultiFactorTypeU2FWithPIN},
+ PasswordlessType: iam_model.PasswordlessTypeAllowed,
+ MultiFactors: []iam_model.MultiFactorType{iam_model.MultiFactorTypeU2FWithPIN},
},
}, false},
[]model.NextStep{&model.VerifyEMailStep{}},
@@ -470,7 +515,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
},
- args{&model.AuthRequest{UserID: "UserID"}, false},
+ args{&model.AuthRequest{UserID: "UserID", LoginPolicy: &iam_model.LoginPolicyView{}}, false},
[]model.NextStep{&model.InitPasswordStep{}},
nil,
},
@@ -534,7 +579,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
PasswordCheckLifeTime: 10 * 24 * time.Hour,
},
- args{&model.AuthRequest{UserID: "UserID"}, false},
+ args{&model.AuthRequest{UserID: "UserID", LoginPolicy: &iam_model.LoginPolicyView{}}, false},
[]model.NextStep{&model.PasswordStep{}},
nil,
},
@@ -566,6 +611,35 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
[]model.NextStep{&model.RedirectToCallbackStep{}},
nil,
},
+ {
+ "password verified, passwordless set up, mfa not verified, mfa check step",
+ fields{
+ userSessionViewProvider: &mockViewUserSession{
+ PasswordVerification: time.Now().UTC().Add(-5 * time.Minute),
+ },
+ userViewProvider: &mockViewUser{
+ PasswordSet: true,
+ PasswordlessTokens: user_view_model.WebAuthNTokens{&user_view_model.WebAuthNView{ID: "id", State: int32(user_model.MFAStateReady)}},
+ OTPState: int32(user_model.MFAStateReady),
+ MFAMaxSetUp: int32(model.MFALevelMultiFactor),
+ },
+ userEventProvider: &mockEventUser{},
+ orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
+ PasswordCheckLifeTime: 10 * 24 * time.Hour,
+ SecondFactorCheckLifeTime: 18 * time.Hour,
+ },
+ args{
+ &model.AuthRequest{
+ UserID: "UserID",
+ LoginPolicy: &iam_model.LoginPolicyView{
+ SecondFactors: []iam_model.SecondFactorType{iam_model.SecondFactorTypeOTP},
+ },
+ }, false},
+ []model.NextStep{&model.MFAVerificationStep{
+ MFAProviders: []model.MFAType{model.MFATypeOTP},
+ }},
+ nil,
+ },
{
"mfa not verified, mfa check step",
fields{
@@ -843,6 +917,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
args{
&model.AuthRequest{
UserID: "UserID",
+ LoginPolicy: &iam_model.LoginPolicyView{},
SelectedIDPConfigID: "IDPConfigID",
LinkingUsers: []*model.ExternalUser{{IDPConfigID: "IDPConfigID", ExternalUserID: "UserID", DisplayName: "DisplayName"}},
}, false},
diff --git a/internal/auth/repository/eventsourcing/eventstore/org.go b/internal/auth/repository/eventsourcing/eventstore/org.go
index c5f3ecced0..9339b1be70 100644
--- a/internal/auth/repository/eventsourcing/eventstore/org.go
+++ b/internal/auth/repository/eventsourcing/eventstore/org.go
@@ -36,7 +36,7 @@ type OrgRepository struct {
func (repo *OrgRepository) SearchOrgs(ctx context.Context, request *org_model.OrgSearchRequest) (*org_model.OrgSearchResult, error) {
request.EnsureLimit(repo.SearchLimit)
- sequence, err := repo.View.GetLatestOrgSequence()
+ sequence, err := repo.View.GetLatestOrgSequence("")
logging.Log("EVENT-7Udhz").OnError(err).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Warn("could not read latest org sequence")
members, count, err := repo.View.SearchOrgs(request)
if err != nil {
diff --git a/internal/auth/repository/eventsourcing/eventstore/user.go b/internal/auth/repository/eventsourcing/eventstore/user.go
index 7fffb728d8..392ff2a793 100644
--- a/internal/auth/repository/eventsourcing/eventstore/user.go
+++ b/internal/auth/repository/eventsourcing/eventstore/user.go
@@ -109,7 +109,7 @@ func (repo *UserRepo) ChangeMyProfile(ctx context.Context, profile *model.Profil
func (repo *UserRepo) SearchMyExternalIDPs(ctx context.Context, request *model.ExternalIDPSearchRequest) (*model.ExternalIDPSearchResponse, error) {
request.EnsureLimit(repo.SearchLimit)
- sequence, seqErr := repo.View.GetLatestExternalIDPSequence()
+ sequence, seqErr := repo.View.GetLatestExternalIDPSequence("")
logging.Log("EVENT-5Jsi8").OnError(seqErr).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Warn("could not read latest user sequence")
request.AppendUserQuery(authz.GetCtxData(ctx).UserID)
externalIDPS, count, err := repo.View.SearchExternalIDPs(request)
@@ -303,11 +303,26 @@ func (repo *UserRepo) RemoveMyMFAOTP(ctx context.Context) error {
}
func (repo *UserRepo) AddMFAU2F(ctx context.Context, userID string) (*model.WebAuthNToken, error) {
- return repo.UserEvents.AddU2F(ctx, userID, true)
+ accountName := ""
+ user, err := repo.UserByID(ctx, userID)
+ if err != nil {
+ logging.Log("EVENT-DAqe1").WithError(err).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Debug("unable to get user for loginname")
+ } else {
+ accountName = user.PreferredLoginName
+ }
+ return repo.UserEvents.AddU2F(ctx, userID, accountName, true)
}
func (repo *UserRepo) AddMyMFAU2F(ctx context.Context) (*model.WebAuthNToken, error) {
- return repo.UserEvents.AddU2F(ctx, authz.GetCtxData(ctx).UserID, false)
+ userID := authz.GetCtxData(ctx).UserID
+ accountName := ""
+ user, err := repo.UserByID(ctx, userID)
+ if err != nil {
+ logging.Log("EVENT-Ghwl1").WithError(err).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Debug("unable to get user for loginname")
+ } else {
+ accountName = user.PreferredLoginName
+ }
+ return repo.UserEvents.AddU2F(ctx, userID, accountName, false)
}
func (repo *UserRepo) VerifyMFAU2FSetup(ctx context.Context, userID, tokenName, userAgentID string, credentialData []byte) error {
@@ -326,12 +341,35 @@ func (repo *UserRepo) RemoveMyMFAU2F(ctx context.Context, webAuthNTokenID string
return repo.UserEvents.RemoveU2FToken(ctx, authz.GetCtxData(ctx).UserID, webAuthNTokenID)
}
+func (repo *UserRepo) GetPasswordless(ctx context.Context, userID string) ([]*model.WebAuthNToken, error) {
+ return repo.UserEvents.GetPasswordless(ctx, userID)
+}
+
func (repo *UserRepo) AddPasswordless(ctx context.Context, userID string) (*model.WebAuthNToken, error) {
- return repo.UserEvents.AddPasswordless(ctx, userID, true)
+ accountName := ""
+ user, err := repo.UserByID(ctx, userID)
+ if err != nil {
+ logging.Log("EVENT-Vj2k1").WithError(err).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Debug("unable to get user for loginname")
+ } else {
+ accountName = user.PreferredLoginName
+ }
+ return repo.UserEvents.AddPasswordless(ctx, userID, accountName, true)
+}
+
+func (repo *UserRepo) GetMyPasswordless(ctx context.Context) ([]*model.WebAuthNToken, error) {
+ return repo.UserEvents.GetPasswordless(ctx, authz.GetCtxData(ctx).UserID)
}
func (repo *UserRepo) AddMyPasswordless(ctx context.Context) (*model.WebAuthNToken, error) {
- return repo.UserEvents.AddPasswordless(ctx, authz.GetCtxData(ctx).UserID, false)
+ userID := authz.GetCtxData(ctx).UserID
+ accountName := ""
+ user, err := repo.UserByID(ctx, userID)
+ if err != nil {
+ logging.Log("EVENT-AEq21").WithError(err).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Debug("unable to get user for loginname")
+ } else {
+ accountName = user.PreferredLoginName
+ }
+ return repo.UserEvents.AddPasswordless(ctx, authz.GetCtxData(ctx).UserID, accountName, false)
}
func (repo *UserRepo) VerifyPasswordlessSetup(ctx context.Context, userID, tokenName, userAgentID string, credentialData []byte) error {
diff --git a/internal/auth/repository/eventsourcing/eventstore/user_grant.go b/internal/auth/repository/eventsourcing/eventstore/user_grant.go
index cba39e4314..d9ba6bc842 100644
--- a/internal/auth/repository/eventsourcing/eventstore/user_grant.go
+++ b/internal/auth/repository/eventsourcing/eventstore/user_grant.go
@@ -29,7 +29,7 @@ type UserGrantRepo struct {
func (repo *UserGrantRepo) SearchMyUserGrants(ctx context.Context, request *grant_model.UserGrantSearchRequest) (*grant_model.UserGrantSearchResponse, error) {
request.EnsureLimit(repo.SearchLimit)
- sequence, err := repo.View.GetLatestUserGrantSequence()
+ sequence, err := repo.View.GetLatestUserGrantSequence("")
logging.Log("EVENT-Hd7s3").OnError(err).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Warn("could not read latest user grant sequence")
request.Queries = append(request.Queries, &grant_model.UserGrantSearchQuery{Key: grant_model.UserGrantSearchKeyUserID, Method: global_model.SearchMethodEquals, Value: authz.GetCtxData(ctx).UserID})
grants, count, err := repo.View.SearchUserGrants(request)
diff --git a/internal/auth/repository/eventsourcing/handler/application.go b/internal/auth/repository/eventsourcing/handler/application.go
index 377e0b0499..5a8d5d41ff 100644
--- a/internal/auth/repository/eventsourcing/handler/application.go
+++ b/internal/auth/repository/eventsourcing/handler/application.go
@@ -5,7 +5,9 @@ import (
"github.com/caos/logging"
+ "github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
"github.com/caos/zitadel/internal/project/repository/eventsourcing"
proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing"
@@ -13,19 +15,52 @@ import (
view_model "github.com/caos/zitadel/internal/project/repository/view/model"
)
-type Application struct {
- handler
- projectEvents *proj_event.ProjectEventstore
-}
-
const (
applicationTable = "auth.applications"
)
+type Application struct {
+ handler
+ projectEvents *proj_event.ProjectEventstore
+ subscription *eventstore.Subscription
+}
+
+func newApplication(handler handler, projectEvents *proj_event.ProjectEventstore) *Application {
+ h := &Application{
+ handler: handler,
+ projectEvents: projectEvents,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (a *Application) subscribe() {
+ a.subscription = a.es.Subscribe(a.AggregateTypes()...)
+ go func() {
+ for event := range a.subscription.Events {
+ query.ReduceEvent(a, event)
+ }
+ }()
+}
+
func (a *Application) ViewModel() string {
return applicationTable
}
+func (_ *Application) AggregateTypes() []models.AggregateType {
+ return []models.AggregateType{es_model.ProjectAggregate}
+}
+
+func (a *Application) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := a.view.GetLatestApplicationSequence()
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (a *Application) EventQuery() (*models.SearchQuery, error) {
sequence, err := a.view.GetLatestApplicationSequence()
if err != nil {
@@ -65,30 +100,33 @@ func (a *Application) Reduce(event *models.Event) (err error) {
if err != nil {
return err
}
- return a.view.DeleteApplication(app.ID, event.Sequence, event.CreationDate)
+ return a.view.DeleteApplication(app.ID, event)
case es_model.ProjectChanged:
apps, err := a.view.ApplicationsByProjectID(event.AggregateID)
if err != nil {
return err
}
if len(apps) == 0 {
- return a.view.ProcessedApplicationSequence(event.Sequence, event.CreationDate)
+ return a.view.ProcessedApplicationSequence(event)
}
for _, app := range apps {
if err := app.AppendEvent(event); err != nil {
return err
}
}
- return a.view.PutApplications(apps, event.Sequence, event.CreationDate)
+ return a.view.PutApplications(apps, event)
case es_model.ProjectRemoved:
- return a.view.DeleteApplicationsByProjectID(event.AggregateID)
+ err = a.view.DeleteApplicationsByProjectID(event.AggregateID)
+ if err == nil {
+ return a.view.ProcessedApplicationSequence(event)
+ }
default:
- return a.view.ProcessedApplicationSequence(event.Sequence, event.CreationDate)
+ return a.view.ProcessedApplicationSequence(event)
}
if err != nil {
return err
}
- return a.view.PutApplication(app, event.CreationDate)
+ return a.view.PutApplication(app, event)
}
func (a *Application) OnError(event *models.Event, spoolerError error) error {
diff --git a/internal/auth/repository/eventsourcing/handler/handler.go b/internal/auth/repository/eventsourcing/handler/handler.go
index d641ec39db..c5825c5abe 100644
--- a/internal/auth/repository/eventsourcing/handler/handler.go
+++ b/internal/auth/repository/eventsourcing/handler/handler.go
@@ -26,6 +26,12 @@ type handler struct {
bulkLimit uint64
cycleDuration time.Duration
errorCountUntilSkip uint64
+
+ es eventstore.Eventstore
+}
+
+func (h *handler) Eventstore() eventstore.Eventstore {
+ return h.es
}
type EventstoreRepos struct {
@@ -35,39 +41,65 @@ type EventstoreRepos struct {
IamEvents *iam_events.IAMEventstore
}
-func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, eventstore eventstore.Eventstore, repos EventstoreRepos, systemDefaults sd.SystemDefaults) []query.Handler {
+func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es eventstore.Eventstore, repos EventstoreRepos, systemDefaults sd.SystemDefaults) []query.Handler {
return []query.Handler{
- &User{handler: handler{view, bulkLimit, configs.cycleDuration("User"), errorCount},
- orgEvents: repos.OrgEvents, iamEvents: repos.IamEvents, iamID: systemDefaults.IamID},
- &UserSession{handler: handler{view, bulkLimit, configs.cycleDuration("UserSession"), errorCount}, userEvents: repos.UserEvents},
- &UserMembership{handler: handler{view, bulkLimit, configs.cycleDuration("UserMembership"), errorCount}, orgEvents: repos.OrgEvents, projectEvents: repos.ProjectEvents},
- &Token{handler: handler{view, bulkLimit, configs.cycleDuration("Token"), errorCount}, ProjectEvents: repos.ProjectEvents},
- &Key{handler: handler{view, bulkLimit, configs.cycleDuration("Key"), errorCount}},
- &Application{handler: handler{view, bulkLimit, configs.cycleDuration("Application"), errorCount}, projectEvents: repos.ProjectEvents},
- &Org{handler: handler{view, bulkLimit, configs.cycleDuration("Org"), errorCount}},
- &UserGrant{
- handler: handler{view, bulkLimit, configs.cycleDuration("UserGrant"), errorCount},
- eventstore: eventstore,
- userEvents: repos.UserEvents,
- orgEvents: repos.OrgEvents,
- projectEvents: repos.ProjectEvents,
- iamEvents: repos.IamEvents,
- iamID: systemDefaults.IamID},
- &MachineKeys{handler: handler{view, bulkLimit, configs.cycleDuration("MachineKey"), errorCount}},
- &LoginPolicy{handler: handler{view, bulkLimit, configs.cycleDuration("LoginPolicy"), errorCount}},
- &IDPConfig{handler: handler{view, bulkLimit, configs.cycleDuration("IDPConfig"), errorCount}},
- &IDPProvider{handler: handler{view, bulkLimit, configs.cycleDuration("IDPProvider"), errorCount}, systemDefaults: systemDefaults, orgEvents: repos.OrgEvents, iamEvents: repos.IamEvents},
- &ExternalIDP{handler: handler{view, bulkLimit, configs.cycleDuration("ExternalIDP"), errorCount}, systemDefaults: systemDefaults, orgEvents: repos.OrgEvents, iamEvents: repos.IamEvents},
- &PasswordComplexityPolicy{handler: handler{view, bulkLimit, configs.cycleDuration("PasswordComplexityPolicy"), errorCount}},
- &OrgIAMPolicy{handler: handler{view, bulkLimit, configs.cycleDuration("OrgIAMPolicy"), errorCount}},
- &ProjectRole{handler: handler{view, bulkLimit, configs.cycleDuration("ProjectRole"), errorCount}, projectEvents: repos.ProjectEvents},
+ newUser(
+ handler{view, bulkLimit, configs.cycleDuration("User"), errorCount, es},
+ repos.OrgEvents,
+ repos.IamEvents,
+ systemDefaults.IamID),
+ newUserSession(
+ handler{view, bulkLimit, configs.cycleDuration("UserSession"), errorCount, es},
+ repos.UserEvents),
+ newUserMembership(
+ handler{view, bulkLimit, configs.cycleDuration("UserMembership"), errorCount, es},
+ repos.OrgEvents,
+ repos.ProjectEvents),
+ newToken(
+ handler{view, bulkLimit, configs.cycleDuration("Token"), errorCount, es},
+ repos.ProjectEvents),
+ newKey(
+ handler{view, bulkLimit, configs.cycleDuration("Key"), errorCount, es}),
+ newApplication(handler{view, bulkLimit, configs.cycleDuration("Application"), errorCount, es},
+ repos.ProjectEvents),
+ newOrg(
+ handler{view, bulkLimit, configs.cycleDuration("Org"), errorCount, es}),
+ newUserGrant(
+ handler{view, bulkLimit, configs.cycleDuration("UserGrant"), errorCount, es},
+ repos.ProjectEvents,
+ repos.UserEvents,
+ repos.OrgEvents,
+ repos.IamEvents,
+ systemDefaults.IamID),
+ newMachineKeys(
+ handler{view, bulkLimit, configs.cycleDuration("MachineKey"), errorCount, es}),
+ newLoginPolicy(
+ handler{view, bulkLimit, configs.cycleDuration("LoginPolicy"), errorCount, es}),
+ newIDPConfig(
+ handler{view, bulkLimit, configs.cycleDuration("IDPConfig"), errorCount, es}),
+ newIDPProvider(
+ handler{view, bulkLimit, configs.cycleDuration("IDPProvider"), errorCount, es},
+ systemDefaults,
+ repos.IamEvents,
+ repos.OrgEvents),
+ newExternalIDP(
+ handler{view, bulkLimit, configs.cycleDuration("ExternalIDP"), errorCount, es},
+ systemDefaults,
+ repos.IamEvents,
+ repos.OrgEvents),
+ newPasswordComplexityPolicy(
+ handler{view, bulkLimit, configs.cycleDuration("PasswordComplexityPolicy"), errorCount, es}),
+ newOrgIAMPolicy(
+ handler{view, bulkLimit, configs.cycleDuration("OrgIAMPolicy"), errorCount, es}),
+ newProjectRole(handler{view, bulkLimit, configs.cycleDuration("ProjectRole"), errorCount, es},
+ repos.ProjectEvents),
}
}
func (configs Configs) cycleDuration(viewModel string) time.Duration {
c, ok := configs[viewModel]
if !ok {
- return 1 * time.Second
+ return 3 * time.Minute
}
return c.MinimumCycleDuration.Duration
}
@@ -76,6 +108,10 @@ func (h *handler) MinimumCycleDuration() time.Duration {
return h.cycleDuration
}
+func (h *handler) LockDuration() time.Duration {
+ return h.cycleDuration / 3
+}
+
func (h *handler) QueryLimit() uint64 {
return h.bulkLimit
}
diff --git a/internal/auth/repository/eventsourcing/handler/idp_config.go b/internal/auth/repository/eventsourcing/handler/idp_config.go
index e6c21a6260..b070d89c8a 100644
--- a/internal/auth/repository/eventsourcing/handler/idp_config.go
+++ b/internal/auth/repository/eventsourcing/handler/idp_config.go
@@ -2,8 +2,10 @@ package handler
import (
"github.com/caos/logging"
+ "github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
iam_model "github.com/caos/zitadel/internal/iam/model"
iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
@@ -11,25 +13,57 @@ import (
"github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
)
-type IDPConfig struct {
- handler
-}
-
const (
idpConfigTable = "auth.idp_configs"
)
+type IDPConfig struct {
+ handler
+ subscription *eventstore.Subscription
+}
+
+func newIDPConfig(h handler) *IDPConfig {
+ idpConfig := &IDPConfig{
+ handler: h,
+ }
+
+ idpConfig.subscribe()
+
+ return idpConfig
+}
+
+func (i *IDPConfig) subscribe() {
+ i.subscription = i.es.Subscribe(i.AggregateTypes()...)
+ go func() {
+ for event := range i.subscription.Events {
+ query.ReduceEvent(i, event)
+ }
+ }()
+}
+
func (i *IDPConfig) ViewModel() string {
return idpConfigTable
}
+func (_ *IDPConfig) AggregateTypes() []models.AggregateType {
+ return []models.AggregateType{model.OrgAggregate, iam_es_model.IAMAggregate}
+}
+
+func (i *IDPConfig) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := i.view.GetLatestIDPConfigSequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (i *IDPConfig) EventQuery() (*models.SearchQuery, error) {
- sequence, err := i.view.GetLatestIDPConfigSequence()
+ sequence, err := i.view.GetLatestIDPConfigSequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(model.OrgAggregate, iam_es_model.IAMAggregate).
+ AggregateTypeFilter(i.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
@@ -66,14 +100,14 @@ func (i *IDPConfig) processIdpConfig(providerType iam_model.IDPProviderType, eve
if err != nil {
return err
}
- return i.view.DeleteIDPConfig(idp.IDPConfigID, event.Sequence, event.CreationDate)
+ return i.view.DeleteIDPConfig(idp.IDPConfigID, event)
default:
- return i.view.ProcessedIDPConfigSequence(event.Sequence, event.CreationDate)
+ return i.view.ProcessedIDPConfigSequence(event)
}
if err != nil {
return err
}
- return i.view.PutIDPConfig(idp, idp.Sequence, event.CreationDate)
+ return i.view.PutIDPConfig(idp, event)
}
func (i *IDPConfig) OnError(event *models.Event, err error) error {
diff --git a/internal/auth/repository/eventsourcing/handler/idp_providers.go b/internal/auth/repository/eventsourcing/handler/idp_providers.go
index b92a20a3b4..8622fc57b1 100644
--- a/internal/auth/repository/eventsourcing/handler/idp_providers.go
+++ b/internal/auth/repository/eventsourcing/handler/idp_providers.go
@@ -2,42 +2,85 @@ package handler
import (
"context"
+
"github.com/caos/logging"
"github.com/caos/zitadel/internal/config/systemdefaults"
+ "github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/iam/repository/eventsourcing"
org_es "github.com/caos/zitadel/internal/org/repository/eventsourcing"
org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
iam_view_model "github.com/caos/zitadel/internal/iam/repository/view/model"
)
+const (
+ idpProviderTable = "auth.idp_providers"
+)
+
type IDPProvider struct {
handler
systemDefaults systemdefaults.SystemDefaults
iamEvents *eventsourcing.IAMEventstore
orgEvents *org_es.OrgEventstore
+ subscription *eventstore.Subscription
}
-const (
- idpProviderTable = "auth.idp_providers"
-)
+func newIDPProvider(
+ h handler,
+ defaults systemdefaults.SystemDefaults,
+ iamEvents *eventsourcing.IAMEventstore,
+ orgEvents *org_es.OrgEventstore,
+) *IDPProvider {
+ idpProvider := &IDPProvider{
+ handler: h,
+ systemDefaults: defaults,
+ iamEvents: iamEvents,
+ orgEvents: orgEvents,
+ }
+
+ idpProvider.subscribe()
+
+ return idpProvider
+}
+
+func (i *IDPProvider) subscribe() {
+ i.subscription = i.es.Subscribe(i.AggregateTypes()...)
+ go func() {
+ for event := range i.subscription.Events {
+ query.ReduceEvent(i, event)
+ }
+ }()
+}
func (i *IDPProvider) ViewModel() string {
return idpProviderTable
}
+func (_ *IDPProvider) AggregateTypes() []models.AggregateType {
+ return []models.AggregateType{model.IAMAggregate, org_es_model.OrgAggregate}
+}
+
+func (i *IDPProvider) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := i.view.GetLatestIDPProviderSequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (i *IDPProvider) EventQuery() (*models.SearchQuery, error) {
- sequence, err := i.view.GetLatestIDPProviderSequence()
+ sequence, err := i.view.GetLatestIDPProviderSequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(model.IAMAggregate, org_es_model.OrgAggregate).
+ AggregateTypeFilter(i.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
@@ -64,7 +107,7 @@ func (i *IDPProvider) processIdpProvider(event *models.Event) (err error) {
if err != nil {
return err
}
- return i.view.DeleteIDPProvider(event.AggregateID, provider.IDPConfigID, event.Sequence, event.CreationDate)
+ return i.view.DeleteIDPProvider(event.AggregateID, provider.IDPConfigID, event)
case model.IDPConfigChanged, org_es_model.IDPConfigChanged:
esConfig := new(iam_view_model.IDPConfigView)
providerType := iam_model.IDPProviderTypeSystem
@@ -88,16 +131,16 @@ func (i *IDPProvider) processIdpProvider(event *models.Event) (err error) {
for _, provider := range providers {
i.fillConfigData(provider, config)
}
- return i.view.PutIDPProviders(event.Sequence, event.CreationDate, providers...)
+ return i.view.PutIDPProviders(event, providers...)
case org_es_model.LoginPolicyRemoved:
- return i.view.DeleteIDPProvidersByAggregateID(event.AggregateID, event.Sequence, event.CreationDate)
+ return i.view.DeleteIDPProvidersByAggregateID(event.AggregateID, event)
default:
- return i.view.ProcessedIDPProviderSequence(event.Sequence, event.CreationDate)
+ return i.view.ProcessedIDPProviderSequence(event)
}
if err != nil {
return err
}
- return i.view.PutIDPProvider(provider, provider.Sequence, event.CreationDate)
+ return i.view.PutIDPProvider(provider, event)
}
func (i *IDPProvider) fillData(provider *iam_view_model.IDPProviderView) (err error) {
diff --git a/internal/auth/repository/eventsourcing/handler/key.go b/internal/auth/repository/eventsourcing/handler/key.go
index 48f224cc29..54703a2509 100644
--- a/internal/auth/repository/eventsourcing/handler/key.go
+++ b/internal/auth/repository/eventsourcing/handler/key.go
@@ -3,30 +3,62 @@ package handler
import (
"time"
- es_model "github.com/caos/zitadel/internal/key/repository/eventsourcing/model"
-
"github.com/caos/logging"
-
+ "github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
"github.com/caos/zitadel/internal/key/repository/eventsourcing"
+ es_model "github.com/caos/zitadel/internal/key/repository/eventsourcing/model"
view_model "github.com/caos/zitadel/internal/key/repository/view/model"
)
-type Key struct {
- handler
-}
-
const (
keyTable = "auth.keys"
)
+type Key struct {
+ handler
+ subscription *eventstore.Subscription
+}
+
+func newKey(handler handler) *Key {
+ h := &Key{
+ handler: handler,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (k *Key) subscribe() {
+ k.subscription = k.es.Subscribe(k.AggregateTypes()...)
+ go func() {
+ for event := range k.subscription.Events {
+ query.ReduceEvent(k, event)
+ }
+ }()
+}
+
func (k *Key) ViewModel() string {
return keyTable
}
+func (_ *Key) AggregateTypes() []models.AggregateType {
+ return []models.AggregateType{es_model.KeyPairAggregate}
+}
+
+func (k *Key) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := k.view.GetLatestKeySequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (k *Key) EventQuery() (*models.SearchQuery, error) {
- sequence, err := k.view.GetLatestKeySequence()
+ sequence, err := k.view.GetLatestKeySequence("")
if err != nil {
return nil, err
}
@@ -41,11 +73,11 @@ func (k *Key) Reduce(event *models.Event) error {
return err
}
if privateKey.Expiry.Before(time.Now()) && publicKey.Expiry.Before(time.Now()) {
- return k.view.ProcessedKeySequence(event.Sequence, event.CreationDate)
+ return k.view.ProcessedKeySequence(event)
}
- return k.view.PutKeys(privateKey, publicKey, event.Sequence, event.CreationDate)
+ return k.view.PutKeys(privateKey, publicKey, event)
default:
- return k.view.ProcessedKeySequence(event.Sequence, event.CreationDate)
+ return k.view.ProcessedKeySequence(event)
}
}
diff --git a/internal/auth/repository/eventsourcing/handler/login_policy.go b/internal/auth/repository/eventsourcing/handler/login_policy.go
index b92dd17a9e..35700d80c7 100644
--- a/internal/auth/repository/eventsourcing/handler/login_policy.go
+++ b/internal/auth/repository/eventsourcing/handler/login_policy.go
@@ -2,34 +2,68 @@ package handler
import (
"github.com/caos/logging"
+ "github.com/caos/zitadel/internal/eventstore"
iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
iam_model "github.com/caos/zitadel/internal/iam/repository/view/model"
"github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
)
-type LoginPolicy struct {
- handler
-}
-
const (
loginPolicyTable = "auth.login_policies"
)
+type LoginPolicy struct {
+ handler
+ subscription *eventstore.Subscription
+}
+
+func newLoginPolicy(handler handler) *LoginPolicy {
+ h := &LoginPolicy{
+ handler: handler,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (p *LoginPolicy) subscribe() {
+ p.subscription = p.es.Subscribe(p.AggregateTypes()...)
+ go func() {
+ for event := range p.subscription.Events {
+ query.ReduceEvent(p, event)
+ }
+ }()
+}
+
func (p *LoginPolicy) ViewModel() string {
return loginPolicyTable
}
+func (_ *LoginPolicy) AggregateTypes() []models.AggregateType {
+ return []models.AggregateType{model.OrgAggregate, iam_es_model.IAMAggregate}
+}
+
+func (p *LoginPolicy) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := p.view.GetLatestLoginPolicySequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (p *LoginPolicy) EventQuery() (*models.SearchQuery, error) {
- sequence, err := p.view.GetLatestLoginPolicySequence()
+ sequence, err := p.view.GetLatestLoginPolicySequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(model.OrgAggregate, iam_es_model.IAMAggregate).
+ AggregateTypeFilter(p.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
@@ -57,14 +91,14 @@ func (p *LoginPolicy) processLoginPolicy(event *models.Event) (err error) {
}
err = policy.AppendEvent(event)
case model.LoginPolicyRemoved:
- return p.view.DeleteLoginPolicy(event.AggregateID, event.Sequence, event.CreationDate)
+ return p.view.DeleteLoginPolicy(event.AggregateID, event)
default:
- return p.view.ProcessedLoginPolicySequence(event.Sequence, event.CreationDate)
+ return p.view.ProcessedLoginPolicySequence(event)
}
if err != nil {
return err
}
- return p.view.PutLoginPolicy(policy, policy.Sequence, event.CreationDate)
+ return p.view.PutLoginPolicy(policy, event)
}
func (p *LoginPolicy) OnError(event *models.Event, err error) error {
diff --git a/internal/auth/repository/eventsourcing/handler/machine_keys.go b/internal/auth/repository/eventsourcing/handler/machine_keys.go
index f9af7e86fb..0ca0532c26 100644
--- a/internal/auth/repository/eventsourcing/handler/machine_keys.go
+++ b/internal/auth/repository/eventsourcing/handler/machine_keys.go
@@ -5,73 +5,107 @@ import (
"github.com/caos/logging"
+ "github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
"github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
usr_model "github.com/caos/zitadel/internal/user/repository/view/model"
)
-type MachineKeys struct {
- handler
-}
-
const (
machineKeysTable = "auth.machine_keys"
)
-func (d *MachineKeys) ViewModel() string {
+type MachineKeys struct {
+ handler
+ subscription *eventstore.Subscription
+}
+
+func newMachineKeys(handler handler) *MachineKeys {
+ h := &MachineKeys{
+ handler: handler,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (k *MachineKeys) subscribe() {
+ k.subscription = k.es.Subscribe(k.AggregateTypes()...)
+ go func() {
+ for event := range k.subscription.Events {
+ query.ReduceEvent(k, event)
+ }
+ }()
+}
+
+func (k *MachineKeys) ViewModel() string {
return machineKeysTable
}
-func (d *MachineKeys) EventQuery() (*models.SearchQuery, error) {
- sequence, err := d.view.GetLatestMachineKeySequence()
+func (_ *MachineKeys) AggregateTypes() []es_models.AggregateType {
+ return []es_models.AggregateType{model.UserAggregate}
+}
+
+func (k *MachineKeys) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := k.view.GetLatestMachineKeySequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
+func (k *MachineKeys) EventQuery() (*es_models.SearchQuery, error) {
+ sequence, err := k.view.GetLatestMachineKeySequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(model.UserAggregate).
+ AggregateTypeFilter(k.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
-func (d *MachineKeys) Reduce(event *models.Event) (err error) {
+func (k *MachineKeys) Reduce(event *es_models.Event) (err error) {
switch event.AggregateType {
case model.UserAggregate:
- err = d.processMachineKeys(event)
+ err = k.processMachineKeys(event)
}
return err
}
-func (d *MachineKeys) processMachineKeys(event *models.Event) (err error) {
+func (k *MachineKeys) processMachineKeys(event *es_models.Event) (err error) {
key := new(usr_model.MachineKeyView)
switch event.Type {
case model.MachineKeyAdded:
err = key.AppendEvent(event)
if key.ExpirationDate.Before(time.Now()) {
- return d.view.ProcessedMachineKeySequence(event.Sequence, event.CreationDate)
+ return k.view.ProcessedMachineKeySequence(event)
}
case model.MachineKeyRemoved:
err = key.SetData(event)
if err != nil {
return err
}
- return d.view.DeleteMachineKey(key.ID, event.Sequence, event.CreationDate)
+ return k.view.DeleteMachineKey(key.ID, event)
case model.UserRemoved:
- return d.view.DeleteMachineKeysByUserID(event.AggregateID, event.Sequence, event.CreationDate)
+ return k.view.DeleteMachineKeysByUserID(event.AggregateID, event)
default:
- return d.view.ProcessedMachineKeySequence(event.Sequence, event.CreationDate)
+ return k.view.ProcessedMachineKeySequence(event)
}
if err != nil {
return err
}
- return d.view.PutMachineKey(key, key.Sequence, event.CreationDate)
+ return k.view.PutMachineKey(key, event)
}
-func (d *MachineKeys) OnError(event *models.Event, err error) error {
+func (k *MachineKeys) OnError(event *es_models.Event, err error) error {
logging.LogWithFields("SPOOL-S9fe", "id", event.AggregateID).WithError(err).Warn("something went wrong in machine key handler")
- return spooler.HandleError(event, err, d.view.GetLatestMachineKeyFailedEvent, d.view.ProcessedMachineKeyFailedEvent, d.view.ProcessedMachineKeySequence, d.errorCountUntilSkip)
+ return spooler.HandleError(event, err, k.view.GetLatestMachineKeyFailedEvent, k.view.ProcessedMachineKeyFailedEvent, k.view.ProcessedMachineKeySequence, k.errorCountUntilSkip)
}
-func (d *MachineKeys) OnSuccess() error {
- return spooler.HandleSuccess(d.view.UpdateMachineKeySpoolerRunTimestamp)
+func (k *MachineKeys) OnSuccess() error {
+ return spooler.HandleSuccess(k.view.UpdateMachineKeySpoolerRunTimestamp)
}
diff --git a/internal/auth/repository/eventsourcing/handler/org.go b/internal/auth/repository/eventsourcing/handler/org.go
index 909cfefc4a..ea87eed2f2 100644
--- a/internal/auth/repository/eventsourcing/handler/org.go
+++ b/internal/auth/repository/eventsourcing/handler/org.go
@@ -3,27 +3,62 @@ package handler
import (
"github.com/caos/logging"
+ "github.com/caos/zitadel/internal/eventstore"
+ "github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
"github.com/caos/zitadel/internal/org/repository/eventsourcing"
"github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
org_model "github.com/caos/zitadel/internal/org/repository/view/model"
)
-type Org struct {
- handler
-}
-
const (
orgTable = "auth.orgs"
)
+type Org struct {
+ handler
+ subscription *eventstore.Subscription
+}
+
+func newOrg(handler handler) *Org {
+ h := &Org{
+ handler: handler,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (o *Org) subscribe() {
+ o.subscription = o.es.Subscribe(o.AggregateTypes()...)
+ go func() {
+ for event := range o.subscription.Events {
+ query.ReduceEvent(o, event)
+ }
+ }()
+}
+
func (o *Org) ViewModel() string {
return orgTable
}
+func (_ *Org) AggregateTypes() []es_models.AggregateType {
+ return []es_models.AggregateType{model.OrgAggregate}
+}
+
+func (o *Org) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := o.view.GetLatestOrgSequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (o *Org) EventQuery() (*es_models.SearchQuery, error) {
- sequence, err := o.view.GetLatestOrgSequence()
+ sequence, err := o.view.GetLatestOrgSequence("")
if err != nil {
return nil, err
}
@@ -58,13 +93,13 @@ func (o *Org) Reduce(event *es_models.Event) (err error) {
}
org.Domain = domain.Domain
default:
- return o.view.ProcessedOrgSequence(event.Sequence, event.CreationDate)
+ return o.view.ProcessedOrgSequence(event)
}
if err != nil {
return err
}
- return o.view.PutOrg(org, event.CreationDate)
+ return o.view.PutOrg(org, event)
}
func (o *Org) OnError(event *es_models.Event, spoolerErr error) error {
diff --git a/internal/auth/repository/eventsourcing/handler/org_iam_policy.go b/internal/auth/repository/eventsourcing/handler/org_iam_policy.go
index ac28b5c7c4..9d9d230a96 100644
--- a/internal/auth/repository/eventsourcing/handler/org_iam_policy.go
+++ b/internal/auth/repository/eventsourcing/handler/org_iam_policy.go
@@ -2,68 +2,101 @@ package handler
import (
"github.com/caos/logging"
- iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
-
+ "github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
+ iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
iam_model "github.com/caos/zitadel/internal/iam/repository/view/model"
- "github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
+ org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
)
-type OrgIAMPolicy struct {
- handler
-}
-
const (
orgIAMPolicyTable = "auth.org_iam_policies"
)
+type OrgIAMPolicy struct {
+ handler
+ subscription *eventstore.Subscription
+}
+
+func newOrgIAMPolicy(handler handler) *OrgIAMPolicy {
+ h := &OrgIAMPolicy{
+ handler: handler,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (p *OrgIAMPolicy) subscribe() {
+ p.subscription = p.es.Subscribe(p.AggregateTypes()...)
+ go func() {
+ for event := range p.subscription.Events {
+ query.ReduceEvent(p, event)
+ }
+ }()
+}
+
func (p *OrgIAMPolicy) ViewModel() string {
return orgIAMPolicyTable
}
-func (p *OrgIAMPolicy) EventQuery() (*models.SearchQuery, error) {
- sequence, err := p.view.GetLatestOrgIAMPolicySequence()
+func (_ *OrgIAMPolicy) AggregateTypes() []es_models.AggregateType {
+ return []es_models.AggregateType{org_es_model.OrgAggregate, iam_es_model.IAMAggregate}
+}
+
+func (p *OrgIAMPolicy) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := p.view.GetLatestOrgIAMPolicySequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
+func (p *OrgIAMPolicy) EventQuery() (*es_models.SearchQuery, error) {
+ sequence, err := p.view.GetLatestOrgIAMPolicySequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(model.OrgAggregate, iam_es_model.IAMAggregate).
+ AggregateTypeFilter(p.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
-func (p *OrgIAMPolicy) Reduce(event *models.Event) (err error) {
+func (p *OrgIAMPolicy) Reduce(event *es_models.Event) (err error) {
switch event.AggregateType {
- case model.OrgAggregate, iam_es_model.IAMAggregate:
+ case org_es_model.OrgAggregate, iam_es_model.IAMAggregate:
err = p.processOrgIAMPolicy(event)
}
return err
}
-func (p *OrgIAMPolicy) processOrgIAMPolicy(event *models.Event) (err error) {
+func (p *OrgIAMPolicy) processOrgIAMPolicy(event *es_models.Event) (err error) {
policy := new(iam_model.OrgIAMPolicyView)
switch event.Type {
- case iam_es_model.OrgIAMPolicyAdded, model.OrgIAMPolicyAdded:
+ case iam_es_model.OrgIAMPolicyAdded, org_es_model.OrgIAMPolicyAdded:
err = policy.AppendEvent(event)
- case iam_es_model.OrgIAMPolicyChanged, model.OrgIAMPolicyChanged:
+ case iam_es_model.OrgIAMPolicyChanged, org_es_model.OrgIAMPolicyChanged:
policy, err = p.view.OrgIAMPolicyByAggregateID(event.AggregateID)
if err != nil {
return err
}
err = policy.AppendEvent(event)
- case model.OrgIAMPolicyRemoved:
- return p.view.DeleteOrgIAMPolicy(event.AggregateID, event.Sequence, event.CreationDate)
+ case org_es_model.OrgIAMPolicyRemoved:
+ return p.view.DeleteOrgIAMPolicy(event.AggregateID, event)
default:
- return p.view.ProcessedOrgIAMPolicySequence(event.Sequence, event.CreationDate)
+ return p.view.ProcessedOrgIAMPolicySequence(event)
}
if err != nil {
return err
}
- return p.view.PutOrgIAMPolicy(policy, policy.Sequence, event.CreationDate)
+ return p.view.PutOrgIAMPolicy(policy, event)
}
-func (p *OrgIAMPolicy) OnError(event *models.Event, err error) error {
+func (p *OrgIAMPolicy) OnError(event *es_models.Event, err error) error {
logging.LogWithFields("SPOOL-3Gj8s", "id", event.AggregateID).WithError(err).Warn("something went wrong in orgIAM policy handler")
return spooler.HandleError(event, err, p.view.GetLatestOrgIAMPolicyFailedEvent, p.view.ProcessedOrgIAMPolicyFailedEvent, p.view.ProcessedOrgIAMPolicySequence, p.errorCountUntilSkip)
}
diff --git a/internal/auth/repository/eventsourcing/handler/password_complexity_policy.go b/internal/auth/repository/eventsourcing/handler/password_complexity_policy.go
index d3656a164a..65a86676a8 100644
--- a/internal/auth/repository/eventsourcing/handler/password_complexity_policy.go
+++ b/internal/auth/repository/eventsourcing/handler/password_complexity_policy.go
@@ -2,68 +2,101 @@ package handler
import (
"github.com/caos/logging"
- iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
-
+ "github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
+ iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
iam_model "github.com/caos/zitadel/internal/iam/repository/view/model"
- "github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
+ org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
)
-type PasswordComplexityPolicy struct {
- handler
-}
-
const (
passwordComplexityPolicyTable = "auth.password_complexity_policies"
)
+type PasswordComplexityPolicy struct {
+ handler
+ subscription *eventstore.Subscription
+}
+
+func newPasswordComplexityPolicy(handler handler) *PasswordComplexityPolicy {
+ h := &PasswordComplexityPolicy{
+ handler: handler,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (p *PasswordComplexityPolicy) subscribe() {
+ p.subscription = p.es.Subscribe(p.AggregateTypes()...)
+ go func() {
+ for event := range p.subscription.Events {
+ query.ReduceEvent(p, event)
+ }
+ }()
+}
+
func (p *PasswordComplexityPolicy) ViewModel() string {
return passwordComplexityPolicyTable
}
-func (p *PasswordComplexityPolicy) EventQuery() (*models.SearchQuery, error) {
- sequence, err := p.view.GetLatestPasswordComplexityPolicySequence()
+func (_ *PasswordComplexityPolicy) AggregateTypes() []es_models.AggregateType {
+ return []es_models.AggregateType{org_es_model.OrgAggregate, iam_es_model.IAMAggregate}
+}
+
+func (p *PasswordComplexityPolicy) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := p.view.GetLatestPasswordComplexityPolicySequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
+func (p *PasswordComplexityPolicy) EventQuery() (*es_models.SearchQuery, error) {
+ sequence, err := p.view.GetLatestPasswordComplexityPolicySequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(model.OrgAggregate, iam_es_model.IAMAggregate).
+ AggregateTypeFilter(p.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
-func (p *PasswordComplexityPolicy) Reduce(event *models.Event) (err error) {
+func (p *PasswordComplexityPolicy) Reduce(event *es_models.Event) (err error) {
switch event.AggregateType {
- case model.OrgAggregate, iam_es_model.IAMAggregate:
+ case org_es_model.OrgAggregate, iam_es_model.IAMAggregate:
err = p.processPasswordComplexityPolicy(event)
}
return err
}
-func (p *PasswordComplexityPolicy) processPasswordComplexityPolicy(event *models.Event) (err error) {
+func (p *PasswordComplexityPolicy) processPasswordComplexityPolicy(event *es_models.Event) (err error) {
policy := new(iam_model.PasswordComplexityPolicyView)
switch event.Type {
- case iam_es_model.PasswordComplexityPolicyAdded, model.PasswordComplexityPolicyAdded:
+ case iam_es_model.PasswordComplexityPolicyAdded, org_es_model.PasswordComplexityPolicyAdded:
err = policy.AppendEvent(event)
- case iam_es_model.PasswordComplexityPolicyChanged, model.PasswordComplexityPolicyChanged:
+ case iam_es_model.PasswordComplexityPolicyChanged, org_es_model.PasswordComplexityPolicyChanged:
policy, err = p.view.PasswordComplexityPolicyByAggregateID(event.AggregateID)
if err != nil {
return err
}
err = policy.AppendEvent(event)
- case model.PasswordComplexityPolicyRemoved:
- return p.view.DeletePasswordComplexityPolicy(event.AggregateID, event.Sequence, event.CreationDate)
+ case org_es_model.PasswordComplexityPolicyRemoved:
+ return p.view.DeletePasswordComplexityPolicy(event.AggregateID, event)
default:
- return p.view.ProcessedPasswordComplexityPolicySequence(event.Sequence, event.CreationDate)
+ return p.view.ProcessedPasswordComplexityPolicySequence(event)
}
if err != nil {
return err
}
- return p.view.PutPasswordComplexityPolicy(policy, policy.Sequence, event.CreationDate)
+ return p.view.PutPasswordComplexityPolicy(policy, event)
}
-func (p *PasswordComplexityPolicy) OnError(event *models.Event, err error) error {
+func (p *PasswordComplexityPolicy) OnError(event *es_models.Event, err error) error {
logging.LogWithFields("SPOOL-4Djo9", "id", event.AggregateID).WithError(err).Warn("something went wrong in passwordComplexity policy handler")
return spooler.HandleError(event, err, p.view.GetLatestPasswordComplexityPolicyFailedEvent, p.view.ProcessedPasswordComplexityPolicyFailedEvent, p.view.ProcessedPasswordComplexityPolicySequence, p.errorCountUntilSkip)
}
diff --git a/internal/auth/repository/eventsourcing/handler/project_role.go b/internal/auth/repository/eventsourcing/handler/project_role.go
index c469019b9f..5ee8722bdc 100644
--- a/internal/auth/repository/eventsourcing/handler/project_role.go
+++ b/internal/auth/repository/eventsourcing/handler/project_role.go
@@ -2,42 +2,80 @@ package handler
import (
"github.com/caos/logging"
-
+ "github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
+ es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
- "github.com/caos/zitadel/internal/project/repository/eventsourcing"
proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing"
- es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model"
+ proj_events "github.com/caos/zitadel/internal/project/repository/eventsourcing"
+ "github.com/caos/zitadel/internal/project/repository/eventsourcing/model"
view_model "github.com/caos/zitadel/internal/project/repository/view/model"
)
-type ProjectRole struct {
- handler
- projectEvents *proj_event.ProjectEventstore
-}
-
const (
projectRoleTable = "auth.project_roles"
)
+type ProjectRole struct {
+ handler
+ projectEvents *proj_event.ProjectEventstore
+ subscription *eventstore.Subscription
+}
+
+func newProjectRole(
+ handler handler,
+ projectEvents *proj_events.ProjectEventstore,
+) *ProjectRole {
+ h := &ProjectRole{
+ handler: handler,
+ projectEvents: projectEvents,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (k *ProjectRole) subscribe() {
+ k.subscription = k.es.Subscribe(k.AggregateTypes()...)
+ go func() {
+ for event := range k.subscription.Events {
+ query.ReduceEvent(k, event)
+ }
+ }()
+}
+
func (p *ProjectRole) ViewModel() string {
return projectRoleTable
}
-func (p *ProjectRole) EventQuery() (*models.SearchQuery, error) {
- sequence, err := p.view.GetLatestProjectRoleSequence()
+func (_ *ProjectRole) AggregateTypes() []es_models.AggregateType {
+ return []es_models.AggregateType{model.ProjectAggregate}
+}
+
+func (p *ProjectRole) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := p.view.GetLatestProjectRoleSequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
+func (p *ProjectRole) EventQuery() (*es_models.SearchQuery, error) {
+ sequence, err := p.view.GetLatestProjectRoleSequence("")
if err != nil {
return nil, err
}
- return eventsourcing.ProjectQuery(sequence.CurrentSequence), nil
+ return proj_events.ProjectQuery(sequence.CurrentSequence), nil
}
-func (p *ProjectRole) Reduce(event *models.Event) (err error) {
+func (p *ProjectRole) Reduce(event *es_models.Event) (err error) {
role := new(view_model.ProjectRoleView)
switch event.Type {
- case es_model.ProjectRoleAdded:
+ case model.ProjectRoleAdded:
err = role.AppendEvent(event)
- case es_model.ProjectRoleChanged:
+ case model.ProjectRoleChanged:
err = role.SetData(event)
if err != nil {
return err
@@ -47,24 +85,27 @@ func (p *ProjectRole) Reduce(event *models.Event) (err error) {
return err
}
err = role.AppendEvent(event)
- case es_model.ProjectRoleRemoved:
+ case model.ProjectRoleRemoved:
err = role.SetData(event)
if err != nil {
return err
}
- return p.view.DeleteProjectRole(event.AggregateID, event.ResourceOwner, role.Key, event.Sequence, event.CreationDate)
- case es_model.ProjectRemoved:
- return p.view.DeleteProjectRolesByProjectID(event.AggregateID)
+ return p.view.DeleteProjectRole(event.AggregateID, event.ResourceOwner, role.Key, event)
+ case model.ProjectRemoved:
+ err := p.view.DeleteProjectRolesByProjectID(event.AggregateID)
+ if err == nil {
+ return p.view.ProcessedProjectRoleSequence(event)
+ }
default:
- return p.view.ProcessedProjectRoleSequence(event.Sequence, event.CreationDate)
+ return p.view.ProcessedProjectRoleSequence(event)
}
if err != nil {
return err
}
- return p.view.PutProjectRole(role, event.CreationDate)
+ return p.view.PutProjectRole(role, event)
}
-func (p *ProjectRole) OnError(event *models.Event, err error) error {
+func (p *ProjectRole) OnError(event *es_models.Event, err error) error {
logging.LogWithFields("SPOOL-lso9w", "id", event.AggregateID).WithError(err).Warn("something went wrong in project role handler")
return spooler.HandleError(event, err, p.view.GetLatestProjectRoleFailedEvent, p.view.ProcessedProjectRoleFailedEvent, p.view.ProcessedProjectRoleSequence, p.errorCountUntilSkip)
}
diff --git a/internal/auth/repository/eventsourcing/handler/token.go b/internal/auth/repository/eventsourcing/handler/token.go
index 2c056cc064..b98e811bda 100644
--- a/internal/auth/repository/eventsourcing/handler/token.go
+++ b/internal/auth/repository/eventsourcing/handler/token.go
@@ -6,8 +6,10 @@ import (
"github.com/caos/logging"
caos_errs "github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing"
project_es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model"
@@ -15,21 +17,57 @@ import (
view_model "github.com/caos/zitadel/internal/user/repository/view/model"
)
-type Token struct {
- handler
- ProjectEvents *proj_event.ProjectEventstore
-}
-
const (
tokenTable = "auth.tokens"
)
+type Token struct {
+ handler
+ ProjectEvents *proj_event.ProjectEventstore
+ subscription *eventstore.Subscription
+}
+
+func newToken(
+ handler handler,
+ projectEvents *proj_event.ProjectEventstore,
+) *Token {
+ h := &Token{
+ handler: handler,
+ ProjectEvents: projectEvents,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (t *Token) subscribe() {
+ t.subscription = t.es.Subscribe(t.AggregateTypes()...)
+ go func() {
+ for event := range t.subscription.Events {
+ query.ReduceEvent(t, event)
+ }
+ }()
+}
+
func (t *Token) ViewModel() string {
return tokenTable
}
+func (_ *Token) AggregateTypes() []es_models.AggregateType {
+ return []es_models.AggregateType{user_es_model.UserAggregate, project_es_model.ProjectAggregate}
+}
+
+func (p *Token) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := p.view.GetLatestTokenSequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (t *Token) EventQuery() (*models.SearchQuery, error) {
- sequence, err := t.view.GetLatestTokenSequence()
+ sequence, err := t.view.GetLatestTokenSequence("")
if err != nil {
return nil, err
}
@@ -49,7 +87,7 @@ func (t *Token) Reduce(event *models.Event) (err error) {
if err != nil {
return err
}
- return t.view.PutToken(token, event.CreationDate)
+ return t.view.PutToken(token, event)
case user_es_model.UserProfileChanged,
user_es_model.HumanProfileChanged:
user := new(view_model.UserView)
@@ -61,25 +99,25 @@ func (t *Token) Reduce(event *models.Event) (err error) {
for _, token := range tokens {
token.PreferredLanguage = user.PreferredLanguage
}
- return t.view.PutTokens(tokens, event.Sequence, event.CreationDate)
+ return t.view.PutTokens(tokens, event)
case user_es_model.SignedOut,
user_es_model.HumanSignedOut:
id, err := agentIDFromSession(event)
if err != nil {
return err
}
- return t.view.DeleteSessionTokens(id, event.AggregateID, event.Sequence, event.CreationDate)
+ return t.view.DeleteSessionTokens(id, event.AggregateID, event)
case user_es_model.UserLocked,
user_es_model.UserDeactivated,
user_es_model.UserRemoved:
- return t.view.DeleteUserTokens(event.AggregateID, event.Sequence, event.CreationDate)
+ return t.view.DeleteUserTokens(event.AggregateID, event)
case project_es_model.ApplicationDeactivated,
project_es_model.ApplicationRemoved:
application, err := applicationFromSession(event)
if err != nil {
return err
}
- return t.view.DeleteApplicationTokens(event.Sequence, event.CreationDate, application.AppID)
+ return t.view.DeleteApplicationTokens(event, application.AppID)
case project_es_model.ProjectDeactivated,
project_es_model.ProjectRemoved:
project, err := t.ProjectEvents.ProjectByID(context.Background(), event.AggregateID)
@@ -90,9 +128,9 @@ func (t *Token) Reduce(event *models.Event) (err error) {
for _, app := range project.Applications {
applicationsIDs = append(applicationsIDs, app.AppID)
}
- return t.view.DeleteApplicationTokens(event.Sequence, event.CreationDate, applicationsIDs...)
+ return t.view.DeleteApplicationTokens(event, applicationsIDs...)
default:
- return t.view.ProcessedTokenSequence(event.Sequence, event.CreationDate)
+ return t.view.ProcessedTokenSequence(event)
}
}
diff --git a/internal/auth/repository/eventsourcing/handler/user.go b/internal/auth/repository/eventsourcing/handler/user.go
index 8b1ceb091c..f960ab720d 100644
--- a/internal/auth/repository/eventsourcing/handler/user.go
+++ b/internal/auth/repository/eventsourcing/handler/user.go
@@ -2,45 +2,83 @@ package handler
import (
"context"
- iam_es "github.com/caos/zitadel/internal/iam/repository/eventsourcing"
+ "github.com/caos/logging"
+ "github.com/caos/zitadel/internal/eventstore"
+ "github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
+ "github.com/caos/zitadel/internal/eventstore/spooler"
+ iam_es "github.com/caos/zitadel/internal/iam/repository/eventsourcing"
org_model "github.com/caos/zitadel/internal/org/model"
org_events "github.com/caos/zitadel/internal/org/repository/eventsourcing"
org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
-
- "github.com/caos/logging"
-
- "github.com/caos/zitadel/internal/eventstore"
- "github.com/caos/zitadel/internal/eventstore/models"
- "github.com/caos/zitadel/internal/eventstore/spooler"
view_model "github.com/caos/zitadel/internal/user/repository/view/model"
)
-type User struct {
- handler
- eventstore eventstore.Eventstore
- orgEvents *org_events.OrgEventstore
- iamEvents *iam_es.IAMEventstore
- iamID string
-}
-
const (
userTable = "auth.users"
)
+type User struct {
+ handler
+ orgEvents *org_events.OrgEventstore
+ iamEvents *iam_es.IAMEventstore
+ iamID string
+ subscription *eventstore.Subscription
+}
+
+func newUser(
+ handler handler,
+ orgEvents *org_events.OrgEventstore,
+ iamEvents *iam_es.IAMEventstore,
+ iamID string,
+) *User {
+ h := &User{
+ handler: handler,
+ orgEvents: orgEvents,
+ iamEvents: iamEvents,
+ iamID: iamID,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (k *User) subscribe() {
+ k.subscription = k.es.Subscribe(k.AggregateTypes()...)
+ go func() {
+ for event := range k.subscription.Events {
+ query.ReduceEvent(k, event)
+ }
+ }()
+}
+
func (u *User) ViewModel() string {
return userTable
}
+func (_ *User) AggregateTypes() []models.AggregateType {
+ return []models.AggregateType{es_model.UserAggregate, org_es_model.OrgAggregate}
+}
+
+func (u *User) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := u.view.GetLatestUserSequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (u *User) EventQuery() (*models.SearchQuery, error) {
- sequence, err := u.view.GetLatestUserSequence()
+ sequence, err := u.view.GetLatestUserSequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(es_model.UserAggregate, org_es_model.OrgAggregate).
+ AggregateTypeFilter(u.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
@@ -120,14 +158,14 @@ func (u *User) ProcessUser(event *models.Event) (err error) {
}
err = u.fillLoginNames(user)
case es_model.UserRemoved:
- return u.view.DeleteUser(event.AggregateID, event.Sequence, event.CreationDate)
+ return u.view.DeleteUser(event.AggregateID, event)
default:
- return u.view.ProcessedUserSequence(event.Sequence, event.CreationDate)
+ return u.view.ProcessedUserSequence(event)
}
if err != nil {
return err
}
- return u.view.PutUser(user, user.Sequence, event.CreationDate)
+ return u.view.PutUser(user, event)
}
func (u *User) fillLoginNames(user *view_model.UserView) (err error) {
@@ -158,7 +196,7 @@ func (u *User) ProcessOrg(event *models.Event) (err error) {
case org_es_model.OrgDomainPrimarySet:
return u.fillPreferredLoginNamesOnOrgUsers(event)
default:
- return u.view.ProcessedUserSequence(event.Sequence, event.CreationDate)
+ return u.view.ProcessedUserSequence(event)
}
}
@@ -181,7 +219,7 @@ func (u *User) fillLoginNamesOnOrgUsers(event *models.Event) error {
for _, user := range users {
user.SetLoginNames(policy, org.Domains)
}
- return u.view.PutUsers(users, event.Sequence, event.CreationDate)
+ return u.view.PutUsers(users, event)
}
func (u *User) fillPreferredLoginNamesOnOrgUsers(event *models.Event) error {
@@ -206,7 +244,7 @@ func (u *User) fillPreferredLoginNamesOnOrgUsers(event *models.Event) error {
for _, user := range users {
user.PreferredLoginName = user.GenerateLoginName(org.GetPrimaryDomain().Domain, policy.UserLoginMustBeDomain)
}
- return u.view.PutUsers(users, 0, event.CreationDate)
+ return u.view.PutUsers(users, event)
}
func (u *User) OnError(event *models.Event, err error) error {
diff --git a/internal/auth/repository/eventsourcing/handler/user_external_idps.go b/internal/auth/repository/eventsourcing/handler/user_external_idps.go
index 826d79170c..8dcaebe3cb 100644
--- a/internal/auth/repository/eventsourcing/handler/user_external_idps.go
+++ b/internal/auth/repository/eventsourcing/handler/user_external_idps.go
@@ -2,11 +2,14 @@ package handler
import (
"context"
+
"github.com/caos/logging"
"github.com/caos/zitadel/internal/config/systemdefaults"
caos_errs "github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/iam/repository/eventsourcing"
@@ -18,28 +21,68 @@ import (
usr_view_model "github.com/caos/zitadel/internal/user/repository/view/model"
)
+const (
+ externalIDPTable = "auth.user_external_idps"
+)
+
type ExternalIDP struct {
handler
systemDefaults systemdefaults.SystemDefaults
iamEvents *eventsourcing.IAMEventstore
orgEvents *org_es.OrgEventstore
+ subscription *eventstore.Subscription
}
-const (
- externalIDPTable = "auth.user_external_idps"
-)
+func newExternalIDP(
+ handler handler,
+ defaults systemdefaults.SystemDefaults,
+ iamEvents *eventsourcing.IAMEventstore,
+ orgEvents *org_es.OrgEventstore,
+) *ExternalIDP {
+ h := &ExternalIDP{
+ handler: handler,
+ systemDefaults: defaults,
+ iamEvents: iamEvents,
+ orgEvents: orgEvents,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (i *ExternalIDP) subscribe() {
+ i.subscription = i.es.Subscribe(i.AggregateTypes()...)
+ go func() {
+ for event := range i.subscription.Events {
+ query.ReduceEvent(i, event)
+ }
+ }()
+}
func (i *ExternalIDP) ViewModel() string {
return externalIDPTable
}
+func (_ *ExternalIDP) AggregateTypes() []es_models.AggregateType {
+ return []es_models.AggregateType{model.UserAggregate, iam_es_model.IAMAggregate, org_es_model.OrgAggregate}
+}
+
+func (i *ExternalIDP) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := i.view.GetLatestExternalIDPSequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (i *ExternalIDP) EventQuery() (*models.SearchQuery, error) {
- sequence, err := i.view.GetLatestExternalIDPSequence()
+ sequence, err := i.view.GetLatestExternalIDPSequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(model.UserAggregate, iam_es_model.IAMAggregate, org_es_model.OrgAggregate).
+ AggregateTypeFilter(i.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
@@ -67,16 +110,16 @@ func (i *ExternalIDP) processUser(event *models.Event) (err error) {
if err != nil {
return err
}
- return i.view.DeleteExternalIDP(externalIDP.ExternalUserID, externalIDP.IDPConfigID, event.Sequence, event.CreationDate)
+ return i.view.DeleteExternalIDP(externalIDP.ExternalUserID, externalIDP.IDPConfigID, event)
case model.UserRemoved:
- return i.view.DeleteExternalIDPsByUserID(event.AggregateID, event.Sequence, event.CreationDate)
+ return i.view.DeleteExternalIDPsByUserID(event.AggregateID, event)
default:
- return i.view.ProcessedExternalIDPSequence(event.Sequence, event.CreationDate)
+ return i.view.ProcessedExternalIDPSequence(event)
}
if err != nil {
return err
}
- return i.view.PutExternalIDP(externalIDP, externalIDP.Sequence, event.CreationDate)
+ return i.view.PutExternalIDP(externalIDP, event)
}
func (i *ExternalIDP) processIdpConfig(event *models.Event) (err error) {
@@ -104,9 +147,9 @@ func (i *ExternalIDP) processIdpConfig(event *models.Event) (err error) {
for _, provider := range exterinalIDPs {
i.fillConfigData(provider, config)
}
- return i.view.PutExternalIDPs(event.Sequence, event.CreationDate, exterinalIDPs...)
+ return i.view.PutExternalIDPs(event, exterinalIDPs...)
default:
- return i.view.ProcessedExternalIDPSequence(event.Sequence, event.CreationDate)
+ return i.view.ProcessedExternalIDPSequence(event)
}
return nil
}
diff --git a/internal/auth/repository/eventsourcing/handler/user_grant.go b/internal/auth/repository/eventsourcing/handler/user_grant.go
index 8aa95311db..4244d0ac34 100644
--- a/internal/auth/repository/eventsourcing/handler/user_grant.go
+++ b/internal/auth/repository/eventsourcing/handler/user_grant.go
@@ -11,6 +11,7 @@ import (
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
iam_events "github.com/caos/zitadel/internal/iam/repository/eventsourcing"
iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
@@ -28,25 +29,68 @@ import (
"github.com/caos/zitadel/internal/v2/domain"
)
+const (
+ userGrantTable = "auth.user_grants"
+)
+
type UserGrant struct {
handler
- eventstore eventstore.Eventstore
projectEvents *proj_event.ProjectEventstore
userEvents *usr_events.UserEventstore
orgEvents *org_events.OrgEventstore
iamEvents *iam_events.IAMEventstore
iamID string
iamProjectID string
+ subscription *eventstore.Subscription
}
-const (
- userGrantTable = "auth.user_grants"
-)
+func newUserGrant(
+ handler handler,
+ projectEvents *proj_event.ProjectEventstore,
+ userEvents *usr_events.UserEventstore,
+ orgEvents *org_events.OrgEventstore,
+ iamEvents *iam_events.IAMEventstore,
+ iamID string,
+) *UserGrant {
+ h := &UserGrant{
+ handler: handler,
+ projectEvents: projectEvents,
+ userEvents: userEvents,
+ orgEvents: orgEvents,
+ iamEvents: iamEvents,
+ iamID: iamID,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (k *UserGrant) subscribe() {
+ k.subscription = k.es.Subscribe(k.AggregateTypes()...)
+ go func() {
+ for event := range k.subscription.Events {
+ query.ReduceEvent(k, event)
+ }
+ }()
+}
func (u *UserGrant) ViewModel() string {
return userGrantTable
}
+func (_ *UserGrant) AggregateTypes() []es_models.AggregateType {
+ return []es_models.AggregateType{grant_es_model.UserGrantAggregate, iam_es_model.IAMAggregate, org_es_model.OrgAggregate, usr_es_model.UserAggregate, proj_es_model.ProjectAggregate}
+}
+
+func (u *UserGrant) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := u.view.GetLatestUserGrantSequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (u *UserGrant) EventQuery() (*models.SearchQuery, error) {
if u.iamProjectID == "" {
err := u.setIamProjectID()
@@ -54,12 +98,12 @@ func (u *UserGrant) EventQuery() (*models.SearchQuery, error) {
return nil, err
}
}
- sequence, err := u.view.GetLatestUserGrantSequence()
+ sequence, err := u.view.GetLatestUserGrantSequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(grant_es_model.UserGrantAggregate, iam_es_model.IAMAggregate, org_es_model.OrgAggregate, usr_es_model.UserAggregate, proj_es_model.ProjectAggregate).
+ AggregateTypeFilter(u.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
@@ -98,14 +142,14 @@ func (u *UserGrant) processUserGrant(event *models.Event) (err error) {
}
err = grant.AppendEvent(event)
case grant_es_model.UserGrantRemoved, grant_es_model.UserGrantCascadeRemoved:
- return u.view.DeleteUserGrant(event.AggregateID, event.Sequence, event.CreationDate)
+ return u.view.DeleteUserGrant(event.AggregateID, event)
default:
- return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
+ return u.view.ProcessedUserGrantSequence(event)
}
if err != nil {
return err
}
- return u.view.PutUserGrant(grant, grant.Sequence, event.CreationDate)
+ return u.view.PutUserGrant(grant, event)
}
func (u *UserGrant) processUser(event *models.Event) (err error) {
@@ -120,7 +164,7 @@ func (u *UserGrant) processUser(event *models.Event) (err error) {
return err
}
if len(grants) == 0 {
- return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
+ return u.view.ProcessedUserGrantSequence(event)
}
user, err := u.userEvents.UserByID(context.Background(), event.AggregateID)
if err != nil {
@@ -129,9 +173,9 @@ func (u *UserGrant) processUser(event *models.Event) (err error) {
for _, grant := range grants {
u.fillUserData(grant, user)
}
- return u.view.PutUserGrants(grants, event.Sequence, event.CreationDate)
+ return u.view.PutUserGrants(grants, event)
default:
- return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
+ return u.view.ProcessedUserGrantSequence(event)
}
}
@@ -149,7 +193,7 @@ func (u *UserGrant) processProject(event *models.Event) (err error) {
for _, grant := range grants {
u.fillProjectData(grant, project)
}
- return u.view.PutUserGrants(grants, event.Sequence, event.CreationDate)
+ return u.view.PutUserGrants(grants, event)
case proj_es_model.ProjectMemberAdded, proj_es_model.ProjectMemberChanged, proj_es_model.ProjectMemberRemoved:
member := new(proj_es_model.ProjectMember)
member.SetData(event)
@@ -159,7 +203,7 @@ func (u *UserGrant) processProject(event *models.Event) (err error) {
member.SetData(event)
return u.processMember(event, "PROJECT_GRANT", member.GrantID, member.UserID, member.Roles)
default:
- return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
+ return u.view.ProcessedUserGrantSequence(event)
}
}
@@ -170,7 +214,7 @@ func (u *UserGrant) processOrg(event *models.Event) (err error) {
member.SetData(event)
return u.processMember(event, "ORG", "", member.UserID, member.Roles)
default:
- return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
+ return u.view.ProcessedUserGrantSequence(event)
}
}
@@ -208,16 +252,16 @@ func (u *UserGrant) processIAMMember(event *models.Event, rolePrefix string, suf
}
grant.Sequence = event.Sequence
grant.ChangeDate = event.CreationDate
- return u.view.PutUserGrant(grant, grant.Sequence, event.CreationDate)
+ return u.view.PutUserGrant(grant, event)
case iam_es_model.IAMMemberRemoved:
member.SetData(event)
grant, err := u.view.UserGrantByIDs(u.iamID, u.iamProjectID, member.UserID)
if err != nil {
return err
}
- return u.view.DeleteUserGrant(grant.ID, event.Sequence, event.CreationDate)
+ return u.view.DeleteUserGrant(grant.ID, event)
default:
- return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
+ return u.view.ProcessedUserGrantSequence(event)
}
}
@@ -253,7 +297,7 @@ func (u *UserGrant) processMember(event *models.Event, rolePrefix, roleSuffix st
}
grant.Sequence = event.Sequence
grant.ChangeDate = event.CreationDate
- return u.view.PutUserGrant(grant, event.Sequence, event.CreationDate)
+ return u.view.PutUserGrant(grant, event)
case org_es_model.OrgMemberRemoved,
proj_es_model.ProjectMemberRemoved,
proj_es_model.ProjectGrantMemberRemoved:
@@ -263,18 +307,18 @@ func (u *UserGrant) processMember(event *models.Event, rolePrefix, roleSuffix st
return err
}
if errors.IsNotFound(err) {
- return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
+ return u.view.ProcessedUserGrantSequence(event)
}
if roleSuffix != "" {
roleKeys = suffixRoles(roleSuffix, roleKeys)
}
if grant.RoleKeys == nil {
- return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
+ return u.view.ProcessedUserGrantSequence(event)
}
grant.RoleKeys = mergeExistingRoles(rolePrefix, roleSuffix, grant.RoleKeys, nil)
- return u.view.PutUserGrant(grant, event.Sequence, event.CreationDate)
+ return u.view.PutUserGrant(grant, event)
default:
- return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
+ return u.view.ProcessedUserGrantSequence(event)
}
}
diff --git a/internal/auth/repository/eventsourcing/handler/user_membership.go b/internal/auth/repository/eventsourcing/handler/user_membership.go
index 7b231a78b5..e1a41eccf5 100644
--- a/internal/auth/repository/eventsourcing/handler/user_membership.go
+++ b/internal/auth/repository/eventsourcing/handler/user_membership.go
@@ -2,52 +2,90 @@ package handler
import (
"context"
- "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
+ "github.com/caos/logging"
+ "github.com/caos/zitadel/internal/eventstore"
+ "github.com/caos/zitadel/internal/eventstore/models"
+ es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
+ "github.com/caos/zitadel/internal/eventstore/spooler"
iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
org_model "github.com/caos/zitadel/internal/org/model"
org_event "github.com/caos/zitadel/internal/org/repository/eventsourcing"
+ org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing"
proj_es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model"
-
- "github.com/caos/logging"
-
- "github.com/caos/zitadel/internal/eventstore/models"
- es_models "github.com/caos/zitadel/internal/eventstore/models"
- "github.com/caos/zitadel/internal/eventstore/spooler"
- org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
usr_model "github.com/caos/zitadel/internal/user/model"
+ "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
usr_es_model "github.com/caos/zitadel/internal/user/repository/view/model"
)
+const (
+ userMembershipTable = "auth.user_memberships"
+)
+
type UserMembership struct {
handler
orgEvents *org_event.OrgEventstore
projectEvents *proj_event.ProjectEventstore
+ subscription *eventstore.Subscription
}
-const (
- userMembershipTable = "auth.user_memberships"
-)
+func newUserMembership(
+ handler handler,
+ orgEvents *org_event.OrgEventstore,
+ projectEvents *proj_event.ProjectEventstore,
+) *UserMembership {
+ h := &UserMembership{
+ handler: handler,
+ orgEvents: orgEvents,
+ projectEvents: projectEvents,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (m *UserMembership) subscribe() {
+ m.subscription = m.es.Subscribe(m.AggregateTypes()...)
+ go func() {
+ for event := range m.subscription.Events {
+ query.ReduceEvent(m, event)
+ }
+ }()
+}
func (m *UserMembership) ViewModel() string {
return userMembershipTable
}
+func (_ *UserMembership) AggregateTypes() []es_models.AggregateType {
+ return []es_models.AggregateType{iam_es_model.IAMAggregate, org_es_model.OrgAggregate, proj_es_model.ProjectAggregate, model.UserAggregate}
+}
+
+func (m *UserMembership) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := m.view.GetLatestUserMembershipSequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (m *UserMembership) EventQuery() (*models.SearchQuery, error) {
- sequence, err := m.view.GetLatestUserMembershipSequence()
+ sequence, err := m.view.GetLatestUserMembershipSequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(iam_es_model.IAMAggregate, org_es_model.OrgAggregate, proj_es_model.ProjectAggregate, model.UserAggregate).
+ AggregateTypeFilter(m.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
func (m *UserMembership) Reduce(event *models.Event) (err error) {
switch event.AggregateType {
case iam_es_model.IAMAggregate:
- err = m.processIam(event)
+ err = m.processIAM(event)
case org_es_model.OrgAggregate:
err = m.processOrg(event)
case proj_es_model.ProjectAggregate:
@@ -58,7 +96,7 @@ func (m *UserMembership) Reduce(event *models.Event) (err error) {
return err
}
-func (m *UserMembership) processIam(event *models.Event) (err error) {
+func (m *UserMembership) processIAM(event *models.Event) (err error) {
member := new(usr_es_model.UserMembershipView)
err = member.AppendEvent(event)
if err != nil {
@@ -74,14 +112,14 @@ func (m *UserMembership) processIam(event *models.Event) (err error) {
}
err = member.AppendEvent(event)
case iam_es_model.IAMMemberRemoved:
- return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeIam, event.Sequence, event.CreationDate)
+ return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeIam, event)
default:
- return m.view.ProcessedUserMembershipSequence(event.Sequence, event.CreationDate)
+ return m.view.ProcessedUserMembershipSequence(event)
}
if err != nil {
return err
}
- return m.view.PutUserMembership(member, event.Sequence, event.CreationDate)
+ return m.view.PutUserMembership(member, event)
}
func (m *UserMembership) fillIamDisplayName(member *usr_es_model.UserMembershipView) {
@@ -105,16 +143,16 @@ func (m *UserMembership) processOrg(event *models.Event) (err error) {
}
err = member.AppendEvent(event)
case org_es_model.OrgMemberRemoved:
- return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeOrganisation, event.Sequence, event.CreationDate)
+ return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeOrganisation, event)
case org_es_model.OrgChanged:
return m.updateOrgName(event)
default:
- return m.view.ProcessedUserMembershipSequence(event.Sequence, event.CreationDate)
+ return m.view.ProcessedUserMembershipSequence(event)
}
if err != nil {
return err
}
- return m.view.PutUserMembership(member, event.Sequence, event.CreationDate)
+ return m.view.PutUserMembership(member, event)
}
func (m *UserMembership) fillOrgName(member *usr_es_model.UserMembershipView) (err error) {
@@ -145,7 +183,7 @@ func (m *UserMembership) updateOrgName(event *models.Event) error {
membership.DisplayName = org.Name
}
}
- return m.view.BulkPutUserMemberships(memberships, event.Sequence, event.CreationDate)
+ return m.view.BulkPutUserMemberships(memberships, event)
}
func (m *UserMembership) processProject(event *models.Event) (err error) {
@@ -168,7 +206,7 @@ func (m *UserMembership) processProject(event *models.Event) (err error) {
}
err = member.AppendEvent(event)
case proj_es_model.ProjectMemberRemoved:
- return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeProject, event.Sequence, event.CreationDate)
+ return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeProject, event)
case proj_es_model.ProjectGrantMemberChanged:
member, err = m.view.UserMembershipByIDs(member.UserID, event.AggregateID, member.ObjectID, usr_model.MemberTypeProjectGrant)
if err != nil {
@@ -176,20 +214,20 @@ func (m *UserMembership) processProject(event *models.Event) (err error) {
}
err = member.AppendEvent(event)
case proj_es_model.ProjectGrantMemberRemoved:
- return m.view.DeleteUserMembership(member.UserID, event.AggregateID, member.ObjectID, usr_model.MemberTypeProjectGrant, event.Sequence, event.CreationDate)
+ return m.view.DeleteUserMembership(member.UserID, event.AggregateID, member.ObjectID, usr_model.MemberTypeProjectGrant, event)
case proj_es_model.ProjectChanged:
return m.updateProjectDisplayName(event)
case proj_es_model.ProjectRemoved:
- return m.view.DeleteUserMembershipsByAggregateID(event.AggregateID, event.Sequence, event.CreationDate)
+ return m.view.DeleteUserMembershipsByAggregateID(event.AggregateID, event)
case proj_es_model.ProjectGrantRemoved:
- return m.view.DeleteUserMembershipsByAggregateIDAndObjectID(event.AggregateID, member.ObjectID, event.Sequence, event.CreationDate)
+ return m.view.DeleteUserMembershipsByAggregateIDAndObjectID(event.AggregateID, member.ObjectID, event)
default:
- return m.view.ProcessedUserMembershipSequence(event.Sequence, event.CreationDate)
+ return m.view.ProcessedUserMembershipSequence(event)
}
if err != nil {
return err
}
- return m.view.PutUserMembership(member, event.Sequence, event.CreationDate)
+ return m.view.PutUserMembership(member, event)
}
func (m *UserMembership) fillProjectDisplayName(member *usr_es_model.UserMembershipView) (err error) {
@@ -214,15 +252,15 @@ func (m *UserMembership) updateProjectDisplayName(event *models.Event) error {
for _, membership := range memberships {
membership.DisplayName = project.Name
}
- return m.view.BulkPutUserMemberships(memberships, event.Sequence, event.CreationDate)
+ return m.view.BulkPutUserMemberships(memberships, event)
}
func (m *UserMembership) processUser(event *models.Event) (err error) {
switch event.Type {
case model.UserRemoved:
- return m.view.DeleteUserMembershipsByUserID(event.AggregateID, event.Sequence, event.CreationDate)
+ return m.view.DeleteUserMembershipsByUserID(event.AggregateID, event)
default:
- return m.view.ProcessedUserMembershipSequence(event.Sequence, event.CreationDate)
+ return m.view.ProcessedUserMembershipSequence(event)
}
}
diff --git a/internal/auth/repository/eventsourcing/handler/user_session.go b/internal/auth/repository/eventsourcing/handler/user_session.go
index b55aacfd63..7ef182f6ae 100644
--- a/internal/auth/repository/eventsourcing/handler/user_session.go
+++ b/internal/auth/repository/eventsourcing/handler/user_session.go
@@ -1,34 +1,70 @@
package handler
import (
+ "github.com/caos/logging"
req_model "github.com/caos/zitadel/internal/auth_request/model"
"github.com/caos/zitadel/internal/errors"
- es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
-
- "github.com/caos/logging"
-
+ "github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
"github.com/caos/zitadel/internal/user/repository/eventsourcing"
user_events "github.com/caos/zitadel/internal/user/repository/eventsourcing"
+ es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
view_model "github.com/caos/zitadel/internal/user/repository/view/model"
)
-type UserSession struct {
- handler
- userEvents *user_events.UserEventstore
-}
-
const (
userSessionTable = "auth.user_sessions"
)
+type UserSession struct {
+ handler
+ userEvents *user_events.UserEventstore
+ subscription *eventstore.Subscription
+}
+
+func newUserSession(
+ handler handler,
+ userEvents *user_events.UserEventstore,
+) *UserSession {
+ h := &UserSession{
+ handler: handler,
+ userEvents: userEvents,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (k *UserSession) subscribe() {
+ k.subscription = k.es.Subscribe(k.AggregateTypes()...)
+ go func() {
+ for event := range k.subscription.Events {
+ query.ReduceEvent(k, event)
+ }
+ }()
+}
+
func (u *UserSession) ViewModel() string {
return userSessionTable
}
+func (_ *UserSession) AggregateTypes() []models.AggregateType {
+ return []models.AggregateType{es_model.UserAggregate}
+}
+
+func (u *UserSession) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := u.view.GetLatestUserSessionSequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (u *UserSession) EventQuery() (*models.SearchQuery, error) {
- sequence, err := u.view.GetLatestUserSessionSequence()
+ sequence, err := u.view.GetLatestUserSessionSequence("")
if err != nil {
return nil, err
}
@@ -90,7 +126,7 @@ func (u *UserSession) Reduce(event *models.Event) (err error) {
return err
}
if len(sessions) == 0 {
- return u.view.ProcessedUserSessionSequence(event.Sequence, event.CreationDate)
+ return u.view.ProcessedUserSessionSequence(event)
}
for _, session := range sessions {
if err := session.AppendEvent(event); err != nil {
@@ -100,11 +136,11 @@ func (u *UserSession) Reduce(event *models.Event) (err error) {
return err
}
}
- return u.view.PutUserSessions(sessions, event.Sequence, event.CreationDate)
+ return u.view.PutUserSessions(sessions, event)
case es_model.UserRemoved:
- return u.view.DeleteUserSessions(event.AggregateID, event.Sequence, event.CreationDate)
+ return u.view.DeleteUserSessions(event.AggregateID, event)
default:
- return u.view.ProcessedUserSessionSequence(event.Sequence, event.CreationDate)
+ return u.view.ProcessedUserSessionSequence(event)
}
}
@@ -124,7 +160,7 @@ func (u *UserSession) updateSession(session *view_model.UserSessionView, event *
if err := u.fillUserInfo(session, event.AggregateID); err != nil {
return err
}
- return u.view.PutUserSession(session, event.CreationDate)
+ return u.view.PutUserSession(session, event)
}
func (u *UserSession) fillUserInfo(session *view_model.UserSessionView, id string) error {
diff --git a/internal/auth/repository/eventsourcing/spooler/lock.go b/internal/auth/repository/eventsourcing/spooler/lock.go
index 1a7ea2990e..5b69f3ae0c 100644
--- a/internal/auth/repository/eventsourcing/spooler/lock.go
+++ b/internal/auth/repository/eventsourcing/spooler/lock.go
@@ -2,8 +2,9 @@ package spooler
import (
"database/sql"
- es_locker "github.com/caos/zitadel/internal/eventstore/locker"
"time"
+
+ es_locker "github.com/caos/zitadel/internal/eventstore/locker"
)
const (
diff --git a/internal/auth/repository/eventsourcing/view/application.go b/internal/auth/repository/eventsourcing/view/application.go
index 556d31d251..5a7f2c6f1b 100644
--- a/internal/auth/repository/eventsourcing/view/application.go
+++ b/internal/auth/repository/eventsourcing/view/application.go
@@ -2,13 +2,14 @@ package view
import (
"context"
+
"github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
global_model "github.com/caos/zitadel/internal/model"
proj_model "github.com/caos/zitadel/internal/project/model"
"github.com/caos/zitadel/internal/project/repository/view"
"github.com/caos/zitadel/internal/project/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -27,28 +28,28 @@ func (v *View) SearchApplications(request *proj_model.ApplicationSearchRequest)
return view.SearchApplications(v.Db, applicationTable, request)
}
-func (v *View) PutApplication(app *model.ApplicationView, eventTimestamp time.Time) error {
+func (v *View) PutApplication(app *model.ApplicationView, event *models.Event) error {
err := view.PutApplication(v.Db, applicationTable, app)
if err != nil {
return err
}
- return v.ProcessedApplicationSequence(app.Sequence, eventTimestamp)
+ return v.ProcessedApplicationSequence(event)
}
-func (v *View) PutApplications(apps []*model.ApplicationView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutApplications(apps []*model.ApplicationView, event *models.Event) error {
err := view.PutApplications(v.Db, applicationTable, apps...)
if err != nil {
return err
}
- return v.ProcessedApplicationSequence(sequence, eventTimestamp)
+ return v.ProcessedApplicationSequence(event)
}
-func (v *View) DeleteApplication(appID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteApplication(appID string, event *models.Event) error {
err := view.DeleteApplication(v.Db, applicationTable, appID)
- if err != nil {
- return nil
+ if err != nil && !errors.IsNotFound(err) {
+ return err
}
- return v.ProcessedApplicationSequence(eventSequence, eventTimestamp)
+ return v.ProcessedApplicationSequence(event)
}
func (v *View) DeleteApplicationsByProjectID(projectID string) error {
@@ -56,11 +57,11 @@ func (v *View) DeleteApplicationsByProjectID(projectID string) error {
}
func (v *View) GetLatestApplicationSequence() (*repository.CurrentSequence, error) {
- return v.latestSequence(applicationTable)
+ return v.latestSequence(applicationTable, "")
}
-func (v *View) ProcessedApplicationSequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(applicationTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedApplicationSequence(event *models.Event) error {
+ return v.saveCurrentSequence(applicationTable, event)
}
func (v *View) UpdateApplicationSpoolerRunTimestamp() error {
diff --git a/internal/auth/repository/eventsourcing/view/external_idps.go b/internal/auth/repository/eventsourcing/view/external_idps.go
index 1381611037..2928421cdc 100644
--- a/internal/auth/repository/eventsourcing/view/external_idps.go
+++ b/internal/auth/repository/eventsourcing/view/external_idps.go
@@ -2,11 +2,11 @@ package view
import (
"github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
usr_model "github.com/caos/zitadel/internal/user/model"
"github.com/caos/zitadel/internal/user/repository/view"
"github.com/caos/zitadel/internal/user/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -33,44 +33,44 @@ func (v *View) SearchExternalIDPs(request *usr_model.ExternalIDPSearchRequest) (
return view.SearchExternalIDPs(v.Db, externalIDPTable, request)
}
-func (v *View) PutExternalIDP(externalIDP *model.ExternalIDPView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutExternalIDP(externalIDP *model.ExternalIDPView, event *models.Event) error {
err := view.PutExternalIDP(v.Db, externalIDPTable, externalIDP)
if err != nil {
return err
}
- return v.ProcessedExternalIDPSequence(sequence, eventTimestamp)
+ return v.ProcessedExternalIDPSequence(event)
}
-func (v *View) PutExternalIDPs(sequence uint64, eventTimestamp time.Time, externalIDPs ...*model.ExternalIDPView) error {
+func (v *View) PutExternalIDPs(event *models.Event, externalIDPs ...*model.ExternalIDPView) error {
err := view.PutExternalIDPs(v.Db, externalIDPTable, externalIDPs...)
if err != nil {
return err
}
- return v.ProcessedExternalIDPSequence(sequence, eventTimestamp)
+ return v.ProcessedExternalIDPSequence(event)
}
-func (v *View) DeleteExternalIDP(externalUserID, idpConfigID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteExternalIDP(externalUserID, idpConfigID string, event *models.Event) error {
err := view.DeleteExternalIDP(v.Db, externalIDPTable, externalUserID, idpConfigID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedExternalIDPSequence(eventSequence, eventTimestamp)
+ return v.ProcessedExternalIDPSequence(event)
}
-func (v *View) DeleteExternalIDPsByUserID(userID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteExternalIDPsByUserID(userID string, event *models.Event) error {
err := view.DeleteExternalIDPsByUserID(v.Db, externalIDPTable, userID)
if err != nil {
return err
}
- return v.ProcessedExternalIDPSequence(eventSequence, eventTimestamp)
+ return v.ProcessedExternalIDPSequence(event)
}
-func (v *View) GetLatestExternalIDPSequence() (*global_view.CurrentSequence, error) {
- return v.latestSequence(externalIDPTable)
+func (v *View) GetLatestExternalIDPSequence(aggregateType string) (*global_view.CurrentSequence, error) {
+ return v.latestSequence(externalIDPTable, aggregateType)
}
-func (v *View) ProcessedExternalIDPSequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(externalIDPTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedExternalIDPSequence(event *models.Event) error {
+ return v.saveCurrentSequence(externalIDPTable, event)
}
func (v *View) UpdateExternalIDPSpoolerRunTimestamp() error {
diff --git a/internal/auth/repository/eventsourcing/view/idp_configs.go b/internal/auth/repository/eventsourcing/view/idp_configs.go
index df591a7a00..65a932b2d1 100644
--- a/internal/auth/repository/eventsourcing/view/idp_configs.go
+++ b/internal/auth/repository/eventsourcing/view/idp_configs.go
@@ -2,11 +2,11 @@ package view
import (
"github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/iam/repository/view"
iam_es_model "github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -25,28 +25,28 @@ func (v *View) SearchIDPConfigs(request *iam_model.IDPConfigSearchRequest) ([]*i
return view.SearchIDPs(v.Db, idpConfigTable, request)
}
-func (v *View) PutIDPConfig(idp *iam_es_model.IDPConfigView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutIDPConfig(idp *iam_es_model.IDPConfigView, event *models.Event) error {
err := view.PutIDP(v.Db, idpConfigTable, idp)
if err != nil {
return err
}
- return v.ProcessedIDPConfigSequence(sequence, eventTimestamp)
+ return v.ProcessedIDPConfigSequence(event)
}
-func (v *View) DeleteIDPConfig(idpID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteIDPConfig(idpID string, event *models.Event) error {
err := view.DeleteIDP(v.Db, idpConfigTable, idpID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedIDPConfigSequence(eventSequence, eventTimestamp)
+ return v.ProcessedIDPConfigSequence(event)
}
-func (v *View) GetLatestIDPConfigSequence() (*global_view.CurrentSequence, error) {
- return v.latestSequence(idpConfigTable)
+func (v *View) GetLatestIDPConfigSequence(aggregateType string) (*global_view.CurrentSequence, error) {
+ return v.latestSequence(idpConfigTable, aggregateType)
}
-func (v *View) ProcessedIDPConfigSequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(idpConfigTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedIDPConfigSequence(event *models.Event) error {
+ return v.saveCurrentSequence(idpConfigTable, event)
}
func (v *View) UpdateIDPConfigSpoolerRunTimestamp() error {
diff --git a/internal/auth/repository/eventsourcing/view/idp_providers.go b/internal/auth/repository/eventsourcing/view/idp_providers.go
index cf81e63745..afd25c15f8 100644
--- a/internal/auth/repository/eventsourcing/view/idp_providers.go
+++ b/internal/auth/repository/eventsourcing/view/idp_providers.go
@@ -2,11 +2,11 @@ package view
import (
"github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -29,44 +29,44 @@ func (v *View) SearchIDPProviders(request *iam_model.IDPProviderSearchRequest) (
return view.SearchIDPProviders(v.Db, idpProviderTable, request)
}
-func (v *View) PutIDPProvider(provider *model.IDPProviderView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutIDPProvider(provider *model.IDPProviderView, event *models.Event) error {
err := view.PutIDPProvider(v.Db, idpProviderTable, provider)
if err != nil {
return err
}
- return v.ProcessedIDPProviderSequence(sequence, eventTimestamp)
+ return v.ProcessedIDPProviderSequence(event)
}
-func (v *View) PutIDPProviders(sequence uint64, eventTimestamp time.Time, providers ...*model.IDPProviderView) error {
+func (v *View) PutIDPProviders(event *models.Event, providers ...*model.IDPProviderView) error {
err := view.PutIDPProviders(v.Db, idpProviderTable, providers...)
if err != nil {
return err
}
- return v.ProcessedIDPProviderSequence(sequence, eventTimestamp)
+ return v.ProcessedIDPProviderSequence(event)
}
-func (v *View) DeleteIDPProvider(aggregateID, idpConfigID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteIDPProvider(aggregateID, idpConfigID string, event *models.Event) error {
err := view.DeleteIDPProvider(v.Db, idpProviderTable, aggregateID, idpConfigID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedIDPProviderSequence(eventSequence, eventTimestamp)
+ return v.ProcessedIDPProviderSequence(event)
}
-func (v *View) DeleteIDPProvidersByAggregateID(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteIDPProvidersByAggregateID(aggregateID string, event *models.Event) error {
err := view.DeleteIDPProvidersByAggregateID(v.Db, idpProviderTable, aggregateID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedIDPProviderSequence(eventSequence, eventTimestamp)
+ return v.ProcessedIDPProviderSequence(event)
}
-func (v *View) GetLatestIDPProviderSequence() (*global_view.CurrentSequence, error) {
- return v.latestSequence(idpProviderTable)
+func (v *View) GetLatestIDPProviderSequence(aggregateType string) (*global_view.CurrentSequence, error) {
+ return v.latestSequence(idpProviderTable, aggregateType)
}
-func (v *View) ProcessedIDPProviderSequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(idpProviderTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedIDPProviderSequence(event *models.Event) error {
+ return v.saveCurrentSequence(idpProviderTable, event)
}
func (v *View) UpdateIDPProviderSpoolerRunTimestamp() error {
diff --git a/internal/auth/repository/eventsourcing/view/key.go b/internal/auth/repository/eventsourcing/view/key.go
index c0c0f7d357..f8fca89445 100644
--- a/internal/auth/repository/eventsourcing/view/key.go
+++ b/internal/auth/repository/eventsourcing/view/key.go
@@ -1,11 +1,12 @@
package view
import (
+ "github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
key_model "github.com/caos/zitadel/internal/key/model"
"github.com/caos/zitadel/internal/key/repository/view"
"github.com/caos/zitadel/internal/key/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -32,36 +33,36 @@ func (v *View) GetActiveKeySet() ([]*key_model.PublicKey, error) {
return key_model.PublicKeysFromKeyView(model.KeyViewsToModel(keys), v.keyAlgorithm)
}
-func (v *View) PutKeys(privateKey, publicKey *model.KeyView, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutKeys(privateKey, publicKey *model.KeyView, event *models.Event) error {
err := view.PutKeys(v.Db, keyTable, privateKey, publicKey)
if err != nil {
return err
}
- return v.ProcessedKeySequence(eventSequence, eventTimestamp)
+ return v.ProcessedKeySequence(event)
}
-func (v *View) DeleteKey(keyID string, private bool, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteKey(keyID string, private bool, event *models.Event) error {
err := view.DeleteKey(v.Db, keyTable, keyID, private)
- if err != nil {
- return nil
+ if err != nil && !errors.IsNotFound(err) {
+ return err
}
- return v.ProcessedKeySequence(eventSequence, eventTimestamp)
+ return v.ProcessedKeySequence(event)
}
-func (v *View) DeleteKeyPair(keyID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteKeyPair(keyID string, event *models.Event) error {
err := view.DeleteKeyPair(v.Db, keyTable, keyID)
- if err != nil {
- return nil
+ if err != nil && !errors.IsNotFound(err) {
+ return err
}
- return v.ProcessedKeySequence(eventSequence, eventTimestamp)
+ return v.ProcessedKeySequence(event)
}
-func (v *View) GetLatestKeySequence() (*repository.CurrentSequence, error) {
- return v.latestSequence(keyTable)
+func (v *View) GetLatestKeySequence(aggregateType string) (*repository.CurrentSequence, error) {
+ return v.latestSequence(keyTable, aggregateType)
}
-func (v *View) ProcessedKeySequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(keyTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedKeySequence(event *models.Event) error {
+ return v.saveCurrentSequence(keyTable, event)
}
func (v *View) UpdateKeySpoolerRunTimestamp() error {
diff --git a/internal/auth/repository/eventsourcing/view/login_policies.go b/internal/auth/repository/eventsourcing/view/login_policies.go
index 2da8862129..2687cd8b6d 100644
--- a/internal/auth/repository/eventsourcing/view/login_policies.go
+++ b/internal/auth/repository/eventsourcing/view/login_policies.go
@@ -2,10 +2,10 @@ package view
import (
"github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -16,28 +16,28 @@ func (v *View) LoginPolicyByAggregateID(aggregateID string) (*model.LoginPolicyV
return view.GetLoginPolicyByAggregateID(v.Db, loginPolicyTable, aggregateID)
}
-func (v *View) PutLoginPolicy(policy *model.LoginPolicyView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutLoginPolicy(policy *model.LoginPolicyView, event *models.Event) error {
err := view.PutLoginPolicy(v.Db, loginPolicyTable, policy)
if err != nil {
return err
}
- return v.ProcessedLoginPolicySequence(sequence, eventTimestamp)
+ return v.ProcessedLoginPolicySequence(event)
}
-func (v *View) DeleteLoginPolicy(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteLoginPolicy(aggregateID string, event *models.Event) error {
err := view.DeleteLoginPolicy(v.Db, loginPolicyTable, aggregateID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedLoginPolicySequence(eventSequence, eventTimestamp)
+ return v.ProcessedLoginPolicySequence(event)
}
-func (v *View) GetLatestLoginPolicySequence() (*global_view.CurrentSequence, error) {
- return v.latestSequence(loginPolicyTable)
+func (v *View) GetLatestLoginPolicySequence(aggregateType string) (*global_view.CurrentSequence, error) {
+ return v.latestSequence(loginPolicyTable, aggregateType)
}
-func (v *View) ProcessedLoginPolicySequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(loginPolicyTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedLoginPolicySequence(event *models.Event) error {
+ return v.saveCurrentSequence(loginPolicyTable, event)
}
func (v *View) UpdateLoginPolicySpoolerRunTimestamp() error {
diff --git a/internal/auth/repository/eventsourcing/view/machine_keys.go b/internal/auth/repository/eventsourcing/view/machine_keys.go
index ac1a442566..b5412d7240 100644
--- a/internal/auth/repository/eventsourcing/view/machine_keys.go
+++ b/internal/auth/repository/eventsourcing/view/machine_keys.go
@@ -1,11 +1,12 @@
package view
import (
+ "github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
usr_model "github.com/caos/zitadel/internal/user/model"
"github.com/caos/zitadel/internal/user/repository/view"
"github.com/caos/zitadel/internal/user/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -28,39 +29,36 @@ func (v *View) SearchMachineKeys(request *usr_model.MachineKeySearchRequest) ([]
return view.SearchMachineKeys(v.Db, machineKeyTable, request)
}
-func (v *View) PutMachineKey(key *model.MachineKeyView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutMachineKey(key *model.MachineKeyView, event *models.Event) error {
err := view.PutMachineKey(v.Db, machineKeyTable, key)
if err != nil {
return err
}
- if sequence != 0 {
- return v.ProcessedMachineKeySequence(sequence, eventTimestamp)
- }
- return nil
+ return v.ProcessedMachineKeySequence(event)
}
-func (v *View) DeleteMachineKey(keyID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteMachineKey(keyID string, event *models.Event) error {
err := view.DeleteMachineKey(v.Db, machineKeyTable, keyID)
- if err != nil {
- return nil
+ if err != nil && !errors.IsNotFound(err) {
+ return err
}
- return v.ProcessedMachineKeySequence(eventSequence, eventTimestamp)
+ return v.ProcessedMachineKeySequence(event)
}
-func (v *View) DeleteMachineKeysByUserID(userID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteMachineKeysByUserID(userID string, event *models.Event) error {
err := view.DeleteMachineKey(v.Db, machineKeyTable, userID)
- if err != nil {
- return nil
+ if err != nil && !errors.IsNotFound(err) {
+ return err
}
- return v.ProcessedMachineKeySequence(eventSequence, eventTimestamp)
+ return v.ProcessedMachineKeySequence(event)
}
-func (v *View) GetLatestMachineKeySequence() (*repository.CurrentSequence, error) {
- return v.latestSequence(machineKeyTable)
+func (v *View) GetLatestMachineKeySequence(aggregateType string) (*repository.CurrentSequence, error) {
+ return v.latestSequence(machineKeyTable, aggregateType)
}
-func (v *View) ProcessedMachineKeySequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(machineKeyTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedMachineKeySequence(event *models.Event) error {
+ return v.saveCurrentSequence(machineKeyTable, event)
}
func (v *View) UpdateMachineKeySpoolerRunTimestamp() error {
diff --git a/internal/auth/repository/eventsourcing/view/org.go b/internal/auth/repository/eventsourcing/view/org.go
index 9f489f5c30..1b9a7c1b4c 100644
--- a/internal/auth/repository/eventsourcing/view/org.go
+++ b/internal/auth/repository/eventsourcing/view/org.go
@@ -1,11 +1,11 @@
package view
import (
+ "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/org/model"
org_view "github.com/caos/zitadel/internal/org/repository/view"
org_model "github.com/caos/zitadel/internal/org/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -24,12 +24,12 @@ func (v *View) SearchOrgs(req *model.OrgSearchRequest) ([]*org_model.OrgView, ui
return org_view.SearchOrgs(v.Db, orgTable, req)
}
-func (v *View) PutOrg(org *org_model.OrgView, eventTimestamp time.Time) error {
+func (v *View) PutOrg(org *org_model.OrgView, event *models.Event) error {
err := org_view.PutOrg(v.Db, orgTable, org)
if err != nil {
return err
}
- return v.ProcessedOrgSequence(org.Sequence, eventTimestamp)
+ return v.ProcessedOrgSequence(event)
}
func (v *View) GetLatestOrgFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
@@ -44,10 +44,10 @@ func (v *View) UpdateOrgSpoolerRunTimestamp() error {
return v.updateSpoolerRunSequence(orgTable)
}
-func (v *View) GetLatestOrgSequence() (*repository.CurrentSequence, error) {
- return v.latestSequence(orgTable)
+func (v *View) GetLatestOrgSequence(aggregateType string) (*repository.CurrentSequence, error) {
+ return v.latestSequence(orgTable, aggregateType)
}
-func (v *View) ProcessedOrgSequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(orgTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedOrgSequence(event *models.Event) error {
+ return v.saveCurrentSequence(orgTable, event)
}
diff --git a/internal/auth/repository/eventsourcing/view/org_iam_policy.go b/internal/auth/repository/eventsourcing/view/org_iam_policy.go
index a9ee5a295f..a05592dae3 100644
--- a/internal/auth/repository/eventsourcing/view/org_iam_policy.go
+++ b/internal/auth/repository/eventsourcing/view/org_iam_policy.go
@@ -2,10 +2,10 @@ package view
import (
"github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -16,28 +16,28 @@ func (v *View) OrgIAMPolicyByAggregateID(aggregateID string) (*model.OrgIAMPolic
return view.GetOrgIAMPolicyByAggregateID(v.Db, orgIAMPolicyTable, aggregateID)
}
-func (v *View) PutOrgIAMPolicy(policy *model.OrgIAMPolicyView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutOrgIAMPolicy(policy *model.OrgIAMPolicyView, event *models.Event) error {
err := view.PutOrgIAMPolicy(v.Db, orgIAMPolicyTable, policy)
if err != nil {
return err
}
- return v.ProcessedOrgIAMPolicySequence(sequence, eventTimestamp)
+ return v.ProcessedOrgIAMPolicySequence(event)
}
-func (v *View) DeleteOrgIAMPolicy(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteOrgIAMPolicy(aggregateID string, event *models.Event) error {
err := view.DeleteOrgIAMPolicy(v.Db, orgIAMPolicyTable, aggregateID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedOrgIAMPolicySequence(eventSequence, eventTimestamp)
+ return v.ProcessedOrgIAMPolicySequence(event)
}
-func (v *View) GetLatestOrgIAMPolicySequence() (*global_view.CurrentSequence, error) {
- return v.latestSequence(orgIAMPolicyTable)
+func (v *View) GetLatestOrgIAMPolicySequence(aggregateType string) (*global_view.CurrentSequence, error) {
+ return v.latestSequence(orgIAMPolicyTable, aggregateType)
}
-func (v *View) ProcessedOrgIAMPolicySequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(orgIAMPolicyTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedOrgIAMPolicySequence(event *models.Event) error {
+ return v.saveCurrentSequence(orgIAMPolicyTable, event)
}
func (v *View) UpdateOrgIAMPolicySpoolerRunTimestamp() error {
diff --git a/internal/auth/repository/eventsourcing/view/password_complexity_policy.go b/internal/auth/repository/eventsourcing/view/password_complexity_policy.go
index 8259c89da0..43ce74f8c1 100644
--- a/internal/auth/repository/eventsourcing/view/password_complexity_policy.go
+++ b/internal/auth/repository/eventsourcing/view/password_complexity_policy.go
@@ -2,10 +2,10 @@ package view
import (
"github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -16,28 +16,28 @@ func (v *View) PasswordComplexityPolicyByAggregateID(aggregateID string) (*model
return view.GetPasswordComplexityPolicyByAggregateID(v.Db, passwordComplexityPolicyTable, aggregateID)
}
-func (v *View) PutPasswordComplexityPolicy(policy *model.PasswordComplexityPolicyView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutPasswordComplexityPolicy(policy *model.PasswordComplexityPolicyView, event *models.Event) error {
err := view.PutPasswordComplexityPolicy(v.Db, passwordComplexityPolicyTable, policy)
if err != nil {
return err
}
- return v.ProcessedPasswordComplexityPolicySequence(sequence, eventTimestamp)
+ return v.ProcessedPasswordComplexityPolicySequence(event)
}
-func (v *View) DeletePasswordComplexityPolicy(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeletePasswordComplexityPolicy(aggregateID string, event *models.Event) error {
err := view.DeletePasswordComplexityPolicy(v.Db, passwordComplexityPolicyTable, aggregateID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedPasswordComplexityPolicySequence(eventSequence, eventTimestamp)
+ return v.ProcessedPasswordComplexityPolicySequence(event)
}
-func (v *View) GetLatestPasswordComplexityPolicySequence() (*global_view.CurrentSequence, error) {
- return v.latestSequence(passwordComplexityPolicyTable)
+func (v *View) GetLatestPasswordComplexityPolicySequence(aggregateType string) (*global_view.CurrentSequence, error) {
+ return v.latestSequence(passwordComplexityPolicyTable, aggregateType)
}
-func (v *View) ProcessedPasswordComplexityPolicySequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(passwordComplexityPolicyTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedPasswordComplexityPolicySequence(event *models.Event) error {
+ return v.saveCurrentSequence(passwordComplexityPolicyTable, event)
}
func (v *View) UpdatePasswordComplexityPolicySpoolerRunTimestamp() error {
diff --git a/internal/auth/repository/eventsourcing/view/project_role.go b/internal/auth/repository/eventsourcing/view/project_role.go
index 66c287ffa1..c5a99bfe4a 100644
--- a/internal/auth/repository/eventsourcing/view/project_role.go
+++ b/internal/auth/repository/eventsourcing/view/project_role.go
@@ -1,11 +1,12 @@
package view
import (
+ "github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
proj_model "github.com/caos/zitadel/internal/project/model"
"github.com/caos/zitadel/internal/project/repository/view"
"github.com/caos/zitadel/internal/project/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -32,32 +33,32 @@ func (v *View) SearchProjectRoles(request *proj_model.ProjectRoleSearchRequest)
return view.SearchProjectRoles(v.Db, projectRoleTable, request)
}
-func (v *View) PutProjectRole(project *model.ProjectRoleView, eventTimestamp time.Time) error {
- err := view.PutProjectRole(v.Db, projectRoleTable, project)
+func (v *View) PutProjectRole(role *model.ProjectRoleView, event *models.Event) error {
+ err := view.PutProjectRole(v.Db, projectRoleTable, role)
if err != nil {
return err
}
- return v.ProcessedProjectRoleSequence(project.Sequence, eventTimestamp)
+ return v.ProcessedProjectRoleSequence(event)
}
-func (v *View) DeleteProjectRole(projectID, orgID, key string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteProjectRole(projectID, orgID, key string, event *models.Event) error {
err := view.DeleteProjectRole(v.Db, projectRoleTable, projectID, orgID, key)
- if err != nil {
- return nil
+ if err != nil && !errors.IsNotFound(err) {
+ return err
}
- return v.ProcessedProjectRoleSequence(eventSequence, eventTimestamp)
+ return v.ProcessedProjectRoleSequence(event)
}
func (v *View) DeleteProjectRolesByProjectID(projectID string) error {
return view.DeleteProjectRolesByProjectID(v.Db, projectRoleTable, projectID)
}
-func (v *View) GetLatestProjectRoleSequence() (*repository.CurrentSequence, error) {
- return v.latestSequence(projectRoleTable)
+func (v *View) GetLatestProjectRoleSequence(aggregateType string) (*repository.CurrentSequence, error) {
+ return v.latestSequence(projectRoleTable, aggregateType)
}
-func (v *View) ProcessedProjectRoleSequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(projectRoleTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedProjectRoleSequence(event *models.Event) error {
+ return v.saveCurrentSequence(projectRoleTable, event)
}
func (v *View) UpdateProjectRoleSpoolerRunTimestamp() error {
diff --git a/internal/auth/repository/eventsourcing/view/sequence.go b/internal/auth/repository/eventsourcing/view/sequence.go
index 4ac2ab80cc..d9eb6c7a64 100644
--- a/internal/auth/repository/eventsourcing/view/sequence.go
+++ b/internal/auth/repository/eventsourcing/view/sequence.go
@@ -1,24 +1,26 @@
package view
import (
- "github.com/caos/zitadel/internal/view/repository"
"time"
+
+ "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/view/repository"
)
const (
sequencesTable = "auth.current_sequences"
)
-func (v *View) saveCurrentSequence(viewName string, sequence uint64, eventTimestamp time.Time) error {
- return repository.SaveCurrentSequence(v.Db, sequencesTable, viewName, sequence, eventTimestamp)
+func (v *View) saveCurrentSequence(viewName string, event *models.Event) error {
+ return repository.SaveCurrentSequence(v.Db, sequencesTable, viewName, string(event.AggregateType), event.Sequence, event.CreationDate)
}
-func (v *View) latestSequence(viewName string) (*repository.CurrentSequence, error) {
- return repository.LatestSequence(v.Db, sequencesTable, viewName)
+func (v *View) latestSequence(viewName, aggregateType string) (*repository.CurrentSequence, error) {
+ return repository.LatestSequence(v.Db, sequencesTable, viewName, aggregateType)
}
func (v *View) updateSpoolerRunSequence(viewName string) error {
- currentSequence, err := repository.LatestSequence(v.Db, sequencesTable, viewName)
+ currentSequence, err := repository.LatestSequence(v.Db, sequencesTable, viewName, "")
if err != nil {
return err
}
@@ -26,5 +28,8 @@ func (v *View) updateSpoolerRunSequence(viewName string) error {
currentSequence.ViewName = viewName
}
currentSequence.LastSuccessfulSpoolerRun = time.Now()
+ //update all aggregate types
+ //TODO: not sure if all scenarios work as expected
+ currentSequence.AggregateType = ""
return repository.UpdateCurrentSequence(v.Db, sequencesTable, currentSequence)
}
diff --git a/internal/auth/repository/eventsourcing/view/token.go b/internal/auth/repository/eventsourcing/view/token.go
index 4cb7c41844..105034a364 100644
--- a/internal/auth/repository/eventsourcing/view/token.go
+++ b/internal/auth/repository/eventsourcing/view/token.go
@@ -1,10 +1,11 @@
package view
import (
+ "github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
usr_view "github.com/caos/zitadel/internal/user/repository/view"
"github.com/caos/zitadel/internal/user/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -19,60 +20,60 @@ func (v *View) TokensByUserID(userID string) ([]*model.TokenView, error) {
return usr_view.TokensByUserID(v.Db, tokenTable, userID)
}
-func (v *View) PutToken(token *model.TokenView, eventTimestamp time.Time) error {
+func (v *View) PutToken(token *model.TokenView, event *models.Event) error {
err := usr_view.PutToken(v.Db, tokenTable, token)
if err != nil {
return err
}
- return v.ProcessedTokenSequence(token.Sequence, eventTimestamp)
+ return v.ProcessedTokenSequence(event)
}
-func (v *View) PutTokens(token []*model.TokenView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutTokens(token []*model.TokenView, event *models.Event) error {
err := usr_view.PutTokens(v.Db, tokenTable, token...)
if err != nil {
return err
}
- return v.ProcessedTokenSequence(sequence, eventTimestamp)
+ return v.ProcessedTokenSequence(event)
}
-func (v *View) DeleteToken(tokenID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteToken(tokenID string, event *models.Event) error {
err := usr_view.DeleteToken(v.Db, tokenTable, tokenID)
- if err != nil {
- return nil
+ if err != nil && !errors.IsNotFound(err) {
+ return err
}
- return v.ProcessedTokenSequence(eventSequence, eventTimestamp)
+ return v.ProcessedTokenSequence(event)
}
-func (v *View) DeleteSessionTokens(agentID, userID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteSessionTokens(agentID, userID string, event *models.Event) error {
err := usr_view.DeleteSessionTokens(v.Db, tokenTable, agentID, userID)
- if err != nil {
- return nil
+ if err != nil && !errors.IsNotFound(err) {
+ return err
}
- return v.ProcessedTokenSequence(eventSequence, eventTimestamp)
+ return v.ProcessedTokenSequence(event)
}
-func (v *View) DeleteUserTokens(userID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteUserTokens(userID string, event *models.Event) error {
err := usr_view.DeleteUserTokens(v.Db, tokenTable, userID)
- if err != nil {
- return nil
+ if err != nil && !errors.IsNotFound(err) {
+ return err
}
- return v.ProcessedTokenSequence(eventSequence, eventTimestamp)
+ return v.ProcessedTokenSequence(event)
}
-func (v *View) DeleteApplicationTokens(eventSequence uint64, eventTimestamp time.Time, ids ...string) error {
+func (v *View) DeleteApplicationTokens(event *models.Event, ids ...string) error {
err := usr_view.DeleteApplicationTokens(v.Db, tokenTable, ids)
- if err != nil {
- return nil
+ if err != nil && !errors.IsNotFound(err) {
+ return err
}
- return v.ProcessedTokenSequence(eventSequence, eventTimestamp)
+ return v.ProcessedTokenSequence(event)
}
-func (v *View) GetLatestTokenSequence() (*repository.CurrentSequence, error) {
- return v.latestSequence(tokenTable)
+func (v *View) GetLatestTokenSequence(aggregateType string) (*repository.CurrentSequence, error) {
+ return v.latestSequence(tokenTable, aggregateType)
}
-func (v *View) ProcessedTokenSequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(tokenTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedTokenSequence(event *models.Event) error {
+ return v.saveCurrentSequence(tokenTable, event)
}
func (v *View) UpdateTokenSpoolerRunTimestamp() error {
diff --git a/internal/auth/repository/eventsourcing/view/user.go b/internal/auth/repository/eventsourcing/view/user.go
index e8b0591d22..21de8cef8d 100644
--- a/internal/auth/repository/eventsourcing/view/user.go
+++ b/internal/auth/repository/eventsourcing/view/user.go
@@ -1,11 +1,12 @@
package view
import (
+ "github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
usr_model "github.com/caos/zitadel/internal/user/model"
"github.com/caos/zitadel/internal/user/repository/view"
"github.com/caos/zitadel/internal/user/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -52,36 +53,36 @@ func (v *View) UserMFAs(userID string) ([]*usr_model.MultiFactor, error) {
return view.UserMFAs(v.Db, userTable, userID)
}
-func (v *View) PutUser(user *model.UserView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutUser(user *model.UserView, event *models.Event) error {
err := view.PutUser(v.Db, userTable, user)
if err != nil {
return err
}
- return v.ProcessedUserSequence(sequence, eventTimestamp)
+ return v.ProcessedUserSequence(event)
}
-func (v *View) PutUsers(users []*model.UserView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutUsers(users []*model.UserView, event *models.Event) error {
err := view.PutUsers(v.Db, userTable, users...)
if err != nil {
return err
}
- return v.ProcessedUserSequence(sequence, eventTimestamp)
+ return v.ProcessedUserSequence(event)
}
-func (v *View) DeleteUser(userID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteUser(userID string, event *models.Event) error {
err := view.DeleteUser(v.Db, userTable, userID)
- if err != nil {
- return nil
+ if err != nil && !errors.IsNotFound(err) {
+ return err
}
- return v.ProcessedUserSequence(eventSequence, eventTimestamp)
+ return v.ProcessedUserSequence(event)
}
-func (v *View) GetLatestUserSequence() (*repository.CurrentSequence, error) {
- return v.latestSequence(userTable)
+func (v *View) GetLatestUserSequence(aggregateType string) (*repository.CurrentSequence, error) {
+ return v.latestSequence(userTable, aggregateType)
}
-func (v *View) ProcessedUserSequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(userTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedUserSequence(event *models.Event) error {
+ return v.saveCurrentSequence(userTable, event)
}
func (v *View) UpdateUserSpoolerRunTimestamp() error {
diff --git a/internal/auth/repository/eventsourcing/view/user_grant.go b/internal/auth/repository/eventsourcing/view/user_grant.go
index 230e9f5c8a..d9a52a586e 100644
--- a/internal/auth/repository/eventsourcing/view/user_grant.go
+++ b/internal/auth/repository/eventsourcing/view/user_grant.go
@@ -1,11 +1,12 @@
package view
import (
+ "github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
grant_model "github.com/caos/zitadel/internal/usergrant/model"
"github.com/caos/zitadel/internal/usergrant/repository/view"
"github.com/caos/zitadel/internal/usergrant/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -36,36 +37,36 @@ func (v *View) SearchUserGrants(request *grant_model.UserGrantSearchRequest) ([]
return view.SearchUserGrants(v.Db, userGrantTable, request)
}
-func (v *View) PutUserGrant(grant *model.UserGrantView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutUserGrant(grant *model.UserGrantView, event *models.Event) error {
err := view.PutUserGrant(v.Db, userGrantTable, grant)
if err != nil {
return err
}
- return v.ProcessedUserGrantSequence(sequence, eventTimestamp)
+ return v.ProcessedUserGrantSequence(event)
}
-func (v *View) PutUserGrants(grants []*model.UserGrantView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutUserGrants(grants []*model.UserGrantView, event *models.Event) error {
err := view.PutUserGrants(v.Db, userGrantTable, grants...)
if err != nil {
return err
}
- return v.ProcessedUserGrantSequence(sequence, eventTimestamp)
+ return v.ProcessedUserGrantSequence(event)
}
-func (v *View) DeleteUserGrant(grantID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteUserGrant(grantID string, event *models.Event) error {
err := view.DeleteUserGrant(v.Db, userGrantTable, grantID)
- if err != nil {
- return nil
+ if err != nil && !errors.IsNotFound(err) {
+ return err
}
- return v.ProcessedUserGrantSequence(eventSequence, eventTimestamp)
+ return v.ProcessedUserGrantSequence(event)
}
-func (v *View) GetLatestUserGrantSequence() (*repository.CurrentSequence, error) {
- return v.latestSequence(userGrantTable)
+func (v *View) GetLatestUserGrantSequence(aggregateType string) (*repository.CurrentSequence, error) {
+ return v.latestSequence(userGrantTable, aggregateType)
}
-func (v *View) ProcessedUserGrantSequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(userGrantTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedUserGrantSequence(event *models.Event) error {
+ return v.saveCurrentSequence(userGrantTable, event)
}
func (v *View) UpdateUserGrantSpoolerRunTimestamp() error {
diff --git a/internal/auth/repository/eventsourcing/view/user_membership.go b/internal/auth/repository/eventsourcing/view/user_membership.go
index 84607584ab..f3d9fae70e 100644
--- a/internal/auth/repository/eventsourcing/view/user_membership.go
+++ b/internal/auth/repository/eventsourcing/view/user_membership.go
@@ -1,11 +1,12 @@
package view
import (
+ "github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
usr_model "github.com/caos/zitadel/internal/user/model"
"github.com/caos/zitadel/internal/user/repository/view"
"github.com/caos/zitadel/internal/user/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -28,60 +29,60 @@ func (v *View) SearchUserMemberships(request *usr_model.UserMembershipSearchRequ
return view.SearchUserMemberships(v.Db, userMembershipTable, request)
}
-func (v *View) PutUserMembership(membership *model.UserMembershipView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutUserMembership(membership *model.UserMembershipView, event *models.Event) error {
err := view.PutUserMembership(v.Db, userMembershipTable, membership)
if err != nil {
return err
}
- return v.ProcessedUserMembershipSequence(sequence, eventTimestamp)
+ return v.ProcessedUserMembershipSequence(event)
}
-func (v *View) BulkPutUserMemberships(memberships []*model.UserMembershipView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) BulkPutUserMemberships(memberships []*model.UserMembershipView, event *models.Event) error {
err := view.PutUserMemberships(v.Db, userMembershipTable, memberships...)
if err != nil {
return err
}
- return v.ProcessedUserMembershipSequence(sequence, eventTimestamp)
+ return v.ProcessedUserMembershipSequence(event)
}
-func (v *View) DeleteUserMembership(userID, aggregateID, objectID string, memberType usr_model.MemberType, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteUserMembership(userID, aggregateID, objectID string, memberType usr_model.MemberType, event *models.Event) error {
err := view.DeleteUserMembership(v.Db, userMembershipTable, userID, aggregateID, objectID, memberType)
- if err != nil {
- return nil
+ if err != nil && !errors.IsNotFound(err) {
+ return err
}
- return v.ProcessedUserMembershipSequence(eventSequence, eventTimestamp)
+ return v.ProcessedUserMembershipSequence(event)
}
-func (v *View) DeleteUserMembershipsByUserID(userID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteUserMembershipsByUserID(userID string, event *models.Event) error {
err := view.DeleteUserMembershipsByUserID(v.Db, userMembershipTable, userID)
- if err != nil {
- return nil
+ if err != nil && !errors.IsNotFound(err) {
+ return err
}
- return v.ProcessedUserMembershipSequence(eventSequence, eventTimestamp)
+ return v.ProcessedUserMembershipSequence(event)
}
-func (v *View) DeleteUserMembershipsByAggregateID(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteUserMembershipsByAggregateID(aggregateID string, event *models.Event) error {
err := view.DeleteUserMembershipsByAggregateID(v.Db, userMembershipTable, aggregateID)
- if err != nil {
- return nil
+ if err != nil && !errors.IsNotFound(err) {
+ return err
}
- return v.ProcessedUserMembershipSequence(eventSequence, eventTimestamp)
+ return v.ProcessedUserMembershipSequence(event)
}
-func (v *View) DeleteUserMembershipsByAggregateIDAndObjectID(aggregateID, objectID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteUserMembershipsByAggregateIDAndObjectID(aggregateID, objectID string, event *models.Event) error {
err := view.DeleteUserMembershipsByAggregateIDAndObjectID(v.Db, userMembershipTable, aggregateID, objectID)
- if err != nil {
- return nil
+ if err != nil && !errors.IsNotFound(err) {
+ return err
}
- return v.ProcessedUserMembershipSequence(eventSequence, eventTimestamp)
+ return v.ProcessedUserMembershipSequence(event)
}
-func (v *View) GetLatestUserMembershipSequence() (*repository.CurrentSequence, error) {
- return v.latestSequence(userMembershipTable)
+func (v *View) GetLatestUserMembershipSequence(aggregateType string) (*repository.CurrentSequence, error) {
+ return v.latestSequence(userMembershipTable, aggregateType)
}
-func (v *View) ProcessedUserMembershipSequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(userMembershipTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedUserMembershipSequence(event *models.Event) error {
+ return v.saveCurrentSequence(userMembershipTable, event)
}
func (v *View) UpdateUserMembershipSpoolerRunTimestamp() error {
diff --git a/internal/auth/repository/eventsourcing/view/user_session.go b/internal/auth/repository/eventsourcing/view/user_session.go
index 805cc04aef..16ce4c7986 100644
--- a/internal/auth/repository/eventsourcing/view/user_session.go
+++ b/internal/auth/repository/eventsourcing/view/user_session.go
@@ -1,10 +1,11 @@
package view
import (
+ "github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/user/repository/view"
"github.com/caos/zitadel/internal/user/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -27,36 +28,36 @@ func (v *View) ActiveUserSessions() ([]*model.UserSessionView, error) {
return view.ActiveUserSessions(v.Db, userSessionTable)
}
-func (v *View) PutUserSession(userSession *model.UserSessionView, eventTimestamp time.Time) error {
+func (v *View) PutUserSession(userSession *model.UserSessionView, event *models.Event) error {
err := view.PutUserSession(v.Db, userSessionTable, userSession)
if err != nil {
return err
}
- return v.ProcessedUserSessionSequence(userSession.Sequence, eventTimestamp)
+ return v.ProcessedUserSessionSequence(event)
}
-func (v *View) PutUserSessions(userSession []*model.UserSessionView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutUserSessions(userSession []*model.UserSessionView, event *models.Event) error {
err := view.PutUserSessions(v.Db, userSessionTable, userSession...)
if err != nil {
return err
}
- return v.ProcessedUserSessionSequence(sequence, eventTimestamp)
+ return v.ProcessedUserSessionSequence(event)
}
-func (v *View) DeleteUserSessions(userID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteUserSessions(userID string, event *models.Event) error {
err := view.DeleteUserSessions(v.Db, userSessionTable, userID)
- if err != nil {
- return nil
+ if err != nil && !errors.IsNotFound(err) {
+ return err
}
- return v.ProcessedUserSessionSequence(eventSequence, eventTimestamp)
+ return v.ProcessedUserSessionSequence(event)
}
-func (v *View) GetLatestUserSessionSequence() (*repository.CurrentSequence, error) {
- return v.latestSequence(userSessionTable)
+func (v *View) GetLatestUserSessionSequence(aggregateType string) (*repository.CurrentSequence, error) {
+ return v.latestSequence(userSessionTable, aggregateType)
}
-func (v *View) ProcessedUserSessionSequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(userSessionTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedUserSessionSequence(event *models.Event) error {
+ return v.saveCurrentSequence(userSessionTable, event)
}
func (v *View) UpdateUserSessionSpoolerRunTimestamp() error {
diff --git a/internal/auth/repository/user.go b/internal/auth/repository/user.go
index 1399a2b6a6..8ae79d92d2 100644
--- a/internal/auth/repository/user.go
+++ b/internal/auth/repository/user.go
@@ -32,6 +32,7 @@ type UserRepository interface {
VerifyMFAU2FSetup(ctx context.Context, userID, tokenName, userAgentID string, credentialData []byte) error
RemoveMFAU2F(ctx context.Context, userID, webAuthNTokenID string) error
+ GetPasswordless(ctx context.Context, id string) ([]*model.WebAuthNToken, error)
AddPasswordless(ctx context.Context, id string) (*model.WebAuthNToken, error)
VerifyPasswordlessSetup(ctx context.Context, userID, tokenName, userAgentID string, credentialData []byte) error
RemovePasswordless(ctx context.Context, userID, webAuthNTokenID string) error
@@ -80,6 +81,7 @@ type myUserRepo interface {
VerifyMyMFAU2FSetup(ctx context.Context, tokenName string, data []byte) error
RemoveMyMFAU2F(ctx context.Context, webAuthNTokenID string) error
+ GetMyPasswordless(ctx context.Context) ([]*model.WebAuthNToken, error)
AddMyPasswordless(ctx context.Context) (*model.WebAuthNToken, error)
VerifyMyPasswordlessSetup(ctx context.Context, tokenName string, data []byte) error
RemoveMyPasswordless(ctx context.Context, webAuthNTokenID string) error
diff --git a/internal/auth_request/model/auth_request.go b/internal/auth_request/model/auth_request.go
index bd51897afd..df74e85d39 100644
--- a/internal/auth_request/model/auth_request.go
+++ b/internal/auth_request/model/auth_request.go
@@ -1,11 +1,13 @@
package model
import (
- "github.com/caos/zitadel/internal/iam/model"
- "golang.org/x/text/language"
"strings"
"time"
+ "golang.org/x/text/language"
+
+ "github.com/caos/zitadel/internal/iam/model"
+
"github.com/caos/zitadel/internal/errors"
)
@@ -30,6 +32,8 @@ type AuthRequest struct {
LoginName string
DisplayName string
UserOrgID string
+ RequestedOrgID string
+ RequestedOrgName string
SelectedIDPConfigID string
LinkingUsers []*ExternalUser
PossibleSteps []NextStep
diff --git a/internal/auth_request/model/next_step.go b/internal/auth_request/model/next_step.go
index 3312244e11..b3a3a07733 100644
--- a/internal/auth_request/model/next_step.go
+++ b/internal/auth_request/model/next_step.go
@@ -48,10 +48,11 @@ func (s *SelectUserStep) Type() NextStepType {
}
type UserSelection struct {
- UserID string
- DisplayName string
- LoginName string
- UserSessionState UserSessionState
+ UserID string
+ DisplayName string
+ LoginName string
+ UserSessionState UserSessionState
+ SelectionPossible bool
}
type InitUserStep struct {
diff --git a/internal/auth_request/model/request.go b/internal/auth_request/model/request.go
index 72f10ce49f..43f8c93eaf 100644
--- a/internal/auth_request/model/request.go
+++ b/internal/auth_request/model/request.go
@@ -20,6 +20,7 @@ const (
const (
OrgDomainPrimaryScope = "urn:zitadel:iam:org:domain:primary:"
+ OrgDomainPrimaryClaim = "urn:zitadel:iam:org:domain:primary"
ProjectIDScope = "urn:zitadel:iam:org:project:id:"
AudSuffix = ":aud"
)
diff --git a/internal/authz/repository/eventsourcing/handler/application.go b/internal/authz/repository/eventsourcing/handler/application.go
index 4b5773607e..fcb84ee675 100644
--- a/internal/authz/repository/eventsourcing/handler/application.go
+++ b/internal/authz/repository/eventsourcing/handler/application.go
@@ -3,27 +3,61 @@ package handler
import (
"github.com/caos/logging"
+ "github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
"github.com/caos/zitadel/internal/project/repository/eventsourcing"
es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model"
view_model "github.com/caos/zitadel/internal/project/repository/view/model"
)
-type Application struct {
- handler
-}
-
const (
applicationTable = "authz.applications"
)
+type Application struct {
+ handler
+ subscription *eventstore.Subscription
+}
+
+func newApplication(handler handler) *Application {
+ h := &Application{
+ handler: handler,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (k *Application) subscribe() {
+ k.subscription = k.es.Subscribe(k.AggregateTypes()...)
+ go func() {
+ for event := range k.subscription.Events {
+ query.ReduceEvent(k, event)
+ }
+ }()
+}
+
func (a *Application) ViewModel() string {
return applicationTable
}
+func (a *Application) AggregateTypes() []models.AggregateType {
+ return []models.AggregateType{es_model.ProjectAggregate}
+}
+
+func (a *Application) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := a.view.GetLatestApplicationSequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (a *Application) EventQuery() (*models.SearchQuery, error) {
- sequence, err := a.view.GetLatestApplicationSequence()
+ sequence, err := a.view.GetLatestApplicationSequence("")
if err != nil {
return nil, err
}
@@ -54,14 +88,14 @@ func (a *Application) Reduce(event *models.Event) (err error) {
if err != nil {
return err
}
- return a.view.DeleteApplication(app.ID, event.Sequence, event.CreationDate)
+ return a.view.DeleteApplication(app.ID, event)
default:
- return a.view.ProcessedApplicationSequence(event.Sequence, event.CreationDate)
+ return a.view.ProcessedApplicationSequence(event)
}
if err != nil {
return err
}
- return a.view.PutApplication(app, event.CreationDate)
+ return a.view.PutApplication(app, event)
}
func (a *Application) OnError(event *models.Event, spoolerError error) error {
diff --git a/internal/authz/repository/eventsourcing/handler/handler.go b/internal/authz/repository/eventsourcing/handler/handler.go
index 31274d77ab..ee21d1b020 100644
--- a/internal/authz/repository/eventsourcing/handler/handler.go
+++ b/internal/authz/repository/eventsourcing/handler/handler.go
@@ -3,13 +3,12 @@ package handler
import (
"time"
+ "github.com/caos/zitadel/internal/authz/repository/eventsourcing/view"
sd "github.com/caos/zitadel/internal/config/systemdefaults"
+ "github.com/caos/zitadel/internal/config/types"
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/query"
iam_events "github.com/caos/zitadel/internal/iam/repository/eventsourcing"
-
- "github.com/caos/zitadel/internal/authz/repository/eventsourcing/view"
- "github.com/caos/zitadel/internal/config/types"
)
type Configs map[string]*Config
@@ -23,29 +22,35 @@ type handler struct {
bulkLimit uint64
cycleDuration time.Duration
errorCountUntilSkip uint64
+
+ es eventstore.Eventstore
+}
+
+func (h *handler) Eventstore() eventstore.Eventstore {
+ return h.es
}
type EventstoreRepos struct {
- IamEvents *iam_events.IAMEventstore
+ IAMEvents *iam_events.IAMEventstore
}
-func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, eventstore eventstore.Eventstore, repos EventstoreRepos, systemDefaults sd.SystemDefaults) []query.Handler {
+func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es eventstore.Eventstore, repos EventstoreRepos, systemDefaults sd.SystemDefaults) []query.Handler {
return []query.Handler{
- &UserGrant{
- handler: handler{view, bulkLimit, configs.cycleDuration("UserGrant"), errorCount},
- eventstore: eventstore,
- iamID: systemDefaults.IamID,
- iamEvents: repos.IamEvents,
- },
- &Application{handler: handler{view, bulkLimit, configs.cycleDuration("Application"), errorCount}},
- &Org{handler: handler{view, bulkLimit, configs.cycleDuration("Org"), errorCount}},
+ newUserGrant(
+ handler{view, bulkLimit, configs.cycleDuration("UserGrant"), errorCount, es},
+ repos.IAMEvents,
+ systemDefaults.IamID),
+ newApplication(
+ handler{view, bulkLimit, configs.cycleDuration("Application"), errorCount, es}),
+ newOrg(
+ handler{view, bulkLimit, configs.cycleDuration("Org"), errorCount, es}),
}
}
func (configs Configs) cycleDuration(viewModel string) time.Duration {
c, ok := configs[viewModel]
if !ok {
- return 1 * time.Second
+ return 3 * time.Minute
}
return c.MinimumCycleDuration.Duration
}
@@ -54,6 +59,10 @@ func (h *handler) MinimumCycleDuration() time.Duration {
return h.cycleDuration
}
+func (h *handler) LockDuration() time.Duration {
+ return h.cycleDuration / 3
+}
+
func (h *handler) QueryLimit() uint64 {
return h.bulkLimit
}
diff --git a/internal/authz/repository/eventsourcing/handler/org.go b/internal/authz/repository/eventsourcing/handler/org.go
index e487831f02..34cc1a69e7 100644
--- a/internal/authz/repository/eventsourcing/handler/org.go
+++ b/internal/authz/repository/eventsourcing/handler/org.go
@@ -3,27 +3,62 @@ package handler
import (
"github.com/caos/logging"
+ "github.com/caos/zitadel/internal/eventstore"
+ "github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
"github.com/caos/zitadel/internal/org/repository/eventsourcing"
"github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
org_model "github.com/caos/zitadel/internal/org/repository/view/model"
)
-type Org struct {
- handler
-}
-
const (
orgTable = "authz.orgs"
)
+type Org struct {
+ handler
+ subscription *eventstore.Subscription
+}
+
+func newOrg(handler handler) *Org {
+ h := &Org{
+ handler: handler,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (k *Org) subscribe() {
+ k.subscription = k.es.Subscribe(k.AggregateTypes()...)
+ go func() {
+ for event := range k.subscription.Events {
+ query.ReduceEvent(k, event)
+ }
+ }()
+}
+
func (o *Org) ViewModel() string {
return orgTable
}
+func (_ *Org) AggregateTypes() []es_models.AggregateType {
+ return []es_models.AggregateType{model.OrgAggregate}
+}
+
+func (o *Org) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := o.view.GetLatestOrgSequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (o *Org) EventQuery() (*es_models.SearchQuery, error) {
- sequence, err := o.view.GetLatestOrgSequence()
+ sequence, err := o.view.GetLatestOrgSequence("")
if err != nil {
return nil, err
}
@@ -53,10 +88,10 @@ func (o *Org) Reduce(event *es_models.Event) error {
return err
}
default:
- return o.view.ProcessedOrgSequence(event.Sequence, event.CreationDate)
+ return o.view.ProcessedOrgSequence(event)
}
- return o.view.PutOrg(org, event.CreationDate)
+ return o.view.PutOrg(org, event)
}
func (o *Org) OnError(event *es_models.Event, spoolerErr error) error {
diff --git a/internal/authz/repository/eventsourcing/handler/user_grant.go b/internal/authz/repository/eventsourcing/handler/user_grant.go
index 1c7b829964..acdc5fde9e 100644
--- a/internal/authz/repository/eventsourcing/handler/user_grant.go
+++ b/internal/authz/repository/eventsourcing/handler/user_grant.go
@@ -11,6 +11,7 @@ import (
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
iam_events "github.com/caos/zitadel/internal/iam/repository/eventsourcing"
iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
@@ -20,22 +21,59 @@ import (
"github.com/caos/zitadel/internal/v2/domain"
)
-type UserGrant struct {
- handler
- eventstore eventstore.Eventstore
- iamEvents *iam_events.IAMEventstore
- iamID string
- iamProjectID string
-}
-
const (
userGrantTable = "authz.user_grants"
)
+type UserGrant struct {
+ handler
+ iamEvents *iam_events.IAMEventstore
+ iamID string
+ iamProjectID string
+ subscription *eventstore.Subscription
+}
+
+func newUserGrant(
+ handler handler,
+ iamEvents *iam_events.IAMEventstore,
+ iamID string,
+) *UserGrant {
+ h := &UserGrant{
+ handler: handler,
+ iamEvents: iamEvents,
+ iamID: iamID,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (k *UserGrant) subscribe() {
+ k.subscription = k.es.Subscribe(k.AggregateTypes()...)
+ go func() {
+ for event := range k.subscription.Events {
+ query.ReduceEvent(k, event)
+ }
+ }()
+}
+
func (u *UserGrant) ViewModel() string {
return userGrantTable
}
+func (_ *UserGrant) AggregateTypes() []es_models.AggregateType {
+ return []es_models.AggregateType{iam_es_model.IAMAggregate, org_es_model.OrgAggregate, proj_es_model.ProjectAggregate}
+}
+
+func (u *UserGrant) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := u.view.GetLatestUserGrantSequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (u *UserGrant) EventQuery() (*models.SearchQuery, error) {
if u.iamProjectID == "" {
err := u.setIamProjectID()
@@ -43,7 +81,7 @@ func (u *UserGrant) EventQuery() (*models.SearchQuery, error) {
return nil, err
}
}
- sequence, err := u.view.GetLatestUserGrantSequence()
+ sequence, err := u.view.GetLatestUserGrantSequence("")
if err != nil {
return nil, err
}
@@ -75,7 +113,7 @@ func (u *UserGrant) processProject(event *models.Event) (err error) {
member.SetData(event)
return u.processMember(event, "PROJECT_GRANT", member.GrantID, member.UserID, member.Roles)
default:
- return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
+ return u.view.ProcessedUserGrantSequence(event)
}
}
@@ -86,7 +124,7 @@ func (u *UserGrant) processOrg(event *models.Event) (err error) {
member.SetData(event)
return u.processMember(event, "ORG", "", member.UserID, member.Roles)
default:
- return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
+ return u.view.ProcessedUserGrantSequence(event)
}
}
@@ -124,16 +162,16 @@ func (u *UserGrant) processIAMMember(event *models.Event, rolePrefix string, suf
}
grant.Sequence = event.Sequence
grant.ChangeDate = event.CreationDate
- return u.view.PutUserGrant(grant, grant.Sequence, event.CreationDate)
+ return u.view.PutUserGrant(grant, event)
case iam_es_model.IAMMemberRemoved:
member.SetData(event)
grant, err := u.view.UserGrantByIDs(u.iamID, u.iamProjectID, member.UserID)
if err != nil {
return err
}
- return u.view.DeleteUserGrant(grant.ID, event.Sequence, event.CreationDate)
+ return u.view.DeleteUserGrant(grant.ID, event)
default:
- return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
+ return u.view.ProcessedUserGrantSequence(event)
}
}
@@ -169,7 +207,7 @@ func (u *UserGrant) processMember(event *models.Event, rolePrefix, roleSuffix st
}
grant.Sequence = event.Sequence
grant.ChangeDate = event.CreationDate
- return u.view.PutUserGrant(grant, event.Sequence, event.CreationDate)
+ return u.view.PutUserGrant(grant, event)
case org_es_model.OrgMemberRemoved,
proj_es_model.ProjectMemberRemoved,
proj_es_model.ProjectGrantMemberRemoved:
@@ -179,18 +217,18 @@ func (u *UserGrant) processMember(event *models.Event, rolePrefix, roleSuffix st
return err
}
if errors.IsNotFound(err) {
- return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
+ return u.view.ProcessedUserGrantSequence(event)
}
if roleSuffix != "" {
roleKeys = suffixRoles(roleSuffix, roleKeys)
}
if grant.RoleKeys == nil {
- return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
+ return u.view.ProcessedUserGrantSequence(event)
}
grant.RoleKeys = mergeExistingRoles(rolePrefix, roleSuffix, grant.RoleKeys, nil)
- return u.view.PutUserGrant(grant, event.Sequence, event.CreationDate)
+ return u.view.PutUserGrant(grant, event)
default:
- return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
+ return u.view.ProcessedUserGrantSequence(event)
}
}
diff --git a/internal/authz/repository/eventsourcing/repository.go b/internal/authz/repository/eventsourcing/repository.go
index 922290cd2d..b6ad0d7680 100644
--- a/internal/authz/repository/eventsourcing/repository.go
+++ b/internal/authz/repository/eventsourcing/repository.go
@@ -84,7 +84,7 @@ func Start(conf Config, authZ authz.Config, systemDefaults sd.SystemDefaults) (*
return nil, err
}
- repos := handler.EventstoreRepos{IamEvents: iam}
+ repos := handler.EventstoreRepos{IAMEvents: iam}
spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient, repos, systemDefaults)
return &EsRepository{
diff --git a/internal/authz/repository/eventsourcing/view/application.go b/internal/authz/repository/eventsourcing/view/application.go
index a8e772b58d..84ae564981 100644
--- a/internal/authz/repository/eventsourcing/view/application.go
+++ b/internal/authz/repository/eventsourcing/view/application.go
@@ -2,8 +2,9 @@ package view
import (
"context"
- "time"
+ "github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
proj_model "github.com/caos/zitadel/internal/project/model"
"github.com/caos/zitadel/internal/project/repository/view"
"github.com/caos/zitadel/internal/project/repository/view/model"
@@ -34,28 +35,28 @@ func (v *View) SearchApplications(request *proj_model.ApplicationSearchRequest)
return view.SearchApplications(v.Db, applicationTable, request)
}
-func (v *View) PutApplication(project *model.ApplicationView, eventTimestamp time.Time) error {
+func (v *View) PutApplication(project *model.ApplicationView, event *models.Event) error {
err := view.PutApplication(v.Db, applicationTable, project)
if err != nil {
return err
}
- return v.ProcessedApplicationSequence(project.Sequence, eventTimestamp)
+ return v.ProcessedApplicationSequence(event)
}
-func (v *View) DeleteApplication(appID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteApplication(appID string, event *models.Event) error {
err := view.DeleteApplication(v.Db, applicationTable, appID)
- if err != nil {
- return nil
+ if err != nil && !errors.IsNotFound(err) {
+ return err
}
- return v.ProcessedApplicationSequence(eventSequence, eventTimestamp)
+ return v.ProcessedApplicationSequence(event)
}
-func (v *View) GetLatestApplicationSequence() (*repository.CurrentSequence, error) {
- return v.latestSequence(applicationTable)
+func (v *View) GetLatestApplicationSequence(aggregateType string) (*repository.CurrentSequence, error) {
+ return v.latestSequence(applicationTable, aggregateType)
}
-func (v *View) ProcessedApplicationSequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(applicationTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedApplicationSequence(event *models.Event) error {
+ return v.saveCurrentSequence(applicationTable, event)
}
func (v *View) UpdateApplicationSpoolerRunTimestamp() error {
diff --git a/internal/authz/repository/eventsourcing/view/org.go b/internal/authz/repository/eventsourcing/view/org.go
index f886123b2e..6d27b5b071 100644
--- a/internal/authz/repository/eventsourcing/view/org.go
+++ b/internal/authz/repository/eventsourcing/view/org.go
@@ -1,11 +1,11 @@
package view
import (
+ "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/org/model"
org_view "github.com/caos/zitadel/internal/org/repository/view"
org_model "github.com/caos/zitadel/internal/org/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -20,12 +20,12 @@ func (v *View) SearchOrgs(req *model.OrgSearchRequest) ([]*org_model.OrgView, ui
return org_view.SearchOrgs(v.Db, orgTable, req)
}
-func (v *View) PutOrg(org *org_model.OrgView, eventTimestamp time.Time) error {
+func (v *View) PutOrg(org *org_model.OrgView, event *models.Event) error {
err := org_view.PutOrg(v.Db, orgTable, org)
if err != nil {
return err
}
- return v.ProcessedOrgSequence(org.Sequence, eventTimestamp)
+ return v.ProcessedOrgSequence(event)
}
func (v *View) GetLatestOrgFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
@@ -36,12 +36,12 @@ func (v *View) ProcessedOrgFailedEvent(failedEvent *repository.FailedEvent) erro
return v.saveFailedEvent(failedEvent)
}
-func (v *View) GetLatestOrgSequence() (*repository.CurrentSequence, error) {
- return v.latestSequence(orgTable)
+func (v *View) GetLatestOrgSequence(aggregateType string) (*repository.CurrentSequence, error) {
+ return v.latestSequence(orgTable, aggregateType)
}
-func (v *View) ProcessedOrgSequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(orgTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedOrgSequence(event *models.Event) error {
+ return v.saveCurrentSequence(orgTable, event)
}
func (v *View) UpdateOrgSpoolerRunTimestamp() error {
diff --git a/internal/authz/repository/eventsourcing/view/sequence.go b/internal/authz/repository/eventsourcing/view/sequence.go
index ad628fbf7b..42e6e20bfd 100644
--- a/internal/authz/repository/eventsourcing/view/sequence.go
+++ b/internal/authz/repository/eventsourcing/view/sequence.go
@@ -1,24 +1,26 @@
package view
import (
- "github.com/caos/zitadel/internal/view/repository"
"time"
+
+ "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/view/repository"
)
const (
sequencesTable = "authz.current_sequences"
)
-func (v *View) saveCurrentSequence(viewName string, sequence uint64, eventTimestamp time.Time) error {
- return repository.SaveCurrentSequence(v.Db, sequencesTable, viewName, sequence, eventTimestamp)
+func (v *View) saveCurrentSequence(viewName string, event *models.Event) error {
+ return repository.SaveCurrentSequence(v.Db, sequencesTable, viewName, string(event.AggregateType), event.Sequence, event.CreationDate)
}
-func (v *View) latestSequence(viewName string) (*repository.CurrentSequence, error) {
- return repository.LatestSequence(v.Db, sequencesTable, viewName)
+func (v *View) latestSequence(viewName, aggregateType string) (*repository.CurrentSequence, error) {
+ return repository.LatestSequence(v.Db, sequencesTable, viewName, aggregateType)
}
func (v *View) updateSpoolerRunSequence(viewName string) error {
- currentSequence, err := repository.LatestSequence(v.Db, sequencesTable, viewName)
+ currentSequence, err := repository.LatestSequence(v.Db, sequencesTable, viewName, "")
if err != nil {
return err
}
@@ -26,5 +28,8 @@ func (v *View) updateSpoolerRunSequence(viewName string) error {
currentSequence.ViewName = viewName
}
currentSequence.LastSuccessfulSpoolerRun = time.Now()
+ //update all aggregate types
+ //TODO: not sure if all scenarios work as expected
+ currentSequence.AggregateType = ""
return repository.UpdateCurrentSequence(v.Db, sequencesTable, currentSequence)
}
diff --git a/internal/authz/repository/eventsourcing/view/token.go b/internal/authz/repository/eventsourcing/view/token.go
index bab80f238a..d2987a8194 100644
--- a/internal/authz/repository/eventsourcing/view/token.go
+++ b/internal/authz/repository/eventsourcing/view/token.go
@@ -1,10 +1,11 @@
package view
import (
+ "github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
usr_view "github.com/caos/zitadel/internal/user/repository/view"
usr_view_model "github.com/caos/zitadel/internal/user/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -15,36 +16,36 @@ func (v *View) TokenByID(tokenID string) (*usr_view_model.TokenView, error) {
return usr_view.TokenByID(v.Db, tokenTable, tokenID)
}
-func (v *View) PutToken(token *usr_view_model.TokenView, eventTimestamp time.Time) error {
+func (v *View) PutToken(token *usr_view_model.TokenView, event *models.Event) error {
err := usr_view.PutToken(v.Db, tokenTable, token)
if err != nil {
return err
}
- return v.ProcessedTokenSequence(token.Sequence, eventTimestamp)
+ return v.ProcessedTokenSequence(event)
}
-func (v *View) DeleteToken(tokenID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteToken(tokenID string, event *models.Event) error {
err := usr_view.DeleteToken(v.Db, tokenTable, tokenID)
- if err != nil {
- return nil
+ if err != nil && !errors.IsNotFound(err) {
+ return err
}
- return v.ProcessedTokenSequence(eventSequence, eventTimestamp)
+ return v.ProcessedTokenSequence(event)
}
-func (v *View) DeleteSessionTokens(agentID, userID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteSessionTokens(agentID, userID string, event *models.Event) error {
err := usr_view.DeleteSessionTokens(v.Db, tokenTable, agentID, userID)
- if err != nil {
- return nil
+ if err != nil && !errors.IsNotFound(err) {
+ return err
}
- return v.ProcessedTokenSequence(eventSequence, eventTimestamp)
+ return v.ProcessedTokenSequence(event)
}
-func (v *View) GetLatestTokenSequence() (*repository.CurrentSequence, error) {
- return v.latestSequence(tokenTable)
+func (v *View) GetLatestTokenSequence(aggregateType string) (*repository.CurrentSequence, error) {
+ return v.latestSequence(tokenTable, aggregateType)
}
-func (v *View) ProcessedTokenSequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(tokenTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedTokenSequence(event *models.Event) error {
+ return v.saveCurrentSequence(tokenTable, event)
}
func (v *View) UpdateTokenSpoolerRunTimestamp() error {
diff --git a/internal/authz/repository/eventsourcing/view/user_grant.go b/internal/authz/repository/eventsourcing/view/user_grant.go
index 68154dc3c9..84de9319ea 100644
--- a/internal/authz/repository/eventsourcing/view/user_grant.go
+++ b/internal/authz/repository/eventsourcing/view/user_grant.go
@@ -1,11 +1,12 @@
package view
import (
+ "github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
grant_model "github.com/caos/zitadel/internal/usergrant/model"
"github.com/caos/zitadel/internal/usergrant/repository/view"
"github.com/caos/zitadel/internal/usergrant/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -32,28 +33,28 @@ func (v *View) SearchUserGrants(request *grant_model.UserGrantSearchRequest) ([]
return view.SearchUserGrants(v.Db, userGrantTable, request)
}
-func (v *View) PutUserGrant(grant *model.UserGrantView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutUserGrant(grant *model.UserGrantView, event *models.Event) error {
err := view.PutUserGrant(v.Db, userGrantTable, grant)
if err != nil {
return err
}
- return v.ProcessedUserGrantSequence(sequence, eventTimestamp)
+ return v.ProcessedUserGrantSequence(event)
}
-func (v *View) DeleteUserGrant(grantID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteUserGrant(grantID string, event *models.Event) error {
err := view.DeleteUserGrant(v.Db, userGrantTable, grantID)
- if err != nil {
- return nil
+ if err != nil && !errors.IsNotFound(err) {
+ return err
}
- return v.ProcessedUserGrantSequence(eventSequence, eventTimestamp)
+ return v.ProcessedUserGrantSequence(event)
}
-func (v *View) GetLatestUserGrantSequence() (*repository.CurrentSequence, error) {
- return v.latestSequence(userGrantTable)
+func (v *View) GetLatestUserGrantSequence(aggregateType string) (*repository.CurrentSequence, error) {
+ return v.latestSequence(userGrantTable, aggregateType)
}
-func (v *View) ProcessedUserGrantSequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(userGrantTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedUserGrantSequence(event *models.Event) error {
+ return v.saveCurrentSequence(userGrantTable, event)
}
func (v *View) UpdateUserGrantSpoolerRunTimestamp() error {
diff --git a/internal/config/types/sql.go b/internal/config/types/sql.go
index 74597c7e84..461dda6e78 100644
--- a/internal/config/types/sql.go
+++ b/internal/config/types/sql.go
@@ -62,6 +62,10 @@ func (s *SQL) Start() (*sql.DB, error) {
if err != nil {
return nil, errors.ThrowPreconditionFailed(err, "TYPES-9qBtr", "unable to open database connection")
}
+ // as we open many sql clients we set the max
+ // open cons deep. now 3(maxconn) * 8(clients) = max 24 conns per pod
+ client.SetMaxOpenConns(3)
+ client.SetMaxIdleConns(3)
return client, nil
}
diff --git a/internal/crypto/aes.go b/internal/crypto/aes.go
index 0aca064941..41720b04f6 100644
--- a/internal/crypto/aes.go
+++ b/internal/crypto/aes.go
@@ -116,7 +116,10 @@ func DecryptAESString(data string, key string) (string, error) {
return string(decrypted), nil
}
-func DecryptAES(cipherText []byte, key string) ([]byte, error) {
+func DecryptAES(text []byte, key string) ([]byte, error) {
+ cipherText := make([]byte, len(text))
+ copy(cipherText, text)
+
block, err := aes.NewCipher([]byte(key))
if err != nil {
return nil, err
diff --git a/internal/eventstore/eventstore.go b/internal/eventstore/eventstore.go
index b4f65d165a..84665dfc77 100644
--- a/internal/eventstore/eventstore.go
+++ b/internal/eventstore/eventstore.go
@@ -16,6 +16,7 @@ type Eventstore interface {
FilterEvents(ctx context.Context, searchQuery *models.SearchQuery) (events []*models.Event, err error)
LatestSequence(ctx context.Context, searchQuery *models.SearchQueryFactory) (uint64, error)
V2() *es_v2.Eventstore
+ Subscribe(aggregates ...models.AggregateType) *Subscription
}
var _ Eventstore = (*eventstore)(nil)
@@ -46,6 +47,8 @@ func (es *eventstore) PushAggregates(ctx context.Context, aggregates ...*models.
if err != nil {
return err
}
+
+ go notify(aggregates)
return nil
}
diff --git a/internal/eventstore/mock/eventstore.mock.go b/internal/eventstore/mock/eventstore.mock.go
index 18fb7a949a..fbe1990856 100644
--- a/internal/eventstore/mock/eventstore.mock.go
+++ b/internal/eventstore/mock/eventstore.mock.go
@@ -6,6 +6,7 @@ package mock
import (
context "context"
+ eventstore "github.com/caos/zitadel/internal/eventstore"
models "github.com/caos/zitadel/internal/eventstore/models"
gomock "github.com/golang/mock/gomock"
reflect "reflect"
@@ -110,3 +111,21 @@ func (mr *MockEventstoreMockRecorder) PushAggregates(arg0 interface{}, arg1 ...i
varargs := append([]interface{}{arg0}, arg1...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PushAggregates", reflect.TypeOf((*MockEventstore)(nil).PushAggregates), varargs...)
}
+
+// Subscribe mocks base method
+func (m *MockEventstore) Subscribe(arg0 ...models.AggregateType) *eventstore.Subscription {
+ m.ctrl.T.Helper()
+ varargs := []interface{}{}
+ for _, a := range arg0 {
+ varargs = append(varargs, a)
+ }
+ ret := m.ctrl.Call(m, "Subscribe", varargs...)
+ ret0, _ := ret[0].(*eventstore.Subscription)
+ return ret0
+}
+
+// Subscribe indicates an expected call of Subscribe
+func (mr *MockEventstoreMockRecorder) Subscribe(arg0 ...interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Subscribe", reflect.TypeOf((*MockEventstore)(nil).Subscribe), arg0...)
+}
diff --git a/internal/eventstore/models/aggregate.go b/internal/eventstore/models/aggregate.go
index 66026b05d5..a0a5c88779 100644
--- a/internal/eventstore/models/aggregate.go
+++ b/internal/eventstore/models/aggregate.go
@@ -27,6 +27,10 @@ type Aggregate struct {
Precondition *precondition
}
+func (a *Aggregate) Type() AggregateType {
+ return a.typ
+}
+
type precondition struct {
Query *SearchQuery
Validation func(...*Event) error
diff --git a/internal/eventstore/models/object.go b/internal/eventstore/models/object.go
index 695610c45c..931014f73b 100644
--- a/internal/eventstore/models/object.go
+++ b/internal/eventstore/models/object.go
@@ -15,6 +15,8 @@ type ObjectRoot struct {
func (o *ObjectRoot) AppendEvent(event *Event) {
if o.AggregateID == "" {
o.AggregateID = event.AggregateID
+ } else if o.AggregateID != event.AggregateID {
+ return
}
if o.ResourceOwner == "" {
o.ResourceOwner = event.ResourceOwner
diff --git a/internal/eventstore/models/search_query.go b/internal/eventstore/models/search_query.go
index 3530db46a8..06cbf97f1d 100644
--- a/internal/eventstore/models/search_query.go
+++ b/internal/eventstore/models/search_query.go
@@ -11,7 +11,8 @@ type SearchQueryFactory struct {
desc bool
aggregateTypes []AggregateType
aggregateIDs []string
- eventSequence uint64
+ sequenceFrom uint64
+ sequenceTo uint64
eventTypes []EventType
resourceOwner string
}
@@ -51,7 +52,11 @@ func FactoryFromSearchQuery(query *SearchQuery) *SearchQueryFactory {
factory = factory.AggregateIDs(aggregateIDs...)
}
case Field_LatestSequence:
- factory = factory.SequenceGreater(filter.value.(uint64))
+ if filter.operation == Operation_Greater {
+ factory = factory.SequenceGreater(filter.value.(uint64))
+ } else {
+ factory = factory.SequenceLess(filter.value.(uint64))
+ }
case Field_ResourceOwner:
factory = factory.ResourceOwner(filter.value.(string))
case Field_EventType:
@@ -82,7 +87,12 @@ func (factory *SearchQueryFactory) Limit(limit uint64) *SearchQueryFactory {
}
func (factory *SearchQueryFactory) SequenceGreater(sequence uint64) *SearchQueryFactory {
- factory.eventSequence = sequence
+ factory.sequenceFrom = sequence
+ return factory
+}
+
+func (factory *SearchQueryFactory) SequenceLess(sequence uint64) *SearchQueryFactory {
+ factory.sequenceTo = sequence
return factory
}
@@ -128,7 +138,8 @@ func (factory *SearchQueryFactory) Build() (*searchQuery, error) {
for _, f := range []func() *Filter{
factory.aggregateIDFilter,
- factory.eventSequenceFilter,
+ factory.sequenceFromFilter,
+ factory.sequenceToFilter,
factory.eventTypeFilter,
factory.resourceOwnerFilter,
} {
@@ -172,15 +183,26 @@ func (factory *SearchQueryFactory) aggregateTypeFilter() *Filter {
return NewFilter(Field_AggregateType, factory.aggregateTypes, Operation_In)
}
-func (factory *SearchQueryFactory) eventSequenceFilter() *Filter {
- if factory.eventSequence == 0 {
+func (factory *SearchQueryFactory) sequenceFromFilter() *Filter {
+ if factory.sequenceFrom == 0 {
return nil
}
sortOrder := Operation_Greater
if factory.desc {
sortOrder = Operation_Less
}
- return NewFilter(Field_LatestSequence, factory.eventSequence, sortOrder)
+ return NewFilter(Field_LatestSequence, factory.sequenceFrom, sortOrder)
+}
+
+func (factory *SearchQueryFactory) sequenceToFilter() *Filter {
+ if factory.sequenceTo == 0 {
+ return nil
+ }
+ sortOrder := Operation_Less
+ if factory.desc {
+ sortOrder = Operation_Greater
+ }
+ return NewFilter(Field_LatestSequence, factory.sequenceTo, sortOrder)
}
func (factory *SearchQueryFactory) resourceOwnerFilter() *Filter {
diff --git a/internal/eventstore/models/search_query_old.go b/internal/eventstore/models/search_query_old.go
index c803fac64b..1748b9d4d7 100644
--- a/internal/eventstore/models/search_query_old.go
+++ b/internal/eventstore/models/search_query_old.go
@@ -58,13 +58,19 @@ func (q *SearchQuery) LatestSequenceFilter(sequence uint64) *SearchQuery {
return q.setFilter(NewFilter(Field_LatestSequence, sequence, sortOrder))
}
+func (q *SearchQuery) SequenceBetween(from, to uint64) *SearchQuery {
+ q.setFilter(NewFilter(Field_LatestSequence, from, Operation_Greater))
+ q.setFilter(NewFilter(Field_LatestSequence, to, Operation_Less))
+ return q
+}
+
func (q *SearchQuery) ResourceOwnerFilter(resourceOwner string) *SearchQuery {
return q.setFilter(NewFilter(Field_ResourceOwner, resourceOwner, Operation_Equals))
}
func (q *SearchQuery) setFilter(filter *Filter) *SearchQuery {
for i, f := range q.Filters {
- if f.field == filter.field {
+ if f.field == filter.field && f.field != Field_LatestSequence {
q.Filters[i] = filter
return q
}
diff --git a/internal/eventstore/models/search_query_test.go b/internal/eventstore/models/search_query_test.go
index ac9380b4d9..b52f6490cf 100644
--- a/internal/eventstore/models/search_query_test.go
+++ b/internal/eventstore/models/search_query_test.go
@@ -103,7 +103,7 @@ func TestSearchQueryFactorySetters(t *testing.T) {
setters: []func(*SearchQueryFactory) *SearchQueryFactory{testSetSequence(90)},
},
res: &SearchQueryFactory{
- eventSequence: 90,
+ sequenceFrom: 90,
},
},
{
diff --git a/internal/eventstore/query/handler.go b/internal/eventstore/query/handler.go
index 36bba2547e..622a69156e 100755
--- a/internal/eventstore/query/handler.go
+++ b/internal/eventstore/query/handler.go
@@ -1,11 +1,18 @@
package query
import (
+ "context"
"time"
+ "github.com/caos/logging"
+ "github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
)
+const (
+ eventLimit = 10000
+)
+
type Handler interface {
ViewModel() string
EventQuery() (*models.SearchQuery, error)
@@ -13,5 +20,63 @@ type Handler interface {
OnError(event *models.Event, err error) error
OnSuccess() error
MinimumCycleDuration() time.Duration
+ LockDuration() time.Duration
QueryLimit() uint64
+
+ AggregateTypes() []models.AggregateType
+ CurrentSequence(*models.Event) (uint64, error)
+ Eventstore() eventstore.Eventstore
+}
+
+func ReduceEvent(handler Handler, event *models.Event) {
+ currentSequence, err := handler.CurrentSequence(event)
+ if err != nil {
+ logging.Log("HANDL-BmpkC").WithError(err).Warn("unable to get current sequence")
+ return
+ }
+
+ searchQuery := models.NewSearchQuery().
+ AggregateTypeFilter(handler.AggregateTypes()...).
+ SequenceBetween(currentSequence, event.Sequence).
+ SetLimit(eventLimit)
+
+ unprocessedEvents, err := handler.Eventstore().FilterEvents(context.Background(), searchQuery)
+ if err != nil {
+ logging.LogWithFields("HANDL-L6YH1", "seq", event.Sequence).Warn("filter failed")
+ return
+ }
+
+ processedSequences := map[models.AggregateType]uint64{}
+
+ for _, unprocessedEvent := range unprocessedEvents {
+ currentSequence, err := handler.CurrentSequence(unprocessedEvent)
+ if err != nil {
+ logging.Log("HANDL-BmpkC").WithError(err).Warn("unable to get current sequence")
+ return
+ }
+ _, ok := processedSequences[unprocessedEvent.AggregateType]
+ if !ok {
+ processedSequences[unprocessedEvent.AggregateType] = currentSequence
+ }
+ if processedSequences[unprocessedEvent.AggregateType] != currentSequence {
+ if currentSequence < processedSequences[unprocessedEvent.AggregateType] {
+ logging.LogWithFields("QUERY-DOYVN",
+ "processed", processedSequences[unprocessedEvent.AggregateType],
+ "current", currentSequence,
+ "view", handler.ViewModel()).
+ Warn("sequence not matching")
+ }
+ return
+ }
+
+ err = handler.Reduce(unprocessedEvent)
+ logging.LogWithFields("HANDL-V42TI", "seq", unprocessedEvent.Sequence).OnError(err).Warn("reduce failed")
+ processedSequences[unprocessedEvent.AggregateType] = unprocessedEvent.Sequence
+ }
+ if len(unprocessedEvents) == eventLimit {
+ logging.LogWithFields("QUERY-BSqe9", "seq", event.Sequence).Warn("didnt process event")
+ return
+ }
+ err = handler.Reduce(event)
+ logging.LogWithFields("HANDL-wQDL2", "seq", event.Sequence).OnError(err).Warn("reduce failed")
}
diff --git a/internal/eventstore/spooler/config.go b/internal/eventstore/spooler/config.go
index fa796f06c3..e89399b38e 100644
--- a/internal/eventstore/spooler/config.go
+++ b/internal/eventstore/spooler/config.go
@@ -1,6 +1,7 @@
package spooler
import (
+ "math/rand"
"os"
"github.com/caos/logging"
@@ -23,6 +24,11 @@ func (c *Config) New() *Spooler {
logging.Log("SPOOL-bdO56").OnError(err).Panic("unable to generate lockID")
}
+ //shuffle the handlers for better balance when running multiple pods
+ rand.Shuffle(len(c.ViewHandlers), func(i, j int) {
+ c.ViewHandlers[i], c.ViewHandlers[j] = c.ViewHandlers[j], c.ViewHandlers[i]
+ })
+
return &Spooler{
handlers: c.ViewHandlers,
lockID: lockID,
diff --git a/internal/eventstore/spooler/spooler.go b/internal/eventstore/spooler/spooler.go
index fb480f7916..40d124a6ed 100644
--- a/internal/eventstore/spooler/spooler.go
+++ b/internal/eventstore/spooler/spooler.go
@@ -4,6 +4,7 @@ import (
"context"
"strconv"
"sync"
+ "time"
"github.com/caos/logging"
"github.com/caos/zitadel/internal/eventstore"
@@ -11,8 +12,6 @@ import (
"github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/telemetry/tracing"
"github.com/caos/zitadel/internal/view/repository"
-
- "time"
)
type Spooler struct {
@@ -71,14 +70,26 @@ func (s *spooledHandler) load(workerID string) {
hasLocked := s.lock(ctx, errs, workerID)
if <-hasLocked {
- events, err := s.query(ctx)
- if err != nil {
- errs <- err
- } else {
- errs <- s.process(ctx, events, workerID)
- logging.Log("SPOOL-0pV8o").WithField("view", s.ViewModel()).WithField("worker", workerID).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Debug("process done")
+ for {
+ events, err := s.query(ctx)
+ if err != nil {
+ errs <- err
+ break
+ }
+ err = s.process(ctx, events, workerID)
+ if err != nil {
+ errs <- err
+ break
+ }
+ if uint64(len(events)) < s.QueryLimit() {
+ // no more events to process
+ // stop chan
+ if ctx.Err() == nil {
+ errs <- nil
+ }
+ break
+ }
}
-
}
<-ctx.Done()
}
@@ -92,14 +103,19 @@ func (s *spooledHandler) awaitError(cancel func(), errs chan error, workerID str
}
func (s *spooledHandler) process(ctx context.Context, events []*models.Event, workerID string) error {
- for _, event := range events {
+ for i, event := range events {
select {
case <-ctx.Done():
logging.LogWithFields("SPOOL-FTKwH", "view", s.ViewModel(), "worker", workerID, "traceID", tracing.TraceIDFromCtx(ctx)).Debug("context canceled")
return nil
default:
if err := s.Reduce(event); err != nil {
- return s.OnError(event, err)
+ err = s.OnError(event, err)
+ if err == nil {
+ continue
+ }
+ time.Sleep(100 * time.Millisecond)
+ return s.process(ctx, events[i:], workerID)
}
}
}
@@ -144,12 +160,12 @@ func (s *spooledHandler) lock(ctx context.Context, errs chan<- error, workerID s
case <-ctx.Done():
return
case <-renewTimer:
- err := s.locker.Renew(workerID, s.ViewModel(), s.MinimumCycleDuration()*2)
+ err := s.locker.Renew(workerID, s.ViewModel(), s.LockDuration())
firstLock.Do(func() {
locked <- err == nil
})
if err == nil {
- renewTimer = time.After(s.MinimumCycleDuration())
+ renewTimer = time.After(s.LockDuration())
continue
}
@@ -167,7 +183,8 @@ func (s *spooledHandler) lock(ctx context.Context, errs chan<- error, workerID s
func HandleError(event *models.Event, failedErr error,
latestFailedEvent func(sequence uint64) (*repository.FailedEvent, error),
processFailedEvent func(*repository.FailedEvent) error,
- processSequence func(uint64, time.Time) error, errorCountUntilSkip uint64) error {
+ processSequence func(*models.Event) error,
+ errorCountUntilSkip uint64) error {
failedEvent, err := latestFailedEvent(event.Sequence)
if err != nil {
return err
@@ -179,9 +196,9 @@ func HandleError(event *models.Event, failedErr error,
return err
}
if errorCountUntilSkip <= failedEvent.FailureCount {
- return processSequence(event.Sequence, event.CreationDate)
+ return processSequence(event)
}
- return nil
+ return failedErr
}
func HandleSuccess(updateSpoolerRunTimestamp func() error) error {
diff --git a/internal/eventstore/spooler/spooler_test.go b/internal/eventstore/spooler/spooler_test.go
index 721ad74e26..5b02977ea1 100644
--- a/internal/eventstore/spooler/spooler_test.go
+++ b/internal/eventstore/spooler/spooler_test.go
@@ -22,30 +22,57 @@ type testHandler struct {
queryError error
viewModel string
bulkLimit uint64
+ maxErrCount int
+}
+
+func (h *testHandler) AggregateTypes() []models.AggregateType {
+ return nil
+}
+
+func (h *testHandler) CurrentSequence(event *models.Event) (uint64, error) {
+ return 0, nil
+}
+
+func (h *testHandler) Eventstore() eventstore.Eventstore {
+ return nil
}
func (h *testHandler) ViewModel() string {
return h.viewModel
}
+
func (h *testHandler) EventQuery() (*models.SearchQuery, error) {
if h.queryError != nil {
return nil, h.queryError
}
return &models.SearchQuery{}, nil
}
+
func (h *testHandler) Reduce(*models.Event) error {
<-time.After(h.processSleep)
return h.processError
}
+
func (h *testHandler) OnError(event *models.Event, err error) error {
+ if h.maxErrCount == 2 {
+ return nil
+ }
+ h.maxErrCount++
return err
}
+
func (h *testHandler) OnSuccess() error {
return nil
}
+
func (h *testHandler) MinimumCycleDuration() time.Duration {
return h.cycleDuration
}
+
+func (h *testHandler) LockDuration() time.Duration {
+ return h.cycleDuration / 2
+}
+
func (h *testHandler) QueryLimit() uint64 {
return h.bulkLimit
}
@@ -55,6 +82,8 @@ type eventstoreStub struct {
err error
}
+func (es *eventstoreStub) Subscribe(...models.AggregateType) *eventstore.Subscription { return nil }
+
func (es *eventstoreStub) Health(ctx context.Context) error {
return nil
}
@@ -79,17 +108,18 @@ func (es *eventstoreStub) LatestSequence(ctx context.Context, in *models.SearchQ
func TestSpooler_process(t *testing.T) {
type fields struct {
- currentHandler query.Handler
+ currentHandler *testHandler
}
type args struct {
timeout time.Duration
events []*models.Event
}
tests := []struct {
- name string
- fields fields
- args args
- wantErr bool
+ name string
+ fields fields
+ args args
+ wantErr bool
+ wantRetries int
}{
{
name: "process all events",
@@ -121,7 +151,8 @@ func TestSpooler_process(t *testing.T) {
args: args{
events: []*models.Event{{}, {}},
},
- wantErr: true,
+ wantErr: false,
+ wantRetries: 2,
},
}
for _, tt := range tests {
@@ -140,6 +171,9 @@ func TestSpooler_process(t *testing.T) {
if err := s.process(ctx, tt.args.events, "test"); (err != nil) != tt.wantErr {
t.Errorf("Spooler.process() error = %v, wantErr %v", err, tt.wantErr)
}
+ if tt.fields.currentHandler.maxErrCount != tt.wantRetries {
+ t.Errorf("Spooler.process() wrong retry count got: %d want %d", tt.fields.currentHandler.maxErrCount, tt.wantRetries)
+ }
elapsed := time.Since(start).Round(1 * time.Second)
if tt.args.timeout != 0 && elapsed != tt.args.timeout {
@@ -208,31 +242,31 @@ func TestSpooler_load(t *testing.T) {
{
"lock exists",
fields{
- currentHandler: &testHandler{processSleep: 500 * time.Millisecond, viewModel: "testView", cycleDuration: 1 * time.Second},
- locker: newTestLocker(t, "testID", "testView").expectRenew(t, fmt.Errorf("lock already exists"), 2000*time.Millisecond),
+ currentHandler: &testHandler{processSleep: 500 * time.Millisecond, viewModel: "testView1", cycleDuration: 1 * time.Second, bulkLimit: 10},
+ locker: newTestLocker(t, "testID", "testView1").expectRenew(t, fmt.Errorf("lock already exists"), 500*time.Millisecond),
},
},
{
"lock fails",
fields{
- currentHandler: &testHandler{processSleep: 100 * time.Millisecond, viewModel: "testView", cycleDuration: 1 * time.Second},
- locker: newTestLocker(t, "testID", "testView").expectRenew(t, fmt.Errorf("fail"), 2000*time.Millisecond),
+ currentHandler: &testHandler{processSleep: 100 * time.Millisecond, viewModel: "testView2", cycleDuration: 1 * time.Second, bulkLimit: 10},
+ locker: newTestLocker(t, "testID", "testView2").expectRenew(t, fmt.Errorf("fail"), 500*time.Millisecond),
eventstore: &eventstoreStub{events: []*models.Event{{}}},
},
},
{
"query fails",
fields{
- currentHandler: &testHandler{processSleep: 100 * time.Millisecond, viewModel: "testView", queryError: fmt.Errorf("query fail"), cycleDuration: 1 * time.Second},
- locker: newTestLocker(t, "testID", "testView").expectRenew(t, nil, 2000*time.Millisecond),
+ currentHandler: &testHandler{processSleep: 100 * time.Millisecond, viewModel: "testView3", queryError: fmt.Errorf("query fail"), cycleDuration: 1 * time.Second, bulkLimit: 10},
+ locker: newTestLocker(t, "testID", "testView3").expectRenew(t, nil, 500*time.Millisecond),
eventstore: &eventstoreStub{err: fmt.Errorf("fail")},
},
},
{
"process event fails",
fields{
- currentHandler: &testHandler{processError: fmt.Errorf("oups"), processSleep: 100 * time.Millisecond, viewModel: "testView", cycleDuration: 500 * time.Millisecond},
- locker: newTestLocker(t, "testID", "testView").expectRenew(t, nil, 1000*time.Millisecond),
+ currentHandler: &testHandler{processError: fmt.Errorf("oups"), processSleep: 100 * time.Millisecond, viewModel: "testView4", cycleDuration: 500 * time.Millisecond, bulkLimit: 10},
+ locker: newTestLocker(t, "testID", "testView4").expectRenew(t, nil, 250*time.Millisecond),
eventstore: &eventstoreStub{events: []*models.Event{{}}},
},
},
@@ -268,7 +302,7 @@ func TestSpooler_lock(t *testing.T) {
"renew correct",
fields{
currentHandler: &testHandler{cycleDuration: 1 * time.Second, viewModel: "testView"},
- locker: newTestLocker(t, "testID", "testView").expectRenew(t, nil, 2000*time.Millisecond),
+ locker: newTestLocker(t, "testID", "testView").expectRenew(t, nil, 500*time.Millisecond),
expectsErr: false,
},
args{
@@ -279,7 +313,7 @@ func TestSpooler_lock(t *testing.T) {
"renew fails",
fields{
currentHandler: &testHandler{cycleDuration: 900 * time.Millisecond, viewModel: "testView"},
- locker: newTestLocker(t, "testID", "testView").expectRenew(t, fmt.Errorf("renew failed"), 1800*time.Millisecond),
+ locker: newTestLocker(t, "testID", "testView").expectRenew(t, fmt.Errorf("renew failed"), 450*time.Millisecond),
expectsErr: true,
},
args{
@@ -333,13 +367,15 @@ func newTestLocker(t *testing.T, lockerID, viewName string) *testLocker {
}
func (l *testLocker) expectRenew(t *testing.T, err error, waitTime time.Duration) *testLocker {
+ t.Helper()
l.mock.EXPECT().Renew(gomock.Any(), l.viewName, gomock.Any()).DoAndReturn(
func(_, _ string, gotten time.Duration) error {
+ t.Helper()
if waitTime-gotten != 0 {
t.Errorf("expected waittime %v got %v", waitTime, gotten)
}
return err
- }).Times(1)
+ }).MinTimes(1).MaxTimes(3)
return l
}
@@ -419,6 +455,7 @@ func TestHandleError(t *testing.T) {
},
res: res{
shouldProcessSequence: false,
+ wantErr: true,
},
},
}
@@ -432,7 +469,7 @@ func TestHandleError(t *testing.T) {
func(*repository.FailedEvent) error {
return nil
},
- func(uint64, time.Time) error {
+ func(*models.Event) error {
processedSequence = true
return nil
},
diff --git a/internal/eventstore/subscription.go b/internal/eventstore/subscription.go
new file mode 100644
index 0000000000..37aa0dd45c
--- /dev/null
+++ b/internal/eventstore/subscription.go
@@ -0,0 +1,73 @@
+package eventstore
+
+import (
+ "sync"
+
+ "github.com/caos/zitadel/internal/eventstore/models"
+)
+
+var (
+ subscriptions map[models.AggregateType][]*Subscription = map[models.AggregateType][]*Subscription{}
+ subsMutext sync.Mutex
+)
+
+type Subscription struct {
+ Events chan *models.Event
+ aggregates []models.AggregateType
+}
+
+func (es *eventstore) Subscribe(aggregates ...models.AggregateType) *Subscription {
+ events := make(chan *models.Event, 100)
+ sub := &Subscription{
+ Events: events,
+ aggregates: aggregates,
+ }
+
+ subsMutext.Lock()
+ defer subsMutext.Unlock()
+
+ for _, aggregate := range aggregates {
+ _, ok := subscriptions[aggregate]
+ if !ok {
+ subscriptions[aggregate] = make([]*Subscription, 0, 1)
+ }
+ subscriptions[aggregate] = append(subscriptions[aggregate], sub)
+ }
+
+ return sub
+}
+
+func notify(aggregates []*models.Aggregate) {
+ subsMutext.Lock()
+ defer subsMutext.Unlock()
+ for _, aggregate := range aggregates {
+ subs, ok := subscriptions[aggregate.Type()]
+ if !ok {
+ continue
+ }
+ for _, sub := range subs {
+ for _, event := range aggregate.Events {
+ sub.Events <- event
+ }
+ }
+ }
+}
+
+func (s *Subscription) Unsubscribe() {
+ subsMutext.Lock()
+ defer subsMutext.Unlock()
+ for _, aggregate := range s.aggregates {
+ subs, ok := subscriptions[aggregate]
+ if !ok {
+ continue
+ }
+ for i := len(subs) - 1; i >= 0; i-- {
+ if subs[i] == s {
+ subs[i] = subs[len(subs)-1]
+ subs[len(subs)-1] = nil
+ subs = subs[:len(subs)-1]
+ }
+ }
+ }
+ close(s.Events)
+}
diff --git a/internal/iam/model/iam.go b/internal/iam/model/iam.go
index 19696f3437..ce88ed38c5 100644
--- a/internal/iam/model/iam.go
+++ b/internal/iam/model/iam.go
@@ -16,6 +16,7 @@ const (
Step6
Step7
Step8
+ Step9
//StepCount marks the the length of possible steps (StepCount-1 == last possible step)
StepCount
)
diff --git a/internal/iam/repository/eventsourcing/eventstore.go b/internal/iam/repository/eventsourcing/eventstore.go
index 3d66ed4dcd..a484a5d573 100644
--- a/internal/iam/repository/eventsourcing/eventstore.go
+++ b/internal/iam/repository/eventsourcing/eventstore.go
@@ -525,20 +525,31 @@ func (es *IAMEventstore) AddLoginPolicy(ctx context.Context, policy *iam_model.L
return model.LoginPolicyToModel(repoIam.DefaultLoginPolicy), nil
}
-func (es *IAMEventstore) ChangeLoginPolicy(ctx context.Context, policy *iam_model.LoginPolicy) (*iam_model.LoginPolicy, error) {
+func (es *IAMEventstore) PrepareChangeLoginPolicy(ctx context.Context, policy *iam_model.LoginPolicy) (*model.IAM, *models.Aggregate, error) {
if policy == nil || !policy.IsValid() {
- return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-3M0so", "Errors.IAM.LoginPolicyInvalid")
+ return nil, nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-3M0so", "Errors.IAM.LoginPolicyInvalid")
}
iam, err := es.IAMByID(ctx, policy.AggregateID)
if err != nil {
- return nil, err
+ return nil, nil, err
}
repoIam := model.IAMFromModel(iam)
repoLoginPolicy := model.LoginPolicyFromModel(policy)
- addAggregate := LoginPolicyChangedAggregate(es.Eventstore.AggregateCreator(), repoIam, repoLoginPolicy)
- err = es_sdk.Push(ctx, es.PushAggregates, repoIam.AppendEvents, addAggregate)
+ changeAgg, err := LoginPolicyChangedAggregate(es.Eventstore.AggregateCreator(), repoIam, repoLoginPolicy)(ctx)
+ if err != nil {
+ return nil, nil, err
+ }
+ return repoIam, changeAgg, nil
+}
+
+func (es *IAMEventstore) ChangeLoginPolicy(ctx context.Context, policy *iam_model.LoginPolicy) (*iam_model.LoginPolicy, error) {
+ repoIam, changeAggregate, err := es.PrepareChangeLoginPolicy(ctx, policy)
+ if err != nil {
+ return nil, err
+ }
+ err = es_sdk.PushAggregates(ctx, es.PushAggregates, repoIam.AppendEvents, changeAggregate)
if err != nil {
return nil, err
}
@@ -665,27 +676,38 @@ func (es *IAMEventstore) RemoveSecondFactorFromLoginPolicy(ctx context.Context,
return nil
}
-func (es *IAMEventstore) AddMultiFactorToLoginPolicy(ctx context.Context, aggregateID string, mfa iam_model.MultiFactorType) (iam_model.MultiFactorType, error) {
+func (es *IAMEventstore) PrepareAddMultiFactorToLoginPolicy(ctx context.Context, aggregateID string, mfa iam_model.MultiFactorType) (*model.IAM, *models.Aggregate, error) {
if mfa == iam_model.MultiFactorTypeUnspecified {
- return 0, caos_errs.ThrowPreconditionFailed(nil, "EVENT-2Dh7J", "Errors.IAM.LoginPolicy.MFA.Unspecified")
+ return nil, nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-2Dh7J", "Errors.IAM.LoginPolicy.MFA.Unspecified")
}
iam, err := es.IAMByID(ctx, aggregateID)
if err != nil {
- return 0, err
+ return nil, nil, err
}
if _, m := iam.DefaultLoginPolicy.GetMultiFactor(mfa); m != 0 {
- return 0, caos_errs.ThrowAlreadyExists(nil, "EVENT-4Rk09", "Errors.IAM.LoginPolicy.MFA.AlreadyExists")
+ return nil, nil, caos_errs.ThrowAlreadyExists(nil, "EVENT-4Rk09", "Errors.IAM.LoginPolicy.MFA.AlreadyExists")
}
repoIam := model.IAMFromModel(iam)
repoMFA := model.MultiFactorFromModel(mfa)
- addAggregate := LoginPolicyMultiFactorAddedAggregate(es.Eventstore.AggregateCreator(), repoIam, repoMFA)
- err = es_sdk.Push(ctx, es.PushAggregates, repoIam.AppendEvents, addAggregate)
+ addAggregate, err := LoginPolicyMultiFactorAddedAggregate(es.Eventstore.AggregateCreator(), repoIam, repoMFA)(ctx)
+ if err != nil {
+ return nil, nil, err
+ }
+ return repoIam, addAggregate, nil
+}
+
+func (es *IAMEventstore) AddMultiFactorToLoginPolicy(ctx context.Context, aggregateID string, mfa iam_model.MultiFactorType) (iam_model.MultiFactorType, error) {
+ repoIAM, addAggregate, err := es.PrepareAddMultiFactorToLoginPolicy(ctx, aggregateID, mfa)
if err != nil {
return 0, err
}
- es.iamCache.cacheIAM(repoIam)
- if _, m := model.GetMFA(repoIam.DefaultLoginPolicy.MultiFactors, int32(mfa)); m != 0 {
+ err = es_sdk.PushAggregates(ctx, es.PushAggregates, repoIAM.AppendEvents, addAggregate)
+ if err != nil {
+ return 0, err
+ }
+ es.iamCache.cacheIAM(repoIAM)
+ if _, m := model.GetMFA(repoIAM.DefaultLoginPolicy.MultiFactors, int32(mfa)); m != 0 {
return iam_model.MultiFactorType(m), nil
}
return 0, caos_errs.ThrowInternal(nil, "EVENT-5N9so", "Errors.Internal")
diff --git a/internal/iam/repository/eventsourcing/model/login_policy.go b/internal/iam/repository/eventsourcing/model/login_policy.go
index 709b201850..4541cf4de1 100644
--- a/internal/iam/repository/eventsourcing/model/login_policy.go
+++ b/internal/iam/repository/eventsourcing/model/login_policy.go
@@ -2,6 +2,7 @@ package model
import (
"encoding/json"
+
"github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
diff --git a/internal/iam/repository/eventsourcing/model/org_iam_policy.go b/internal/iam/repository/eventsourcing/model/org_iam_policy.go
index 3056750803..1612d84c12 100644
--- a/internal/iam/repository/eventsourcing/model/org_iam_policy.go
+++ b/internal/iam/repository/eventsourcing/model/org_iam_policy.go
@@ -2,6 +2,7 @@ package model
import (
"encoding/json"
+
"github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
diff --git a/internal/iam/repository/eventsourcing/model/password_age_policy.go b/internal/iam/repository/eventsourcing/model/password_age_policy.go
index 86c65247d9..7d4b96d4d4 100644
--- a/internal/iam/repository/eventsourcing/model/password_age_policy.go
+++ b/internal/iam/repository/eventsourcing/model/password_age_policy.go
@@ -2,6 +2,7 @@ package model
import (
"encoding/json"
+
"github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
diff --git a/internal/iam/repository/eventsourcing/model/password_complexity_policy.go b/internal/iam/repository/eventsourcing/model/password_complexity_policy.go
index 37dc2db784..148db9f422 100644
--- a/internal/iam/repository/eventsourcing/model/password_complexity_policy.go
+++ b/internal/iam/repository/eventsourcing/model/password_complexity_policy.go
@@ -2,6 +2,7 @@ package model
import (
"encoding/json"
+
"github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
diff --git a/internal/iam/repository/eventsourcing/model/password_lockout_policy.go b/internal/iam/repository/eventsourcing/model/password_lockout_policy.go
index e4878c82f9..15c78c45ac 100644
--- a/internal/iam/repository/eventsourcing/model/password_lockout_policy.go
+++ b/internal/iam/repository/eventsourcing/model/password_lockout_policy.go
@@ -2,6 +2,7 @@ package model
import (
"encoding/json"
+
"github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
diff --git a/internal/management/repository/eventsourcing/eventstore/org.go b/internal/management/repository/eventsourcing/eventstore/org.go
index 0d8d3de3a0..4cd80676aa 100644
--- a/internal/management/repository/eventsourcing/eventstore/org.go
+++ b/internal/management/repository/eventsourcing/eventstore/org.go
@@ -108,7 +108,7 @@ func (repo *OrgRepository) GetMyOrgIamPolicy(ctx context.Context) (*iam_model.Or
func (repo *OrgRepository) SearchMyOrgDomains(ctx context.Context, request *org_model.OrgDomainSearchRequest) (*org_model.OrgDomainSearchResponse, error) {
request.EnsureLimit(repo.SearchLimit)
request.Queries = append(request.Queries, &org_model.OrgDomainSearchQuery{Key: org_model.OrgDomainSearchKeyOrgID, Method: global_model.SearchMethodEquals, Value: authz.GetCtxData(ctx).OrgID})
- sequence, sequenceErr := repo.View.GetLatestOrgDomainSequence()
+ sequence, sequenceErr := repo.View.GetLatestOrgDomainSequence("")
logging.Log("EVENT-SLowp").OnError(sequenceErr).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Warn("could not read latest org domain sequence")
domains, count, err := repo.View.SearchOrgDomains(request)
if err != nil {
@@ -205,7 +205,7 @@ func (repo *OrgRepository) RemoveMyOrgMember(ctx context.Context, userID string)
func (repo *OrgRepository) SearchMyOrgMembers(ctx context.Context, request *org_model.OrgMemberSearchRequest) (*org_model.OrgMemberSearchResponse, error) {
request.EnsureLimit(repo.SearchLimit)
request.Queries[len(request.Queries)-1] = &org_model.OrgMemberSearchQuery{Key: org_model.OrgMemberSearchKeyOrgID, Method: global_model.SearchMethodEquals, Value: authz.GetCtxData(ctx).OrgID}
- sequence, sequenceErr := repo.View.GetLatestOrgMemberSequence()
+ sequence, sequenceErr := repo.View.GetLatestOrgMemberSequence("")
logging.Log("EVENT-Smu3d").OnError(sequenceErr).Warn("could not read latest org member sequence")
members, count, err := repo.View.SearchOrgMembers(request)
if err != nil {
@@ -292,7 +292,7 @@ func (repo *OrgRepository) SearchIDPConfigs(ctx context.Context, request *iam_mo
request.EnsureLimit(repo.SearchLimit)
request.AppendMyOrgQuery(authz.GetCtxData(ctx).OrgID, repo.SystemDefaults.IamID)
- sequence, sequenceErr := repo.View.GetLatestIDPConfigSequence()
+ sequence, sequenceErr := repo.View.GetLatestIDPConfigSequence("")
logging.Log("EVENT-Dk8si").OnError(sequenceErr).Warn("could not read latest idp config sequence")
idps, count, err := repo.View.SearchIDPConfigs(request)
if err != nil {
@@ -414,7 +414,7 @@ func (repo *OrgRepository) SearchIDPProviders(ctx context.Context, request *iam_
request.AppendAggregateIDQuery(authz.GetCtxData(ctx).OrgID)
}
request.EnsureLimit(repo.SearchLimit)
- sequence, sequenceErr := repo.View.GetLatestIDPProviderSequence()
+ sequence, sequenceErr := repo.View.GetLatestIDPProviderSequence("")
logging.Log("EVENT-Tuiks").OnError(sequenceErr).Warn("could not read latest iam sequence")
providers, count, err := repo.View.SearchIDPProviders(request)
if err != nil {
diff --git a/internal/management/repository/eventsourcing/eventstore/project.go b/internal/management/repository/eventsourcing/eventstore/project.go
index 5a9343ff11..2d949a3f95 100644
--- a/internal/management/repository/eventsourcing/eventstore/project.go
+++ b/internal/management/repository/eventsourcing/eventstore/project.go
@@ -118,7 +118,7 @@ func (repo *ProjectRepo) RemoveProject(ctx context.Context, projectID string) er
func (repo *ProjectRepo) SearchProjects(ctx context.Context, request *proj_model.ProjectViewSearchRequest) (*proj_model.ProjectViewSearchResponse, error) {
request.EnsureLimit(repo.SearchLimit)
- sequence, sequenceErr := repo.View.GetLatestProjectSequence()
+ sequence, sequenceErr := repo.View.GetLatestProjectSequence("")
logging.Log("EVENT-Edc56").OnError(sequenceErr).Warn("could not read latest project sequence")
permissions := authz.GetRequestPermissionsFromCtx(ctx)
@@ -198,7 +198,7 @@ func (repo *ProjectRepo) RemoveProjectMember(ctx context.Context, projectID, use
func (repo *ProjectRepo) SearchProjectMembers(ctx context.Context, request *proj_model.ProjectMemberSearchRequest) (*proj_model.ProjectMemberSearchResponse, error) {
request.EnsureLimit(repo.SearchLimit)
- sequence, sequenceErr := repo.View.GetLatestProjectMemberSequence()
+ sequence, sequenceErr := repo.View.GetLatestProjectMemberSequence("")
logging.Log("EVENT-3dgt6").OnError(sequenceErr).Warn("could not read latest project member sequence")
members, count, err := repo.View.SearchProjectMembers(request)
if err != nil {
@@ -270,7 +270,7 @@ func (repo *ProjectRepo) RemoveProjectRole(ctx context.Context, projectID, key s
func (repo *ProjectRepo) SearchProjectRoles(ctx context.Context, projectID string, request *proj_model.ProjectRoleSearchRequest) (*proj_model.ProjectRoleSearchResponse, error) {
request.EnsureLimit(repo.SearchLimit)
request.AppendProjectQuery(projectID)
- sequence, sequenceErr := repo.View.GetLatestProjectRoleSequence()
+ sequence, sequenceErr := repo.View.GetLatestProjectRoleSequence("")
logging.Log("LSp0d-47suf").OnError(sequenceErr).Warn("could not read latest project role sequence")
roles, count, err := repo.View.SearchProjectRoles(request)
if err != nil {
@@ -366,7 +366,7 @@ func (repo *ProjectRepo) RemoveApplication(ctx context.Context, projectID, appID
func (repo *ProjectRepo) SearchApplications(ctx context.Context, request *proj_model.ApplicationSearchRequest) (*proj_model.ApplicationSearchResponse, error) {
request.EnsureLimit(repo.SearchLimit)
- sequence, sequenceErr := repo.View.GetLatestApplicationSequence()
+ sequence, sequenceErr := repo.View.GetLatestApplicationSequence("")
logging.Log("EVENT-SKe8s").OnError(sequenceErr).Warn("could not read latest application sequence")
apps, count, err := repo.View.SearchApplications(request)
if err != nil {
@@ -423,7 +423,7 @@ func (repo *ProjectRepo) ProjectGrantByID(ctx context.Context, grantID string) (
func (repo *ProjectRepo) SearchProjectGrants(ctx context.Context, request *proj_model.ProjectGrantViewSearchRequest) (*proj_model.ProjectGrantViewSearchResponse, error) {
request.EnsureLimit(repo.SearchLimit)
- sequence, sequenceErr := repo.View.GetLatestProjectGrantSequence()
+ sequence, sequenceErr := repo.View.GetLatestProjectGrantSequence("")
logging.Log("EVENT-Skw9f").OnError(sequenceErr).Warn("could not read latest project grant sequence")
projects, count, err := repo.View.SearchProjectGrants(request)
if err != nil {
@@ -444,7 +444,7 @@ func (repo *ProjectRepo) SearchProjectGrants(ctx context.Context, request *proj_
func (repo *ProjectRepo) SearchGrantedProjects(ctx context.Context, request *proj_model.ProjectGrantViewSearchRequest) (*proj_model.ProjectGrantViewSearchResponse, error) {
request.EnsureLimit(repo.SearchLimit)
- sequence, sequenceErr := repo.View.GetLatestProjectGrantSequence()
+ sequence, sequenceErr := repo.View.GetLatestProjectGrantSequence("")
logging.Log("EVENT-Skw9f").OnError(sequenceErr).Warn("could not read latest project grant sequence")
permissions := authz.GetRequestPermissionsFromCtx(ctx)
@@ -612,7 +612,7 @@ func (repo *ProjectRepo) RemoveProjectGrantMember(ctx context.Context, projectID
func (repo *ProjectRepo) SearchProjectGrantMembers(ctx context.Context, request *proj_model.ProjectGrantMemberSearchRequest) (*proj_model.ProjectGrantMemberSearchResponse, error) {
request.EnsureLimit(repo.SearchLimit)
- sequence, sequenceErr := repo.View.GetLatestProjectGrantMemberSequence()
+ sequence, sequenceErr := repo.View.GetLatestProjectGrantMemberSequence("")
logging.Log("EVENT-Du8sk").OnError(sequenceErr).Warn("could not read latest project grant sequence")
members, count, err := repo.View.SearchProjectGrantMembers(request)
if err != nil {
diff --git a/internal/management/repository/eventsourcing/eventstore/user.go b/internal/management/repository/eventsourcing/eventstore/user.go
index a9c77c84b8..1c16407b4f 100644
--- a/internal/management/repository/eventsourcing/eventstore/user.go
+++ b/internal/management/repository/eventsourcing/eventstore/user.go
@@ -3,24 +3,22 @@ package eventstore
import (
"context"
- es_int "github.com/caos/zitadel/internal/eventstore"
- es_models "github.com/caos/zitadel/internal/eventstore/models"
- es_sdk "github.com/caos/zitadel/internal/eventstore/sdk"
- iam_es_model "github.com/caos/zitadel/internal/iam/repository/view/model"
- usr_grant_event "github.com/caos/zitadel/internal/usergrant/repository/eventsourcing"
-
"github.com/caos/logging"
-
"github.com/caos/zitadel/internal/api/authz"
"github.com/caos/zitadel/internal/config/systemdefaults"
"github.com/caos/zitadel/internal/errors"
caos_errs "github.com/caos/zitadel/internal/errors"
+ es_int "github.com/caos/zitadel/internal/eventstore"
+ es_models "github.com/caos/zitadel/internal/eventstore/models"
+ es_sdk "github.com/caos/zitadel/internal/eventstore/sdk"
+ iam_es_model "github.com/caos/zitadel/internal/iam/repository/view/model"
"github.com/caos/zitadel/internal/management/repository/eventsourcing/view"
global_model "github.com/caos/zitadel/internal/model"
org_event "github.com/caos/zitadel/internal/org/repository/eventsourcing"
usr_model "github.com/caos/zitadel/internal/user/model"
usr_event "github.com/caos/zitadel/internal/user/repository/eventsourcing"
"github.com/caos/zitadel/internal/user/repository/view/model"
+ usr_grant_event "github.com/caos/zitadel/internal/usergrant/repository/eventsourcing"
"github.com/caos/zitadel/internal/view/repository"
)
@@ -158,7 +156,7 @@ func (repo *UserRepo) RemoveUser(ctx context.Context, id string) error {
func (repo *UserRepo) SearchUsers(ctx context.Context, request *usr_model.UserSearchRequest) (*usr_model.UserSearchResponse, error) {
request.EnsureLimit(repo.SearchLimit)
- sequence, sequenceErr := repo.View.GetLatestUserSequence()
+ sequence, sequenceErr := repo.View.GetLatestUserSequence("")
logging.Log("EVENT-Lcn7d").OnError(sequenceErr).Warn("could not read latest user sequence")
users, count, err := repo.View.SearchUsers(request)
if err != nil {
@@ -187,7 +185,7 @@ func (repo *UserRepo) UserChanges(ctx context.Context, id string, lastSequence u
user, _ := repo.UserEvents.UserByID(ctx, change.ModifierID)
if user != nil {
if user.Human != nil {
- change.ModifierName = user.DisplayName
+ change.ModifierName = user.Human.DisplayName
}
if user.Machine != nil {
change.ModifierName = user.Machine.Name
@@ -231,6 +229,18 @@ func (repo *UserRepo) RemoveOTP(ctx context.Context, userID string) error {
return repo.UserEvents.RemoveOTP(ctx, userID)
}
+func (repo *UserRepo) RemoveU2F(ctx context.Context, userID, webAuthNTokenID string) error {
+ return repo.UserEvents.RemoveU2FToken(ctx, userID, webAuthNTokenID)
+}
+
+func (repo *UserRepo) GetPasswordless(ctx context.Context, userID string) ([]*usr_model.WebAuthNToken, error) {
+ return repo.UserEvents.GetPasswordless(ctx, userID)
+}
+
+func (repo *UserRepo) RemovePasswordless(ctx context.Context, userID, webAuthNTokenID string) error {
+ return repo.UserEvents.RemovePasswordlessToken(ctx, userID, webAuthNTokenID)
+}
+
func (repo *UserRepo) SetOneTimePassword(ctx context.Context, password *usr_model.Password) (*usr_model.Password, error) {
policy, err := repo.View.PasswordComplexityPolicyByAggregateID(authz.GetCtxData(ctx).OrgID)
if err != nil && caos_errs.IsNotFound(err) {
@@ -264,7 +274,7 @@ func (repo *UserRepo) ProfileByID(ctx context.Context, userID string) (*usr_mode
func (repo *UserRepo) SearchExternalIDPs(ctx context.Context, request *usr_model.ExternalIDPSearchRequest) (*usr_model.ExternalIDPSearchResponse, error) {
request.EnsureLimit(repo.SearchLimit)
- sequence, seqErr := repo.View.GetLatestExternalIDPSequence()
+ sequence, seqErr := repo.View.GetLatestExternalIDPSequence("")
logging.Log("EVENT-Qs7uf").OnError(seqErr).Warn("could not read latest external idp sequence")
externalIDPS, count, err := repo.View.SearchExternalIDPs(request)
if err != nil {
@@ -301,7 +311,7 @@ func (repo *UserRepo) GetMachineKey(ctx context.Context, userID, keyID string) (
func (repo *UserRepo) SearchMachineKeys(ctx context.Context, request *usr_model.MachineKeySearchRequest) (*usr_model.MachineKeySearchResponse, error) {
request.EnsureLimit(repo.SearchLimit)
- sequence, seqErr := repo.View.GetLatestMachineKeySequence()
+ sequence, seqErr := repo.View.GetLatestMachineKeySequence("")
logging.Log("EVENT-Sk8fs").OnError(seqErr).Warn("could not read latest user sequence")
keys, count, err := repo.View.SearchMachineKeys(request)
if err != nil {
@@ -403,7 +413,7 @@ func (repo *UserRepo) ChangeAddress(ctx context.Context, address *usr_model.Addr
func (repo *UserRepo) SearchUserMemberships(ctx context.Context, request *usr_model.UserMembershipSearchRequest) (*usr_model.UserMembershipSearchResponse, error) {
request.EnsureLimit(repo.SearchLimit)
- sequence, sequenceErr := repo.View.GetLatestUserMembershipSequence()
+ sequence, sequenceErr := repo.View.GetLatestUserMembershipSequence("")
logging.Log("EVENT-Dn7sf").OnError(sequenceErr).Warn("could not read latest user sequence")
result := handleSearchUserMembershipsPermissions(ctx, request, sequence)
diff --git a/internal/management/repository/eventsourcing/eventstore/user_grant.go b/internal/management/repository/eventsourcing/eventstore/user_grant.go
index 09568b64fc..d2f4f337e9 100644
--- a/internal/management/repository/eventsourcing/eventstore/user_grant.go
+++ b/internal/management/repository/eventsourcing/eventstore/user_grant.go
@@ -116,7 +116,7 @@ func (repo *UserGrantRepo) BulkRemoveUserGrant(ctx context.Context, grantIDs ...
func (repo *UserGrantRepo) SearchUserGrants(ctx context.Context, request *grant_model.UserGrantSearchRequest) (*grant_model.UserGrantSearchResponse, error) {
request.EnsureLimit(repo.SearchLimit)
- sequence, sequenceErr := repo.View.GetLatestUserGrantSequence()
+ sequence, sequenceErr := repo.View.GetLatestUserGrantSequence("")
logging.Log("EVENT-5Viwf").OnError(sequenceErr).Warn("could not read latest user grant sequence")
result := handleSearchUserGrantPermissions(ctx, request, sequence)
diff --git a/internal/management/repository/eventsourcing/handler/application.go b/internal/management/repository/eventsourcing/handler/application.go
index 8d1490c433..442eae59b3 100644
--- a/internal/management/repository/eventsourcing/handler/application.go
+++ b/internal/management/repository/eventsourcing/handler/application.go
@@ -5,7 +5,9 @@ import (
"github.com/caos/logging"
+ "github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
"github.com/caos/zitadel/internal/project/repository/eventsourcing"
proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing"
@@ -13,21 +15,57 @@ import (
view_model "github.com/caos/zitadel/internal/project/repository/view/model"
)
-type Application struct {
- handler
- projectEvents *proj_event.ProjectEventstore
-}
-
const (
applicationTable = "management.applications"
)
+type Application struct {
+ handler
+ projectEvents *proj_event.ProjectEventstore
+ subscription *eventstore.Subscription
+}
+
+func newApplication(
+ handler handler,
+ projectEvents *proj_event.ProjectEventstore,
+) *Application {
+ h := &Application{
+ handler: handler,
+ projectEvents: projectEvents,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (a *Application) subscribe() {
+ a.subscription = a.es.Subscribe(a.AggregateTypes()...)
+ go func() {
+ for event := range a.subscription.Events {
+ query.ReduceEvent(a, event)
+ }
+ }()
+}
+
func (a *Application) ViewModel() string {
return applicationTable
}
+func (_ *Application) AggregateTypes() []models.AggregateType {
+ return []models.AggregateType{es_model.ProjectAggregate}
+}
+
+func (a *Application) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := a.view.GetLatestApplicationSequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (a *Application) EventQuery() (*models.SearchQuery, error) {
- sequence, err := a.view.GetLatestApplicationSequence()
+ sequence, err := a.view.GetLatestApplicationSequence("")
if err != nil {
return nil, err
}
@@ -65,30 +103,30 @@ func (a *Application) Reduce(event *models.Event) (err error) {
if err != nil {
return err
}
- return a.view.DeleteApplication(app.ID, event.Sequence, event.CreationDate)
+ return a.view.DeleteApplication(app.ID, event)
case es_model.ProjectChanged:
apps, err := a.view.ApplicationsByProjectID(event.AggregateID)
if err != nil {
return err
}
if len(apps) == 0 {
- return a.view.ProcessedApplicationSequence(event.Sequence, event.CreationDate)
+ return a.view.ProcessedApplicationSequence(event)
}
for _, app := range apps {
if err := app.AppendEvent(event); err != nil {
return err
}
}
- return a.view.PutApplications(apps, event.Sequence, event.CreationDate)
+ return a.view.PutApplications(apps, event)
case es_model.ProjectRemoved:
return a.view.DeleteApplicationsByProjectID(event.AggregateID)
default:
- return a.view.ProcessedApplicationSequence(event.Sequence, event.CreationDate)
+ return a.view.ProcessedApplicationSequence(event)
}
if err != nil {
return err
}
- return a.view.PutApplication(app, event.CreationDate)
+ return a.view.PutApplication(app, event)
}
func (a *Application) OnError(event *models.Event, spoolerError error) error {
diff --git a/internal/management/repository/eventsourcing/handler/handler.go b/internal/management/repository/eventsourcing/handler/handler.go
index 531a9db468..addd360caf 100644
--- a/internal/management/repository/eventsourcing/handler/handler.go
+++ b/internal/management/repository/eventsourcing/handler/handler.go
@@ -25,6 +25,12 @@ type handler struct {
bulkLimit uint64
cycleDuration time.Duration
errorCountUntilSkip uint64
+
+ es eventstore.Eventstore
+}
+
+func (h *handler) Eventstore() eventstore.Eventstore {
+ return h.es
}
type EventstoreRepos struct {
@@ -34,49 +40,76 @@ type EventstoreRepos struct {
IamEvents *iam_event.IAMEventstore
}
-func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, eventstore eventstore.Eventstore, repos EventstoreRepos, defaults systemdefaults.SystemDefaults) []query.Handler {
+func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es eventstore.Eventstore, repos EventstoreRepos, defaults systemdefaults.SystemDefaults) []query.Handler {
return []query.Handler{
- &Project{handler: handler{view, bulkLimit, configs.cycleDuration("Project"), errorCount},
- eventstore: eventstore},
- &ProjectGrant{handler: handler{view, bulkLimit, configs.cycleDuration("ProjectGrant"), errorCount},
- eventstore: eventstore, projectEvents: repos.ProjectEvents, orgEvents: repos.OrgEvents},
- &ProjectRole{handler: handler{view, bulkLimit, configs.cycleDuration("ProjectRole"), errorCount},
- projectEvents: repos.ProjectEvents},
- &ProjectMember{handler: handler{view, bulkLimit, configs.cycleDuration("ProjectMember"), errorCount},
- userEvents: repos.UserEvents},
- &ProjectGrantMember{handler: handler{view, bulkLimit, configs.cycleDuration("ProjectGrantMember"), errorCount},
- userEvents: repos.UserEvents},
- &Application{handler: handler{view, bulkLimit, configs.cycleDuration("Application"), errorCount},
- projectEvents: repos.ProjectEvents},
- &User{handler: handler{view, bulkLimit, configs.cycleDuration("User"), errorCount},
- eventstore: eventstore, orgEvents: repos.OrgEvents, iamEvents: repos.IamEvents, iamID: defaults.IamID},
- &UserGrant{handler: handler{view, bulkLimit, configs.cycleDuration("UserGrant"), errorCount},
- projectEvents: repos.ProjectEvents, userEvents: repos.UserEvents, orgEvents: repos.OrgEvents},
- &Org{handler: handler{view, bulkLimit, configs.cycleDuration("Org"), errorCount}},
- &OrgMember{handler: handler{view, bulkLimit, configs.cycleDuration("OrgMember"), errorCount},
- userEvents: repos.UserEvents},
- &OrgDomain{handler: handler{view, bulkLimit, configs.cycleDuration("OrgDomain"), errorCount}},
- &UserMembership{handler: handler{view, bulkLimit, configs.cycleDuration("UserMembership"), errorCount},
- orgEvents: repos.OrgEvents, projectEvents: repos.ProjectEvents},
- &MachineKeys{handler: handler{view, bulkLimit, configs.cycleDuration("MachineKeys"), errorCount}},
- &IDPConfig{handler: handler{view, bulkLimit, configs.cycleDuration("IDPConfig"), errorCount}},
- &LoginPolicy{handler: handler{view, bulkLimit, configs.cycleDuration("LoginPolicy"), errorCount}},
- &LabelPolicy{handler: handler{view, bulkLimit, configs.cycleDuration("LabelPolicy"), errorCount}},
- &IDPProvider{handler: handler{view, bulkLimit, configs.cycleDuration("IDPProvider"), errorCount},
- systemDefaults: defaults, iamEvents: repos.IamEvents, orgEvents: repos.OrgEvents},
- &ExternalIDP{handler: handler{view, bulkLimit, configs.cycleDuration("ExternalIDP"), errorCount},
- systemDefaults: defaults, iamEvents: repos.IamEvents, orgEvents: repos.OrgEvents},
- &PasswordComplexityPolicy{handler: handler{view, bulkLimit, configs.cycleDuration("PasswordComplexityPolicy"), errorCount}},
- &PasswordAgePolicy{handler: handler{view, bulkLimit, configs.cycleDuration("PasswordAgePolicy"), errorCount}},
- &PasswordLockoutPolicy{handler: handler{view, bulkLimit, configs.cycleDuration("PasswordLockoutPolicy"), errorCount}},
- &OrgIAMPolicy{handler: handler{view, bulkLimit, configs.cycleDuration("OrgIAMPolicy"), errorCount}},
+ newProject(
+ handler{view, bulkLimit, configs.cycleDuration("Project"), errorCount, es}),
+ newProjectGrant(
+ handler{view, bulkLimit, configs.cycleDuration("ProjectGrant"), errorCount, es},
+ repos.ProjectEvents,
+ repos.OrgEvents),
+ newProjectRole(handler{view, bulkLimit, configs.cycleDuration("ProjectRole"), errorCount, es},
+ repos.ProjectEvents),
+ newProjectMember(handler{view, bulkLimit, configs.cycleDuration("ProjectMember"), errorCount, es},
+ repos.UserEvents),
+ newProjectGrantMember(handler{view, bulkLimit, configs.cycleDuration("ProjectGrantMember"), errorCount, es},
+ repos.UserEvents),
+ newApplication(handler{view, bulkLimit, configs.cycleDuration("Application"), errorCount, es},
+ repos.ProjectEvents),
+ newUser(handler{view, bulkLimit, configs.cycleDuration("User"), errorCount, es},
+ repos.OrgEvents,
+ repos.IamEvents,
+ defaults.IamID),
+ newUserGrant(handler{view, bulkLimit, configs.cycleDuration("UserGrant"), errorCount, es},
+ repos.ProjectEvents,
+ repos.UserEvents,
+ repos.OrgEvents),
+ newOrg(
+ handler{view, bulkLimit, configs.cycleDuration("Org"), errorCount, es}),
+ newOrgMember(
+ handler{view, bulkLimit, configs.cycleDuration("OrgMember"), errorCount, es},
+ repos.UserEvents),
+ newOrgDomain(
+ handler{view, bulkLimit, configs.cycleDuration("OrgDomain"), errorCount, es}),
+ newUserMembership(
+ handler{view, bulkLimit, configs.cycleDuration("UserMembership"), errorCount, es},
+ repos.OrgEvents,
+ repos.ProjectEvents),
+ newMachineKeys(
+ handler{view, bulkLimit, configs.cycleDuration("MachineKeys"), errorCount, es}),
+ newIDPConfig(
+ handler{view, bulkLimit, configs.cycleDuration("IDPConfig"), errorCount, es}),
+ newLoginPolicy(
+ handler{view, bulkLimit, configs.cycleDuration("LoginPolicy"), errorCount, es}),
+ newLabelPolicy(
+ handler{view, bulkLimit, configs.cycleDuration("LabelPolicy"), errorCount, es}),
+ newIDPProvider(
+ handler{view, bulkLimit, configs.cycleDuration("IDPProvider"), errorCount, es},
+
+ defaults,
+ repos.IamEvents,
+ repos.OrgEvents),
+ newExternalIDP(
+ handler{view, bulkLimit, configs.cycleDuration("ExternalIDP"), errorCount, es},
+
+ defaults,
+ repos.IamEvents,
+ repos.OrgEvents),
+ newPasswordComplexityPolicy(
+ handler{view, bulkLimit, configs.cycleDuration("PasswordComplexityPolicy"), errorCount, es}),
+ newPasswordAgePolicy(
+ handler{view, bulkLimit, configs.cycleDuration("PasswordAgePolicy"), errorCount, es}),
+ newPasswordLockoutPolicy(
+ handler{view, bulkLimit, configs.cycleDuration("PasswordLockoutPolicy"), errorCount, es}),
+ newOrgIAMPolicy(
+ handler{view, bulkLimit, configs.cycleDuration("OrgIAMPolicy"), errorCount, es}),
}
}
func (configs Configs) cycleDuration(viewModel string) time.Duration {
c, ok := configs[viewModel]
if !ok {
- return 1 * time.Second
+ return 3 * time.Minute
}
return c.MinimumCycleDuration.Duration
}
@@ -85,6 +118,10 @@ func (h *handler) MinimumCycleDuration() time.Duration {
return h.cycleDuration
}
+func (h *handler) LockDuration() time.Duration {
+ return h.cycleDuration / 3
+}
+
func (h *handler) QueryLimit() uint64 {
return h.bulkLimit
}
diff --git a/internal/management/repository/eventsourcing/handler/idp_config.go b/internal/management/repository/eventsourcing/handler/idp_config.go
index 07301c71b8..5fa73038e5 100644
--- a/internal/management/repository/eventsourcing/handler/idp_config.go
+++ b/internal/management/repository/eventsourcing/handler/idp_config.go
@@ -2,8 +2,10 @@ package handler
import (
"github.com/caos/logging"
+ "github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
iam_model "github.com/caos/zitadel/internal/iam/model"
iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
@@ -11,29 +13,61 @@ import (
"github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
)
-type IDPConfig struct {
- handler
-}
-
const (
idpConfigTable = "management.idp_configs"
)
+type IDPConfig struct {
+ handler
+ subscription *eventstore.Subscription
+}
+
+func newIDPConfig(handler handler) *IDPConfig {
+ h := &IDPConfig{
+ handler: handler,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (m *IDPConfig) subscribe() {
+ m.subscription = m.es.Subscribe(m.AggregateTypes()...)
+ go func() {
+ for event := range m.subscription.Events {
+ query.ReduceEvent(m, event)
+ }
+ }()
+}
+
func (m *IDPConfig) ViewModel() string {
return idpConfigTable
}
-func (m *IDPConfig) EventQuery() (*models.SearchQuery, error) {
- sequence, err := m.view.GetLatestIDPConfigSequence()
+func (_ *IDPConfig) AggregateTypes() []es_models.AggregateType {
+ return []es_models.AggregateType{model.OrgAggregate, iam_es_model.IAMAggregate}
+}
+
+func (m *IDPConfig) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := m.view.GetLatestIDPConfigSequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
+func (m *IDPConfig) EventQuery() (*es_models.SearchQuery, error) {
+ sequence, err := m.view.GetLatestIDPConfigSequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(model.OrgAggregate, iam_es_model.IAMAggregate).
+ AggregateTypeFilter(m.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
-func (m *IDPConfig) Reduce(event *models.Event) (err error) {
+func (m *IDPConfig) Reduce(event *es_models.Event) (err error) {
switch event.AggregateType {
case model.OrgAggregate:
err = m.processIdpConfig(iam_model.IDPProviderTypeOrg, event)
@@ -43,7 +77,7 @@ func (m *IDPConfig) Reduce(event *models.Event) (err error) {
return err
}
-func (m *IDPConfig) processIdpConfig(providerType iam_model.IDPProviderType, event *models.Event) (err error) {
+func (m *IDPConfig) processIdpConfig(providerType iam_model.IDPProviderType, event *es_models.Event) (err error) {
idp := new(iam_view_model.IDPConfigView)
switch event.Type {
case model.IDPConfigAdded,
@@ -66,17 +100,17 @@ func (m *IDPConfig) processIdpConfig(providerType iam_model.IDPProviderType, eve
if err != nil {
return err
}
- return m.view.DeleteIDPConfig(idp.IDPConfigID, event.Sequence, event.CreationDate)
+ return m.view.DeleteIDPConfig(idp.IDPConfigID, event)
default:
- return m.view.ProcessedIDPConfigSequence(event.Sequence, event.CreationDate)
+ return m.view.ProcessedIDPConfigSequence(event)
}
if err != nil {
return err
}
- return m.view.PutIDPConfig(idp, idp.Sequence, event.CreationDate)
+ return m.view.PutIDPConfig(idp, event)
}
-func (i *IDPConfig) OnError(event *models.Event, err error) error {
+func (i *IDPConfig) OnError(event *es_models.Event, err error) error {
logging.LogWithFields("SPOOL-Nxu8s", "id", event.AggregateID).WithError(err).Warn("something went wrong in idp config handler")
return spooler.HandleError(event, err, i.view.GetLatestIDPConfigFailedEvent, i.view.ProcessedIDPConfigFailedEvent, i.view.ProcessedIDPConfigSequence, i.errorCountUntilSkip)
}
diff --git a/internal/management/repository/eventsourcing/handler/idp_providers.go b/internal/management/repository/eventsourcing/handler/idp_providers.go
index 9d873eed67..1b5933917b 100644
--- a/internal/management/repository/eventsourcing/handler/idp_providers.go
+++ b/internal/management/repository/eventsourcing/handler/idp_providers.go
@@ -2,18 +2,23 @@ package handler
import (
"context"
+
"github.com/caos/logging"
"github.com/caos/zitadel/internal/config/systemdefaults"
- "github.com/caos/zitadel/internal/iam/repository/eventsourcing"
- org_es "github.com/caos/zitadel/internal/org/repository/eventsourcing"
- org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
-
- "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
iam_model "github.com/caos/zitadel/internal/iam/model"
+ "github.com/caos/zitadel/internal/iam/repository/eventsourcing"
"github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
iam_view_model "github.com/caos/zitadel/internal/iam/repository/view/model"
+ org_es "github.com/caos/zitadel/internal/org/repository/eventsourcing"
+ org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
+)
+
+const (
+ idpProviderTable = "management.idp_providers"
)
type IDPProvider struct {
@@ -21,27 +26,63 @@ type IDPProvider struct {
systemDefaults systemdefaults.SystemDefaults
iamEvents *eventsourcing.IAMEventstore
orgEvents *org_es.OrgEventstore
+ subscription *eventstore.Subscription
}
-const (
- idpProviderTable = "management.idp_providers"
-)
+func newIDPProvider(
+ handler handler,
+ systemDefaults systemdefaults.SystemDefaults,
+ iamEvents *eventsourcing.IAMEventstore,
+ orgEvents *org_es.OrgEventstore,
+) *IDPProvider {
+ h := &IDPProvider{
+ handler: handler,
+ systemDefaults: systemDefaults,
+ iamEvents: iamEvents,
+ orgEvents: orgEvents,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (m *IDPProvider) subscribe() {
+ m.subscription = m.es.Subscribe(m.AggregateTypes()...)
+ go func() {
+ for event := range m.subscription.Events {
+ query.ReduceEvent(m, event)
+ }
+ }()
+}
func (m *IDPProvider) ViewModel() string {
return idpProviderTable
}
-func (m *IDPProvider) EventQuery() (*models.SearchQuery, error) {
- sequence, err := m.view.GetLatestIDPProviderSequence()
+func (_ *IDPProvider) AggregateTypes() []es_models.AggregateType {
+ return []es_models.AggregateType{model.IAMAggregate, org_es_model.OrgAggregate}
+}
+
+func (m *IDPProvider) CurrentSequence(event *es_models.Event) (uint64, error) {
+ sequence, err := m.view.GetLatestIDPProviderSequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
+func (m *IDPProvider) EventQuery() (*es_models.SearchQuery, error) {
+ sequence, err := m.view.GetLatestIDPProviderSequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(model.IAMAggregate, org_es_model.OrgAggregate).
+ AggregateTypeFilter(m.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
-func (m *IDPProvider) Reduce(event *models.Event) (err error) {
+func (m *IDPProvider) Reduce(event *es_models.Event) (err error) {
switch event.AggregateType {
case model.IAMAggregate, org_es_model.OrgAggregate:
err = m.processIdpProvider(event)
@@ -49,7 +90,7 @@ func (m *IDPProvider) Reduce(event *models.Event) (err error) {
return err
}
-func (m *IDPProvider) processIdpProvider(event *models.Event) (err error) {
+func (m *IDPProvider) processIdpProvider(event *es_models.Event) (err error) {
provider := new(iam_view_model.IDPProviderView)
switch event.Type {
case model.LoginPolicyIDPProviderAdded, org_es_model.LoginPolicyIDPProviderAdded:
@@ -64,7 +105,7 @@ func (m *IDPProvider) processIdpProvider(event *models.Event) (err error) {
if err != nil {
return err
}
- return m.view.DeleteIDPProvider(event.AggregateID, provider.IDPConfigID, event.Sequence, event.CreationDate)
+ return m.view.DeleteIDPProvider(event.AggregateID, provider.IDPConfigID, event)
case model.IDPConfigChanged, org_es_model.IDPConfigChanged:
esConfig := new(iam_view_model.IDPConfigView)
providerType := iam_model.IDPProviderTypeSystem
@@ -88,16 +129,16 @@ func (m *IDPProvider) processIdpProvider(event *models.Event) (err error) {
for _, provider := range providers {
m.fillConfigData(provider, config)
}
- return m.view.PutIDPProviders(event.Sequence, event.CreationDate, providers...)
+ return m.view.PutIDPProviders(event, providers...)
case org_es_model.LoginPolicyRemoved:
- return m.view.DeleteIDPProvidersByAggregateID(event.AggregateID, event.Sequence, event.CreationDate)
+ return m.view.DeleteIDPProvidersByAggregateID(event.AggregateID, event)
default:
- return m.view.ProcessedIDPProviderSequence(event.Sequence, event.CreationDate)
+ return m.view.ProcessedIDPProviderSequence(event)
}
if err != nil {
return err
}
- return m.view.PutIDPProvider(provider, provider.Sequence, event.CreationDate)
+ return m.view.PutIDPProvider(provider, event)
}
func (m *IDPProvider) fillData(provider *iam_view_model.IDPProviderView) (err error) {
@@ -121,7 +162,7 @@ func (m *IDPProvider) fillConfigData(provider *iam_view_model.IDPProviderView, c
provider.IDPState = int32(config.State)
}
-func (m *IDPProvider) OnError(event *models.Event, err error) error {
+func (m *IDPProvider) OnError(event *es_models.Event, err error) error {
logging.LogWithFields("SPOOL-Msj8c", "id", event.AggregateID).WithError(err).Warn("something went wrong in idp provider handler")
return spooler.HandleError(event, err, m.view.GetLatestIDPProviderFailedEvent, m.view.ProcessedIDPProviderFailedEvent, m.view.ProcessedIDPProviderSequence, m.errorCountUntilSkip)
}
diff --git a/internal/management/repository/eventsourcing/handler/label_policy.go b/internal/management/repository/eventsourcing/handler/label_policy.go
index 2c47a03c80..2cc3ba833e 100644
--- a/internal/management/repository/eventsourcing/handler/label_policy.go
+++ b/internal/management/repository/eventsourcing/handler/label_policy.go
@@ -2,34 +2,67 @@ package handler
import (
"github.com/caos/logging"
- iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
-
+ "github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
+ iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
iam_model "github.com/caos/zitadel/internal/iam/repository/view/model"
"github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
)
-type LabelPolicy struct {
- handler
-}
-
const (
labelPolicyTable = "management.label_policies"
)
+type LabelPolicy struct {
+ handler
+ subscription *eventstore.Subscription
+}
+
+func newLabelPolicy(handler handler) *LabelPolicy {
+ h := &LabelPolicy{
+ handler: handler,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (m *LabelPolicy) subscribe() {
+ m.subscription = m.es.Subscribe(m.AggregateTypes()...)
+ go func() {
+ for event := range m.subscription.Events {
+ query.ReduceEvent(m, event)
+ }
+ }()
+}
+
func (m *LabelPolicy) ViewModel() string {
return labelPolicyTable
}
+func (_ *LabelPolicy) AggregateTypes() []models.AggregateType {
+ return []models.AggregateType{model.OrgAggregate, iam_es_model.IAMAggregate}
+}
+
+func (m *LabelPolicy) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := m.view.GetLatestLabelPolicySequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (m *LabelPolicy) EventQuery() (*models.SearchQuery, error) {
- sequence, err := m.view.GetLatestLabelPolicySequence()
+ sequence, err := m.view.GetLatestLabelPolicySequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(model.OrgAggregate, iam_es_model.IAMAggregate).
+ AggregateTypeFilter(m.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
@@ -53,12 +86,12 @@ func (m *LabelPolicy) processLabelPolicy(event *models.Event) (err error) {
}
err = policy.AppendEvent(event)
default:
- return m.view.ProcessedLabelPolicySequence(event.Sequence, event.CreationDate)
+ return m.view.ProcessedLabelPolicySequence(event)
}
if err != nil {
return err
}
- return m.view.PutLabelPolicy(policy, policy.Sequence, event.CreationDate)
+ return m.view.PutLabelPolicy(policy, event)
}
func (m *LabelPolicy) OnError(event *models.Event, err error) error {
diff --git a/internal/management/repository/eventsourcing/handler/login_policy.go b/internal/management/repository/eventsourcing/handler/login_policy.go
index cb6f06c4d2..cf8994ff1e 100644
--- a/internal/management/repository/eventsourcing/handler/login_policy.go
+++ b/internal/management/repository/eventsourcing/handler/login_policy.go
@@ -2,34 +2,67 @@ package handler
import (
"github.com/caos/logging"
- iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
-
+ "github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
+ iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
iam_model "github.com/caos/zitadel/internal/iam/repository/view/model"
"github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
)
-type LoginPolicy struct {
- handler
-}
-
const (
loginPolicyTable = "management.login_policies"
)
+type LoginPolicy struct {
+ handler
+ subscription *eventstore.Subscription
+}
+
+func newLoginPolicy(handler handler) *LoginPolicy {
+ h := &LoginPolicy{
+ handler: handler,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (m *LoginPolicy) subscribe() {
+ m.subscription = m.es.Subscribe(m.AggregateTypes()...)
+ go func() {
+ for event := range m.subscription.Events {
+ query.ReduceEvent(m, event)
+ }
+ }()
+}
+
func (m *LoginPolicy) ViewModel() string {
return loginPolicyTable
}
+func (_ *LoginPolicy) AggregateTypes() []models.AggregateType {
+ return []models.AggregateType{model.OrgAggregate, iam_es_model.IAMAggregate}
+}
+
+func (m *LoginPolicy) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := m.view.GetLatestLoginPolicySequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (m *LoginPolicy) EventQuery() (*models.SearchQuery, error) {
- sequence, err := m.view.GetLatestLoginPolicySequence()
+ sequence, err := m.view.GetLatestLoginPolicySequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(model.OrgAggregate, iam_es_model.IAMAggregate).
+ AggregateTypeFilter(m.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
@@ -57,14 +90,14 @@ func (m *LoginPolicy) processLoginPolicy(event *models.Event) (err error) {
}
err = policy.AppendEvent(event)
case model.LoginPolicyRemoved:
- return m.view.DeleteLoginPolicy(event.AggregateID, event.Sequence, event.CreationDate)
+ return m.view.DeleteLoginPolicy(event.AggregateID, event)
default:
- return m.view.ProcessedLoginPolicySequence(event.Sequence, event.CreationDate)
+ return m.view.ProcessedLoginPolicySequence(event)
}
if err != nil {
return err
}
- return m.view.PutLoginPolicy(policy, policy.Sequence, event.CreationDate)
+ return m.view.PutLoginPolicy(policy, event)
}
func (m *LoginPolicy) OnError(event *models.Event, err error) error {
diff --git a/internal/management/repository/eventsourcing/handler/machine_keys.go b/internal/management/repository/eventsourcing/handler/machine_keys.go
index cd6b29b6a8..6758c4f173 100644
--- a/internal/management/repository/eventsourcing/handler/machine_keys.go
+++ b/internal/management/repository/eventsourcing/handler/machine_keys.go
@@ -4,33 +4,66 @@ import (
"time"
"github.com/caos/logging"
-
+ "github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
"github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
usr_model "github.com/caos/zitadel/internal/user/repository/view/model"
)
-type MachineKeys struct {
- handler
-}
-
const (
machineKeysTable = "management.machine_keys"
)
+type MachineKeys struct {
+ handler
+ subscription *eventstore.Subscription
+}
+
+func newMachineKeys(handler handler) *MachineKeys {
+ h := &MachineKeys{
+ handler: handler,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (m *MachineKeys) subscribe() {
+ m.subscription = m.es.Subscribe(m.AggregateTypes()...)
+ go func() {
+ for event := range m.subscription.Events {
+ query.ReduceEvent(m, event)
+ }
+ }()
+}
+
func (d *MachineKeys) ViewModel() string {
return machineKeysTable
}
+func (_ *MachineKeys) AggregateTypes() []es_models.AggregateType {
+ return []es_models.AggregateType{model.UserAggregate}
+}
+
+func (k *MachineKeys) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := k.view.GetLatestMachineKeySequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (d *MachineKeys) EventQuery() (*models.SearchQuery, error) {
- sequence, err := d.view.GetLatestMachineKeySequence()
+ sequence, err := d.view.GetLatestMachineKeySequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(model.UserAggregate).
+ AggregateTypeFilter(d.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
@@ -48,23 +81,23 @@ func (d *MachineKeys) processMachineKeys(event *models.Event) (err error) {
case model.MachineKeyAdded:
err = key.AppendEvent(event)
if key.ExpirationDate.Before(time.Now()) {
- return d.view.ProcessedMachineKeySequence(event.Sequence, event.CreationDate)
+ return d.view.ProcessedMachineKeySequence(event)
}
case model.MachineKeyRemoved:
err = key.SetData(event)
if err != nil {
return err
}
- return d.view.DeleteMachineKey(key.ID, event.Sequence, event.CreationDate)
+ return d.view.DeleteMachineKey(key.ID, event)
case model.UserRemoved:
- return d.view.DeleteMachineKeysByUserID(event.AggregateID, event.Sequence, event.CreationDate)
+ return d.view.DeleteMachineKeysByUserID(event.AggregateID, event)
default:
- return d.view.ProcessedMachineKeySequence(event.Sequence, event.CreationDate)
+ return d.view.ProcessedMachineKeySequence(event)
}
if err != nil {
return err
}
- return d.view.PutMachineKey(key, key.Sequence, event.CreationDate)
+ return d.view.PutMachineKey(key, event)
}
func (d *MachineKeys) OnError(event *models.Event, err error) error {
diff --git a/internal/management/repository/eventsourcing/handler/org.go b/internal/management/repository/eventsourcing/handler/org.go
index 23155a5c52..a4f6eb211d 100644
--- a/internal/management/repository/eventsourcing/handler/org.go
+++ b/internal/management/repository/eventsourcing/handler/org.go
@@ -2,28 +2,62 @@ package handler
import (
"github.com/caos/logging"
-
+ "github.com/caos/zitadel/internal/eventstore"
+ "github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
"github.com/caos/zitadel/internal/org/repository/eventsourcing"
"github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
org_model "github.com/caos/zitadel/internal/org/repository/view/model"
)
-type Org struct {
- handler
-}
-
const (
orgTable = "management.orgs"
)
+type Org struct {
+ handler
+ subscription *eventstore.Subscription
+}
+
+func newOrg(handler handler) *Org {
+ h := &Org{
+ handler: handler,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (m *Org) subscribe() {
+ m.subscription = m.es.Subscribe(m.AggregateTypes()...)
+ go func() {
+ for event := range m.subscription.Events {
+ query.ReduceEvent(m, event)
+ }
+ }()
+}
+
func (o *Org) ViewModel() string {
return orgTable
}
+func (_ *Org) AggregateTypes() []es_models.AggregateType {
+ return []es_models.AggregateType{model.OrgAggregate}
+}
+
+func (o *Org) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := o.view.GetLatestOrgSequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (o *Org) EventQuery() (*es_models.SearchQuery, error) {
- sequence, err := o.view.GetLatestOrgSequence()
+ sequence, err := o.view.GetLatestOrgSequence("")
if err != nil {
return nil, err
}
@@ -47,12 +81,12 @@ func (o *Org) Reduce(event *es_models.Event) (err error) {
}
err = org.AppendEvent(event)
default:
- return o.view.ProcessedOrgSequence(event.Sequence, event.CreationDate)
+ return o.view.ProcessedOrgSequence(event)
}
if err != nil {
return err
}
- return o.view.PutOrg(org, event.CreationDate)
+ return o.view.PutOrg(org, event)
}
func (o *Org) OnError(event *es_models.Event, spoolerErr error) error {
diff --git a/internal/management/repository/eventsourcing/handler/org_domain.go b/internal/management/repository/eventsourcing/handler/org_domain.go
index 9dc6307749..9a7dedb5ee 100644
--- a/internal/management/repository/eventsourcing/handler/org_domain.go
+++ b/internal/management/repository/eventsourcing/handler/org_domain.go
@@ -2,33 +2,66 @@ package handler
import (
"github.com/caos/logging"
-
+ "github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
"github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
org_model "github.com/caos/zitadel/internal/org/repository/view/model"
)
-type OrgDomain struct {
- handler
-}
-
const (
orgDomainTable = "management.org_domains"
)
+type OrgDomain struct {
+ handler
+ subscription *eventstore.Subscription
+}
+
+func newOrgDomain(handler handler) *OrgDomain {
+ h := &OrgDomain{
+ handler: handler,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (m *OrgDomain) subscribe() {
+ m.subscription = m.es.Subscribe(m.AggregateTypes()...)
+ go func() {
+ for event := range m.subscription.Events {
+ query.ReduceEvent(m, event)
+ }
+ }()
+}
+
func (d *OrgDomain) ViewModel() string {
return orgDomainTable
}
+func (_ *OrgDomain) AggregateTypes() []es_models.AggregateType {
+ return []es_models.AggregateType{model.OrgAggregate}
+}
+
+func (p *OrgDomain) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := p.view.GetLatestOrgDomainSequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (d *OrgDomain) EventQuery() (*models.SearchQuery, error) {
- sequence, err := d.view.GetLatestOrgDomainSequence()
+ sequence, err := d.view.GetLatestOrgDomainSequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(model.OrgAggregate).
+ AggregateTypeFilter(d.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
@@ -72,7 +105,7 @@ func (d *OrgDomain) processOrgDomain(event *models.Event) (err error) {
for _, existingDomain := range existingDomains {
existingDomain.Primary = false
}
- err = d.view.PutOrgDomains(existingDomains, 0, event.CreationDate)
+ err = d.view.PutOrgDomains(existingDomains, event)
if err != nil {
return err
}
@@ -82,14 +115,14 @@ func (d *OrgDomain) processOrgDomain(event *models.Event) (err error) {
if err != nil {
return err
}
- return d.view.DeleteOrgDomain(event.AggregateID, domain.Domain, event.Sequence, event.CreationDate)
+ return d.view.DeleteOrgDomain(event.AggregateID, domain.Domain, event)
default:
- return d.view.ProcessedOrgDomainSequence(event.Sequence, event.CreationDate)
+ return d.view.ProcessedOrgDomainSequence(event)
}
if err != nil {
return err
}
- return d.view.PutOrgDomain(domain, domain.Sequence, event.CreationDate)
+ return d.view.PutOrgDomain(domain, event)
}
func (d *OrgDomain) OnError(event *models.Event, err error) error {
diff --git a/internal/management/repository/eventsourcing/handler/org_iam_policy.go b/internal/management/repository/eventsourcing/handler/org_iam_policy.go
index fffe08cfec..796652bbb4 100644
--- a/internal/management/repository/eventsourcing/handler/org_iam_policy.go
+++ b/internal/management/repository/eventsourcing/handler/org_iam_policy.go
@@ -2,34 +2,67 @@ package handler
import (
"github.com/caos/logging"
- iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
-
+ "github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
+ iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
iam_model "github.com/caos/zitadel/internal/iam/repository/view/model"
"github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
)
-type OrgIAMPolicy struct {
- handler
-}
-
const (
orgIAMPolicyTable = "management.org_iam_policies"
)
+type OrgIAMPolicy struct {
+ handler
+ subscription *eventstore.Subscription
+}
+
+func newOrgIAMPolicy(handler handler) *OrgIAMPolicy {
+ h := &OrgIAMPolicy{
+ handler: handler,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (m *OrgIAMPolicy) subscribe() {
+ m.subscription = m.es.Subscribe(m.AggregateTypes()...)
+ go func() {
+ for event := range m.subscription.Events {
+ query.ReduceEvent(m, event)
+ }
+ }()
+}
+
func (m *OrgIAMPolicy) ViewModel() string {
return orgIAMPolicyTable
}
+func (_ *OrgIAMPolicy) AggregateTypes() []es_models.AggregateType {
+ return []es_models.AggregateType{model.OrgAggregate, iam_es_model.IAMAggregate}
+}
+
+func (p *OrgIAMPolicy) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := p.view.GetLatestOrgIAMPolicySequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (m *OrgIAMPolicy) EventQuery() (*models.SearchQuery, error) {
- sequence, err := m.view.GetLatestOrgIAMPolicySequence()
+ sequence, err := m.view.GetLatestOrgIAMPolicySequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(model.OrgAggregate, iam_es_model.IAMAggregate).
+ AggregateTypeFilter(m.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
@@ -53,14 +86,14 @@ func (m *OrgIAMPolicy) processOrgIAMPolicy(event *models.Event) (err error) {
}
err = policy.AppendEvent(event)
case model.OrgIAMPolicyRemoved:
- return m.view.DeleteOrgIAMPolicy(event.AggregateID, event.Sequence, event.CreationDate)
+ return m.view.DeleteOrgIAMPolicy(event.AggregateID, event)
default:
- return m.view.ProcessedOrgIAMPolicySequence(event.Sequence, event.CreationDate)
+ return m.view.ProcessedOrgIAMPolicySequence(event)
}
if err != nil {
return err
}
- return m.view.PutOrgIAMPolicy(policy, policy.Sequence, event.CreationDate)
+ return m.view.PutOrgIAMPolicy(policy, event)
}
func (m *OrgIAMPolicy) OnError(event *models.Event, err error) error {
diff --git a/internal/management/repository/eventsourcing/handler/org_member.go b/internal/management/repository/eventsourcing/handler/org_member.go
index 26f2b2fb86..cf3e1b6499 100644
--- a/internal/management/repository/eventsourcing/handler/org_member.go
+++ b/internal/management/repository/eventsourcing/handler/org_member.go
@@ -4,9 +4,10 @@ import (
"context"
"github.com/caos/logging"
-
+ "github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
"github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
org_model "github.com/caos/zitadel/internal/org/repository/view/model"
@@ -15,26 +16,62 @@ import (
usr_es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
)
-type OrgMember struct {
- handler
- userEvents *usr_event.UserEventstore
-}
-
const (
orgMemberTable = "management.org_members"
)
+type OrgMember struct {
+ handler
+ userEvents *usr_event.UserEventstore
+ subscription *eventstore.Subscription
+}
+
+func newOrgMember(
+ handler handler,
+ userEvents *usr_event.UserEventstore,
+) *OrgMember {
+ h := &OrgMember{
+ handler: handler,
+ userEvents: userEvents,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (m *OrgMember) subscribe() {
+ m.subscription = m.es.Subscribe(m.AggregateTypes()...)
+ go func() {
+ for event := range m.subscription.Events {
+ query.ReduceEvent(m, event)
+ }
+ }()
+}
+
func (m *OrgMember) ViewModel() string {
return orgMemberTable
}
+func (_ *OrgMember) AggregateTypes() []es_models.AggregateType {
+ return []es_models.AggregateType{model.OrgAggregate, usr_es_model.UserAggregate}
+}
+
+func (p *OrgMember) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := p.view.GetLatestOrgMemberSequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (m *OrgMember) EventQuery() (*models.SearchQuery, error) {
- sequence, err := m.view.GetLatestOrgMemberSequence()
+ sequence, err := m.view.GetLatestOrgMemberSequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(model.OrgAggregate, usr_es_model.UserAggregate).
+ AggregateTypeFilter(m.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
@@ -72,14 +109,14 @@ func (m *OrgMember) processOrgMember(event *models.Event) (err error) {
if err != nil {
return err
}
- return m.view.DeleteOrgMember(event.AggregateID, member.UserID, event.Sequence, event.CreationDate)
+ return m.view.DeleteOrgMember(event.AggregateID, member.UserID, event)
default:
- return m.view.ProcessedOrgMemberSequence(event.Sequence, event.CreationDate)
+ return m.view.ProcessedOrgMemberSequence(event)
}
if err != nil {
return err
}
- return m.view.PutOrgMember(member, member.Sequence, event.CreationDate)
+ return m.view.PutOrgMember(member, event)
}
func (m *OrgMember) processUser(event *models.Event) (err error) {
@@ -94,7 +131,7 @@ func (m *OrgMember) processUser(event *models.Event) (err error) {
return err
}
if len(members) == 0 {
- return m.view.ProcessedOrgMemberSequence(event.Sequence, event.CreationDate)
+ return m.view.ProcessedOrgMemberSequence(event)
}
user, err := m.userEvents.UserByID(context.Background(), event.AggregateID)
if err != nil {
@@ -103,13 +140,12 @@ func (m *OrgMember) processUser(event *models.Event) (err error) {
for _, member := range members {
m.fillUserData(member, user)
}
- return m.view.PutOrgMembers(members, event.Sequence, event.CreationDate)
+ return m.view.PutOrgMembers(members, event)
case usr_es_model.UserRemoved:
- return m.view.DeleteOrgMembersByUserID(event.AggregateID, event.Sequence, event.CreationDate)
+ return m.view.DeleteOrgMembersByUserID(event.AggregateID, event)
default:
- return m.view.ProcessedOrgMemberSequence(event.Sequence, event.CreationDate)
+ return m.view.ProcessedOrgMemberSequence(event)
}
- return nil
}
func (m *OrgMember) fillData(member *org_model.OrgMemberView) (err error) {
diff --git a/internal/management/repository/eventsourcing/handler/password_age_policy.go b/internal/management/repository/eventsourcing/handler/password_age_policy.go
index 535acf03db..eee2e2711c 100644
--- a/internal/management/repository/eventsourcing/handler/password_age_policy.go
+++ b/internal/management/repository/eventsourcing/handler/password_age_policy.go
@@ -2,34 +2,67 @@ package handler
import (
"github.com/caos/logging"
- iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
-
+ "github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
+ iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
iam_model "github.com/caos/zitadel/internal/iam/repository/view/model"
"github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
)
-type PasswordAgePolicy struct {
- handler
-}
-
const (
passwordAgePolicyTable = "management.password_age_policies"
)
+type PasswordAgePolicy struct {
+ handler
+ subscription *eventstore.Subscription
+}
+
+func newPasswordAgePolicy(handler handler) *PasswordAgePolicy {
+ h := &PasswordAgePolicy{
+ handler: handler,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (m *PasswordAgePolicy) subscribe() {
+ m.subscription = m.es.Subscribe(m.AggregateTypes()...)
+ go func() {
+ for event := range m.subscription.Events {
+ query.ReduceEvent(m, event)
+ }
+ }()
+}
+
func (m *PasswordAgePolicy) ViewModel() string {
return passwordAgePolicyTable
}
-func (m *PasswordAgePolicy) EventQuery() (*models.SearchQuery, error) {
- sequence, err := m.view.GetLatestPasswordAgePolicySequence()
+func (_ *PasswordAgePolicy) AggregateTypes() []es_models.AggregateType {
+ return []es_models.AggregateType{model.OrgAggregate, iam_es_model.IAMAggregate}
+}
+
+func (o *PasswordAgePolicy) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := o.view.GetLatestPasswordAgePolicySequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
+func (p *PasswordAgePolicy) EventQuery() (*models.SearchQuery, error) {
+ sequence, err := p.view.GetLatestPasswordAgePolicySequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(model.OrgAggregate, iam_es_model.IAMAggregate).
+ AggregateTypeFilter(p.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
@@ -53,14 +86,14 @@ func (m *PasswordAgePolicy) processPasswordAgePolicy(event *models.Event) (err e
}
err = policy.AppendEvent(event)
case model.PasswordAgePolicyRemoved:
- return m.view.DeletePasswordAgePolicy(event.AggregateID, event.Sequence, event.CreationDate)
+ return m.view.DeletePasswordAgePolicy(event.AggregateID, event)
default:
- return m.view.ProcessedPasswordAgePolicySequence(event.Sequence, event.CreationDate)
+ return m.view.ProcessedPasswordAgePolicySequence(event)
}
if err != nil {
return err
}
- return m.view.PutPasswordAgePolicy(policy, policy.Sequence, event.CreationDate)
+ return m.view.PutPasswordAgePolicy(policy, event)
}
func (m *PasswordAgePolicy) OnError(event *models.Event, err error) error {
diff --git a/internal/management/repository/eventsourcing/handler/password_complexity_policy.go b/internal/management/repository/eventsourcing/handler/password_complexity_policy.go
index 4ada8b0c95..d2d14c885d 100644
--- a/internal/management/repository/eventsourcing/handler/password_complexity_policy.go
+++ b/internal/management/repository/eventsourcing/handler/password_complexity_policy.go
@@ -2,34 +2,67 @@ package handler
import (
"github.com/caos/logging"
- iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
-
+ "github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
+ iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
iam_model "github.com/caos/zitadel/internal/iam/repository/view/model"
"github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
)
-type PasswordComplexityPolicy struct {
- handler
-}
-
const (
passwordComplexityPolicyTable = "management.password_complexity_policies"
)
+type PasswordComplexityPolicy struct {
+ handler
+ subscription *eventstore.Subscription
+}
+
+func newPasswordComplexityPolicy(handler handler) *PasswordComplexityPolicy {
+ h := &PasswordComplexityPolicy{
+ handler: handler,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (m *PasswordComplexityPolicy) subscribe() {
+ m.subscription = m.es.Subscribe(m.AggregateTypes()...)
+ go func() {
+ for event := range m.subscription.Events {
+ query.ReduceEvent(m, event)
+ }
+ }()
+}
+
func (p *PasswordComplexityPolicy) ViewModel() string {
return passwordComplexityPolicyTable
}
+func (_ *PasswordComplexityPolicy) AggregateTypes() []es_models.AggregateType {
+ return []es_models.AggregateType{model.OrgAggregate, iam_es_model.IAMAggregate}
+}
+
+func (p *PasswordComplexityPolicy) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := p.view.GetLatestPasswordComplexityPolicySequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (p *PasswordComplexityPolicy) EventQuery() (*models.SearchQuery, error) {
- sequence, err := p.view.GetLatestPasswordComplexityPolicySequence()
+ sequence, err := p.view.GetLatestPasswordComplexityPolicySequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(model.OrgAggregate, iam_es_model.IAMAggregate).
+ AggregateTypeFilter(p.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
@@ -53,14 +86,14 @@ func (p *PasswordComplexityPolicy) processPasswordComplexityPolicy(event *models
}
err = policy.AppendEvent(event)
case model.PasswordComplexityPolicyRemoved:
- return p.view.DeletePasswordComplexityPolicy(event.AggregateID, event.Sequence, event.CreationDate)
+ return p.view.DeletePasswordComplexityPolicy(event.AggregateID, event)
default:
- return p.view.ProcessedPasswordComplexityPolicySequence(event.Sequence, event.CreationDate)
+ return p.view.ProcessedPasswordComplexityPolicySequence(event)
}
if err != nil {
return err
}
- return p.view.PutPasswordComplexityPolicy(policy, policy.Sequence, event.CreationDate)
+ return p.view.PutPasswordComplexityPolicy(policy, event)
}
func (p *PasswordComplexityPolicy) OnError(event *models.Event, err error) error {
diff --git a/internal/management/repository/eventsourcing/handler/password_lockout_policy.go b/internal/management/repository/eventsourcing/handler/password_lockout_policy.go
index c5a66d9528..19e7c9c0b6 100644
--- a/internal/management/repository/eventsourcing/handler/password_lockout_policy.go
+++ b/internal/management/repository/eventsourcing/handler/password_lockout_policy.go
@@ -2,34 +2,68 @@ package handler
import (
"github.com/caos/logging"
+ "github.com/caos/zitadel/internal/eventstore"
iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
iam_model "github.com/caos/zitadel/internal/iam/repository/view/model"
"github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
)
-type PasswordLockoutPolicy struct {
- handler
-}
-
const (
passwordLockoutPolicyTable = "management.password_lockout_policies"
)
+type PasswordLockoutPolicy struct {
+ handler
+ subscription *eventstore.Subscription
+}
+
+func newPasswordLockoutPolicy(handler handler) *PasswordLockoutPolicy {
+ h := &PasswordLockoutPolicy{
+ handler: handler,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (m *PasswordLockoutPolicy) subscribe() {
+ m.subscription = m.es.Subscribe(m.AggregateTypes()...)
+ go func() {
+ for event := range m.subscription.Events {
+ query.ReduceEvent(m, event)
+ }
+ }()
+}
+
func (p *PasswordLockoutPolicy) ViewModel() string {
return passwordLockoutPolicyTable
}
+func (_ *PasswordLockoutPolicy) AggregateTypes() []es_models.AggregateType {
+ return []es_models.AggregateType{model.OrgAggregate, iam_es_model.IAMAggregate}
+}
+
+func (p *PasswordLockoutPolicy) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := p.view.GetLatestPasswordLockoutPolicySequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (p *PasswordLockoutPolicy) EventQuery() (*models.SearchQuery, error) {
- sequence, err := p.view.GetLatestPasswordLockoutPolicySequence()
+ sequence, err := p.view.GetLatestPasswordLockoutPolicySequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(model.OrgAggregate, iam_es_model.IAMAggregate).
+ AggregateTypeFilter(p.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
@@ -53,14 +87,14 @@ func (p *PasswordLockoutPolicy) processPasswordLockoutPolicy(event *models.Event
}
err = policy.AppendEvent(event)
case model.PasswordLockoutPolicyRemoved:
- return p.view.DeletePasswordLockoutPolicy(event.AggregateID, event.Sequence, event.CreationDate)
+ return p.view.DeletePasswordLockoutPolicy(event.AggregateID, event)
default:
- return p.view.ProcessedPasswordLockoutPolicySequence(event.Sequence, event.CreationDate)
+ return p.view.ProcessedPasswordLockoutPolicySequence(event)
}
if err != nil {
return err
}
- return p.view.PutPasswordLockoutPolicy(policy, policy.Sequence, event.CreationDate)
+ return p.view.PutPasswordLockoutPolicy(policy, event)
}
func (p *PasswordLockoutPolicy) OnError(event *models.Event, err error) error {
diff --git a/internal/management/repository/eventsourcing/handler/project.go b/internal/management/repository/eventsourcing/handler/project.go
index 0536de9ae5..51331d44ee 100644
--- a/internal/management/repository/eventsourcing/handler/project.go
+++ b/internal/management/repository/eventsourcing/handler/project.go
@@ -5,27 +5,59 @@ import (
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing"
es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model"
view_model "github.com/caos/zitadel/internal/project/repository/view/model"
)
-type Project struct {
- handler
- eventstore eventstore.Eventstore
-}
-
const (
projectTable = "management.projects"
)
+type Project struct {
+ handler
+ subscription *eventstore.Subscription
+}
+
+func newProject(handler handler) *Project {
+ h := &Project{
+ handler: handler,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (m *Project) subscribe() {
+ m.subscription = m.es.Subscribe(m.AggregateTypes()...)
+ go func() {
+ for event := range m.subscription.Events {
+ query.ReduceEvent(m, event)
+ }
+ }()
+}
+
func (p *Project) ViewModel() string {
return projectTable
}
+func (_ *Project) AggregateTypes() []models.AggregateType {
+ return []models.AggregateType{es_model.ProjectAggregate}
+}
+
+func (p *Project) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := p.view.GetLatestProjectSequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (p *Project) EventQuery() (*models.SearchQuery, error) {
- sequence, err := p.view.GetLatestProjectSequence()
+ sequence, err := p.view.GetLatestProjectSequence("")
if err != nil {
return nil, err
}
@@ -46,14 +78,14 @@ func (p *Project) Reduce(event *models.Event) (err error) {
}
err = project.AppendEvent(event)
case es_model.ProjectRemoved:
- return p.view.DeleteProject(event.AggregateID, event.Sequence, event.CreationDate)
+ return p.view.DeleteProject(event.AggregateID, event)
default:
- return p.view.ProcessedProjectSequence(event.Sequence, event.CreationDate)
+ return p.view.ProcessedProjectSequence(event)
}
if err != nil {
return err
}
- return p.view.PutProject(project, event.CreationDate)
+ return p.view.PutProject(project, event)
}
func (p *Project) OnError(event *models.Event, err error) error {
diff --git a/internal/management/repository/eventsourcing/handler/project_grant.go b/internal/management/repository/eventsourcing/handler/project_grant.go
index 1c7306bb21..918eb54f56 100644
--- a/internal/management/repository/eventsourcing/handler/project_grant.go
+++ b/internal/management/repository/eventsourcing/handler/project_grant.go
@@ -2,12 +2,12 @@ package handler
import (
"context"
- "time"
"github.com/caos/logging"
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
org_model "github.com/caos/zitadel/internal/org/model"
org_event "github.com/caos/zitadel/internal/org/repository/eventsourcing"
@@ -17,23 +17,60 @@ import (
view_model "github.com/caos/zitadel/internal/project/repository/view/model"
)
-type ProjectGrant struct {
- handler
- eventstore eventstore.Eventstore
- projectEvents *proj_event.ProjectEventstore
- orgEvents *org_event.OrgEventstore
-}
-
const (
grantedProjectTable = "management.project_grants"
)
+type ProjectGrant struct {
+ handler
+ projectEvents *proj_event.ProjectEventstore
+ orgEvents *org_event.OrgEventstore
+ subscription *eventstore.Subscription
+}
+
+func newProjectGrant(
+ handler handler,
+ projectEvents *proj_event.ProjectEventstore,
+ orgEvents *org_event.OrgEventstore,
+) *ProjectGrant {
+ h := &ProjectGrant{
+ handler: handler,
+ projectEvents: projectEvents,
+ orgEvents: orgEvents,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (m *ProjectGrant) subscribe() {
+ m.subscription = m.es.Subscribe(m.AggregateTypes()...)
+ go func() {
+ for event := range m.subscription.Events {
+ query.ReduceEvent(m, event)
+ }
+ }()
+}
+
func (p *ProjectGrant) ViewModel() string {
return grantedProjectTable
}
+func (_ *ProjectGrant) AggregateTypes() []models.AggregateType {
+ return []models.AggregateType{es_model.ProjectAggregate}
+}
+
+func (p *ProjectGrant) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := p.view.GetLatestProjectGrantSequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (p *ProjectGrant) EventQuery() (*models.SearchQuery, error) {
- sequence, err := p.view.GetLatestProjectGrantSequence()
+ sequence, err := p.view.GetLatestProjectGrantSequence("")
if err != nil {
return nil, err
}
@@ -48,7 +85,7 @@ func (p *ProjectGrant) Reduce(event *models.Event) (err error) {
if err != nil {
return err
}
- return p.updateExistingProjects(project, event.Sequence, event.CreationDate)
+ return p.updateExistingProjects(project, event)
case es_model.ProjectGrantAdded:
err = grantedProject.AppendEvent(event)
if err != nil {
@@ -86,16 +123,20 @@ func (p *ProjectGrant) Reduce(event *models.Event) (err error) {
if err != nil {
return err
}
- return p.view.DeleteProjectGrant(grant.GrantID, event.Sequence, event.CreationDate)
+ return p.view.DeleteProjectGrant(grant.GrantID, event)
case es_model.ProjectRemoved:
- return p.view.DeleteProjectGrantsByProjectID(event.AggregateID)
+ err = p.view.DeleteProjectGrantsByProjectID(event.AggregateID)
+ if err != nil {
+ return err
+ }
+ return p.view.ProcessedProjectGrantSequence(event)
default:
- return p.view.ProcessedProjectGrantSequence(event.Sequence, event.CreationDate)
+ return p.view.ProcessedProjectGrantSequence(event)
}
if err != nil {
return err
}
- return p.view.PutProjectGrant(grantedProject, event.CreationDate)
+ return p.view.PutProjectGrant(grantedProject, event)
}
func (p *ProjectGrant) fillOrgData(grantedProject *view_model.ProjectGrantView, org, resourceOwner *org_model.Org) {
@@ -107,7 +148,7 @@ func (p *ProjectGrant) getProject(projectID string) (*proj_model.Project, error)
return p.projectEvents.ProjectByID(context.Background(), projectID)
}
-func (p *ProjectGrant) updateExistingProjects(project *view_model.ProjectView, sequence uint64, eventTimestamp time.Time) error {
+func (p *ProjectGrant) updateExistingProjects(project *view_model.ProjectView, event *models.Event) error {
projectGrants, err := p.view.ProjectGrantsByProjectID(project.ProjectID)
if err != nil {
logging.LogWithFields("SPOOL-los03", "id", project.ProjectID).WithError(err).Warn("could not update existing projects")
@@ -115,7 +156,7 @@ func (p *ProjectGrant) updateExistingProjects(project *view_model.ProjectView, s
for _, existingGrant := range projectGrants {
existingGrant.Name = project.Name
}
- return p.view.PutProjectGrants(projectGrants, sequence, eventTimestamp)
+ return p.view.PutProjectGrants(projectGrants, event)
}
func (p *ProjectGrant) OnError(event *models.Event, err error) error {
diff --git a/internal/management/repository/eventsourcing/handler/project_grant_member.go b/internal/management/repository/eventsourcing/handler/project_grant_member.go
index fb37af782e..159be6d870 100644
--- a/internal/management/repository/eventsourcing/handler/project_grant_member.go
+++ b/internal/management/repository/eventsourcing/handler/project_grant_member.go
@@ -5,8 +5,10 @@ import (
"github.com/caos/logging"
+ "github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
proj_es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model"
view_model "github.com/caos/zitadel/internal/project/repository/view/model"
@@ -15,26 +17,62 @@ import (
usr_es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
)
-type ProjectGrantMember struct {
- handler
- userEvents *usr_event.UserEventstore
-}
-
const (
projectGrantMemberTable = "management.project_grant_members"
)
+type ProjectGrantMember struct {
+ handler
+ userEvents *usr_event.UserEventstore
+ subscription *eventstore.Subscription
+}
+
+func newProjectGrantMember(
+ handler handler,
+ userEvents *usr_event.UserEventstore,
+) *ProjectGrantMember {
+ h := &ProjectGrantMember{
+ handler: handler,
+ userEvents: userEvents,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (m *ProjectGrantMember) subscribe() {
+ m.subscription = m.es.Subscribe(m.AggregateTypes()...)
+ go func() {
+ for event := range m.subscription.Events {
+ query.ReduceEvent(m, event)
+ }
+ }()
+}
+
func (p *ProjectGrantMember) ViewModel() string {
return projectGrantMemberTable
}
+func (_ *ProjectGrantMember) AggregateTypes() []es_models.AggregateType {
+ return []es_models.AggregateType{proj_es_model.ProjectAggregate, usr_es_model.UserAggregate}
+}
+
+func (p *ProjectGrantMember) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := p.view.GetLatestProjectGrantMemberSequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (p *ProjectGrantMember) EventQuery() (*models.SearchQuery, error) {
- sequence, err := p.view.GetLatestProjectGrantMemberSequence()
+ sequence, err := p.view.GetLatestProjectGrantMemberSequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(proj_es_model.ProjectAggregate, usr_es_model.UserAggregate).
+ AggregateTypeFilter(p.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
@@ -72,16 +110,20 @@ func (p *ProjectGrantMember) processProjectGrantMember(event *models.Event) (err
if err != nil {
return err
}
- return p.view.DeleteProjectGrantMember(member.GrantID, member.UserID, event.Sequence, event.CreationDate)
+ return p.view.DeleteProjectGrantMember(member.GrantID, member.UserID, event)
case proj_es_model.ProjectRemoved:
- return p.view.DeleteProjectGrantMembersByProjectID(event.AggregateID)
+ err = p.view.DeleteProjectGrantMembersByProjectID(event.AggregateID)
+ if err != nil {
+ return err
+ }
+ return p.view.ProcessedProjectGrantMemberSequence(event)
default:
- return p.view.ProcessedProjectGrantMemberSequence(event.Sequence, event.CreationDate)
+ return p.view.ProcessedProjectGrantMemberSequence(event)
}
if err != nil {
return err
}
- return p.view.PutProjectGrantMember(member, member.Sequence, event.CreationDate)
+ return p.view.PutProjectGrantMember(member, event)
}
func (p *ProjectGrantMember) processUser(event *models.Event) (err error) {
@@ -96,7 +138,7 @@ func (p *ProjectGrantMember) processUser(event *models.Event) (err error) {
return err
}
if len(members) == 0 {
- return p.view.ProcessedProjectGrantMemberSequence(event.Sequence, event.CreationDate)
+ return p.view.ProcessedProjectGrantMemberSequence(event)
}
user, err := p.userEvents.UserByID(context.Background(), event.AggregateID)
if err != nil {
@@ -105,11 +147,10 @@ func (p *ProjectGrantMember) processUser(event *models.Event) (err error) {
for _, member := range members {
p.fillUserData(member, user)
}
- return p.view.PutProjectGrantMembers(members, event.Sequence, event.CreationDate)
+ return p.view.PutProjectGrantMembers(members, event)
default:
- return p.view.ProcessedProjectGrantMemberSequence(event.Sequence, event.CreationDate)
+ return p.view.ProcessedProjectGrantMemberSequence(event)
}
- return nil
}
func (p *ProjectGrantMember) fillData(member *view_model.ProjectGrantMemberView) (err error) {
diff --git a/internal/management/repository/eventsourcing/handler/project_member.go b/internal/management/repository/eventsourcing/handler/project_member.go
index 7de3603f25..721f42e9d8 100644
--- a/internal/management/repository/eventsourcing/handler/project_member.go
+++ b/internal/management/repository/eventsourcing/handler/project_member.go
@@ -5,8 +5,10 @@ import (
"github.com/caos/logging"
+ "github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
proj_es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model"
view_model "github.com/caos/zitadel/internal/project/repository/view/model"
@@ -15,26 +17,62 @@ import (
usr_es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
)
-type ProjectMember struct {
- handler
- userEvents *usr_event.UserEventstore
-}
-
const (
projectMemberTable = "management.project_members"
)
+type ProjectMember struct {
+ handler
+ userEvents *usr_event.UserEventstore
+ subscription *eventstore.Subscription
+}
+
+func newProjectMember(
+ handler handler,
+ userEvents *usr_event.UserEventstore,
+) *ProjectMember {
+ h := &ProjectMember{
+ handler: handler,
+ userEvents: userEvents,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (m *ProjectMember) subscribe() {
+ m.subscription = m.es.Subscribe(m.AggregateTypes()...)
+ go func() {
+ for event := range m.subscription.Events {
+ query.ReduceEvent(m, event)
+ }
+ }()
+}
+
func (p *ProjectMember) ViewModel() string {
return projectMemberTable
}
+func (_ *ProjectMember) AggregateTypes() []models.AggregateType {
+ return []models.AggregateType{proj_es_model.ProjectAggregate, usr_es_model.UserAggregate}
+}
+
+func (p *ProjectMember) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := p.view.GetLatestProjectMemberSequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (p *ProjectMember) EventQuery() (*models.SearchQuery, error) {
- sequence, err := p.view.GetLatestProjectMemberSequence()
+ sequence, err := p.view.GetLatestProjectMemberSequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(proj_es_model.ProjectAggregate, usr_es_model.UserAggregate).
+ AggregateTypeFilter(p.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
@@ -72,16 +110,16 @@ func (p *ProjectMember) processProjectMember(event *models.Event) (err error) {
if err != nil {
return err
}
- return p.view.DeleteProjectMember(event.AggregateID, member.UserID, event.Sequence, event.CreationDate)
+ return p.view.DeleteProjectMember(event.AggregateID, member.UserID, event)
case proj_es_model.ProjectRemoved:
return p.view.DeleteProjectMembersByProjectID(event.AggregateID)
default:
- return p.view.ProcessedProjectMemberSequence(event.Sequence, event.CreationDate)
+ return p.view.ProcessedProjectMemberSequence(event)
}
if err != nil {
return err
}
- return p.view.PutProjectMember(member, member.Sequence, event.CreationDate)
+ return p.view.PutProjectMember(member, event)
}
func (p *ProjectMember) processUser(event *models.Event) (err error) {
@@ -96,7 +134,7 @@ func (p *ProjectMember) processUser(event *models.Event) (err error) {
return err
}
if len(members) == 0 {
- return p.view.ProcessedProjectMemberSequence(event.Sequence, event.CreationDate)
+ return p.view.ProcessedProjectMemberSequence(event)
}
user, err := p.userEvents.UserByID(context.Background(), event.AggregateID)
if err != nil {
@@ -105,9 +143,9 @@ func (p *ProjectMember) processUser(event *models.Event) (err error) {
for _, member := range members {
p.fillUserData(member, user)
}
- return p.view.PutProjectMembers(members, event.Sequence, event.CreationDate)
+ return p.view.PutProjectMembers(members, event)
default:
- return p.view.ProcessedProjectMemberSequence(event.Sequence, event.CreationDate)
+ return p.view.ProcessedProjectMemberSequence(event)
}
return nil
}
diff --git a/internal/management/repository/eventsourcing/handler/project_role.go b/internal/management/repository/eventsourcing/handler/project_role.go
index 0dba4b14e8..3d89ba4a9f 100644
--- a/internal/management/repository/eventsourcing/handler/project_role.go
+++ b/internal/management/repository/eventsourcing/handler/project_role.go
@@ -3,7 +3,9 @@ package handler
import (
"github.com/caos/logging"
+ "github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
"github.com/caos/zitadel/internal/project/repository/eventsourcing"
proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing"
@@ -11,21 +13,57 @@ import (
view_model "github.com/caos/zitadel/internal/project/repository/view/model"
)
-type ProjectRole struct {
- handler
- projectEvents *proj_event.ProjectEventstore
-}
-
const (
projectRoleTable = "management.project_roles"
)
+type ProjectRole struct {
+ handler
+ projectEvents *proj_event.ProjectEventstore
+ subscription *eventstore.Subscription
+}
+
+func newProjectRole(
+ handler handler,
+ projectEvents *proj_event.ProjectEventstore,
+) *ProjectRole {
+ h := &ProjectRole{
+ handler: handler,
+ projectEvents: projectEvents,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (m *ProjectRole) subscribe() {
+ m.subscription = m.es.Subscribe(m.AggregateTypes()...)
+ go func() {
+ for event := range m.subscription.Events {
+ query.ReduceEvent(m, event)
+ }
+ }()
+}
+
func (p *ProjectRole) ViewModel() string {
return projectRoleTable
}
+func (_ *ProjectRole) AggregateTypes() []models.AggregateType {
+ return []models.AggregateType{es_model.ProjectAggregate}
+}
+
+func (p *ProjectRole) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := p.view.GetLatestProjectRoleSequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (p *ProjectRole) EventQuery() (*models.SearchQuery, error) {
- sequence, err := p.view.GetLatestProjectRoleSequence()
+ sequence, err := p.view.GetLatestProjectRoleSequence("")
if err != nil {
return nil, err
}
@@ -52,16 +90,16 @@ func (p *ProjectRole) Reduce(event *models.Event) (err error) {
if err != nil {
return err
}
- return p.view.DeleteProjectRole(event.AggregateID, event.ResourceOwner, role.Key, event.Sequence, event.CreationDate)
+ return p.view.DeleteProjectRole(event.AggregateID, event.ResourceOwner, role.Key, event)
case es_model.ProjectRemoved:
return p.view.DeleteProjectRolesByProjectID(event.AggregateID)
default:
- return p.view.ProcessedProjectRoleSequence(event.Sequence, event.CreationDate)
+ return p.view.ProcessedProjectRoleSequence(event)
}
if err != nil {
return err
}
- return p.view.PutProjectRole(role, event.CreationDate)
+ return p.view.PutProjectRole(role, event)
}
func (p *ProjectRole) OnError(event *models.Event, err error) error {
diff --git a/internal/management/repository/eventsourcing/handler/user.go b/internal/management/repository/eventsourcing/handler/user.go
index 0721e0fcd3..bf415d1602 100644
--- a/internal/management/repository/eventsourcing/handler/user.go
+++ b/internal/management/repository/eventsourcing/handler/user.go
@@ -2,14 +2,14 @@ package handler
import (
"context"
- iam_es "github.com/caos/zitadel/internal/iam/repository/eventsourcing"
"github.com/caos/logging"
-
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
+ iam_es "github.com/caos/zitadel/internal/iam/repository/eventsourcing"
org_model "github.com/caos/zitadel/internal/org/model"
org_events "github.com/caos/zitadel/internal/org/repository/eventsourcing"
org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
@@ -17,29 +17,68 @@ import (
view_model "github.com/caos/zitadel/internal/user/repository/view/model"
)
-type User struct {
- handler
- eventstore eventstore.Eventstore
- orgEvents *org_events.OrgEventstore
- iamEvents *iam_es.IAMEventstore
- iamID string
-}
-
const (
userTable = "management.users"
)
+type User struct {
+ handler
+ orgEvents *org_events.OrgEventstore
+ iamEvents *iam_es.IAMEventstore
+ iamID string
+ subscription *eventstore.Subscription
+}
+
+func newUser(
+ handler handler,
+ orgEvents *org_events.OrgEventstore,
+ iamEvents *iam_es.IAMEventstore,
+ iamID string,
+) *User {
+ h := &User{
+ handler: handler,
+ orgEvents: orgEvents,
+ iamEvents: iamEvents,
+ iamID: iamID,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (m *User) subscribe() {
+ m.subscription = m.es.Subscribe(m.AggregateTypes()...)
+ go func() {
+ for event := range m.subscription.Events {
+ query.ReduceEvent(m, event)
+ }
+ }()
+}
+
func (u *User) ViewModel() string {
return userTable
}
+func (_ *User) AggregateTypes() []es_models.AggregateType {
+ return []es_models.AggregateType{es_model.UserAggregate, org_es_model.OrgAggregate}
+}
+
+func (u *User) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := u.view.GetLatestUserSequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (u *User) EventQuery() (*models.SearchQuery, error) {
- sequence, err := u.view.GetLatestUserSequence()
+ sequence, err := u.view.GetLatestUserSequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(es_model.UserAggregate, org_es_model.OrgAggregate).
+ AggregateTypeFilter(u.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
@@ -115,14 +154,14 @@ func (u *User) ProcessUser(event *models.Event) (err error) {
}
err = u.fillLoginNames(user)
case es_model.UserRemoved:
- return u.view.DeleteUser(event.AggregateID, event.Sequence, event.CreationDate)
+ return u.view.DeleteUser(event.AggregateID, event)
default:
- return u.view.ProcessedUserSequence(event.Sequence, event.CreationDate)
+ return u.view.ProcessedUserSequence(event)
}
if err != nil {
return err
}
- return u.view.PutUser(user, user.Sequence, event.CreationDate)
+ return u.view.PutUser(user, event)
}
func (u *User) ProcessOrg(event *models.Event) (err error) {
@@ -136,7 +175,7 @@ func (u *User) ProcessOrg(event *models.Event) (err error) {
case org_es_model.OrgDomainPrimarySet:
return u.fillPreferredLoginNamesOnOrgUsers(event)
default:
- return u.view.ProcessedUserSequence(event.Sequence, event.CreationDate)
+ return u.view.ProcessedUserSequence(event)
}
}
@@ -159,7 +198,7 @@ func (u *User) fillLoginNamesOnOrgUsers(event *models.Event) error {
for _, user := range users {
user.SetLoginNames(policy, org.Domains)
}
- return u.view.PutUsers(users, event.Sequence, event.CreationDate)
+ return u.view.PutUsers(users, event)
}
func (u *User) fillPreferredLoginNamesOnOrgUsers(event *models.Event) error {
@@ -175,7 +214,7 @@ func (u *User) fillPreferredLoginNamesOnOrgUsers(event *models.Event) error {
}
}
if !policy.UserLoginMustBeDomain {
- return nil
+ return u.view.ProcessedUserSequence(event)
}
users, err := u.view.UsersByOrgID(event.AggregateID)
if err != nil {
@@ -184,7 +223,7 @@ func (u *User) fillPreferredLoginNamesOnOrgUsers(event *models.Event) error {
for _, user := range users {
user.PreferredLoginName = user.GenerateLoginName(org.GetPrimaryDomain().Domain, policy.UserLoginMustBeDomain)
}
- return u.view.PutUsers(users, event.Sequence, event.CreationDate)
+ return u.view.PutUsers(users, event)
}
func (u *User) fillLoginNames(user *view_model.UserView) (err error) {
diff --git a/internal/management/repository/eventsourcing/handler/user_external_idps.go b/internal/management/repository/eventsourcing/handler/user_external_idps.go
index de57a8f0f2..059a15c9bd 100644
--- a/internal/management/repository/eventsourcing/handler/user_external_idps.go
+++ b/internal/management/repository/eventsourcing/handler/user_external_idps.go
@@ -2,21 +2,27 @@ package handler
import (
"context"
+
"github.com/caos/logging"
"github.com/caos/zitadel/internal/config/systemdefaults"
caos_errs "github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore"
+ "github.com/caos/zitadel/internal/eventstore/models"
+ es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
+ "github.com/caos/zitadel/internal/eventstore/spooler"
+ iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/iam/repository/eventsourcing"
+ iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
iam_view_model "github.com/caos/zitadel/internal/iam/repository/view/model"
org_es "github.com/caos/zitadel/internal/org/repository/eventsourcing"
org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
"github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
usr_view_model "github.com/caos/zitadel/internal/user/repository/view/model"
+)
- "github.com/caos/zitadel/internal/eventstore/models"
- es_models "github.com/caos/zitadel/internal/eventstore/models"
- "github.com/caos/zitadel/internal/eventstore/spooler"
- iam_model "github.com/caos/zitadel/internal/iam/model"
- iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
+const (
+ externalIDPTable = "management.user_external_idps"
)
type ExternalIDP struct {
@@ -24,27 +30,63 @@ type ExternalIDP struct {
systemDefaults systemdefaults.SystemDefaults
iamEvents *eventsourcing.IAMEventstore
orgEvents *org_es.OrgEventstore
+ subscription *eventstore.Subscription
}
-const (
- externalIDPTable = "management.user_external_idps"
-)
+func newExternalIDP(
+ handler handler,
+ systemDefaults systemdefaults.SystemDefaults,
+ iamEvents *eventsourcing.IAMEventstore,
+ orgEvents *org_es.OrgEventstore,
+) *ExternalIDP {
+ h := &ExternalIDP{
+ handler: handler,
+ systemDefaults: systemDefaults,
+ iamEvents: iamEvents,
+ orgEvents: orgEvents,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (m *ExternalIDP) subscribe() {
+ m.subscription = m.es.Subscribe(m.AggregateTypes()...)
+ go func() {
+ for event := range m.subscription.Events {
+ query.ReduceEvent(m, event)
+ }
+ }()
+}
func (i *ExternalIDP) ViewModel() string {
return externalIDPTable
}
-func (i *ExternalIDP) EventQuery() (*models.SearchQuery, error) {
- sequence, err := i.view.GetLatestExternalIDPSequence()
+func (_ *ExternalIDP) AggregateTypes() []es_models.AggregateType {
+ return []es_models.AggregateType{model.UserAggregate, iam_es_model.IAMAggregate, org_es_model.OrgAggregate}
+}
+
+func (i *ExternalIDP) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := i.view.GetLatestExternalIDPSequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
+func (i *ExternalIDP) EventQuery() (*es_models.SearchQuery, error) {
+ sequence, err := i.view.GetLatestExternalIDPSequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(model.UserAggregate, iam_es_model.IAMAggregate, org_es_model.OrgAggregate).
+ AggregateTypeFilter(i.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
-func (i *ExternalIDP) Reduce(event *models.Event) (err error) {
+func (i *ExternalIDP) Reduce(event *es_models.Event) (err error) {
switch event.AggregateType {
case model.UserAggregate:
err = i.processUser(event)
@@ -54,7 +96,7 @@ func (i *ExternalIDP) Reduce(event *models.Event) (err error) {
return err
}
-func (i *ExternalIDP) processUser(event *models.Event) (err error) {
+func (i *ExternalIDP) processUser(event *es_models.Event) (err error) {
externalIDP := new(usr_view_model.ExternalIDPView)
switch event.Type {
case model.HumanExternalIDPAdded:
@@ -68,19 +110,19 @@ func (i *ExternalIDP) processUser(event *models.Event) (err error) {
if err != nil {
return err
}
- return i.view.DeleteExternalIDP(externalIDP.ExternalUserID, externalIDP.IDPConfigID, event.Sequence, event.CreationDate)
+ return i.view.DeleteExternalIDP(externalIDP.ExternalUserID, externalIDP.IDPConfigID, event)
case model.UserRemoved:
- return i.view.DeleteExternalIDPsByUserID(event.AggregateID, event.Sequence, event.CreationDate)
+ return i.view.DeleteExternalIDPsByUserID(event.AggregateID, event)
default:
- return i.view.ProcessedExternalIDPSequence(event.Sequence, event.CreationDate)
+ return i.view.ProcessedExternalIDPSequence(event)
}
if err != nil {
return err
}
- return i.view.PutExternalIDP(externalIDP, externalIDP.Sequence, event.CreationDate)
+ return i.view.PutExternalIDP(externalIDP, event)
}
-func (i *ExternalIDP) processIdpConfig(event *models.Event) (err error) {
+func (i *ExternalIDP) processIdpConfig(event *es_models.Event) (err error) {
switch event.Type {
case iam_es_model.IDPConfigChanged, org_es_model.IDPConfigChanged:
configView := new(iam_view_model.IDPConfigView)
@@ -105,9 +147,9 @@ func (i *ExternalIDP) processIdpConfig(event *models.Event) (err error) {
for _, provider := range exterinalIDPs {
i.fillConfigData(provider, config)
}
- return i.view.PutExternalIDPs(event.Sequence, event.CreationDate, exterinalIDPs...)
+ return i.view.PutExternalIDPs(event, exterinalIDPs...)
default:
- return i.view.ProcessedExternalIDPSequence(event.Sequence, event.CreationDate)
+ return i.view.ProcessedExternalIDPSequence(event)
}
return nil
}
@@ -128,7 +170,7 @@ func (i *ExternalIDP) fillConfigData(externalIDP *usr_view_model.ExternalIDPView
externalIDP.IDPName = config.Name
}
-func (i *ExternalIDP) OnError(event *models.Event, err error) error {
+func (i *ExternalIDP) OnError(event *es_models.Event, err error) error {
logging.LogWithFields("SPOOL-4Rsu8", "id", event.AggregateID).WithError(err).Warn("something went wrong in idp provider handler")
return spooler.HandleError(event, err, i.view.GetLatestExternalIDPFailedEvent, i.view.ProcessedExternalIDPFailedEvent, i.view.ProcessedExternalIDPSequence, i.errorCountUntilSkip)
}
diff --git a/internal/management/repository/eventsourcing/handler/user_grant.go b/internal/management/repository/eventsourcing/handler/user_grant.go
index 0ffe6955ac..a4f0869783 100644
--- a/internal/management/repository/eventsourcing/handler/user_grant.go
+++ b/internal/management/repository/eventsourcing/handler/user_grant.go
@@ -3,7 +3,12 @@ package handler
import (
"context"
+ "github.com/caos/logging"
+ "github.com/caos/zitadel/internal/eventstore"
+ "github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
+ "github.com/caos/zitadel/internal/eventstore/spooler"
org_model "github.com/caos/zitadel/internal/org/model"
org_events "github.com/caos/zitadel/internal/org/repository/eventsourcing"
proj_model "github.com/caos/zitadel/internal/project/model"
@@ -13,42 +18,75 @@ import (
usr_events "github.com/caos/zitadel/internal/user/repository/eventsourcing"
usr_es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
grant_es_model "github.com/caos/zitadel/internal/usergrant/repository/eventsourcing/model"
-
- "github.com/caos/logging"
-
- "github.com/caos/zitadel/internal/eventstore"
- "github.com/caos/zitadel/internal/eventstore/models"
- "github.com/caos/zitadel/internal/eventstore/spooler"
view_model "github.com/caos/zitadel/internal/usergrant/repository/view/model"
)
-type UserGrant struct {
- handler
- eventstore eventstore.Eventstore
- projectEvents *proj_event.ProjectEventstore
- userEvents *usr_events.UserEventstore
- orgEvents *org_events.OrgEventstore
-}
-
const (
userGrantTable = "management.user_grants"
)
+type UserGrant struct {
+ handler
+ projectEvents *proj_event.ProjectEventstore
+ userEvents *usr_events.UserEventstore
+ orgEvents *org_events.OrgEventstore
+ subscription *eventstore.Subscription
+}
+
+func newUserGrant(
+ handler handler,
+ projectEvents *proj_event.ProjectEventstore,
+ userEvents *usr_events.UserEventstore,
+ orgEvents *org_events.OrgEventstore,
+) *UserGrant {
+ h := &UserGrant{
+ handler: handler,
+ projectEvents: projectEvents,
+ userEvents: userEvents,
+ orgEvents: orgEvents,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (m *UserGrant) subscribe() {
+ m.subscription = m.es.Subscribe(m.AggregateTypes()...)
+ go func() {
+ for event := range m.subscription.Events {
+ query.ReduceEvent(m, event)
+ }
+ }()
+}
+
func (u *UserGrant) ViewModel() string {
return userGrantTable
}
-func (u *UserGrant) EventQuery() (*models.SearchQuery, error) {
- sequence, err := u.view.GetLatestUserGrantSequence()
+func (_ *UserGrant) AggregateTypes() []es_models.AggregateType {
+ return []es_models.AggregateType{grant_es_model.UserGrantAggregate, usr_es_model.UserAggregate, proj_es_model.ProjectAggregate}
+}
+
+func (u *UserGrant) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := u.view.GetLatestUserGrantSequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
+func (u *UserGrant) EventQuery() (*es_models.SearchQuery, error) {
+ sequence, err := u.view.GetLatestUserGrantSequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(grant_es_model.UserGrantAggregate, usr_es_model.UserAggregate, proj_es_model.ProjectAggregate).
+ AggregateTypeFilter(u.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
-func (u *UserGrant) Reduce(event *models.Event) (err error) {
+func (u *UserGrant) Reduce(event *es_models.Event) (err error) {
switch event.AggregateType {
case grant_es_model.UserGrantAggregate:
err = u.processUserGrant(event)
@@ -60,7 +98,7 @@ func (u *UserGrant) Reduce(event *models.Event) (err error) {
return err
}
-func (u *UserGrant) processUserGrant(event *models.Event) (err error) {
+func (u *UserGrant) processUserGrant(event *es_models.Event) (err error) {
grant := new(view_model.UserGrantView)
switch event.Type {
case grant_es_model.UserGrantAdded:
@@ -79,17 +117,17 @@ func (u *UserGrant) processUserGrant(event *models.Event) (err error) {
}
err = grant.AppendEvent(event)
case grant_es_model.UserGrantRemoved, grant_es_model.UserGrantCascadeRemoved:
- return u.view.DeleteUserGrant(event.AggregateID, event.Sequence, event.CreationDate)
+ return u.view.DeleteUserGrant(event.AggregateID, event)
default:
- return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
+ return u.view.ProcessedUserGrantSequence(event)
}
if err != nil {
return err
}
- return u.view.PutUserGrant(grant, grant.Sequence, event.CreationDate)
+ return u.view.PutUserGrant(grant, event)
}
-func (u *UserGrant) processUser(event *models.Event) (err error) {
+func (u *UserGrant) processUser(event *es_models.Event) (err error) {
switch event.Type {
case usr_es_model.UserProfileChanged,
usr_es_model.UserEmailChanged,
@@ -101,7 +139,7 @@ func (u *UserGrant) processUser(event *models.Event) (err error) {
return err
}
if len(grants) == 0 {
- return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
+ return u.view.ProcessedUserGrantSequence(event)
}
user, err := u.userEvents.UserByID(context.Background(), event.AggregateID)
if err != nil {
@@ -110,14 +148,13 @@ func (u *UserGrant) processUser(event *models.Event) (err error) {
for _, grant := range grants {
u.fillUserData(grant, user)
}
- return u.view.PutUserGrants(grants, event.Sequence, event.CreationDate)
+ return u.view.PutUserGrants(grants, event)
default:
- return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
+ return u.view.ProcessedUserGrantSequence(event)
}
- return nil
}
-func (u *UserGrant) processProject(event *models.Event) (err error) {
+func (u *UserGrant) processProject(event *es_models.Event) (err error) {
switch event.Type {
case proj_es_model.ProjectChanged:
grants, err := u.view.UserGrantsByProjectID(event.AggregateID)
@@ -125,7 +162,7 @@ func (u *UserGrant) processProject(event *models.Event) (err error) {
return err
}
if len(grants) == 0 {
- return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
+ return u.view.ProcessedUserGrantSequence(event)
}
project, err := u.projectEvents.ProjectByID(context.Background(), event.AggregateID)
if err != nil {
@@ -134,11 +171,10 @@ func (u *UserGrant) processProject(event *models.Event) (err error) {
for _, grant := range grants {
u.fillProjectData(grant, project)
}
- return u.view.PutUserGrants(grants, event.Sequence, event.CreationDate)
+ return u.view.PutUserGrants(grants, event)
default:
- return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
+ return u.view.ProcessedUserGrantSequence(event)
}
- return nil
}
func (u *UserGrant) fillData(grant *view_model.UserGrantView, resourceOwner string) (err error) {
@@ -189,7 +225,7 @@ func (u *UserGrant) fillOrgData(grant *view_model.UserGrantView, org *org_model.
}
}
-func (u *UserGrant) OnError(event *models.Event, err error) error {
+func (u *UserGrant) OnError(event *es_models.Event, err error) error {
logging.LogWithFields("SPOOL-8is4s", "id", event.AggregateID).WithError(err).Warn("something went wrong in user handler")
return spooler.HandleError(event, err, u.view.GetLatestUserGrantFailedEvent, u.view.ProcessedUserGrantFailedEvent, u.view.ProcessedUserGrantSequence, u.errorCountUntilSkip)
}
diff --git a/internal/management/repository/eventsourcing/handler/user_membership.go b/internal/management/repository/eventsourcing/handler/user_membership.go
index 8537905d47..9358acc4e2 100644
--- a/internal/management/repository/eventsourcing/handler/user_membership.go
+++ b/internal/management/repository/eventsourcing/handler/user_membership.go
@@ -2,51 +2,90 @@ package handler
import (
"context"
+
+ "github.com/caos/logging"
+ "github.com/caos/zitadel/internal/eventstore"
+ "github.com/caos/zitadel/internal/eventstore/models"
+ es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
+ "github.com/caos/zitadel/internal/eventstore/spooler"
iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
org_model "github.com/caos/zitadel/internal/org/model"
org_event "github.com/caos/zitadel/internal/org/repository/eventsourcing"
+ org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing"
proj_es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model"
- "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
-
- "github.com/caos/logging"
-
- "github.com/caos/zitadel/internal/eventstore/models"
- es_models "github.com/caos/zitadel/internal/eventstore/models"
- "github.com/caos/zitadel/internal/eventstore/spooler"
- org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
usr_model "github.com/caos/zitadel/internal/user/model"
+ "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
usr_es_model "github.com/caos/zitadel/internal/user/repository/view/model"
)
+const (
+ userMembershipTable = "management.user_memberships"
+)
+
type UserMembership struct {
handler
orgEvents *org_event.OrgEventstore
projectEvents *proj_event.ProjectEventstore
+ subscription *eventstore.Subscription
}
-const (
- userMembershipTable = "management.user_memberships"
-)
+func newUserMembership(
+ handler handler,
+ orgEvents *org_event.OrgEventstore,
+ projectEvents *proj_event.ProjectEventstore,
+) *UserMembership {
+ h := &UserMembership{
+ handler: handler,
+ orgEvents: orgEvents,
+ projectEvents: projectEvents,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (m *UserMembership) subscribe() {
+ m.subscription = m.es.Subscribe(m.AggregateTypes()...)
+ go func() {
+ for event := range m.subscription.Events {
+ query.ReduceEvent(m, event)
+ }
+ }()
+}
func (m *UserMembership) ViewModel() string {
return userMembershipTable
}
-func (m *UserMembership) EventQuery() (*models.SearchQuery, error) {
- sequence, err := m.view.GetLatestUserMembershipSequence()
+func (_ *UserMembership) AggregateTypes() []es_models.AggregateType {
+ return []es_models.AggregateType{iam_es_model.IAMAggregate, org_es_model.OrgAggregate, proj_es_model.ProjectAggregate, model.UserAggregate}
+}
+
+func (u *UserMembership) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := u.view.GetLatestUserMembershipSequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
+func (m *UserMembership) EventQuery() (*es_models.SearchQuery, error) {
+ sequence, err := m.view.GetLatestUserMembershipSequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(iam_es_model.IAMAggregate, org_es_model.OrgAggregate, proj_es_model.ProjectAggregate, model.UserAggregate).
+ AggregateTypeFilter(m.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
-func (m *UserMembership) Reduce(event *models.Event) (err error) {
+func (m *UserMembership) Reduce(event *es_models.Event) (err error) {
switch event.AggregateType {
case iam_es_model.IAMAggregate:
- err = m.processIam(event)
+ err = m.processIAM(event)
case org_es_model.OrgAggregate:
err = m.processOrg(event)
case proj_es_model.ProjectAggregate:
@@ -57,7 +96,7 @@ func (m *UserMembership) Reduce(event *models.Event) (err error) {
return err
}
-func (m *UserMembership) processIam(event *models.Event) (err error) {
+func (m *UserMembership) processIAM(event *es_models.Event) (err error) {
member := new(usr_es_model.UserMembershipView)
err = member.AppendEvent(event)
if err != nil {
@@ -73,21 +112,21 @@ func (m *UserMembership) processIam(event *models.Event) (err error) {
}
err = member.AppendEvent(event)
case iam_es_model.IAMMemberRemoved:
- return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeIam, event.Sequence, event.CreationDate)
+ return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeIam, event)
default:
- return m.view.ProcessedUserMembershipSequence(event.Sequence, event.CreationDate)
+ return m.view.ProcessedUserMembershipSequence(event)
}
if err != nil {
return err
}
- return m.view.PutUserMembership(member, event.Sequence, event.CreationDate)
+ return m.view.PutUserMembership(member, event)
}
func (m *UserMembership) fillIamDisplayName(member *usr_es_model.UserMembershipView) {
member.DisplayName = member.AggregateID
}
-func (m *UserMembership) processOrg(event *models.Event) (err error) {
+func (m *UserMembership) processOrg(event *es_models.Event) (err error) {
member := new(usr_es_model.UserMembershipView)
err = member.AppendEvent(event)
if err != nil {
@@ -103,16 +142,16 @@ func (m *UserMembership) processOrg(event *models.Event) (err error) {
}
err = member.AppendEvent(event)
case org_es_model.OrgMemberRemoved:
- return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeOrganisation, event.Sequence, event.CreationDate)
+ return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeOrganisation, event)
case org_es_model.OrgChanged:
return m.updateOrgDisplayName(event)
default:
- return m.view.ProcessedUserMembershipSequence(event.Sequence, event.CreationDate)
+ return m.view.ProcessedUserMembershipSequence(event)
}
if err != nil {
return err
}
- return m.view.PutUserMembership(member, event.Sequence, event.CreationDate)
+ return m.view.PutUserMembership(member, event)
}
func (m *UserMembership) fillOrgDisplayName(member *usr_es_model.UserMembershipView) (err error) {
@@ -124,7 +163,7 @@ func (m *UserMembership) fillOrgDisplayName(member *usr_es_model.UserMembershipV
return nil
}
-func (m *UserMembership) updateOrgDisplayName(event *models.Event) error {
+func (m *UserMembership) updateOrgDisplayName(event *es_models.Event) error {
org, err := m.orgEvents.OrgByID(context.Background(), org_model.NewOrg(event.AggregateID))
if err != nil {
return err
@@ -137,10 +176,10 @@ func (m *UserMembership) updateOrgDisplayName(event *models.Event) error {
for _, membership := range memberships {
membership.DisplayName = org.Name
}
- return m.view.BulkPutUserMemberships(memberships, event.Sequence, event.CreationDate)
+ return m.view.BulkPutUserMemberships(memberships, event)
}
-func (m *UserMembership) processProject(event *models.Event) (err error) {
+func (m *UserMembership) processProject(event *es_models.Event) (err error) {
member := new(usr_es_model.UserMembershipView)
err = member.AppendEvent(event)
if err != nil {
@@ -156,7 +195,7 @@ func (m *UserMembership) processProject(event *models.Event) (err error) {
}
err = member.AppendEvent(event)
case proj_es_model.ProjectMemberRemoved:
- return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeProject, event.Sequence, event.CreationDate)
+ return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeProject, event)
case proj_es_model.ProjectGrantMemberChanged:
member, err = m.view.UserMembershipByIDs(member.UserID, event.AggregateID, member.ObjectID, usr_model.MemberTypeProjectGrant)
if err != nil {
@@ -164,20 +203,20 @@ func (m *UserMembership) processProject(event *models.Event) (err error) {
}
err = member.AppendEvent(event)
case proj_es_model.ProjectGrantMemberRemoved:
- return m.view.DeleteUserMembership(member.UserID, event.AggregateID, member.ObjectID, usr_model.MemberTypeProjectGrant, event.Sequence, event.CreationDate)
+ return m.view.DeleteUserMembership(member.UserID, event.AggregateID, member.ObjectID, usr_model.MemberTypeProjectGrant, event)
case proj_es_model.ProjectChanged:
return m.updateProjectDisplayName(event)
case proj_es_model.ProjectRemoved:
- return m.view.DeleteUserMembershipsByAggregateID(event.AggregateID, event.Sequence, event.CreationDate)
+ return m.view.DeleteUserMembershipsByAggregateID(event.AggregateID, event)
case proj_es_model.ProjectGrantRemoved:
- return m.view.DeleteUserMembershipsByAggregateIDAndObjectID(event.AggregateID, member.ObjectID, event.Sequence, event.CreationDate)
+ return m.view.DeleteUserMembershipsByAggregateIDAndObjectID(event.AggregateID, member.ObjectID, event)
default:
- return m.view.ProcessedUserMembershipSequence(event.Sequence, event.CreationDate)
+ return m.view.ProcessedUserMembershipSequence(event)
}
if err != nil {
return err
}
- return m.view.PutUserMembership(member, event.Sequence, event.CreationDate)
+ return m.view.PutUserMembership(member, event)
}
func (m *UserMembership) fillProjectDisplayName(member *usr_es_model.UserMembershipView) (err error) {
@@ -189,7 +228,7 @@ func (m *UserMembership) fillProjectDisplayName(member *usr_es_model.UserMembers
return nil
}
-func (m *UserMembership) updateProjectDisplayName(event *models.Event) error {
+func (m *UserMembership) updateProjectDisplayName(event *es_models.Event) error {
project, err := m.projectEvents.ProjectByID(context.Background(), event.AggregateID)
if err != nil {
return err
@@ -202,19 +241,19 @@ func (m *UserMembership) updateProjectDisplayName(event *models.Event) error {
for _, membership := range memberships {
membership.DisplayName = project.Name
}
- return m.view.BulkPutUserMemberships(memberships, event.Sequence, event.CreationDate)
+ return m.view.BulkPutUserMemberships(memberships, event)
}
-func (m *UserMembership) processUser(event *models.Event) (err error) {
+func (m *UserMembership) processUser(event *es_models.Event) (err error) {
switch event.Type {
case model.UserRemoved:
- return m.view.DeleteUserMembershipsByUserID(event.AggregateID, event.Sequence, event.CreationDate)
+ return m.view.DeleteUserMembershipsByUserID(event.AggregateID, event)
default:
- return m.view.ProcessedUserMembershipSequence(event.Sequence, event.CreationDate)
+ return m.view.ProcessedUserMembershipSequence(event)
}
}
-func (m *UserMembership) OnError(event *models.Event, err error) error {
+func (m *UserMembership) OnError(event *es_models.Event, err error) error {
logging.LogWithFields("SPOOL-Fwer2", "id", event.AggregateID).WithError(err).Warn("something went wrong in user membership handler")
return spooler.HandleError(event, err, m.view.GetLatestUserMembershipFailedEvent, m.view.ProcessedUserMembershipFailedEvent, m.view.ProcessedUserMembershipSequence, m.errorCountUntilSkip)
}
diff --git a/internal/management/repository/eventsourcing/view/application.go b/internal/management/repository/eventsourcing/view/application.go
index 46672fc74a..c9b4a6fbd0 100644
--- a/internal/management/repository/eventsourcing/view/application.go
+++ b/internal/management/repository/eventsourcing/view/application.go
@@ -1,11 +1,12 @@
package view
import (
+ "github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
proj_model "github.com/caos/zitadel/internal/project/model"
"github.com/caos/zitadel/internal/project/repository/view"
"github.com/caos/zitadel/internal/project/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -24,40 +25,40 @@ func (v *View) SearchApplications(request *proj_model.ApplicationSearchRequest)
return view.SearchApplications(v.Db, applicationTable, request)
}
-func (v *View) PutApplication(app *model.ApplicationView, eventTimestamp time.Time) error {
+func (v *View) PutApplication(app *model.ApplicationView, event *models.Event) error {
err := view.PutApplication(v.Db, applicationTable, app)
- if err != nil {
+ if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedApplicationSequence(app.Sequence, eventTimestamp)
+ return v.ProcessedApplicationSequence(event)
}
-func (v *View) PutApplications(apps []*model.ApplicationView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutApplications(apps []*model.ApplicationView, event *models.Event) error {
err := view.PutApplications(v.Db, applicationTable, apps...)
if err != nil {
return err
}
- return v.ProcessedApplicationSequence(sequence, eventTimestamp)
+ return v.ProcessedApplicationSequence(event)
}
-func (v *View) DeleteApplication(appID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteApplication(appID string, event *models.Event) error {
err := view.DeleteApplication(v.Db, applicationTable, appID)
if err != nil {
- return nil
+ return err
}
- return v.ProcessedApplicationSequence(eventSequence, eventTimestamp)
+ return v.ProcessedApplicationSequence(event)
}
func (v *View) DeleteApplicationsByProjectID(projectID string) error {
return view.DeleteApplicationsByProjectID(v.Db, applicationTable, projectID)
}
-func (v *View) GetLatestApplicationSequence() (*repository.CurrentSequence, error) {
- return v.latestSequence(applicationTable)
+func (v *View) GetLatestApplicationSequence(aggregateType string) (*repository.CurrentSequence, error) {
+ return v.latestSequence(applicationTable, aggregateType)
}
-func (v *View) ProcessedApplicationSequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(applicationTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedApplicationSequence(event *models.Event) error {
+ return v.saveCurrentSequence(applicationTable, event)
}
func (v *View) UpdateApplicationSpoolerRunTimestamp() error {
diff --git a/internal/management/repository/eventsourcing/view/external_idps.go b/internal/management/repository/eventsourcing/view/external_idps.go
index c2944c7a5f..0b8eb3648e 100644
--- a/internal/management/repository/eventsourcing/view/external_idps.go
+++ b/internal/management/repository/eventsourcing/view/external_idps.go
@@ -2,11 +2,11 @@ package view
import (
"github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
usr_model "github.com/caos/zitadel/internal/user/model"
"github.com/caos/zitadel/internal/user/repository/view"
"github.com/caos/zitadel/internal/user/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -33,43 +33,43 @@ func (v *View) SearchExternalIDPs(request *usr_model.ExternalIDPSearchRequest) (
return view.SearchExternalIDPs(v.Db, externalIDPTable, request)
}
-func (v *View) PutExternalIDP(externalIDP *model.ExternalIDPView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutExternalIDP(externalIDP *model.ExternalIDPView, event *models.Event) error {
err := view.PutExternalIDP(v.Db, externalIDPTable, externalIDP)
if err != nil {
return err
}
- return v.ProcessedExternalIDPSequence(sequence, eventTimestamp)
+ return v.ProcessedExternalIDPSequence(event)
}
-func (v *View) PutExternalIDPs(sequence uint64, eventTimestamp time.Time, externalIDPs ...*model.ExternalIDPView) error {
+func (v *View) PutExternalIDPs(event *models.Event, externalIDPs ...*model.ExternalIDPView) error {
err := view.PutExternalIDPs(v.Db, externalIDPTable, externalIDPs...)
if err != nil {
return err
}
- return v.ProcessedExternalIDPSequence(sequence, eventTimestamp)
+ return v.ProcessedExternalIDPSequence(event)
}
-func (v *View) DeleteExternalIDP(externalUserID, idpConfigID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteExternalIDP(externalUserID, idpConfigID string, event *models.Event) error {
err := view.DeleteExternalIDP(v.Db, externalIDPTable, externalUserID, idpConfigID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedExternalIDPSequence(eventSequence, eventTimestamp)
+ return v.ProcessedExternalIDPSequence(event)
}
-func (v *View) DeleteExternalIDPsByUserID(userID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteExternalIDPsByUserID(userID string, event *models.Event) error {
err := view.DeleteExternalIDPsByUserID(v.Db, externalIDPTable, userID)
if err != nil {
return err
}
- return v.ProcessedExternalIDPSequence(eventSequence, eventTimestamp)
+ return v.ProcessedExternalIDPSequence(event)
}
-func (v *View) GetLatestExternalIDPSequence() (*global_view.CurrentSequence, error) {
- return v.latestSequence(externalIDPTable)
+func (v *View) GetLatestExternalIDPSequence(aggregateType string) (*global_view.CurrentSequence, error) {
+ return v.latestSequence(externalIDPTable, aggregateType)
}
-func (v *View) ProcessedExternalIDPSequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(externalIDPTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedExternalIDPSequence(event *models.Event) error {
+ return v.saveCurrentSequence(externalIDPTable, event)
}
func (v *View) UpdateExternalIDPSpoolerRunTimestamp() error {
diff --git a/internal/management/repository/eventsourcing/view/idp_configs.go b/internal/management/repository/eventsourcing/view/idp_configs.go
index a9dfde45da..5770f36b38 100644
--- a/internal/management/repository/eventsourcing/view/idp_configs.go
+++ b/internal/management/repository/eventsourcing/view/idp_configs.go
@@ -2,11 +2,11 @@ package view
import (
"github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/iam/repository/view"
iam_es_model "github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -21,28 +21,28 @@ func (v *View) SearchIDPConfigs(request *iam_model.IDPConfigSearchRequest) ([]*i
return view.SearchIDPs(v.Db, idpConfigTable, request)
}
-func (v *View) PutIDPConfig(idp *iam_es_model.IDPConfigView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutIDPConfig(idp *iam_es_model.IDPConfigView, event *models.Event) error {
err := view.PutIDP(v.Db, idpConfigTable, idp)
if err != nil {
return err
}
- return v.ProcessedIDPConfigSequence(sequence, eventTimestamp)
+ return v.ProcessedIDPConfigSequence(event)
}
-func (v *View) DeleteIDPConfig(idpID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteIDPConfig(idpID string, event *models.Event) error {
err := view.DeleteIDP(v.Db, idpConfigTable, idpID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedIDPConfigSequence(eventSequence, eventTimestamp)
+ return v.ProcessedIDPConfigSequence(event)
}
-func (v *View) GetLatestIDPConfigSequence() (*global_view.CurrentSequence, error) {
- return v.latestSequence(idpConfigTable)
+func (v *View) GetLatestIDPConfigSequence(aggregateType string) (*global_view.CurrentSequence, error) {
+ return v.latestSequence(idpConfigTable, aggregateType)
}
-func (v *View) ProcessedIDPConfigSequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(idpConfigTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedIDPConfigSequence(event *models.Event) error {
+ return v.saveCurrentSequence(idpConfigTable, event)
}
func (v *View) UpdateIDPConfigSpoolerRunTimestamp() error {
diff --git a/internal/management/repository/eventsourcing/view/idp_providers.go b/internal/management/repository/eventsourcing/view/idp_providers.go
index 207feb621f..a293ec1637 100644
--- a/internal/management/repository/eventsourcing/view/idp_providers.go
+++ b/internal/management/repository/eventsourcing/view/idp_providers.go
@@ -2,11 +2,11 @@ package view
import (
"github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -25,44 +25,44 @@ func (v *View) SearchIDPProviders(request *iam_model.IDPProviderSearchRequest) (
return view.SearchIDPProviders(v.Db, idpProviderTable, request)
}
-func (v *View) PutIDPProvider(provider *model.IDPProviderView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutIDPProvider(provider *model.IDPProviderView, event *models.Event) error {
err := view.PutIDPProvider(v.Db, idpProviderTable, provider)
if err != nil {
return err
}
- return v.ProcessedIDPProviderSequence(sequence, eventTimestamp)
+ return v.ProcessedIDPProviderSequence(event)
}
-func (v *View) PutIDPProviders(sequence uint64, eventTimestamp time.Time, providers ...*model.IDPProviderView) error {
+func (v *View) PutIDPProviders(event *models.Event, providers ...*model.IDPProviderView) error {
err := view.PutIDPProviders(v.Db, idpProviderTable, providers...)
if err != nil {
return err
}
- return v.ProcessedIDPProviderSequence(sequence, eventTimestamp)
+ return v.ProcessedIDPProviderSequence(event)
}
-func (v *View) DeleteIDPProvider(aggregateID, idpConfigID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteIDPProvider(aggregateID, idpConfigID string, event *models.Event) error {
err := view.DeleteIDPProvider(v.Db, idpProviderTable, aggregateID, idpConfigID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedIDPProviderSequence(eventSequence, eventTimestamp)
+ return v.ProcessedIDPProviderSequence(event)
}
-func (v *View) DeleteIDPProvidersByAggregateID(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteIDPProvidersByAggregateID(aggregateID string, event *models.Event) error {
err := view.DeleteIDPProvidersByAggregateID(v.Db, idpProviderTable, aggregateID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedIDPProviderSequence(eventSequence, eventTimestamp)
+ return v.ProcessedIDPProviderSequence(event)
}
-func (v *View) GetLatestIDPProviderSequence() (*global_view.CurrentSequence, error) {
- return v.latestSequence(idpProviderTable)
+func (v *View) GetLatestIDPProviderSequence(aggregateType string) (*global_view.CurrentSequence, error) {
+ return v.latestSequence(idpProviderTable, aggregateType)
}
-func (v *View) ProcessedIDPProviderSequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(idpProviderTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedIDPProviderSequence(event *models.Event) error {
+ return v.saveCurrentSequence(idpProviderTable, event)
}
func (v *View) UpdateIDPProviderSpoolerRunTimestamp() error {
diff --git a/internal/management/repository/eventsourcing/view/label_policies.go b/internal/management/repository/eventsourcing/view/label_policies.go
index 27b234fc29..05bb9550a4 100644
--- a/internal/management/repository/eventsourcing/view/label_policies.go
+++ b/internal/management/repository/eventsourcing/view/label_policies.go
@@ -2,10 +2,10 @@ package view
import (
"github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -16,28 +16,28 @@ func (v *View) LabelPolicyByAggregateID(aggregateID string) (*model.LabelPolicyV
return view.GetLabelPolicyByAggregateID(v.Db, labelPolicyTable, aggregateID)
}
-func (v *View) PutLabelPolicy(policy *model.LabelPolicyView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutLabelPolicy(policy *model.LabelPolicyView, event *models.Event) error {
err := view.PutLabelPolicy(v.Db, labelPolicyTable, policy)
if err != nil {
return err
}
- return v.ProcessedLabelPolicySequence(sequence, eventTimestamp)
+ return v.ProcessedLabelPolicySequence(event)
}
-func (v *View) DeleteLabelPolicy(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteLabelPolicy(aggregateID string, event *models.Event) error {
err := view.DeleteLabelPolicy(v.Db, labelPolicyTable, aggregateID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedLabelPolicySequence(eventSequence, eventTimestamp)
+ return v.ProcessedLabelPolicySequence(event)
}
-func (v *View) GetLatestLabelPolicySequence() (*global_view.CurrentSequence, error) {
- return v.latestSequence(labelPolicyTable)
+func (v *View) GetLatestLabelPolicySequence(aggregateType string) (*global_view.CurrentSequence, error) {
+ return v.latestSequence(labelPolicyTable, aggregateType)
}
-func (v *View) ProcessedLabelPolicySequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(labelPolicyTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedLabelPolicySequence(event *models.Event) error {
+ return v.saveCurrentSequence(labelPolicyTable, event)
}
func (v *View) UpdateLabelPolicySpoolerRunTimestamp() error {
diff --git a/internal/management/repository/eventsourcing/view/login_policies.go b/internal/management/repository/eventsourcing/view/login_policies.go
index c37f4283d6..56e6e80f8f 100644
--- a/internal/management/repository/eventsourcing/view/login_policies.go
+++ b/internal/management/repository/eventsourcing/view/login_policies.go
@@ -2,10 +2,10 @@ package view
import (
"github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -16,28 +16,28 @@ func (v *View) LoginPolicyByAggregateID(aggregateID string) (*model.LoginPolicyV
return view.GetLoginPolicyByAggregateID(v.Db, loginPolicyTable, aggregateID)
}
-func (v *View) PutLoginPolicy(policy *model.LoginPolicyView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutLoginPolicy(policy *model.LoginPolicyView, event *models.Event) error {
err := view.PutLoginPolicy(v.Db, loginPolicyTable, policy)
if err != nil {
return err
}
- return v.ProcessedLoginPolicySequence(sequence, eventTimestamp)
+ return v.ProcessedLoginPolicySequence(event)
}
-func (v *View) DeleteLoginPolicy(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteLoginPolicy(aggregateID string, event *models.Event) error {
err := view.DeleteLoginPolicy(v.Db, loginPolicyTable, aggregateID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedLoginPolicySequence(eventSequence, eventTimestamp)
+ return v.ProcessedLoginPolicySequence(event)
}
-func (v *View) GetLatestLoginPolicySequence() (*global_view.CurrentSequence, error) {
- return v.latestSequence(loginPolicyTable)
+func (v *View) GetLatestLoginPolicySequence(aggregateType string) (*global_view.CurrentSequence, error) {
+ return v.latestSequence(loginPolicyTable, aggregateType)
}
-func (v *View) ProcessedLoginPolicySequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(loginPolicyTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedLoginPolicySequence(event *models.Event) error {
+ return v.saveCurrentSequence(loginPolicyTable, event)
}
func (v *View) UpdateLoginPolicySpoolerRunTimestamp() error {
diff --git a/internal/management/repository/eventsourcing/view/machine_keys.go b/internal/management/repository/eventsourcing/view/machine_keys.go
index b037137c82..c861cfd58c 100644
--- a/internal/management/repository/eventsourcing/view/machine_keys.go
+++ b/internal/management/repository/eventsourcing/view/machine_keys.go
@@ -1,11 +1,12 @@
package view
import (
+ "github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
usr_model "github.com/caos/zitadel/internal/user/model"
"github.com/caos/zitadel/internal/user/repository/view"
"github.com/caos/zitadel/internal/user/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -24,39 +25,36 @@ func (v *View) SearchMachineKeys(request *usr_model.MachineKeySearchRequest) ([]
return view.SearchMachineKeys(v.Db, machineKeyTable, request)
}
-func (v *View) PutMachineKey(org *model.MachineKeyView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutMachineKey(org *model.MachineKeyView, event *models.Event) error {
err := view.PutMachineKey(v.Db, machineKeyTable, org)
if err != nil {
return err
}
- if sequence != 0 {
- return v.ProcessedMachineKeySequence(sequence, eventTimestamp)
- }
- return nil
+ return v.ProcessedMachineKeySequence(event)
}
-func (v *View) DeleteMachineKey(keyID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteMachineKey(keyID string, event *models.Event) error {
err := view.DeleteMachineKey(v.Db, machineKeyTable, keyID)
- if err != nil {
- return nil
+ if err != nil && !errors.IsNotFound(err) {
+ return err
}
- return v.ProcessedMachineKeySequence(eventSequence, eventTimestamp)
+ return v.ProcessedMachineKeySequence(event)
}
-func (v *View) DeleteMachineKeysByUserID(userID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteMachineKeysByUserID(userID string, event *models.Event) error {
err := view.DeleteMachineKey(v.Db, machineKeyTable, userID)
- if err != nil {
- return nil
+ if err != nil && !errors.IsNotFound(err) {
+ return err
}
- return v.ProcessedMachineKeySequence(eventSequence, eventTimestamp)
+ return v.ProcessedMachineKeySequence(event)
}
-func (v *View) GetLatestMachineKeySequence() (*repository.CurrentSequence, error) {
- return v.latestSequence(machineKeyTable)
+func (v *View) GetLatestMachineKeySequence(aggregateType string) (*repository.CurrentSequence, error) {
+ return v.latestSequence(machineKeyTable, aggregateType)
}
-func (v *View) ProcessedMachineKeySequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(machineKeyTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedMachineKeySequence(event *models.Event) error {
+ return v.saveCurrentSequence(machineKeyTable, event)
}
func (v *View) UpdateMachineKeySpoolerRunTimestamp() error {
diff --git a/internal/management/repository/eventsourcing/view/org.go b/internal/management/repository/eventsourcing/view/org.go
index a5de5fdb46..3a53b92031 100644
--- a/internal/management/repository/eventsourcing/view/org.go
+++ b/internal/management/repository/eventsourcing/view/org.go
@@ -1,10 +1,10 @@
package view
import (
+ "github.com/caos/zitadel/internal/eventstore/models"
org_view "github.com/caos/zitadel/internal/org/repository/view"
"github.com/caos/zitadel/internal/org/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -15,12 +15,12 @@ func (v *View) OrgByID(orgID string) (*model.OrgView, error) {
return org_view.OrgByID(v.Db, orgTable, orgID)
}
-func (v *View) PutOrg(org *model.OrgView, eventTimestamp time.Time) error {
+func (v *View) PutOrg(org *model.OrgView, event *models.Event) error {
err := org_view.PutOrg(v.Db, orgTable, org)
if err != nil {
return err
}
- return v.ProcessedOrgSequence(org.Sequence, eventTimestamp)
+ return v.ProcessedOrgSequence(event)
}
func (v *View) GetLatestOrgFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
@@ -35,10 +35,10 @@ func (v *View) UpdateOrgSpoolerRunTimestamp() error {
return v.updateSpoolerRunSequence(orgTable)
}
-func (v *View) GetLatestOrgSequence() (*repository.CurrentSequence, error) {
- return v.latestSequence(orgTable)
+func (v *View) GetLatestOrgSequence(aggregateType string) (*repository.CurrentSequence, error) {
+ return v.latestSequence(orgTable, aggregateType)
}
-func (v *View) ProcessedOrgSequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(orgTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedOrgSequence(event *models.Event) error {
+ return v.saveCurrentSequence(orgTable, event)
}
diff --git a/internal/management/repository/eventsourcing/view/org_domain.go b/internal/management/repository/eventsourcing/view/org_domain.go
index 94f3f84c95..45ee4ad912 100644
--- a/internal/management/repository/eventsourcing/view/org_domain.go
+++ b/internal/management/repository/eventsourcing/view/org_domain.go
@@ -1,11 +1,12 @@
package view
import (
+ "github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
org_model "github.com/caos/zitadel/internal/org/model"
"github.com/caos/zitadel/internal/org/repository/view"
"github.com/caos/zitadel/internal/org/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -28,39 +29,36 @@ func (v *View) SearchOrgDomains(request *org_model.OrgDomainSearchRequest) ([]*m
return view.SearchOrgDomains(v.Db, orgDomainTable, request)
}
-func (v *View) PutOrgDomain(org *model.OrgDomainView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutOrgDomain(org *model.OrgDomainView, event *models.Event) error {
err := view.PutOrgDomain(v.Db, orgDomainTable, org)
if err != nil {
return err
}
- if sequence != 0 {
- return v.ProcessedOrgDomainSequence(sequence, eventTimestamp)
- }
- return nil
+ return v.ProcessedOrgDomainSequence(event)
}
-func (v *View) PutOrgDomains(domains []*model.OrgDomainView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutOrgDomains(domains []*model.OrgDomainView, event *models.Event) error {
err := view.PutOrgDomains(v.Db, orgDomainTable, domains...)
if err != nil {
return err
}
- return v.ProcessedUserSequence(sequence, eventTimestamp)
+ return v.ProcessedUserSequence(event)
}
-func (v *View) DeleteOrgDomain(orgID, domain string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteOrgDomain(orgID, domain string, event *models.Event) error {
err := view.DeleteOrgDomain(v.Db, orgDomainTable, orgID, domain)
- if err != nil {
- return nil
+ if err != nil && !errors.IsNotFound(err) {
+ return err
}
- return v.ProcessedOrgDomainSequence(eventSequence, eventTimestamp)
+ return v.ProcessedOrgDomainSequence(event)
}
-func (v *View) GetLatestOrgDomainSequence() (*repository.CurrentSequence, error) {
- return v.latestSequence(orgDomainTable)
+func (v *View) GetLatestOrgDomainSequence(aggregateType string) (*repository.CurrentSequence, error) {
+ return v.latestSequence(orgDomainTable, aggregateType)
}
-func (v *View) ProcessedOrgDomainSequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(orgDomainTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedOrgDomainSequence(event *models.Event) error {
+ return v.saveCurrentSequence(orgDomainTable, event)
}
func (v *View) UpdateOrgDomainSpoolerRunTimestamp() error {
diff --git a/internal/management/repository/eventsourcing/view/org_iam_policy.go b/internal/management/repository/eventsourcing/view/org_iam_policy.go
index db9d113155..90d3de2b9c 100644
--- a/internal/management/repository/eventsourcing/view/org_iam_policy.go
+++ b/internal/management/repository/eventsourcing/view/org_iam_policy.go
@@ -2,10 +2,10 @@ package view
import (
"github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -16,28 +16,28 @@ func (v *View) OrgIAMPolicyByAggregateID(aggregateID string) (*model.OrgIAMPolic
return view.GetOrgIAMPolicyByAggregateID(v.Db, orgIAMPolicyTable, aggregateID)
}
-func (v *View) PutOrgIAMPolicy(policy *model.OrgIAMPolicyView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutOrgIAMPolicy(policy *model.OrgIAMPolicyView, event *models.Event) error {
err := view.PutOrgIAMPolicy(v.Db, orgIAMPolicyTable, policy)
if err != nil {
return err
}
- return v.ProcessedOrgIAMPolicySequence(sequence, eventTimestamp)
+ return v.ProcessedOrgIAMPolicySequence(event)
}
-func (v *View) DeleteOrgIAMPolicy(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteOrgIAMPolicy(aggregateID string, event *models.Event) error {
err := view.DeleteOrgIAMPolicy(v.Db, orgIAMPolicyTable, aggregateID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedOrgIAMPolicySequence(eventSequence, eventTimestamp)
+ return v.ProcessedOrgIAMPolicySequence(event)
}
-func (v *View) GetLatestOrgIAMPolicySequence() (*global_view.CurrentSequence, error) {
- return v.latestSequence(orgIAMPolicyTable)
+func (v *View) GetLatestOrgIAMPolicySequence(aggregateType string) (*global_view.CurrentSequence, error) {
+ return v.latestSequence(orgIAMPolicyTable, aggregateType)
}
-func (v *View) ProcessedOrgIAMPolicySequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(orgIAMPolicyTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedOrgIAMPolicySequence(event *models.Event) error {
+ return v.saveCurrentSequence(orgIAMPolicyTable, event)
}
func (v *View) UpdateOrgIAMPolicySpoolerRunTimestamp() error {
diff --git a/internal/management/repository/eventsourcing/view/org_member.go b/internal/management/repository/eventsourcing/view/org_member.go
index d1cb20b3c0..ee6deac739 100644
--- a/internal/management/repository/eventsourcing/view/org_member.go
+++ b/internal/management/repository/eventsourcing/view/org_member.go
@@ -1,11 +1,12 @@
package view
import (
+ "github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
org_model "github.com/caos/zitadel/internal/org/model"
"github.com/caos/zitadel/internal/org/repository/view"
"github.com/caos/zitadel/internal/org/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -24,44 +25,44 @@ func (v *View) OrgMembersByUserID(userID string) ([]*model.OrgMemberView, error)
return view.OrgMembersByUserID(v.Db, orgMemberTable, userID)
}
-func (v *View) PutOrgMember(member *model.OrgMemberView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutOrgMember(member *model.OrgMemberView, event *models.Event) error {
err := view.PutOrgMember(v.Db, orgMemberTable, member)
if err != nil {
return err
}
- return v.ProcessedOrgMemberSequence(sequence, eventTimestamp)
+ return v.ProcessedOrgMemberSequence(event)
}
-func (v *View) PutOrgMembers(members []*model.OrgMemberView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutOrgMembers(members []*model.OrgMemberView, event *models.Event) error {
err := view.PutOrgMembers(v.Db, orgMemberTable, members...)
if err != nil {
return err
}
- return v.ProcessedOrgMemberSequence(sequence, eventTimestamp)
+ return v.ProcessedOrgMemberSequence(event)
}
-func (v *View) DeleteOrgMember(orgID, userID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteOrgMember(orgID, userID string, event *models.Event) error {
err := view.DeleteOrgMember(v.Db, orgMemberTable, orgID, userID)
- if err != nil {
- return nil
+ if err != nil && !errors.IsNotFound(err) {
+ return err
}
- return v.ProcessedOrgMemberSequence(eventSequence, eventTimestamp)
+ return v.ProcessedOrgMemberSequence(event)
}
-func (v *View) DeleteOrgMembersByUserID(userID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteOrgMembersByUserID(userID string, event *models.Event) error {
err := view.DeleteOrgMembersByUserID(v.Db, orgMemberTable, userID)
- if err != nil {
- return nil
+ if err != nil && !errors.IsNotFound(err) {
+ return err
}
- return v.ProcessedOrgMemberSequence(eventSequence, eventTimestamp)
+ return v.ProcessedOrgMemberSequence(event)
}
-func (v *View) GetLatestOrgMemberSequence() (*repository.CurrentSequence, error) {
- return v.latestSequence(orgMemberTable)
+func (v *View) GetLatestOrgMemberSequence(aggregateType string) (*repository.CurrentSequence, error) {
+ return v.latestSequence(orgMemberTable, aggregateType)
}
-func (v *View) ProcessedOrgMemberSequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(orgMemberTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedOrgMemberSequence(event *models.Event) error {
+ return v.saveCurrentSequence(orgMemberTable, event)
}
func (v *View) UpdateOrgMemberSpoolerRunTimestamp() error {
diff --git a/internal/management/repository/eventsourcing/view/password_age_policy.go b/internal/management/repository/eventsourcing/view/password_age_policy.go
index e37d650072..e1bd56a596 100644
--- a/internal/management/repository/eventsourcing/view/password_age_policy.go
+++ b/internal/management/repository/eventsourcing/view/password_age_policy.go
@@ -2,10 +2,10 @@ package view
import (
"github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -16,28 +16,28 @@ func (v *View) PasswordAgePolicyByAggregateID(aggregateID string) (*model.Passwo
return view.GetPasswordAgePolicyByAggregateID(v.Db, passwordAgePolicyTable, aggregateID)
}
-func (v *View) PutPasswordAgePolicy(policy *model.PasswordAgePolicyView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutPasswordAgePolicy(policy *model.PasswordAgePolicyView, event *models.Event) error {
err := view.PutPasswordAgePolicy(v.Db, passwordAgePolicyTable, policy)
if err != nil {
return err
}
- return v.ProcessedPasswordAgePolicySequence(sequence, eventTimestamp)
+ return v.ProcessedPasswordAgePolicySequence(event)
}
-func (v *View) DeletePasswordAgePolicy(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeletePasswordAgePolicy(aggregateID string, event *models.Event) error {
err := view.DeletePasswordAgePolicy(v.Db, passwordAgePolicyTable, aggregateID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedPasswordAgePolicySequence(eventSequence, eventTimestamp)
+ return v.ProcessedPasswordAgePolicySequence(event)
}
-func (v *View) GetLatestPasswordAgePolicySequence() (*global_view.CurrentSequence, error) {
- return v.latestSequence(passwordAgePolicyTable)
+func (v *View) GetLatestPasswordAgePolicySequence(aggregateType string) (*global_view.CurrentSequence, error) {
+ return v.latestSequence(passwordAgePolicyTable, aggregateType)
}
-func (v *View) ProcessedPasswordAgePolicySequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(passwordAgePolicyTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedPasswordAgePolicySequence(event *models.Event) error {
+ return v.saveCurrentSequence(passwordAgePolicyTable, event)
}
func (v *View) UpdatePasswordAgePolicySpoolerRunTimestamp() error {
diff --git a/internal/management/repository/eventsourcing/view/password_complexity_policy.go b/internal/management/repository/eventsourcing/view/password_complexity_policy.go
index 70895d13a9..80d9e2d90d 100644
--- a/internal/management/repository/eventsourcing/view/password_complexity_policy.go
+++ b/internal/management/repository/eventsourcing/view/password_complexity_policy.go
@@ -2,10 +2,10 @@ package view
import (
"github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -16,28 +16,28 @@ func (v *View) PasswordComplexityPolicyByAggregateID(aggregateID string) (*model
return view.GetPasswordComplexityPolicyByAggregateID(v.Db, passwordComplexityPolicyTable, aggregateID)
}
-func (v *View) PutPasswordComplexityPolicy(policy *model.PasswordComplexityPolicyView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutPasswordComplexityPolicy(policy *model.PasswordComplexityPolicyView, event *models.Event) error {
err := view.PutPasswordComplexityPolicy(v.Db, passwordComplexityPolicyTable, policy)
if err != nil {
return err
}
- return v.ProcessedPasswordComplexityPolicySequence(sequence, eventTimestamp)
+ return v.ProcessedPasswordComplexityPolicySequence(event)
}
-func (v *View) DeletePasswordComplexityPolicy(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeletePasswordComplexityPolicy(aggregateID string, event *models.Event) error {
err := view.DeletePasswordComplexityPolicy(v.Db, passwordComplexityPolicyTable, aggregateID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedPasswordComplexityPolicySequence(eventSequence, eventTimestamp)
+ return v.ProcessedPasswordComplexityPolicySequence(event)
}
-func (v *View) GetLatestPasswordComplexityPolicySequence() (*global_view.CurrentSequence, error) {
- return v.latestSequence(passwordComplexityPolicyTable)
+func (v *View) GetLatestPasswordComplexityPolicySequence(aggregateType string) (*global_view.CurrentSequence, error) {
+ return v.latestSequence(passwordComplexityPolicyTable, aggregateType)
}
-func (v *View) ProcessedPasswordComplexityPolicySequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(passwordComplexityPolicyTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedPasswordComplexityPolicySequence(event *models.Event) error {
+ return v.saveCurrentSequence(passwordComplexityPolicyTable, event)
}
func (v *View) UpdatePasswordComplexityPolicySpoolerRunTimestamp() error {
diff --git a/internal/management/repository/eventsourcing/view/password_lockout_policy.go b/internal/management/repository/eventsourcing/view/password_lockout_policy.go
index 11e3955720..549f704c75 100644
--- a/internal/management/repository/eventsourcing/view/password_lockout_policy.go
+++ b/internal/management/repository/eventsourcing/view/password_lockout_policy.go
@@ -2,10 +2,10 @@ package view
import (
"github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -16,28 +16,28 @@ func (v *View) PasswordLockoutPolicyByAggregateID(aggregateID string) (*model.Pa
return view.GetPasswordLockoutPolicyByAggregateID(v.Db, passwordLockoutPolicyTable, aggregateID)
}
-func (v *View) PutPasswordLockoutPolicy(policy *model.PasswordLockoutPolicyView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutPasswordLockoutPolicy(policy *model.PasswordLockoutPolicyView, event *models.Event) error {
err := view.PutPasswordLockoutPolicy(v.Db, passwordLockoutPolicyTable, policy)
if err != nil {
return err
}
- return v.ProcessedPasswordLockoutPolicySequence(sequence, eventTimestamp)
+ return v.ProcessedPasswordLockoutPolicySequence(event)
}
-func (v *View) DeletePasswordLockoutPolicy(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeletePasswordLockoutPolicy(aggregateID string, event *models.Event) error {
err := view.DeletePasswordLockoutPolicy(v.Db, passwordLockoutPolicyTable, aggregateID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedPasswordLockoutPolicySequence(eventSequence, eventTimestamp)
+ return v.ProcessedPasswordLockoutPolicySequence(event)
}
-func (v *View) GetLatestPasswordLockoutPolicySequence() (*global_view.CurrentSequence, error) {
- return v.latestSequence(passwordLockoutPolicyTable)
+func (v *View) GetLatestPasswordLockoutPolicySequence(aggregateType string) (*global_view.CurrentSequence, error) {
+ return v.latestSequence(passwordLockoutPolicyTable, aggregateType)
}
-func (v *View) ProcessedPasswordLockoutPolicySequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(passwordLockoutPolicyTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedPasswordLockoutPolicySequence(event *models.Event) error {
+ return v.saveCurrentSequence(passwordLockoutPolicyTable, event)
}
func (v *View) UpdatePasswordLockoutPolicySpoolerRunTimestamp() error {
diff --git a/internal/management/repository/eventsourcing/view/project.go b/internal/management/repository/eventsourcing/view/project.go
index fede8830ee..f5ac609ddc 100644
--- a/internal/management/repository/eventsourcing/view/project.go
+++ b/internal/management/repository/eventsourcing/view/project.go
@@ -1,11 +1,12 @@
package view
import (
+ "github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
proj_model "github.com/caos/zitadel/internal/project/model"
"github.com/caos/zitadel/internal/project/repository/view"
"github.com/caos/zitadel/internal/project/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -20,28 +21,28 @@ func (v *View) SearchProjects(request *proj_model.ProjectViewSearchRequest) ([]*
return view.SearchProjects(v.Db, projectTable, request)
}
-func (v *View) PutProject(project *model.ProjectView, eventTimestamp time.Time) error {
+func (v *View) PutProject(project *model.ProjectView, event *models.Event) error {
err := view.PutProject(v.Db, projectTable, project)
if err != nil {
return err
}
- return v.ProcessedProjectSequence(project.Sequence, eventTimestamp)
+ return v.ProcessedProjectSequence(event)
}
-func (v *View) DeleteProject(projectID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteProject(projectID string, event *models.Event) error {
err := view.DeleteProject(v.Db, projectTable, projectID)
- if err != nil {
- return nil
+ if err != nil && !errors.IsNotFound(err) {
+ return err
}
- return v.ProcessedProjectSequence(eventSequence, eventTimestamp)
+ return v.ProcessedProjectSequence(event)
}
-func (v *View) GetLatestProjectSequence() (*repository.CurrentSequence, error) {
- return v.latestSequence(projectTable)
+func (v *View) GetLatestProjectSequence(aggregateType string) (*repository.CurrentSequence, error) {
+ return v.latestSequence(projectTable, aggregateType)
}
-func (v *View) ProcessedProjectSequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(projectTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedProjectSequence(event *models.Event) error {
+ return v.saveCurrentSequence(projectTable, event)
}
func (v *View) UpdateProjectSpoolerRunTimestamp() error {
diff --git a/internal/management/repository/eventsourcing/view/project_grant.go b/internal/management/repository/eventsourcing/view/project_grant.go
index 64f1f6272e..ab54927a30 100644
--- a/internal/management/repository/eventsourcing/view/project_grant.go
+++ b/internal/management/repository/eventsourcing/view/project_grant.go
@@ -1,11 +1,11 @@
package view
import (
+ "github.com/caos/zitadel/internal/eventstore/models"
proj_model "github.com/caos/zitadel/internal/project/model"
"github.com/caos/zitadel/internal/project/repository/view"
"github.com/caos/zitadel/internal/project/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -32,40 +32,40 @@ func (v *View) SearchProjectGrants(request *proj_model.ProjectGrantViewSearchReq
return view.SearchProjectGrants(v.Db, grantedProjectTable, request)
}
-func (v *View) PutProjectGrant(grant *model.ProjectGrantView, eventTimestamp time.Time) error {
+func (v *View) PutProjectGrant(grant *model.ProjectGrantView, event *models.Event) error {
err := view.PutProjectGrant(v.Db, grantedProjectTable, grant)
if err != nil {
return err
}
- return v.ProcessedProjectGrantSequence(grant.Sequence, eventTimestamp)
+ return v.ProcessedProjectGrantSequence(event)
}
-func (v *View) PutProjectGrants(grants []*model.ProjectGrantView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutProjectGrants(grants []*model.ProjectGrantView, event *models.Event) error {
err := view.PutProjectGrants(v.Db, grantedProjectTable, grants...)
if err != nil {
return err
}
- return v.ProcessedProjectGrantSequence(sequence, eventTimestamp)
+ return v.ProcessedProjectGrantSequence(event)
}
-func (v *View) DeleteProjectGrant(grantID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteProjectGrant(grantID string, event *models.Event) error {
err := view.DeleteProjectGrant(v.Db, grantedProjectTable, grantID)
if err != nil {
return err
}
- return v.ProcessedProjectGrantSequence(eventSequence, eventTimestamp)
+ return v.ProcessedProjectGrantSequence(event)
}
func (v *View) DeleteProjectGrantsByProjectID(projectID string) error {
return view.DeleteProjectGrantsByProjectID(v.Db, grantedProjectTable, projectID)
}
-func (v *View) GetLatestProjectGrantSequence() (*repository.CurrentSequence, error) {
- return v.latestSequence(grantedProjectTable)
+func (v *View) GetLatestProjectGrantSequence(aggregateType string) (*repository.CurrentSequence, error) {
+ return v.latestSequence(grantedProjectTable, aggregateType)
}
-func (v *View) ProcessedProjectGrantSequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(grantedProjectTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedProjectGrantSequence(event *models.Event) error {
+ return v.saveCurrentSequence(grantedProjectTable, event)
}
func (v *View) UpdateProjectGrantSpoolerRunTimestamp() error {
diff --git a/internal/management/repository/eventsourcing/view/project_grant_member.go b/internal/management/repository/eventsourcing/view/project_grant_member.go
index b9cf4391ba..7634cefbf5 100644
--- a/internal/management/repository/eventsourcing/view/project_grant_member.go
+++ b/internal/management/repository/eventsourcing/view/project_grant_member.go
@@ -1,11 +1,12 @@
package view
import (
+ "github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
proj_model "github.com/caos/zitadel/internal/project/model"
"github.com/caos/zitadel/internal/project/repository/view"
"github.com/caos/zitadel/internal/project/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -28,40 +29,40 @@ func (v *View) ProjectGrantMembersByUserID(userID string) ([]*model.ProjectGrant
return view.ProjectGrantMembersByUserID(v.Db, projectGrantMemberTable, userID)
}
-func (v *View) PutProjectGrantMember(member *model.ProjectGrantMemberView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutProjectGrantMember(member *model.ProjectGrantMemberView, event *models.Event) error {
err := view.PutProjectGrantMember(v.Db, projectGrantMemberTable, member)
if err != nil {
return err
}
- return v.ProcessedProjectGrantMemberSequence(sequence, eventTimestamp)
+ return v.ProcessedProjectGrantMemberSequence(event)
}
-func (v *View) PutProjectGrantMembers(members []*model.ProjectGrantMemberView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutProjectGrantMembers(members []*model.ProjectGrantMemberView, event *models.Event) error {
err := view.PutProjectGrantMembers(v.Db, projectGrantMemberTable, members...)
if err != nil {
return err
}
- return v.ProcessedProjectGrantMemberSequence(sequence, eventTimestamp)
+ return v.ProcessedProjectGrantMemberSequence(event)
}
-func (v *View) DeleteProjectGrantMember(grantID, userID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteProjectGrantMember(grantID, userID string, event *models.Event) error {
err := view.DeleteProjectGrantMember(v.Db, projectGrantMemberTable, grantID, userID)
- if err != nil {
- return nil
+ if err != nil && !errors.IsNotFound(err) {
+ return err
}
- return v.ProcessedProjectGrantMemberSequence(eventSequence, eventTimestamp)
+ return v.ProcessedProjectGrantMemberSequence(event)
}
func (v *View) DeleteProjectGrantMembersByProjectID(projectID string) error {
return view.DeleteProjectGrantMembersByProjectID(v.Db, projectGrantMemberTable, projectID)
}
-func (v *View) GetLatestProjectGrantMemberSequence() (*repository.CurrentSequence, error) {
- return v.latestSequence(projectGrantMemberTable)
+func (v *View) GetLatestProjectGrantMemberSequence(aggregateType string) (*repository.CurrentSequence, error) {
+ return v.latestSequence(projectGrantMemberTable, aggregateType)
}
-func (v *View) ProcessedProjectGrantMemberSequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(projectGrantMemberTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedProjectGrantMemberSequence(event *models.Event) error {
+ return v.saveCurrentSequence(projectGrantMemberTable, event)
}
func (v *View) UpdateProjectGrantMemberSpoolerRunTimestamp() error {
diff --git a/internal/management/repository/eventsourcing/view/project_member.go b/internal/management/repository/eventsourcing/view/project_member.go
index c21dee73e2..09f3b31518 100644
--- a/internal/management/repository/eventsourcing/view/project_member.go
+++ b/internal/management/repository/eventsourcing/view/project_member.go
@@ -1,11 +1,12 @@
package view
import (
+ "github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
proj_model "github.com/caos/zitadel/internal/project/model"
"github.com/caos/zitadel/internal/project/repository/view"
"github.com/caos/zitadel/internal/project/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -28,40 +29,40 @@ func (v *View) ProjectMembersByUserID(userID string) ([]*model.ProjectMemberView
return view.ProjectMembersByUserID(v.Db, projectMemberTable, userID)
}
-func (v *View) PutProjectMember(project *model.ProjectMemberView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutProjectMember(project *model.ProjectMemberView, event *models.Event) error {
err := view.PutProjectMember(v.Db, projectMemberTable, project)
if err != nil {
return err
}
- return v.ProcessedProjectMemberSequence(sequence, eventTimestamp)
+ return v.ProcessedProjectMemberSequence(event)
}
-func (v *View) PutProjectMembers(project []*model.ProjectMemberView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutProjectMembers(project []*model.ProjectMemberView, event *models.Event) error {
err := view.PutProjectMembers(v.Db, projectMemberTable, project...)
if err != nil {
return err
}
- return v.ProcessedProjectMemberSequence(sequence, eventTimestamp)
+ return v.ProcessedProjectMemberSequence(event)
}
-func (v *View) DeleteProjectMember(projectID, userID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteProjectMember(projectID, userID string, event *models.Event) error {
err := view.DeleteProjectMember(v.Db, projectMemberTable, projectID, userID)
- if err != nil {
- return nil
+ if err != nil && !errors.IsNotFound(err) {
+ return err
}
- return v.ProcessedProjectMemberSequence(eventSequence, eventTimestamp)
+ return v.ProcessedProjectMemberSequence(event)
}
func (v *View) DeleteProjectMembersByProjectID(projectID string) error {
return view.DeleteProjectMembersByProjectID(v.Db, projectMemberTable, projectID)
}
-func (v *View) GetLatestProjectMemberSequence() (*repository.CurrentSequence, error) {
- return v.latestSequence(projectMemberTable)
+func (v *View) GetLatestProjectMemberSequence(aggregateType string) (*repository.CurrentSequence, error) {
+ return v.latestSequence(projectMemberTable, aggregateType)
}
-func (v *View) ProcessedProjectMemberSequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(projectMemberTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedProjectMemberSequence(event *models.Event) error {
+ return v.saveCurrentSequence(projectMemberTable, event)
}
func (v *View) UpdateProjectMemberSpoolerRunTimestamp() error {
diff --git a/internal/management/repository/eventsourcing/view/project_role.go b/internal/management/repository/eventsourcing/view/project_role.go
index 6703a93efd..5b251fa24b 100644
--- a/internal/management/repository/eventsourcing/view/project_role.go
+++ b/internal/management/repository/eventsourcing/view/project_role.go
@@ -1,11 +1,12 @@
package view
import (
+ "github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
proj_model "github.com/caos/zitadel/internal/project/model"
"github.com/caos/zitadel/internal/project/repository/view"
"github.com/caos/zitadel/internal/project/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -32,32 +33,32 @@ func (v *View) SearchProjectRoles(request *proj_model.ProjectRoleSearchRequest)
return view.SearchProjectRoles(v.Db, projectRoleTable, request)
}
-func (v *View) PutProjectRole(project *model.ProjectRoleView, eventTimestamp time.Time) error {
+func (v *View) PutProjectRole(project *model.ProjectRoleView, event *models.Event) error {
err := view.PutProjectRole(v.Db, projectRoleTable, project)
if err != nil {
return err
}
- return v.ProcessedProjectRoleSequence(project.Sequence, eventTimestamp)
+ return v.ProcessedProjectRoleSequence(event)
}
-func (v *View) DeleteProjectRole(projectID, orgID, key string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteProjectRole(projectID, orgID, key string, event *models.Event) error {
err := view.DeleteProjectRole(v.Db, projectRoleTable, projectID, orgID, key)
- if err != nil {
- return nil
+ if err != nil && !errors.IsNotFound(err) {
+ return err
}
- return v.ProcessedProjectRoleSequence(eventSequence, eventTimestamp)
+ return v.ProcessedProjectRoleSequence(event)
}
func (v *View) DeleteProjectRolesByProjectID(projectID string) error {
return view.DeleteProjectRolesByProjectID(v.Db, projectRoleTable, projectID)
}
-func (v *View) GetLatestProjectRoleSequence() (*repository.CurrentSequence, error) {
- return v.latestSequence(projectRoleTable)
+func (v *View) GetLatestProjectRoleSequence(aggregateType string) (*repository.CurrentSequence, error) {
+ return v.latestSequence(projectRoleTable, aggregateType)
}
-func (v *View) ProcessedProjectRoleSequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(projectRoleTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedProjectRoleSequence(event *models.Event) error {
+ return v.saveCurrentSequence(projectRoleTable, event)
}
func (v *View) UpdateProjectRoleSpoolerRunTimestamp() error {
diff --git a/internal/management/repository/eventsourcing/view/sequence.go b/internal/management/repository/eventsourcing/view/sequence.go
index 82354c98e4..808ff58216 100644
--- a/internal/management/repository/eventsourcing/view/sequence.go
+++ b/internal/management/repository/eventsourcing/view/sequence.go
@@ -1,24 +1,26 @@
package view
import (
- "github.com/caos/zitadel/internal/view/repository"
"time"
+
+ "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/view/repository"
)
const (
sequencesTable = "management.current_sequences"
)
-func (v *View) saveCurrentSequence(viewName string, sequence uint64, eventTimestamp time.Time) error {
- return repository.SaveCurrentSequence(v.Db, sequencesTable, viewName, sequence, eventTimestamp)
+func (v *View) saveCurrentSequence(viewName string, event *models.Event) error {
+ return repository.SaveCurrentSequence(v.Db, sequencesTable, viewName, string(event.AggregateType), event.Sequence, event.CreationDate)
}
-func (v *View) latestSequence(viewName string) (*repository.CurrentSequence, error) {
- return repository.LatestSequence(v.Db, sequencesTable, viewName)
+func (v *View) latestSequence(viewName, aggregateType string) (*repository.CurrentSequence, error) {
+ return repository.LatestSequence(v.Db, sequencesTable, viewName, aggregateType)
}
func (v *View) updateSpoolerRunSequence(viewName string) error {
- currentSequence, err := repository.LatestSequence(v.Db, sequencesTable, viewName)
+ currentSequence, err := repository.LatestSequence(v.Db, sequencesTable, viewName, "")
if err != nil {
return err
}
@@ -26,5 +28,8 @@ func (v *View) updateSpoolerRunSequence(viewName string) error {
currentSequence.ViewName = viewName
}
currentSequence.LastSuccessfulSpoolerRun = time.Now()
+ //update all aggregate types
+ //TODO: not sure if all scenarios work as expected
+ currentSequence.AggregateType = ""
return repository.UpdateCurrentSequence(v.Db, sequencesTable, currentSequence)
}
diff --git a/internal/management/repository/eventsourcing/view/user.go b/internal/management/repository/eventsourcing/view/user.go
index 69fc14a270..d589b546f7 100644
--- a/internal/management/repository/eventsourcing/view/user.go
+++ b/internal/management/repository/eventsourcing/view/user.go
@@ -1,11 +1,12 @@
package view
import (
+ "github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
usr_model "github.com/caos/zitadel/internal/user/model"
"github.com/caos/zitadel/internal/user/repository/view"
"github.com/caos/zitadel/internal/user/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -40,39 +41,36 @@ func (v *View) UserMFAs(userID string) ([]*usr_model.MultiFactor, error) {
return view.UserMFAs(v.Db, userTable, userID)
}
-func (v *View) PutUsers(user []*model.UserView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutUsers(user []*model.UserView, event *models.Event) error {
err := view.PutUsers(v.Db, userTable, user...)
if err != nil {
return err
}
- return v.ProcessedUserSequence(sequence, eventTimestamp)
+ return v.ProcessedUserSequence(event)
}
-func (v *View) PutUser(user *model.UserView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutUser(user *model.UserView, event *models.Event) error {
err := view.PutUser(v.Db, userTable, user)
if err != nil {
return err
}
- if sequence != 0 {
- return v.ProcessedUserSequence(sequence, eventTimestamp)
- }
- return nil
+ return v.ProcessedUserSequence(event)
}
-func (v *View) DeleteUser(userID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteUser(userID string, event *models.Event) error {
err := view.DeleteUser(v.Db, userTable, userID)
- if err != nil {
- return nil
+ if err != nil && !errors.IsNotFound(err) {
+ return err
}
- return v.ProcessedUserSequence(eventSequence, eventTimestamp)
+ return v.ProcessedUserSequence(event)
}
-func (v *View) GetLatestUserSequence() (*repository.CurrentSequence, error) {
- return v.latestSequence(userTable)
+func (v *View) GetLatestUserSequence(aggregateType string) (*repository.CurrentSequence, error) {
+ return v.latestSequence(userTable, aggregateType)
}
-func (v *View) ProcessedUserSequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(userTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedUserSequence(event *models.Event) error {
+ return v.saveCurrentSequence(userTable, event)
}
func (v *View) UpdateUserSpoolerRunTimestamp() error {
diff --git a/internal/management/repository/eventsourcing/view/user_grant.go b/internal/management/repository/eventsourcing/view/user_grant.go
index 209fbfe6f4..15dd3220d2 100644
--- a/internal/management/repository/eventsourcing/view/user_grant.go
+++ b/internal/management/repository/eventsourcing/view/user_grant.go
@@ -1,11 +1,12 @@
package view
import (
+ "github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
grant_model "github.com/caos/zitadel/internal/usergrant/model"
"github.com/caos/zitadel/internal/usergrant/repository/view"
"github.com/caos/zitadel/internal/usergrant/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -40,36 +41,36 @@ func (v *View) UserGrantsByOrgIDAndProjectID(orgID, projectID string) ([]*model.
return view.UserGrantsByOrgIDAndProjectID(v.Db, userGrantTable, orgID, projectID)
}
-func (v *View) PutUserGrant(grant *model.UserGrantView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutUserGrant(grant *model.UserGrantView, event *models.Event) error {
err := view.PutUserGrant(v.Db, userGrantTable, grant)
if err != nil {
return err
}
- return v.ProcessedUserGrantSequence(sequence, eventTimestamp)
+ return v.ProcessedUserGrantSequence(event)
}
-func (v *View) PutUserGrants(grants []*model.UserGrantView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutUserGrants(grants []*model.UserGrantView, event *models.Event) error {
err := view.PutUserGrants(v.Db, userGrantTable, grants...)
if err != nil {
return err
}
- return v.ProcessedUserGrantSequence(sequence, eventTimestamp)
+ return v.ProcessedUserGrantSequence(event)
}
-func (v *View) DeleteUserGrant(grantID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteUserGrant(grantID string, event *models.Event) error {
err := view.DeleteUserGrant(v.Db, userGrantTable, grantID)
- if err != nil {
- return nil
+ if err != nil && !errors.IsNotFound(err) {
+ return err
}
- return v.ProcessedUserGrantSequence(eventSequence, eventTimestamp)
+ return v.ProcessedUserGrantSequence(event)
}
-func (v *View) GetLatestUserGrantSequence() (*repository.CurrentSequence, error) {
- return v.latestSequence(userGrantTable)
+func (v *View) GetLatestUserGrantSequence(aggregateType string) (*repository.CurrentSequence, error) {
+ return v.latestSequence(userGrantTable, aggregateType)
}
-func (v *View) ProcessedUserGrantSequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(userGrantTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedUserGrantSequence(event *models.Event) error {
+ return v.saveCurrentSequence(userGrantTable, event)
}
func (v *View) UpdateUserGrantSpoolerRunTimestamp() error {
diff --git a/internal/management/repository/eventsourcing/view/user_membership.go b/internal/management/repository/eventsourcing/view/user_membership.go
index 4c733dc875..90f64906a7 100644
--- a/internal/management/repository/eventsourcing/view/user_membership.go
+++ b/internal/management/repository/eventsourcing/view/user_membership.go
@@ -1,11 +1,12 @@
package view
import (
+ "github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
usr_model "github.com/caos/zitadel/internal/user/model"
"github.com/caos/zitadel/internal/user/repository/view"
"github.com/caos/zitadel/internal/user/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -24,60 +25,60 @@ func (v *View) SearchUserMemberships(request *usr_model.UserMembershipSearchRequ
return view.SearchUserMemberships(v.Db, userMembershipTable, request)
}
-func (v *View) PutUserMembership(membership *model.UserMembershipView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutUserMembership(membership *model.UserMembershipView, event *models.Event) error {
err := view.PutUserMembership(v.Db, userMembershipTable, membership)
if err != nil {
return err
}
- return v.ProcessedUserMembershipSequence(sequence, eventTimestamp)
+ return v.ProcessedUserMembershipSequence(event)
}
-func (v *View) BulkPutUserMemberships(memberships []*model.UserMembershipView, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) BulkPutUserMemberships(memberships []*model.UserMembershipView, event *models.Event) error {
err := view.PutUserMemberships(v.Db, userMembershipTable, memberships...)
if err != nil {
return err
}
- return v.ProcessedUserMembershipSequence(sequence, eventTimestamp)
+ return v.ProcessedUserMembershipSequence(event)
}
-func (v *View) DeleteUserMembership(userID, aggregateID, objectID string, memberType usr_model.MemberType, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteUserMembership(userID, aggregateID, objectID string, memberType usr_model.MemberType, event *models.Event) error {
err := view.DeleteUserMembership(v.Db, userMembershipTable, userID, aggregateID, objectID, memberType)
- if err != nil {
- return nil
+ if err != nil && !errors.IsNotFound(err) {
+ return err
}
- return v.ProcessedUserMembershipSequence(eventSequence, eventTimestamp)
+ return v.ProcessedUserMembershipSequence(event)
}
-func (v *View) DeleteUserMembershipsByUserID(userID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteUserMembershipsByUserID(userID string, event *models.Event) error {
err := view.DeleteUserMembershipsByUserID(v.Db, userMembershipTable, userID)
- if err != nil {
- return nil
+ if err != nil && !errors.IsNotFound(err) {
+ return err
}
- return v.ProcessedUserMembershipSequence(eventSequence, eventTimestamp)
+ return v.ProcessedUserMembershipSequence(event)
}
-func (v *View) DeleteUserMembershipsByAggregateID(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteUserMembershipsByAggregateID(aggregateID string, event *models.Event) error {
err := view.DeleteUserMembershipsByAggregateID(v.Db, userMembershipTable, aggregateID)
- if err != nil {
- return nil
+ if err != nil && !errors.IsNotFound(err) {
+ return err
}
- return v.ProcessedUserMembershipSequence(eventSequence, eventTimestamp)
+ return v.ProcessedUserMembershipSequence(event)
}
-func (v *View) DeleteUserMembershipsByAggregateIDAndObjectID(aggregateID, objectID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteUserMembershipsByAggregateIDAndObjectID(aggregateID, objectID string, event *models.Event) error {
err := view.DeleteUserMembershipsByAggregateIDAndObjectID(v.Db, userMembershipTable, aggregateID, objectID)
- if err != nil {
- return nil
+ if err != nil && !errors.IsNotFound(err) {
+ return err
}
- return v.ProcessedUserMembershipSequence(eventSequence, eventTimestamp)
+ return v.ProcessedUserMembershipSequence(event)
}
-func (v *View) GetLatestUserMembershipSequence() (*repository.CurrentSequence, error) {
- return v.latestSequence(userMembershipTable)
+func (v *View) GetLatestUserMembershipSequence(aggregateType string) (*repository.CurrentSequence, error) {
+ return v.latestSequence(userMembershipTable, aggregateType)
}
-func (v *View) ProcessedUserMembershipSequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(userMembershipTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedUserMembershipSequence(event *models.Event) error {
+ return v.saveCurrentSequence(userMembershipTable, event)
}
func (v *View) UpdateUserMembershipSpoolerRunTimestamp() error {
diff --git a/internal/management/repository/user.go b/internal/management/repository/user.go
index 92a2364c11..da8d81b359 100644
--- a/internal/management/repository/user.go
+++ b/internal/management/repository/user.go
@@ -32,6 +32,10 @@ type UserRepository interface {
UserMFAs(ctx context.Context, userID string) ([]*model.MultiFactor, error)
RemoveOTP(ctx context.Context, userID string) error
+ RemoveU2F(ctx context.Context, userID, webAuthNTokenID string) error
+
+ GetPasswordless(ctx context.Context, userID string) ([]*model.WebAuthNToken, error)
+ RemovePasswordless(ctx context.Context, userID, webAuthNTokenID string) error
SearchExternalIDPs(ctx context.Context, request *model.ExternalIDPSearchRequest) (*model.ExternalIDPSearchResponse, error)
RemoveExternalIDP(ctx context.Context, externalIDP *model.ExternalIDP) error
diff --git a/internal/notification/repository/eventsourcing/handler/handler.go b/internal/notification/repository/eventsourcing/handler/handler.go
index a6db3edb74..eb8035ed88 100644
--- a/internal/notification/repository/eventsourcing/handler/handler.go
+++ b/internal/notification/repository/eventsourcing/handler/handler.go
@@ -1,6 +1,9 @@
package handler
import (
+ "net/http"
+ "time"
+
"github.com/caos/logging"
sd "github.com/caos/zitadel/internal/config/systemdefaults"
"github.com/caos/zitadel/internal/config/types"
@@ -12,8 +15,6 @@ import (
"github.com/caos/zitadel/internal/notification/repository/eventsourcing/view"
org_event "github.com/caos/zitadel/internal/org/repository/eventsourcing"
usr_event "github.com/caos/zitadel/internal/user/repository/eventsourcing"
- "net/http"
- "time"
)
type Configs map[string]*Config
@@ -27,6 +28,12 @@ type handler struct {
bulkLimit uint64
cycleDuration time.Duration
errorCountUntilSkip uint64
+
+ es eventstore.Eventstore
+}
+
+func (h *handler) Eventstore() eventstore.Eventstore {
+ return h.es
}
type EventstoreRepos struct {
@@ -35,34 +42,33 @@ type EventstoreRepos struct {
IAMEvents *iam_es.IAMEventstore
}
-func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, eventstore eventstore.Eventstore, repos EventstoreRepos, systemDefaults sd.SystemDefaults, i18n *i18n.Translator, dir http.FileSystem) []query.Handler {
+func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es eventstore.Eventstore, repos EventstoreRepos, systemDefaults sd.SystemDefaults, i18n *i18n.Translator, dir http.FileSystem) []query.Handler {
aesCrypto, err := crypto.NewAESCrypto(systemDefaults.UserVerificationKey)
if err != nil {
logging.Log("HANDL-s90ew").WithError(err).Debug("error create new aes crypto")
}
return []query.Handler{
- &NotifyUser{
- handler: handler{view, bulkLimit, configs.cycleDuration("User"), errorCount},
- orgEvents: repos.OrgEvents,
- iamEvents: repos.IAMEvents,
- iamID: systemDefaults.IamID,
- },
- &Notification{
- handler: handler{view, bulkLimit, configs.cycleDuration("Notification"), errorCount},
- eventstore: eventstore,
- userEvents: repos.UserEvents,
- systemDefaults: systemDefaults,
- AesCrypto: aesCrypto,
- i18n: i18n,
- statikDir: dir,
- },
+ newNotifyUser(
+ handler{view, bulkLimit, configs.cycleDuration("User"), errorCount, es},
+ repos.OrgEvents,
+ repos.IAMEvents,
+ systemDefaults.IamID,
+ ),
+ newNotification(
+ handler{view, bulkLimit, configs.cycleDuration("Notification"), errorCount, es},
+ repos.UserEvents,
+ systemDefaults,
+ aesCrypto,
+ i18n,
+ dir,
+ ),
}
}
func (configs Configs) cycleDuration(viewModel string) time.Duration {
c, ok := configs[viewModel]
if !ok {
- return 1 * time.Second
+ return 3 * time.Minute
}
return c.MinimumCycleDuration.Duration
}
@@ -71,6 +77,10 @@ func (h *handler) MinimumCycleDuration() time.Duration {
return h.cycleDuration
}
+func (h *handler) LockDuration() time.Duration {
+ return h.cycleDuration / 3
+}
+
func (h *handler) QueryLimit() uint64 {
return h.bulkLimit
}
diff --git a/internal/notification/repository/eventsourcing/handler/notification.go b/internal/notification/repository/eventsourcing/handler/notification.go
index 96ff4ae9ce..0d37914e3a 100644
--- a/internal/notification/repository/eventsourcing/handler/notification.go
+++ b/internal/notification/repository/eventsourcing/handler/notification.go
@@ -7,34 +7,22 @@ import (
"time"
"github.com/caos/logging"
-
"github.com/caos/zitadel/internal/api/authz"
sd "github.com/caos/zitadel/internal/config/systemdefaults"
"github.com/caos/zitadel/internal/crypto"
- "github.com/caos/zitadel/internal/errors"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
"github.com/caos/zitadel/internal/i18n"
iam_model "github.com/caos/zitadel/internal/iam/model"
iam_es_model "github.com/caos/zitadel/internal/iam/repository/view/model"
"github.com/caos/zitadel/internal/notification/types"
- "github.com/caos/zitadel/internal/user/repository/eventsourcing"
usr_event "github.com/caos/zitadel/internal/user/repository/eventsourcing"
es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
)
-type Notification struct {
- handler
- eventstore eventstore.Eventstore
- userEvents *usr_event.UserEventstore
- systemDefaults sd.SystemDefaults
- AesCrypto crypto.EncryptionAlgorithm
- i18n *i18n.Translator
- statikDir http.FileSystem
-}
-
const (
notificationTable = "notification.notifications"
NotifyUserID = "NOTIFICATION"
@@ -42,16 +30,69 @@ const (
labelPolicyTableDef = "adminapi.label_policies"
)
+type Notification struct {
+ handler
+ userEvents *usr_event.UserEventstore
+ systemDefaults sd.SystemDefaults
+ AesCrypto crypto.EncryptionAlgorithm
+ i18n *i18n.Translator
+ statikDir http.FileSystem
+ subscription *eventstore.Subscription
+}
+
+func newNotification(
+ handler handler,
+ userEvents *usr_event.UserEventstore,
+ defaults sd.SystemDefaults,
+ aesCrypto crypto.EncryptionAlgorithm,
+ translator *i18n.Translator,
+ statikDir http.FileSystem,
+) *Notification {
+ h := &Notification{
+ handler: handler,
+ userEvents: userEvents,
+ systemDefaults: defaults,
+ i18n: translator,
+ statikDir: statikDir,
+ AesCrypto: aesCrypto,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (k *Notification) subscribe() {
+ k.subscription = k.es.Subscribe(k.AggregateTypes()...)
+ go func() {
+ for event := range k.subscription.Events {
+ query.ReduceEvent(k, event)
+ }
+ }()
+}
+
func (n *Notification) ViewModel() string {
return notificationTable
}
+func (_ *Notification) AggregateTypes() []models.AggregateType {
+ return []models.AggregateType{es_model.UserAggregate}
+}
+
+func (n *Notification) CurrentSequence(event *models.Event) (uint64, error) {
+ sequence, err := n.view.GetLatestNotificationSequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
func (n *Notification) EventQuery() (*models.SearchQuery, error) {
- sequence, err := n.view.GetLatestNotificationSequence()
+ sequence, err := n.view.GetLatestNotificationSequence("")
if err != nil {
return nil, err
}
- return eventsourcing.UserQuery(sequence.CurrentSequence), nil
+ return usr_event.UserQuery(sequence.CurrentSequence), nil
}
func (n *Notification) Reduce(event *models.Event) (err error) {
@@ -70,13 +111,11 @@ func (n *Notification) Reduce(event *models.Event) (err error) {
err = n.handlePasswordCode(event)
case es_model.DomainClaimed:
err = n.handleDomainClaimed(event)
- default:
- return n.view.ProcessedNotificationSequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return n.view.ProcessedNotificationSequence(event.Sequence, event.CreationDate)
+ return n.view.ProcessedNotificationSequence(event)
}
func (n *Notification) handleInitUserCode(event *models.Event) (err error) {
@@ -229,12 +268,12 @@ func (n *Notification) checkIfAlreadyHandled(userID string, sequence uint64, eve
}
func (n *Notification) getUserEvents(userID string, sequence uint64) ([]*models.Event, error) {
- query, err := eventsourcing.UserByIDQuery(userID, sequence)
+ query, err := usr_event.UserByIDQuery(userID, sequence)
if err != nil {
return nil, err
}
- return n.eventstore.FilterEvents(context.Background(), query)
+ return n.es.FilterEvents(context.Background(), query)
}
func (n *Notification) OnError(event *models.Event, err error) error {
@@ -254,7 +293,7 @@ func getSetNotifyContextData(orgID string) context.Context {
func (n *Notification) getLabelPolicy(ctx context.Context) (*iam_model.LabelPolicyView, error) {
// read from Org
policy, err := n.view.LabelPolicyByAggregateID(authz.GetCtxData(ctx).OrgID, labelPolicyTableOrg)
- if errors.IsNotFound(err) {
+ if caos_errs.IsNotFound(err) {
// read from default
policy, err = n.view.LabelPolicyByAggregateID(n.systemDefaults.IamID, labelPolicyTableDef)
if err != nil {
diff --git a/internal/notification/repository/eventsourcing/handler/notify_user.go b/internal/notification/repository/eventsourcing/handler/notify_user.go
index b41cd93ce7..4b82a16c0c 100644
--- a/internal/notification/repository/eventsourcing/handler/notify_user.go
+++ b/internal/notification/repository/eventsourcing/handler/notify_user.go
@@ -2,14 +2,13 @@ package handler
import (
"context"
- iam_es "github.com/caos/zitadel/internal/iam/repository/eventsourcing"
"github.com/caos/logging"
-
"github.com/caos/zitadel/internal/eventstore"
- "github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
+ iam_es "github.com/caos/zitadel/internal/iam/repository/eventsourcing"
org_model "github.com/caos/zitadel/internal/org/model"
org_events "github.com/caos/zitadel/internal/org/repository/eventsourcing"
org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
@@ -17,33 +16,72 @@ import (
view_model "github.com/caos/zitadel/internal/user/repository/view/model"
)
-type NotifyUser struct {
- handler
- eventstore eventstore.Eventstore
- orgEvents *org_events.OrgEventstore
- iamEvents *iam_es.IAMEventstore
- iamID string
-}
-
const (
userTable = "notification.notify_users"
)
+type NotifyUser struct {
+ handler
+ orgEvents *org_events.OrgEventstore
+ iamEvents *iam_es.IAMEventstore
+ iamID string
+ subscription *eventstore.Subscription
+}
+
+func newNotifyUser(
+ handler handler,
+ orgEvents *org_events.OrgEventstore,
+ iamEvents *iam_es.IAMEventstore,
+ iamID string,
+) *NotifyUser {
+ h := &NotifyUser{
+ handler: handler,
+ orgEvents: orgEvents,
+ iamEvents: iamEvents,
+ iamID: iamID,
+ }
+
+ h.subscribe()
+
+ return h
+}
+
+func (k *NotifyUser) subscribe() {
+ k.subscription = k.es.Subscribe(k.AggregateTypes()...)
+ go func() {
+ for event := range k.subscription.Events {
+ query.ReduceEvent(k, event)
+ }
+ }()
+}
+
func (p *NotifyUser) ViewModel() string {
return userTable
}
-func (p *NotifyUser) EventQuery() (*models.SearchQuery, error) {
- sequence, err := p.view.GetLatestNotifyUserSequence()
+func (_ *NotifyUser) AggregateTypes() []es_models.AggregateType {
+ return []es_models.AggregateType{es_model.UserAggregate, org_es_model.OrgAggregate}
+}
+
+func (p *NotifyUser) CurrentSequence(event *es_models.Event) (uint64, error) {
+ sequence, err := p.view.GetLatestNotifyUserSequence(string(event.AggregateType))
+ if err != nil {
+ return 0, err
+ }
+ return sequence.CurrentSequence, nil
+}
+
+func (p *NotifyUser) EventQuery() (*es_models.SearchQuery, error) {
+ sequence, err := p.view.GetLatestNotifyUserSequence("")
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
- AggregateTypeFilter(es_model.UserAggregate, org_es_model.OrgAggregate).
+ AggregateTypeFilter(p.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
-func (u *NotifyUser) Reduce(event *models.Event) (err error) {
+func (u *NotifyUser) Reduce(event *es_models.Event) (err error) {
switch event.AggregateType {
case es_model.UserAggregate:
return u.ProcessUser(event)
@@ -54,7 +92,7 @@ func (u *NotifyUser) Reduce(event *models.Event) (err error) {
}
}
-func (u *NotifyUser) ProcessUser(event *models.Event) (err error) {
+func (u *NotifyUser) ProcessUser(event *es_models.Event) (err error) {
user := new(view_model.NotifyUser)
switch event.Type {
case es_model.UserAdded,
@@ -93,17 +131,17 @@ func (u *NotifyUser) ProcessUser(event *models.Event) (err error) {
}
u.fillLoginNames(user)
case es_model.UserRemoved:
- return u.view.DeleteNotifyUser(event.AggregateID, event.Sequence, event.CreationDate)
+ return u.view.DeleteNotifyUser(event.AggregateID, event)
default:
- return u.view.ProcessedNotifyUserSequence(event.Sequence, event.CreationDate)
+ return u.view.ProcessedNotifyUserSequence(event)
}
if err != nil {
return err
}
- return u.view.PutNotifyUser(user, user.Sequence, event.CreationDate)
+ return u.view.PutNotifyUser(user, event)
}
-func (u *NotifyUser) ProcessOrg(event *models.Event) (err error) {
+func (u *NotifyUser) ProcessOrg(event *es_models.Event) (err error) {
switch event.Type {
case org_es_model.OrgDomainVerified,
org_es_model.OrgDomainRemoved,
@@ -114,11 +152,11 @@ func (u *NotifyUser) ProcessOrg(event *models.Event) (err error) {
case org_es_model.OrgDomainPrimarySet:
return u.fillPreferredLoginNamesOnOrgUsers(event)
default:
- return u.view.ProcessedNotifyUserSequence(event.Sequence, event.CreationDate)
+ return u.view.ProcessedNotifyUserSequence(event)
}
}
-func (u *NotifyUser) fillLoginNamesOnOrgUsers(event *models.Event) error {
+func (u *NotifyUser) fillLoginNamesOnOrgUsers(event *es_models.Event) error {
org, err := u.orgEvents.OrgByID(context.Background(), org_model.NewOrg(event.ResourceOwner))
if err != nil {
return err
@@ -136,15 +174,15 @@ func (u *NotifyUser) fillLoginNamesOnOrgUsers(event *models.Event) error {
}
for _, user := range users {
user.SetLoginNames(policy, org.Domains)
- err := u.view.PutNotifyUser(user, 0, event.CreationDate)
+ err := u.view.PutNotifyUser(user, event)
if err != nil {
return err
}
}
- return u.view.ProcessedNotifyUserSequence(event.Sequence, event.CreationDate)
+ return u.view.ProcessedNotifyUserSequence(event)
}
-func (u *NotifyUser) fillPreferredLoginNamesOnOrgUsers(event *models.Event) error {
+func (u *NotifyUser) fillPreferredLoginNamesOnOrgUsers(event *es_models.Event) error {
org, err := u.orgEvents.OrgByID(context.Background(), org_model.NewOrg(event.ResourceOwner))
if err != nil {
return err
@@ -165,7 +203,7 @@ func (u *NotifyUser) fillPreferredLoginNamesOnOrgUsers(event *models.Event) erro
}
for _, user := range users {
user.PreferredLoginName = user.GenerateLoginName(org.GetPrimaryDomain().Domain, policy.UserLoginMustBeDomain)
- err := u.view.PutNotifyUser(user, 0, event.CreationDate)
+ err := u.view.PutNotifyUser(user, event)
if err != nil {
return err
}
@@ -190,7 +228,7 @@ func (u *NotifyUser) fillLoginNames(user *view_model.NotifyUser) (err error) {
return nil
}
-func (p *NotifyUser) OnError(event *models.Event, err error) error {
+func (p *NotifyUser) OnError(event *es_models.Event, err error) error {
logging.LogWithFields("SPOOL-9spwf", "id", event.AggregateID).WithError(err).Warn("something went wrong in notify user handler")
return spooler.HandleError(event, err, p.view.GetLatestNotifyUserFailedEvent, p.view.ProcessedNotifyUserFailedEvent, p.view.ProcessedNotifyUserSequence, p.errorCountUntilSkip)
}
diff --git a/internal/notification/repository/eventsourcing/view/notification.go b/internal/notification/repository/eventsourcing/view/notification.go
index baeb75e162..b14242f47e 100644
--- a/internal/notification/repository/eventsourcing/view/notification.go
+++ b/internal/notification/repository/eventsourcing/view/notification.go
@@ -1,20 +1,20 @@
package view
import (
+ "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
notificationTable = "notification.notifications"
)
-func (v *View) GetLatestNotificationSequence() (*repository.CurrentSequence, error) {
- return v.latestSequence(notificationTable)
+func (v *View) GetLatestNotificationSequence(aggregateType string) (*repository.CurrentSequence, error) {
+ return v.latestSequence(notificationTable, aggregateType)
}
-func (v *View) ProcessedNotificationSequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(notificationTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedNotificationSequence(event *models.Event) error {
+ return v.saveCurrentSequence(notificationTable, event)
}
func (v *View) UpdateNotificationSpoolerRunTimestamp() error {
diff --git a/internal/notification/repository/eventsourcing/view/notify_user.go b/internal/notification/repository/eventsourcing/view/notify_user.go
index 44d1a1e32b..f81c986d0a 100644
--- a/internal/notification/repository/eventsourcing/view/notify_user.go
+++ b/internal/notification/repository/eventsourcing/view/notify_user.go
@@ -1,10 +1,11 @@
package view
import (
+ "github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/user/repository/view"
"github.com/caos/zitadel/internal/user/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
- "time"
)
const (
@@ -15,35 +16,32 @@ func (v *View) NotifyUserByID(userID string) (*model.NotifyUser, error) {
return view.NotifyUserByID(v.Db, notifyUserTable, userID)
}
-func (v *View) PutNotifyUser(user *model.NotifyUser, sequence uint64, eventTimestamp time.Time) error {
+func (v *View) PutNotifyUser(user *model.NotifyUser, event *models.Event) error {
err := view.PutNotifyUser(v.Db, notifyUserTable, user)
if err != nil {
return err
}
- if sequence != 0 {
- return v.ProcessedNotifyUserSequence(sequence, eventTimestamp)
- }
- return nil
+ return v.ProcessedNotifyUserSequence(event)
}
func (v *View) NotifyUsersByOrgID(orgID string) ([]*model.NotifyUser, error) {
return view.NotifyUsersByOrgID(v.Db, notifyUserTable, orgID)
}
-func (v *View) DeleteNotifyUser(userID string, eventSequence uint64, eventTimestamp time.Time) error {
+func (v *View) DeleteNotifyUser(userID string, event *models.Event) error {
err := view.DeleteNotifyUser(v.Db, notifyUserTable, userID)
- if err != nil {
- return nil
+ if err != nil && !errors.IsNotFound(err) {
+ return err
}
- return v.ProcessedNotifyUserSequence(eventSequence, eventTimestamp)
+ return v.ProcessedNotifyUserSequence(event)
}
-func (v *View) GetLatestNotifyUserSequence() (*repository.CurrentSequence, error) {
- return v.latestSequence(notifyUserTable)
+func (v *View) GetLatestNotifyUserSequence(aggregateType string) (*repository.CurrentSequence, error) {
+ return v.latestSequence(notifyUserTable, aggregateType)
}
-func (v *View) ProcessedNotifyUserSequence(eventSequence uint64, eventTimestamp time.Time) error {
- return v.saveCurrentSequence(notifyUserTable, eventSequence, eventTimestamp)
+func (v *View) ProcessedNotifyUserSequence(event *models.Event) error {
+ return v.saveCurrentSequence(notifyUserTable, event)
}
func (v *View) UpdateNotifyUserSpoolerRunTimestamp() error {
diff --git a/internal/notification/repository/eventsourcing/view/sequence.go b/internal/notification/repository/eventsourcing/view/sequence.go
index f1868e4f44..8d56cc19b9 100644
--- a/internal/notification/repository/eventsourcing/view/sequence.go
+++ b/internal/notification/repository/eventsourcing/view/sequence.go
@@ -1,24 +1,26 @@
package view
import (
- "github.com/caos/zitadel/internal/view/repository"
"time"
+
+ "github.com/caos/zitadel/internal/eventstore/models"
+ "github.com/caos/zitadel/internal/view/repository"
)
const (
sequencesTable = "notification.current_sequences"
)
-func (v *View) saveCurrentSequence(viewName string, sequence uint64, eventTimestamp time.Time) error {
- return repository.SaveCurrentSequence(v.Db, sequencesTable, viewName, sequence, eventTimestamp)
+func (v *View) saveCurrentSequence(viewName string, event *models.Event) error {
+ return repository.SaveCurrentSequence(v.Db, sequencesTable, viewName, string(event.AggregateType), event.Sequence, event.CreationDate)
}
-func (v *View) latestSequence(viewName string) (*repository.CurrentSequence, error) {
- return repository.LatestSequence(v.Db, sequencesTable, viewName)
+func (v *View) latestSequence(viewName, aggregateType string) (*repository.CurrentSequence, error) {
+ return repository.LatestSequence(v.Db, sequencesTable, viewName, aggregateType)
}
func (v *View) updateSpoolerRunSequence(viewName string) error {
- currentSequence, err := repository.LatestSequence(v.Db, sequencesTable, viewName)
+ currentSequence, err := repository.LatestSequence(v.Db, sequencesTable, viewName, "")
if err != nil {
return err
}
@@ -26,5 +28,8 @@ func (v *View) updateSpoolerRunSequence(viewName string) error {
currentSequence.ViewName = viewName
}
currentSequence.LastSuccessfulSpoolerRun = time.Now()
+ //update all aggregate types
+ //TODO: not sure if all scenarios work as expected
+ currentSequence.AggregateType = ""
return repository.UpdateCurrentSequence(v.Db, sequencesTable, currentSequence)
}
diff --git a/internal/notification/templates/templateData.go b/internal/notification/templates/templateData.go
index ee7b910709..676af69d4b 100644
--- a/internal/notification/templates/templateData.go
+++ b/internal/notification/templates/templateData.go
@@ -24,6 +24,8 @@ func (data *TemplateData) Translate(i18n *i18n.Translator, args map[string]inter
data.Subject = i18n.Localize(data.Subject, nil, langs...)
data.Greeting = i18n.Localize(data.Greeting, args, langs...)
data.Text = html.UnescapeString(i18n.Localize(data.Text, args, langs...))
- data.Href = i18n.Localize(data.Href, nil, langs...)
+ if data.Href != "" {
+ data.Href = i18n.Localize(data.Href, nil, langs...)
+ }
data.ButtonText = i18n.Localize(data.ButtonText, nil, langs...)
}
diff --git a/internal/org/repository/eventsourcing/eventstore_mock_test.go b/internal/org/repository/eventsourcing/eventstore_mock_test.go
index 6d7d175317..f36f48d7f9 100644
--- a/internal/org/repository/eventsourcing/eventstore_mock_test.go
+++ b/internal/org/repository/eventsourcing/eventstore_mock_test.go
@@ -42,7 +42,7 @@ func GetMockChangesOrgOK(ctrl *gomock.Controller) *OrgEventstore {
}
events := []*es_models.Event{
- {AggregateID: "AggregateIDApp", Sequence: 1, AggregateType: repo_model.OrgAggregate, Data: data},
+ {AggregateID: "AggregateID", Sequence: 1, AggregateType: repo_model.OrgAggregate, Data: data},
}
mockEs := mock.NewMockEventstore(ctrl)
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
diff --git a/internal/org/repository/eventsourcing/eventstore_test.go b/internal/org/repository/eventsourcing/eventstore_test.go
index b0c1430b8b..b1b0a75aa3 100644
--- a/internal/org/repository/eventsourcing/eventstore_test.go
+++ b/internal/org/repository/eventsourcing/eventstore_test.go
@@ -179,7 +179,7 @@ func TestOrgEventstore_OrgByID(t *testing.T) {
{
name: "new events found and added success",
fields: fields{Eventstore: newTestEventstore(t).expectFilterEvents([]*es_models.Event{
- {Sequence: 6},
+ {Sequence: 6, AggregateID: "hodor-org"},
}, nil)},
args: args{
ctx: authz.NewMockContext("user", "org"),
diff --git a/internal/org/repository/view/org_member_view.go b/internal/org/repository/view/org_member_view.go
index ef52864b52..c9035d38dc 100644
--- a/internal/org/repository/view/org_member_view.go
+++ b/internal/org/repository/view/org_member_view.go
@@ -17,7 +17,7 @@ func OrgMemberByIDs(db *gorm.DB, table, orgID, userID string) (*model.OrgMemberV
query := repository.PrepareGetByQuery(table, orgIDQuery, userIDQuery)
err := query(db, member)
if caos_errs.IsNotFound(err) {
- return nil, caos_errs.ThrowNotFound(nil, "VIEW-DG1qh", "Errors.Org.MemberNotFound")
+ return nil, caos_errs.ThrowNotFound(nil, "VIEW-gIaTM", "Errors.Org.MemberNotFound")
}
return member, err
}
diff --git a/internal/project/repository/eventsourcing/eventstore.go b/internal/project/repository/eventsourcing/eventstore.go
index 8967c81389..81d60dbcf8 100644
--- a/internal/project/repository/eventsourcing/eventstore.go
+++ b/internal/project/repository/eventsourcing/eventstore.go
@@ -811,12 +811,13 @@ func (es *ProjectEventstore) VerifyOIDCClientSecret(ctx context.Context, project
err = crypto.CompareHash(app.OIDCConfig.ClientSecret, []byte(secret), es.passwordAlg)
spanHash.EndWithError(err)
if err == nil {
- return es.setOIDCClientSecretCheckResult(ctx, existingProject, app.AppID, OIDCClientSecretCheckSucceededAggregate)
+ err = es.setOIDCClientSecretCheckResult(ctx, existingProject, app.AppID, OIDCClientSecretCheckSucceededAggregate)
+ logging.Log("EVENT-AE1vf").OnError(err).Warn("could not push event OIDCClientSecretCheckSucceeded")
+ return nil
}
- if err := es.setOIDCClientSecretCheckResult(ctx, existingProject, app.AppID, OIDCClientSecretCheckFailedAggregate); err != nil {
- return err
- }
- return caos_errs.ThrowInvalidArgument(nil, "EVENT-wg24q", "Errors.Internal")
+ err = es.setOIDCClientSecretCheckResult(ctx, existingProject, app.AppID, OIDCClientSecretCheckFailedAggregate)
+ logging.Log("EVENT-GD1gh").OnError(err).Warn("could not push event OIDCClientSecretCheckFailed")
+ return caos_errs.ThrowInvalidArgument(nil, "EVENT-wg24q", "Errors.Project.OIDCSecretInvalid")
}
func (es *ProjectEventstore) setOIDCClientSecretCheckResult(ctx context.Context, project *proj_model.Project, appID string, check func(*es_models.AggregateCreator, *model.Project, string) es_sdk.AggregateFunc) error {
diff --git a/internal/project/repository/view/application_view.go b/internal/project/repository/view/application_view.go
index 414d7dfcf7..2abfd9f47d 100644
--- a/internal/project/repository/view/application_view.go
+++ b/internal/project/repository/view/application_view.go
@@ -24,7 +24,7 @@ func ApplicationByID(db *gorm.DB, table, projectID, appID string) (*model.Applic
func ApplicationsByProjectID(db *gorm.DB, table, projectID string) ([]*model.ApplicationView, error) {
applications := make([]*model.ApplicationView, 0)
queries := []*proj_model.ApplicationSearchQuery{
- &proj_model.ApplicationSearchQuery{Key: proj_model.AppSearchKeyProjectID, Value: projectID, Method: global_model.SearchMethodEquals},
+ {Key: proj_model.AppSearchKeyProjectID, Value: projectID, Method: global_model.SearchMethodEquals},
}
query := repository.PrepareSearchQuery(table, model.ApplicationSearchRequest{Queries: queries})
_, err := query(db, &applications)
diff --git a/internal/project/repository/view/project_role_view.go b/internal/project/repository/view/project_role_view.go
index 12248b6640..4065439d46 100644
--- a/internal/project/repository/view/project_role_view.go
+++ b/internal/project/repository/view/project_role_view.go
@@ -26,7 +26,7 @@ func ProjectRoleByIDs(db *gorm.DB, table, projectID, orgID, key string) (*model.
func ProjectRolesByProjectID(db *gorm.DB, table, projectID string) ([]*model.ProjectRoleView, error) {
roles := make([]*model.ProjectRoleView, 0)
queries := []*proj_model.ProjectRoleSearchQuery{
- &proj_model.ProjectRoleSearchQuery{Key: proj_model.ProjectRoleSearchKeyProjectID, Value: projectID, Method: global_model.SearchMethodEquals},
+ {Key: proj_model.ProjectRoleSearchKeyProjectID, Value: projectID, Method: global_model.SearchMethodEquals},
}
query := repository.PrepareSearchQuery(table, model.ProjectRoleSearchRequest{Queries: queries})
_, err := query(db, &roles)
@@ -39,9 +39,9 @@ func ProjectRolesByProjectID(db *gorm.DB, table, projectID string) ([]*model.Pro
func ResourceOwnerProjectRolesByKey(db *gorm.DB, table, projectID, resourceOwner, key string) ([]*model.ProjectRoleView, error) {
roles := make([]*model.ProjectRoleView, 0)
queries := []*proj_model.ProjectRoleSearchQuery{
- &proj_model.ProjectRoleSearchQuery{Key: proj_model.ProjectRoleSearchKeyProjectID, Value: projectID, Method: global_model.SearchMethodEquals},
- &proj_model.ProjectRoleSearchQuery{Key: proj_model.ProjectRoleSearchKeyResourceOwner, Value: resourceOwner, Method: global_model.SearchMethodEquals},
- &proj_model.ProjectRoleSearchQuery{Key: proj_model.ProjectRoleSearchKeyKey, Value: key, Method: global_model.SearchMethodEquals},
+ {Key: proj_model.ProjectRoleSearchKeyProjectID, Value: projectID, Method: global_model.SearchMethodEquals},
+ {Key: proj_model.ProjectRoleSearchKeyResourceOwner, Value: resourceOwner, Method: global_model.SearchMethodEquals},
+ {Key: proj_model.ProjectRoleSearchKeyKey, Value: key, Method: global_model.SearchMethodEquals},
}
query := repository.PrepareSearchQuery(table, model.ProjectRoleSearchRequest{Queries: queries})
_, err := query(db, &roles)
@@ -54,8 +54,8 @@ func ResourceOwnerProjectRolesByKey(db *gorm.DB, table, projectID, resourceOwner
func ResourceOwnerProjectRoles(db *gorm.DB, table, projectID, resourceOwner string) ([]*model.ProjectRoleView, error) {
roles := make([]*model.ProjectRoleView, 0)
queries := []*proj_model.ProjectRoleSearchQuery{
- &proj_model.ProjectRoleSearchQuery{Key: proj_model.ProjectRoleSearchKeyProjectID, Value: projectID, Method: global_model.SearchMethodEquals},
- &proj_model.ProjectRoleSearchQuery{Key: proj_model.ProjectRoleSearchKeyResourceOwner, Value: resourceOwner, Method: global_model.SearchMethodEquals},
+ {Key: proj_model.ProjectRoleSearchKeyProjectID, Value: projectID, Method: global_model.SearchMethodEquals},
+ {Key: proj_model.ProjectRoleSearchKeyResourceOwner, Value: resourceOwner, Method: global_model.SearchMethodEquals},
}
query := repository.PrepareSearchQuery(table, model.ProjectRoleSearchRequest{Queries: queries})
_, err := query(db, &roles)
diff --git a/internal/setup/config.go b/internal/setup/config.go
index be3e19099a..01143e7af1 100644
--- a/internal/setup/config.go
+++ b/internal/setup/config.go
@@ -14,6 +14,7 @@ type IAMSetUp struct {
//Step6 *Step6
//Step7 *Step7
//Step8 *Step8
+ //Step9 *Step9
}
func (setup *IAMSetUp) steps(currentDone iam_model.Step) ([]stepV2, error) {
@@ -29,6 +30,7 @@ func (setup *IAMSetUp) steps(currentDone iam_model.Step) ([]stepV2, error) {
//setup.Step6,
//setup.Step7,
//setup.Step8,
+ //setup.Step9,
} {
if step.step() <= currentDone {
continue
diff --git a/internal/setup/step9.go b/internal/setup/step9.go
new file mode 100644
index 0000000000..2733dbb51a
--- /dev/null
+++ b/internal/setup/step9.go
@@ -0,0 +1,74 @@
+package setup
+
+import (
+ "context"
+
+ "github.com/caos/logging"
+
+ "github.com/caos/zitadel/internal/eventstore/models"
+ es_sdk "github.com/caos/zitadel/internal/eventstore/sdk"
+ iam_model "github.com/caos/zitadel/internal/iam/model"
+ iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
+)
+
+type Step9 struct {
+ Passwordless bool
+
+ setup *Setup
+}
+
+func (step *Step9) isNil() bool {
+ return step == nil
+}
+
+func (step *Step9) step() iam_model.Step {
+ return iam_model.Step9
+}
+
+func (step *Step9) init(setup *Setup) {
+ step.setup = setup
+}
+
+func (step *Step9) execute(ctx context.Context) (*iam_model.IAM, error) {
+ if !step.Passwordless {
+ return step.setup.IamEvents.IAMByID(ctx, step.setup.iamID)
+ }
+ iam, agg, err := step.setPasswordlessAllowedInPolicy(ctx)
+ if err != nil {
+ logging.Log("SETUP-Gdbjq").WithField("step", step.step()).WithError(err).Error("unable to finish setup (add default mfa to login policy)")
+ return nil, err
+ }
+ iam, agg2, err := step.addMFAToPolicy(ctx)
+ if err != nil {
+ logging.Log("SETUP-Gdbjq").WithField("step", step.step()).WithError(err).Error("unable to finish setup (add default mfa to login policy)")
+ return nil, err
+ }
+ agg.Events = append(agg.Events, agg2.Events...)
+ iam, agg, push, err := step.setup.IamEvents.PrepareSetupDone(ctx, iam, agg, step.step())
+ if err != nil {
+ logging.Log("SETUP-Cnf21").WithField("step", step.step()).WithError(err).Error("unable to finish setup (prepare setup done)")
+ return nil, err
+ }
+ err = es_sdk.PushAggregates(ctx, push, iam.AppendEvents, agg)
+ if err != nil {
+ logging.Log("SETUP-NFq21").WithField("step", step.step()).WithError(err).Error("unable to finish setup")
+ return nil, err
+ }
+ return iam_es_model.IAMToModel(iam), nil
+}
+
+func (step *Step9) setPasswordlessAllowedInPolicy(ctx context.Context) (*iam_es_model.IAM, *models.Aggregate, error) {
+ logging.Log("SETUP-DAd1h").Info("enabling passwordless in loginPolicy")
+ iam, err := step.setup.IamEvents.IAMByID(ctx, step.setup.iamID)
+ if err != nil {
+ return nil, nil, err
+ }
+ iam.DefaultLoginPolicy.AggregateID = step.setup.iamID
+ iam.DefaultLoginPolicy.PasswordlessType = iam_model.PasswordlessTypeAllowed
+ return step.setup.IamEvents.PrepareChangeLoginPolicy(ctx, iam.DefaultLoginPolicy)
+}
+
+func (step *Step9) addMFAToPolicy(ctx context.Context) (*iam_es_model.IAM, *models.Aggregate, error) {
+ logging.Log("SETUP-DAd1h").Info("adding MFA to loginPolicy")
+ return step.setup.IamEvents.PrepareAddMultiFactorToLoginPolicy(ctx, step.setup.iamID, iam_model.MultiFactorTypeU2FWithPIN)
+}
diff --git a/internal/static/i18n/de.yaml b/internal/static/i18n/de.yaml
index 1749bdc67c..41d3b104bf 100644
--- a/internal/static/i18n/de.yaml
+++ b/internal/static/i18n/de.yaml
@@ -4,6 +4,8 @@ Errors:
OriginNotAllowed: Dieser "Origin" ist nicht freigeschaltet
User:
NotFound: Benutzer konnte nicht gefunden werden
+ NotFoundOnOrg: Benutzer konnte in der gewünschten Organisation nicht gefunden werden
+ NotAllowedOrg: Benutzer gehört nicht der benötigten Organisation an
UserIDMissing: User ID fehlt
OrgIamPolicyNil: Organisations Policy ist leer
EmailAsUsernameNotAllowed: Benutzername darf keine E-Mail Adresse sein
@@ -169,6 +171,7 @@ Errors:
GrantNotExists: Projekt Grant existiert nicht
GrantHasNotExistingRole: Eine der Rollen existiert nicht auf dem Projekt
UserIDMisisng: User ID fehlt
+ OIDCSecretInvalid: Client Secret ist ungültig
IAM:
Member:
RolesNotChanged: Rollen wurden nicht verändert
@@ -466,9 +469,16 @@ EventTypes:
login:
added: Login Richtlinie hinzugefügt
changed: Login Richtlinie geändert
+ removed: Login Richtline gelöscht
idpprovider:
added: Idp Provider zu Login Richtlinie hinzugefügt
removed: Idp Provider aus Login Richtlinie gelöscht
+ secondfactor:
+ added: Zweitfaktor zu Login Richtlinie hinzugefügt
+ removed: Zweitfaktor aus Login Richtlinie gelöscht
+ multifactor:
+ added: Multifaktor zu Login Richtlinie hinzugefügt
+ removed: Multifaktor aus Login Richtlinie gelöscht
password:
complexity:
added: Passwort Komplexitäts Richtlinie hinzugefügt
diff --git a/internal/static/i18n/en.yaml b/internal/static/i18n/en.yaml
index 6ae31d5862..d2a7c1f4bb 100644
--- a/internal/static/i18n/en.yaml
+++ b/internal/static/i18n/en.yaml
@@ -4,6 +4,8 @@ Errors:
OriginNotAllowed: This "Origin" is not allowed
User:
NotFound: User could not be found
+ NotFoundOnOrg: User could not be found on chosen organisation
+ NotAllowedOrg: User is no member of the required organisation
UserIDMissing: User ID missing
OrgIamPolicyNil: Organisation Policy is empty
EmailAsUsernameNotAllowed: Email is not allowed as username
@@ -169,6 +171,7 @@ Errors:
GrantNotExists: Project grant doesn't exist
GrantHasNotExistingRole: One role doesn't exist on project
UserIDMisisng: User ID missing
+ OIDCSecretInvalid: Client Secret is invalid
IAM:
Member:
RolesNotChanged: Roles habe not been changed
@@ -463,9 +466,16 @@ EventTypes:
login:
added: Login Policy added
changed: Login Policy changed
+ removed: Login Policy removed
idpprovider:
added: Idp Provider added to Login Policy
removed: Idp Provider removed from Login Policy
+ secondfactor:
+ added: Second factor added to Login Policy
+ removed: Second factor removed from Login Policy
+ multifactor:
+ added: Multi factor added to Login Policy
+ removed: Multi factor removed from Login Policy
password:
complexity:
added: Password complexity policy added
diff --git a/internal/ui/login/handler/external_login_handler.go b/internal/ui/login/handler/external_login_handler.go
index 2bb2d0d6e7..1d7455e91f 100644
--- a/internal/ui/login/handler/external_login_handler.go
+++ b/internal/ui/login/handler/external_login_handler.go
@@ -188,16 +188,10 @@ func (l *Login) handleAutoRegister(w http.ResponseWriter, r *http.Request, authR
ObjectRoot: models.ObjectRoot{AggregateID: iam.GlobalOrgID},
Roles: []string{orgProjectCreatorRole},
}
- if authReq.GetScopeOrgPrimaryDomain() != "" {
- primaryDomain := authReq.GetScopeOrgPrimaryDomain()
- org, err := l.authRepo.GetOrgByPrimaryDomain(primaryDomain)
- if err != nil {
- l.renderExternalNotFoundOption(w, r, authReq, err)
- }
- if org.ID != iam.GlobalOrgID {
- member = nil
- resourceOwner = org.ID
- }
+
+ if authReq.RequestedOrgID != "" && authReq.RequestedOrgID != iam.GlobalOrgID {
+ member = nil
+ resourceOwner = authReq.RequestedOrgID
}
orgIamPolicy, err := l.getOrgIamPolicy(r, resourceOwner)
diff --git a/internal/ui/login/handler/external_register_handler.go b/internal/ui/login/handler/external_register_handler.go
index 0d8079adeb..3d2834bb47 100644
--- a/internal/ui/login/handler/external_register_handler.go
+++ b/internal/ui/login/handler/external_register_handler.go
@@ -85,17 +85,9 @@ func (l *Login) handleExternalUserRegister(w http.ResponseWriter, r *http.Reques
Roles: []string{orgProjectCreatorRole},
}
- if authReq.GetScopeOrgPrimaryDomain() != "" {
- primaryDomain := authReq.GetScopeOrgPrimaryDomain()
- org, err := l.authRepo.GetOrgByPrimaryDomain(primaryDomain)
- if err != nil {
- l.renderRegisterOption(w, r, authReq, err)
- return
- }
- if org.ID != iam.GlobalOrgID {
- member = nil
- resourceOwner = org.ID
- }
+ if authReq.RequestedOrgID != "" && authReq.RequestedOrgID != iam.GlobalOrgID {
+ member = nil
+ resourceOwner = authReq.RequestedOrgID
}
orgIamPolicy, err := l.getOrgIamPolicy(r, resourceOwner)
if err != nil {
diff --git a/internal/ui/login/handler/mfa_verify_handler.go b/internal/ui/login/handler/mfa_verify_handler.go
index 5e3b5c5a8f..3d284e01aa 100644
--- a/internal/ui/login/handler/mfa_verify_handler.go
+++ b/internal/ui/login/handler/mfa_verify_handler.go
@@ -60,6 +60,9 @@ func (l *Login) renderMFAVerifySelected(w http.ResponseWriter, r *http.Request,
case model.MFATypeOTP:
data.MFAProviders = removeSelectedProviderFromList(verificationStep.MFAProviders, model.MFATypeOTP)
data.SelectedMFAProvider = model.MFATypeOTP
+ default:
+ l.renderError(w, r, authReq, err)
+ return
}
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplMFAVerify], data, nil)
}
diff --git a/internal/ui/login/handler/passwordless_login_handler.go b/internal/ui/login/handler/passwordless_login_handler.go
index ee0ae68579..7523e3d1f6 100644
--- a/internal/ui/login/handler/passwordless_login_handler.go
+++ b/internal/ui/login/handler/passwordless_login_handler.go
@@ -13,6 +13,16 @@ const (
tmplPasswordlessVerification = "passwordlessverification"
)
+type passwordlessData struct {
+ webAuthNData
+ PasswordLogin bool
+}
+
+type passwordlessFormData struct {
+ webAuthNFormData
+ PasswordLogin bool `schema:"passwordlogin"`
+}
+
func (l *Login) renderPasswordlessVerification(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, err error) {
var errType, errMessage, credentialData string
var webAuthNLogin *user_model.WebAuthNLogin
@@ -26,20 +36,31 @@ func (l *Login) renderPasswordlessVerification(w http.ResponseWriter, r *http.Re
if webAuthNLogin != nil {
credentialData = base64.RawURLEncoding.EncodeToString(webAuthNLogin.CredentialAssertionData)
}
- data := &webAuthNData{
- userData: l.getUserData(r, authReq, "Login Passwordless", errType, errMessage),
- CredentialCreationData: credentialData,
+ var passwordLogin bool
+ if authReq.LoginPolicy != nil {
+ passwordLogin = authReq.LoginPolicy.AllowUsernamePassword
+ }
+ data := &passwordlessData{
+ webAuthNData{
+ userData: l.getUserData(r, authReq, "Login Passwordless", errType, errMessage),
+ CredentialCreationData: credentialData,
+ },
+ passwordLogin,
}
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplPasswordlessVerification], data, nil)
}
func (l *Login) handlePasswordlessVerification(w http.ResponseWriter, r *http.Request) {
- formData := new(webAuthNFormData)
+ formData := new(passwordlessFormData)
authReq, err := l.getAuthRequestAndParseData(r, formData)
if err != nil {
l.renderError(w, r, authReq, err)
return
}
+ if formData.PasswordLogin {
+ l.renderPassword(w, r, authReq, nil)
+ return
+ }
credData, err := base64.URLEncoding.DecodeString(formData.CredentialData)
if err != nil {
l.renderPasswordlessVerification(w, r, authReq, err)
diff --git a/internal/ui/login/handler/register_handler.go b/internal/ui/login/handler/register_handler.go
index 4ec4eb1bf8..ffb9d91731 100644
--- a/internal/ui/login/handler/register_handler.go
+++ b/internal/ui/login/handler/register_handler.go
@@ -1,9 +1,10 @@
package handler
import (
- "golang.org/x/text/language"
"net/http"
+ "golang.org/x/text/language"
+
"github.com/caos/zitadel/internal/auth_request/model"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/models"
@@ -71,17 +72,9 @@ func (l *Login) handleRegisterCheck(w http.ResponseWriter, r *http.Request) {
ObjectRoot: models.ObjectRoot{AggregateID: iam.GlobalOrgID},
Roles: []string{orgProjectCreatorRole},
}
- if authRequest.GetScopeOrgPrimaryDomain() != "" {
- primaryDomain := authRequest.GetScopeOrgPrimaryDomain()
- org, err := l.authRepo.GetOrgByPrimaryDomain(primaryDomain)
- if err != nil {
- l.renderRegisterOption(w, r, authRequest, err)
- return
- }
- if org.ID != iam.GlobalOrgID {
- member = nil
- resourceOwner = org.ID
- }
+ if authRequest.RequestedOrgID != "" && authRequest.RequestedOrgID != iam.GlobalOrgID {
+ member = nil
+ resourceOwner = authRequest.RequestedOrgID
}
user, err := l.authRepo.Register(setContext(r.Context(), resourceOwner), data.toUserModel(), member, resourceOwner)
if err != nil {
diff --git a/internal/ui/login/handler/register_org_handler.go b/internal/ui/login/handler/register_org_handler.go
index c1a4b8dc6e..ea2f7a739d 100644
--- a/internal/ui/login/handler/register_org_handler.go
+++ b/internal/ui/login/handler/register_org_handler.go
@@ -1,9 +1,9 @@
package handler
import (
- auth_model "github.com/caos/zitadel/internal/auth/model"
"net/http"
+ auth_model "github.com/caos/zitadel/internal/auth/model"
"github.com/caos/zitadel/internal/auth_request/model"
caos_errs "github.com/caos/zitadel/internal/errors"
org_model "github.com/caos/zitadel/internal/org/model"
@@ -15,14 +15,14 @@ const (
)
type registerOrgFormData struct {
- OrgName string `schema:"orgname"`
- Email string `schema:"email"`
- Username string `schema:"username"`
- Firstname string `schema:"firstname"`
- Lastname string `schema:"lastname"`
- Password string `schema:"register-password"`
- Password2 string `schema:"register-password-confirmation"`
- TermsConfirm bool `schema:"terms-confirm"`
+ RegisterOrgName string `schema:"orgname"`
+ Email string `schema:"email"`
+ Username string `schema:"username"`
+ Firstname string `schema:"firstname"`
+ Lastname string `schema:"lastname"`
+ Password string `schema:"register-password"`
+ Password2 string `schema:"register-password-confirmation"`
+ TermsConfirm bool `schema:"terms-confirm"`
}
type registerOrgData struct {
@@ -140,6 +140,6 @@ func (d registerOrgFormData) toUserModel() *usr_model.User {
func (d registerOrgFormData) toOrgModel() *org_model.Org {
return &org_model.Org{
- Name: d.OrgName,
+ Name: d.RegisterOrgName,
}
}
diff --git a/internal/ui/login/handler/renderer.go b/internal/ui/login/handler/renderer.go
index dad96049cb..6dbf8d2dce 100644
--- a/internal/ui/login/handler/renderer.go
+++ b/internal/ui/login/handler/renderer.go
@@ -267,6 +267,7 @@ func (l *Login) getBaseData(r *http.Request, authReq *model.AuthRequest, title s
Theme: l.getTheme(r),
ThemeMode: l.getThemeMode(r),
OrgID: l.getOrgID(authReq),
+ OrgName: l.getOrgName(authReq),
AuthReqID: getRequestID(authReq, r),
CSRF: csrf.TemplateField(r),
Nonce: http_mw.GetNonce(r),
@@ -312,20 +313,17 @@ func (l *Login) getOrgID(authReq *model.AuthRequest) string {
if authReq == nil {
return ""
}
- if authReq.UserOrgID != "" {
- return authReq.UserOrgID
+ if authReq.RequestedOrgID != "" {
+ return authReq.RequestedOrgID
}
- if authReq.Request == nil {
+ return authReq.UserOrgID
+}
+
+func (l *Login) getOrgName(authReq *model.AuthRequest) string {
+ if authReq == nil {
return ""
}
- primaryDomain := authReq.GetScopeOrgPrimaryDomain()
- if primaryDomain != "" {
- org, _ := l.authRepo.GetOrgByPrimaryDomain(primaryDomain)
- if org != nil {
- return org.ID
- }
- }
- return ""
+ return authReq.RequestedOrgName
}
func getRequestID(authReq *model.AuthRequest, r *http.Request) string {
@@ -355,6 +353,7 @@ type baseData struct {
Theme string
ThemeMode string
OrgID string
+ OrgName string
AuthReqID string
CSRF template.HTML
Nonce string
diff --git a/internal/ui/login/static/i18n/de.yaml b/internal/ui/login/static/i18n/de.yaml
index d0a303da13..fc86aaa0ad 100644
--- a/internal/ui/login/static/i18n/de.yaml
+++ b/internal/ui/login/static/i18n/de.yaml
@@ -16,6 +16,7 @@ Login:
Loginname: Loginname
LoginnamePlaceHolder: username@domain
ExternalLogin: Melde dich mit einem externen Benutzer an
+ MustBeMemberOfOrg: Der Benutzer muss der Organisation {{.OrgName}} angehören.
UserSelection:
Title: Account auswählen
@@ -25,6 +26,7 @@ UserSelection:
OtherUser: Anderer Benutzer
SessionState0: aktiv
SessionState1: inaktiv
+ MustBeMemberOfOrg: Der Benutzer muss der Organisation {{.OrgName}} angehören.
UsernameChange:
Title: Usernamen ändern
@@ -207,6 +209,7 @@ Actions:
RegisterToken: Token registrieren
ValidateToken: Token validieren
Recreate: erneut erstellen
+ PasswordLogin: Mit Passwort anmelden
Errors:
Internal: Es ist ein interner Fehler aufgetreten
@@ -216,6 +219,8 @@ Errors:
RequestTypeNotSupported: Requesttyp wird nicht unterstürzt
User:
NotFound: Benutzer konnte nicht gefunden werden
+ NotFoundOnOrg: Benutzer konnte in der gewünschten Organisation nicht gefunden werden
+ NotAllowedOrg: Benutzer gehört nicht der benötigten Organisation an
NotMatchingUserID: User stimm nicht mit User in Auth Request überein
UserIDMissing: UserID ist leer
Invalid: Userdaten sind ungültig
diff --git a/internal/ui/login/static/i18n/en.yaml b/internal/ui/login/static/i18n/en.yaml
index a66f72f465..73ae3d217a 100644
--- a/internal/ui/login/static/i18n/en.yaml
+++ b/internal/ui/login/static/i18n/en.yaml
@@ -6,6 +6,7 @@ Login:
Loginname: Loginname
LoginnamePlaceHolder: username@domain
ExternalLogin: Login with an external user.
+ MustBeMemberOfOrg: The user must be mermber of the {{.OrgDomain}} organisation.
UserSelection:
Title: Select account
@@ -15,6 +16,7 @@ UserSelection:
OtherUser: Other User
SessionState0: active
SessionState1: inactive
+ MustBeMemberOfOrg: The user must be mermber of the {{.OrgDomain}} organisation.
Password:
Title: Password
@@ -207,6 +209,7 @@ Actions:
RegisterToken: Register Token
ValidateToken: Validate Token
Recreate: recreate
+ PasswordLogin: Login with password
Errors:
Internal: An internal error occured
@@ -216,6 +219,8 @@ Errors:
RequestTypeNotSupported: Request type is not supported
User:
NotFound: User could not be found
+ NotFoundOnOrg: User could not be found on chosen organisation
+ NotAllowedOrg: User is no member of the required organisation
NotMatchingUserID: User and user in authrequest don't match
UserIDMissing: UserID is empty
Invalid: Invalid userdata
diff --git a/internal/ui/login/static/resources/themes/caos/css/dark.css b/internal/ui/login/static/resources/themes/caos/css/dark.css
index 49c8e83bed..7506180196 100644
--- a/internal/ui/login/static/resources/themes/caos/css/dark.css
+++ b/internal/ui/login/static/resources/themes/caos/css/dark.css
@@ -75,7 +75,6 @@
font-family: Lato;
font-size: 16px;
font-weight: 400;
- cursor: default !important;
}
body {
@@ -227,6 +226,7 @@ form button.user-selection .profile-image, .login-profile .profile-image {
width: 80px;
background-position: center;
background-repeat: no-repeat;
+ background-size: contain;
background-image: url("../../../images/icon-user-dark.png");
}
@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {
@@ -334,10 +334,6 @@ form button.clean * {
form .user-selection-list {
margin-bottom: 40px;
}
-form button.user-selection .profile-image {
- height: 80px;
- width: 80px;
-}
form button.user-selection .sessionstate {
display: inline-block;
height: 20px;
@@ -360,7 +356,7 @@ form button.user-selection > div {
position: relative;
}
form button.user-selection > div.names {
- margin: 15px;
+ margin: 0 15px;
}
form button.user-selection > div.names .displayname {
font-size: 1.4rem;
@@ -368,6 +364,21 @@ form button.user-selection > div.names .displayname {
form button.user-selection > div.names .loginname {
color: #898989;
}
+form button.user-selection:disabled {
+ background: transparent;
+ border: none;
+ cursor: not-allowed;
+}
+form button.user-selection:disabled .profile-image {
+ opacity: 0.3;
+}
+form button.user-selection:disabled .sessionstate {
+ background-color: #282828;
+}
+form button.user-selection:disabled .names .displayname, form button.user-selection:disabled .names .loginname {
+ font-style: italic;
+ color: #444444;
+}
.user-selection + form button.other-user {
margin-top: 80px;
}
diff --git a/internal/ui/login/static/resources/themes/caos/css/dark.css.map b/internal/ui/login/static/resources/themes/caos/css/dark.css.map
index 2e58686f16..5c2f220cfe 100644
--- a/internal/ui/login/static/resources/themes/caos/css/dark.css.map
+++ b/internal/ui/login/static/resources/themes/caos/css/dark.css.map
@@ -1 +1 @@
-{"version":3,"sourceRoot":"","sources":["../../scss/fonts.scss","../../scss/main.scss","../../scss/caos/variables.scss","../../scss/variables.scss"],"names":[],"mappings":"AACA;EACI;EACA;;AAIJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAIJ;EACI;EACA;EACA;EACA;AAA6D;EAC7D;;AC5EJ;EACI;EACA,aCMW;EDLX;EACA;EACA;;;AAGJ;EACI;;AAEA;EACI;;;AAIR;EACI;EACA;EACA;EACA,kBCNc;EDOd,OCNQ;EDOR;EACA;EACA;;;AAMJ;EACI,OChBQ;EDiBR,aCvBS;EDwBT;EACA,WE9BS;EF+BT;;;AAGJ;EACI,OCxBQ;EDyBR,aC/BS;EDgCT;EACA,WErCU;;;AFwCd;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OC5DW;ED6DX;EACA;;AAEA;EACI,OChEY;;ADmEhB;EACI;;;AAIR;EACI,kBC5Ec;ED6Ed,OC3EW;ED4EX;EACA;EACA;EACA;EACA,QE7FU;EF8FV;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI,kBCzFY;ED0FZ,OC7FU;ED8FV;;AAGJ;EACI,kBChGO;EDiGP,OClGI;EDmGJ;;AACA;EACI,kBCnGQ;;ADuGhB;EACI,kBE7FW;EF8FX;;AAEA;EACI,kBEjGO;EFkGP;;AAIR;EACI;EACA;EACA;EACA;EACA,OErGa;EFsGb,kBErGmB;;AFuGnB;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;;;AAOZ;EACI,kBEnImB;EFoInB,OClJQ;EDmJR,QE/JU;EFgKV;EACA;EACA;;;AAIA;EACI;EACA;EACA;EACA;EE9JN;;AACA;EFyJE;IExJA;IACA;;;AF+JA;EElKF;;AACA;EFiKE;IEhKA;IACA;;;;AFsKA;EACI;EACA;;AAGJ;EACI;EACA;;AAEA;EACI,WE5LE;EF6LF;;AAGJ;EACI;EACA;EACA;EACA,OE/KC;;;AFqLT;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA,OCpOA;;ADwOR;EACI,OE7NK;EF8NL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;AAIR;EACI;EACA;EACA,OCnQI;EDoQJ;EACA;EACA;EACA;;AAEA;EACI;EACA,kBE7PW;;AFgQf;EACI;;AAIR;EACI;;AAKA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA,cEtRO;EFuRP;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;;AAKR;EACI;;AAEA;EACI;;AAEA;EACI;;AAEJ;EACI,OElTP;;AFyTL;EACI;;AAEJ;EACI;EACA;EACA;EACA;EE5UV;;AACA;EFuUM;IEtUJ;IACA;;;AF8UQ;EACI;EACA;EEnVd;;AACA;EFgVU;IE/UR;IACA;;;AFqVI;EACI;EACA;;AAIR;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA,OE1VN;;AF+VE;EACI,OEjWL;;AFsWP;EACI;;AACA;EACI;EACA;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI,MC7YI;;ADgZR;EACI,MClZU;;;ADuZd;EACI;EACA;;;AAIR;EAEQ;EAEJ;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA;;;AAGJ;EACI;EACA;EACA;;;AAGJ;EACI,OEjbO;;;AFobX;EACI;;;AAGJ;EACI","file":"dark.css"}
\ No newline at end of file
+{"version":3,"sourceRoot":"","sources":["../../scss/fonts.scss","../../scss/main.scss","../../scss/caos/variables.scss","../../scss/variables.scss"],"names":[],"mappings":"AACA;EACI;EACA;;AAIJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAIJ;EACI;EACA;EACA;EACA;AAA6D;EAC7D;;AC5EJ;EACI;EACA,aCMW;EDLX;EACA;;;AAGJ;EACI;;AAEA;EACI;;;AAIR;EACI;EACA;EACA;EACA,kBCLc;EDMd,OCLQ;EDMR;EACA;EACA;;;AAMJ;EACI,OCfQ;EDgBR,aCtBS;EDuBT;EACA,WE7BS;EF8BT;;;AAGJ;EACI,OCvBQ;EDwBR,aC9BS;ED+BT;EACA,WEpCU;;;AFuCd;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OC3DW;ED4DX;EACA;;AAEA;EACI,OC/DY;;ADkEhB;EACI;;;AAIR;EACI,kBC3Ec;ED4Ed,OC1EW;ED2EX;EACA;EACA;EACA;EACA,QE5FU;EF6FV;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI,kBCxFY;EDyFZ,OC5FU;ED6FV;;AAGJ;EACI,kBC/FO;EDgGP,OCjGI;EDkGJ;;AACA;EACI,kBClGQ;;ADsGhB;EACI,kBE5FW;EF6FX;;AAEA;EACI,kBEhGO;EFiGP;;AAIR;EACI;EACA;EACA;EACA;EACA,OEpGa;EFqGb,kBEpGmB;;AFsGnB;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;;;AAOZ;EACI,kBElImB;EFmInB,OCjJQ;EDkJR,QE9JU;EF+JV;EACA;EACA;;;AAIA;EACI;EACA;EACA;EACA;EACA;EE9JN;;AACA;EFwJE;IEvJA;IACA;;;AF+JA;EElKF;;AACA;EFiKE;IEhKA;IACA;;;;AFsKA;EACI;EACA;;AAGJ;EACI;EACA;;AAEA;EACI,WE5LE;EF6LF;;AAGJ;EACI;EACA;EACA;EACA,OE/KC;;;AFqLT;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA,OCpOA;;ADwOR;EACI,OE7NK;EF8NL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;AAIR;EACI;EACA;EACA,OCnQI;EDoQJ;EACA;EACA;EACA;;AAEA;EACI;EACA,kBE7PW;;AFgQf;EACI;;AAIR;EACI;;AAMA;EACI;EACA;EACA;EACA;EACA,cElRO;EFmRP;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;;AAKR;EACI;;AAEA;EACI;;AAEA;EACI;;AAEJ;EACI,OE9SP;;AFmTL;EACI;EACA;EACA;;AAEA;EACI;;AAGJ;EACI,kBC1UE;;AD8UF;EACI;EACA;;AAOZ;EACI;;AAEJ;EACI;EACA;EACA;EACA;EE7VV;;AACA;EFwVM;IEvVJ;IACA;;;AF+VQ;EACI;EACA;EEpWd;;AACA;EFiWU;IEhWR;IACA;;;AFsWI;EACI;EACA;;AAIR;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA,OE3WN;;AFgXE;EACI,OElXL;;AFuXP;EACI;;AACA;EACI;EACA;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI,MC9ZI;;ADiaR;EACI,MCnaU;;;ADwad;EACI;EACA;;;AAIR;EAEQ;EAEJ;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA;;;AAGJ;EACI;EACA;EACA;;;AAGJ;EACI,OElcO;;;AFqcX;EACI;;;AAGJ;EACI","file":"dark.css"}
\ No newline at end of file
diff --git a/internal/ui/login/static/resources/themes/caos/css/light.css b/internal/ui/login/static/resources/themes/caos/css/light.css
index c4cd152ea1..1d905b2969 100644
--- a/internal/ui/login/static/resources/themes/caos/css/light.css
+++ b/internal/ui/login/static/resources/themes/caos/css/light.css
@@ -75,7 +75,6 @@
font-family: Lato;
font-size: 16px;
font-weight: 400;
- cursor: default !important;
}
body {
@@ -227,6 +226,7 @@ form button.user-selection .profile-image, .login-profile .profile-image {
width: 80px;
background-position: center;
background-repeat: no-repeat;
+ background-size: contain;
background-image: url("../../../images/icon-user-dark.png");
}
@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {
@@ -334,10 +334,6 @@ form button.clean * {
form .user-selection-list {
margin-bottom: 40px;
}
-form button.user-selection .profile-image {
- height: 80px;
- width: 80px;
-}
form button.user-selection .sessionstate {
display: inline-block;
height: 20px;
@@ -360,7 +356,7 @@ form button.user-selection > div {
position: relative;
}
form button.user-selection > div.names {
- margin: 15px;
+ margin: 0 15px;
}
form button.user-selection > div.names .displayname {
font-size: 1.4rem;
@@ -368,6 +364,21 @@ form button.user-selection > div.names .displayname {
form button.user-selection > div.names .loginname {
color: #898989;
}
+form button.user-selection:disabled {
+ background: transparent;
+ border: none;
+ cursor: not-allowed;
+}
+form button.user-selection:disabled .profile-image {
+ opacity: 0.3;
+}
+form button.user-selection:disabled .sessionstate {
+ background-color: #282828;
+}
+form button.user-selection:disabled .names .displayname, form button.user-selection:disabled .names .loginname {
+ font-style: italic;
+ color: #444444;
+}
.user-selection + form button.other-user {
margin-top: 80px;
}
diff --git a/internal/ui/login/static/resources/themes/caos/css/light.css.map b/internal/ui/login/static/resources/themes/caos/css/light.css.map
index 6c3f74693e..18d1ec38a3 100644
--- a/internal/ui/login/static/resources/themes/caos/css/light.css.map
+++ b/internal/ui/login/static/resources/themes/caos/css/light.css.map
@@ -1 +1 @@
-{"version":3,"sourceRoot":"","sources":["../../scss/fonts.scss","../../scss/main.scss","../../scss/caos/variables.scss","../../scss/variables.scss","../../scss/light.scss"],"names":[],"mappings":"AACA;EACI;EACA;;AAIJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAIJ;EACI;EACA;EACA;EACA;AAA6D;EAC7D;;AC5EJ;EACI;EACA,aCMW;EDLX;EACA;EACA;;;AAGJ;EACI;;AAEA;EACI;;;AAIR;EACI;EACA;EACA;EACA,kBCNc;EDOd,OCNQ;EDOR;EACA;EACA;;;AAMJ;EACI,OChBQ;EDiBR,aCvBS;EDwBT;EACA,WE9BS;EF+BT;;;AAGJ;EACI,OCxBQ;EDyBR,aC/BS;EDgCT;EACA,WErCU;;;AFwCd;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OC5DW;ED6DX;EACA;;AAEA;EACI,OChEY;;ADmEhB;EACI;;;AAIR;EACI,kBC5Ec;ED6Ed,OC3EW;ED4EX;EACA;EACA;EACA;EACA,QE7FU;EF8FV;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI,kBCzFY;ED0FZ,OC7FU;ED8FV;;AAGJ;EACI,kBChGO;EDiGP,OClGI;EDmGJ;;AACA;EACI,kBCnGQ;;ADuGhB;EACI,kBE7FW;EF8FX;;AAEA;EACI,kBEjGO;EFkGP;;AAIR;EACI;EACA;EACA;EACA;EACA,OErGa;EFsGb,kBErGmB;;AFuGnB;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;;;AAOZ;EACI,kBEnImB;EFoInB,OClJQ;EDmJR,QE/JU;EFgKV;EACA;EACA;;;AAIA;EACI;EACA;EACA;EACA;EE9JN;;AACA;EFyJE;IExJA;IACA;;;AF+JA;EElKF;;AACA;EFiKE;IEhKA;IACA;;;;AFsKA;EACI;EACA;;AAGJ;EACI;EACA;;AAEA;EACI,WE5LE;EF6LF;;AAGJ;EACI;EACA;EACA;EACA,OE/KC;;;AFqLT;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA,OCpOA;;ADwOR;EACI,OE7NK;EF8NL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;AAIR;EACI;EACA;EACA,OCnQI;EDoQJ;EACA;EACA;EACA;;AAEA;EACI;EACA,kBE7PW;;AFgQf;EACI;;AAIR;EACI;;AAKA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA,cEtRO;EFuRP;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;;AAKR;EACI;;AAEA;EACI;;AAEA;EACI;;AAEJ;EACI,OElTP;;AFyTL;EACI;;AAEJ;EACI;EACA;EACA;EACA;EE5UV;;AACA;EFuUM;IEtUJ;IACA;;;AF8UQ;EACI;EACA;EEnVd;;AACA;EFgVU;IE/UR;IACA;;;AFqVI;EACI;EACA;;AAIR;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA,OE1VN;;AF+VE;EACI,OEjWL;;AFsWP;EACI;;AACA;EACI;EACA;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI,MC7YI;;ADgZR;EACI,MClZU;;;ADuZd;EACI;EACA;;;AAIR;EAEQ;EAEJ;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA;;;AAGJ;EACI;EACA;EACA;;;AAGJ;EACI,OEjbO;;;AFobX;EACI;;;AAGJ;EACI;;;AG9dJ;EACI,kBFeQ;EEdR,OFac;;AERd;EACI;;AAGJ;EACI,OFGU;;AEAd;EACI;EACA;EACA;;AAEA;EACI,kBFIa;EEHb;EACA,ODyBgB;;ACtBpB;EACI,kBFVG;EEWH,ODoBgB;ECnBhB;EACA;;AACA;EACI,kBFdI;;AEkBZ;EACI,kBDRO;ECSP;;AAEA;EACI,kBDZG;ECaH;;AAIR;EACI,OFhCM;;AEkCN;EACI;EACA,kBDHY;;ACQhB;EDxCV;;AACA;ECuCU;IDtCR;IACA;;;ACyCQ;EACI,kBDbY;;ACeZ;ED/Cd;;AACA;EC8Cc;ID7CZ;IACA;;;ACmDQ;EDtDV;;AACA;ECqDU;IDpDR;IACA;;;ACwDY;ED3Dd;;AACA;EC0Dc;IDzDZ;IACA;;;AC8DI;EACI,OD7Bc;EC8Bd,kBD7BoB;;AC+BpB;EACI;;AAKZ;EACI,kBD5CoB;EC6CpB,OF9EU;;AEkFV;EACI,MFnFM;;AEsFV;EACI,MFtFA;;AE0FR;EAEQ;;;AAMR;EACI,OFpGU;;AEwGb;EACI,ODhEM;;ACoEN;EACI,ODtEG;;;AC8EZ;EDrHF;;AACA;ECoHE;IDnHA;IACA;;;ACsHA;EDzHF;;AACA;ECwHE;IDvHA;IACA;;;;AC2HJ;EACI;;;AAGJ;EACI,OD5FY","file":"light.css"}
\ No newline at end of file
+{"version":3,"sourceRoot":"","sources":["../../scss/fonts.scss","../../scss/main.scss","../../scss/caos/variables.scss","../../scss/variables.scss","../../scss/light.scss"],"names":[],"mappings":"AACA;EACI;EACA;;AAIJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAIJ;EACI;EACA;EACA;EACA;AAA6D;EAC7D;;AC5EJ;EACI;EACA,aCMW;EDLX;EACA;;;AAGJ;EACI;;AAEA;EACI;;;AAIR;EACI;EACA;EACA;EACA,kBCLc;EDMd,OCLQ;EDMR;EACA;EACA;;;AAMJ;EACI,OCfQ;EDgBR,aCtBS;EDuBT;EACA,WE7BS;EF8BT;;;AAGJ;EACI,OCvBQ;EDwBR,aC9BS;ED+BT;EACA,WEpCU;;;AFuCd;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OC3DW;ED4DX;EACA;;AAEA;EACI,OC/DY;;ADkEhB;EACI;;;AAIR;EACI,kBC3Ec;ED4Ed,OC1EW;ED2EX;EACA;EACA;EACA;EACA,QE5FU;EF6FV;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI,kBCxFY;EDyFZ,OC5FU;ED6FV;;AAGJ;EACI,kBC/FO;EDgGP,OCjGI;EDkGJ;;AACA;EACI,kBClGQ;;ADsGhB;EACI,kBE5FW;EF6FX;;AAEA;EACI,kBEhGO;EFiGP;;AAIR;EACI;EACA;EACA;EACA;EACA,OEpGa;EFqGb,kBEpGmB;;AFsGnB;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;;;AAOZ;EACI,kBElImB;EFmInB,OCjJQ;EDkJR,QE9JU;EF+JV;EACA;EACA;;;AAIA;EACI;EACA;EACA;EACA;EACA;EE9JN;;AACA;EFwJE;IEvJA;IACA;;;AF+JA;EElKF;;AACA;EFiKE;IEhKA;IACA;;;;AFsKA;EACI;EACA;;AAGJ;EACI;EACA;;AAEA;EACI,WE5LE;EF6LF;;AAGJ;EACI;EACA;EACA;EACA,OE/KC;;;AFqLT;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA,OCpOA;;ADwOR;EACI,OE7NK;EF8NL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;AAIR;EACI;EACA;EACA,OCnQI;EDoQJ;EACA;EACA;EACA;;AAEA;EACI;EACA,kBE7PW;;AFgQf;EACI;;AAIR;EACI;;AAMA;EACI;EACA;EACA;EACA;EACA,cElRO;EFmRP;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;;AAKR;EACI;;AAEA;EACI;;AAEA;EACI;;AAEJ;EACI,OE9SP;;AFmTL;EACI;EACA;EACA;;AAEA;EACI;;AAGJ;EACI,kBC1UE;;AD8UF;EACI;EACA;;AAOZ;EACI;;AAEJ;EACI;EACA;EACA;EACA;EE7VV;;AACA;EFwVM;IEvVJ;IACA;;;AF+VQ;EACI;EACA;EEpWd;;AACA;EFiWU;IEhWR;IACA;;;AFsWI;EACI;EACA;;AAIR;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA,OE3WN;;AFgXE;EACI,OElXL;;AFuXP;EACI;;AACA;EACI;EACA;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI,MC9ZI;;ADiaR;EACI,MCnaU;;;ADwad;EACI;EACA;;;AAIR;EAEQ;EAEJ;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA;;;AAGJ;EACI;EACA;EACA;;;AAGJ;EACI,OElcO;;;AFqcX;EACI;;;AAGJ;EACI;;;AG/eJ;EACI,kBFeQ;EEdR,OFac;;AERd;EACI;;AAGJ;EACI,OFGU;;AEAd;EACI;EACA;EACA;;AAEA;EACI,kBFIa;EEHb;EACA,ODyBgB;;ACtBpB;EACI,kBFVG;EEWH,ODoBgB;ECnBhB;EACA;;AACA;EACI,kBFdI;;AEkBZ;EACI,kBDRO;ECSP;;AAEA;EACI,kBDZG;ECaH;;AAIR;EACI,OFhCM;;AEkCN;EACI;EACA,kBDHY;;ACQhB;EDxCV;;AACA;ECuCU;IDtCR;IACA;;;ACyCQ;EACI,kBDbY;;ACeZ;ED/Cd;;AACA;EC8Cc;ID7CZ;IACA;;;ACmDQ;EDtDV;;AACA;ECqDU;IDpDR;IACA;;;ACwDY;ED3Dd;;AACA;EC0Dc;IDzDZ;IACA;;;AC8DI;EACI,OD7Bc;EC8Bd,kBD7BoB;;AC+BpB;EACI;;AAKZ;EACI,kBD5CoB;EC6CpB,OF9EU;;AEkFV;EACI,MFnFM;;AEsFV;EACI,MFtFA;;AE0FR;EAEQ;;;AAMR;EACI,OFpGU;;AEwGb;EACI,ODhEM;;ACoEN;EACI,ODtEG;;;AC8EZ;EDrHF;;AACA;ECoHE;IDnHA;IACA;;;ACsHA;EDzHF;;AACA;ECwHE;IDvHA;IACA;;;;AC2HJ;EACI;;;AAGJ;EACI,OD5FY","file":"light.css"}
\ No newline at end of file
diff --git a/internal/ui/login/static/resources/themes/scss/main.scss b/internal/ui/login/static/resources/themes/scss/main.scss
index 137c9081ce..30296adb94 100644
--- a/internal/ui/login/static/resources/themes/scss/main.scss
+++ b/internal/ui/login/static/resources/themes/scss/main.scss
@@ -5,7 +5,6 @@
font-family: $standardFont;
font-size: 16px;
font-weight: 400;
- cursor: default !important;
}
body {
@@ -174,6 +173,7 @@ input:not([type='radio']), select {
width: 80px;
background-position: center;
background-repeat: no-repeat;
+ background-size: contain;
@include retina-background-image($profileImgDark, "png", false, 80px, 80px);
}
@@ -296,10 +296,6 @@ form {
button.user-selection {
@extend %profile-image;
- .profile-image {
- height: 80px;
- width: 80px;
- }
.sessionstate {
display: inline-block;
@@ -327,7 +323,7 @@ form {
position: relative;
&.names {
- margin: 15px;
+ margin: 0 15px;
.displayname {
font-size: 1.4rem;
@@ -337,6 +333,27 @@ form {
}
}
}
+
+ &:disabled {
+ background: transparent;
+ border: none;
+ cursor: not-allowed;
+
+ .profile-image {
+ opacity: 0.3;
+ }
+
+ .sessionstate {
+ background-color: $backgroundColor;
+ }
+
+ .names {
+ .displayname, .loginname {
+ font-style: italic;
+ color: #444444;
+ }
+ }
+ }
}
button.other-user {
diff --git a/internal/ui/login/static/resources/themes/zitadel/css/dark.css b/internal/ui/login/static/resources/themes/zitadel/css/dark.css
index f289f43bc1..e9f2328c89 100644
--- a/internal/ui/login/static/resources/themes/zitadel/css/dark.css
+++ b/internal/ui/login/static/resources/themes/zitadel/css/dark.css
@@ -75,7 +75,6 @@
font-family: Lato;
font-size: 16px;
font-weight: 400;
- cursor: default !important;
}
body {
@@ -228,6 +227,7 @@ form button.user-selection .profile-image, .login-profile .profile-image {
width: 80px;
background-position: center;
background-repeat: no-repeat;
+ background-size: contain;
background-image: url("../../../images/icon-user-dark.png");
}
@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {
@@ -335,10 +335,6 @@ form button.clean * {
form .user-selection-list {
margin-bottom: 40px;
}
-form button.user-selection .profile-image {
- height: 80px;
- width: 80px;
-}
form button.user-selection .sessionstate {
display: inline-block;
height: 20px;
@@ -361,7 +357,7 @@ form button.user-selection > div {
position: relative;
}
form button.user-selection > div.names {
- margin: 15px;
+ margin: 0 15px;
}
form button.user-selection > div.names .displayname {
font-size: 1.4rem;
@@ -369,6 +365,21 @@ form button.user-selection > div.names .displayname {
form button.user-selection > div.names .loginname {
color: #898989;
}
+form button.user-selection:disabled {
+ background: transparent;
+ border: none;
+ cursor: not-allowed;
+}
+form button.user-selection:disabled .profile-image {
+ opacity: 0.3;
+}
+form button.user-selection:disabled .sessionstate {
+ background-color: #282828;
+}
+form button.user-selection:disabled .names .displayname, form button.user-selection:disabled .names .loginname {
+ font-style: italic;
+ color: #444444;
+}
.user-selection + form button.other-user {
margin-top: 80px;
}
diff --git a/internal/ui/login/static/resources/themes/zitadel/css/dark.css.map b/internal/ui/login/static/resources/themes/zitadel/css/dark.css.map
index bab7b8d3dc..7bb0985450 100644
--- a/internal/ui/login/static/resources/themes/zitadel/css/dark.css.map
+++ b/internal/ui/login/static/resources/themes/zitadel/css/dark.css.map
@@ -1 +1 @@
-{"version":3,"sourceRoot":"","sources":["../../scss/fonts.scss","../../scss/main.scss","../../scss/variables.scss"],"names":[],"mappings":"AACA;EACI;EACA;;AAIJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAIJ;EACI;EACA;EACA;EACA;AAA6D;EAC7D;;AC5EJ;EACI;EACA,aCHW;EDIX;EACA;EACA;;;AAGJ;EACI;;AAEA;EACI;;;AAIR;EACI;EACA;EACA;EACA,kBCGc;EDFd,OCGQ;EDFR;EACA;EACA;EAEI;;;AAIR;EACI,OCPQ;EDQR,aChCS;EDiCT;EACA,WC9BS;ED+BT;;;AAGJ;EACI,OCfQ;EDgBR,aCxCS;EDyCT;EACA,WCrCU;;;ADwCd;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OCnDW;EDoDX;EACA;;AAEA;EACI,OCvDY;;AD0DhB;EACI;;;AAIR;EACI,kBCnEc;EDoEd,OClEW;EDmEX;EACA;EACA;EACA;EACA,QC7FU;ED8FV;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI,kBChFY;EDiFZ,OCpFU;EDqFV;;AAGJ;EACI,kBCvFO;EDwFP,OCzFI;ED0FJ;;AACA;EACI,kBC1FQ;;AD8FhB;EACI,kBC7FW;ED8FX;;AAEA;EACI,kBCjGO;EDkGP;;AAIR;EACI;EACA;EACA;EACA;EACA,OCrGa;EDsGb,kBCrGmB;;ADuGnB;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;;;AAOZ;EACI,kBCnImB;EDoInB,OCzIQ;ED0IR,QC/JU;EDgKV;EACA;EACA;;;AAIA;EACI;EACA;EACA;EACA;EC9JN;;AACA;EDyJE;ICxJA;IACA;;;AD+JA;EClKF;;AACA;EDiKE;IChKA;IACA;;;;ADsKA;EACI;EACA;;AAGJ;EACI;EACA;;AAEA;EACI,WC5LE;ED6LF;;AAGJ;EACI;EACA;EACA;EACA,OC/KC;;;ADqLT;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA,OC3NA;;AD+NR;EACI,OC7NK;ED8NL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;AAIR;EACI;EACA;EACA,OC1PI;ED2PJ;EACA;EACA;EACA;;AAEA;EACI;EACA,kBC7PW;;ADgQf;EACI;;AAIR;EACI;;AAKA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA,cCtRO;EDuRP;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;;AAKR;EACI;;AAEA;EACI;;AAEA;EACI;;AAEJ;EACI,OClTP;;ADyTL;EACI;;AAEJ;EACI;EACA;EACA;EACA;EC5UV;;AACA;EDuUM;ICtUJ;IACA;;;AD8UQ;EACI;EACA;ECnVd;;AACA;EDgVU;IC/UR;IACA;;;ADqVI;EACI;EACA;;AAIR;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA,OC1VN;;AD+VE;EACI,OCjWL;;ADsWP;EACI;;AACA;EACI;EACA;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI,MCpYI;;ADuYR;EACI,MCzYU;;;AD8Yd;EACI;EACA;;;AAIR;EAII;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA;;;AAGJ;EACI;EACA;EACA;;;AAGJ;EACI,OCjbO;;;ADobX;EACI;;;AAGJ;EACI","file":"dark.css"}
\ No newline at end of file
+{"version":3,"sourceRoot":"","sources":["../../scss/fonts.scss","../../scss/main.scss","../../scss/variables.scss"],"names":[],"mappings":"AACA;EACI;EACA;;AAIJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAIJ;EACI;EACA;EACA;EACA;AAA6D;EAC7D;;AC5EJ;EACI;EACA,aCHW;EDIX;EACA;;;AAGJ;EACI;;AAEA;EACI;;;AAIR;EACI;EACA;EACA;EACA,kBCIc;EDHd,OCIQ;EDHR;EACA;EACA;EAEI;;;AAIR;EACI,OCNQ;EDOR,aC/BS;EDgCT;EACA,WC7BS;ED8BT;;;AAGJ;EACI,OCdQ;EDeR,aCvCS;EDwCT;EACA,WCpCU;;;ADuCd;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OClDW;EDmDX;EACA;;AAEA;EACI,OCtDY;;ADyDhB;EACI;;;AAIR;EACI,kBClEc;EDmEd,OCjEW;EDkEX;EACA;EACA;EACA;EACA,QC5FU;ED6FV;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI,kBC/EY;EDgFZ,OCnFU;EDoFV;;AAGJ;EACI,kBCtFO;EDuFP,OCxFI;EDyFJ;;AACA;EACI,kBCzFQ;;AD6FhB;EACI,kBC5FW;ED6FX;;AAEA;EACI,kBChGO;EDiGP;;AAIR;EACI;EACA;EACA;EACA;EACA,OCpGa;EDqGb,kBCpGmB;;ADsGnB;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;;;AAOZ;EACI,kBClImB;EDmInB,OCxIQ;EDyIR,QC9JU;ED+JV;EACA;EACA;;;AAIA;EACI;EACA;EACA;EACA;EACA;EC9JN;;AACA;EDwJE;ICvJA;IACA;;;AD+JA;EClKF;;AACA;EDiKE;IChKA;IACA;;;;ADsKA;EACI;EACA;;AAGJ;EACI;EACA;;AAEA;EACI,WC5LE;ED6LF;;AAGJ;EACI;EACA;EACA;EACA,OC/KC;;;ADqLT;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA,OC3NA;;AD+NR;EACI,OC7NK;ED8NL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;AAIR;EACI;EACA;EACA,OC1PI;ED2PJ;EACA;EACA;EACA;;AAEA;EACI;EACA,kBC7PW;;ADgQf;EACI;;AAIR;EACI;;AAMA;EACI;EACA;EACA;EACA;EACA,cClRO;EDmRP;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;;AAKR;EACI;;AAEA;EACI;;AAEA;EACI;;AAEJ;EACI,OC9SP;;ADmTL;EACI;EACA;EACA;;AAEA;EACI;;AAGJ;EACI,kBCjUE;;ADqUF;EACI;EACA;;AAOZ;EACI;;AAEJ;EACI;EACA;EACA;EACA;EC7VV;;AACA;EDwVM;ICvVJ;IACA;;;AD+VQ;EACI;EACA;ECpWd;;AACA;EDiWU;IChWR;IACA;;;ADsWI;EACI;EACA;;AAIR;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA,OC3WN;;ADgXE;EACI,OClXL;;ADuXP;EACI;;AACA;EACI;EACA;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI,MCrZI;;ADwZR;EACI,MC1ZU;;;AD+Zd;EACI;EACA;;;AAIR;EAII;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA;;;AAGJ;EACI;EACA;EACA;;;AAGJ;EACI,OClcO;;;ADqcX;EACI;;;AAGJ;EACI","file":"dark.css"}
\ No newline at end of file
diff --git a/internal/ui/login/static/resources/themes/zitadel/css/light.css b/internal/ui/login/static/resources/themes/zitadel/css/light.css
index eae167bc73..26432267ba 100644
--- a/internal/ui/login/static/resources/themes/zitadel/css/light.css
+++ b/internal/ui/login/static/resources/themes/zitadel/css/light.css
@@ -75,7 +75,6 @@
font-family: Lato;
font-size: 16px;
font-weight: 400;
- cursor: default !important;
}
body {
@@ -228,6 +227,7 @@ form button.user-selection .profile-image, .login-profile .profile-image {
width: 80px;
background-position: center;
background-repeat: no-repeat;
+ background-size: contain;
background-image: url("../../../images/icon-user-dark.png");
}
@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {
@@ -335,10 +335,6 @@ form button.clean * {
form .user-selection-list {
margin-bottom: 40px;
}
-form button.user-selection .profile-image {
- height: 80px;
- width: 80px;
-}
form button.user-selection .sessionstate {
display: inline-block;
height: 20px;
@@ -361,7 +357,7 @@ form button.user-selection > div {
position: relative;
}
form button.user-selection > div.names {
- margin: 15px;
+ margin: 0 15px;
}
form button.user-selection > div.names .displayname {
font-size: 1.4rem;
@@ -369,6 +365,21 @@ form button.user-selection > div.names .displayname {
form button.user-selection > div.names .loginname {
color: #898989;
}
+form button.user-selection:disabled {
+ background: transparent;
+ border: none;
+ cursor: not-allowed;
+}
+form button.user-selection:disabled .profile-image {
+ opacity: 0.3;
+}
+form button.user-selection:disabled .sessionstate {
+ background-color: #282828;
+}
+form button.user-selection:disabled .names .displayname, form button.user-selection:disabled .names .loginname {
+ font-style: italic;
+ color: #444444;
+}
.user-selection + form button.other-user {
margin-top: 80px;
}
diff --git a/internal/ui/login/static/resources/themes/zitadel/css/light.css.map b/internal/ui/login/static/resources/themes/zitadel/css/light.css.map
index b7dfa7f778..ab57d44c72 100644
--- a/internal/ui/login/static/resources/themes/zitadel/css/light.css.map
+++ b/internal/ui/login/static/resources/themes/zitadel/css/light.css.map
@@ -1 +1 @@
-{"version":3,"sourceRoot":"","sources":["../../scss/fonts.scss","../../scss/main.scss","../../scss/variables.scss","../../scss/light.scss"],"names":[],"mappings":"AACA;EACI;EACA;;AAIJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAIJ;EACI;EACA;EACA;EACA;AAA6D;EAC7D;;AC5EJ;EACI;EACA,aCHW;EDIX;EACA;EACA;;;AAGJ;EACI;;AAEA;EACI;;;AAIR;EACI;EACA;EACA;EACA,kBCGc;EDFd,OCGQ;EDFR;EACA;EACA;EAEI;;;AAIR;EACI,OCPQ;EDQR,aChCS;EDiCT;EACA,WC9BS;ED+BT;;;AAGJ;EACI,OCfQ;EDgBR,aCxCS;EDyCT;EACA,WCrCU;;;ADwCd;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OCnDW;EDoDX;EACA;;AAEA;EACI,OCvDY;;AD0DhB;EACI;;;AAIR;EACI,kBCnEc;EDoEd,OClEW;EDmEX;EACA;EACA;EACA;EACA,QC7FU;ED8FV;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI,kBChFY;EDiFZ,OCpFU;EDqFV;;AAGJ;EACI,kBCvFO;EDwFP,OCzFI;ED0FJ;;AACA;EACI,kBC1FQ;;AD8FhB;EACI,kBC7FW;ED8FX;;AAEA;EACI,kBCjGO;EDkGP;;AAIR;EACI;EACA;EACA;EACA;EACA,OCrGa;EDsGb,kBCrGmB;;ADuGnB;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;;;AAOZ;EACI,kBCnImB;EDoInB,OCzIQ;ED0IR,QC/JU;EDgKV;EACA;EACA;;;AAIA;EACI;EACA;EACA;EACA;EC9JN;;AACA;EDyJE;ICxJA;IACA;;;AD+JA;EClKF;;AACA;EDiKE;IChKA;IACA;;;;ADsKA;EACI;EACA;;AAGJ;EACI;EACA;;AAEA;EACI,WC5LE;ED6LF;;AAGJ;EACI;EACA;EACA;EACA,OC/KC;;;ADqLT;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA,OC3NA;;AD+NR;EACI,OC7NK;ED8NL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;AAIR;EACI;EACA;EACA,OC1PI;ED2PJ;EACA;EACA;EACA;;AAEA;EACI;EACA,kBC7PW;;ADgQf;EACI;;AAIR;EACI;;AAKA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA,cCtRO;EDuRP;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;;AAKR;EACI;;AAEA;EACI;;AAEA;EACI;;AAEJ;EACI,OClTP;;ADyTL;EACI;;AAEJ;EACI;EACA;EACA;EACA;EC5UV;;AACA;EDuUM;ICtUJ;IACA;;;AD8UQ;EACI;EACA;ECnVd;;AACA;EDgVU;IC/UR;IACA;;;ADqVI;EACI;EACA;;AAIR;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA,OC1VN;;AD+VE;EACI,OCjWL;;ADsWP;EACI;;AACA;EACI;EACA;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI,MCpYI;;ADuYR;EACI,MCzYU;;;AD8Yd;EACI;EACA;;;AAIR;EAII;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA;;;AAGJ;EACI;EACA;EACA;;;AAGJ;EACI,OCjbO;;;ADobX;EACI;;;AAGJ;EACI;;;AE9dJ;EACI,kBD2CmB;EC1CnB,ODsBc;ECpBV;;AAGJ;EACI;;AAGJ;EACI,ODYU;;ACTd;EACI,kBD4Be;EC3Bf,ODSO;ECRP;;AAEA;EACI,kBD0Ba;ECzBb;EACA,ODyBgB;;ACtBpB;EACI,kBDDG;ECEH,ODoBgB;ECnBhB;EACA;;AACA;EACI,kBDLI;;ACSZ;EACI,kBDRO;ECSP;;AAEA;EACI,kBDZG;ECaH;;AAIR;EACI,ODvBM;;ACyBN;EACI;EACA,kBDHY;;ACQhB;EDxCV;;AACA;ECuCU;IDtCR;IACA;;;ACyCQ;EACI,kBDbY;;ACeZ;ED/Cd;;AACA;EC8Cc;ID7CZ;IACA;;;ACmDQ;EDtDV;;AACA;ECqDU;IDpDR;IACA;;;ACwDY;ED3Dd;;AACA;EC0Dc;IDzDZ;IACA;;;AC8DI;EACI,OD7Bc;EC8Bd,kBD7BoB;;AC+BpB;EACI;;AAKZ;EACI,kBD5CoB;EC6CpB,ODrEU;;ACyEV;EACI,MD1EM;;AC6EV;EACI,MD1DW;;ACsEnB;EACI,OD3FU;;AC+Fb;EACI,ODhEM;;ACoEN;EACI,ODtEG;;;AC8EZ;EDrHF;;AACA;ECoHE;IDnHA;IACA;;;ACsHA;EDzHF;;AACA;ECwHE;IDvHA;IACA;;;;AC2HJ;EACI;;;AAGJ;EACI,OD5FY","file":"light.css"}
\ No newline at end of file
+{"version":3,"sourceRoot":"","sources":["../../scss/fonts.scss","../../scss/main.scss","../../scss/variables.scss","../../scss/light.scss"],"names":[],"mappings":"AACA;EACI;EACA;;AAIJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAIJ;EACI;EACA;EACA;EACA;AAA6D;EAC7D;;AC5EJ;EACI;EACA,aCHW;EDIX;EACA;;;AAGJ;EACI;;AAEA;EACI;;;AAIR;EACI;EACA;EACA;EACA,kBCIc;EDHd,OCIQ;EDHR;EACA;EACA;EAEI;;;AAIR;EACI,OCNQ;EDOR,aC/BS;EDgCT;EACA,WC7BS;ED8BT;;;AAGJ;EACI,OCdQ;EDeR,aCvCS;EDwCT;EACA,WCpCU;;;ADuCd;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OClDW;EDmDX;EACA;;AAEA;EACI,OCtDY;;ADyDhB;EACI;;;AAIR;EACI,kBClEc;EDmEd,OCjEW;EDkEX;EACA;EACA;EACA;EACA,QC5FU;ED6FV;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI,kBC/EY;EDgFZ,OCnFU;EDoFV;;AAGJ;EACI,kBCtFO;EDuFP,OCxFI;EDyFJ;;AACA;EACI,kBCzFQ;;AD6FhB;EACI,kBC5FW;ED6FX;;AAEA;EACI,kBChGO;EDiGP;;AAIR;EACI;EACA;EACA;EACA;EACA,OCpGa;EDqGb,kBCpGmB;;ADsGnB;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;;;AAOZ;EACI,kBClImB;EDmInB,OCxIQ;EDyIR,QC9JU;ED+JV;EACA;EACA;;;AAIA;EACI;EACA;EACA;EACA;EACA;EC9JN;;AACA;EDwJE;ICvJA;IACA;;;AD+JA;EClKF;;AACA;EDiKE;IChKA;IACA;;;;ADsKA;EACI;EACA;;AAGJ;EACI;EACA;;AAEA;EACI,WC5LE;ED6LF;;AAGJ;EACI;EACA;EACA;EACA,OC/KC;;;ADqLT;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA,OC3NA;;AD+NR;EACI,OC7NK;ED8NL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;AAIR;EACI;EACA;EACA,OC1PI;ED2PJ;EACA;EACA;EACA;;AAEA;EACI;EACA,kBC7PW;;ADgQf;EACI;;AAIR;EACI;;AAMA;EACI;EACA;EACA;EACA;EACA,cClRO;EDmRP;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;;AAKR;EACI;;AAEA;EACI;;AAEA;EACI;;AAEJ;EACI,OC9SP;;ADmTL;EACI;EACA;EACA;;AAEA;EACI;;AAGJ;EACI,kBCjUE;;ADqUF;EACI;EACA;;AAOZ;EACI;;AAEJ;EACI;EACA;EACA;EACA;EC7VV;;AACA;EDwVM;ICvVJ;IACA;;;AD+VQ;EACI;EACA;ECpWd;;AACA;EDiWU;IChWR;IACA;;;ADsWI;EACI;EACA;;AAIR;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA,OC3WN;;ADgXE;EACI,OClXL;;ADuXP;EACI;;AACA;EACI;EACA;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI,MCrZI;;ADwZR;EACI,MC1ZU;;;AD+Zd;EACI;EACA;;;AAIR;EAII;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA;;;AAGJ;EACI;EACA;EACA;;;AAGJ;EACI,OClcO;;;ADqcX;EACI;;;AAGJ;EACI;;;AE/eJ;EACI,kBD2CmB;EC1CnB,ODsBc;ECpBV;;AAGJ;EACI;;AAGJ;EACI,ODYU;;ACTd;EACI,kBD4Be;EC3Bf,ODSO;ECRP;;AAEA;EACI,kBD0Ba;ECzBb;EACA,ODyBgB;;ACtBpB;EACI,kBDDG;ECEH,ODoBgB;ECnBhB;EACA;;AACA;EACI,kBDLI;;ACSZ;EACI,kBDRO;ECSP;;AAEA;EACI,kBDZG;ECaH;;AAIR;EACI,ODvBM;;ACyBN;EACI;EACA,kBDHY;;ACQhB;EDxCV;;AACA;ECuCU;IDtCR;IACA;;;ACyCQ;EACI,kBDbY;;ACeZ;ED/Cd;;AACA;EC8Cc;ID7CZ;IACA;;;ACmDQ;EDtDV;;AACA;ECqDU;IDpDR;IACA;;;ACwDY;ED3Dd;;AACA;EC0Dc;IDzDZ;IACA;;;AC8DI;EACI,OD7Bc;EC8Bd,kBD7BoB;;AC+BpB;EACI;;AAKZ;EACI,kBD5CoB;EC6CpB,ODrEU;;ACyEV;EACI,MD1EM;;AC6EV;EACI,MD1DW;;ACsEnB;EACI,OD3FU;;AC+Fb;EACI,ODhEM;;ACoEN;EACI,ODtEG;;;AC8EZ;EDrHF;;AACA;ECoHE;IDnHA;IACA;;;ACsHA;EDzHF;;AACA;ECwHE;IDvHA;IACA;;;;AC2HJ;EACI;;;AAGJ;EACI,OD5FY","file":"light.css"}
\ No newline at end of file
diff --git a/internal/ui/login/static/templates/login.html b/internal/ui/login/static/templates/login.html
index 0df0371c3c..347770c129 100644
--- a/internal/ui/login/static/templates/login.html
+++ b/internal/ui/login/static/templates/login.html
@@ -4,10 +4,10 @@
{{if .Linking}}
{{t "Login.TitleLinking"}}
-
{{t "Login.DescriptionLinking"}}
+
{{t "Login.DescriptionLinking"}}{{if .OrgName}} {{t "Login.MustBeMemberOfOrg" "OrgName" .OrgName}}{{end}}
{{else}}
{{t "Login.Title"}}
-
{{t "Login.Description"}}
+
{{t "Login.Description"}}{{if .OrgName}} {{t "Login.MustBeMemberOfOrg" "OrgName" .OrgName}}{{end}}
{{end}}
diff --git a/internal/ui/login/static/templates/mfa_init_verify.html b/internal/ui/login/static/templates/mfa_init_verify.html
index de9ff51e14..98a51e787c 100644
--- a/internal/ui/login/static/templates/mfa_init_verify.html
+++ b/internal/ui/login/static/templates/mfa_init_verify.html
@@ -35,6 +35,8 @@
{{end}}
+ {{ template "error-message" .}}
+
diff --git a/internal/ui/login/static/templates/passwordless.html b/internal/ui/login/static/templates/passwordless.html
index 120889be6d..70276780e2 100644
--- a/internal/ui/login/static/templates/passwordless.html
+++ b/internal/ui/login/static/templates/passwordless.html
@@ -26,6 +26,9 @@
{{ template "error-message" .}}
+ {{if .PasswordLogin}}
+
+ {{end}}
diff --git a/internal/ui/login/static/templates/register_org.html b/internal/ui/login/static/templates/register_org.html
index fc0aeea156..ed8037bea1 100644
--- a/internal/ui/login/static/templates/register_org.html
+++ b/internal/ui/login/static/templates/register_org.html
@@ -15,7 +15,7 @@
-
+
{{if .UserLoginMustBeDomain}}
diff --git a/internal/ui/login/static/templates/select_user.html b/internal/ui/login/static/templates/select_user.html
index 26f7c02ec1..fc09fa66b6 100644
--- a/internal/ui/login/static/templates/select_user.html
+++ b/internal/ui/login/static/templates/select_user.html
@@ -3,10 +3,10 @@
{{if .Linking}}
{{t "UserSelection.TitleLinking"}}
-
{{t "UserSelection.DescriptionLinking"}}
+
{{t "UserSelection.DescriptionLinking"}}{{if .OrgName}} {{t "UserSelection.MustBeMemberOfOrg" "OrgName" .OrgName}}{{end}}
{{else}}
{{t "UserSelection.Title"}}
-
{{t "UserSelection.Description"}}
+
{{t "UserSelection.Description"}}{{if .OrgName}} {{t "UserSelection.MustBeMemberOfOrg" "OrgName" .OrgName}}{{end}}
{{end}}
@@ -22,7 +22,7 @@
{{ range $user := .Users }}
{{ $sessionState := (printf "sessionstate-%v" $user.UserSessionState) }}
-