mirror of
https://github.com/zitadel/zitadel.git
synced 2025-12-03 08:52:13 +00:00
fix: tos on external registration (#2164)
* faet: add tos checkbox to external login * fix: add tos to external not found option * fix: add tos to external not found option * fix: show register external user overview * fix: no init user mail on external register * fix: custom login text * add missing custom text tests on org * add missing custom text tests on iam * fix: custom login text external registration overview tests * fix: back button on registration overview * fix: add texts, change register form * fix: external not found html * fix: remove form validation Co-authored-by: Livio Amstutz <livio.a@gmail.com>
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/caos/oidc/pkg/client/rp"
|
||||
"github.com/caos/oidc/pkg/oidc"
|
||||
"golang.org/x/oauth2"
|
||||
@@ -11,9 +15,6 @@ import (
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
caos_errors "github.com/caos/zitadel/internal/errors"
|
||||
iam_model "github.com/caos/zitadel/internal/iam/model"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -34,6 +35,7 @@ type externalNotFoundOptionFormData struct {
|
||||
Link bool `schema:"link"`
|
||||
AutoRegister bool `schema:"autoregister"`
|
||||
ResetLinking bool `schema:"resetlinking"`
|
||||
TermsConfirm bool `schema:"terms-confirm"`
|
||||
}
|
||||
|
||||
type externalNotFoundOptionData struct {
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/caos/oidc/pkg/client/rp"
|
||||
"github.com/caos/oidc/pkg/oidc"
|
||||
"golang.org/x/text/language"
|
||||
|
||||
http_mw "github.com/caos/zitadel/internal/api/http/middleware"
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
@@ -13,6 +14,42 @@ import (
|
||||
iam_model "github.com/caos/zitadel/internal/iam/model"
|
||||
)
|
||||
|
||||
const (
|
||||
tmplExternalRegisterOverview = "externalregisteroverview"
|
||||
)
|
||||
|
||||
type externalRegisterFormData struct {
|
||||
ExternalIDPConfigID string `schema:"external-idp-config-id"`
|
||||
ExternalIDPExtUserID string `schema:"external-idp-ext-user-id"`
|
||||
ExternalIDPDisplayName string `schema:"external-idp-display-name"`
|
||||
ExternalEmail string `schema:"external-email"`
|
||||
ExternalEmailVerified bool `schema:"external-email-verified"`
|
||||
Email string `schema:"email"`
|
||||
Username string `schema:"username"`
|
||||
Firstname string `schema:"firstname"`
|
||||
Lastname string `schema:"lastname"`
|
||||
Nickname string `schema:"nickname"`
|
||||
ExternalPhone string `schema:"external-phone"`
|
||||
ExternalPhoneVerified bool `schema:"external-phone-verified"`
|
||||
Phone string `schema:"phone"`
|
||||
Language string `schema:"language"`
|
||||
TermsConfirm bool `schema:"terms-confirm"`
|
||||
}
|
||||
|
||||
type externalRegisterData struct {
|
||||
baseData
|
||||
externalRegisterFormData
|
||||
ExternalIDPID string
|
||||
ExternalIDPUserID string
|
||||
ExternalIDPUserDisplayName string
|
||||
ShowUsername bool
|
||||
OrgRegister bool
|
||||
ExternalEmail string
|
||||
ExternalEmailVerified bool
|
||||
ExternalPhone string
|
||||
ExternalPhoneVerified bool
|
||||
}
|
||||
|
||||
func (l *Login) handleExternalRegister(w http.ResponseWriter, r *http.Request) {
|
||||
data := new(externalIDPData)
|
||||
authReq, err := l.getAuthRequestAndParseData(r, data)
|
||||
@@ -76,18 +113,77 @@ func (l *Login) handleExternalUserRegister(w http.ResponseWriter, r *http.Reques
|
||||
return
|
||||
}
|
||||
resourceOwner := iam.GlobalOrgID
|
||||
memberRoles := []string{domain.RoleOrgProjectCreator}
|
||||
|
||||
if authReq.RequestedOrgID != "" && authReq.RequestedOrgID != iam.GlobalOrgID {
|
||||
memberRoles = nil
|
||||
resourceOwner = authReq.RequestedOrgID
|
||||
}
|
||||
orgIamPolicy, err := l.getOrgIamPolicy(r, resourceOwner)
|
||||
if err != nil {
|
||||
l.renderRegisterOption(w, r, authReq, err)
|
||||
return
|
||||
}
|
||||
user, externalIDP := l.mapTokenToLoginHumanAndExternalIDP(orgIamPolicy, tokens, idpConfig)
|
||||
l.renderExternalRegisterOverview(w, r, authReq, orgIamPolicy, user, externalIDP, nil)
|
||||
}
|
||||
|
||||
func (l *Login) renderExternalRegisterOverview(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, orgIAMPolicy *iam_model.OrgIAMPolicyView, human *domain.Human, idp *domain.ExternalIDP, err error) {
|
||||
var errID, errMessage string
|
||||
if err != nil {
|
||||
errID, errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
data := externalRegisterData{
|
||||
baseData: l.getBaseData(r, authReq, "ExternalRegisterOverview", errID, errMessage),
|
||||
externalRegisterFormData: externalRegisterFormData{
|
||||
Email: human.EmailAddress,
|
||||
Username: human.PreferredLoginName,
|
||||
Firstname: human.FirstName,
|
||||
Lastname: human.LastName,
|
||||
Nickname: human.NickName,
|
||||
Language: human.PreferredLanguage.String(),
|
||||
},
|
||||
ExternalIDPID: idp.IDPConfigID,
|
||||
ExternalIDPUserID: idp.ExternalUserID,
|
||||
ExternalIDPUserDisplayName: idp.DisplayName,
|
||||
ExternalEmail: human.EmailAddress,
|
||||
ExternalEmailVerified: human.IsEmailVerified,
|
||||
ShowUsername: orgIAMPolicy.UserLoginMustBeDomain,
|
||||
OrgRegister: orgIAMPolicy.UserLoginMustBeDomain,
|
||||
}
|
||||
if human.Phone != nil {
|
||||
data.Phone = human.PhoneNumber
|
||||
data.ExternalPhone = human.PhoneNumber
|
||||
data.ExternalPhoneVerified = human.IsPhoneVerified
|
||||
}
|
||||
translator := l.getTranslator(authReq)
|
||||
l.renderer.RenderTemplate(w, r, translator, l.renderer.Templates[tmplExternalRegisterOverview], data, nil)
|
||||
}
|
||||
|
||||
func (l *Login) handleExternalRegisterCheck(w http.ResponseWriter, r *http.Request) {
|
||||
data := new(externalRegisterFormData)
|
||||
authReq, err := l.getAuthRequestAndParseData(r, data)
|
||||
if err != nil {
|
||||
l.renderError(w, r, authReq, err)
|
||||
return
|
||||
}
|
||||
|
||||
iam, err := l.authRepo.GetIAM(r.Context())
|
||||
if err != nil {
|
||||
l.renderRegisterOption(w, r, authReq, err)
|
||||
return
|
||||
}
|
||||
resourceOwner := iam.GlobalOrgID
|
||||
memberRoles := []string{domain.RoleOrgProjectCreator}
|
||||
|
||||
if authReq.RequestedOrgID != "" && authReq.RequestedOrgID != iam.GlobalOrgID {
|
||||
memberRoles = nil
|
||||
resourceOwner = authReq.RequestedOrgID
|
||||
}
|
||||
externalIDP, err := l.getExternalIDP(data)
|
||||
if externalIDP == nil {
|
||||
l.renderRegisterOption(w, r, authReq, err)
|
||||
return
|
||||
}
|
||||
user, err := l.mapExternalRegisterDataToUser(r, data)
|
||||
if err != nil {
|
||||
l.renderRegisterOption(w, r, authReq, err)
|
||||
return
|
||||
}
|
||||
_, err = l.command.RegisterHuman(setContext(r.Context(), resourceOwner), resourceOwner, user, externalIDP, memberRoles)
|
||||
if err != nil {
|
||||
l.renderRegisterOption(w, r, authReq, err)
|
||||
@@ -140,6 +236,9 @@ func (l *Login) mapTokenToLoginHumanAndExternalIDP(orgIamPolicy *iam_model.OrgIA
|
||||
displayName = tokens.IDTokenClaims.GetEmail()
|
||||
}
|
||||
}
|
||||
if displayName == "" {
|
||||
displayName = tokens.IDTokenClaims.GetEmail()
|
||||
}
|
||||
|
||||
externalIDP := &domain.ExternalIDP{
|
||||
IDPConfigID: idpConfig.IDPConfigID,
|
||||
@@ -148,3 +247,43 @@ func (l *Login) mapTokenToLoginHumanAndExternalIDP(orgIamPolicy *iam_model.OrgIA
|
||||
}
|
||||
return human, externalIDP
|
||||
}
|
||||
|
||||
func (l *Login) mapExternalRegisterDataToUser(r *http.Request, data *externalRegisterFormData) (*domain.Human, error) {
|
||||
human := &domain.Human{
|
||||
Username: data.Username,
|
||||
Profile: &domain.Profile{
|
||||
FirstName: data.Firstname,
|
||||
LastName: data.Lastname,
|
||||
PreferredLanguage: language.Make(data.Language),
|
||||
NickName: data.Nickname,
|
||||
},
|
||||
Email: &domain.Email{
|
||||
EmailAddress: data.Email,
|
||||
},
|
||||
}
|
||||
if data.ExternalEmail != data.Email {
|
||||
human.IsEmailVerified = false
|
||||
} else {
|
||||
human.IsEmailVerified = data.ExternalEmailVerified
|
||||
}
|
||||
if data.ExternalPhone == "" {
|
||||
return human, nil
|
||||
}
|
||||
human.Phone = &domain.Phone{
|
||||
PhoneNumber: data.Phone,
|
||||
}
|
||||
if data.ExternalPhone != data.Phone {
|
||||
human.IsPhoneVerified = false
|
||||
} else {
|
||||
human.IsPhoneVerified = data.ExternalPhoneVerified
|
||||
}
|
||||
return human, nil
|
||||
}
|
||||
|
||||
func (l *Login) getExternalIDP(data *externalRegisterFormData) (*domain.ExternalIDP, error) {
|
||||
return &domain.ExternalIDP{
|
||||
IDPConfigID: data.ExternalIDPConfigID,
|
||||
ExternalUserID: data.ExternalIDPExtUserID,
|
||||
DisplayName: data.ExternalIDPDisplayName,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ func CreateRenderer(pathPrefix string, staticDir http.FileSystem, staticStorage
|
||||
tmplChangePasswordDone: "change_password_done.html",
|
||||
tmplRegisterOption: "register_option.html",
|
||||
tmplRegister: "register.html",
|
||||
tmplExternalRegisterOverview: "external_register_overview.html",
|
||||
tmplLogoutDone: "logout_done.html",
|
||||
tmplRegisterOrg: "register_org.html",
|
||||
tmplChangeUsername: "change_username.html",
|
||||
@@ -181,6 +182,9 @@ func CreateRenderer(pathPrefix string, staticDir http.FileSystem, staticStorage
|
||||
"orgRegistrationUrl": func() string {
|
||||
return path.Join(r.pathPrefix, EndpointRegisterOrg)
|
||||
},
|
||||
"externalRegistrationUrl": func() string {
|
||||
return path.Join(r.pathPrefix, EndpointExternalRegister)
|
||||
},
|
||||
"changeUsernameUrl": func() string {
|
||||
return path.Join(r.pathPrefix, EndpointChangeUsername)
|
||||
},
|
||||
|
||||
@@ -82,6 +82,7 @@ func CreateRouter(login *Login, staticDir http.FileSystem, interceptors ...mux.M
|
||||
router.HandleFunc(EndpointRegister, login.handleRegister).Methods(http.MethodGet)
|
||||
router.HandleFunc(EndpointRegister, login.handleRegisterCheck).Methods(http.MethodPost)
|
||||
router.HandleFunc(EndpointExternalRegister, login.handleExternalRegister).Methods(http.MethodGet)
|
||||
router.HandleFunc(EndpointExternalRegister, login.handleExternalRegisterCheck).Methods(http.MethodPost)
|
||||
router.HandleFunc(EndpointExternalRegisterCallback, login.handleExternalRegisterCallback).Methods(http.MethodGet)
|
||||
router.HandleFunc(EndpointLogoutDone, login.handleLogoutDone).Methods(http.MethodGet)
|
||||
router.HandleFunc(EndpointDynamicResources, login.handleDynamicResources).Methods(http.MethodGet)
|
||||
|
||||
@@ -221,6 +221,26 @@ RegistrationUser:
|
||||
BackButtonText: zurück
|
||||
NextButtonText: weiter
|
||||
|
||||
ExternalRegistrationUserOverview:
|
||||
Title: Externer Benutzer Registration
|
||||
Description: Deine Benutzerangaben werden vom ausgewählten Provider übernommen. Du kannst sie hier ändern und ergänzen, bevor dein Benutzer angelegt wird.
|
||||
EmailLabel: E-Mail
|
||||
UsernameLabel: Benutzername
|
||||
FirstnameLabel: Vorname
|
||||
LastnameLabel: Nachname
|
||||
NicknameLabel: Nachname
|
||||
PhoneLabel: Telefonnummer
|
||||
LanguageLabel: Sprache
|
||||
German: Deutsch
|
||||
English: English
|
||||
TosAndPrivacyLabel: Allgemeine Geschäftsbedingungen und Datenschutz
|
||||
TosConfirm: Ich akzeptiere die
|
||||
TosLinkText: AGBs
|
||||
TosConfirmAnd: und die
|
||||
PrivacyLinkText: Datenschutzerklärung
|
||||
BackButtonText: zurück
|
||||
NextButtonText: speichern
|
||||
|
||||
RegistrationOrg:
|
||||
Title: Organisations Registration
|
||||
Description: Gib deinen Organisationsnamen und deine Benutzerangaben an.
|
||||
@@ -260,6 +280,11 @@ ExternalNotFoundOption:
|
||||
Description: Externer Benutzer konnte nicht gefunden werden. Willst du deinen Benutzer mit einem bestehenden verlinken oder diesen als neuen Benutzer registrieren.
|
||||
LinkButtonText: Verlinken
|
||||
AutoRegisterButtonText: Automatisches registrieren
|
||||
TosAndPrivacyLabel: Allgemeine Geschäftsbedingungen und Datenschutz
|
||||
TosConfirm: Ich akzeptiere die
|
||||
TosLinkText: AGBs
|
||||
TosConfirmAnd: und die
|
||||
PrivacyLinkText: Datenschutzerklärung
|
||||
|
||||
Footer:
|
||||
PoweredBy: Powered By
|
||||
@@ -305,6 +330,8 @@ Errors:
|
||||
GeneratorAlgNotSupported: Generator Algorithums wird nicht unterstützt
|
||||
EmailVerify:
|
||||
UserIDEmpty: UserID ist leer
|
||||
ExternalData:
|
||||
CouldNotRead: Externe Daten konnten nicht korrekt gelesen werden
|
||||
MFA:
|
||||
NoProviders: Es stehen keine Multifaktorprovider zur Verfügung
|
||||
OTP:
|
||||
@@ -318,6 +345,9 @@ Errors:
|
||||
ExternalIDP:
|
||||
IDPTypeNotImplemented: IDP Typ ist nicht implementiert
|
||||
NotAllowed: Externer Login Provider ist nicht erlaubt
|
||||
IDPConfigIDEmpty: Identity Provider ID ist leer
|
||||
ExternalUserIDEmpty: Externe User ID ist leer
|
||||
UserDisplayNameEmpty: Benutzer Anzeige Name ist leer
|
||||
GrantRequired: Der Login an diese Applikation ist nicht möglich. Der Benutzer benötigt mindestens eine Berechtigung an der Applikation. Bitte melde dich bei deinem Administrator.
|
||||
IdentityProvider:
|
||||
InvalidConfig: Identitäts Provider Konfiguration ist ungültig
|
||||
|
||||
@@ -221,6 +221,27 @@ RegistrationUser:
|
||||
BackButtonText: back
|
||||
NextButtonText: next
|
||||
|
||||
ExternalRegistrationUserOverview:
|
||||
Title: External User Registration
|
||||
Description: We have taken your user details from the selected provider. You can now change or complete them.
|
||||
EmailLabel: E-Mail
|
||||
UsernameLabel: Username
|
||||
FirstnameLabel: Firstname
|
||||
LastnameLabel: Lastname
|
||||
NicknameLabel: Nickname
|
||||
PhoneLabel: Phonenumber
|
||||
LanguageLabel: Language
|
||||
German: Deutsch
|
||||
English: English
|
||||
TosAndPrivacyLabel: Terms and conditions
|
||||
TosConfirm: I accept the
|
||||
TosLinkText: TOS
|
||||
TosConfirmAnd: and the
|
||||
PrivacyLinkText: privacy policy
|
||||
ExternalLogin: or register with an external user
|
||||
BackButtonText: back
|
||||
NextButtonText: save
|
||||
|
||||
RegistrationOrg:
|
||||
Title: Organisation Registration
|
||||
Description: Enter your organisationname and userdata.
|
||||
@@ -260,6 +281,11 @@ ExternalNotFoundOption:
|
||||
Description: External user not found. Do you want to link your user or auto register a new one.
|
||||
LinkButtonText: Link
|
||||
AutoRegisterButtonText: Auto register
|
||||
TosAndPrivacyLabel: Terms and conditions
|
||||
TosConfirm: I accept the
|
||||
TosLinkText: TOS
|
||||
TosConfirmAnd: and the
|
||||
PrivacyLinkText: privacy policy
|
||||
|
||||
Footer:
|
||||
PoweredBy: Powered By
|
||||
@@ -305,6 +331,8 @@ Errors:
|
||||
GeneratorAlgNotSupported: Unsupported generator algorithm
|
||||
EmailVerify:
|
||||
UserIDEmpty: UserID is empty
|
||||
ExternalData:
|
||||
CouldNotRead: External data could not be read correctly
|
||||
MFA:
|
||||
NoProviders: No available multifactor providers
|
||||
OTP:
|
||||
@@ -318,6 +346,9 @@ Errors:
|
||||
ExternalIDP:
|
||||
IDPTypeNotImplemented: IDP Type is not implemented
|
||||
NotAllowed: External Login Provider not allowed
|
||||
IDPConfigIDEmpty: Identity Provider ID is empty
|
||||
ExternalUserIDEmpty: External User ID is empty
|
||||
UserDisplayNameEmpty: User Display Name is empty
|
||||
GrantRequired: Login not possible. The user is required to have at least one grant on the application. Please contact your administrator.
|
||||
IdentityProvider:
|
||||
InvalidConfig: Identity Provider configuration is invalid
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
let button1 = document.getElementById("link-button");
|
||||
disableSubmit(undefined, button1);
|
||||
|
||||
let button2 = document.getElementById("auto-register-button");
|
||||
disableSubmit(undefined, button2);
|
||||
@@ -3,32 +3,65 @@
|
||||
<div class="lgn-head">
|
||||
<h1>{{t "ExternalNotFoundOption.Title"}}</h1>
|
||||
<p>{{t "ExternalNotFoundOption.Description"}}</p>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<form action="{{ externalNotFoundOptionUrl }}" method="POST">
|
||||
|
||||
{{ .CSRF }}
|
||||
|
||||
<input type="hidden" name="authRequestID" value="{{ .AuthReqID }}" />
|
||||
|
||||
<div class="lgn-register">
|
||||
{{ if or .TOSLink .PrivacyLink }}
|
||||
<div class="lgn-field">
|
||||
<label class="lgn-label">{{t "ExternalNotFoundOption.TosAndPrivacyLabel"}}</label>
|
||||
<div class="lgn-checkbox">
|
||||
<input type="checkbox" id="register-term-confirmation"
|
||||
name="register-term-confirmation" required>
|
||||
<label for="register-term-confirmation">
|
||||
{{t "ExternalNotFoundOption.TosConfirm"}}
|
||||
{{ if .TOSLink }}
|
||||
<a class="tos-link" target="_blank" href="{{ .TOSLink }}" rel="noopener noreferrer">
|
||||
{{t "ExternalNotFoundOption.TosLinkText"}}
|
||||
</a>
|
||||
{{end}}
|
||||
{{ if and .TOSLink .PrivacyLink }}
|
||||
{{t "ExternalNotFoundOption.TosConfirmAnd"}}
|
||||
{{ end }}
|
||||
{{ if .PrivacyLink }}
|
||||
<a class="tos-link" target="_blank" href="{{ .PrivacyLink}}" rel="noopener noreferrer">
|
||||
{{t "ExternalNotFoundOption.PrivacyLinkText"}}
|
||||
</a>
|
||||
{{end}}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
{{template "error-message" .}}
|
||||
|
||||
<div class="lgn-actions">
|
||||
<button class="lgn-icon-button lgn-left-action" name="resetlinking" value="true"
|
||||
formnovalidate>
|
||||
formnovalidate>
|
||||
<i class="lgn-icon-arrow-left-solid"></i>
|
||||
</button>
|
||||
|
||||
<button class="lgn-raised-button lgn-primary" name="link" value="true"
|
||||
formnovalidate>{{t "ExternalNotFoundOption.LinkButtonText"}}</button>
|
||||
<span class="fill-space"></span>
|
||||
<button class="lgn-raised-button lgn-primary" name="autoregister" value="true"
|
||||
formnovalidate>{{t "ExternalNotFoundOption.AutoRegisterButtonText"}}</button>
|
||||
|
||||
<button class="lgn-raised-button lgn-primary" name="link" value="true">
|
||||
{{t "ExternalNotFoundOption.LinkButtonText"}}
|
||||
</button>
|
||||
<span class="fill-space"></span>
|
||||
<button class="lgn-raised-button lgn-primary" name="autoregister" value="true">
|
||||
{{t "ExternalNotFoundOption.AutoRegisterButtonText"}}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{{template "error-message" .}}
|
||||
</form>
|
||||
|
||||
|
||||
<script src="{{ resourceUrl "scripts/form_submit.js" }}"></script>
|
||||
<script src="{{ resourceUrl "scripts/default_form_validation.js" }}"></script>
|
||||
<script src="{{ resourceUrl "scripts/external_not_found_check.js" }}"></script>
|
||||
|
||||
{{template "main-bottom" .}}
|
||||
@@ -0,0 +1,114 @@
|
||||
{{template "main-top" .}}
|
||||
|
||||
<div class="lgn-head">
|
||||
<h1>{{t "ExternalRegistrationUserOverview.Title"}}</h1>
|
||||
<p>{{t "ExternalRegistrationUserOverview.Description"}}</p>
|
||||
</div>
|
||||
|
||||
|
||||
<form action="{{ externalRegistrationUrl }}" method="POST">
|
||||
|
||||
{{ .CSRF }}
|
||||
|
||||
<input type="hidden" name="authRequestID" value="{{ .AuthReqID }}" />
|
||||
<input type="hidden" id="external-idp-config-id" name="external-idp-config-id" value="{{ .ExternalIDPID }}" />
|
||||
<input type="hidden" id="external-idp-ext-user-id" name="external-idp-ext-user-id" value="{{ .ExternalIDPUserID }}" />
|
||||
<input type="hidden" id="external-idp-display-name" name="external-idp-display-name" value="{{ .ExternalIDPUserDisplayName }}" />
|
||||
<input type="hidden" id="external-email" name="external-email" value="{{ .ExternalEmail }}" />
|
||||
<input type="hidden" id="external-email-verified" name="external-email-verified" value="{{ .ExternalEmailVerified }}" />
|
||||
<input type="hidden" id="external-phone" name="external-phone" value="{{ .ExternalPhone }}" />
|
||||
<input type="hidden" id="external-phone-verified" name="external-phone-verified" value="{{ .ExternalPhoneVerified }}" />
|
||||
|
||||
<div class="lgn-register">
|
||||
|
||||
<div class="double-col">
|
||||
<div class="lgn-field">
|
||||
<label class="lgn-label" for="firstname">{{t "ExternalRegistrationUserOverview.FirstnameLabel"}}</label>
|
||||
<input class="lgn-input" type="text" id="firstname" name="firstname" autocomplete="given-name"
|
||||
value="{{ .Firstname }}" autofocus required>
|
||||
</div>
|
||||
<div class="lgn-field">
|
||||
<label class="lgn-label" for="lastname">{{t "ExternalRegistrationUserOverview.LastnameLabel"}}</label>
|
||||
<input class="lgn-input" type="text" id="lastname" name="lastname" autocomplete="family-name"
|
||||
value="{{ .Lastname }}" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="lgn-field double">
|
||||
<label class="lgn-label" for="email">{{t "ExternalRegistrationUserOverview.EmailLabel"}}</label>
|
||||
<input class="lgn-input" type="text" id="email" name="email" autocomplete="email" value="{{ .Email }}" required>
|
||||
</div>
|
||||
|
||||
<div class="lgn-field double">
|
||||
<label class="lgn-label" for="phone">{{t "ExternalRegistrationUserOverview.PhoneLabel"}}</label>
|
||||
<input class="lgn-input" type="text" id="phone" name="phone" autocomplete="tel" value="{{ .Phone }}">
|
||||
</div>
|
||||
|
||||
{{if .ShowUsername}}
|
||||
<div class="lgn-field double">
|
||||
<label class="lgn-label" for="username">{{t "ExternalRegistrationUserOverview.UsernameLabel"}}</label>
|
||||
<div class="lgn-suffix-wrapper">
|
||||
<input class="lgn-input lgn-suffix-input" type="text" id="username" name="username" autocomplete="email" value="{{ .Email }}" required>
|
||||
{{if .DisplayLoginNameSuffix}}
|
||||
<span id="default-login-suffix" lgnsuffix class="loginname-suffix">@{{.PrimaryDomain}}</span>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
<div class="double-col">
|
||||
<div class="lgn-field">
|
||||
<label class="lgn-label" for="languages">{{t "ExternalRegistrationUserOverview.LanguageLabel"}}</label>
|
||||
<select id="languages" name="language">
|
||||
<option value=""></option>
|
||||
<option value="de" id="de" {{if (selectedLanguage "de")}} selected {{end}}>{{t "ExternalRegistrationUserOverview.German"}}
|
||||
</option>
|
||||
<option value="en" id="en" {{if (selectedLanguage "en")}} selected {{end}}>{{t "ExternalRegistrationUserOverview.English"}}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{ if or .TOSLink .PrivacyLink }}
|
||||
<div class="lgn-field">
|
||||
<label class="lgn-label">{{t "ExternalRegistrationUserOverview.TosAndPrivacyLabel"}}</label>
|
||||
<div class="lgn-checkbox">
|
||||
<input type="checkbox" id="register-term-confirmation"
|
||||
name="register-term-confirmation" required>
|
||||
<label for="register-term-confirmation">
|
||||
{{t "ExternalRegistrationUserOverview.TosConfirm"}}
|
||||
{{ if .TOSLink }}
|
||||
<a class="tos-link" target="_blank" href="{{ .TOSLink }}" rel="noopener noreferrer">
|
||||
{{t "ExternalRegistrationUserOverview.TosLinkText"}}
|
||||
</a>
|
||||
{{end}}
|
||||
{{ if and .TOSLink .PrivacyLink }}
|
||||
{{t "ExternalRegistrationUserOverview.TosConfirmAnd"}}
|
||||
{{ end }}
|
||||
{{ if .PrivacyLink }}
|
||||
<a class="tos-link" target="_blank" href="{{ .PrivacyLink}}" rel="noopener noreferrer">
|
||||
{{t "ExternalRegistrationUserOverview.PrivacyLinkText"}}
|
||||
</a>
|
||||
{{end}}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
{{template "error-message" .}}
|
||||
|
||||
<div class="lgn-actions">
|
||||
<a class="lgn-stroked-button lgn-primary" href="{{ registerOptionUrl }}">
|
||||
{{t "ExternalRegistrationUserOverview.BackButtonText"}}
|
||||
</a>
|
||||
<span class="fill-space"></span>
|
||||
<button class="lgn-raised-button lgn-primary" id="submit-button" type="submit">{{t "ExternalRegistrationUserOverview.NextButtonText"}}</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<script src="{{ resourceUrl "scripts/input_suffix_offset.js" }}"></script>
|
||||
<script src="{{ resourceUrl "scripts/form_submit.js" }}"></script>
|
||||
<script src="{{ resourceUrl "scripts/default_form_validation.js" }}"></script>
|
||||
|
||||
{{template "main-bottom" .}}
|
||||
@@ -39,7 +39,7 @@
|
||||
|
||||
{{if .ShowUsername}}
|
||||
<div class="lgn-field double">
|
||||
<label class="lgn-label" for="email">{{t "RegistrationUser.UsernameLabel"}}</label>
|
||||
<label class="lgn-label" for="username">{{t "RegistrationUser.UsernameLabel"}}</label>
|
||||
<div class="lgn-suffix-wrapper">
|
||||
<input class="lgn-input lgn-suffix-input" type="text" id="username" name="username" autocomplete="email" value="{{ .Email }}" required>
|
||||
{{if .DisplayLoginNameSuffix}}
|
||||
|
||||
Reference in New Issue
Block a user