+
-
-
+
+
-
+
+
+
+
+
+ {{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 8a18e531c..5814f3129 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 91220f09a..5cdaf2be5 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 201208f02..ff6f9b241 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 c751dc34a..69e2a3830 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 4aad40dfc..646f68abd 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 74738375a..4f73d67c5 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 5c28614c3..37f9be827 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 bd5484afe..100929d24 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 cd482b7ff..0820f88c9 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 dabf6946f..cfd74d04a 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 2f47a3913..6143aab91 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 40b4e7d83..31ce1b310 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 13c1281d4..393b7c422 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 6ca3298c2..374b5f6fd 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 2c2c9fb4c..b21ea5451 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 ea9ea464b..41d771e01 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 067d2092f..9c5bc7230 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 f78c5ac12..897181562 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 6c98c09dd..966412f0f 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 587da8c8e..dfd592c64 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 614566898..3913aa137 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 a3675345d..5f4a1040a 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 bdb074398..6ccf8db64 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 79460f19a..5bde39d1e 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 166bc8474..fd12f6ee7 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 55b247144..321d66b08 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 4e8901cf3..42c76d8e6 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 281a09288..c4758fb66 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 9e9d01b5c..8fb2f6678 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 b6a478422..ec6b7254c 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 98965443f..e4f7578b5 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 f3326a456..085154b50 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 846377720..9fa3203d5 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 9ea20b55d..bbf53dd31 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 f5b806ff1..9d50ee4b6 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 e9bab1285..ddc9e81bc 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 f670c4669..b9b62e83f 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 290662a3b..6f428e65d 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 ba5cc80d6..83b5aafb8 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 8c0a2eaf5..79ee3e263 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 d0bc837f4..40d28862b 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 917fdfde5..0128d5fd4 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 e327c0467..8001e29cd 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 9c45e2cc3..3dea4c36a 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 171b48f75..d5ff331db 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 ba762371c..36a8b1ba8 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 07e489f44..9dbd6722a 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 f6df852a7..cb8ef5236 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 e93fe3183..370f77a59 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 5eab8c9b9..5e0ad5ccc 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 386eaf22b..df7c2a9d7 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 9eb58f389..eec1ff8c2 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 93fa3b3b3..81bb6bbef 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 4cef14f6f..ad4727c3d 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 676ea8a08..a938e5149 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 98fe95d19..b8544706d 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 389ad4d46..c554bbbde 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 154dffae2..4673bc6db 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 9e7e0102a..58069c290 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 eeed193e1..2e4dd699c 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 6124875d7..8d23f9567 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 2a36ac2cc..0f722fe39 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 9748f6a3d..e74c03cb2 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 5dbe1f9ab..dd9d0f8bd 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 f84a5b00a..da4b30e4c 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 8d7015667..59fbfbe69 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 0b7672a18..51261f749 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 4c5fdb388..860682514 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 dfe1217a8..e28f9d28e 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 b76150c33..36b3b2501 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 5eda4ff57..13db35a19 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 0c4961f65..72ae6a8cf 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 9963483a9..ab1684649 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 1171c3a94..79a23bda1 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 18b615fc0..672e3f5ed 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 0e627c74f..be70d8a71 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 209010135..a390816a4 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 3be4a3ed6..92eee5d35 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 b4f9f75ff..cbe5090b0 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 a4d9c15c7..03c29f658 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 faa811a1f..82ebaed89 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 {