+
-
-
+
+
-
+
+
+
+
+
+ {{LANGPLACEHOLDER}}
+
+
+
+
+
diff --git a/console/src/app/modules/policies/privacy-policy/privacy-policy.component.scss b/console/src/app/modules/policies/privacy-policy/privacy-policy.component.scss
index 8a18e531cf..5814f31299 100644
--- a/console/src/app/modules/policies/privacy-policy/privacy-policy.component.scss
+++ b/console/src/app/modules/policies/privacy-policy/privacy-policy.component.scss
@@ -1,26 +1,26 @@
.spinner-wr {
- margin: .5rem 0;
+ margin: 0.5rem 0;
}
.top-actions {
display: flex;
- margin: 0 -.5rem;
+ margin: 0 -0.5rem;
flex-wrap: wrap;
.keys {
flex: 1;
- margin: 0 .5rem;
+ margin: 0 0.5rem;
min-width: 150px;
}
.language {
- margin: 0 .5rem;
+ margin: 0 0.5rem;
min-width: 150px;
.lighter {
font-size: 12px;
color: var(--grey);
- padding: 0 .5rem;
+ padding: 0 0.5rem;
}
}
}
@@ -34,40 +34,66 @@
padding-top: 1rem;
}
-.chips {
- display: flex;
- margin: 0 -.25rem;
-
- .chip {
- border-radius: 50vw;
- padding: 2px .5rem;
- font-size: 12px;
- background: #cbf4c9;
- color: #0e6245;
- margin: .25rem;
+.privacy-policy-formfield {
+ .chips {
display: flex;
- align-items: center;
- justify-content: center;
- z-index: 10;
+ flex-wrap: wrap;
+ opacity: 0;
+ margin: 0 -0.25rem;
+ transition: all 0.2s ease;
+
+ .chip {
+ border-radius: 50vw;
+ padding: 4px 0.5rem;
+ font-size: 12px;
+ background: #5282c1;
+ color: white;
+ margin: 0.25rem;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 10;
+
+ * {
+ transition: all 0.2s ease;
+ }
+
+ i {
+ opacity: 0.5;
+ font-size: 1.1rem;
+ margin-left: 0.5rem;
+ }
+
+ .key {
+ display: inline-block;
+ }
+ }
+ }
+
+ &.cnsl-focused {
+ .chips {
+ opacity: 1;
+ cursor: copy;
+ }
}
}
.divider {
width: 100%;
height: 1px;
- background-color: rgba(#81868a, .5);
+ background-color: rgba(#81868a, 0.5);
margin: 1.5rem 0 0 0;
}
.actions {
display: flex;
justify-content: flex-end;
- margin: 0 -.25rem;
+ margin: 0 -0.25rem;
.save-button,
.reset-button {
display: block;
- margin: 0 .25rem 3rem .25rem;
+ margin: 0 0.25rem 3rem 0.25rem;
}
.reset-button {
diff --git a/console/src/app/modules/policies/privacy-policy/privacy-policy.component.ts b/console/src/app/modules/policies/privacy-policy/privacy-policy.component.ts
index 91220f09ac..5cdaf2be52 100644
--- a/console/src/app/modules/policies/privacy-policy/privacy-policy.component.ts
+++ b/console/src/app/modules/policies/privacy-policy/privacy-policy.component.ts
@@ -37,11 +37,14 @@ export class PrivacyPolicyComponent implements OnDestroy {
public nextLinks: CnslLinks[] = [];
private sub: Subscription = new Subscription();
- public privacyPolicy!: PrivacyPolicy.AsObject;
+ public privacyPolicy: PrivacyPolicy.AsObject | undefined = undefined;
public form!: FormGroup;
public currentPolicy: GridPolicy = PRIVACY_POLICY;
public InfoSectionType: any = InfoSectionType;
+ public LANGPLACEHOLDER: string = '{{.Lang}}';
+ public copied: string = '';
+
constructor(
private route: ActivatedRoute,
private injector: Injector,
@@ -49,70 +52,108 @@ export class PrivacyPolicyComponent implements OnDestroy {
private toast: ToastService,
private fb: FormBuilder,
) {
-
this.form = this.fb.group({
tosLink: ['', []],
privacyLink: ['', []],
+ helpLink: ['', []],
});
- this.route.data.pipe(switchMap(data => {
- this.serviceType = data.serviceType;
- switch (this.serviceType) {
- case PolicyComponentServiceType.MGMT:
- this.service = this.injector.get(ManagementService as Type
);
- this.loadData();
- break;
- case PolicyComponentServiceType.ADMIN:
- this.service = this.injector.get(AdminService as Type);
- this.loadData();
- break;
- }
+ this.route.data
+ .pipe(
+ switchMap((data) => {
+ this.serviceType = data.serviceType;
+ switch (this.serviceType) {
+ case PolicyComponentServiceType.MGMT:
+ this.service = this.injector.get(ManagementService as Type);
+ this.loadData();
+ break;
+ case PolicyComponentServiceType.ADMIN:
+ this.service = this.injector.get(AdminService as Type);
+ this.loadData();
+ break;
+ }
- return this.route.params;
- })).subscribe();
+ return this.route.params;
+ }),
+ )
+ .subscribe();
+ }
+
+ public addChip(formControlName: string, value: string): void {
+ const c = this.form.get(formControlName)?.value;
+ this.form.get(formControlName)?.setValue(`${c}${value}`);
}
public async loadData(): Promise {
- const getData = ():
- Promise => {
- return (this.service as AdminService).getPrivacyPolicy();
+ const getData = (): Promise => {
+ return this.service.getPrivacyPolicy();
};
- getData().then(resp => {
- if (resp.policy) {
- this.privacyPolicy = resp.policy;
- this.form.patchValue(this.privacyPolicy);
- }
- });
+ getData()
+ .then((resp) => {
+ if (resp.policy) {
+ this.privacyPolicy = resp.policy;
+ this.form.patchValue(this.privacyPolicy);
+ } else {
+ this.privacyPolicy = undefined;
+ this.form.patchValue({
+ tosLink: '',
+ privacyLink: '',
+ helpLink: '',
+ });
+ }
+ })
+ .catch((error) => {
+ this.privacyPolicy = undefined;
+ this.form.patchValue({
+ tosLink: '',
+ privacyLink: '',
+ helpLink: '',
+ });
+ });
}
public saveCurrentMessage(): void {
- console.log(this.form.get('privacyLink')?.value, this.form.get('tosLink')?.value);
if (this.serviceType === PolicyComponentServiceType.MGMT) {
- if ((this.privacyPolicy as PrivacyPolicy.AsObject).isDefault) {
+ if (!this.privacyPolicy || (this.privacyPolicy as PrivacyPolicy.AsObject).isDefault) {
const req = new AddCustomPrivacyPolicyRequest();
req.setPrivacyLink(this.form.get('privacyLink')?.value);
req.setTosLink(this.form.get('tosLink')?.value);
- (this.service as ManagementService).addCustomPrivacyPolicy(req).then(() => {
- this.toast.showInfo('POLICY.PRIVACY_POLICY.SAVED', true);
- }).catch(error => this.toast.showError(error));
+ req.setHelpLink(this.form.get('helpLink')?.value);
+ (this.service as ManagementService)
+ .addCustomPrivacyPolicy(req)
+ .then(() => {
+ this.toast.showInfo('POLICY.PRIVACY_POLICY.SAVED', true);
+ this.loadData();
+ })
+ .catch((error) => this.toast.showError(error));
} else {
const req = new UpdateCustomPrivacyPolicyRequest();
req.setPrivacyLink(this.form.get('privacyLink')?.value);
req.setTosLink(this.form.get('tosLink')?.value);
- (this.service as ManagementService).updateCustomPrivacyPolicy(req).then(() => {
- this.toast.showInfo('POLICY.PRIVACY_POLICY.SAVED', true);
- }).catch(error => this.toast.showError(error));
- }
+ req.setHelpLink(this.form.get('helpLink')?.value);
+ (this.service as ManagementService)
+ .updateCustomPrivacyPolicy(req)
+ .then(() => {
+ this.toast.showInfo('POLICY.PRIVACY_POLICY.SAVED', true);
+ this.loadData();
+ })
+ .catch((error) => this.toast.showError(error));
+ }
} else if (this.serviceType === PolicyComponentServiceType.ADMIN) {
const req = new UpdatePrivacyPolicyRequest();
req.setPrivacyLink(this.form.get('privacyLink')?.value);
req.setTosLink(this.form.get('tosLink')?.value);
+ req.setHelpLink(this.form.get('helpLink')?.value);
- (this.service as AdminService).updatePrivacyPolicy(req).then(() => {
- this.toast.showInfo('POLICY.PRIVACY_POLICY.SAVED', true);
- }).catch(error => this.toast.showError(error));
+ (this.service as AdminService)
+ .updatePrivacyPolicy(req)
+ .then(() => {
+ this.toast.showInfo('POLICY.PRIVACY_POLICY.SAVED', true);
+ this.loadData();
+ })
+ .catch((error) => this.toast.showError(error));
}
}
@@ -128,16 +169,19 @@ export class PrivacyPolicyComponent implements OnDestroy {
width: '400px',
});
- dialogRef.afterClosed().subscribe(resp => {
+ dialogRef.afterClosed().subscribe((resp) => {
if (resp) {
if (this.serviceType === PolicyComponentServiceType.MGMT) {
- (this.service as ManagementService).resetPrivacyPolicyToDefault().then(() => {
- setTimeout(() => {
- this.loadData();
- }, 1000);
- }).catch(error => {
- this.toast.showError(error);
- });
+ (this.service as ManagementService)
+ .resetPrivacyPolicyToDefault()
+ .then(() => {
+ setTimeout(() => {
+ this.loadData();
+ }, 1000);
+ })
+ .catch((error) => {
+ this.toast.showError(error);
+ });
}
}
});
diff --git a/console/src/app/modules/policies/privacy-policy/privacy-policy.module.ts b/console/src/app/modules/policies/privacy-policy/privacy-policy.module.ts
index 201208f026..ff6f9b2419 100644
--- a/console/src/app/modules/policies/privacy-policy/privacy-policy.module.ts
+++ b/console/src/app/modules/policies/privacy-policy/privacy-policy.module.ts
@@ -9,6 +9,7 @@ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatSelectModule } from '@angular/material/select';
import { MatTooltipModule } from '@angular/material/tooltip';
import { TranslateModule } from '@ngx-translate/core';
+import { CopyToClipboardModule } from 'src/app/directives/copy-to-clipboard/copy-to-clipboard.module';
import { HasRoleModule } from '../../../directives/has-role/has-role.module';
import { DetailLayoutModule } from '../../../modules/detail-layout/detail-layout.module';
@@ -32,6 +33,7 @@ import { PrivacyPolicyComponent } from './privacy-policy.component';
FormsModule,
InputModule,
FormFieldModule,
+ CopyToClipboardModule,
MatButtonModule,
HasFeaturePipeModule,
MatIconModule,
@@ -49,4 +51,4 @@ import { PrivacyPolicyComponent } from './privacy-policy.component';
InfoSectionModule,
],
})
-export class PrivacyPolicyModule { }
+export class PrivacyPolicyModule {}
diff --git a/console/src/assets/i18n/de.json b/console/src/assets/i18n/de.json
index c751dc34a5..69e2a38305 100644
--- a/console/src/assets/i18n/de.json
+++ b/console/src/assets/i18n/de.json
@@ -873,6 +873,7 @@
"DESCRIPTION": "Legen Sie Ihre Datenschutzrichtlinien und Nutzungsbedingungen fest",
"TOSLINK": "Link zu den Allgemeinen Geschäftsbedingungen",
"POLICYLINK": "Link zur den Datenschutzrichtlinien",
+ "HELPLINK": "Link zur Hilfestellung",
"SAVED": "Saved successfully!",
"RESET_TITLE": "Standardwerte wiederherstellen",
"RESET_DESCRIPTION": "Sie sind im Begriff die Standardlinks für die AGBs und Datenschutzrichtlinie wiederherzustellen. Wollen Sie fortfahren?"
diff --git a/console/src/assets/i18n/en.json b/console/src/assets/i18n/en.json
index 4aad40dfc6..646f68abde 100644
--- a/console/src/assets/i18n/en.json
+++ b/console/src/assets/i18n/en.json
@@ -873,6 +873,7 @@
"DESCRIPTION": "Set your Privacy Policy and Terms of Service Links",
"TOSLINK": "Link to Terms of Service",
"POLICYLINK": "Link to Privacy Policy",
+ "HELPLINK": "Link to Help",
"SAVED": "Saved successfully!",
"RESET_TITLE": "Restore Default Values",
"RESET_DESCRIPTION": "You are about to restore the default Links for TOS and Privacy Policy. Do you really want to continue?"
diff --git a/console/src/assets/i18n/it.json b/console/src/assets/i18n/it.json
index 74738375a1..4f73d67c53 100644
--- a/console/src/assets/i18n/it.json
+++ b/console/src/assets/i18n/it.json
@@ -873,6 +873,7 @@
"DESCRIPTION": "Imposta i tuoi link all'informativa sulla privacy e ai termini di servizio",
"TOSLINK": "Link ai termini di servizio",
"POLICYLINK": "Link all'informativa sulla privacy",
+ "HELPLINK": "link per l'aiuto",
"SAVED": "Salvato con successo!",
"RESET_TITLE": "Ripristina i valori predefiniti",
"RESET_DESCRIPTION": "Stai per ripristinare i link predefiniti per i TOS e l'informativa sulla privacy. Vuoi davvero continuare?"
diff --git a/docs/docs/apis/proto/admin.md b/docs/docs/apis/proto/admin.md
index 5c28614c35..37f9be8270 100644
--- a/docs/docs/apis/proto/admin.md
+++ b/docs/docs/apis/proto/admin.md
@@ -888,6 +888,7 @@ Returns the privacy policy defined by the administrators of ZITADEL
Updates the default privacy policy of ZITADEL
it impacts all organisations without a customised policy
+Variable {{.Lang}} can be set to have different links based on the language
@@ -3816,6 +3817,7 @@ This is an empty request
| ----- | ---- | ----------- | ----------- |
| tos_link | string | - | |
| privacy_link | string | - | |
+| help_link | string | - | |
diff --git a/docs/docs/apis/proto/management.md b/docs/docs/apis/proto/management.md
index bd5484afe6..100929d241 100644
--- a/docs/docs/apis/proto/management.md
+++ b/docs/docs/apis/proto/management.md
@@ -2095,6 +2095,7 @@ With this policy the privacy relevant things can be configured (e.g tos link)
Add a custom privacy policy for the organisation
With this policy privacy relevant things can be configured (e.g. tos link)
+Variable {{.Lang}} can be set to have different links based on the language
@@ -2108,6 +2109,7 @@ With this policy privacy relevant things can be configured (e.g. tos link)
Update the privacy complexity policy for the organisation
With this policy privacy relevant things can be configured (e.g. tos link)
+Variable {{.Lang}} can be set to have different links based on the language
@@ -3113,6 +3115,7 @@ This is an empty request
| ----- | ---- | ----------- | ----------- |
| tos_link | string | - | |
| privacy_link | string | - | |
+| help_link | string | - | |
@@ -7833,6 +7836,7 @@ This is an empty request
| ----- | ---- | ----------- | ----------- |
| tos_link | string | - | |
| privacy_link | string | - | |
+| help_link | string | - | |
diff --git a/docs/docs/apis/proto/policy.md b/docs/docs/apis/proto/policy.md
index cd482b7ff6..0820f88c95 100644
--- a/docs/docs/apis/proto/policy.md
+++ b/docs/docs/apis/proto/policy.md
@@ -126,6 +126,7 @@ title: zitadel/policy.proto
| tos_link | string | - | |
| privacy_link | string | - | |
| is_default | bool | - | |
+| help_link | string | - | |
diff --git a/docs/docs/apis/proto/text.md b/docs/docs/apis/proto/text.md
index dabf6946f7..cfd74d04aa 100644
--- a/docs/docs/apis/proto/text.md
+++ b/docs/docs/apis/proto/text.md
@@ -93,7 +93,6 @@ title: zitadel/text.proto
| tos | string | - | string.max_len: 200
|
| privacy_policy | string | - | string.max_len: 200
|
| help | string | - | string.max_len: 200
|
-| help_link | string | - | string.max_len: 500
|
diff --git a/docs/docs/apis/proto/user.md b/docs/docs/apis/proto/user.md
index 2f47a39135..6143aab915 100644
--- a/docs/docs/apis/proto/user.md
+++ b/docs/docs/apis/proto/user.md
@@ -374,6 +374,7 @@ UserTypeQuery is always equals
| project_name | string | - | |
| project_grant_id | string | - | |
| avatar_url | string | - | |
+| preferred_login_name | string | - | |
diff --git a/go.mod b/go.mod
index 40b4e7d838..31ce1b3101 100644
--- a/go.mod
+++ b/go.mod
@@ -44,10 +44,12 @@ require (
github.com/pquerna/otp v1.3.0
github.com/rakyll/statik v0.1.7
github.com/rs/cors v1.8.0
+ github.com/sirupsen/logrus v1.8.1
github.com/sony/sonyflake v1.0.0
github.com/spf13/cobra v1.3.0
github.com/spf13/viper v1.10.1
github.com/stretchr/testify v1.7.0
+ github.com/superseriousbusiness/exifremove v0.0.0-20210330092427-6acd27eac203
github.com/ttacon/libphonenumber v1.2.1
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.27.0
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.27.0
@@ -88,17 +90,28 @@ require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect
github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91 // indirect
+ github.com/dsoprea/go-exif v0.0.0-20210131231135-d154f10435cc // indirect
+ github.com/dsoprea/go-exif/v2 v2.0.0-20200604193436-ca8584a0e1c4 // indirect
+ github.com/dsoprea/go-iptc v0.0.0-20200609062250-162ae6b44feb // indirect
+ github.com/dsoprea/go-jpeg-image-structure v0.0.0-20210128210355-86b1014917f2 // indirect
+ github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d // indirect
+ github.com/dsoprea/go-photoshop-info-format v0.0.0-20200609050348-3db9b63b202c // indirect
+ github.com/dsoprea/go-png-image-structure v0.0.0-20200807080309-a98d4e94ac82 // indirect
+ github.com/dsoprea/go-utility v0.0.0-20200512094054-1abbbc781176 // indirect
github.com/dustin/go-humanize v1.0.0 // indirect
github.com/envoyproxy/go-control-plane v0.10.1 // indirect
github.com/felixge/httpsnoop v1.0.2 // indirect
github.com/fsnotify/fsnotify v1.5.1 // indirect
github.com/fxamacker/cbor/v2 v2.2.0 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
+ github.com/go-errors/errors v1.0.2 // indirect
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
+ github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b // indirect
github.com/gofrs/flock v0.8.1 // indirect
github.com/gofrs/uuid v4.0.0+incompatible // indirect
github.com/golang-jwt/jwt/v4 v4.1.0 // indirect
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
+ github.com/golang/geo v0.0.0-20200319012246-673a6f80352d // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/certificate-transparency-go v1.0.21 // indirect
@@ -107,6 +120,7 @@ require (
github.com/googleapis/gax-go/v2 v2.1.1 // indirect
github.com/gorilla/handlers v1.5.1 // indirect
github.com/gorilla/websocket v1.4.2 // indirect
+ github.com/h2non/filetype v1.1.1 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/huandu/xstrings v1.3.2 // indirect
github.com/imdario/mergo v0.3.12 // indirect
@@ -139,7 +153,6 @@ require (
github.com/prometheus/procfs v0.6.0 // indirect
github.com/rs/xid v1.2.1 // indirect
github.com/satori/go.uuid v1.2.0 // indirect
- github.com/sirupsen/logrus v1.8.1 // indirect
github.com/spf13/afero v1.8.1 // indirect
github.com/spf13/cast v1.4.1 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
diff --git a/go.sum b/go.sum
index 13c1281d47..393b7c4223 100644
--- a/go.sum
+++ b/go.sum
@@ -203,6 +203,24 @@ github.com/dop251/goja v0.0.0-20211129110639-4739a1d10a51/go.mod h1:R9ET47fwRVRP
github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y=
github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d h1:W1n4DvpzZGOISgp7wWNtraLcHtnmnTwBlJidqtMIuwQ=
github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM=
+github.com/dsoprea/go-exif v0.0.0-20210131231135-d154f10435cc h1:AuzYp98IFVOi0NU/WcZyGDQ6vAh/zkCjxGD3kt8aLzA=
+github.com/dsoprea/go-exif v0.0.0-20210131231135-d154f10435cc/go.mod h1:lOaOt7+UEppOgyvRy749v3do836U/hw0YVJNjoyPaEs=
+github.com/dsoprea/go-exif/v2 v2.0.0-20200321225314-640175a69fe4/go.mod h1:Lm2lMM2zx8p4a34ZemkaUV95AnMl4ZvLbCUbwOvLC2E=
+github.com/dsoprea/go-exif/v2 v2.0.0-20200604193436-ca8584a0e1c4 h1:Mg7pY7kxDQD2Bkvr1N+XW4BESSIQ7tTTR7Vv+Gi2CsM=
+github.com/dsoprea/go-exif/v2 v2.0.0-20200604193436-ca8584a0e1c4/go.mod h1:9EXlPeHfblFFnwu5UOqmP2eoZfJyAZ2Ri/Vki33ajO0=
+github.com/dsoprea/go-iptc v0.0.0-20200609062250-162ae6b44feb h1:gwjJjUr6FY7zAWVEueFPrcRHhd9+IK81TcItbqw2du4=
+github.com/dsoprea/go-iptc v0.0.0-20200609062250-162ae6b44feb/go.mod h1:kYIdx9N9NaOyD7U6D+YtExN7QhRm+5kq7//yOsRXQtM=
+github.com/dsoprea/go-jpeg-image-structure v0.0.0-20210128210355-86b1014917f2 h1:ULCSN6v0WISNbALxomGPXh4dSjRKPW+7+seYoMz8UTc=
+github.com/dsoprea/go-jpeg-image-structure v0.0.0-20210128210355-86b1014917f2/go.mod h1:ZoOP3yUG0HD1T4IUjIFsz/2OAB2yB4YX6NSm4K+uJRg=
+github.com/dsoprea/go-logging v0.0.0-20190624164917-c4f10aab7696/go.mod h1:Nm/x2ZUNRW6Fe5C3LxdY1PyZY5wmDv/s5dkPJ/VB3iA=
+github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d h1:F/7L5wr/fP/SKeO5HuMlNEX9Ipyx2MbH2rV9G4zJRpk=
+github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d/go.mod h1:7I+3Pe2o/YSU88W0hWlm9S22W7XI1JFNJ86U0zPKMf8=
+github.com/dsoprea/go-photoshop-info-format v0.0.0-20200609050348-3db9b63b202c h1:7j5aWACOzROpr+dvMtu8GnI97g9ShLWD72XIELMgn+c=
+github.com/dsoprea/go-photoshop-info-format v0.0.0-20200609050348-3db9b63b202c/go.mod h1:pqKB+ijp27cEcrHxhXVgUUMlSDRuGJJp1E+20Lj5H0E=
+github.com/dsoprea/go-png-image-structure v0.0.0-20200807080309-a98d4e94ac82 h1:RdwKOEEe2ND/JmoKh6I/EQlR9idKJTDOMffPFK6vN2M=
+github.com/dsoprea/go-png-image-structure v0.0.0-20200807080309-a98d4e94ac82/go.mod h1:aDYQkL/5gfRNZkoxiLTSWU4Y8/gV/4MVsy/MU9uwTak=
+github.com/dsoprea/go-utility v0.0.0-20200512094054-1abbbc781176 h1:CfXezFYb2STGOd1+n1HshvE191zVx+QX3A1nML5xxME=
+github.com/dsoprea/go-utility v0.0.0-20200512094054-1abbbc781176/go.mod h1:95+K3z2L0mqsVYd6yveIv1lmtT3tcQQ3dVakPySffW8=
github.com/duo-labs/webauthn v0.0.0-20211216225436-9a12cd078b8a h1:mKoV2b/J8sVVvc6jCl7SxdOrED5cHKdQaHUxjoO5W74=
github.com/duo-labs/webauthn v0.0.0-20211216225436-9a12cd078b8a/go.mod h1:EYSpSkwoEcryMmQGfhol2IiB3IMN9IIIaNd/wcAQMGQ=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
@@ -256,8 +274,9 @@ github.com/gin-gonic/gin v1.7.4 h1:QmUZXrvJ9qZ3GfWvQ+2wnW/1ePrTEJqPKMYEU3lD/DM=
github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
-github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
+github.com/go-errors/errors v1.0.2 h1:xMxH9j2fNg/L4hLn/4y3M0IUsn0M6Wbu/Uh9QlOfBh4=
+github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@@ -286,6 +305,8 @@ github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG
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-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b h1:khEcpUM4yFcxg4/FHQWkvVRmgijNXRfzkIDHh23ggEo=
+github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8=
@@ -309,6 +330,9 @@ github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZ
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
+github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
+github.com/golang/geo v0.0.0-20200319012246-673a6f80352d h1:C/hKUcHT483btRbeGkrRjJz+Zbcj8audldIi9tRJDCc=
+github.com/golang/geo v0.0.0-20200319012246-673a6f80352d/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ=
github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
@@ -434,6 +458,8 @@ github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.1 h1:p5m7GOEGXyoq6QWl4/RRMsQ6tWbTpbQmAnkxXgWSprY=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.1/go.mod h1:8ZeZajTed/blCOHBbj8Fss8bPHiFKcmJJzuIbUtFCAo=
+github.com/h2non/filetype v1.1.1 h1:xvOwnXKAckvtLWsN398qS9QhlxlnVXBjXBydK2/UFB4=
+github.com/h2non/filetype v1.1.1/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY=
github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M=
github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0=
@@ -535,6 +561,7 @@ github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0f
github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
+github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
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=
@@ -870,6 +897,8 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
+github.com/superseriousbusiness/exifremove v0.0.0-20210330092427-6acd27eac203 h1:1SWXcTphBQjYGWRRxLFIAR1LVtQEj4eR7xPtyeOVM/c=
+github.com/superseriousbusiness/exifremove v0.0.0-20210330092427-6acd27eac203/go.mod h1:0Xw5cYMOYpgaWs+OOSx41ugycl2qvKTi9tlMMcZhFyY=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2 h1:5u+EJUQiosu3JFX0XS0qTf5FznsMOzTjGqavBGuCbo0=
github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2/go.mod h1:4kyMkleCiLkgY6z8gK5BkI01ChBtxR0ro3I1ZDcGM3w=
@@ -1073,6 +1102,7 @@ golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200320220750-118fecf932d8/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
diff --git a/internal/api/assets/asset.go b/internal/api/assets/asset.go
index 6ca3298c22..374b5f6fd0 100644
--- a/internal/api/assets/asset.go
+++ b/internal/api/assets/asset.go
@@ -1,8 +1,10 @@
package assets
import (
+ "bytes"
"context"
"fmt"
+ "io"
"io/ioutil"
"net/http"
"strconv"
@@ -11,6 +13,7 @@ import (
"github.com/caos/logging"
sentryhttp "github.com/getsentry/sentry-go/http"
"github.com/gorilla/mux"
+ "github.com/superseriousbusiness/exifremove/pkg/exifremove"
"github.com/caos/zitadel/internal/api/authz"
http_mw "github.com/caos/zitadel/internal/api/http/middleware"
@@ -136,7 +139,13 @@ func UploadHandleFunc(s AssetsService, uploader Uploader) func(http.ResponseWrit
s.ErrorHandler()(w, r, fmt.Errorf("upload failed: %v", err), http.StatusInternalServerError)
return
}
- info, err := s.Commands().UploadAsset(ctx, bucketName, objectName, contentType, file, size)
+ cleanedFile, cleanedSize, err := removeExif(file, size, contentType)
+ if err != nil {
+ s.ErrorHandler()(w, r, fmt.Errorf("remove exif error: %v", err), http.StatusInternalServerError)
+ return
+ }
+
+ info, err := s.Commands().UploadAsset(ctx, bucketName, objectName, contentType, cleanedFile, cleanedSize)
if err != nil {
s.ErrorHandler()(w, r, fmt.Errorf("upload failed: %v", err), http.StatusInternalServerError)
return
@@ -191,3 +200,25 @@ func DownloadHandleFunc(s AssetsService, downloader Downloader) func(http.Respon
w.Write(data)
}
}
+
+func removeExif(file io.Reader, size int64, contentType string) (io.Reader, int64, error) {
+ if !isAllowedContentType(contentType) {
+ return file, size, nil
+ }
+ buf := new(bytes.Buffer)
+ _, err := buf.ReadFrom(file)
+ if err != nil {
+ return file, 0, err
+ }
+ data, err := exifremove.Remove(buf.Bytes())
+ if err != nil {
+ return nil, 0, err
+ }
+ return bytes.NewReader(data), int64(len(data)), nil
+}
+
+func isAllowedContentType(contentType string) bool {
+ return strings.HasSuffix(contentType, "png") ||
+ strings.HasSuffix(contentType, "jpg") ||
+ strings.HasSuffix(contentType, "jpeg")
+}
diff --git a/internal/api/grpc/admin/privacy_policy_converter.go b/internal/api/grpc/admin/privacy_policy_converter.go
index 2c2c9fb4cc..b21ea5451d 100644
--- a/internal/api/grpc/admin/privacy_policy_converter.go
+++ b/internal/api/grpc/admin/privacy_policy_converter.go
@@ -9,5 +9,6 @@ func UpdatePrivacyPolicyToDomain(req *admin_pb.UpdatePrivacyPolicyRequest) *doma
return &domain.PrivacyPolicy{
TOSLink: req.TosLink,
PrivacyLink: req.PrivacyLink,
+ HelpLink: req.HelpLink,
}
}
diff --git a/internal/api/grpc/auth/permission.go b/internal/api/grpc/auth/permission.go
index ea9ea464b2..41d771e018 100644
--- a/internal/api/grpc/auth/permission.go
+++ b/internal/api/grpc/auth/permission.go
@@ -11,7 +11,7 @@ import (
)
func (s *Server) ListMyZitadelPermissions(ctx context.Context, _ *auth_pb.ListMyZitadelPermissionsRequest) (*auth_pb.ListMyZitadelPermissionsResponse, error) {
- perms, err := s.query.MyZitadelPermissions(ctx, authz.GetCtxData(ctx).UserID)
+ perms, err := s.query.MyZitadelPermissions(ctx, authz.GetCtxData(ctx).OrgID, authz.GetCtxData(ctx).UserID)
if err != nil {
return nil, err
}
diff --git a/internal/api/grpc/auth/user.go b/internal/api/grpc/auth/user.go
index 067d2092fe..9c5bc7230b 100644
--- a/internal/api/grpc/auth/user.go
+++ b/internal/api/grpc/auth/user.go
@@ -168,6 +168,7 @@ func (s *Server) ListMyProjectOrgs(ctx context.Context, req *auth_pb.ListMyProje
if err != nil {
return nil, err
}
+
grants, err := s.query.UserGrants(ctx, &query.UserGrantsQueries{Queries: []query.SearchQuery{userGrantProjectID, userGrantUserID}})
if err != nil {
return nil, err
diff --git a/internal/api/grpc/management/policy_privacy_converter.go b/internal/api/grpc/management/policy_privacy_converter.go
index f78c5ac12d..8971815626 100644
--- a/internal/api/grpc/management/policy_privacy_converter.go
+++ b/internal/api/grpc/management/policy_privacy_converter.go
@@ -9,6 +9,7 @@ func AddPrivacyPolicyToDomain(req *mgmt_pb.AddCustomPrivacyPolicyRequest) *domai
return &domain.PrivacyPolicy{
TOSLink: req.TosLink,
PrivacyLink: req.PrivacyLink,
+ HelpLink: req.HelpLink,
}
}
@@ -16,5 +17,6 @@ func UpdatePrivacyPolicyToDomain(req *mgmt_pb.UpdateCustomPrivacyPolicyRequest)
return &domain.PrivacyPolicy{
TOSLink: req.TosLink,
PrivacyLink: req.PrivacyLink,
+ HelpLink: req.HelpLink,
}
}
diff --git a/internal/api/grpc/management/project_grant_converter.go b/internal/api/grpc/management/project_grant_converter.go
index 6c98c09dd4..966412f0fb 100644
--- a/internal/api/grpc/management/project_grant_converter.go
+++ b/internal/api/grpc/management/project_grant_converter.go
@@ -126,11 +126,6 @@ func ListProjectGrantMembersRequestToModel(ctx context.Context, req *mgmt_pb.Lis
if err != nil {
return nil, err
}
- ownerQuery, err := query.NewMemberResourceOwnerSearchQuery(authz.GetCtxData(ctx).OrgID)
- if err != nil {
- return nil, err
- }
- queries = append(queries, ownerQuery)
return &query.ProjectGrantMembersQuery{
MembersQuery: query.MembersQuery{
SearchRequest: query.SearchRequest{
@@ -143,6 +138,7 @@ func ListProjectGrantMembersRequestToModel(ctx context.Context, req *mgmt_pb.Lis
},
ProjectID: req.ProjectId,
GrantID: req.GrantId,
+ OrgID: authz.GetCtxData(ctx).OrgID,
}, nil
}
diff --git a/internal/api/grpc/org/converter.go b/internal/api/grpc/org/converter.go
index 587da8c8e8..dfd592c649 100644
--- a/internal/api/grpc/org/converter.go
+++ b/internal/api/grpc/org/converter.go
@@ -88,7 +88,7 @@ func OrgToPb(org *query.Org) *org_pb.Org {
Id: org.ID,
Name: org.Name,
PrimaryDomain: org.Domain,
- Details: object.AddToDetailsPb(org.Sequence, org.CreationDate, org.ResourceOwner),
+ Details: object.ToViewDetailsPb(org.Sequence, org.CreationDate, org.ChangeDate, org.ResourceOwner),
State: OrgStateToPb(org.State),
}
}
diff --git a/internal/api/grpc/policy/privacy_policy.go b/internal/api/grpc/policy/privacy_policy.go
index 6145668982..3913aa137c 100644
--- a/internal/api/grpc/policy/privacy_policy.go
+++ b/internal/api/grpc/policy/privacy_policy.go
@@ -11,6 +11,7 @@ func ModelPrivacyPolicyToPb(policy *query.PrivacyPolicy) *policy_pb.PrivacyPolic
IsDefault: policy.IsDefault,
TosLink: policy.TOSLink,
PrivacyLink: policy.PrivacyLink,
+ HelpLink: policy.HelpLink,
Details: object.ToViewDetailsPb(
policy.Sequence,
policy.CreationDate,
diff --git a/internal/api/grpc/text/custom_text.go b/internal/api/grpc/text/custom_text.go
index a3675345d8..5f4a1040a1 100644
--- a/internal/api/grpc/text/custom_text.go
+++ b/internal/api/grpc/text/custom_text.go
@@ -457,7 +457,6 @@ func FooterTextToPb(text domain.FooterText) *text_pb.FooterText {
Tos: text.TOS,
PrivacyPolicy: text.PrivacyPolicy,
Help: text.Help,
- HelpLink: text.HelpLink,
}
}
@@ -947,6 +946,5 @@ func FooterTextPbToDomain(text *text_pb.FooterText) domain.FooterText {
TOS: text.Tos,
PrivacyPolicy: text.PrivacyPolicy,
Help: text.Help,
- HelpLink: text.HelpLink,
}
}
diff --git a/internal/api/grpc/user/user_grant.go b/internal/api/grpc/user/user_grant.go
index bdb074398d..6ccf8db646 100644
--- a/internal/api/grpc/user/user_grant.go
+++ b/internal/api/grpc/user/user_grant.go
@@ -21,22 +21,23 @@ func UserGrantsToPb(assetPrefix string, grants []*query.UserGrant) []*user_pb.Us
func UserGrantToPb(assetPrefix string, grant *query.UserGrant) *user_pb.UserGrant {
return &user_pb.UserGrant{
- Id: grant.ID,
- UserId: grant.UserID,
- State: user_pb.UserGrantState_USER_GRANT_STATE_ACTIVE,
- RoleKeys: grant.Roles,
- ProjectId: grant.ProjectID,
- OrgId: grant.ResourceOwner,
- ProjectGrantId: grant.GrantID,
- UserName: grant.Username,
- FirstName: grant.FirstName,
- LastName: grant.LastName,
- Email: grant.Email,
- DisplayName: grant.DisplayName,
- OrgDomain: grant.OrgPrimaryDomain,
- OrgName: grant.OrgName,
- ProjectName: grant.ProjectName,
- AvatarUrl: domain.AvatarURL(assetPrefix, grant.UserResourceOwner, grant.AvatarURL),
+ Id: grant.ID,
+ UserId: grant.UserID,
+ State: user_pb.UserGrantState_USER_GRANT_STATE_ACTIVE,
+ RoleKeys: grant.Roles,
+ ProjectId: grant.ProjectID,
+ OrgId: grant.ResourceOwner,
+ ProjectGrantId: grant.GrantID,
+ UserName: grant.Username,
+ FirstName: grant.FirstName,
+ LastName: grant.LastName,
+ Email: grant.Email,
+ DisplayName: grant.DisplayName,
+ OrgDomain: grant.OrgPrimaryDomain,
+ OrgName: grant.OrgName,
+ ProjectName: grant.ProjectName,
+ AvatarUrl: domain.AvatarURL(assetPrefix, grant.UserResourceOwner, grant.AvatarURL),
+ PreferredLoginName: grant.PreferredLoginName,
Details: object.ToViewDetailsPb(
grant.Sequence,
grant.CreationDate,
diff --git a/internal/api/oidc/auth_request.go b/internal/api/oidc/auth_request.go
index 79460f19a6..5bde39d1ee 100644
--- a/internal/api/oidc/auth_request.go
+++ b/internal/api/oidc/auth_request.go
@@ -95,7 +95,7 @@ func (o *OPStorage) CreateAccessToken(ctx context.Context, req op.TokenRequest)
applicationID = authReq.ApplicationID
userOrgID = authReq.UserOrgID
}
- resp, err := o.command.AddUserToken(ctx, userOrgID, userAgentID, applicationID, req.GetSubject(), req.GetAudience(), req.GetScopes(), o.defaultAccessTokenLifetime) //PLANNED: lifetime from client
+ resp, err := o.command.AddUserToken(setContextUserSystem(ctx), userOrgID, userAgentID, applicationID, req.GetSubject(), req.GetAudience(), req.GetScopes(), o.defaultAccessTokenLifetime) //PLANNED: lifetime from client
if err != nil {
return "", time.Time{}, err
}
@@ -123,7 +123,7 @@ func (o *OPStorage) CreateAccessAndRefreshTokens(ctx context.Context, req op.Tok
if request, ok := req.(op.RefreshTokenRequest); ok {
request.SetCurrentScopes(scopes)
}
- resp, token, err := o.command.AddAccessAndRefreshToken(ctx, userOrgID, userAgentID, applicationID, req.GetSubject(),
+ resp, token, err := o.command.AddAccessAndRefreshToken(setContextUserSystem(ctx), userOrgID, userAgentID, applicationID, req.GetSubject(),
refreshToken, req.GetAudience(), scopes, authMethodsReferences, o.defaultAccessTokenLifetime,
o.defaultRefreshTokenIdleExpiration, o.defaultRefreshTokenExpiration, authTime) //PLANNED: lifetime from client
if err != nil {
@@ -171,7 +171,10 @@ func (o *OPStorage) TerminateSession(ctx context.Context, userID, clientID strin
if len(userIDs) == 0 {
return nil
}
- err = o.command.HumansSignOut(ctx, userAgentID, userIDs)
+ data := authz.CtxData{
+ UserID: userID,
+ }
+ err = o.command.HumansSignOut(authz.SetCtxData(ctx, data), userAgentID, userIDs)
logging.Log("OIDC-Dggt2").OnError(err).Error("error signing out")
return err
}
@@ -255,3 +258,10 @@ func (o *OPStorage) assertClientScopesForPAT(ctx context.Context, token *model.T
}
return nil
}
+
+func setContextUserSystem(ctx context.Context) context.Context {
+ data := authz.CtxData{
+ UserID: "SYSTEM",
+ }
+ return authz.SetCtxData(ctx, data)
+}
diff --git a/internal/api/ui/login/external_login_handler.go b/internal/api/ui/login/external_login_handler.go
index 166bc8474c..fd12f6ee70 100644
--- a/internal/api/ui/login/external_login_handler.go
+++ b/internal/api/ui/login/external_login_handler.go
@@ -203,7 +203,7 @@ func (l *Login) handleExternalUserAuthenticated(w http.ResponseWriter, r *http.R
}
instanceID := authz.GetInstance(r.Context()).ID
- err = l.authRepo.CheckExternalUserLogin(r.Context(), authReq.ID, userAgentID, instanceID, externalUser, domain.BrowserInfoFromRequest(r))
+ err = l.authRepo.CheckExternalUserLogin(setContext(r.Context(), ""), authReq.ID, userAgentID, instanceID, externalUser, domain.BrowserInfoFromRequest(r))
if err != nil {
if errors.IsNotFound(err) {
err = nil
diff --git a/internal/api/ui/login/jwt_handler.go b/internal/api/ui/login/jwt_handler.go
index 55b2471440..321d66b086 100644
--- a/internal/api/ui/login/jwt_handler.go
+++ b/internal/api/ui/login/jwt_handler.go
@@ -84,7 +84,7 @@ func (l *Login) handleJWTExtraction(w http.ResponseWriter, r *http.Request, auth
return
}
metadata := externalUser.Metadatas
- err = l.authRepo.CheckExternalUserLogin(r.Context(), authReq.ID, authReq.AgentID, authReq.InstanceID, externalUser, domain.BrowserInfoFromRequest(r))
+ err = l.authRepo.CheckExternalUserLogin(setContext(r.Context(), ""), authReq.ID, authReq.AgentID, authReq.InstanceID, externalUser, domain.BrowserInfoFromRequest(r))
if err != nil {
l.jwtExtractionUserNotFound(w, r, authReq, idpConfig, tokens, err)
return
diff --git a/internal/api/ui/login/renderer.go b/internal/api/ui/login/renderer.go
index 4e8901cf37..42c76d8e65 100644
--- a/internal/api/ui/login/renderer.go
+++ b/internal/api/ui/login/renderer.go
@@ -16,6 +16,7 @@ import (
"github.com/caos/zitadel/internal/domain"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/i18n"
+ "github.com/caos/zitadel/internal/notification/templates"
"github.com/caos/zitadel/internal/renderer"
"github.com/caos/zitadel/internal/static"
)
@@ -30,6 +31,10 @@ type Renderer struct {
staticStorage static.Storage
}
+type LanguageData struct {
+ Lang string
+}
+
func CreateRenderer(pathPrefix string, staticDir http.FileSystem, staticStorage static.Storage, cookieName string, defaultLanguage language.Tag) *Renderer {
r := &Renderer{
pathPrefix: pathPrefix,
@@ -345,24 +350,23 @@ func (l *Login) getBaseData(r *http.Request, authReq *domain.AuthRequest, title
CSRF: csrf.TemplateField(r),
Nonce: http_mw.GetNonce(r),
}
+ var privacyPolicy *domain.PrivacyPolicy
if authReq != nil {
baseData.LoginPolicy = authReq.LoginPolicy
baseData.LabelPolicy = authReq.LabelPolicy
baseData.IDPProviders = authReq.AllowedExternalIDPs
- if authReq.PrivacyPolicy != nil {
- baseData.TOSLink = authReq.PrivacyPolicy.TOSLink
- baseData.PrivacyLink = authReq.PrivacyPolicy.PrivacyLink
+ if authReq.PrivacyPolicy == nil {
+ return baseData
}
+ privacyPolicy = authReq.PrivacyPolicy
} else {
- privacyPolicy, err := l.query.DefaultPrivacyPolicy(r.Context())
+ policy, err := l.query.DefaultPrivacyPolicy(r.Context())
if err != nil {
return baseData
}
- if privacyPolicy != nil {
- baseData.TOSLink = privacyPolicy.TOSLink
- baseData.PrivacyLink = privacyPolicy.PrivacyLink
- }
+ privacyPolicy = policy.ToDomain()
}
+ baseData = l.setLinksOnBaseData(baseData, privacyPolicy)
return baseData
}
@@ -392,6 +396,26 @@ func (l *Login) getProfileData(authReq *domain.AuthRequest) profileData {
}
}
+func (l *Login) setLinksOnBaseData(baseData baseData, privacyPolicy *domain.PrivacyPolicy) baseData {
+ lang := LanguageData{
+ Lang: baseData.Lang,
+ }
+ baseData.TOSLink = privacyPolicy.TOSLink
+ baseData.PrivacyLink = privacyPolicy.PrivacyLink
+ baseData.HelpLink = privacyPolicy.HelpLink
+
+ if link, err := templates.ParseTemplateText(privacyPolicy.TOSLink, lang); err == nil {
+ baseData.TOSLink = link
+ }
+ if link, err := templates.ParseTemplateText(privacyPolicy.PrivacyLink, lang); err == nil {
+ baseData.PrivacyLink = link
+ }
+ if link, err := templates.ParseTemplateText(privacyPolicy.HelpLink, lang); err == nil {
+ baseData.HelpLink = link
+ }
+ return baseData
+}
+
func (l *Login) getErrorMessage(r *http.Request, err error) (errID, errMsg string) {
caosErr := new(caos_errs.CaosError)
if errors.As(err, &caosErr) {
@@ -519,6 +543,7 @@ type baseData struct {
DisplayLoginNameSuffix bool
TOSLink string
PrivacyLink string
+ HelpLink string
AuthReqID string
CSRF template.HTML
Nonce string
diff --git a/internal/api/ui/login/static/i18n/de.yaml b/internal/api/ui/login/static/i18n/de.yaml
index 281a09288b..c4758fb660 100644
--- a/internal/api/ui/login/static/i18n/de.yaml
+++ b/internal/api/ui/login/static/i18n/de.yaml
@@ -297,7 +297,6 @@ Footer:
Tos: AGB
PrivacyPolicy: Datenschutzerklärung
Help: Hilfe
- HelpLink: https://docs.zitadel.ch/docs/manuals/user-login
Errors:
Internal: Es ist ein interner Fehler aufgetreten
diff --git a/internal/api/ui/login/static/i18n/en.yaml b/internal/api/ui/login/static/i18n/en.yaml
index 9e9d01b5c5..8fb2f6678f 100644
--- a/internal/api/ui/login/static/i18n/en.yaml
+++ b/internal/api/ui/login/static/i18n/en.yaml
@@ -298,7 +298,6 @@ Footer:
Tos: TOS
PrivacyPolicy: Privacy policy
Help: Help
- HelpLink: https://docs.zitadel.ch/docs/manuals/user-login
Errors:
Internal: An internal error occured
diff --git a/internal/api/ui/login/static/i18n/it.yaml b/internal/api/ui/login/static/i18n/it.yaml
index b6a4784224..ec6b7254c4 100644
--- a/internal/api/ui/login/static/i18n/it.yaml
+++ b/internal/api/ui/login/static/i18n/it.yaml
@@ -298,7 +298,6 @@ Footer:
Tos: Termini di servizio
PrivacyPolicy: l'informativa sulla privacy
Help: Aiuto
- HelpLink: 'https://docs.zitadel.ch/docs/manuals/user-login'
Errors:
Internal: Si è verificato un errore interno
diff --git a/internal/api/ui/login/static/templates/footer.html b/internal/api/ui/login/static/templates/footer.html
index 98965443f1..e4f7578b51 100644
--- a/internal/api/ui/login/static/templates/footer.html
+++ b/internal/api/ui/login/static/templates/footer.html
@@ -13,6 +13,8 @@
{{ if .PrivacyLink }}
{{t "Footer.PrivacyPolicy"}}
{{end}}
- {{t "Footer.Help"}}
+ {{ if .HelpLink }}
+ {{t "Footer.Help"}}
+ {{end}}
{{end}}
diff --git a/internal/auth/repository/eventsourcing/eventstore/auth_request.go b/internal/auth/repository/eventsourcing/eventstore/auth_request.go
index f3326a4567..085154b503 100644
--- a/internal/auth/repository/eventsourcing/eventstore/auth_request.go
+++ b/internal/auth/repository/eventsourcing/eventstore/auth_request.go
@@ -560,7 +560,7 @@ func (repo *AuthRequestRepo) fillPolicies(ctx context.Context, request *domain.A
return err
}
request.LockoutPolicy = lockoutPolicyToDomain(lockoutPolicy)
- privacyPolicy, err := repo.getPrivacyPolicy(ctx, orgID)
+ privacyPolicy, err := repo.GetPrivacyPolicy(ctx, orgID)
if err != nil {
return err
}
@@ -936,8 +936,11 @@ func (repo *AuthRequestRepo) mfaSkippedOrSetUp(user *user_model.UserView, reques
return checkVerificationTime(user.MFAInitSkipped, request.LoginPolicy.MFAInitSkipLifetime)
}
-func (repo *AuthRequestRepo) getPrivacyPolicy(ctx context.Context, orgID string) (*domain.PrivacyPolicy, error) {
+func (repo *AuthRequestRepo) GetPrivacyPolicy(ctx context.Context, orgID string) (*domain.PrivacyPolicy, error) {
policy, err := repo.PrivacyPolicyProvider.PrivacyPolicyByOrg(ctx, orgID)
+ if errors.IsNotFound(err) {
+ return new(domain.PrivacyPolicy), nil
+ }
if err != nil {
return nil, err
}
@@ -957,6 +960,7 @@ func privacyPolicyToDomain(p *query.PrivacyPolicy) *domain.PrivacyPolicy {
Default: p.IsDefault,
TOSLink: p.TOSLink,
PrivacyLink: p.PrivacyLink,
+ HelpLink: p.HelpLink,
}
}
diff --git a/internal/auth/repository/eventsourcing/handler/user.go b/internal/auth/repository/eventsourcing/handler/user.go
index 8463777200..9fa3203d52 100644
--- a/internal/auth/repository/eventsourcing/handler/user.go
+++ b/internal/auth/repository/eventsourcing/handler/user.go
@@ -4,8 +4,9 @@ import (
"context"
"github.com/caos/logging"
+
"github.com/caos/zitadel/internal/errors"
- "github.com/caos/zitadel/internal/eventstore/v1"
+ v1 "github.com/caos/zitadel/internal/eventstore/v1"
es_models "github.com/caos/zitadel/internal/eventstore/v1/models"
"github.com/caos/zitadel/internal/eventstore/v1/query"
es_sdk "github.com/caos/zitadel/internal/eventstore/v1/sdk"
@@ -172,19 +173,12 @@ func (u *User) ProcessUser(event *es_models.Event) (err error) {
}
func (u *User) fillLoginNames(user *view_model.UserView) (err error) {
- org, err := u.getOrgByID(context.Background(), user.ResourceOwner)
+ userLoginMustBeDomain, primaryDomain, domains, err := u.loginNameInformation(context.Background(), user.ResourceOwner)
if err != nil {
return err
}
- policy := new(query2.OrgIAMPolicy)
- if policy == nil {
- policy, err = u.getDefaultOrgIAMPolicy(context.Background())
- if err != nil {
- return err
- }
- }
- user.SetLoginNames(policy, org.Domains)
- user.PreferredLoginName = user.GenerateLoginName(org.GetPrimaryDomain().Domain, policy.UserLoginMustBeDomain)
+ user.SetLoginNames(userLoginMustBeDomain, domains)
+ user.PreferredLoginName = user.GenerateLoginName(primaryDomain, userLoginMustBeDomain)
return nil
}
@@ -204,40 +198,26 @@ func (u *User) ProcessOrg(event *es_models.Event) (err error) {
}
func (u *User) fillLoginNamesOnOrgUsers(event *es_models.Event) error {
- org, err := u.getOrgByID(context.Background(), event.ResourceOwner)
+ userLoginMustBeDomain, _, domains, err := u.loginNameInformation(context.Background(), event.ResourceOwner)
if err != nil {
return err
}
- policy := new(query2.OrgIAMPolicy)
- if policy == nil {
- policy, err = u.getDefaultOrgIAMPolicy(context.Background())
- if err != nil {
- return err
- }
- }
users, err := u.view.UsersByOrgID(event.AggregateID)
if err != nil {
return err
}
for _, user := range users {
- user.SetLoginNames(policy, org.Domains)
+ user.SetLoginNames(userLoginMustBeDomain, domains)
}
return u.view.PutUsers(users, event)
}
func (u *User) fillPreferredLoginNamesOnOrgUsers(event *es_models.Event) error {
- org, err := u.getOrgByID(context.Background(), event.ResourceOwner)
+ userLoginMustBeDomain, primaryDomain, _, err := u.loginNameInformation(context.Background(), event.ResourceOwner)
if err != nil {
return err
}
- policy := new(query2.OrgIAMPolicy)
- if policy == nil {
- policy, err = u.getDefaultOrgIAMPolicy(context.Background())
- if err != nil {
- return err
- }
- }
- if !policy.UserLoginMustBeDomain {
+ if !userLoginMustBeDomain {
return nil
}
users, err := u.view.UsersByOrgID(event.AggregateID)
@@ -245,7 +225,7 @@ func (u *User) fillPreferredLoginNamesOnOrgUsers(event *es_models.Event) error {
return err
}
for _, user := range users {
- user.PreferredLoginName = user.GenerateLoginName(org.GetPrimaryDomain().Domain, policy.UserLoginMustBeDomain)
+ user.PreferredLoginName = user.GenerateLoginName(primaryDomain, userLoginMustBeDomain)
}
return u.view.PutUsers(users, event)
}
@@ -281,6 +261,17 @@ func (u *User) getOrgByID(ctx context.Context, orgID string) (*org_model.Org, er
return org_es_model.OrgToModel(esOrg), nil
}
-func (u *User) getDefaultOrgIAMPolicy(ctx context.Context) (*query2.OrgIAMPolicy, error) {
- return u.queries.DefaultOrgIAMPolicy(ctx)
+func (u *User) loginNameInformation(ctx context.Context, orgID string) (userLoginMustBeDomain bool, primaryDomain string, domains []*org_model.OrgDomain, err error) {
+ org, err := u.getOrgByID(ctx, orgID)
+ if err != nil {
+ return false, "", nil, err
+ }
+ if org.OrgIamPolicy == nil {
+ policy, err := u.queries.DefaultOrgIAMPolicy(ctx)
+ if err != nil {
+ return false, "", nil, err
+ }
+ userLoginMustBeDomain = policy.UserLoginMustBeDomain
+ }
+ return userLoginMustBeDomain, org.GetPrimaryDomain().Domain, org.Domains, nil
}
diff --git a/internal/command/custom_login_text.go b/internal/command/custom_login_text.go
index 9ea20b55d7..bbf53dd31a 100644
--- a/internal/command/custom_login_text.go
+++ b/internal/command/custom_login_text.go
@@ -1089,10 +1089,6 @@ func (c *Commands) createFooterTextEvents(ctx context.Context, agg *eventstore.A
if event != nil {
events = append(events, event)
}
- event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyFooterHelpLink, existingText.FooterHelpLink, text.Footer.HelpLink, text.Language, defaultText)
- if event != nil {
- events = append(events, event)
- }
return events
}
diff --git a/internal/command/custom_login_text_model.go b/internal/command/custom_login_text_model.go
index f5b806ff1c..9d50ee4b6f 100644
--- a/internal/command/custom_login_text_model.go
+++ b/internal/command/custom_login_text_model.go
@@ -2508,10 +2508,6 @@ func (wm *CustomLoginTextReadModel) handleFooterTextSetEvent(e *policy.CustomTex
wm.FooterHelp = e.Text
return
}
- if e.Key == domain.LoginKeyFooterHelpLink {
- wm.FooterHelpLink = e.Text
- return
- }
}
func (wm *CustomLoginTextReadModel) handleFooterTextRemoveEvent(e *policy.CustomTextRemovedEvent) {
@@ -2527,8 +2523,4 @@ func (wm *CustomLoginTextReadModel) handleFooterTextRemoveEvent(e *policy.Custom
wm.FooterHelp = ""
return
}
- if e.Key == domain.LoginKeyFooterHelpLink {
- wm.FooterHelpLink = ""
- return
- }
}
diff --git a/internal/command/iam_converter.go b/internal/command/iam_converter.go
index e9bab1285e..ddc9e81bc5 100644
--- a/internal/command/iam_converter.go
+++ b/internal/command/iam_converter.go
@@ -130,6 +130,7 @@ func writeModelToPrivacyPolicy(wm *PrivacyPolicyWriteModel) *domain.PrivacyPolic
ObjectRoot: writeModelToObjectRoot(wm.WriteModel),
TOSLink: wm.TOSLink,
PrivacyLink: wm.PrivacyLink,
+ HelpLink: wm.HelpLink,
}
}
diff --git a/internal/command/iam_custom_login_text_test.go b/internal/command/iam_custom_login_text_test.go
index f670c46696..b9b62e83fb 100644
--- a/internal/command/iam_custom_login_text_test.go
+++ b/internal/command/iam_custom_login_text_test.go
@@ -1143,11 +1143,6 @@ func TestCommandSide_SetCustomIAMLoginText(t *testing.T) {
&iam.NewAggregate().Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelp, "Help", language.English,
),
),
- eventFromEventPusher(
- iam.NewCustomTextSetEvent(context.Background(),
- &iam.NewAggregate().Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelpLink, "HelpLink", language.English,
- ),
- ),
},
),
),
@@ -1441,7 +1436,6 @@ func TestCommandSide_SetCustomIAMLoginText(t *testing.T) {
TOS: "TOS",
PrivacyPolicy: "PrivacyPolicy",
Help: "Help",
- HelpLink: "HelpLink",
},
},
},
@@ -2547,11 +2541,6 @@ func TestCommandSide_SetCustomIAMLoginText(t *testing.T) {
&iam.NewAggregate().Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelp, "Help", language.English,
),
),
- eventFromEventPusher(
- iam.NewCustomTextSetEvent(context.Background(),
- &iam.NewAggregate().Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelpLink, "HelpLink", language.English,
- ),
- ),
),
expectPush(
[]*repository.Event{
@@ -3645,11 +3634,6 @@ func TestCommandSide_SetCustomIAMLoginText(t *testing.T) {
&iam.NewAggregate().Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelp, language.English,
),
),
- eventFromEventPusher(
- iam.NewCustomTextRemovedEvent(context.Background(),
- &iam.NewAggregate().Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelpLink, language.English,
- ),
- ),
},
),
),
@@ -4797,11 +4781,6 @@ func TestCommandSide_SetCustomIAMLoginText(t *testing.T) {
&iam.NewAggregate().Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelp, "Help", language.English,
),
),
- eventFromEventPusher(
- iam.NewCustomTextSetEvent(context.Background(),
- &iam.NewAggregate().Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelpLink, "HelpLink", language.English,
- ),
- ),
eventFromEventPusher(
iam.NewCustomTextRemovedEvent(context.Background(),
&iam.NewAggregate().Aggregate, domain.LoginCustomText, domain.LoginKeySelectAccountTitle, language.English,
@@ -5892,11 +5871,6 @@ func TestCommandSide_SetCustomIAMLoginText(t *testing.T) {
&iam.NewAggregate().Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelp, language.English,
),
),
- eventFromEventPusher(
- iam.NewCustomTextRemovedEvent(context.Background(),
- &iam.NewAggregate().Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelpLink, language.English,
- ),
- ),
),
expectPush(
[]*repository.Event{
@@ -6990,11 +6964,6 @@ func TestCommandSide_SetCustomIAMLoginText(t *testing.T) {
&iam.NewAggregate().Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelp, "Help", language.English,
),
),
- eventFromEventPusher(
- iam.NewCustomTextSetEvent(context.Background(),
- &iam.NewAggregate().Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelpLink, "HelpLink", language.English,
- ),
- ),
},
),
),
@@ -7288,7 +7257,6 @@ func TestCommandSide_SetCustomIAMLoginText(t *testing.T) {
TOS: "TOS",
PrivacyPolicy: "PrivacyPolicy",
Help: "Help",
- HelpLink: "HelpLink",
},
},
},
diff --git a/internal/command/iam_policy_privacy.go b/internal/command/iam_policy_privacy.go
index 290662a3b1..6f428e65d5 100644
--- a/internal/command/iam_policy_privacy.go
+++ b/internal/command/iam_policy_privacy.go
@@ -52,7 +52,7 @@ func (c *Commands) addDefaultPrivacyPolicy(ctx context.Context, iamAgg *eventsto
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-M00rJ", "Errors.IAM.PrivacyPolicy.AlreadyExists")
}
- return iam_repo.NewPrivacyPolicyAddedEvent(ctx, iamAgg, policy.TOSLink, policy.PrivacyLink), nil
+ return iam_repo.NewPrivacyPolicyAddedEvent(ctx, iamAgg, policy.TOSLink, policy.PrivacyLink, policy.HelpLink), nil
}
func (c *Commands) ChangeDefaultPrivacyPolicy(ctx context.Context, policy *domain.PrivacyPolicy) (*domain.PrivacyPolicy, error) {
@@ -65,7 +65,7 @@ func (c *Commands) ChangeDefaultPrivacyPolicy(ctx context.Context, policy *domai
}
iamAgg := IAMAggregateFromWriteModel(&existingPolicy.PrivacyPolicyWriteModel.WriteModel)
- changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, iamAgg, policy.TOSLink, policy.PrivacyLink)
+ changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, iamAgg, policy.TOSLink, policy.PrivacyLink, policy.HelpLink)
if !hasChanged {
return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-4M9vs", "Errors.IAM.LabelPolicy.NotChanged")
}
diff --git a/internal/command/iam_policy_privacy_model.go b/internal/command/iam_policy_privacy_model.go
index ba5cc80d64..83b5aafb8e 100644
--- a/internal/command/iam_policy_privacy_model.go
+++ b/internal/command/iam_policy_privacy_model.go
@@ -56,7 +56,8 @@ func (wm *IAMPrivacyPolicyWriteModel) NewChangedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
tosLink,
- privacyLink string,
+ privacyLink,
+ helpLink string,
) (*iam.PrivacyPolicyChangedEvent, bool) {
changes := make([]policy.PrivacyPolicyChanges, 0)
@@ -66,6 +67,9 @@ func (wm *IAMPrivacyPolicyWriteModel) NewChangedEvent(
if wm.PrivacyLink != privacyLink {
changes = append(changes, policy.ChangePrivacyLink(privacyLink))
}
+ if wm.HelpLink != helpLink {
+ changes = append(changes, policy.ChangeHelpLink(helpLink))
+ }
if len(changes) == 0 {
return nil, false
}
diff --git a/internal/command/iam_policy_privacy_test.go b/internal/command/iam_policy_privacy_test.go
index 8c0a2eaf5a..79ee3e2633 100644
--- a/internal/command/iam_policy_privacy_test.go
+++ b/internal/command/iam_policy_privacy_test.go
@@ -2,6 +2,10 @@ package command
import (
"context"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+
"github.com/caos/zitadel/internal/domain"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore"
@@ -9,8 +13,6 @@ import (
"github.com/caos/zitadel/internal/eventstore/v1/models"
"github.com/caos/zitadel/internal/repository/iam"
"github.com/caos/zitadel/internal/repository/policy"
- "github.com/stretchr/testify/assert"
- "testing"
)
func TestCommandSide_AddDefaultPrivacyPolicy(t *testing.T) {
@@ -42,6 +44,7 @@ func TestCommandSide_AddDefaultPrivacyPolicy(t *testing.T) {
&iam.NewAggregate().Aggregate,
"TOSLink",
"PrivacyLink",
+ "HelpLink",
),
),
),
@@ -52,6 +55,7 @@ func TestCommandSide_AddDefaultPrivacyPolicy(t *testing.T) {
policy: &domain.PrivacyPolicy{
TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink",
+ HelpLink: "HelpLink",
},
},
res: res{
@@ -71,6 +75,7 @@ func TestCommandSide_AddDefaultPrivacyPolicy(t *testing.T) {
&iam.NewAggregate().Aggregate,
"TOSLink",
"PrivacyLink",
+ "HelpLink",
),
),
},
@@ -82,6 +87,7 @@ func TestCommandSide_AddDefaultPrivacyPolicy(t *testing.T) {
policy: &domain.PrivacyPolicy{
TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink",
+ HelpLink: "HelpLink",
},
},
res: res{
@@ -92,6 +98,7 @@ func TestCommandSide_AddDefaultPrivacyPolicy(t *testing.T) {
},
TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink",
+ HelpLink: "HelpLink",
},
},
},
@@ -108,6 +115,7 @@ func TestCommandSide_AddDefaultPrivacyPolicy(t *testing.T) {
&iam.NewAggregate().Aggregate,
"",
"",
+ "",
),
),
},
@@ -119,6 +127,7 @@ func TestCommandSide_AddDefaultPrivacyPolicy(t *testing.T) {
policy: &domain.PrivacyPolicy{
TOSLink: "",
PrivacyLink: "",
+ HelpLink: "",
},
},
res: res{
@@ -129,6 +138,7 @@ func TestCommandSide_AddDefaultPrivacyPolicy(t *testing.T) {
},
TOSLink: "",
PrivacyLink: "",
+ HelpLink: "",
},
},
},
@@ -183,6 +193,7 @@ func TestCommandSide_ChangeDefaultPrivacyPolicy(t *testing.T) {
policy: &domain.PrivacyPolicy{
TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink",
+ HelpLink: "HelpLink",
},
},
res: res{
@@ -200,6 +211,7 @@ func TestCommandSide_ChangeDefaultPrivacyPolicy(t *testing.T) {
&iam.NewAggregate().Aggregate,
"TOSLink",
"PrivacyLink",
+ "HelpLink",
),
),
),
@@ -210,6 +222,7 @@ func TestCommandSide_ChangeDefaultPrivacyPolicy(t *testing.T) {
policy: &domain.PrivacyPolicy{
TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink",
+ HelpLink: "HelpLink",
},
},
res: res{
@@ -227,6 +240,7 @@ func TestCommandSide_ChangeDefaultPrivacyPolicy(t *testing.T) {
&iam.NewAggregate().Aggregate,
"TOSLink",
"PrivacyLink",
+ "HelpLink",
),
),
),
@@ -236,6 +250,7 @@ func TestCommandSide_ChangeDefaultPrivacyPolicy(t *testing.T) {
newDefaultPrivacyPolicyChangedEvent(context.Background(),
"TOSLinkChanged",
"PrivacyLinkChanged",
+ "HelpLinkChanged",
),
),
},
@@ -247,6 +262,7 @@ func TestCommandSide_ChangeDefaultPrivacyPolicy(t *testing.T) {
policy: &domain.PrivacyPolicy{
TOSLink: "TOSLinkChanged",
PrivacyLink: "PrivacyLinkChanged",
+ HelpLink: "HelpLinkChanged",
},
},
res: res{
@@ -257,6 +273,7 @@ func TestCommandSide_ChangeDefaultPrivacyPolicy(t *testing.T) {
},
TOSLink: "TOSLinkChanged",
PrivacyLink: "PrivacyLinkChanged",
+ HelpLink: "HelpLinkChanged",
},
},
},
@@ -280,12 +297,13 @@ func TestCommandSide_ChangeDefaultPrivacyPolicy(t *testing.T) {
}
}
-func newDefaultPrivacyPolicyChangedEvent(ctx context.Context, tosLink, privacyLink string) *iam.PrivacyPolicyChangedEvent {
+func newDefaultPrivacyPolicyChangedEvent(ctx context.Context, tosLink, privacyLink, helpLink string) *iam.PrivacyPolicyChangedEvent {
event, _ := iam.NewPrivacyPolicyChangedEvent(ctx,
&iam.NewAggregate().Aggregate,
[]policy.PrivacyPolicyChanges{
policy.ChangeTOSLink(tosLink),
policy.ChangePrivacyLink(privacyLink),
+ policy.ChangeHelpLink(helpLink),
},
)
return event
diff --git a/internal/command/org_custom_login_text_test.go b/internal/command/org_custom_login_text_test.go
index d0bc837f43..40d28862b1 100644
--- a/internal/command/org_custom_login_text_test.go
+++ b/internal/command/org_custom_login_text_test.go
@@ -1161,11 +1161,6 @@ func TestCommandSide_SetCustomOrgLoginText(t *testing.T) {
&org.NewAggregate("org1", "org1").Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelp, "Help", language.English,
),
),
- eventFromEventPusher(
- org.NewCustomTextSetEvent(context.Background(),
- &org.NewAggregate("org1", "org1").Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelpLink, "HelpLink", language.English,
- ),
- ),
},
),
),
@@ -1460,7 +1455,6 @@ func TestCommandSide_SetCustomOrgLoginText(t *testing.T) {
TOS: "TOS",
PrivacyPolicy: "PrivacyPolicy",
Help: "Help",
- HelpLink: "HelpLink",
},
},
},
@@ -2566,11 +2560,6 @@ func TestCommandSide_SetCustomOrgLoginText(t *testing.T) {
&org.NewAggregate("org1", "org1").Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelp, "Help", language.English,
),
),
- eventFromEventPusher(
- org.NewCustomTextSetEvent(context.Background(),
- &org.NewAggregate("org1", "org1").Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelpLink, "HelpLink", language.English,
- ),
- ),
),
expectPush(
[]*repository.Event{
@@ -3664,11 +3653,6 @@ func TestCommandSide_SetCustomOrgLoginText(t *testing.T) {
&org.NewAggregate("org1", "org1").Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelp, language.English,
),
),
- eventFromEventPusher(
- org.NewCustomTextRemovedEvent(context.Background(),
- &org.NewAggregate("org1", "org1").Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelpLink, language.English,
- ),
- ),
},
),
),
@@ -4816,11 +4800,6 @@ func TestCommandSide_SetCustomOrgLoginText(t *testing.T) {
&org.NewAggregate("org1", "org1").Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelp, "Help", language.English,
),
),
- eventFromEventPusher(
- org.NewCustomTextSetEvent(context.Background(),
- &org.NewAggregate("org1", "org1").Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelpLink, "HelpLink", language.English,
- ),
- ),
eventFromEventPusher(
org.NewCustomTextRemovedEvent(context.Background(),
&org.NewAggregate("org1", "org1").Aggregate, domain.LoginCustomText, domain.LoginKeySelectAccountTitle, language.English,
@@ -5911,11 +5890,6 @@ func TestCommandSide_SetCustomOrgLoginText(t *testing.T) {
&org.NewAggregate("org1", "org1").Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelp, language.English,
),
),
- eventFromEventPusher(
- org.NewCustomTextRemovedEvent(context.Background(),
- &org.NewAggregate("org1", "org1").Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelpLink, language.English,
- ),
- ),
),
expectPush(
[]*repository.Event{
@@ -7009,11 +6983,6 @@ func TestCommandSide_SetCustomOrgLoginText(t *testing.T) {
&org.NewAggregate("org1", "org1").Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelp, "Help", language.English,
),
),
- eventFromEventPusher(
- org.NewCustomTextSetEvent(context.Background(),
- &org.NewAggregate("org1", "org1").Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelpLink, "HelpLink", language.English,
- ),
- ),
},
),
),
@@ -7308,7 +7277,6 @@ func TestCommandSide_SetCustomOrgLoginText(t *testing.T) {
TOS: "TOS",
PrivacyPolicy: "PrivacyPolicy",
Help: "Help",
- HelpLink: "HelpLink",
},
},
},
diff --git a/internal/command/org_features_test.go b/internal/command/org_features_test.go
index 917fdfde52..0128d5fd46 100644
--- a/internal/command/org_features_test.go
+++ b/internal/command/org_features_test.go
@@ -5,12 +5,13 @@ import (
"testing"
"time"
- "github.com/caos/zitadel/internal/repository/user"
- "github.com/caos/zitadel/internal/static/mock"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
"golang.org/x/text/language"
+ "github.com/caos/zitadel/internal/repository/user"
+ "github.com/caos/zitadel/internal/static/mock"
+
"github.com/caos/zitadel/internal/domain"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore"
@@ -266,6 +267,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
&iam.NewAggregate().Aggregate,
"toslink",
"privacylink",
+ "helpLink",
),
),
),
@@ -470,6 +472,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
&iam.NewAggregate().Aggregate,
"toslink",
"privacylink",
+ "helplink",
),
),
),
@@ -686,6 +689,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
&iam.NewAggregate().Aggregate,
"toslink",
"privacylink",
+ "helplink",
),
),
),
@@ -912,6 +916,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
&iam.NewAggregate().Aggregate,
"toslink",
"privacylink",
+ "helplink",
),
),
),
@@ -1203,6 +1208,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
&iam.NewAggregate().Aggregate,
"toslink",
"privacylink",
+ "helplink",
),
),
),
@@ -1420,6 +1426,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
&iam.NewAggregate().Aggregate,
"toslink",
"privacylink",
+ "helplink",
),
),
),
@@ -1684,6 +1691,7 @@ func TestCommandSide_RemoveOrgFeatures(t *testing.T) {
&iam.NewAggregate().Aggregate,
"toslink",
"privacylink",
+ "helplink",
),
),
),
diff --git a/internal/command/org_policy_org_iam.go b/internal/command/org_policy_org_iam.go
index e327c0467a..8001e29cd0 100644
--- a/internal/command/org_policy_org_iam.go
+++ b/internal/command/org_policy_org_iam.go
@@ -80,7 +80,7 @@ func (c *Commands) RemoveOrgIAMPolicy(ctx context.Context, orgID string) error {
return err
}
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
- return caos_errs.ThrowNotFound(nil, "ORG-Dvsh3", "Errors.Org.OrgIAM.NotFound")
+ return caos_errs.ThrowNotFound(nil, "ORG-Dvsh3", "Errors.Org.OrgIAMPolicy.NotFound")
}
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.PolicyOrgIAMWriteModel.WriteModel)
diff --git a/internal/command/org_policy_privacy.go b/internal/command/org_policy_privacy.go
index 9c45e2cc37..3dea4c36ad 100644
--- a/internal/command/org_policy_privacy.go
+++ b/internal/command/org_policy_privacy.go
@@ -48,7 +48,8 @@ func (c *Commands) AddPrivacyPolicy(ctx context.Context, resourceOwner string, p
ctx,
orgAgg,
policy.TOSLink,
- policy.PrivacyLink))
+ policy.PrivacyLink,
+ policy.HelpLink))
if err != nil {
return nil, err
}
@@ -74,7 +75,7 @@ func (c *Commands) ChangePrivacyPolicy(ctx context.Context, resourceOwner string
}
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.PrivacyPolicyWriteModel.WriteModel)
- changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, orgAgg, policy.TOSLink, policy.PrivacyLink)
+ changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, orgAgg, policy.TOSLink, policy.PrivacyLink, policy.HelpLink)
if !hasChanged {
return nil, caos_errs.ThrowPreconditionFailed(nil, "Org-4N9fs", "Errors.Org.PrivacyPolicy.NotChanged")
}
diff --git a/internal/command/org_policy_privacy_model.go b/internal/command/org_policy_privacy_model.go
index 171b48f75a..d5ff331dbd 100644
--- a/internal/command/org_policy_privacy_model.go
+++ b/internal/command/org_policy_privacy_model.go
@@ -57,7 +57,8 @@ func (wm *OrgPrivacyPolicyWriteModel) NewChangedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
tosLink,
- privacyLink string,
+ privacyLink,
+ helpLink string,
) (*org.PrivacyPolicyChangedEvent, bool) {
changes := make([]policy.PrivacyPolicyChanges, 0)
@@ -67,6 +68,9 @@ func (wm *OrgPrivacyPolicyWriteModel) NewChangedEvent(
if wm.PrivacyLink != privacyLink {
changes = append(changes, policy.ChangePrivacyLink(privacyLink))
}
+ if wm.HelpLink != helpLink {
+ changes = append(changes, policy.ChangeHelpLink(helpLink))
+ }
if len(changes) == 0 {
return nil, false
}
diff --git a/internal/command/org_policy_privacy_test.go b/internal/command/org_policy_privacy_test.go
index ba762371cb..36a8b1ba81 100644
--- a/internal/command/org_policy_privacy_test.go
+++ b/internal/command/org_policy_privacy_test.go
@@ -46,6 +46,7 @@ func TestCommandSide_AddPrivacyPolicy(t *testing.T) {
policy: &domain.PrivacyPolicy{
TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink",
+ HelpLink: "HelpLink",
},
},
res: res{
@@ -63,6 +64,7 @@ func TestCommandSide_AddPrivacyPolicy(t *testing.T) {
&org.NewAggregate("org1", "org1").Aggregate,
"TOSLink",
"PrivacyLink",
+ "HelpLink",
),
),
),
@@ -74,6 +76,7 @@ func TestCommandSide_AddPrivacyPolicy(t *testing.T) {
policy: &domain.PrivacyPolicy{
TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink",
+ HelpLink: "HelpLink",
},
},
res: res{
@@ -93,6 +96,7 @@ func TestCommandSide_AddPrivacyPolicy(t *testing.T) {
&org.NewAggregate("org1", "org1").Aggregate,
"TOSLink",
"PrivacyLink",
+ "HelpLink",
),
),
},
@@ -105,6 +109,7 @@ func TestCommandSide_AddPrivacyPolicy(t *testing.T) {
policy: &domain.PrivacyPolicy{
TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink",
+ HelpLink: "HelpLink",
},
},
res: res{
@@ -115,6 +120,7 @@ func TestCommandSide_AddPrivacyPolicy(t *testing.T) {
},
TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink",
+ HelpLink: "HelpLink",
},
},
},
@@ -131,6 +137,7 @@ func TestCommandSide_AddPrivacyPolicy(t *testing.T) {
&org.NewAggregate("org1", "org1").Aggregate,
"",
"",
+ "",
),
),
},
@@ -143,6 +150,7 @@ func TestCommandSide_AddPrivacyPolicy(t *testing.T) {
policy: &domain.PrivacyPolicy{
TOSLink: "",
PrivacyLink: "",
+ HelpLink: "",
},
},
res: res{
@@ -153,6 +161,7 @@ func TestCommandSide_AddPrivacyPolicy(t *testing.T) {
},
TOSLink: "",
PrivacyLink: "",
+ HelpLink: "",
},
},
},
@@ -207,6 +216,7 @@ func TestCommandSide_ChangePrivacyPolicy(t *testing.T) {
policy: &domain.PrivacyPolicy{
TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink",
+ HelpLink: "HelpLink",
},
},
res: res{
@@ -227,6 +237,7 @@ func TestCommandSide_ChangePrivacyPolicy(t *testing.T) {
policy: &domain.PrivacyPolicy{
TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink",
+ HelpLink: "HelpLink",
},
},
res: res{
@@ -244,6 +255,7 @@ func TestCommandSide_ChangePrivacyPolicy(t *testing.T) {
&org.NewAggregate("org1", "org1").Aggregate,
"TOSLink",
"PrivacyLink",
+ "HelpLink",
),
),
),
@@ -255,6 +267,7 @@ func TestCommandSide_ChangePrivacyPolicy(t *testing.T) {
policy: &domain.PrivacyPolicy{
TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink",
+ HelpLink: "HelpLink",
},
},
res: res{
@@ -272,13 +285,14 @@ func TestCommandSide_ChangePrivacyPolicy(t *testing.T) {
&org.NewAggregate("org1", "org1").Aggregate,
"TOSLink",
"PrivacyLink",
+ "HelpLink",
),
),
),
expectPush(
[]*repository.Event{
eventFromEventPusher(
- newPrivacyPolicyChangedEvent(context.Background(), "org1", "TOSLinkChange", "PrivacyLinkChange"),
+ newPrivacyPolicyChangedEvent(context.Background(), "org1", "TOSLinkChange", "PrivacyLinkChange", "HelpLinkChange"),
),
},
),
@@ -290,6 +304,7 @@ func TestCommandSide_ChangePrivacyPolicy(t *testing.T) {
policy: &domain.PrivacyPolicy{
TOSLink: "TOSLinkChange",
PrivacyLink: "PrivacyLinkChange",
+ HelpLink: "HelpLinkChange",
},
},
res: res{
@@ -300,6 +315,7 @@ func TestCommandSide_ChangePrivacyPolicy(t *testing.T) {
},
TOSLink: "TOSLinkChange",
PrivacyLink: "PrivacyLinkChange",
+ HelpLink: "HelpLinkChange",
},
},
},
@@ -314,13 +330,14 @@ func TestCommandSide_ChangePrivacyPolicy(t *testing.T) {
&org.NewAggregate("org1", "org1").Aggregate,
"TOSLink",
"PrivacyLink",
+ "HelpLink",
),
),
),
expectPush(
[]*repository.Event{
eventFromEventPusher(
- newPrivacyPolicyChangedEvent(context.Background(), "org1", "", ""),
+ newPrivacyPolicyChangedEvent(context.Background(), "org1", "", "", ""),
),
},
),
@@ -332,6 +349,7 @@ func TestCommandSide_ChangePrivacyPolicy(t *testing.T) {
policy: &domain.PrivacyPolicy{
TOSLink: "",
PrivacyLink: "",
+ HelpLink: "",
},
},
res: res{
@@ -342,6 +360,7 @@ func TestCommandSide_ChangePrivacyPolicy(t *testing.T) {
},
TOSLink: "",
PrivacyLink: "",
+ HelpLink: "",
},
},
},
@@ -424,6 +443,7 @@ func TestCommandSide_RemovePrivacyPolicy(t *testing.T) {
&org.NewAggregate("org1", "org1").Aggregate,
"TOSLink",
"PrivacyLink",
+ "HelpLink",
),
),
),
@@ -467,12 +487,13 @@ func TestCommandSide_RemovePrivacyPolicy(t *testing.T) {
}
}
-func newPrivacyPolicyChangedEvent(ctx context.Context, orgID string, tosLink, privacyLink string) *org.PrivacyPolicyChangedEvent {
+func newPrivacyPolicyChangedEvent(ctx context.Context, orgID string, tosLink, privacyLink, helpLink string) *org.PrivacyPolicyChangedEvent {
event, _ := org.NewPrivacyPolicyChangedEvent(ctx,
&org.NewAggregate(orgID, orgID).Aggregate,
[]policy.PrivacyPolicyChanges{
policy.ChangeTOSLink(tosLink),
policy.ChangePrivacyLink(privacyLink),
+ policy.ChangeHelpLink(helpLink),
},
)
return event
diff --git a/internal/command/policy_privacy_model.go b/internal/command/policy_privacy_model.go
index 07e489f447..9dbd6722af 100644
--- a/internal/command/policy_privacy_model.go
+++ b/internal/command/policy_privacy_model.go
@@ -11,6 +11,7 @@ type PrivacyPolicyWriteModel struct {
TOSLink string
PrivacyLink string
+ HelpLink string
State domain.PolicyState
}
@@ -20,6 +21,7 @@ func (wm *PrivacyPolicyWriteModel) Reduce() error {
case *policy.PrivacyPolicyAddedEvent:
wm.TOSLink = e.TOSLink
wm.PrivacyLink = e.PrivacyLink
+ wm.HelpLink = e.HelpLink
wm.State = domain.PolicyStateActive
case *policy.PrivacyPolicyChangedEvent:
if e.PrivacyLink != nil {
@@ -28,6 +30,9 @@ func (wm *PrivacyPolicyWriteModel) Reduce() error {
if e.TOSLink != nil {
wm.TOSLink = *e.TOSLink
}
+ if e.HelpLink != nil {
+ wm.HelpLink = *e.HelpLink
+ }
case *policy.PrivacyPolicyRemovedEvent:
wm.State = domain.PolicyStateRemoved
}
diff --git a/internal/command/user.go b/internal/command/user.go
index f6df852a7e..cb8ef5236f 100644
--- a/internal/command/user.go
+++ b/internal/command/user.go
@@ -38,7 +38,7 @@ func (c *Commands) ChangeUsername(ctx context.Context, orgID, userID, userName s
orgIAMPolicy, err := c.getOrgIAMPolicy(ctx, orgID)
if err != nil {
- return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-38fnu", "Errors.Org.OrgIAM.NotExisting")
+ return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-38fnu", "Errors.Org.OrgIAMPolicy.NotExisting")
}
if err := CheckOrgIAMPolicyForUserName(userName, orgIAMPolicy); err != nil {
@@ -188,7 +188,7 @@ func (c *Commands) RemoveUser(ctx context.Context, userID, resourceOwner string,
orgIAMPolicy, err := c.getOrgIAMPolicy(ctx, existingUser.ResourceOwner)
if err != nil {
- return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-3M9fs", "Errors.Org.OrgIAM.NotExisting")
+ return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-3M9fs", "Errors.Org.OrgIAMPolicy.NotExisting")
}
var events []eventstore.Command
userAgg := UserAggregateFromWriteModel(&existingUser.WriteModel)
diff --git a/internal/command/user_human.go b/internal/command/user_human.go
index e93fe3183b..370f77a594 100644
--- a/internal/command/user_human.go
+++ b/internal/command/user_human.go
@@ -34,7 +34,7 @@ func (c *Commands) AddHuman(ctx context.Context, orgID string, human *domain.Hum
}
pwPolicy, err := c.getOrgPasswordComplexityPolicy(ctx, orgID)
if err != nil {
- return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-M5Fsd", "Errors.Org.PasswordComplexity.NotFound")
+ return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-M5Fsd", "Errors.Org.PasswordComplexityPolicy.NotFound")
}
events, addedHuman, err := c.addHuman(ctx, orgID, human, orgIAMPolicy, pwPolicy, initCodeGenerator, phoneCodeGenerator)
if err != nil {
@@ -63,7 +63,7 @@ func (c *Commands) ImportHuman(ctx context.Context, orgID string, human *domain.
}
pwPolicy, err := c.getOrgPasswordComplexityPolicy(ctx, orgID)
if err != nil {
- return nil, nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-4N8gs", "Errors.Org.PasswordComplexity.NotFound")
+ return nil, nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-4N8gs", "Errors.Org.PasswordComplexityPolicy.NotFound")
}
events, addedHuman, addedCode, code, err := c.importHuman(ctx, orgID, human, passwordless, orgIAMPolicy, pwPolicy, initCodeGenerator, phoneCodeGenerator, passwordlessCodeGenerator)
if err != nil {
@@ -128,7 +128,7 @@ func (c *Commands) RegisterHuman(ctx context.Context, orgID string, human *domai
}
pwPolicy, err := c.getOrgPasswordComplexityPolicy(ctx, orgID)
if err != nil {
- return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-M5Fsd", "Errors.Org.PasswordComplexity.NotFound")
+ return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-M5Fsd", "Errors.Org.PasswordComplexityPolicy.NotFound")
}
loginPolicy, err := c.getOrgLoginPolicy(ctx, orgID)
if err != nil {
diff --git a/internal/command/user_human_otp.go b/internal/command/user_human_otp.go
index 5eab8c9b9d..5e0ad5cccc 100644
--- a/internal/command/user_human_otp.go
+++ b/internal/command/user_human_otp.go
@@ -28,7 +28,7 @@ func (c *Commands) AddHumanOTP(ctx context.Context, userID, resourceowner string
orgPolicy, err := c.getOrgIAMPolicy(ctx, org.AggregateID)
if err != nil {
logging.Log("COMMAND-y5zv9").WithError(err).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Debug("unable to get org policy for loginname")
- return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-8ugTs", "Errors.Org.OrgIAM.NotFound")
+ return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-8ugTs", "Errors.Org.OrgIAMPolicy.NotFound")
}
otpWriteModel, err := c.otpWriteModelByID(ctx, userID, resourceowner)
if err != nil {
diff --git a/internal/domain/custom_login_text.go b/internal/domain/custom_login_text.go
index 386eaf22ba..df7c2a9d77 100644
--- a/internal/domain/custom_login_text.go
+++ b/internal/domain/custom_login_text.go
@@ -294,7 +294,6 @@ const (
LoginKeyFooterTOS = LoginKeyFooter + "Tos"
LoginKeyFooterPrivacyPolicy = LoginKeyFooter + "PrivacyPolicy"
LoginKeyFooterHelp = LoginKeyFooter + "Help"
- LoginKeyFooterHelpLink = LoginKeyFooter + "HelpLink"
)
type CustomLoginText struct {
@@ -637,7 +636,6 @@ type FooterText struct {
TOS string
PrivacyPolicy string
Help string
- HelpLink string
}
type PasswordlessPromptScreenText struct {
diff --git a/internal/domain/policy_privacy.go b/internal/domain/policy_privacy.go
index 9eb58f3897..eec1ff8c26 100644
--- a/internal/domain/policy_privacy.go
+++ b/internal/domain/policy_privacy.go
@@ -12,4 +12,5 @@ type PrivacyPolicy struct {
TOSLink string
PrivacyLink string
+ HelpLink string
}
diff --git a/internal/iam/repository/view/model/custom_text.go b/internal/iam/repository/view/model/custom_text.go
index 93fa3b3b37..81bb6bbef8 100644
--- a/internal/iam/repository/view/model/custom_text.go
+++ b/internal/iam/repository/view/model/custom_text.go
@@ -894,7 +894,4 @@ func footerKeyToDomain(text *CustomTextView, result *domain.CustomLoginText) {
if text.Key == domain.LoginKeyFooterHelp {
result.Footer.Help = text.Text
}
- if text.Key == domain.LoginKeyFooterHelpLink {
- result.Footer.HelpLink = text.Text
- }
}
diff --git a/internal/notification/repository/eventsourcing/handler/notify_user.go b/internal/notification/repository/eventsourcing/handler/notify_user.go
index 4cef14f6f8..ad4727c3df 100644
--- a/internal/notification/repository/eventsourcing/handler/notify_user.go
+++ b/internal/notification/repository/eventsourcing/handler/notify_user.go
@@ -3,14 +3,14 @@ package handler
import (
"context"
+ "github.com/caos/logging"
+
caos_errs "github.com/caos/zitadel/internal/errors"
- "github.com/caos/zitadel/internal/eventstore/v1"
+ v1 "github.com/caos/zitadel/internal/eventstore/v1"
es_sdk "github.com/caos/zitadel/internal/eventstore/v1/sdk"
org_view "github.com/caos/zitadel/internal/org/repository/view"
query2 "github.com/caos/zitadel/internal/query"
- "github.com/caos/logging"
-
es_models "github.com/caos/zitadel/internal/eventstore/v1/models"
"github.com/caos/zitadel/internal/eventstore/v1/query"
"github.com/caos/zitadel/internal/eventstore/v1/spooler"
@@ -163,23 +163,16 @@ func (u *NotifyUser) ProcessOrg(event *es_models.Event) (err error) {
}
func (u *NotifyUser) fillLoginNamesOnOrgUsers(event *es_models.Event) error {
- org, err := u.getOrgByID(context.Background(), event.ResourceOwner)
+ userLoginMustBeDomain, _, domains, err := u.loginNameInformation(context.Background(), event.ResourceOwner)
if err != nil {
return err
}
- policy := new(query2.OrgIAMPolicy)
- if policy == nil {
- policy, err = u.getDefaultOrgIAMPolicy(context.Background())
- if err != nil {
- return err
- }
- }
users, err := u.view.NotifyUsersByOrgID(event.AggregateID)
if err != nil {
return err
}
for _, user := range users {
- user.SetLoginNames(policy, org.Domains)
+ user.SetLoginNames(userLoginMustBeDomain, domains)
err := u.view.PutNotifyUser(user, event)
if err != nil {
return err
@@ -189,16 +182,11 @@ func (u *NotifyUser) fillLoginNamesOnOrgUsers(event *es_models.Event) error {
}
func (u *NotifyUser) fillPreferredLoginNamesOnOrgUsers(event *es_models.Event) error {
- org, err := u.getOrgByID(context.Background(), event.ResourceOwner)
+ userLoginMustBeDomain, primaryDomain, _, err := u.loginNameInformation(context.Background(), event.ResourceOwner)
if err != nil {
return err
}
-
- policy, err := u.getDefaultOrgIAMPolicy(context.Background())
- if err != nil {
- return err
- }
- if !policy.UserLoginMustBeDomain {
+ if !userLoginMustBeDomain {
return nil
}
users, err := u.view.NotifyUsersByOrgID(event.AggregateID)
@@ -206,7 +194,7 @@ func (u *NotifyUser) fillPreferredLoginNamesOnOrgUsers(event *es_models.Event) e
return err
}
for _, user := range users {
- user.PreferredLoginName = user.GenerateLoginName(org.GetPrimaryDomain().Domain, policy.UserLoginMustBeDomain)
+ user.PreferredLoginName = user.GenerateLoginName(primaryDomain, userLoginMustBeDomain)
err := u.view.PutNotifyUser(user, event)
if err != nil {
return err
@@ -216,17 +204,12 @@ func (u *NotifyUser) fillPreferredLoginNamesOnOrgUsers(event *es_models.Event) e
}
func (u *NotifyUser) fillLoginNames(user *view_model.NotifyUser) (err error) {
- org, err := u.getOrgByID(context.Background(), user.ResourceOwner)
+ userLoginMustBeDomain, primaryDomain, domains, err := u.loginNameInformation(context.Background(), user.ResourceOwner)
if err != nil {
return err
}
-
- policy, err := u.getDefaultOrgIAMPolicy(context.Background())
- if err != nil {
- return err
- }
- user.SetLoginNames(policy, org.Domains)
- user.PreferredLoginName = user.GenerateLoginName(org.GetPrimaryDomain().Domain, policy.UserLoginMustBeDomain)
+ user.SetLoginNames(userLoginMustBeDomain, domains)
+ user.PreferredLoginName = user.GenerateLoginName(primaryDomain, userLoginMustBeDomain)
return nil
}
@@ -261,6 +244,17 @@ func (u *NotifyUser) getOrgByID(ctx context.Context, orgID string) (*org_model.O
return org_es_model.OrgToModel(esOrg), nil
}
-func (u *NotifyUser) getDefaultOrgIAMPolicy(ctx context.Context) (*query2.OrgIAMPolicy, error) {
- return u.queries.DefaultOrgIAMPolicy(ctx)
+func (u *NotifyUser) loginNameInformation(ctx context.Context, orgID string) (userLoginMustBeDomain bool, primaryDomain string, domains []*org_model.OrgDomain, err error) {
+ org, err := u.getOrgByID(ctx, orgID)
+ if err != nil {
+ return false, "", nil, err
+ }
+ if org.OrgIamPolicy == nil {
+ policy, err := u.queries.DefaultOrgIAMPolicy(ctx)
+ if err != nil {
+ return false, "", nil, err
+ }
+ userLoginMustBeDomain = policy.UserLoginMustBeDomain
+ }
+ return userLoginMustBeDomain, org.GetPrimaryDomain().Domain, org.Domains, nil
}
diff --git a/internal/query/custom_text.go b/internal/query/custom_text.go
index 676ea8a084..a938e51497 100644
--- a/internal/query/custom_text.go
+++ b/internal/query/custom_text.go
@@ -1101,7 +1101,4 @@ func footerKeyToDomain(text *CustomText, result *domain.CustomLoginText) {
if text.Key == domain.LoginKeyFooterHelp {
result.Footer.Help = text.Text
}
- if text.Key == domain.LoginKeyFooterHelpLink {
- result.Footer.HelpLink = text.Text
- }
}
diff --git a/internal/query/privacy_policy.go b/internal/query/privacy_policy.go
index 98fe95d190..b8544706df 100644
--- a/internal/query/privacy_policy.go
+++ b/internal/query/privacy_policy.go
@@ -24,6 +24,7 @@ type PrivacyPolicy struct {
TOSLink string
PrivacyLink string
+ HelpLink string
IsDefault bool
}
@@ -64,6 +65,10 @@ var (
name: projection.PrivacyPolicyTOSLinkCol,
table: privacyTable,
}
+ PrivacyColHelpLink = Column{
+ name: projection.PrivacyPolicyHelpLinkCol,
+ table: privacyTable,
+ }
PrivacyColIsDefault = Column{
name: projection.PrivacyPolicyIsDefaultCol,
table: privacyTable,
@@ -125,6 +130,7 @@ func preparePrivacyPolicyQuery() (sq.SelectBuilder, func(*sql.Row) (*PrivacyPoli
PrivacyColResourceOwner.identifier(),
PrivacyColPrivacyLink.identifier(),
PrivacyColTOSLink.identifier(),
+ PrivacyColHelpLink.identifier(),
PrivacyColIsDefault.identifier(),
PrivacyColState.identifier(),
).
@@ -139,6 +145,7 @@ func preparePrivacyPolicyQuery() (sq.SelectBuilder, func(*sql.Row) (*PrivacyPoli
&policy.ResourceOwner,
&policy.PrivacyLink,
&policy.TOSLink,
+ &policy.HelpLink,
&policy.IsDefault,
&policy.State,
)
@@ -151,3 +158,12 @@ func preparePrivacyPolicyQuery() (sq.SelectBuilder, func(*sql.Row) (*PrivacyPoli
return policy, nil
}
}
+
+func (p *PrivacyPolicy) ToDomain() *domain.PrivacyPolicy {
+ return &domain.PrivacyPolicy{
+ TOSLink: p.TOSLink,
+ PrivacyLink: p.PrivacyLink,
+ HelpLink: p.HelpLink,
+ Default: p.IsDefault,
+ }
+}
diff --git a/internal/query/privacy_policy_test.go b/internal/query/privacy_policy_test.go
index 389ad4d46e..c554bbbdea 100644
--- a/internal/query/privacy_policy_test.go
+++ b/internal/query/privacy_policy_test.go
@@ -35,6 +35,7 @@ func Test_PrivacyPolicyPrepares(t *testing.T) {
` projections.privacy_policies.resource_owner,`+
` projections.privacy_policies.privacy_link,`+
` projections.privacy_policies.tos_link,`+
+ ` projections.privacy_policies.help_link,`+
` projections.privacy_policies.is_default,`+
` projections.privacy_policies.state`+
` FROM projections.privacy_policies`),
@@ -43,7 +44,7 @@ func Test_PrivacyPolicyPrepares(t *testing.T) {
),
err: func(err error) (error, bool) {
if !errs.IsNotFound(err) {
- return fmt.Errorf("err should be zitadel.NotFoundError got: %w", err), false
+ return fmt.Errorf("err should be NotFoundError got: %w", err), false
}
return nil, true
},
@@ -62,6 +63,7 @@ func Test_PrivacyPolicyPrepares(t *testing.T) {
` projections.privacy_policies.resource_owner,`+
` projections.privacy_policies.privacy_link,`+
` projections.privacy_policies.tos_link,`+
+ ` projections.privacy_policies.help_link,`+
` projections.privacy_policies.is_default,`+
` projections.privacy_policies.state`+
` FROM projections.privacy_policies`),
@@ -73,6 +75,7 @@ func Test_PrivacyPolicyPrepares(t *testing.T) {
"resource_owner",
"privacy_link",
"tos_link",
+ "help_link",
"is_default",
"state",
},
@@ -84,6 +87,7 @@ func Test_PrivacyPolicyPrepares(t *testing.T) {
"ro",
"privacy.ch",
"tos.ch",
+ "help.ch",
true,
domain.PolicyStateActive,
},
@@ -98,6 +102,7 @@ func Test_PrivacyPolicyPrepares(t *testing.T) {
State: domain.PolicyStateActive,
PrivacyLink: "privacy.ch",
TOSLink: "tos.ch",
+ HelpLink: "help.ch",
IsDefault: true,
},
},
@@ -113,6 +118,7 @@ func Test_PrivacyPolicyPrepares(t *testing.T) {
` projections.privacy_policies.resource_owner,`+
` projections.privacy_policies.privacy_link,`+
` projections.privacy_policies.tos_link,`+
+ ` projections.privacy_policies.help_link,`+
` projections.privacy_policies.is_default,`+
` projections.privacy_policies.state`+
` FROM projections.privacy_policies`),
diff --git a/internal/query/project_grant_member.go b/internal/query/project_grant_member.go
index 154dffae23..4673bc6db9 100644
--- a/internal/query/project_grant_member.go
+++ b/internal/query/project_grant_member.go
@@ -58,15 +58,21 @@ var (
type ProjectGrantMembersQuery struct {
MembersQuery
- ProjectID, GrantID string
+ ProjectID, GrantID, OrgID string
}
func (q *ProjectGrantMembersQuery) toQuery(query sq.SelectBuilder) sq.SelectBuilder {
return q.MembersQuery.
toQuery(query).
- Where(sq.Eq{
- ProjectGrantMemberProjectID.identifier(): q.ProjectID,
- ProjectGrantMemberGrantID.identifier(): q.GrantID,
+ Where(sq.And{
+ sq.Eq{
+ ProjectGrantMemberProjectID.identifier(): q.ProjectID,
+ ProjectGrantMemberGrantID.identifier(): q.GrantID,
+ },
+ sq.Or{
+ sq.Eq{ProjectGrantColumnResourceOwner.identifier(): q.OrgID},
+ sq.Eq{ProjectGrantColumnGrantedOrgID.identifier(): q.OrgID},
+ },
})
}
@@ -117,6 +123,7 @@ func prepareProjectGrantMembersQuery() (sq.SelectBuilder, func(*sql.Rows) (*Memb
LeftJoin(join(HumanUserIDCol, ProjectGrantMemberUserID)).
LeftJoin(join(MachineUserIDCol, ProjectGrantMemberUserID)).
LeftJoin(join(LoginNameUserIDCol, ProjectGrantMemberUserID)).
+ LeftJoin(join(ProjectGrantColumnGrantID, ProjectGrantMemberGrantID)).
Where(
sq.Eq{LoginNameIsPrimaryCol.identifier(): true},
).PlaceholderFormat(sq.Dollar),
diff --git a/internal/query/project_grant_member_test.go b/internal/query/project_grant_member_test.go
index 9e7e0102a1..58069c2908 100644
--- a/internal/query/project_grant_member_test.go
+++ b/internal/query/project_grant_member_test.go
@@ -34,6 +34,8 @@ var (
"ON members.user_id = projections.users_machines.user_id " +
"LEFT JOIN projections.login_names " +
"ON members.user_id = projections.login_names.user_id " +
+ "LEFT JOIN projections.project_grants " +
+ "ON members.grant_id = projections.project_grants.grant_id " +
"WHERE projections.login_names.is_primary = $1")
projectGrantMembersColumns = []string{
"creation_date",
diff --git a/internal/query/projection/flow.go b/internal/query/projection/flow.go
index eeed193e13..2e4dd699cf 100644
--- a/internal/query/projection/flow.go
+++ b/internal/query/projection/flow.go
@@ -76,6 +76,7 @@ func (p *FlowProjection) reduceTriggerActionsSetEventType(event eventstore.Event
[]handler.Condition{
handler.NewCond(FlowTypeCol, e.FlowType),
handler.NewCond(FlowTriggerTypeCol, e.TriggerType),
+ handler.NewCond(FlowResourceOwnerCol, e.Aggregate().ResourceOwner),
},
)
for i, id := range e.ActionIDs {
@@ -104,6 +105,7 @@ func (p *FlowProjection) reduceFlowClearedEventType(event eventstore.Event) (*ha
e,
[]handler.Condition{
handler.NewCond(FlowTypeCol, e.FlowType),
+ handler.NewCond(FlowResourceOwnerCol, e.Aggregate().ResourceOwner),
},
), nil
}
diff --git a/internal/query/projection/flow_test.go b/internal/query/projection/flow_test.go
index 6124875d79..8d23f95672 100644
--- a/internal/query/projection/flow_test.go
+++ b/internal/query/projection/flow_test.go
@@ -39,10 +39,11 @@ func TestFlowProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "DELETE FROM projections.flows_triggers WHERE (flow_type = $1) AND (trigger_type = $2)",
+ expectedStmt: "DELETE FROM projections.flows_triggers WHERE (flow_type = $1) AND (trigger_type = $2) AND (resource_owner = $3)",
expectedArgs: []interface{}{
domain.FlowTypeExternalAuthentication,
domain.TriggerTypePostAuthentication,
+ "ro-id",
},
},
{
@@ -93,9 +94,10 @@ func TestFlowProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "DELETE FROM projections.flows_triggers WHERE (flow_type = $1)",
+ expectedStmt: "DELETE FROM projections.flows_triggers WHERE (flow_type = $1) AND (resource_owner = $2)",
expectedArgs: []interface{}{
domain.FlowTypeExternalAuthentication,
+ "ro-id",
},
},
},
diff --git a/internal/query/projection/privacy_policy.go b/internal/query/projection/privacy_policy.go
index 2a36ac2cc8..0f722fe398 100644
--- a/internal/query/projection/privacy_policy.go
+++ b/internal/query/projection/privacy_policy.go
@@ -26,6 +26,7 @@ const (
PrivacyPolicyInstanceIDCol = "instance_id"
PrivacyPolicyPrivacyLinkCol = "privacy_link"
PrivacyPolicyTOSLinkCol = "tos_link"
+ PrivacyPolicyHelpLinkCol = "help_link"
)
type PrivacyPolicyProjection struct {
@@ -48,6 +49,7 @@ func NewPrivacyPolicyProjection(ctx context.Context, config crdb.StatementHandle
crdb.NewColumn(PrivacyPolicyInstanceIDCol, crdb.ColumnTypeText),
crdb.NewColumn(PrivacyPolicyPrivacyLinkCol, crdb.ColumnTypeText),
crdb.NewColumn(PrivacyPolicyTOSLinkCol, crdb.ColumnTypeText),
+ crdb.NewColumn(PrivacyPolicyHelpLinkCol, crdb.ColumnTypeText),
},
crdb.NewPrimaryKey(PrivacyPolicyInstanceIDCol, PrivacyPolicyIDCol),
),
@@ -114,6 +116,7 @@ func (p *PrivacyPolicyProjection) reduceAdded(event eventstore.Event) (*handler.
handler.NewCol(PrivacyPolicyStateCol, domain.PolicyStateActive),
handler.NewCol(PrivacyPolicyPrivacyLinkCol, policyEvent.PrivacyLink),
handler.NewCol(PrivacyPolicyTOSLinkCol, policyEvent.TOSLink),
+ handler.NewCol(PrivacyPolicyHelpLinkCol, policyEvent.HelpLink),
handler.NewCol(PrivacyPolicyIsDefaultCol, isDefault),
handler.NewCol(PrivacyPolicyResourceOwnerCol, policyEvent.Aggregate().ResourceOwner),
handler.NewCol(PrivacyPolicyInstanceIDCol, policyEvent.Aggregate().InstanceID),
@@ -140,6 +143,9 @@ func (p *PrivacyPolicyProjection) reduceChanged(event eventstore.Event) (*handle
if policyEvent.TOSLink != nil {
cols = append(cols, handler.NewCol(PrivacyPolicyTOSLinkCol, *policyEvent.TOSLink))
}
+ if policyEvent.HelpLink != nil {
+ cols = append(cols, handler.NewCol(PrivacyPolicyHelpLinkCol, *policyEvent.HelpLink))
+ }
return crdb.NewUpdateStatement(
&policyEvent,
cols,
diff --git a/internal/query/projection/privacy_policy_test.go b/internal/query/projection/privacy_policy_test.go
index 9748f6a3d8..e74c03cb2b 100644
--- a/internal/query/projection/privacy_policy_test.go
+++ b/internal/query/projection/privacy_policy_test.go
@@ -30,7 +30,8 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) {
org.AggregateType,
[]byte(`{
"tosLink": "http://tos.link",
- "privacyLink": "http://privacy.link"
+ "privacyLink": "http://privacy.link",
+ "helpLink": "http://help.link"
}`),
), org.PrivacyPolicyAddedEventMapper),
},
@@ -43,7 +44,7 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "INSERT INTO projections.privacy_policies (creation_date, change_date, sequence, id, state, privacy_link, tos_link, is_default, resource_owner, instance_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
+ expectedStmt: "INSERT INTO projections.privacy_policies (creation_date, change_date, sequence, id, state, privacy_link, tos_link, help_link, is_default, resource_owner, instance_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)",
expectedArgs: []interface{}{
anyArg{},
anyArg{},
@@ -52,6 +53,7 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) {
domain.PolicyStateActive,
"http://privacy.link",
"http://tos.link",
+ "http://help.link",
false,
"ro-id",
"instance-id",
@@ -70,7 +72,8 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) {
org.AggregateType,
[]byte(`{
"tosLink": "http://tos.link",
- "privacyLink": "http://privacy.link"
+ "privacyLink": "http://privacy.link",
+ "helpLink": "http://help.link"
}`),
), org.PrivacyPolicyChangedEventMapper),
},
@@ -82,12 +85,13 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.privacy_policies SET (change_date, sequence, privacy_link, tos_link) = ($1, $2, $3, $4) WHERE (id = $5)",
+ expectedStmt: "UPDATE projections.privacy_policies SET (change_date, sequence, privacy_link, tos_link, help_link) = ($1, $2, $3, $4, $5) WHERE (id = $6)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
"http://privacy.link",
"http://tos.link",
+ "http://help.link",
"agg-id",
},
},
@@ -131,7 +135,8 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) {
iam.AggregateType,
[]byte(`{
"tosLink": "http://tos.link",
- "privacyLink": "http://privacy.link"
+ "privacyLink": "http://privacy.link",
+ "helpLink": "http://help.link"
}`),
), iam.PrivacyPolicyAddedEventMapper),
},
@@ -143,7 +148,7 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "INSERT INTO projections.privacy_policies (creation_date, change_date, sequence, id, state, privacy_link, tos_link, is_default, resource_owner, instance_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
+ expectedStmt: "INSERT INTO projections.privacy_policies (creation_date, change_date, sequence, id, state, privacy_link, tos_link, help_link, is_default, resource_owner, instance_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)",
expectedArgs: []interface{}{
anyArg{},
anyArg{},
@@ -152,6 +157,7 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) {
domain.PolicyStateActive,
"http://privacy.link",
"http://tos.link",
+ "http://help.link",
true,
"ro-id",
"instance-id",
@@ -170,7 +176,8 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) {
iam.AggregateType,
[]byte(`{
"tosLink": "http://tos.link",
- "privacyLink": "http://privacy.link"
+ "privacyLink": "http://privacy.link",
+ "helpLink": "http://help.link"
}`),
), iam.PrivacyPolicyChangedEventMapper),
},
@@ -182,12 +189,13 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
- expectedStmt: "UPDATE projections.privacy_policies SET (change_date, sequence, privacy_link, tos_link) = ($1, $2, $3, $4) WHERE (id = $5)",
+ expectedStmt: "UPDATE projections.privacy_policies SET (change_date, sequence, privacy_link, tos_link, help_link) = ($1, $2, $3, $4, $5) WHERE (id = $6)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
"http://privacy.link",
"http://tos.link",
+ "http://help.link",
"agg-id",
},
},
diff --git a/internal/query/user_grant.go b/internal/query/user_grant.go
index 5dbe1f9ab1..dd9d0f8bde 100644
--- a/internal/query/user_grant.go
+++ b/internal/query/user_grant.go
@@ -25,15 +25,16 @@ type UserGrant struct {
GrantID string
State domain.UserGrantState
- UserID string
- Username string
- UserType domain.UserType
- UserResourceOwner string
- FirstName string
- LastName string
- Email string
- DisplayName string
- AvatarURL string
+ UserID string
+ Username string
+ UserType domain.UserType
+ UserResourceOwner string
+ FirstName string
+ LastName string
+ Email string
+ DisplayName string
+ AvatarURL string
+ PreferredLoginName string
ResourceOwner string
OrgName string
@@ -255,6 +256,7 @@ func prepareUserGrantQuery() (sq.SelectBuilder, func(*sql.Row) (*UserGrant, erro
HumanEmailCol.identifier(),
HumanDisplayNameCol.identifier(),
HumanAvatarURLCol.identifier(),
+ LoginNameNameCol.identifier(),
UserGrantResourceOwner.identifier(),
OrgColumnName.identifier(),
@@ -268,20 +270,24 @@ func prepareUserGrantQuery() (sq.SelectBuilder, func(*sql.Row) (*UserGrant, erro
LeftJoin(join(HumanUserIDCol, UserGrantUserID)).
LeftJoin(join(OrgColumnID, UserGrantResourceOwner)).
LeftJoin(join(ProjectColumnID, UserGrantProjectID)).
- PlaceholderFormat(sq.Dollar),
+ LeftJoin(join(LoginNameUserIDCol, UserGrantUserID)).
+ Where(
+ sq.Eq{LoginNameIsPrimaryCol.identifier(): true},
+ ).PlaceholderFormat(sq.Dollar),
func(row *sql.Row) (*UserGrant, error) {
g := new(UserGrant)
var (
- roles = pq.StringArray{}
- username sql.NullString
- firstName sql.NullString
- userType sql.NullInt32
- userOwner sql.NullString
- lastName sql.NullString
- email sql.NullString
- displayName sql.NullString
- avatarURL sql.NullString
+ roles = pq.StringArray{}
+ username sql.NullString
+ firstName sql.NullString
+ userType sql.NullInt32
+ userOwner sql.NullString
+ lastName sql.NullString
+ email sql.NullString
+ displayName sql.NullString
+ avatarURL sql.NullString
+ preferredLoginName sql.NullString
orgName sql.NullString
orgDomain sql.NullString
@@ -307,6 +313,7 @@ func prepareUserGrantQuery() (sq.SelectBuilder, func(*sql.Row) (*UserGrant, erro
&email,
&displayName,
&avatarURL,
+ &preferredLoginName,
&g.ResourceOwner,
&orgName,
@@ -331,6 +338,7 @@ func prepareUserGrantQuery() (sq.SelectBuilder, func(*sql.Row) (*UserGrant, erro
g.Email = email.String
g.DisplayName = displayName.String
g.AvatarURL = avatarURL.String
+ g.PreferredLoginName = preferredLoginName.String
g.OrgName = orgName.String
g.OrgPrimaryDomain = orgDomain.String
g.ProjectName = projectName.String
@@ -358,6 +366,7 @@ func prepareUserGrantsQuery() (sq.SelectBuilder, func(*sql.Rows) (*UserGrants, e
HumanEmailCol.identifier(),
HumanDisplayNameCol.identifier(),
HumanAvatarURLCol.identifier(),
+ LoginNameNameCol.identifier(),
UserGrantResourceOwner.identifier(),
OrgColumnName.identifier(),
@@ -373,7 +382,10 @@ func prepareUserGrantsQuery() (sq.SelectBuilder, func(*sql.Rows) (*UserGrants, e
LeftJoin(join(HumanUserIDCol, UserGrantUserID)).
LeftJoin(join(OrgColumnID, UserGrantResourceOwner)).
LeftJoin(join(ProjectColumnID, UserGrantProjectID)).
- PlaceholderFormat(sq.Dollar),
+ LeftJoin(join(LoginNameUserIDCol, UserGrantUserID)).
+ Where(
+ sq.Eq{LoginNameIsPrimaryCol.identifier(): true},
+ ).PlaceholderFormat(sq.Dollar),
func(rows *sql.Rows) (*UserGrants, error) {
userGrants := make([]*UserGrant, 0)
var count uint64
@@ -381,15 +393,16 @@ func prepareUserGrantsQuery() (sq.SelectBuilder, func(*sql.Rows) (*UserGrants, e
g := new(UserGrant)
var (
- roles = pq.StringArray{}
- username sql.NullString
- userType sql.NullInt32
- userOwner sql.NullString
- firstName sql.NullString
- lastName sql.NullString
- email sql.NullString
- displayName sql.NullString
- avatarURL sql.NullString
+ roles = pq.StringArray{}
+ username sql.NullString
+ userType sql.NullInt32
+ userOwner sql.NullString
+ firstName sql.NullString
+ lastName sql.NullString
+ email sql.NullString
+ displayName sql.NullString
+ avatarURL sql.NullString
+ preferredLoginName sql.NullString
orgName sql.NullString
orgDomain sql.NullString
@@ -415,6 +428,7 @@ func prepareUserGrantsQuery() (sq.SelectBuilder, func(*sql.Rows) (*UserGrants, e
&email,
&displayName,
&avatarURL,
+ &preferredLoginName,
&g.ResourceOwner,
&orgName,
@@ -438,6 +452,7 @@ func prepareUserGrantsQuery() (sq.SelectBuilder, func(*sql.Rows) (*UserGrants, e
g.Email = email.String
g.DisplayName = displayName.String
g.AvatarURL = avatarURL.String
+ g.PreferredLoginName = preferredLoginName.String
g.OrgName = orgName.String
g.OrgPrimaryDomain = orgDomain.String
g.ProjectName = projectName.String
diff --git a/internal/query/user_grant_test.go b/internal/query/user_grant_test.go
index f84a5b00ab..da4b30e4ca 100644
--- a/internal/query/user_grant_test.go
+++ b/internal/query/user_grant_test.go
@@ -32,6 +32,7 @@ var (
", projections.users_humans.email" +
", projections.users_humans.display_name" +
", projections.users_humans.avatar_key" +
+ ", projections.login_names.login_name" +
", projections.user_grants.resource_owner" +
", projections.orgs.name" +
", projections.orgs.primary_domain" +
@@ -41,7 +42,9 @@ var (
" LEFT JOIN projections.users ON projections.user_grants.user_id = projections.users.id" +
" LEFT JOIN projections.users_humans ON projections.user_grants.user_id = projections.users_humans.user_id" +
" LEFT JOIN projections.orgs ON projections.user_grants.resource_owner = projections.orgs.id" +
- " LEFT JOIN projections.projects ON projections.user_grants.project_id = projections.projects.id")
+ " LEFT JOIN projections.projects ON projections.user_grants.project_id = projections.projects.id" +
+ " LEFT JOIN projections.login_names ON projections.user_grants.user_id = projections.login_names.user_id" +
+ " WHERE projections.login_names.is_primary = $1")
userGrantCols = []string{
"id",
"creation_date",
@@ -59,6 +62,7 @@ var (
"email",
"display_name",
"avatar_key",
+ "login_name",
"resource_owner", //user_grant resource owner
"name", //org name
"primary_domain",
@@ -82,6 +86,7 @@ var (
", projections.users_humans.email" +
", projections.users_humans.display_name" +
", projections.users_humans.avatar_key" +
+ ", projections.login_names.login_name" +
", projections.user_grants.resource_owner" +
", projections.orgs.name" +
", projections.orgs.primary_domain" +
@@ -92,7 +97,9 @@ var (
" LEFT JOIN projections.users ON projections.user_grants.user_id = projections.users.id" +
" LEFT JOIN projections.users_humans ON projections.user_grants.user_id = projections.users_humans.user_id" +
" LEFT JOIN projections.orgs ON projections.user_grants.resource_owner = projections.orgs.id" +
- " LEFT JOIN projections.projects ON projections.user_grants.project_id = projections.projects.id")
+ " LEFT JOIN projections.projects ON projections.user_grants.project_id = projections.projects.id" +
+ " LEFT JOIN projections.login_names ON projections.user_grants.user_id = projections.login_names.user_id" +
+ " WHERE projections.login_names.is_primary = $1")
userGrantsCols = append(
userGrantCols,
"count",
@@ -152,6 +159,7 @@ func Test_UserGrantPrepares(t *testing.T) {
"email",
"display-name",
"avatar-key",
+ "login-name",
"ro",
"org-name",
"primary-domain",
@@ -161,27 +169,28 @@ func Test_UserGrantPrepares(t *testing.T) {
),
},
object: &UserGrant{
- ID: "id",
- CreationDate: testNow,
- ChangeDate: testNow,
- Sequence: 20211111,
- Roles: []string{"role-key"},
- GrantID: "grant-id",
- State: domain.UserGrantStateActive,
- UserID: "user-id",
- Username: "username",
- UserType: domain.UserTypeHuman,
- UserResourceOwner: "resource-owner",
- FirstName: "first-name",
- LastName: "last-name",
- Email: "email",
- DisplayName: "display-name",
- AvatarURL: "avatar-key",
- ResourceOwner: "ro",
- OrgName: "org-name",
- OrgPrimaryDomain: "primary-domain",
- ProjectID: "project-id",
- ProjectName: "project-name",
+ ID: "id",
+ CreationDate: testNow,
+ ChangeDate: testNow,
+ Sequence: 20211111,
+ Roles: []string{"role-key"},
+ GrantID: "grant-id",
+ State: domain.UserGrantStateActive,
+ UserID: "user-id",
+ Username: "username",
+ UserType: domain.UserTypeHuman,
+ UserResourceOwner: "resource-owner",
+ FirstName: "first-name",
+ LastName: "last-name",
+ Email: "email",
+ DisplayName: "display-name",
+ AvatarURL: "avatar-key",
+ PreferredLoginName: "login-name",
+ ResourceOwner: "ro",
+ OrgName: "org-name",
+ OrgPrimaryDomain: "primary-domain",
+ ProjectID: "project-id",
+ ProjectName: "project-name",
},
},
{
@@ -208,6 +217,7 @@ func Test_UserGrantPrepares(t *testing.T) {
nil,
nil,
nil,
+ "login-name",
"ro",
"org-name",
"primary-domain",
@@ -217,27 +227,28 @@ func Test_UserGrantPrepares(t *testing.T) {
),
},
object: &UserGrant{
- ID: "id",
- CreationDate: testNow,
- ChangeDate: testNow,
- Sequence: 20211111,
- Roles: []string{"role-key"},
- GrantID: "grant-id",
- State: domain.UserGrantStateActive,
- UserID: "user-id",
- Username: "username",
- UserType: domain.UserTypeMachine,
- UserResourceOwner: "resource-owner",
- FirstName: "",
- LastName: "",
- Email: "",
- DisplayName: "",
- AvatarURL: "",
- ResourceOwner: "ro",
- OrgName: "org-name",
- OrgPrimaryDomain: "primary-domain",
- ProjectID: "project-id",
- ProjectName: "project-name",
+ ID: "id",
+ CreationDate: testNow,
+ ChangeDate: testNow,
+ Sequence: 20211111,
+ Roles: []string{"role-key"},
+ GrantID: "grant-id",
+ State: domain.UserGrantStateActive,
+ UserID: "user-id",
+ Username: "username",
+ UserType: domain.UserTypeMachine,
+ UserResourceOwner: "resource-owner",
+ FirstName: "",
+ LastName: "",
+ Email: "",
+ DisplayName: "",
+ AvatarURL: "",
+ PreferredLoginName: "login-name",
+ ResourceOwner: "ro",
+ OrgName: "org-name",
+ OrgPrimaryDomain: "primary-domain",
+ ProjectID: "project-id",
+ ProjectName: "project-name",
},
},
{
@@ -264,6 +275,7 @@ func Test_UserGrantPrepares(t *testing.T) {
"email",
"display-name",
"avatar-key",
+ "login-name",
"ro",
nil,
nil,
@@ -273,27 +285,28 @@ func Test_UserGrantPrepares(t *testing.T) {
),
},
object: &UserGrant{
- ID: "id",
- CreationDate: testNow,
- ChangeDate: testNow,
- Sequence: 20211111,
- Roles: []string{"role-key"},
- GrantID: "grant-id",
- State: domain.UserGrantStateActive,
- UserID: "user-id",
- Username: "username",
- UserType: domain.UserTypeHuman,
- UserResourceOwner: "resource-owner",
- FirstName: "first-name",
- LastName: "last-name",
- Email: "email",
- DisplayName: "display-name",
- AvatarURL: "avatar-key",
- ResourceOwner: "ro",
- OrgName: "",
- OrgPrimaryDomain: "",
- ProjectID: "project-id",
- ProjectName: "project-name",
+ ID: "id",
+ CreationDate: testNow,
+ ChangeDate: testNow,
+ Sequence: 20211111,
+ Roles: []string{"role-key"},
+ GrantID: "grant-id",
+ State: domain.UserGrantStateActive,
+ UserID: "user-id",
+ Username: "username",
+ UserType: domain.UserTypeHuman,
+ UserResourceOwner: "resource-owner",
+ FirstName: "first-name",
+ LastName: "last-name",
+ Email: "email",
+ DisplayName: "display-name",
+ AvatarURL: "avatar-key",
+ PreferredLoginName: "login-name",
+ ResourceOwner: "ro",
+ OrgName: "",
+ OrgPrimaryDomain: "",
+ ProjectID: "project-id",
+ ProjectName: "project-name",
},
},
{
@@ -320,6 +333,7 @@ func Test_UserGrantPrepares(t *testing.T) {
"email",
"display-name",
"avatar-key",
+ "login-name",
"ro",
"org-name",
"primary-domain",
@@ -329,27 +343,86 @@ func Test_UserGrantPrepares(t *testing.T) {
),
},
object: &UserGrant{
- ID: "id",
- CreationDate: testNow,
- ChangeDate: testNow,
- Sequence: 20211111,
- Roles: []string{"role-key"},
- GrantID: "grant-id",
- State: domain.UserGrantStateActive,
- UserID: "user-id",
- Username: "username",
- UserType: domain.UserTypeHuman,
- UserResourceOwner: "resource-owner",
- FirstName: "first-name",
- LastName: "last-name",
- Email: "email",
- DisplayName: "display-name",
- AvatarURL: "avatar-key",
- ResourceOwner: "ro",
- OrgName: "org-name",
- OrgPrimaryDomain: "primary-domain",
- ProjectID: "project-id",
- ProjectName: "",
+ ID: "id",
+ CreationDate: testNow,
+ ChangeDate: testNow,
+ Sequence: 20211111,
+ Roles: []string{"role-key"},
+ GrantID: "grant-id",
+ State: domain.UserGrantStateActive,
+ UserID: "user-id",
+ Username: "username",
+ UserType: domain.UserTypeHuman,
+ UserResourceOwner: "resource-owner",
+ FirstName: "first-name",
+ LastName: "last-name",
+ Email: "email",
+ DisplayName: "display-name",
+ AvatarURL: "avatar-key",
+ PreferredLoginName: "login-name",
+ ResourceOwner: "ro",
+ OrgName: "org-name",
+ OrgPrimaryDomain: "primary-domain",
+ ProjectID: "project-id",
+ ProjectName: "",
+ },
+ },
+ {
+ name: "prepareUserGrantQuery (no loginname) found",
+ prepare: prepareUserGrantQuery,
+ want: want{
+ sqlExpectations: mockQuery(
+ userGrantStmt,
+ userGrantCols,
+ []driver.Value{
+ "id",
+ testNow,
+ testNow,
+ 20211111,
+ "grant-id",
+ pq.StringArray{"role-key"},
+ domain.UserGrantStateActive,
+ "user-id",
+ "username",
+ domain.UserTypeHuman,
+ "resource-owner",
+ "first-name",
+ "last-name",
+ "email",
+ "display-name",
+ "avatar-key",
+ nil,
+ "ro",
+ "org-name",
+ "primary-domain",
+ "project-id",
+ "project-name",
+ },
+ ),
+ },
+ object: &UserGrant{
+ ID: "id",
+ CreationDate: testNow,
+ ChangeDate: testNow,
+ Sequence: 20211111,
+ Roles: []string{"role-key"},
+ GrantID: "grant-id",
+ State: domain.UserGrantStateActive,
+ UserID: "user-id",
+ Username: "username",
+ UserType: domain.UserTypeHuman,
+ UserResourceOwner: "resource-owner",
+ FirstName: "first-name",
+ LastName: "last-name",
+ Email: "email",
+ DisplayName: "display-name",
+ AvatarURL: "avatar-key",
+ PreferredLoginName: "",
+ ResourceOwner: "ro",
+ OrgName: "org-name",
+ OrgPrimaryDomain: "primary-domain",
+ ProjectID: "project-id",
+ ProjectName: "project-name",
},
},
{
@@ -406,6 +479,7 @@ func Test_UserGrantPrepares(t *testing.T) {
"email",
"display-name",
"avatar-key",
+ "login-name",
"ro",
"org-name",
"primary-domain",
@@ -421,27 +495,28 @@ func Test_UserGrantPrepares(t *testing.T) {
},
UserGrants: []*UserGrant{
{
- ID: "id",
- CreationDate: testNow,
- ChangeDate: testNow,
- Sequence: 20211111,
- Roles: []string{"role-key"},
- GrantID: "grant-id",
- State: domain.UserGrantStateActive,
- UserID: "user-id",
- Username: "username",
- UserType: domain.UserTypeHuman,
- UserResourceOwner: "resource-owner",
- FirstName: "first-name",
- LastName: "last-name",
- Email: "email",
- DisplayName: "display-name",
- AvatarURL: "avatar-key",
- ResourceOwner: "ro",
- OrgName: "org-name",
- OrgPrimaryDomain: "primary-domain",
- ProjectID: "project-id",
- ProjectName: "project-name",
+ ID: "id",
+ CreationDate: testNow,
+ ChangeDate: testNow,
+ Sequence: 20211111,
+ Roles: []string{"role-key"},
+ GrantID: "grant-id",
+ State: domain.UserGrantStateActive,
+ UserID: "user-id",
+ Username: "username",
+ UserType: domain.UserTypeHuman,
+ UserResourceOwner: "resource-owner",
+ FirstName: "first-name",
+ LastName: "last-name",
+ Email: "email",
+ DisplayName: "display-name",
+ AvatarURL: "avatar-key",
+ PreferredLoginName: "login-name",
+ ResourceOwner: "ro",
+ OrgName: "org-name",
+ OrgPrimaryDomain: "primary-domain",
+ ProjectID: "project-id",
+ ProjectName: "project-name",
},
},
},
@@ -471,6 +546,7 @@ func Test_UserGrantPrepares(t *testing.T) {
nil,
nil,
nil,
+ "login-name",
"ro",
"org-name",
"primary-domain",
@@ -486,27 +562,28 @@ func Test_UserGrantPrepares(t *testing.T) {
},
UserGrants: []*UserGrant{
{
- ID: "id",
- CreationDate: testNow,
- ChangeDate: testNow,
- Sequence: 20211111,
- Roles: []string{"role-key"},
- GrantID: "grant-id",
- State: domain.UserGrantStateActive,
- UserID: "user-id",
- Username: "username",
- UserType: domain.UserTypeMachine,
- UserResourceOwner: "resource-owner",
- FirstName: "",
- LastName: "",
- Email: "",
- DisplayName: "",
- AvatarURL: "",
- ResourceOwner: "ro",
- OrgName: "org-name",
- OrgPrimaryDomain: "primary-domain",
- ProjectID: "project-id",
- ProjectName: "project-name",
+ ID: "id",
+ CreationDate: testNow,
+ ChangeDate: testNow,
+ Sequence: 20211111,
+ Roles: []string{"role-key"},
+ GrantID: "grant-id",
+ State: domain.UserGrantStateActive,
+ UserID: "user-id",
+ Username: "username",
+ UserType: domain.UserTypeMachine,
+ UserResourceOwner: "resource-owner",
+ FirstName: "",
+ LastName: "",
+ Email: "",
+ DisplayName: "",
+ AvatarURL: "",
+ PreferredLoginName: "login-name",
+ ResourceOwner: "ro",
+ OrgName: "org-name",
+ OrgPrimaryDomain: "primary-domain",
+ ProjectID: "project-id",
+ ProjectName: "project-name",
},
},
},
@@ -536,6 +613,7 @@ func Test_UserGrantPrepares(t *testing.T) {
"email",
"display-name",
"avatar-key",
+ "login-name",
"ro",
nil,
nil,
@@ -551,27 +629,28 @@ func Test_UserGrantPrepares(t *testing.T) {
},
UserGrants: []*UserGrant{
{
- ID: "id",
- CreationDate: testNow,
- ChangeDate: testNow,
- Sequence: 20211111,
- Roles: []string{"role-key"},
- GrantID: "grant-id",
- State: domain.UserGrantStateActive,
- UserID: "user-id",
- Username: "username",
- UserType: domain.UserTypeMachine,
- UserResourceOwner: "resource-owner",
- FirstName: "first-name",
- LastName: "last-name",
- Email: "email",
- DisplayName: "display-name",
- AvatarURL: "avatar-key",
- ResourceOwner: "ro",
- OrgName: "",
- OrgPrimaryDomain: "",
- ProjectID: "project-id",
- ProjectName: "project-name",
+ ID: "id",
+ CreationDate: testNow,
+ ChangeDate: testNow,
+ Sequence: 20211111,
+ Roles: []string{"role-key"},
+ GrantID: "grant-id",
+ State: domain.UserGrantStateActive,
+ UserID: "user-id",
+ Username: "username",
+ UserType: domain.UserTypeMachine,
+ UserResourceOwner: "resource-owner",
+ FirstName: "first-name",
+ LastName: "last-name",
+ Email: "email",
+ DisplayName: "display-name",
+ AvatarURL: "avatar-key",
+ PreferredLoginName: "login-name",
+ ResourceOwner: "ro",
+ OrgName: "",
+ OrgPrimaryDomain: "",
+ ProjectID: "project-id",
+ ProjectName: "project-name",
},
},
},
@@ -601,6 +680,7 @@ func Test_UserGrantPrepares(t *testing.T) {
"email",
"display-name",
"avatar-key",
+ "login-name",
"ro",
"org-name",
"primary-domain",
@@ -616,27 +696,95 @@ func Test_UserGrantPrepares(t *testing.T) {
},
UserGrants: []*UserGrant{
{
- ID: "id",
- CreationDate: testNow,
- ChangeDate: testNow,
- Sequence: 20211111,
- Roles: []string{"role-key"},
- GrantID: "grant-id",
- State: domain.UserGrantStateActive,
- UserID: "user-id",
- Username: "username",
- UserType: domain.UserTypeHuman,
- UserResourceOwner: "resource-owner",
- FirstName: "first-name",
- LastName: "last-name",
- Email: "email",
- DisplayName: "display-name",
- AvatarURL: "avatar-key",
- ResourceOwner: "ro",
- OrgName: "org-name",
- OrgPrimaryDomain: "primary-domain",
- ProjectID: "project-id",
- ProjectName: "",
+ ID: "id",
+ CreationDate: testNow,
+ ChangeDate: testNow,
+ Sequence: 20211111,
+ Roles: []string{"role-key"},
+ GrantID: "grant-id",
+ State: domain.UserGrantStateActive,
+ UserID: "user-id",
+ Username: "username",
+ UserType: domain.UserTypeHuman,
+ UserResourceOwner: "resource-owner",
+ FirstName: "first-name",
+ LastName: "last-name",
+ Email: "email",
+ DisplayName: "display-name",
+ AvatarURL: "avatar-key",
+ PreferredLoginName: "login-name",
+ ResourceOwner: "ro",
+ OrgName: "org-name",
+ OrgPrimaryDomain: "primary-domain",
+ ProjectID: "project-id",
+ ProjectName: "",
+ },
+ },
+ },
+ },
+ {
+ name: "prepareUserGrantsQuery one grant (no loginname)",
+ prepare: prepareUserGrantsQuery,
+ want: want{
+ sqlExpectations: mockQueries(
+ userGrantsStmt,
+ userGrantsCols,
+ [][]driver.Value{
+ {
+ "id",
+ testNow,
+ testNow,
+ 20211111,
+ "grant-id",
+ pq.StringArray{"role-key"},
+ domain.UserGrantStateActive,
+ "user-id",
+ "username",
+ domain.UserTypeHuman,
+ "resource-owner",
+ "first-name",
+ "last-name",
+ "email",
+ "display-name",
+ "avatar-key",
+ nil,
+ "ro",
+ "org-name",
+ "primary-domain",
+ "project-id",
+ "project-name",
+ },
+ },
+ ),
+ },
+ object: &UserGrants{
+ SearchResponse: SearchResponse{
+ Count: 1,
+ },
+ UserGrants: []*UserGrant{
+ {
+ ID: "id",
+ CreationDate: testNow,
+ ChangeDate: testNow,
+ Sequence: 20211111,
+ Roles: []string{"role-key"},
+ GrantID: "grant-id",
+ State: domain.UserGrantStateActive,
+ UserID: "user-id",
+ Username: "username",
+ UserType: domain.UserTypeHuman,
+ UserResourceOwner: "resource-owner",
+ FirstName: "first-name",
+ LastName: "last-name",
+ Email: "email",
+ DisplayName: "display-name",
+ AvatarURL: "avatar-key",
+ PreferredLoginName: "",
+ ResourceOwner: "ro",
+ OrgName: "org-name",
+ OrgPrimaryDomain: "primary-domain",
+ ProjectID: "project-id",
+ ProjectName: "project-name",
},
},
},
@@ -666,6 +814,7 @@ func Test_UserGrantPrepares(t *testing.T) {
"email",
"display-name",
"avatar-key",
+ "login-name",
"ro",
"org-name",
"primary-domain",
@@ -689,6 +838,7 @@ func Test_UserGrantPrepares(t *testing.T) {
"email",
"display-name",
"avatar-key",
+ "login-name",
"ro",
"org-name",
"primary-domain",
@@ -704,50 +854,52 @@ func Test_UserGrantPrepares(t *testing.T) {
},
UserGrants: []*UserGrant{
{
- ID: "id",
- CreationDate: testNow,
- ChangeDate: testNow,
- Sequence: 20211111,
- Roles: []string{"role-key"},
- GrantID: "grant-id",
- State: domain.UserGrantStateActive,
- UserID: "user-id",
- Username: "username",
- UserType: domain.UserTypeHuman,
- UserResourceOwner: "resource-owner",
- FirstName: "first-name",
- LastName: "last-name",
- Email: "email",
- DisplayName: "display-name",
- AvatarURL: "avatar-key",
- ResourceOwner: "ro",
- OrgName: "org-name",
- OrgPrimaryDomain: "primary-domain",
- ProjectID: "project-id",
- ProjectName: "project-name",
+ ID: "id",
+ CreationDate: testNow,
+ ChangeDate: testNow,
+ Sequence: 20211111,
+ Roles: []string{"role-key"},
+ GrantID: "grant-id",
+ State: domain.UserGrantStateActive,
+ UserID: "user-id",
+ Username: "username",
+ UserType: domain.UserTypeHuman,
+ UserResourceOwner: "resource-owner",
+ FirstName: "first-name",
+ LastName: "last-name",
+ Email: "email",
+ DisplayName: "display-name",
+ AvatarURL: "avatar-key",
+ PreferredLoginName: "login-name",
+ ResourceOwner: "ro",
+ OrgName: "org-name",
+ OrgPrimaryDomain: "primary-domain",
+ ProjectID: "project-id",
+ ProjectName: "project-name",
},
{
- ID: "id",
- CreationDate: testNow,
- ChangeDate: testNow,
- Sequence: 20211111,
- Roles: []string{"role-key"},
- GrantID: "grant-id",
- State: domain.UserGrantStateActive,
- UserID: "user-id",
- Username: "username",
- UserType: domain.UserTypeHuman,
- UserResourceOwner: "resource-owner",
- FirstName: "first-name",
- LastName: "last-name",
- Email: "email",
- DisplayName: "display-name",
- AvatarURL: "avatar-key",
- ResourceOwner: "ro",
- OrgName: "org-name",
- OrgPrimaryDomain: "primary-domain",
- ProjectID: "project-id",
- ProjectName: "project-name",
+ ID: "id",
+ CreationDate: testNow,
+ ChangeDate: testNow,
+ Sequence: 20211111,
+ Roles: []string{"role-key"},
+ GrantID: "grant-id",
+ State: domain.UserGrantStateActive,
+ UserID: "user-id",
+ Username: "username",
+ UserType: domain.UserTypeHuman,
+ UserResourceOwner: "resource-owner",
+ FirstName: "first-name",
+ LastName: "last-name",
+ Email: "email",
+ DisplayName: "display-name",
+ AvatarURL: "avatar-key",
+ PreferredLoginName: "login-name",
+ ResourceOwner: "ro",
+ OrgName: "org-name",
+ OrgPrimaryDomain: "primary-domain",
+ ProjectID: "project-id",
+ ProjectName: "project-name",
},
},
},
diff --git a/internal/query/user_membership.go b/internal/query/user_membership.go
index 8d70156675..59fbfbe69b 100644
--- a/internal/query/user_membership.go
+++ b/internal/query/user_membership.go
@@ -70,6 +70,14 @@ func NewMembershipOrgIDQuery(value string) (SearchQuery, error) {
return NewTextQuery(membershipOrgID, value, TextEquals)
}
+func NewMembershipResourceOwnersSearchQuery(ids ...string) (SearchQuery, error) {
+ list := make([]interface{}, len(ids))
+ for i, value := range ids {
+ list[i] = value
+ }
+ return NewListQuery(membershipResourceOwner, list, ListIn)
+}
+
func NewMembershipProjectIDQuery(value string) (SearchQuery, error) {
return NewTextQuery(membershipProjectID, value, TextEquals)
}
diff --git a/internal/query/zitadel_permission.go b/internal/query/zitadel_permission.go
index 0b7672a18f..51261f749b 100644
--- a/internal/query/zitadel_permission.go
+++ b/internal/query/zitadel_permission.go
@@ -6,13 +6,17 @@ import (
"github.com/caos/zitadel/internal/domain"
)
-func (q *Queries) MyZitadelPermissions(ctx context.Context, userID string) (*domain.Permissions, error) {
+func (q *Queries) MyZitadelPermissions(ctx context.Context, orgID, userID string) (*domain.Permissions, error) {
userIDQuery, err := NewMembershipUserIDQuery(userID)
if err != nil {
return nil, err
}
+ orgIDsQuery, err := NewMembershipResourceOwnersSearchQuery(orgID, domain.IAMID)
+ if err != nil {
+ return nil, err
+ }
memberships, err := q.Memberships(ctx, &MembershipSearchQuery{
- Queries: []SearchQuery{userIDQuery},
+ Queries: []SearchQuery{userIDQuery, orgIDsQuery},
})
if err != nil {
return nil, err
diff --git a/internal/repository/iam/policy_privacy.go b/internal/repository/iam/policy_privacy.go
index 4c5fdb3882..8606825149 100644
--- a/internal/repository/iam/policy_privacy.go
+++ b/internal/repository/iam/policy_privacy.go
@@ -22,7 +22,8 @@ func NewPrivacyPolicyAddedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
tosLink,
- privacyLink string,
+ privacyLink,
+ helpLink string,
) *PrivacyPolicyAddedEvent {
return &PrivacyPolicyAddedEvent{
PrivacyPolicyAddedEvent: *policy.NewPrivacyPolicyAddedEvent(
@@ -31,7 +32,8 @@ func NewPrivacyPolicyAddedEvent(
aggregate,
PrivacyPolicyAddedEventType),
tosLink,
- privacyLink),
+ privacyLink,
+ helpLink),
}
}
diff --git a/internal/repository/org/policy_privacy.go b/internal/repository/org/policy_privacy.go
index dfe1217a80..e28f9d28ea 100644
--- a/internal/repository/org/policy_privacy.go
+++ b/internal/repository/org/policy_privacy.go
@@ -23,7 +23,8 @@ func NewPrivacyPolicyAddedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
tosLink,
- privacyLink string,
+ privacyLink,
+ helpLink string,
) *PrivacyPolicyAddedEvent {
return &PrivacyPolicyAddedEvent{
PrivacyPolicyAddedEvent: *policy.NewPrivacyPolicyAddedEvent(
@@ -32,7 +33,8 @@ func NewPrivacyPolicyAddedEvent(
aggregate,
PrivacyPolicyAddedEventType),
tosLink,
- privacyLink),
+ privacyLink,
+ helpLink),
}
}
diff --git a/internal/repository/policy/policy_privacy.go b/internal/repository/policy/policy_privacy.go
index b76150c338..36b3b2501c 100644
--- a/internal/repository/policy/policy_privacy.go
+++ b/internal/repository/policy/policy_privacy.go
@@ -20,6 +20,7 @@ type PrivacyPolicyAddedEvent struct {
TOSLink string `json:"tosLink,omitempty"`
PrivacyLink string `json:"privacyLink,omitempty"`
+ HelpLink string `json:"helpLink,omitempty"`
}
func (e *PrivacyPolicyAddedEvent) Data() interface{} {
@@ -33,12 +34,14 @@ func (e *PrivacyPolicyAddedEvent) UniqueConstraints() []*eventstore.EventUniqueC
func NewPrivacyPolicyAddedEvent(
base *eventstore.BaseEvent,
tosLink,
- privacyLink string,
+ privacyLink,
+ helpLink string,
) *PrivacyPolicyAddedEvent {
return &PrivacyPolicyAddedEvent{
BaseEvent: *base,
TOSLink: tosLink,
PrivacyLink: privacyLink,
+ HelpLink: helpLink,
}
}
@@ -59,6 +62,7 @@ type PrivacyPolicyChangedEvent struct {
TOSLink *string `json:"tosLink,omitempty"`
PrivacyLink *string `json:"privacyLink,omitempty"`
+ HelpLink *string `json:"helpLink,omitempty"`
}
func (e *PrivacyPolicyChangedEvent) Data() interface{} {
@@ -99,6 +103,12 @@ func ChangePrivacyLink(privacyLink string) func(*PrivacyPolicyChangedEvent) {
}
}
+func ChangeHelpLink(helpLink string) func(*PrivacyPolicyChangedEvent) {
+ return func(e *PrivacyPolicyChangedEvent) {
+ e.HelpLink = &helpLink
+ }
+}
+
func PrivacyPolicyChangedEventMapper(event *repository.Event) (eventstore.Event, error) {
e := &PrivacyPolicyChangedEvent{
BaseEvent: *eventstore.BaseEventFromRepo(event),
diff --git a/internal/static/i18n/de.yaml b/internal/static/i18n/de.yaml
index 5eda4ff579..13db35a19e 100644
--- a/internal/static/i18n/de.yaml
+++ b/internal/static/i18n/de.yaml
@@ -193,22 +193,22 @@ Errors:
NotChanged: Default Message Text wurde nicht verändert
AlreadyExists: Default Message Text existiert bereits
Invalid: Default Message Text ist ungültig
- PasswordComplexity:
+ PasswordComplexityPolicy:
NotFound: Password Komplexitäts Policy konnte nicht gefunden werden
Empty: Passwort Komplexitäts Policy ist leer
NotExisting: Passwort Komplexitäts Policy existiert nicht
AlreadyExists: Passwort Komplexitäts Policy existiert bereits
- PasswordLockout:
+ PasswordLockoutPolicy:
NotFound: Password Lockout Policy konnte nicht gefunden werden
Empty: Passwort Lockout Policy ist leer
NotExisting: Passwort Lockout Policy existiert nicht
AlreadyExists: Passwort Lockout Policy existiert bereits
- PasswordAge:
+ PasswordAgePolicy:
NotFound: Password Age Policy konnte nicht gefunden werden
Empty: Passwort Age Policy ist leer
NotExisting: Passwort Age Policy existiert nicht
AlreadyExists: Passwort Age Policy existiert bereits
- OrgIAM:
+ OrgIAMPolicy:
Empty: Org IAM Policy ist leer
NotExisting: Org IAM Policy existiert nicht
AlreadyExists: Org IAM Policy existiert bereits
@@ -589,6 +589,10 @@ EventTypes:
cascade:
removed: Berechtigung entfernt
changed: Berechtigung geändert
+ metadata:
+ set: Benutzer Metadaten gesetzt
+ removed: Benutzer Metadaten gelöscht
+ removed.all: Alle Benutzer Metadaten gelöscht
org:
added: Organisation hinzugefügt
changed: Organisation geändert
diff --git a/internal/static/i18n/en.yaml b/internal/static/i18n/en.yaml
index 0c4961f656..72ae6a8cf5 100644
--- a/internal/static/i18n/en.yaml
+++ b/internal/static/i18n/en.yaml
@@ -193,22 +193,22 @@ Errors:
NotChanged: Default Message Text has not been changed
AlreadyExists: Default Message Text already exists
Invalid: Default Message Text is invalid
- PasswordComplexity:
+ PasswordComplexityPolicy:
NotFound: Password Complexity Policy not found
Empty: Password Complexity Policy is empty
NotExisting: Password Complexity Policy doesn't exist
AlreadyExists: Password Complexity Policy already exists
- PasswordLockout:
+ PasswordLockoutPolicy:
NotFound: Password Lockout Policy not found
Empty: Password Lockout Policy is empty
NotExisting: Password Lockout Policy doesn't exist
AlreadyExists: Password Lockout Policy already exists
- PasswordAge:
+ PasswordAgePolicy:
NotFound: Password Age Policy not found
Empty: Password Age Policy is empty
NotExisting: Password Age Policy doesn't exist
AlreadyExists: Password Age Policy already exists
- OrgIAM:
+ OrgIAMPolicy:
Empty: Org IAM Policy is empty
NotExisting: Org IAM Policy doesn't exist
AlreadyExists: Org IAM Policy already exists
@@ -589,6 +589,10 @@ EventTypes:
cascade:
removed: Authorization removed
changed: Authorization changed
+ metadata:
+ set: User metadata set
+ removed: User metadata removed
+ removed.all: All user metadata removed
org:
added: Organization added
changed: Organization changed
diff --git a/internal/static/i18n/it.yaml b/internal/static/i18n/it.yaml
index 9963483a96..ab1684649d 100644
--- a/internal/static/i18n/it.yaml
+++ b/internal/static/i18n/it.yaml
@@ -191,22 +191,22 @@ Errors:
NotChanged: Il testo predefinito non è stato cambiato
AlreadyExists: Il testo predefinito già eistente
Invalid: Il testo predefinito non è valido
- PasswordComplexity:
+ PasswordComplexityPolicy:
NotFound: Impostazioni di complessità della password non trovati
Empty: Mancano le impostazioni di complessità della password
NotExisting: Impostazioni di complessità della password non esistenti
AlreadyExists: Impostazioni di complessità della password sono già esistenti
- PasswordLockout:
+ PasswordLockoutPolicy:
NotFound: Impostazioni di blocco della password non trovati
Empty: Mancano le impostazioni di blocco della password
NotExisting: Le impostazioni di blocco della password non esistenti
AlreadyExists: Le impostazioni di blocco della password sono già esistenti
- PasswordAge:
+ PasswordAgePolicy:
NotFound: Impostazioni di validità della password
Empty: Impostazioni di validità della password mancanti
NotExisting: Impostazioni di validità della password non esistenti
AlreadyExists: Impostazioni di validità della password sono già esistenti
- OrgIAM:
+ OrgIAMPolicy:
Empty: Mancano le impostazioni Org IAM
NotExisting: Impostazioni Org IAM non esistenti
AlreadyExists: Impostazioni Org IAM già esistenti
@@ -587,6 +587,10 @@ EventTypes:
cascade:
removed: Autorizzazione rimossa
changed: Autorizzazione cambiata
+ metadata:
+ set: Set di metadati utente
+ removed: Metadati utente rimossi
+ removed.all: Tutti i metadati utente rimossi
org:
added: Organizzazione aggiunta
changed: Organizzazione cambiata
diff --git a/internal/user/repository/view/model/notify_user.go b/internal/user/repository/view/model/notify_user.go
index 1171c3a943..79a23bda1a 100644
--- a/internal/user/repository/view/model/notify_user.go
+++ b/internal/user/repository/view/model/notify_user.go
@@ -4,8 +4,6 @@ import (
"encoding/json"
"time"
- "github.com/caos/zitadel/internal/query"
-
"github.com/caos/logging"
"github.com/lib/pq"
@@ -100,14 +98,14 @@ func (u *NotifyUser) GenerateLoginName(domain string, appendDomain bool) string
return u.UserName + "@" + domain
}
-func (u *NotifyUser) SetLoginNames(policy *query.OrgIAMPolicy, domains []*org_model.OrgDomain) {
+func (u *NotifyUser) SetLoginNames(userLoginMustBeDomain bool, domains []*org_model.OrgDomain) {
loginNames := make([]string, 0)
for _, d := range domains {
if d.Verified {
loginNames = append(loginNames, u.GenerateLoginName(d.Domain, true))
}
}
- if !policy.UserLoginMustBeDomain {
+ if !userLoginMustBeDomain {
loginNames = append(loginNames, u.UserName)
}
u.LoginNames = loginNames
diff --git a/internal/user/repository/view/model/user.go b/internal/user/repository/view/model/user.go
index 18b615fc05..672e3f5edd 100644
--- a/internal/user/repository/view/model/user.go
+++ b/internal/user/repository/view/model/user.go
@@ -8,8 +8,6 @@ import (
"github.com/caos/logging"
"github.com/lib/pq"
- "github.com/caos/zitadel/internal/query"
-
req_model "github.com/caos/zitadel/internal/auth_request/model"
"github.com/caos/zitadel/internal/domain"
caos_errs "github.com/caos/zitadel/internal/errors"
@@ -230,14 +228,14 @@ func (u *UserView) GenerateLoginName(domain string, appendDomain bool) string {
return u.UserName + "@" + domain
}
-func (u *UserView) SetLoginNames(policy *query.OrgIAMPolicy, domains []*org_model.OrgDomain) {
+func (u *UserView) SetLoginNames(userLoginMustBeDomain bool, domains []*org_model.OrgDomain) {
loginNames := make([]string, 0)
for _, d := range domains {
if d.Verified {
loginNames = append(loginNames, u.GenerateLoginName(d.Domain, true))
}
}
- if !policy.UserLoginMustBeDomain {
+ if !userLoginMustBeDomain {
loginNames = append(loginNames, u.UserName)
}
u.LoginNames = loginNames
diff --git a/internal/webauthn/webauthn.go b/internal/webauthn/webauthn.go
index 0e627c74fb..be70d8a719 100644
--- a/internal/webauthn/webauthn.go
+++ b/internal/webauthn/webauthn.go
@@ -4,6 +4,7 @@ import (
"bytes"
"encoding/json"
+ "github.com/caos/logging"
"github.com/duo-labs/webauthn/protocol"
"github.com/duo-labs/webauthn/webauthn"
@@ -107,6 +108,8 @@ func (w *WebAuthN) FinishRegistration(user *domain.Human, webAuthN *domain.WebAu
}
credentialData, err := protocol.ParseCredentialCreationResponseBody(bytes.NewReader(credData))
if err != nil {
+ e := *err.(*protocol.Error)
+ logging.WithFields("error", e).Error("webauthn credential could not be parsed")
return nil, caos_errs.ThrowInternal(err, "WEBAU-sEr8c", "Errors.User.WebAuthN.ErrorOnParseCredential")
}
sessionData := WebAuthNToSessionData(webAuthN)
diff --git a/proto/zitadel/admin.proto b/proto/zitadel/admin.proto
index 2090101353..a390816a4f 100644
--- a/proto/zitadel/admin.proto
+++ b/proto/zitadel/admin.proto
@@ -1771,6 +1771,7 @@ service AdminService {
//Updates the default privacy policy of ZITADEL
// it impacts all organisations without a customised policy
+ // Variable {{.Lang}} can be set to have different links based on the language
rpc UpdatePrivacyPolicy(UpdatePrivacyPolicyRequest) returns (UpdatePrivacyPolicyResponse) {
option (google.api.http) = {
put: "/policies/privacy";
@@ -3765,6 +3766,7 @@ message GetPrivacyPolicyResponse {
message UpdatePrivacyPolicyRequest {
string tos_link = 1;
string privacy_link = 2;
+ string help_link = 3;
}
message UpdatePrivacyPolicyResponse {
diff --git a/proto/zitadel/management.proto b/proto/zitadel/management.proto
index 3be4a3ed61..92eee5d352 100644
--- a/proto/zitadel/management.proto
+++ b/proto/zitadel/management.proto
@@ -2133,6 +2133,7 @@ service ManagementService {
// Add a custom privacy policy for the organisation
// With this policy privacy relevant things can be configured (e.g. tos link)
+ // Variable {{.Lang}} can be set to have different links based on the language
rpc AddCustomPrivacyPolicy(AddCustomPrivacyPolicyRequest) returns (AddCustomPrivacyPolicyResponse) {
option (google.api.http) = {
post: "/policies/privacy"
@@ -2147,6 +2148,7 @@ service ManagementService {
// Update the privacy complexity policy for the organisation
// With this policy privacy relevant things can be configured (e.g. tos link)
+ // Variable {{.Lang}} can be set to have different links based on the language
rpc UpdateCustomPrivacyPolicy(UpdateCustomPrivacyPolicyRequest) returns (UpdateCustomPrivacyPolicyResponse) {
option (google.api.http) = {
put: "/policies/privacy"
@@ -4646,6 +4648,7 @@ message GetDefaultPrivacyPolicyResponse {
message AddCustomPrivacyPolicyRequest {
string tos_link = 1;
string privacy_link = 2;
+ string help_link = 3;
}
message AddCustomPrivacyPolicyResponse {
@@ -4655,6 +4658,7 @@ message AddCustomPrivacyPolicyResponse {
message UpdateCustomPrivacyPolicyRequest {
string tos_link = 1;
string privacy_link = 2;
+ string help_link = 3;
}
message UpdateCustomPrivacyPolicyResponse {
diff --git a/proto/zitadel/policy.proto b/proto/zitadel/policy.proto
index b4f9f75ff5..cbe5090b0c 100644
--- a/proto/zitadel/policy.proto
+++ b/proto/zitadel/policy.proto
@@ -229,4 +229,5 @@ message PrivacyPolicy {
string tos_link = 2;
string privacy_link = 3;
bool is_default = 4;
-}
\ No newline at end of file
+ string help_link = 5;
+}
diff --git a/proto/zitadel/text.proto b/proto/zitadel/text.proto
index a4d9c15c71..03c29f658a 100644
--- a/proto/zitadel/text.proto
+++ b/proto/zitadel/text.proto
@@ -382,12 +382,11 @@ message LogoutDoneScreenText {
}
message FooterText {
- reserved 2, 4;
- reserved "tos_link", "privacy_policy_link";
+ reserved 2, 4, 6;
+ reserved "tos_link", "privacy_policy_link", "help_link";
string tos = 1 [(validate.rules).string = {max_len: 200}];
string privacy_policy = 3 [(validate.rules).string = {max_len: 200}];
string help = 5 [(validate.rules).string = {max_len: 200}];
- string help_link = 6 [(validate.rules).string = {max_len: 500}];
}
message PasswordlessPromptScreenText {
diff --git a/proto/zitadel/user.proto b/proto/zitadel/user.proto
index faa811a1f9..82ebaed89e 100644
--- a/proto/zitadel/user.proto
+++ b/proto/zitadel/user.proto
@@ -681,6 +681,11 @@ message UserGrant {
example: "\"https://api.zitadel.ch/assets/v1/avatar-32432jkh4kj32\"";
}
];
+ string preferred_login_name = 18 [
+ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
+ example: "\"gigi@caos.ch\"";
+ }
+ ];
}
enum UserGrantState {