feat(cnsl): docs link can be customized and custom button is available (#7840)

* feat: customize doc link and additional custom link

* feat: add e2e tests

* fix: update docs

* fix: add @peintnermax changes about cache

* fix: golangci-lint complains preparation.PrepareCommands

---------

Co-authored-by: Max Peintner <max@caos.ch>
This commit is contained in:
Miguel Cabrerizo 2024-05-13 16:01:50 +02:00 committed by GitHub
parent 6942324741
commit 15d5338b91
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
61 changed files with 1000 additions and 286 deletions

View File

@ -14,16 +14,16 @@ Tracing:
# for type 'otel' is used for standard [open telemetry](https://opentelemetry.io)
# Fraction: 1.0
# Endpoint: 'otel.collector.endpoint'
#
#
# type 'log' or '' disables tracing
#
#
# for type 'google'
# ProjectID: ''
# Fraction: 1.0
Type: none # ZITADEL_TRACING_TYPE
Fraction: 1.0 # ZITADEL_TRACING_FRACTION
# The endpoint of the otel collector endpoint
Endpoint: '' #ZITADEL_TRACING_ENDPOINT
Endpoint: "" #ZITADEL_TRACING_ENDPOINT
Telemetry:
# As long as Enabled is true, ZITADEL tries to send usage data to the configured Telemetry.Endpoints.
@ -200,7 +200,7 @@ AssetStorage:
# The Projections section defines the behavior for the scheduled and synchronous events projections.
Projections:
# The maximum duration a transaction remains open
# The maximum duration a transaction remains open
# before it spots left folding additional events
# and updates the table.
TransactionDuration: 500ms # ZITADEL_PROJECTIONS_TRANSACTIONDURATION
@ -264,7 +264,7 @@ Auth:
# See Projections.BulkLimit
SearchLimit: 1000 # ZITADEL_AUTH_SEARCHLIMIT
Spooler:
# See Projections.TransationDuration
# See Projections.TransationDuration
TransactionDuration: 10s #ZITADEL_AUTH_SPOOLER_TRANSACTIONDURATION
# See Projections.BulkLimit
BulkLimit: 100 #ZITADEL_AUTH_SPOOLER_BULKLIMIT
@ -704,6 +704,9 @@ DefaultInstance:
PrivacyLink: https://zitadel.com/docs/legal/privacy-policy # ZITADEL_DEFAULTINSTANCE_PRIVACYPOLICY_PRIVACYLINK
HelpLink: "" # ZITADEL_DEFAULTINSTANCE_PRIVACYPOLICY_HELPLINK
SupportEmail: "" # ZITADEL_DEFAULTINSTANCE_PRIVACYPOLICY_SUPPORTEMAIL
DocsLink: https://zitadel.com/docs # ZITADEL_DEFAULTINSTANCE_PRIVACYPOLICY_DOCSLINK
CustomLink: "" # ZITADEL_DEFAULTINSTANCE_PRIVACYPOLICY_CUSTOMLINK
CustomLinkText: "" # ZITADEL_DEFAULTINSTANCE_PRIVACYPOLICY_CUSTOMLINKTEXT
NotificationPolicy:
PasswordChange: true # ZITADEL_DEFAULTINSTANCE_NOTIFICATIONPOLICY_PASSWORDCHANGE
LabelPolicy:
@ -1432,4 +1435,4 @@ InitProjections:
Enabled: true # ZITADEL_INITPROJECTIONS_ENABLED
RetryFailedAfter: 100ms # ZITADEL_INITPROJECTIONS_RETRYFAILEDAFTER
MaxFailureCount: 2 # ZITADEL_INITPROJECTIONS_MAXFAILURECOUNT
BulkLimit: 1000 # ZITADEL_INITPROJECTIONS_BULKLIMIT
BulkLimit: 1000 # ZITADEL_INITPROJECTIONS_BULKLIMIT

View File

@ -1,11 +1,11 @@
<div class="footer-wrapper">
<div class="footer-row">
<div class="footer-links">
<a target="_blank" *ngIf="policy?.tosLink" rel="noreferrer" [href]="policy?.tosLink" external>
<div class="footer-links" *ngIf="authService.privacypolicy | async as pP">
<a target="_blank" *ngIf="pP?.tosLink" rel="noreferrer" [href]="pP?.tosLink" external>
<span>{{ 'FOOTER.LINKS.TOS' | translate }}</span>
<i class="las la-external-link-alt"></i>
</a>
<a target="_blank" *ngIf="policy?.privacyLink" rel="noreferrer" [href]="policy?.privacyLink" external>
<a target="_blank" *ngIf="pP?.privacyLink" rel="noreferrer" [href]="pP?.privacyLink" external>
<span>{{ 'FOOTER.LINKS.PP' | translate }}</span>
<i class="las la-external-link-alt"></i>
</a>

View File

@ -8,16 +8,7 @@ import { faXTwitter } from '@fortawesome/free-brands-svg-icons';
templateUrl: './footer.component.html',
styleUrls: ['./footer.component.scss'],
})
export class FooterComponent implements OnInit {
public policy?: PrivacyPolicy.AsObject;
export class FooterComponent {
public faXTwitter = faXTwitter;
constructor(public authService: GrpcAuthService) {}
ngOnInit(): void {
this.authService.getMyPrivacyPolicy().then((policyResp) => {
if (policyResp.policy) {
this.policy = policyResp.policy;
}
});
}
}

View File

@ -168,7 +168,11 @@
<span class="fill-space"></span>
<a class="doc-link" href="https://zitadel.com/docs" mat-stroked-button target="_blank">
<a class="custom-link" *ngIf="customLink && customLinkText" href="{{ customLink }}" mat-stroked-button target="_blank">
{{ customLinkText }}
</a>
<a class="doc-link" *ngIf="docsLink" href="{{ docsLink }}" mat-stroked-button target="_blank">
{{ 'MENU.DOCUMENTATION' | translate }}
</a>

View File

@ -224,7 +224,8 @@
flex: 1;
}
.doc-link {
.doc-link,
.custom-link {
margin-right: 1rem;
@media only screen and (max-width: 800px) {

View File

@ -1,5 +1,5 @@
import { ConnectedPosition, ConnectionPositionPair } from '@angular/cdk/overlay';
import { Component, ElementRef, EventEmitter, Input, OnDestroy, Output, ViewChild } from '@angular/core';
import { Component, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Output, ViewChild } from '@angular/core';
import { Router } from '@angular/router';
import { BehaviorSubject, Observable, of, Subject } from 'rxjs';
import { Org } from 'src/app/proto/generated/zitadel/org_pb';
@ -8,8 +8,8 @@ import { AuthenticationService } from 'src/app/services/authentication.service';
import { BreadcrumbService, BreadcrumbType } from 'src/app/services/breadcrumb.service';
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
import { ManagementService } from 'src/app/services/mgmt.service';
import { ActionKeysType } from '../action-keys/action-keys.component';
import { GetPrivacyPolicyResponse } from 'src/app/proto/generated/zitadel/management_pb';
@Component({
selector: 'cnsl-header',
@ -31,6 +31,9 @@ export class HeaderComponent implements OnDestroy {
private destroy$: Subject<void> = new Subject();
public BreadcrumbType: any = BreadcrumbType;
public ActionKeysType: any = ActionKeysType;
public docsLink = 'https://zitadel.com/docs';
public customLink = '';
public customLinkText = '';
public positions: ConnectedPosition[] = [
new ConnectionPositionPair({ originX: 'start', originY: 'bottom' }, { overlayX: 'start', overlayY: 'top' }, 0, 10),
@ -47,7 +50,25 @@ export class HeaderComponent implements OnDestroy {
public mgmtService: ManagementService,
public breadcrumbService: BreadcrumbService,
public router: Router,
) {}
) {
this.loadData();
}
public async loadData(): Promise<any> {
const getData = (): Promise<GetPrivacyPolicyResponse.AsObject> => {
return this.mgmtService.getPrivacyPolicy();
};
getData()
.then((resp) => {
if (resp.policy) {
this.docsLink = resp.policy.docsLink;
this.customLink = resp.policy.customLink;
this.customLinkText = resp.policy.customLinkText;
}
})
.catch(() => {});
}
public ngOnDestroy() {
this.destroy$.next();

View File

@ -9,6 +9,7 @@
color="warn"
(click)="resetDefault()"
mat-stroked-button
data-e2e="reset-button"
>
{{ 'POLICY.RESET' | translate }}
</button>
@ -40,7 +41,23 @@
<cnsl-form-field class="privacy-policy-formfield">
<cnsl-label>{{ 'POLICY.PRIVACY_POLICY.SUPPORTEMAIL' | translate }}</cnsl-label>
<input cnslInput name="supportEmail" formControlName="supportEmail" />
<template [ngTemplateOutlet]="templateRef" [ngTemplateOutletContext]="{ key: 'supportEmail' }"></template>
</cnsl-form-field>
<cnsl-form-field class="privacy-policy-formfield">
<cnsl-label>{{ 'POLICY.PRIVACY_POLICY.CUSTOMLINK' | translate }}</cnsl-label>
<input cnslInput name="customLink" formControlName="customLink" />
<template [ngTemplateOutlet]="templateRef" [ngTemplateOutletContext]="{ key: 'customLink' }"></template>
</cnsl-form-field>
<cnsl-form-field class="privacy-policy-formfield">
<cnsl-label>{{ 'POLICY.PRIVACY_POLICY.CUSTOMLINKTEXT' | translate }}</cnsl-label>
<input cnslInput name="customLinkText" formControlName="customLinkText" />
</cnsl-form-field>
<cnsl-form-field class="privacy-policy-formfield">
<cnsl-label>{{ 'POLICY.PRIVACY_POLICY.DOCSLINK' | translate }}</cnsl-label>
<input cnslInput name="docsLink" formControlName="docsLink" />
<template [ngTemplateOutlet]="templateRef" [ngTemplateOutletContext]="{ key: 'docsLink' }"></template>
</cnsl-form-field>
</form>
</div>
@ -53,6 +70,7 @@
color="primary"
type="submit"
mat-raised-button
data-e2e="save-button"
>
{{ 'ACTIONS.SAVE' | translate }}
</button>

View File

@ -61,6 +61,9 @@ export class PrivacyPolicyComponent implements OnInit, OnDestroy {
privacyLink: ['', []],
helpLink: ['', []],
supportEmail: ['', []],
docsLink: ['', []],
customLink: ['', []],
customLinkText: ['', []],
});
this.canWrite$.pipe(take(1)).subscribe((canWrite) => {
@ -107,6 +110,9 @@ export class PrivacyPolicyComponent implements OnInit, OnDestroy {
privacyLink: '',
helpLink: '',
supportEmail: '',
docsLink: '',
customLink: '',
customLinkText: '',
});
}
})
@ -117,6 +123,9 @@ export class PrivacyPolicyComponent implements OnInit, OnDestroy {
privacyLink: '',
helpLink: '',
supportEmail: '',
docsLink: '',
customLink: '',
customLinkText: '',
});
});
}
@ -129,11 +138,16 @@ export class PrivacyPolicyComponent implements OnInit, OnDestroy {
req.setTosLink(this.form.get('tosLink')?.value);
req.setHelpLink(this.form.get('helpLink')?.value);
req.setSupportEmail(this.form.get('supportEmail')?.value);
req.setDocsLink(this.form.get('docsLink')?.value);
req.setCustomLink(this.form.get('customLink')?.value);
req.setCustomLinkText(this.form.get('customLinkText')?.value);
(this.service as ManagementService)
.addCustomPrivacyPolicy(req)
.then(() => {
this.toast.showInfo('POLICY.PRIVACY_POLICY.SAVED', true);
this.loadData();
// Reload console as links may have changed
this.reloadConsole();
})
.catch((error) => this.toast.showError(error));
} else {
@ -142,12 +156,17 @@ export class PrivacyPolicyComponent implements OnInit, OnDestroy {
req.setTosLink(this.form.get('tosLink')?.value);
req.setHelpLink(this.form.get('helpLink')?.value);
req.setSupportEmail(this.form.get('supportEmail')?.value);
req.setDocsLink(this.form.get('docsLink')?.value);
req.setCustomLink(this.form.get('customLink')?.value);
req.setCustomLinkText(this.form.get('customLinkText')?.value);
(this.service as ManagementService)
.updateCustomPrivacyPolicy(req)
.then(() => {
this.toast.showInfo('POLICY.PRIVACY_POLICY.SAVED', true);
this.loadData();
// Reload console as links may have changed
this.reloadConsole();
})
.catch((error) => this.toast.showError(error));
}
@ -157,12 +176,17 @@ export class PrivacyPolicyComponent implements OnInit, OnDestroy {
req.setTosLink(this.form.get('tosLink')?.value);
req.setHelpLink(this.form.get('helpLink')?.value);
req.setSupportEmail(this.form.get('supportEmail')?.value);
req.setDocsLink(this.form.get('docsLink')?.value);
req.setCustomLink(this.form.get('customLink')?.value);
req.setCustomLinkText(this.form.get('customLinkText')?.value);
(this.service as AdminService)
.updatePrivacyPolicy(req)
.then(() => {
this.toast.showInfo('POLICY.PRIVACY_POLICY.SAVED', true);
this.loadData();
// Reload console as links may have changed
this.reloadConsole();
})
.catch((error) => this.toast.showError(error));
}
@ -188,6 +212,7 @@ export class PrivacyPolicyComponent implements OnInit, OnDestroy {
.then(() => {
setTimeout(() => {
this.loadData();
window.location.reload();
}, 1000);
})
.catch((error) => {
@ -209,4 +234,10 @@ export class PrivacyPolicyComponent implements OnInit, OnDestroy {
return false;
}
}
private reloadConsole(): void {
setTimeout(() => {
window.location.reload();
}, 1000);
}
}

View File

@ -36,7 +36,7 @@ export const APPEARANCE_GROUP: SettingLinks = {
};
export const PRIVACY_POLICY: SettingLinks = {
i18nTitle: 'SETTINGS.LIST.PRIVACYPOLICY',
i18nTitle: 'DESCRIPTIONS.SETTINGS.PRIVACY_POLICY.TITLE',
i18nDesc: 'POLICY.PRIVACY_POLICY.DESCRIPTION',
iamRouterLink: ['/settings'],
orgRouterLink: ['/org-settings'],

View File

@ -187,7 +187,7 @@ export const LOGINTEXTS: SidenavSetting = {
export const PRIVACYPOLICY: SidenavSetting = {
id: 'privacypolicy',
i18nKey: 'SETTINGS.LIST.PRIVACYPOLICY',
i18nKey: 'DESCRIPTIONS.SETTINGS.PRIVACY_POLICY.TITLE',
groupI18nKey: 'SETTINGS.GROUPS.OTHER',
requiredRoles: {
[PolicyComponentServiceType.MGMT]: ['policy.read'],

View File

@ -27,7 +27,6 @@ import {
GetMyPhoneRequest,
GetMyPhoneResponse,
GetMyPrivacyPolicyRequest,
GetMyPrivacyPolicyResponse,
GetMyProfileRequest,
GetMyProfileResponse,
GetMyUserRequest,
@ -99,11 +98,10 @@ import { ChangeQuery } from '../proto/generated/zitadel/change_pb';
import { MetadataQuery } from '../proto/generated/zitadel/metadata_pb';
import { ListQuery } from '../proto/generated/zitadel/object_pb';
import { Org, OrgFieldName, OrgQuery } from '../proto/generated/zitadel/org_pb';
import { LabelPolicy } from '../proto/generated/zitadel/policy_pb';
import { LabelPolicy, PrivacyPolicy } from '../proto/generated/zitadel/policy_pb';
import { Gender, MembershipQuery, User, WebAuthNVerification } from '../proto/generated/zitadel/user_pb';
import { GrpcService } from './grpc.service';
import { StorageKey, StorageLocation, StorageService } from './storage.service';
import { ThemeService } from './theme.service';
@Injectable({
providedIn: 'root',
@ -137,11 +135,18 @@ export class GrpcAuthService {
>(undefined);
labelPolicyLoading$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);
public privacypolicy$!: Observable<PrivacyPolicy.AsObject>;
public privacypolicy: BehaviorSubject<PrivacyPolicy.AsObject | undefined> = new BehaviorSubject<
PrivacyPolicy.AsObject | undefined
>(undefined);
privacyPolicyLoading$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);
public zitadelPermissions: BehaviorSubject<string[]> = new BehaviorSubject<string[]>([]);
public readonly fetchedZitadelPermissions: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
public cachedOrgs: BehaviorSubject<Org.AsObject[]> = new BehaviorSubject<Org.AsObject[]>([]);
private cachedLabelPolicies: { [orgId: string]: LabelPolicy.AsObject } = {};
private cachedPrivacyPolicies: { [orgId: string]: PrivacyPolicy.AsObject } = {};
constructor(
private readonly grpcService: GrpcService,
@ -169,6 +174,25 @@ export class GrpcAuthService {
},
});
this.privacypolicy$ = this.activeOrgChanged.pipe(
switchMap((org) => {
this.privacyPolicyLoading$.next(true);
return from(this.getMyPrivacyPolicy(org ? org.id : ''));
}),
filter((policy) => !!policy),
);
this.privacypolicy$.subscribe({
next: (policy) => {
this.privacypolicy.next(policy);
this.privacyPolicyLoading$.next(false);
},
error: (error) => {
console.error(error);
this.privacyPolicyLoading$.next(false);
},
});
this.user = forkJoin([
of(this.oauthService.getAccessToken()),
this.oauthService.events.pipe(
@ -697,7 +721,23 @@ export class GrpcAuthService {
}
}
public getMyPrivacyPolicy(): Promise<GetMyPrivacyPolicyResponse.AsObject> {
return this.grpcService.auth.getMyPrivacyPolicy(new GetMyPrivacyPolicyRequest(), null).then((resp) => resp.toObject());
public getMyPrivacyPolicy(orgIdForCache?: string): Promise<PrivacyPolicy.AsObject> {
if (orgIdForCache && this.cachedPrivacyPolicies[orgIdForCache]) {
return Promise.resolve(this.cachedPrivacyPolicies[orgIdForCache]);
} else {
return this.grpcService.auth
.getMyPrivacyPolicy(new GetMyPrivacyPolicyRequest(), null)
.then((resp) => resp.toObject())
.then((resp) => {
if (resp.policy) {
if (orgIdForCache) {
this.cachedPrivacyPolicies[orgIdForCache] = resp.policy;
}
return Promise.resolve(resp.policy);
} else {
return Promise.reject();
}
});
}
}
}

View File

@ -129,7 +129,7 @@
},
"PRIVACY_POLICY": {
"TITLE": "Външни връзки",
"DESCRIPTION": "Насочете вашите потребители към персонализирани външни ресурси, показани на страницата за вход. Потребителите трябва да приемат Условията за ползване и Политиката за поверителност, преди да могат да се регистрират."
"DESCRIPTION": "Насочете потребителите си към персонализирани външни ресурси, показани на страницата за вход. Потребителите трябва да приемат Общите условия и Политиката за поверителност, преди да могат да се регистрират. Променете връзката към вашата документация или задайте празен низ, за ​​да скриете бутона за документация от конзолата. Добавете персонализирана външна връзка и персонализиран текст за тази връзка в конзолата или ги оставете празни, за да скриете този бутон."
},
"SMTP_PROVIDER": {
"TITLE": "Настройки на SMTP",
@ -1564,6 +1564,9 @@
"POLICYLINK": "Връзка към Политика за поверителност",
"HELPLINK": "Връзка към Помощ",
"SUPPORTEMAIL": "Имейл за поддръжка",
"DOCSLINK": "Връзка към документи (Console)",
"CUSTOMLINK": "Персонализирана връзка (Console)",
"CUSTOMLINKTEXT": "Персонализиран текст на връзката (Console)",
"SAVED": "Запазено успешно!",
"RESET_TITLE": "Възстановяване на стойностите по подразбиране",
"RESET_DESCRIPTION": "На път сте да възстановите връзките по подразбиране за TOS и Политика за поверителност. "

View File

@ -129,7 +129,7 @@
},
"PRIVACY_POLICY": {
"TITLE": "Externí odkazy",
"DESCRIPTION": "Navede vaše uživatele k vlastním externím zdrojům zobrazeným na přihlašovací stránce. Uživatelé musí přijmout Podmínky služby a Zásady ochrany osobních údajů, než se mohou zaregistrovat."
"DESCRIPTION": "Naveďte své uživatele k vlastním externím zdrojům zobrazeným na přihlašovací stránce. Než se uživatelé mohou zaregistrovat, musí přijmout podmínky služby a zásady ochrany osobních údajů. Změňte odkaz na dokumentaci nebo nastavte prázdný řetězec, abyste skryli tlačítko dokumentace z konzoly. Přidejte vlastní externí odkaz a vlastní text pro tento odkaz v konzole nebo je nastavte na prázdné, abyste toto tlačítko skryli."
},
"SMTP_PROVIDER": {
"TITLE": "Nastavení SMTP",
@ -1571,6 +1571,9 @@
"POLICYLINK": "Odkaz na Zásady ochrany osobních údajů",
"HELPLINK": "Odkaz na pomoc",
"SUPPORTEMAIL": "E-mailová podpora",
"DOCSLINK": "Odkaz na Dokumenty (Console)",
"CUSTOMLINK": "Vlastní odkaz (Console)",
"CUSTOMLINKTEXT": "Text vlastního odkazu (Console)",
"SAVED": "Úspěšně uloženo!",
"RESET_TITLE": "Obnovit výchozí hodnoty",
"RESET_DESCRIPTION": "Chystáte se obnovit výchozí odkazy pro Podmínky služby a Zásady ochrany osobních údajů. Opravdu chcete pokračovat?"

View File

@ -129,7 +129,7 @@
},
"PRIVACY_POLICY": {
"TITLE": "Externe Links",
"DESCRIPTION": "Leite deine Benutzer zu benutzerdefinierten externen Ressourcen, die auf der Anmeldeseite angezeigt werden. Benutzer müssen die Allgemeinen Geschäftsbedingungen und die Datenschutzrichtlinie akzeptieren, bevor sie sich anmelden können."
"DESCRIPTION": "Leiten Sie Ihre Benutzer zu benutzerdefinierten externen Ressourcen, die auf der Anmeldeseite angezeigt werden. Benutzer müssen die Nutzungsbedingungen und Datenschutzrichtlinien akzeptieren, bevor sie sich anmelden können. Ändern Sie den Link zu Ihrer Dokumentation oder legen Sie eine leere Zeichenfolge fest, um die Dokumentationsschaltfläche in der Konsole auszublenden. Fügen Sie in der Konsole einen benutzerdefinierten externen Link und einen benutzerdefinierten Text für diesen Link hinzu oder setzen Sie sie leer, um diese Schaltfläche auszublenden."
},
"SMTP_PROVIDER": {
"TITLE": "SMTP-Einstellungen",
@ -1570,6 +1570,9 @@
"POLICYLINK": "Link zur den Datenschutzrichtlinien",
"HELPLINK": "Link zur Hilfestellung",
"SUPPORTEMAIL": "Support E-Mail",
"DOCSLINK": "Link zu Dokumenten (Console)",
"CUSTOMLINK": "Benutzerdefinierter Link (Console)",
"CUSTOMLINKTEXT": "Benutzerdefinierter Linktext (Console)",
"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?"

View File

@ -129,7 +129,7 @@
},
"PRIVACY_POLICY": {
"TITLE": "External Links",
"DESCRIPTION": "Guide your users to custom external resources shown on the login page. Users need to accept the Terms of Service and Privacy Policy before they can sign up."
"DESCRIPTION": "Guide your users to custom external resources shown on the login page. Users need to accept the Terms of Service and Privacy Policy before they can sign up. Change the link to your documentation or set an empty string to hide the documentation button from the console. Add a custom external link and a custom text for that link in the console, or set them empty to hide that button."
},
"SMTP_PROVIDER": {
"TITLE": "SMTP Settings",
@ -1335,7 +1335,7 @@
"DOMAIN": "Domain settings",
"LOGINTEXTS": "Login Interface Texts",
"BRANDING": "Branding",
"PRIVACYPOLICY": "Privacy Policy",
"PRIVACYPOLICY": "External links",
"OIDC": "OIDC Token lifetime and expiration",
"SECRETS": "Secret Generator",
"SECURITY": "Security settings",
@ -1571,6 +1571,9 @@
"POLICYLINK": "Link to Privacy Policy",
"HELPLINK": "Link to Help",
"SUPPORTEMAIL": "Support Email",
"DOCSLINK": "Docs Link (Console)",
"CUSTOMLINK": "Custom Link (Console)",
"CUSTOMLINKTEXT": "Custom Link Text (Console)",
"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?"

View File

@ -129,7 +129,7 @@
},
"PRIVACY_POLICY": {
"TITLE": "Enlaces Externos",
"DESCRIPTION": "Guía a tus usuarios hacia recursos externos personalizados mostrados en la página de inicio de sesión. Los usuarios necesitan aceptar los Términos de Servicio y la Política de Privacidad antes de que puedan registrarse."
"DESCRIPTION": "Guía a tus usuarios a recursos externos personalizados que se muestran en la página de inicio de sesión. Los usuarios deben aceptar los Términos de servicio y la Política de privacidad antes de poder registrarse. Cambia el enlace a tu documentación o introduce una cadena de texto vacía para ocultar el botón de documentación de la consola. Agrega un enlace externo personalizado y un texto personalizado para dicho enlace en la consola, o déjalos vacíos para ocultar ese botón."
},
"SMTP_PROVIDER": {
"TITLE": "Configuración de SMTP",
@ -1572,6 +1572,9 @@
"POLICYLINK": "Enlace a Política de privacidad",
"HELPLINK": "Enlace de ayuda",
"SUPPORTEMAIL": "Email de soporte",
"DOCSLINK": "Enlace de documentos (Console)",
"CUSTOMLINK": "Enlace personalizado (Console)",
"CUSTOMLINKTEXT": "Texto de enlace personalizado (Console)",
"SAVED": "¡Se guardó con éxito!",
"RESET_TITLE": "Restaurar valores por defecto",
"RESET_DESCRIPTION": "Estás a punto de restaurar los enlaces por defecto para los TDS y la política de privacida. ¿Quieres continuar?"

View File

@ -129,7 +129,7 @@
},
"PRIVACY_POLICY": {
"TITLE": "Liens Externes",
"DESCRIPTION": "Guide tes utilisateurs vers des ressources externes personnalisées affichées sur la page de connexion. Les utilisateurs doivent accepter les Termes de Service et la Politique de Confidentialité avant de pouvoir s'inscrire."
"DESCRIPTION": "Guidez vos utilisateurs vers des ressources externes personnalisées affichées sur la page de connexion. Les utilisateurs doivent accepter les conditions d'utilisation et la politique de confidentialité avant de pouvoir s'inscrire. Modifiez le lien vers votre documentation ou définissez une chaîne vide pour masquer le bouton de documentation de la console. Ajoutez un lien externe personnalisé et un texte personnalisé pour ce lien dans la console, ou définissez-les vides pour masquer ce bouton."
},
"SMTP_PROVIDER": {
"TITLE": "Paramètres SMTP",
@ -1570,6 +1570,9 @@
"POLICYLINK": "Lien vers la politique de confidentialité",
"HELPLINK": "Lien vers l'aide",
"SUPPORTEMAIL": "E-mail d'assistance",
"DOCSLINK": "Lien Docs (Console)",
"CUSTOMLINK": "Lien personnalisé (Console)",
"CUSTOMLINKTEXT": "Texte de lien personnalisé (Console)",
"SAVED": "Enregistré avec succès !",
"RESET_TITLE": "Restaurer les valeurs par défaut",
"RESET_DESCRIPTION": "Vous êtes sur le point de restaurer les liens par défaut pour les CGS et la politique de confidentialité. Voulez-vous vraiment continuer ?"

View File

@ -129,7 +129,7 @@
},
"PRIVACY_POLICY": {
"TITLE": "Link Esterni",
"DESCRIPTION": "Guida i tuoi utenti verso risorse esterne personalizzate mostrate nella pagina di login. Gli utenti devono accettare i Termini di Servizio e la Politica sulla Privacy prima che possano iscriversi."
"DESCRIPTION": "Guida i tuoi utenti alle risorse esterne personalizzate mostrate nella pagina di accesso. Gli utenti devono accettare i Termini di servizio e l'Informativa sulla privacy prima di potersi registrare. Cambia il collegamento alla tua documentazione o imposta una stringa vuota per nascondere il pulsante della documentazione dalla console. Aggiungi un collegamento esterno personalizzato e un testo personalizzato per quel collegamento nella console oppure impostali vuoti per nascondere quel pulsante."
},
"SMTP_PROVIDER": {
"TITLE": "Impostazioni SMTP",
@ -1570,6 +1570,9 @@
"POLICYLINK": "Link all'informativa sulla privacy",
"HELPLINK": "link per l'aiuto",
"SUPPORTEMAIL": "e-mail di supporto",
"DOCSLINK": "Collegamento a Documenti (Console)",
"CUSTOMLINK": "Collegamento personalizzato (Console)",
"CUSTOMLINKTEXT": "Testo del collegamento personalizzato (Console)",
"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?"

View File

@ -129,7 +129,7 @@
},
"PRIVACY_POLICY": {
"TITLE": "外部リンク",
"DESCRIPTION": "ログインページに表示されるカスタム外部リソースへのユーザーガイドです。ユーザーは、サインアップする前に利用規約とプライバシーポリシーを受け入れる必要があります。"
"DESCRIPTION": "ログイン ページに表示されるカスタム外部リソースにユーザーを誘導します。ユーザーはサインアップする前に、サービス利用規約とプライバシー ポリシーに同意する必要があります。ドキュメントへのリンクを変更するか、空の文字列を設定してコンソールからドキュメント ボタンを非表示にします。カスタム外部リンクとそのリンクのカスタム テキストをコンソールに追加するか、それらを空に設定してそのボタンを非表示にします。"
},
"SMTP_PROVIDER": {
"TITLE": "SMTP設定",
@ -1566,6 +1566,10 @@
"TOSLINK": "利用規約へのリンク",
"POLICYLINK": "プライバシーポリシーへのリンク",
"HELPLINK": "ヘルプへのリンク",
"SUPPORTEMAIL": "サポートメール",
"DOCSLINK": "ドキュメントリンク (Console)",
"CUSTOMLINK": "カスタムリンク(Console)",
"CUSTOMLINKTEXT": "カスタム リンク テキスト (Console)",
"SAVED": "正常に保存されました!",
"RESET_TITLE": "デフォルト値を復元する",
"RESET_DESCRIPTION": "TOSおよびプライバシーポリシーのデフォルトリンクを復元しようとしています。本当によろしいですか"

View File

@ -129,7 +129,7 @@
},
"PRIVACY_POLICY": {
"TITLE": "Надворешни врски",
"DESCRIPTION": "Упатете ги вашите корисници кон прилагодени надворешни ресурси прикажани на страницата за најава. Корисниците треба да ги прифатат условите за користење и политиката за приватност пред да се регистрираат."
"DESCRIPTION": "Водете ги вашите корисници до сопствени надворешни ресурси прикажани на страницата за најавување. Корисниците треба да ги прифатат Условите за користење и Политиката за приватност пред да можат да се регистрираат. Променете ја врската до вашата документација или поставете празна низа за да го скриете копчето за документација од конзолата. Додајте приспособена надворешна врска и прилагоден текст за таа врска во конзолата или поставете ги празни за да го скриете тоа копче."
},
"SMTP_PROVIDER": {
"TITLE": "SMTP поставки",
@ -1572,6 +1572,9 @@
"POLICYLINK": "Линк кон Политиката за приватност",
"HELPLINK": "Линк кон Помош",
"SUPPORTEMAIL": "Е-пошта за поддршка",
"DOCSLINK": "Врска за документи (Console)",
"CUSTOMLINK": "Прилагодена врска (Console)",
"CUSTOMLINKTEXT": "Текст за приспособена врска (Console)",
"SAVED": "Успешно зачувано!",
"RESET_TITLE": "Врати на стандардни вредности",
"RESET_DESCRIPTION": "Се подготвувате да ги вратите стандардните линкови за Условите за користење и Политиката за приватност. Дали сте сигурни дека сакате да продолжите?"

View File

@ -129,7 +129,7 @@
},
"PRIVACY_POLICY": {
"TITLE": "Externe links",
"DESCRIPTION": "Leid je gebruikers naar aangepaste externe bronnen die worden getoond op de inlogpagina. Gebruikers moeten de Algemene Voorwaarden en het Privacybeleid accepteren voordat ze zich kunnen aanmelden."
"DESCRIPTION": "Leid uw gebruikers naar aangepaste externe bronnen die op de inlogpagina worden weergegeven. Gebruikers moeten de Servicevoorwaarden en het Privacybeleid accepteren voordat ze zich kunnen aanmelden. Wijzig de link naar uw documentatie of stel een lege string in om de documentatieknop voor de console te verbergen. Voeg een aangepaste externe link en een aangepaste tekst voor die link toe in de console, of stel ze leeg om die knop te verbergen."
},
"SMTP_PROVIDER": {
"TITLE": "SMTP-instellingen",
@ -1571,6 +1571,9 @@
"POLICYLINK": "Link naar Privacybeleid",
"HELPLINK": "Link naar Help",
"SUPPORTEMAIL": "Ondersteuning Email",
"DOCSLINK": "Documentenlink (Console)",
"CUSTOMLINK": "Aangepaste link (Console)",
"CUSTOMLINKTEXT": "Aangepaste linktekst (Console)",
"SAVED": "Succesvol opgeslagen!",
"RESET_TITLE": "Herstel Standaard Waarden",
"RESET_DESCRIPTION": "U staat op het punt de standaard Links voor TOS en Privacybeleid te herstellen. Weet u zeker dat u wilt doorgaan?"

View File

@ -129,7 +129,7 @@
},
"PRIVACY_POLICY": {
"TITLE": "Linki zewnętrzne",
"DESCRIPTION": "Przekieruj użytkowników do niestandardowych zasobów zewnętrznych pokazanych na stronie logowania. Użytkownicy muszą zaakceptować Warunki korzystania z usługi i Politykę prywatności, zanim będą mogli się zarejestrować."
"DESCRIPTION": "Poprowadź użytkowników do niestandardowych zasobów zewnętrznych wyświetlanych na stronie logowania. Użytkownicy muszą zaakceptować Warunki świadczenia usług i Politykę prywatności, zanim będą mogli się zarejestrować. Zmień łącze do dokumentacji lub ustaw pusty ciąg, aby ukryć przycisk dokumentacji w konsoli. Dodaj niestandardowy link zewnętrzny i niestandardowy tekst dla tego łącza w konsoli lub ustaw je puste, aby ukryć ten przycisk."
},
"SMTP_PROVIDER": {
"TITLE": "Ustawienia SMTP",
@ -1570,6 +1570,9 @@
"POLICYLINK": "Link do polityki prywatności",
"HELPLINK": "Link do pomocy",
"SUPPORTEMAIL": "E-mail wsparcia",
"DOCSLINK": "Link do Dokumentów (Console)",
"CUSTOMLINK": "Link niestandardowy (Console)",
"CUSTOMLINKTEXT": "Niestandardowy tekst łącza (Console)",
"SAVED": "Pomyślnie zapisano!",
"RESET_TITLE": "Przywróć wartości domyślne",
"RESET_DESCRIPTION": "Masz zamiar przywrócić domyślne linki dla TOS i polityki prywatności. Czy na pewno chcesz kontynuować?"

View File

@ -129,7 +129,7 @@
},
"PRIVACY_POLICY": {
"TITLE": "Links Externos",
"DESCRIPTION": "Guie seus usuários para recursos externos personalizados mostrados na página de login. Os usuários precisam aceitar os Termos de Serviço e a Política de Privacidade antes de poderem se inscrever."
"DESCRIPTION": "Oriente seus usuários sobre recursos externos personalizados mostrados na página de login. Os usuários precisam aceitar os Termos de Serviço e a Política de Privacidade antes de se inscreverem. Altere o link para sua documentação ou defina uma string vazia para ocultar o botão de documentação do console. Adicione um link externo personalizado e um texto personalizado para esse link no console ou deixe-os vazios para ocultar esse botão."
},
"SMTP_PROVIDER": {
"TITLE": "Configurações de SMTP",
@ -1572,6 +1572,9 @@
"POLICYLINK": "Link para a Política de Privacidade",
"HELPLINK": "Link para Ajuda",
"SUPPORTEMAIL": "E-mail de suporte",
"DOCSLINK": "Link do Documentos (Console)",
"CUSTOMLINK": "Link personalizado (Console)",
"CUSTOMLINKTEXT": "Texto do link personalizado (Console)",
"SAVED": "Salvo com sucesso!",
"RESET_TITLE": "Restaurar valores padrão",
"RESET_DESCRIPTION": "Você está prestes a restaurar os Links padrão para TOS e Política de Privacidade. Deseja realmente continuar?"

View File

@ -129,7 +129,7 @@
},
"PRIVACY_POLICY": {
"TITLE": "Внешние ссылки",
"DESCRIPTION": "Направьте ваших пользователей к пользовательским внешним ресурсам, показанным на странице входа. Пользователи должны принять Условия обслуживания и Политику конфиденциальности, прежде чем они смогут зарегистрироваться."
"DESCRIPTION": "Guide your users to custom external resources shown on the login page. Users need to accept the Terms of Service and Privacy Policy before they can sign up. Change the link to your documentation or set an empty string to hide the documentation button from the console. Add a custom external link and a custom text for that link in the console, or set them empty to hide that button."
},
"SMTP_PROVIDER": {
"TITLE": "Настройки SMTP",
@ -1626,6 +1626,9 @@
"POLICYLINK": "Ссылка на Политику конфиденциальности",
"HELPLINK": "Ссылка на Помощь",
"SUPPORTEMAIL": "Электронная почта поддержки",
"DOCSLINK": "Ссылка на Документы (Console)",
"CUSTOMLINK": "Пользовательская ссылка (Console)",
"CUSTOMLINKTEXT": "Пользовательский текст ссылки (Console)",
"SAVED": "Успешно сохранено!",
"RESET_TITLE": "Восстановить значения по умолчанию",
"RESET_DESCRIPTION": "Вы собираетесь восстановить ссылки по умолчанию для Пользовательского соглашения и Политики конфиденциальности. Вы действительно хотите продолжить?"

View File

@ -129,7 +129,7 @@
},
"PRIVACY_POLICY": {
"TITLE": "外部链接",
"DESCRIPTION": "引导您的用户到登录页面上显示的自定义外部资源。用户需要在注册前接受服务条款和隐私政策。"
"DESCRIPTION": "引导您的用户访问登录页面上显示的自定义外部资源。用户需要先接受服务条款和隐私政策,然后才能注册。更改文档的链接或设置空字符串以在控制台中隐藏文档按钮。在控制台中添加自定义外部链接和该链接的自定义文本,或将它们设置为空以隐藏该按钮。"
},
"SMTP_PROVIDER": {
"TITLE": "SMTP设置",
@ -1569,6 +1569,9 @@
"POLICYLINK": "链接到隐私政策",
"HELPLINK": "链接到帮助",
"SUPPORTEMAIL": "支持邮箱",
"DOCSLINK": "文档链接Console",
"CUSTOMLINK": "自定义链接Console",
"CUSTOMLINKTEXT": "自定义链接文本Console",
"SAVED": "保存成功!",
"RESET_TITLE": "恢复默认值",
"RESET_DESCRIPTION": "您即将恢复 TOS 和隐私政策的默认链接。你真的要继续吗?"

View File

@ -26,8 +26,7 @@ When you configure your default settings, you can set the following:
- [**Branding**](#branding): Appearance of the login interface.
- [**Message Texts**](#message-texts): Text and internationalization for emails
- [**Login Interface Texts**](#login-interface-texts): Text and internationalization for the login interface
- [**Languages**](#languages): Select which supported langauges are shown to your users. Set the default language if no context is provided.
- [**Privacy Policy**](#privacy-policy-and-tos): Links to your own Terms of Service and Privacy Policy regulations. Link to Help Page.
- [**External Links**](#external-links): Links to your own Terms of Service and Privacy Policy regulations, Help Page, Support email, documentation link...
- [**OIDC Token Lifetimes and Expiration**](#oidc-token-lifetimes-and-expiration): Token lifetime and expiration settings.
- [**Secret Generator**](#secret-generator): Appearance and expiration of the generated codes and secrets used in mails for verification etc.
@ -256,9 +255,10 @@ You can either set this attribute on your whole ZITADEL instance or just on some
Please refer to the [configuration guide](/docs/guides/solution-scenarios/configurations#use-email-to-login) for more information.
## Privacy Policy and TOS
## External links
With this setting you are able to configure your privacy policy, terms of service, help links and help/support email address.
On register each user has to accept these policies.
This policy can be also be overriden by your organizations.
@ -269,8 +269,16 @@ Example:
`https://demo.com/tos-{{.Lang}}`
<img
src="/docs/img/guides/console/privacypolicy.png"
alt="Privacy Policy"
src="/docs/img/guides/console/external_links_1.png"
alt="External Links"
width="600px"
/>
Also you can set the link associated to the Documentation button in the console. Set an empty text if you don't want to show a Documentation button in your console. If you need a custom button to be shown in the console you can set the button text and the link associated to the button (if the button text is button no text will be shown).
<img
src="/docs/img/guides/console/external_links_2.png"
alt="Custom button"
width="600px"
/>

View File

@ -114,7 +114,7 @@ Those settings are the same as on your instance.
- [**Branding**](./default-settings#branding): Appearance of the login interface.
- [**Message Texts**](./default-settings#message-texts): Text and internationalization for emails
- [**Login Interface Texts**](./default-settings#login-interface-texts): Text and internationalization for the login interface
- [**Privacy Policy**](./default-settings#privacy-policy-and-tos): Links to your own Terms of Service and Privacy Policy regulations. Link to Help Page.
- [**External Links**](./default-settings#external-links): Links to your own Terms of Service and Privacy Policy regulations, Help Page, Support email, documentation link...
If you need custom branding on a organization (for example in a B2B scenario, where organizations are allowed to use their custom design), navigate back to the home page, choose your organization in the header above, navigate to the organization settings and set the custom design here.

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

View File

@ -0,0 +1,104 @@
import { ensureExternalLinksSettingsSet } from 'support/api/external-links-settings';
import { apiAuth } from '../../support/api/apiauth';
describe('instance external link settings', () => {
const externalLinkSettingsPath = `/instance?id=privacypolicy`;
const tosLink = 'https://zitadel.com/docs/legal/terms-of-service';
const privacyPolicyLink = 'https://zitadel.com/docs/legal/privacy-policy';
const helpLink = '';
const supportEmail = '';
const customLink = '';
const customLinkText = '';
const docsLink = 'https://zitadel.com/docs';
beforeEach(`ensure they are set`, () => {
apiAuth().then((apiCallProperties) => {
ensureExternalLinksSettingsSet(apiCallProperties, tosLink, privacyPolicyLink, docsLink);
cy.visit(externalLinkSettingsPath);
});
});
it(`should have default settings`, () => {
cy.get('[formcontrolname="tosLink"]').should('value', tosLink);
cy.get('[formcontrolname="privacyLink"]').should('value', privacyPolicyLink);
cy.get('[formcontrolname="helpLink"]').should('value', helpLink);
cy.get('[formcontrolname="supportEmail"]').should('value', supportEmail);
cy.get('[formcontrolname="customLink"]').should('value', customLink);
cy.get('[formcontrolname="customLinkText"]').should('value', customLinkText);
cy.get('[formcontrolname="docsLink"]').should('value', docsLink);
});
it(`should update external links`, () => {
cy.get('[formcontrolname="tosLink"]').clear().type('tosLink2');
cy.get('[formcontrolname="privacyLink"]').clear().type('privacyLink2');
cy.get('[formcontrolname="helpLink"]').clear().type('helpLink');
cy.get('[formcontrolname="supportEmail"]').clear().type('support@example.com');
cy.get('[formcontrolname="customLink"]').clear().type('customLink');
cy.get('[formcontrolname="customLinkText"]').clear().type('customLinkText');
cy.get('[formcontrolname="docsLink"]').clear().type('docsLink');
cy.get('[data-e2e="save-button"]').click();
cy.shouldConfirmSuccess();
});
it(`should return to default values`, () => {
cy.get('[formcontrolname="tosLink"]').should('value', tosLink);
cy.get('[formcontrolname="privacyLink"]').should('value', privacyPolicyLink);
cy.get('[formcontrolname="helpLink"]').should('value', helpLink);
cy.get('[formcontrolname="supportEmail"]').should('value', supportEmail);
cy.get('[formcontrolname="customLink"]').should('value', customLink);
cy.get('[formcontrolname="customLinkText"]').should('value', customLinkText);
cy.get('[formcontrolname="docsLink"]').should('value', docsLink);
});
});
describe('instance external link settings', () => {
const externalLinkSettingsPath = `/org-settings?id=privacypolicy`;
const tosLink = 'https://zitadel.com/docs/legal/terms-of-service';
const privacyPolicyLink = 'https://zitadel.com/docs/legal/privacy-policy';
const helpLink = '';
const supportEmail = '';
const customLink = '';
const customLinkText = '';
const docsLink = 'https://zitadel.com/docs';
beforeEach(() => {
cy.context().as('ctx');
cy.visit(externalLinkSettingsPath);
});
it(`should have default settings`, () => {
cy.get('[formcontrolname="tosLink"]').should('value', tosLink);
cy.get('[formcontrolname="privacyLink"]').should('value', privacyPolicyLink);
cy.get('[formcontrolname="helpLink"]').should('value', helpLink);
cy.get('[formcontrolname="supportEmail"]').should('value', supportEmail);
cy.get('[formcontrolname="customLink"]').should('value', customLink);
cy.get('[formcontrolname="customLinkText"]').should('value', customLinkText);
cy.get('[formcontrolname="docsLink"]').should('value', docsLink);
});
it(`should update external links`, () => {
cy.get('[formcontrolname="tosLink"]').clear().type('tosLink2');
cy.get('[formcontrolname="privacyLink"]').clear().type('privacyLink2');
cy.get('[formcontrolname="helpLink"]').clear().type('helpLink');
cy.get('[formcontrolname="supportEmail"]').clear().type('support@example.com');
cy.get('[formcontrolname="customLink"]').clear().type('customLink');
cy.get('[formcontrolname="customLinkText"]').clear().type('customLinkText');
cy.get('[formcontrolname="docsLink"]').clear().type('docsLink');
cy.get('[data-e2e="save-button"]').click();
cy.shouldConfirmSuccess();
});
it(`should return to default values`, () => {
cy.get('[data-e2e="reset-button"]').click();
cy.get('[data-e2e="confirm-dialog-button"]').click();
cy.get('[formcontrolname="tosLink"]').should('value', tosLink);
cy.get('[formcontrolname="privacyLink"]').should('value', privacyPolicyLink);
cy.get('[formcontrolname="helpLink"]').should('value', helpLink);
cy.get('[formcontrolname="supportEmail"]').should('value', supportEmail);
cy.get('[formcontrolname="customLink"]').should('value', customLink);
cy.get('[formcontrolname="customLinkText"]').should('value', customLinkText);
cy.get('[formcontrolname="docsLink"]').should('value', docsLink);
});
});

View File

@ -0,0 +1,32 @@
import { ensureSetting } from './ensure';
import { API } from './types';
export function ensureExternalLinksSettingsSet(api: API, tosLink: string, privacyPolicyLink: string, docsLink: string) {
return ensureSetting(
api,
`${api.adminBaseURL}/policies/privacy`,
(body: any) => {
const result = {
sequence: body.policy?.details?.sequence,
id: body.policy.id,
entity: null,
};
if (
body.policy &&
body.policy.tosLink === tosLink &&
body.policy.privacyLink === privacyPolicyLink &&
body.policy.docsLink === docsLink
) {
return { ...result, entity: body.policy };
}
return result;
},
`${api.adminBaseURL}/policies/privacy`,
{
tosLink,
privacyLink: privacyPolicyLink,
docsLink,
},
);
}

View File

@ -534,10 +534,13 @@ func (s *Server) getPrivacyPolicy(ctx context.Context, orgID string) (_ *managem
}
if !queriedPrivacy.IsDefault {
return &management_pb.AddCustomPrivacyPolicyRequest{
TosLink: queriedPrivacy.TOSLink,
PrivacyLink: queriedPrivacy.PrivacyLink,
HelpLink: queriedPrivacy.HelpLink,
SupportEmail: string(queriedPrivacy.SupportEmail),
TosLink: queriedPrivacy.TOSLink,
PrivacyLink: queriedPrivacy.PrivacyLink,
HelpLink: queriedPrivacy.HelpLink,
SupportEmail: string(queriedPrivacy.SupportEmail),
DocsLink: queriedPrivacy.DocsLink,
CustomLink: queriedPrivacy.CustomLink,
CustomLinkText: queriedPrivacy.CustomLinkText,
}, nil
}
return nil, nil

View File

@ -7,9 +7,12 @@ import (
func UpdatePrivacyPolicyToDomain(req *admin_pb.UpdatePrivacyPolicyRequest) *domain.PrivacyPolicy {
return &domain.PrivacyPolicy{
TOSLink: req.TosLink,
PrivacyLink: req.PrivacyLink,
HelpLink: req.HelpLink,
SupportEmail: domain.EmailAddress(req.SupportEmail),
TOSLink: req.TosLink,
PrivacyLink: req.PrivacyLink,
HelpLink: req.HelpLink,
SupportEmail: domain.EmailAddress(req.SupportEmail),
DocsLink: req.DocsLink,
CustomLink: req.CustomLink,
CustomLinkText: req.CustomLinkText,
}
}

View File

@ -7,18 +7,24 @@ import (
func AddPrivacyPolicyToDomain(req *mgmt_pb.AddCustomPrivacyPolicyRequest) *domain.PrivacyPolicy {
return &domain.PrivacyPolicy{
TOSLink: req.TosLink,
PrivacyLink: req.PrivacyLink,
HelpLink: req.HelpLink,
SupportEmail: domain.EmailAddress(req.SupportEmail),
TOSLink: req.TosLink,
PrivacyLink: req.PrivacyLink,
HelpLink: req.HelpLink,
SupportEmail: domain.EmailAddress(req.SupportEmail),
DocsLink: req.DocsLink,
CustomLink: req.CustomLink,
CustomLinkText: req.CustomLinkText,
}
}
func UpdatePrivacyPolicyToDomain(req *mgmt_pb.UpdateCustomPrivacyPolicyRequest) *domain.PrivacyPolicy {
return &domain.PrivacyPolicy{
TOSLink: req.TosLink,
PrivacyLink: req.PrivacyLink,
HelpLink: req.HelpLink,
SupportEmail: domain.EmailAddress(req.SupportEmail),
TOSLink: req.TosLink,
PrivacyLink: req.PrivacyLink,
HelpLink: req.HelpLink,
SupportEmail: domain.EmailAddress(req.SupportEmail),
DocsLink: req.DocsLink,
CustomLink: req.CustomLink,
CustomLinkText: req.CustomLinkText,
}
}

View File

@ -19,5 +19,8 @@ func ModelPrivacyPolicyToPb(policy *query.PrivacyPolicy) *policy_pb.PrivacyPolic
policy.ChangeDate,
policy.ResourceOwner,
),
DocsLink: policy.DocsLink,
CustomLink: policy.CustomLink,
CustomLinkText: policy.CustomLinkText,
}
}

View File

@ -154,6 +154,9 @@ func legalAndSupportSettingsToPb(current *query.PrivacyPolicy) *settings.LegalAn
HelpLink: current.HelpLink,
SupportEmail: string(current.SupportEmail),
ResourceOwnerType: isDefaultToResourceOwnerTypePb(current.IsDefault),
DocsLink: current.DocsLink,
CustomLink: current.CustomLink,
CustomLinkText: current.CustomLinkText,
}
}

View File

@ -316,17 +316,23 @@ func Test_domainSettingsToPb(t *testing.T) {
func Test_legalSettingsToPb(t *testing.T) {
arg := &query.PrivacyPolicy{
TOSLink: "http://example.com/tos",
PrivacyLink: "http://example.com/pricacy",
HelpLink: "http://example.com/help",
SupportEmail: "support@zitadel.com",
IsDefault: true,
TOSLink: "http://example.com/tos",
PrivacyLink: "http://example.com/pricacy",
HelpLink: "http://example.com/help",
SupportEmail: "support@zitadel.com",
IsDefault: true,
DocsLink: "http://example.com/docs",
CustomLink: "http://example.com/custom",
CustomLinkText: "Custom",
}
want := &settings.LegalAndSupportSettings{
TosLink: "http://example.com/tos",
PrivacyPolicyLink: "http://example.com/pricacy",
HelpLink: "http://example.com/help",
SupportEmail: "support@zitadel.com",
DocsLink: "http://example.com/docs",
CustomLink: "http://example.com/custom",
CustomLinkText: "Custom",
ResourceOwnerType: settings.ResourceOwnerType_RESOURCE_OWNER_TYPE_INSTANCE,
}
got := legalAndSupportSettingsToPb(arg)

View File

@ -1286,12 +1286,15 @@ func privacyPolicyToDomain(p *query.PrivacyPolicy) *domain.PrivacyPolicy {
CreationDate: p.CreationDate,
ChangeDate: p.ChangeDate,
},
State: p.State,
Default: p.IsDefault,
TOSLink: p.TOSLink,
PrivacyLink: p.PrivacyLink,
HelpLink: p.HelpLink,
SupportEmail: p.SupportEmail,
State: p.State,
Default: p.IsDefault,
TOSLink: p.TOSLink,
PrivacyLink: p.PrivacyLink,
HelpLink: p.HelpLink,
SupportEmail: p.SupportEmail,
DocsLink: p.DocsLink,
CustomLink: p.CustomLink,
CustomLinkText: p.CustomLinkText,
}
}

View File

@ -81,10 +81,13 @@ type InstanceSetup struct {
PasswordChange bool
}
PrivacyPolicy struct {
TOSLink string
PrivacyLink string
HelpLink string
SupportEmail domain.EmailAddress
TOSLink string
PrivacyLink string
HelpLink string
SupportEmail domain.EmailAddress
DocsLink string
CustomLink string
CustomLinkText string
}
LabelPolicy struct {
PrimaryColor string
@ -270,7 +273,7 @@ func (c *Commands) SetUpInstance(ctx context.Context, setup *InstanceSetup) (str
*/
prepareAddMultiFactorToDefaultLoginPolicy(instanceAgg, domain.MultiFactorTypeU2FWithPIN),
prepareAddDefaultPrivacyPolicy(instanceAgg, setup.PrivacyPolicy.TOSLink, setup.PrivacyPolicy.PrivacyLink, setup.PrivacyPolicy.HelpLink, setup.PrivacyPolicy.SupportEmail),
prepareAddDefaultPrivacyPolicy(instanceAgg, setup.PrivacyPolicy.TOSLink, setup.PrivacyPolicy.PrivacyLink, setup.PrivacyPolicy.HelpLink, setup.PrivacyPolicy.SupportEmail, setup.PrivacyPolicy.DocsLink, setup.PrivacyPolicy.CustomLink, setup.PrivacyPolicy.CustomLinkText),
prepareAddDefaultNotificationPolicy(instanceAgg, setup.NotificationPolicy.PasswordChange),
prepareAddDefaultLockoutPolicy(instanceAgg, setup.LockoutPolicy.MaxPasswordAttempts, setup.LockoutPolicy.MaxOTPAttempts, setup.LockoutPolicy.ShouldShowLockoutFailure),

View File

@ -116,11 +116,14 @@ func writeModelToLockoutPolicy(wm *LockoutPolicyWriteModel) *domain.LockoutPolic
func writeModelToPrivacyPolicy(wm *PrivacyPolicyWriteModel) *domain.PrivacyPolicy {
return &domain.PrivacyPolicy{
ObjectRoot: writeModelToObjectRoot(wm.WriteModel),
TOSLink: wm.TOSLink,
PrivacyLink: wm.PrivacyLink,
HelpLink: wm.HelpLink,
SupportEmail: wm.SupportEmail,
ObjectRoot: writeModelToObjectRoot(wm.WriteModel),
TOSLink: wm.TOSLink,
PrivacyLink: wm.PrivacyLink,
HelpLink: wm.HelpLink,
SupportEmail: wm.SupportEmail,
DocsLink: wm.DocsLink,
CustomLink: wm.CustomLink,
CustomLinkText: wm.CustomLinkText,
}
}

View File

@ -12,17 +12,37 @@ import (
"github.com/zitadel/zitadel/internal/zerrors"
)
func (c *Commands) AddDefaultPrivacyPolicy(ctx context.Context, tosLink, privacyLink, helpLink string, supportEmail domain.EmailAddress) (*domain.ObjectDetails, error) {
func (c *Commands) AddDefaultPrivacyPolicy(ctx context.Context, tosLink, privacyLink, helpLink string, supportEmail domain.EmailAddress, docsLink, customLink, customLinkText string) (*domain.ObjectDetails, error) {
instanceAgg := instance.NewAggregate(authz.GetInstance(ctx).InstanceID())
cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, prepareAddDefaultPrivacyPolicy(instanceAgg, tosLink, privacyLink, helpLink, supportEmail))
if supportEmail != "" {
if err := supportEmail.Validate(); err != nil {
return nil, err
}
supportEmail = supportEmail.Normalize()
}
writeModel := NewInstancePrivacyPolicyWriteModel(ctx)
err := c.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return nil, err
}
pushedEvents, err := c.eventstore.Push(ctx, cmds...)
if writeModel.State.Exists() {
return nil, zerrors.ThrowAlreadyExists(nil, "INSTANCE-M00rJ", "Errors.Instance.PrivacyPolicy.AlreadyExists")
}
event := instance.NewPrivacyPolicyAddedEvent(ctx, &instanceAgg.Aggregate, tosLink, privacyLink, helpLink, supportEmail, docsLink, customLink, customLinkText)
pushedEvents, err := c.eventstore.Push(ctx, event)
if err != nil {
return nil, err
}
return pushedEventsToObjectDetails(pushedEvents), nil
err = AppendAndReduce(writeModel, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToObjectDetails(&writeModel.WriteModel), nil
}
func (c *Commands) ChangeDefaultPrivacyPolicy(ctx context.Context, policy *domain.PrivacyPolicy) (*domain.PrivacyPolicy, error) {
@ -42,7 +62,7 @@ func (c *Commands) ChangeDefaultPrivacyPolicy(ctx context.Context, policy *domai
}
instanceAgg := InstanceAggregateFromWriteModel(&existingPolicy.PrivacyPolicyWriteModel.WriteModel)
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, instanceAgg, policy.TOSLink, policy.PrivacyLink, policy.HelpLink, policy.SupportEmail)
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, instanceAgg, policy.TOSLink, policy.PrivacyLink, policy.HelpLink, policy.SupportEmail, policy.DocsLink, policy.CustomLink, policy.CustomLinkText)
if !hasChanged {
return nil, zerrors.ThrowPreconditionFailed(nil, "INSTANCE-9jJfs", "Errors.IAM.PrivacyPolicy.NotChanged")
}
@ -89,6 +109,7 @@ func prepareAddDefaultPrivacyPolicy(
privacyLink,
helpLink string,
supportEmail domain.EmailAddress,
docsLink, customLink, customLinkText string,
) preparation.Validation {
return func() (preparation.CreateCommands, error) {
if supportEmail != "" {
@ -111,7 +132,7 @@ func prepareAddDefaultPrivacyPolicy(
return nil, zerrors.ThrowAlreadyExists(nil, "INSTANCE-M00rJ", "Errors.Instance.PrivacyPolicy.AlreadyExists")
}
return []eventstore.Command{
instance.NewPrivacyPolicyAddedEvent(ctx, &a.Aggregate, tosLink, privacyLink, helpLink, supportEmail),
instance.NewPrivacyPolicyAddedEvent(ctx, &a.Aggregate, tosLink, privacyLink, helpLink, supportEmail, docsLink, customLink, customLinkText),
}, nil
}, nil
}

View File

@ -59,6 +59,7 @@ func (wm *InstancePrivacyPolicyWriteModel) NewChangedEvent(
privacyLink,
helpLink string,
supportEmail domain.EmailAddress,
docsLink, customLink, customLinkText string,
) (*instance.PrivacyPolicyChangedEvent, bool) {
changes := make([]policy.PrivacyPolicyChanges, 0)
@ -74,6 +75,15 @@ func (wm *InstancePrivacyPolicyWriteModel) NewChangedEvent(
if wm.SupportEmail != supportEmail {
changes = append(changes, policy.ChangeSupportEmail(supportEmail))
}
if wm.DocsLink != docsLink {
changes = append(changes, policy.ChangeDocsLink(docsLink))
}
if wm.CustomLink != customLink {
changes = append(changes, policy.ChangeCustomLink(customLink))
}
if wm.CustomLinkText != customLinkText {
changes = append(changes, policy.ChangeCustomLinkText(customLinkText))
}
if len(changes) == 0 {
return nil, false
}

View File

@ -20,11 +20,14 @@ func TestCommandSide_AddDefaultPrivacyPolicy(t *testing.T) {
eventstore *eventstore.Eventstore
}
type args struct {
ctx context.Context
tosLink string
privacyLink string
helpLink string
supportEmail domain.EmailAddress
ctx context.Context
tosLink string
privacyLink string
helpLink string
supportEmail domain.EmailAddress
docsLink string
customLink string
customLinkText string
}
type res struct {
want *domain.ObjectDetails
@ -49,17 +52,23 @@ func TestCommandSide_AddDefaultPrivacyPolicy(t *testing.T) {
"PrivacyLink",
"HelpLink",
"support@example.com",
"DocsLink",
"CustomLink",
"Custom",
),
),
),
),
},
args: args{
ctx: context.Background(),
tosLink: "TOSLink",
privacyLink: "PrivacyLink",
helpLink: "HelpLink",
supportEmail: "support@example.com",
ctx: context.Background(),
tosLink: "TOSLink",
privacyLink: "PrivacyLink",
helpLink: "HelpLink",
supportEmail: "support@example.com",
docsLink: "DocsLink",
customLink: "CustomLink",
customLinkText: "Custom",
},
res: res{
err: zerrors.IsErrorAlreadyExists,
@ -78,16 +87,22 @@ func TestCommandSide_AddDefaultPrivacyPolicy(t *testing.T) {
"PrivacyLink",
"HelpLink",
"support@example.com",
"DocsLink",
"CustomLink",
"Custom",
),
),
),
},
args: args{
ctx: authz.WithInstanceID(context.Background(), "INSTANCE"),
tosLink: "TOSLink",
privacyLink: "PrivacyLink",
helpLink: "HelpLink",
supportEmail: "support@example.com",
ctx: authz.WithInstanceID(context.Background(), "INSTANCE"),
tosLink: "TOSLink",
privacyLink: "PrivacyLink",
helpLink: "HelpLink",
supportEmail: "support@example.com",
docsLink: "DocsLink",
customLink: "CustomLink",
customLinkText: "Custom",
},
res: res{
want: &domain.ObjectDetails{
@ -103,11 +118,14 @@ func TestCommandSide_AddDefaultPrivacyPolicy(t *testing.T) {
),
},
args: args{
ctx: authz.WithInstanceID(context.Background(), "INSTANCE"),
tosLink: "TOSLink",
privacyLink: "PrivacyLink",
helpLink: "HelpLink",
supportEmail: "wrong email",
ctx: authz.WithInstanceID(context.Background(), "INSTANCE"),
tosLink: "TOSLink",
privacyLink: "PrivacyLink",
helpLink: "HelpLink",
supportEmail: "wrong email",
docsLink: "DocsLink",
customLink: "CustomLink",
customLinkText: "Custom",
},
res: res{
err: zerrors.IsErrorInvalidArgument,
@ -126,6 +144,9 @@ func TestCommandSide_AddDefaultPrivacyPolicy(t *testing.T) {
"",
"",
"",
"",
"",
"",
),
),
),
@ -149,7 +170,7 @@ func TestCommandSide_AddDefaultPrivacyPolicy(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
}
got, err := r.AddDefaultPrivacyPolicy(tt.args.ctx, tt.args.tosLink, tt.args.privacyLink, tt.args.helpLink, tt.args.supportEmail)
got, err := r.AddDefaultPrivacyPolicy(tt.args.ctx, tt.args.tosLink, tt.args.privacyLink, tt.args.helpLink, tt.args.supportEmail, tt.args.docsLink, tt.args.customLink, tt.args.customLinkText)
if tt.res.err == nil {
assert.NoError(t, err)
}
@ -192,10 +213,13 @@ func TestCommandSide_ChangeDefaultPrivacyPolicy(t *testing.T) {
args: args{
ctx: context.Background(),
policy: &domain.PrivacyPolicy{
TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink",
HelpLink: "HelpLink",
SupportEmail: "support@example.com",
TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink",
HelpLink: "HelpLink",
SupportEmail: "support@example.com",
DocsLink: "DocsLink",
CustomLink: "CustomLink",
CustomLinkText: "CustomLinkText",
},
},
res: res{
@ -215,6 +239,9 @@ func TestCommandSide_ChangeDefaultPrivacyPolicy(t *testing.T) {
"PrivacyLink",
"HelpLink",
"support@example.com",
"DocsLink",
"CustomLink",
"CustomLinkText",
),
),
),
@ -223,10 +250,13 @@ func TestCommandSide_ChangeDefaultPrivacyPolicy(t *testing.T) {
args: args{
ctx: context.Background(),
policy: &domain.PrivacyPolicy{
TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink",
HelpLink: "HelpLink",
SupportEmail: "support@example.com",
TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink",
HelpLink: "HelpLink",
SupportEmail: "support@example.com",
DocsLink: "DocsLink",
CustomLink: "CustomLink",
CustomLinkText: "CustomLinkText",
},
},
res: res{
@ -243,10 +273,13 @@ func TestCommandSide_ChangeDefaultPrivacyPolicy(t *testing.T) {
args: args{
ctx: context.Background(),
policy: &domain.PrivacyPolicy{
TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink",
HelpLink: "HelpLink",
SupportEmail: "wrong email",
TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink",
HelpLink: "HelpLink",
SupportEmail: "wrong email",
DocsLink: "DocsLink",
CustomLink: "CustomLink",
CustomLinkText: "CustomLinkText",
},
},
res: res{
@ -266,6 +299,9 @@ func TestCommandSide_ChangeDefaultPrivacyPolicy(t *testing.T) {
"PrivacyLink",
"HelpLink",
"support@example.com",
"DocsLink",
"CustomLink",
"CustomLinkText",
),
),
),
@ -275,6 +311,9 @@ func TestCommandSide_ChangeDefaultPrivacyPolicy(t *testing.T) {
"PrivacyLinkChanged",
"HelpLinkChanged",
"support2@example.com",
"DocsLinkChanged",
"CustomLinkChanged",
"CustomLinkTextChanged",
),
),
),
@ -282,10 +321,13 @@ func TestCommandSide_ChangeDefaultPrivacyPolicy(t *testing.T) {
args: args{
ctx: context.Background(),
policy: &domain.PrivacyPolicy{
TOSLink: "TOSLinkChanged",
PrivacyLink: "PrivacyLinkChanged",
HelpLink: "HelpLinkChanged",
SupportEmail: "support2@example.com",
TOSLink: "TOSLinkChanged",
PrivacyLink: "PrivacyLinkChanged",
HelpLink: "HelpLinkChanged",
SupportEmail: "support2@example.com",
DocsLink: "DocsLinkChanged",
CustomLink: "CustomLinkChanged",
CustomLinkText: "CustomLinkTextChanged",
},
},
res: res{
@ -295,10 +337,13 @@ func TestCommandSide_ChangeDefaultPrivacyPolicy(t *testing.T) {
ResourceOwner: "INSTANCE",
InstanceID: "INSTANCE",
},
TOSLink: "TOSLinkChanged",
PrivacyLink: "PrivacyLinkChanged",
HelpLink: "HelpLinkChanged",
SupportEmail: "support2@example.com",
TOSLink: "TOSLinkChanged",
PrivacyLink: "PrivacyLinkChanged",
HelpLink: "HelpLinkChanged",
SupportEmail: "support2@example.com",
DocsLink: "DocsLinkChanged",
CustomLink: "CustomLinkChanged",
CustomLinkText: "CustomLinkTextChanged",
},
},
},
@ -322,7 +367,7 @@ func TestCommandSide_ChangeDefaultPrivacyPolicy(t *testing.T) {
}
}
func newDefaultPrivacyPolicyChangedEvent(ctx context.Context, tosLink, privacyLink, helpLink, supportEmail string) *instance.PrivacyPolicyChangedEvent {
func newDefaultPrivacyPolicyChangedEvent(ctx context.Context, tosLink, privacyLink, helpLink, supportEmail, docsLink, customLink, customLinkText string) *instance.PrivacyPolicyChangedEvent {
event, _ := instance.NewPrivacyPolicyChangedEvent(ctx,
&instance.NewAggregate("INSTANCE").Aggregate,
[]policy.PrivacyPolicyChanges{
@ -330,6 +375,9 @@ func newDefaultPrivacyPolicyChangedEvent(ctx context.Context, tosLink, privacyLi
policy.ChangePrivacyLink(privacyLink),
policy.ChangeHelpLink(helpLink),
policy.ChangeSupportEmail(domain.EmailAddress(supportEmail)),
policy.ChangeDocsLink(docsLink),
policy.ChangeCustomLink(customLink),
policy.ChangeCustomLinkText(customLinkText),
},
)
return event

View File

@ -46,10 +46,13 @@ func orgDomainWriteModelToOrgDomain(wm *OrgDomainWriteModel) *domain.OrgDomain {
func orgWriteModelToPrivacyPolicy(wm *OrgPrivacyPolicyWriteModel) *domain.PrivacyPolicy {
return &domain.PrivacyPolicy{
ObjectRoot: writeModelToObjectRoot(wm.PrivacyPolicyWriteModel.WriteModel),
TOSLink: wm.TOSLink,
PrivacyLink: wm.PrivacyLink,
HelpLink: wm.HelpLink,
SupportEmail: wm.SupportEmail,
ObjectRoot: writeModelToObjectRoot(wm.PrivacyPolicyWriteModel.WriteModel),
TOSLink: wm.TOSLink,
PrivacyLink: wm.PrivacyLink,
HelpLink: wm.HelpLink,
SupportEmail: wm.SupportEmail,
DocsLink: wm.DocsLink,
CustomLink: wm.CustomLink,
CustomLinkText: wm.CustomLinkText,
}
}

View File

@ -58,7 +58,10 @@ func (c *Commands) AddPrivacyPolicy(ctx context.Context, resourceOwner string, p
policy.TOSLink,
policy.PrivacyLink,
policy.HelpLink,
policy.SupportEmail))
policy.SupportEmail,
policy.DocsLink,
policy.CustomLink,
policy.CustomLinkText))
if err != nil {
return nil, err
}
@ -91,7 +94,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, policy.HelpLink, policy.SupportEmail)
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, orgAgg, policy.TOSLink, policy.PrivacyLink, policy.HelpLink, policy.SupportEmail, policy.DocsLink, policy.CustomLink, policy.CustomLinkText)
if !hasChanged {
return nil, zerrors.ThrowPreconditionFailed(nil, "Org-4N9fs", "Errors.Org.PrivacyPolicy.NotChanged")
}

View File

@ -60,6 +60,7 @@ func (wm *OrgPrivacyPolicyWriteModel) NewChangedEvent(
privacyLink,
helpLink string,
supportEmail domain.EmailAddress,
docsLink, customLink, customLinkText string,
) (*org.PrivacyPolicyChangedEvent, bool) {
changes := make([]policy.PrivacyPolicyChanges, 0)
@ -75,6 +76,15 @@ func (wm *OrgPrivacyPolicyWriteModel) NewChangedEvent(
if wm.SupportEmail != supportEmail {
changes = append(changes, policy.ChangeSupportEmail(supportEmail))
}
if wm.DocsLink != docsLink {
changes = append(changes, policy.ChangeDocsLink(docsLink))
}
if wm.CustomLink != customLink {
changes = append(changes, policy.ChangeCustomLink(customLink))
}
if wm.CustomLinkText != customLinkText {
changes = append(changes, policy.ChangeCustomLinkText(customLinkText))
}
if len(changes) == 0 {
return nil, false
}

View File

@ -43,10 +43,13 @@ func TestCommandSide_AddPrivacyPolicy(t *testing.T) {
args: args{
ctx: context.Background(),
policy: &domain.PrivacyPolicy{
TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink",
HelpLink: "HelpLink",
SupportEmail: "support@example.com",
TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink",
HelpLink: "HelpLink",
SupportEmail: "support@example.com",
DocsLink: "DocsLink",
CustomLink: "CustomLink",
CustomLinkText: "CustomLinkText",
},
},
res: res{
@ -66,7 +69,9 @@ func TestCommandSide_AddPrivacyPolicy(t *testing.T) {
"PrivacyLink",
"HelpLink",
"support@example.com",
),
"DocsLink",
"CustomLink",
"CustomLinkText"),
),
),
),
@ -75,10 +80,13 @@ func TestCommandSide_AddPrivacyPolicy(t *testing.T) {
ctx: context.Background(),
orgID: "org1",
policy: &domain.PrivacyPolicy{
TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink",
HelpLink: "HelpLink",
SupportEmail: "support@example.com",
TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink",
HelpLink: "HelpLink",
SupportEmail: "support@example.com",
DocsLink: "DocsLink",
CustomLink: "CustomLink",
CustomLinkText: "CustomLinkText",
},
},
res: res{
@ -98,6 +106,9 @@ func TestCommandSide_AddPrivacyPolicy(t *testing.T) {
"PrivacyLink",
"HelpLink",
"support@example.com",
"DocsLink",
"CustomLink",
"CustomLinkText",
),
),
),
@ -106,10 +117,13 @@ func TestCommandSide_AddPrivacyPolicy(t *testing.T) {
ctx: context.Background(),
orgID: "org1",
policy: &domain.PrivacyPolicy{
TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink",
HelpLink: "HelpLink",
SupportEmail: "support@example.com",
TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink",
HelpLink: "HelpLink",
SupportEmail: "support@example.com",
DocsLink: "DocsLink",
CustomLink: "CustomLink",
CustomLinkText: "CustomLinkText",
},
},
res: res{
@ -118,10 +132,13 @@ func TestCommandSide_AddPrivacyPolicy(t *testing.T) {
AggregateID: "org1",
ResourceOwner: "org1",
},
TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink",
HelpLink: "HelpLink",
SupportEmail: "support@example.com",
TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink",
HelpLink: "HelpLink",
SupportEmail: "support@example.com",
DocsLink: "DocsLink",
CustomLink: "CustomLink",
CustomLinkText: "CustomLinkText",
},
},
},
@ -136,10 +153,13 @@ func TestCommandSide_AddPrivacyPolicy(t *testing.T) {
ctx: context.Background(),
orgID: "org1",
policy: &domain.PrivacyPolicy{
TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink",
HelpLink: "HelpLink",
SupportEmail: "wrong email",
TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink",
HelpLink: "HelpLink",
SupportEmail: "wrong email",
DocsLink: "DocsLink",
CustomLink: "CustomLink",
CustomLinkText: "CustomLinkText",
},
},
res: res{
@ -159,6 +179,9 @@ func TestCommandSide_AddPrivacyPolicy(t *testing.T) {
"",
"",
"",
"",
"",
"",
),
),
),
@ -167,10 +190,13 @@ func TestCommandSide_AddPrivacyPolicy(t *testing.T) {
ctx: context.Background(),
orgID: "org1",
policy: &domain.PrivacyPolicy{
TOSLink: "",
PrivacyLink: "",
HelpLink: "",
SupportEmail: "",
TOSLink: "",
PrivacyLink: "",
HelpLink: "",
SupportEmail: "",
DocsLink: "",
CustomLink: "",
CustomLinkText: "",
},
},
res: res{
@ -179,10 +205,13 @@ func TestCommandSide_AddPrivacyPolicy(t *testing.T) {
AggregateID: "org1",
ResourceOwner: "org1",
},
TOSLink: "",
PrivacyLink: "",
HelpLink: "",
SupportEmail: "",
TOSLink: "",
PrivacyLink: "",
HelpLink: "",
SupportEmail: "",
DocsLink: "",
CustomLink: "",
CustomLinkText: "",
},
},
},
@ -235,10 +264,13 @@ func TestCommandSide_ChangePrivacyPolicy(t *testing.T) {
args: args{
ctx: context.Background(),
policy: &domain.PrivacyPolicy{
TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink",
HelpLink: "HelpLink",
SupportEmail: "support@example.com",
TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink",
HelpLink: "HelpLink",
SupportEmail: "support@example.com",
DocsLink: "DocsLink",
CustomLink: "CustomLink",
CustomLinkText: "CustomLinkText",
},
},
res: res{
@ -257,10 +289,13 @@ func TestCommandSide_ChangePrivacyPolicy(t *testing.T) {
ctx: context.Background(),
orgID: "org1",
policy: &domain.PrivacyPolicy{
TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink",
HelpLink: "HelpLink",
SupportEmail: "support@example.com",
TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink",
HelpLink: "HelpLink",
SupportEmail: "support@example.com",
DocsLink: "DocsLink",
CustomLink: "CustomLink",
CustomLinkText: "CustomLinkText",
},
},
res: res{
@ -280,6 +315,9 @@ func TestCommandSide_ChangePrivacyPolicy(t *testing.T) {
"PrivacyLink",
"HelpLink",
"support@example.com",
"DocsLink",
"CustomLink",
"CustomLinkText",
),
),
),
@ -289,10 +327,13 @@ func TestCommandSide_ChangePrivacyPolicy(t *testing.T) {
ctx: context.Background(),
orgID: "org1",
policy: &domain.PrivacyPolicy{
TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink",
HelpLink: "HelpLink",
SupportEmail: "support@example.com",
TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink",
HelpLink: "HelpLink",
SupportEmail: "support@example.com",
DocsLink: "DocsLink",
CustomLink: "CustomLink",
CustomLinkText: "CustomLinkText",
},
},
res: res{
@ -305,10 +346,13 @@ func TestCommandSide_ChangePrivacyPolicy(t *testing.T) {
ctx: context.Background(),
orgID: "org1",
policy: &domain.PrivacyPolicy{
TOSLink: "TOSLinkChange",
PrivacyLink: "PrivacyLinkChange",
HelpLink: "HelpLinkChange",
SupportEmail: "wrong email",
TOSLink: "TOSLinkChange",
PrivacyLink: "PrivacyLinkChange",
HelpLink: "HelpLinkChange",
SupportEmail: "wrong email",
DocsLink: "DocsLink",
CustomLink: "CustomLink",
CustomLinkText: "CustomLinkText",
},
},
res: res{
@ -328,11 +372,14 @@ func TestCommandSide_ChangePrivacyPolicy(t *testing.T) {
"PrivacyLink",
"HelpLink",
"support@example.com",
"DocsLink",
"CustomLink",
"CustomLinkText",
),
),
),
expectPush(
newPrivacyPolicyChangedEvent(context.Background(), "org1", "TOSLinkChange", "PrivacyLinkChange", "HelpLinkChange", "support2@example.com"),
newPrivacyPolicyChangedEvent(context.Background(), "org1", "TOSLinkChange", "PrivacyLinkChange", "HelpLinkChange", "support2@example.com", "DocsLinkChange", "CustomLinkChange", "CustomLinkTextChange"),
),
),
},
@ -340,10 +387,13 @@ func TestCommandSide_ChangePrivacyPolicy(t *testing.T) {
ctx: context.Background(),
orgID: "org1",
policy: &domain.PrivacyPolicy{
TOSLink: "TOSLinkChange",
PrivacyLink: "PrivacyLinkChange",
HelpLink: "HelpLinkChange",
SupportEmail: "support2@example.com",
TOSLink: "TOSLinkChange",
PrivacyLink: "PrivacyLinkChange",
HelpLink: "HelpLinkChange",
SupportEmail: "support2@example.com",
DocsLink: "DocsLinkChange",
CustomLink: "CustomLinkChange",
CustomLinkText: "CustomLinkTextChange",
},
},
res: res{
@ -352,10 +402,13 @@ func TestCommandSide_ChangePrivacyPolicy(t *testing.T) {
AggregateID: "org1",
ResourceOwner: "org1",
},
TOSLink: "TOSLinkChange",
PrivacyLink: "PrivacyLinkChange",
HelpLink: "HelpLinkChange",
SupportEmail: "support2@example.com",
TOSLink: "TOSLinkChange",
PrivacyLink: "PrivacyLinkChange",
HelpLink: "HelpLinkChange",
SupportEmail: "support2@example.com",
DocsLink: "DocsLinkChange",
CustomLink: "CustomLinkChange",
CustomLinkText: "CustomLinkTextChange",
},
},
},
@ -372,11 +425,14 @@ func TestCommandSide_ChangePrivacyPolicy(t *testing.T) {
"PrivacyLink",
"HelpLink",
"support@example.com",
"DocsLink",
"CustomLink",
"CustomLinkText",
),
),
),
expectPush(
newPrivacyPolicyChangedEvent(context.Background(), "org1", "", "", "", ""),
newPrivacyPolicyChangedEvent(context.Background(), "org1", "", "", "", "", "", "", ""),
),
),
},
@ -384,10 +440,13 @@ func TestCommandSide_ChangePrivacyPolicy(t *testing.T) {
ctx: context.Background(),
orgID: "org1",
policy: &domain.PrivacyPolicy{
TOSLink: "",
PrivacyLink: "",
HelpLink: "",
SupportEmail: "",
TOSLink: "",
PrivacyLink: "",
HelpLink: "",
SupportEmail: "",
DocsLink: "",
CustomLink: "",
CustomLinkText: "",
},
},
res: res{
@ -396,10 +455,13 @@ func TestCommandSide_ChangePrivacyPolicy(t *testing.T) {
AggregateID: "org1",
ResourceOwner: "org1",
},
TOSLink: "",
PrivacyLink: "",
HelpLink: "",
SupportEmail: "",
TOSLink: "",
PrivacyLink: "",
HelpLink: "",
SupportEmail: "",
DocsLink: "",
CustomLink: "",
CustomLinkText: "",
},
},
},
@ -484,6 +546,9 @@ func TestCommandSide_RemovePrivacyPolicy(t *testing.T) {
"PrivacyLink",
"HelpLink",
"support@example.com",
"DocsLink",
"CustomLink",
"CustomLinkText",
),
),
),
@ -523,7 +588,7 @@ func TestCommandSide_RemovePrivacyPolicy(t *testing.T) {
}
}
func newPrivacyPolicyChangedEvent(ctx context.Context, orgID string, tosLink, privacyLink, helpLink, supportEmail string) *org.PrivacyPolicyChangedEvent {
func newPrivacyPolicyChangedEvent(ctx context.Context, orgID string, tosLink, privacyLink, helpLink, supportEmail, docsLink, customLink, customLinkText string) *org.PrivacyPolicyChangedEvent {
event, _ := org.NewPrivacyPolicyChangedEvent(ctx,
&org.NewAggregate(orgID).Aggregate,
[]policy.PrivacyPolicyChanges{
@ -531,6 +596,9 @@ func newPrivacyPolicyChangedEvent(ctx context.Context, orgID string, tosLink, pr
policy.ChangePrivacyLink(privacyLink),
policy.ChangeHelpLink(helpLink),
policy.ChangeSupportEmail(domain.EmailAddress(supportEmail)),
policy.ChangeDocsLink(docsLink),
policy.ChangeCustomLink(customLink),
policy.ChangeCustomLinkText(customLinkText),
},
)
return event

View File

@ -9,11 +9,14 @@ import (
type PrivacyPolicyWriteModel struct {
eventstore.WriteModel
TOSLink string
PrivacyLink string
HelpLink string
SupportEmail domain.EmailAddress
State domain.PolicyState
TOSLink string
PrivacyLink string
HelpLink string
SupportEmail domain.EmailAddress
State domain.PolicyState
DocsLink string
CustomLink string
CustomLinkText string
}
func (wm *PrivacyPolicyWriteModel) Reduce() error {
@ -25,6 +28,9 @@ func (wm *PrivacyPolicyWriteModel) Reduce() error {
wm.HelpLink = e.HelpLink
wm.SupportEmail = e.SupportEmail
wm.State = domain.PolicyStateActive
wm.DocsLink = e.DocsLink
wm.CustomLink = e.CustomLink
wm.CustomLinkText = e.CustomLinkText
case *policy.PrivacyPolicyChangedEvent:
if e.PrivacyLink != nil {
wm.PrivacyLink = *e.PrivacyLink
@ -38,6 +44,15 @@ func (wm *PrivacyPolicyWriteModel) Reduce() error {
if e.SupportEmail != nil {
wm.SupportEmail = *e.SupportEmail
}
if e.DocsLink != nil {
wm.DocsLink = *e.DocsLink
}
if e.CustomLink != nil {
wm.CustomLink = *e.CustomLink
}
if e.CustomLinkText != nil {
wm.CustomLinkText = *e.CustomLinkText
}
case *policy.PrivacyPolicyRemovedEvent:
wm.State = domain.PolicyStateRemoved
}

View File

@ -10,8 +10,11 @@ type PrivacyPolicy struct {
State PolicyState
Default bool
TOSLink string
PrivacyLink string
HelpLink string
SupportEmail EmailAddress
TOSLink string
PrivacyLink string
HelpLink string
SupportEmail EmailAddress
DocsLink string
CustomLink string
CustomLinkText string
}

View File

@ -26,10 +26,13 @@ type PrivacyPolicy struct {
ResourceOwner string
State domain.PolicyState
TOSLink string
PrivacyLink string
HelpLink string
SupportEmail domain.EmailAddress
TOSLink string
PrivacyLink string
HelpLink string
SupportEmail domain.EmailAddress
DocsLink string
CustomLink string
CustomLinkText string
IsDefault bool
}
@ -91,6 +94,18 @@ var (
name: projection.PrivacyPolicyOwnerRemovedCol,
table: privacyTable,
}
PrivacyColDocsLink = Column{
name: projection.PrivacyPolicyDocsLinkCol,
table: privacyTable,
}
PrivacyColCustomLink = Column{
name: projection.PrivacyPolicyCustomLinkCol,
table: privacyTable,
}
PrivacyColCustomLinkText = Column{
name: projection.PrivacyPolicyCustomLinkTextCol,
table: privacyTable,
}
)
func (q *Queries) PrivacyPolicyByOrg(ctx context.Context, shouldTriggerBulk bool, orgID string, withOwnerRemoved bool) (policy *PrivacyPolicy, err error) {
@ -168,6 +183,9 @@ func preparePrivacyPolicyQuery(ctx context.Context, db prepareDatabase) (sq.Sele
PrivacyColTOSLink.identifier(),
PrivacyColHelpLink.identifier(),
PrivacyColSupportEmail.identifier(),
PrivacyColDocsLink.identifier(),
PrivacyColCustomLink.identifier(),
PrivacyColCustomLinkText.identifier(),
PrivacyColIsDefault.identifier(),
PrivacyColState.identifier(),
).
@ -185,6 +203,9 @@ func preparePrivacyPolicyQuery(ctx context.Context, db prepareDatabase) (sq.Sele
&policy.TOSLink,
&policy.HelpLink,
&policy.SupportEmail,
&policy.DocsLink,
&policy.CustomLink,
&policy.CustomLinkText,
&policy.IsDefault,
&policy.State,
)
@ -200,10 +221,13 @@ func preparePrivacyPolicyQuery(ctx context.Context, db prepareDatabase) (sq.Sele
func (p *PrivacyPolicy) ToDomain() *domain.PrivacyPolicy {
return &domain.PrivacyPolicy{
TOSLink: p.TOSLink,
PrivacyLink: p.PrivacyLink,
HelpLink: p.HelpLink,
SupportEmail: p.SupportEmail,
Default: p.IsDefault,
TOSLink: p.TOSLink,
PrivacyLink: p.PrivacyLink,
HelpLink: p.HelpLink,
SupportEmail: p.SupportEmail,
Default: p.IsDefault,
DocsLink: p.DocsLink,
CustomLink: p.CustomLink,
CustomLinkText: p.CustomLinkText,
}
}

View File

@ -13,18 +13,21 @@ import (
)
var (
preparePrivacyPolicyStmt = `SELECT projections.privacy_policies3.id,` +
` projections.privacy_policies3.sequence,` +
` projections.privacy_policies3.creation_date,` +
` projections.privacy_policies3.change_date,` +
` projections.privacy_policies3.resource_owner,` +
` projections.privacy_policies3.privacy_link,` +
` projections.privacy_policies3.tos_link,` +
` projections.privacy_policies3.help_link,` +
` projections.privacy_policies3.support_email,` +
` projections.privacy_policies3.is_default,` +
` projections.privacy_policies3.state` +
` FROM projections.privacy_policies3` +
preparePrivacyPolicyStmt = `SELECT projections.privacy_policies4.id,` +
` projections.privacy_policies4.sequence,` +
` projections.privacy_policies4.creation_date,` +
` projections.privacy_policies4.change_date,` +
` projections.privacy_policies4.resource_owner,` +
` projections.privacy_policies4.privacy_link,` +
` projections.privacy_policies4.tos_link,` +
` projections.privacy_policies4.help_link,` +
` projections.privacy_policies4.support_email,` +
` projections.privacy_policies4.docs_link,` +
` projections.privacy_policies4.custom_link,` +
` projections.privacy_policies4.custom_link_text,` +
` projections.privacy_policies4.is_default,` +
` projections.privacy_policies4.state` +
` FROM projections.privacy_policies4` +
` AS OF SYSTEM TIME '-1 ms'`
preparePrivacyPolicyCols = []string{
"id",
@ -36,6 +39,9 @@ var (
"tos_link",
"help_link",
"support_email",
"docs_link",
"custom_link",
"custom_link_text",
"is_default",
"state",
}
@ -87,23 +93,29 @@ func Test_PrivacyPolicyPrepares(t *testing.T) {
"tos.ch",
"help.ch",
"support@example.com",
"zitadel.com/docs",
"zitadel.com",
"Zitadel",
true,
domain.PolicyStateActive,
},
),
},
object: &PrivacyPolicy{
ID: "pol-id",
CreationDate: testNow,
ChangeDate: testNow,
Sequence: 20211109,
ResourceOwner: "ro",
State: domain.PolicyStateActive,
PrivacyLink: "privacy.ch",
TOSLink: "tos.ch",
HelpLink: "help.ch",
SupportEmail: "support@example.com",
IsDefault: true,
ID: "pol-id",
CreationDate: testNow,
ChangeDate: testNow,
Sequence: 20211109,
ResourceOwner: "ro",
State: domain.PolicyStateActive,
PrivacyLink: "privacy.ch",
TOSLink: "tos.ch",
HelpLink: "help.ch",
SupportEmail: "support@example.com",
DocsLink: "zitadel.com/docs",
CustomLink: "zitadel.com",
CustomLinkText: "Zitadel",
IsDefault: true,
},
},
{

View File

@ -14,21 +14,24 @@ import (
)
const (
PrivacyPolicyTable = "projections.privacy_policies3"
PrivacyPolicyTable = "projections.privacy_policies4"
PrivacyPolicyIDCol = "id"
PrivacyPolicyCreationDateCol = "creation_date"
PrivacyPolicyChangeDateCol = "change_date"
PrivacyPolicySequenceCol = "sequence"
PrivacyPolicyStateCol = "state"
PrivacyPolicyIsDefaultCol = "is_default"
PrivacyPolicyResourceOwnerCol = "resource_owner"
PrivacyPolicyInstanceIDCol = "instance_id"
PrivacyPolicyPrivacyLinkCol = "privacy_link"
PrivacyPolicyTOSLinkCol = "tos_link"
PrivacyPolicyHelpLinkCol = "help_link"
PrivacyPolicySupportEmailCol = "support_email"
PrivacyPolicyOwnerRemovedCol = "owner_removed"
PrivacyPolicyIDCol = "id"
PrivacyPolicyCreationDateCol = "creation_date"
PrivacyPolicyChangeDateCol = "change_date"
PrivacyPolicySequenceCol = "sequence"
PrivacyPolicyStateCol = "state"
PrivacyPolicyIsDefaultCol = "is_default"
PrivacyPolicyResourceOwnerCol = "resource_owner"
PrivacyPolicyInstanceIDCol = "instance_id"
PrivacyPolicyPrivacyLinkCol = "privacy_link"
PrivacyPolicyTOSLinkCol = "tos_link"
PrivacyPolicyHelpLinkCol = "help_link"
PrivacyPolicySupportEmailCol = "support_email"
PrivacyPolicyDocsLinkCol = "docs_link"
PrivacyPolicyCustomLinkCol = "custom_link"
PrivacyPolicyCustomLinkTextCol = "custom_link_text"
PrivacyPolicyOwnerRemovedCol = "owner_removed"
)
type privacyPolicyProjection struct{}
@ -56,6 +59,9 @@ func (*privacyPolicyProjection) Init() *old_handler.Check {
handler.NewColumn(PrivacyPolicyTOSLinkCol, handler.ColumnTypeText),
handler.NewColumn(PrivacyPolicyHelpLinkCol, handler.ColumnTypeText),
handler.NewColumn(PrivacyPolicySupportEmailCol, handler.ColumnTypeText),
handler.NewColumn(PrivacyPolicyDocsLinkCol, handler.ColumnTypeText, handler.Default("https://zitadel.com/docs")),
handler.NewColumn(PrivacyPolicyCustomLinkCol, handler.ColumnTypeText),
handler.NewColumn(PrivacyPolicyCustomLinkTextCol, handler.ColumnTypeText),
handler.NewColumn(PrivacyPolicyOwnerRemovedCol, handler.ColumnTypeBool, handler.Default(false)),
},
handler.NewPrimaryKey(PrivacyPolicyInstanceIDCol, PrivacyPolicyIDCol),
@ -132,6 +138,9 @@ func (p *privacyPolicyProjection) reduceAdded(event eventstore.Event) (*handler.
handler.NewCol(PrivacyPolicyTOSLinkCol, policyEvent.TOSLink),
handler.NewCol(PrivacyPolicyHelpLinkCol, policyEvent.HelpLink),
handler.NewCol(PrivacyPolicySupportEmailCol, policyEvent.SupportEmail),
handler.NewCol(PrivacyPolicyDocsLinkCol, policyEvent.DocsLink),
handler.NewCol(PrivacyPolicyCustomLinkCol, policyEvent.CustomLink),
handler.NewCol(PrivacyPolicyCustomLinkTextCol, policyEvent.CustomLinkText),
handler.NewCol(PrivacyPolicyIsDefaultCol, isDefault),
handler.NewCol(PrivacyPolicyResourceOwnerCol, policyEvent.Aggregate().ResourceOwner),
handler.NewCol(PrivacyPolicyInstanceIDCol, policyEvent.Aggregate().InstanceID),
@ -164,6 +173,15 @@ func (p *privacyPolicyProjection) reduceChanged(event eventstore.Event) (*handle
if policyEvent.SupportEmail != nil {
cols = append(cols, handler.NewCol(PrivacyPolicySupportEmailCol, *policyEvent.SupportEmail))
}
if policyEvent.DocsLink != nil {
cols = append(cols, handler.NewCol(PrivacyPolicyDocsLinkCol, *policyEvent.DocsLink))
}
if policyEvent.CustomLink != nil {
cols = append(cols, handler.NewCol(PrivacyPolicyCustomLinkCol, *policyEvent.CustomLink))
}
if policyEvent.CustomLinkText != nil {
cols = append(cols, handler.NewCol(PrivacyPolicyCustomLinkTextCol, *policyEvent.CustomLinkText))
}
return handler.NewUpdateStatement(
&policyEvent,
cols,

View File

@ -32,6 +32,9 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) {
"tosLink": "http://tos.link",
"privacyLink": "http://privacy.link",
"helpLink": "http://help.link",
"docsLink": "http://docs.link",
"customLink": "http://custom.link",
"customLinkText": "Custom Link",
"supportEmail": "support@example.com"}`),
), org.PrivacyPolicyAddedEventMapper),
},
@ -42,7 +45,7 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "INSERT INTO projections.privacy_policies3 (creation_date, change_date, sequence, id, state, privacy_link, tos_link, help_link, support_email, is_default, resource_owner, instance_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)",
expectedStmt: "INSERT INTO projections.privacy_policies4 (creation_date, change_date, sequence, id, state, privacy_link, tos_link, help_link, support_email, docs_link, custom_link, custom_link_text, is_default, resource_owner, instance_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)",
expectedArgs: []interface{}{
anyArg{},
anyArg{},
@ -53,6 +56,9 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) {
"http://tos.link",
"http://help.link",
domain.EmailAddress("support@example.com"),
"http://docs.link",
"http://custom.link",
"Custom Link",
false,
"ro-id",
"instance-id",
@ -74,6 +80,9 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) {
"tosLink": "http://tos.link",
"privacyLink": "http://privacy.link",
"helpLink": "http://help.link",
"docsLink": "http://docs.link",
"customLink": "http://custom.link",
"customLinkText": "Custom Link",
"supportEmail": "support@example.com"}`),
), org.PrivacyPolicyChangedEventMapper),
},
@ -83,7 +92,7 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.privacy_policies3 SET (change_date, sequence, privacy_link, tos_link, help_link, support_email) = ($1, $2, $3, $4, $5, $6) WHERE (id = $7) AND (instance_id = $8)",
expectedStmt: "UPDATE projections.privacy_policies4 SET (change_date, sequence, privacy_link, tos_link, help_link, support_email, docs_link, custom_link, custom_link_text) = ($1, $2, $3, $4, $5, $6, $7, $8, $9) WHERE (id = $10) AND (instance_id = $11)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@ -91,6 +100,9 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) {
"http://tos.link",
"http://help.link",
domain.EmailAddress("support@example.com"),
"http://docs.link",
"http://custom.link",
"Custom Link",
"agg-id",
"instance-id",
},
@ -116,7 +128,7 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "DELETE FROM projections.privacy_policies3 WHERE (id = $1) AND (instance_id = $2)",
expectedStmt: "DELETE FROM projections.privacy_policies4 WHERE (id = $1) AND (instance_id = $2)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@ -142,7 +154,7 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "DELETE FROM projections.privacy_policies3 WHERE (instance_id = $1)",
expectedStmt: "DELETE FROM projections.privacy_policies4 WHERE (instance_id = $1)",
expectedArgs: []interface{}{
"agg-id",
},
@ -163,6 +175,9 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) {
"tosLink": "http://tos.link",
"privacyLink": "http://privacy.link",
"helpLink": "http://help.link",
"docsLink": "http://docs.link",
"customLink": "http://custom.link",
"customLinkText": "Custom Link",
"supportEmail": "support@example.com"}`),
), instance.PrivacyPolicyAddedEventMapper),
},
@ -172,7 +187,7 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "INSERT INTO projections.privacy_policies3 (creation_date, change_date, sequence, id, state, privacy_link, tos_link, help_link, support_email, is_default, resource_owner, instance_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)",
expectedStmt: "INSERT INTO projections.privacy_policies4 (creation_date, change_date, sequence, id, state, privacy_link, tos_link, help_link, support_email, docs_link, custom_link, custom_link_text, is_default, resource_owner, instance_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)",
expectedArgs: []interface{}{
anyArg{},
anyArg{},
@ -183,6 +198,9 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) {
"http://tos.link",
"http://help.link",
domain.EmailAddress("support@example.com"),
"http://docs.link",
"http://custom.link",
"Custom Link",
true,
"ro-id",
"instance-id",
@ -204,6 +222,9 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) {
"tosLink": "http://tos.link",
"privacyLink": "http://privacy.link",
"helpLink": "http://help.link",
"docsLink": "http://docs.link",
"customLink": "http://custom.link",
"customLinkText": "Custom Link",
"supportEmail": "support@example.com"}`),
), instance.PrivacyPolicyChangedEventMapper),
},
@ -213,7 +234,7 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.privacy_policies3 SET (change_date, sequence, privacy_link, tos_link, help_link, support_email) = ($1, $2, $3, $4, $5, $6) WHERE (id = $7) AND (instance_id = $8)",
expectedStmt: "UPDATE projections.privacy_policies4 SET (change_date, sequence, privacy_link, tos_link, help_link, support_email, docs_link, custom_link, custom_link_text) = ($1, $2, $3, $4, $5, $6, $7, $8, $9) WHERE (id = $10) AND (instance_id = $11)",
expectedArgs: []interface{}{
anyArg{},
uint64(15),
@ -221,6 +242,9 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) {
"http://tos.link",
"http://help.link",
domain.EmailAddress("support@example.com"),
"http://docs.link",
"http://custom.link",
"Custom Link",
"agg-id",
"instance-id",
},
@ -246,7 +270,7 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "DELETE FROM projections.privacy_policies3 WHERE (instance_id = $1) AND (resource_owner = $2)",
expectedStmt: "DELETE FROM projections.privacy_policies4 WHERE (instance_id = $1) AND (resource_owner = $2)",
expectedArgs: []interface{}{
"instance-id",
"agg-id",

View File

@ -24,6 +24,7 @@ func NewPrivacyPolicyAddedEvent(
privacyLink,
helpLink string,
supportEmail domain.EmailAddress,
docsLink, customLink, customLinkText string,
) *PrivacyPolicyAddedEvent {
return &PrivacyPolicyAddedEvent{
PrivacyPolicyAddedEvent: *policy.NewPrivacyPolicyAddedEvent(
@ -34,7 +35,10 @@ func NewPrivacyPolicyAddedEvent(
tosLink,
privacyLink,
helpLink,
supportEmail),
supportEmail,
docsLink,
customLink,
customLinkText),
}
}

View File

@ -25,6 +25,7 @@ func NewPrivacyPolicyAddedEvent(
privacyLink,
helpLink string,
supportEmail domain.EmailAddress,
docsLink, customLink, customLinkText string,
) *PrivacyPolicyAddedEvent {
return &PrivacyPolicyAddedEvent{
PrivacyPolicyAddedEvent: *policy.NewPrivacyPolicyAddedEvent(
@ -35,7 +36,10 @@ func NewPrivacyPolicyAddedEvent(
tosLink,
privacyLink,
helpLink,
supportEmail),
supportEmail,
docsLink,
customLink,
customLinkText),
}
}

View File

@ -15,10 +15,13 @@ const (
type PrivacyPolicyAddedEvent struct {
eventstore.BaseEvent `json:"-"`
TOSLink string `json:"tosLink,omitempty"`
PrivacyLink string `json:"privacyLink,omitempty"`
HelpLink string `json:"helpLink,omitempty"`
SupportEmail domain.EmailAddress `json:"supportEmail,omitempty"`
TOSLink string `json:"tosLink,omitempty"`
PrivacyLink string `json:"privacyLink,omitempty"`
HelpLink string `json:"helpLink,omitempty"`
SupportEmail domain.EmailAddress `json:"supportEmail,omitempty"`
DocsLink string `json:"docsLink,omitempty"`
CustomLink string `json:"customLink,omitempty"`
CustomLinkText string `json:"customLinkText,omitempty"`
}
func (e *PrivacyPolicyAddedEvent) Payload() interface{} {
@ -35,13 +38,17 @@ func NewPrivacyPolicyAddedEvent(
privacyLink,
helpLink string,
supportEmail domain.EmailAddress,
docsLink, customLink, customLinkText string,
) *PrivacyPolicyAddedEvent {
return &PrivacyPolicyAddedEvent{
BaseEvent: *base,
TOSLink: tosLink,
PrivacyLink: privacyLink,
HelpLink: helpLink,
SupportEmail: supportEmail,
BaseEvent: *base,
TOSLink: tosLink,
PrivacyLink: privacyLink,
HelpLink: helpLink,
SupportEmail: supportEmail,
DocsLink: docsLink,
CustomLink: customLink,
CustomLinkText: customLinkText,
}
}
@ -60,10 +67,13 @@ func PrivacyPolicyAddedEventMapper(event eventstore.Event) (eventstore.Event, er
type PrivacyPolicyChangedEvent struct {
eventstore.BaseEvent `json:"-"`
TOSLink *string `json:"tosLink,omitempty"`
PrivacyLink *string `json:"privacyLink,omitempty"`
HelpLink *string `json:"helpLink,omitempty"`
SupportEmail *domain.EmailAddress `json:"supportEmail,omitempty"`
TOSLink *string `json:"tosLink,omitempty"`
PrivacyLink *string `json:"privacyLink,omitempty"`
HelpLink *string `json:"helpLink,omitempty"`
SupportEmail *domain.EmailAddress `json:"supportEmail,omitempty"`
DocsLink *string `json:"docsLink,omitempty"`
CustomLink *string `json:"customLink,omitempty"`
CustomLinkText *string `json:"customLinkText,omitempty"`
}
func (e *PrivacyPolicyChangedEvent) Payload() interface{} {
@ -116,6 +126,24 @@ func ChangeSupportEmail(supportEmail domain.EmailAddress) func(*PrivacyPolicyCha
}
}
func ChangeDocsLink(docsLink string) func(*PrivacyPolicyChangedEvent) {
return func(e *PrivacyPolicyChangedEvent) {
e.DocsLink = &docsLink
}
}
func ChangeCustomLink(customLink string) func(*PrivacyPolicyChangedEvent) {
return func(e *PrivacyPolicyChangedEvent) {
e.CustomLink = &customLink
}
}
func ChangeCustomLinkText(customLinkText string) func(*PrivacyPolicyChangedEvent) {
return func(e *PrivacyPolicyChangedEvent) {
e.CustomLinkText = &customLinkText
}
}
func PrivacyPolicyChangedEventMapper(event eventstore.Event) (eventstore.Event, error) {
e := &PrivacyPolicyChangedEvent{
BaseEvent: *eventstore.BaseEventFromRepo(event),

View File

@ -6817,6 +6817,23 @@ message UpdatePrivacyPolicyRequest {
description: "help / support email address."
}
];
string docs_link = 5 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"https://zitadel.com/docs\"";
}
];
string custom_link = 6 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "Link to an external resource that will be available to users in the console.";
example: "\"https://external.link\"";
}
];
string custom_link_text = 7 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "The button text that would be shown in console pointing to custom link.";
example: "\"External\"";
}
];
}
message UpdatePrivacyPolicyResponse {

View File

@ -10495,6 +10495,24 @@ message AddCustomPrivacyPolicyRequest {
description: "help / support email address."
}
];
string docs_link = 5 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "Link to documentation to be shown in the console.";
example: "\"https://zitadel.com/docs\"";
}
];
string custom_link = 6 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "Link to an external resource that will be available to users in the console.";
example: "\"https://external.link\"";
}
];
string custom_link_text = 7 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "The button text that would be shown in console pointing to custom link.";
example: "\"External\"";
}
];
}
message AddCustomPrivacyPolicyResponse {
@ -10527,6 +10545,24 @@ message UpdateCustomPrivacyPolicyRequest {
description: "help / support email address."
}
];
string docs_link = 5 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "Link to documentation to be shown in the console.";
example: "\"https://zitadel.com/docs\"";
}
];
string custom_link = 6 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "Link to an external resource that will be available to users in the console.";
example: "\"https://external.link\"";
}
];
string custom_link_text = 7 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "The button text that would be shown in console pointing to custom link.";
example: "\"External\"";
}
];
}
message UpdateCustomPrivacyPolicyResponse {

View File

@ -375,6 +375,25 @@ message PrivacyPolicy {
description: "help / support email address."
}
];
string docs_link = 7 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "Link to documentation to be shown in the console.";
example: "\"https://zitadel.com/docs\"";
}
];
string custom_link = 8 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "Link to an external resource that will be available to users in the console.";
example: "\"https://external.link\"";
}
];
string custom_link_text = 9 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "The button text that would be shown in console pointing to custom link.";
example: "\"External\"";
}
];
}
message NotificationPolicy {

View File

@ -37,4 +37,22 @@ message LegalAndSupportSettings {
description: "resource_owner_type returns if the setting is managed on the organization or on the instance";
}
];
string docs_link = 6 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "Link to documentation to be shown in the console.";
example: "\"https://zitadel.com/docs\"";
}
];
string custom_link = 7 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "Link to an external resource that will be available to users in the console.";
example: "\"https://external.link\"";
}
];
string custom_link_text = 8 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "The button text that would be shown in console pointing to custom link.";
example: "\"External\"";
}
];
}