fix: make user creation errors helpful (#5382)

* fix: make user creation errors helpful

* fix linting and unit testing errors

* fix linting

* make zitadel config reusable

* fix human validations

* translate ssr errors

* make zitadel config reusable

* cover more translations for ssr

* handle email validation message centrally

* fix unit tests

* fix linting

* align signatures

* use more precise wording

* handle phone validation message centrally

* fix: return specific profile errors

* docs: edit comments

* fix unit tests

---------

Co-authored-by: Silvan <silvan.reusser@gmail.com>
This commit is contained in:
Elio Bischof
2023-03-14 20:20:38 +01:00
committed by GitHub
parent 9ff810eb92
commit e00cc187fa
79 changed files with 610 additions and 485 deletions

View File

@@ -564,13 +564,13 @@ func (s *Server) getUsers(ctx context.Context, org string, withPasswords bool, w
}
if user.Human.Email != "" {
dataUser.User.Email = &management_pb.ImportHumanUserRequest_Email{
Email: user.Human.Email,
Email: string(user.Human.Email),
IsEmailVerified: user.Human.IsEmailVerified,
}
}
if user.Human.Phone != "" {
dataUser.User.Phone = &management_pb.ImportHumanUserRequest_Phone{
Phone: user.Human.Phone,
Phone: string(user.Human.Phone),
IsPhoneVerified: user.Human.IsPhoneVerified,
}
}

View File

@@ -6,6 +6,7 @@ import (
user_grpc "github.com/zitadel/zitadel/internal/api/grpc/user"
"github.com/zitadel/zitadel/internal/command"
"github.com/zitadel/zitadel/internal/domain"
admin_grpc "github.com/zitadel/zitadel/pkg/grpc/admin"
)
@@ -29,7 +30,7 @@ func setUpOrgHumanToCommand(human *admin_grpc.SetUpOrgRequest_Human) *command.Ad
func setUpOrgHumanEmailToDomain(email *admin_grpc.SetUpOrgRequest_Human_Email) command.Email {
return command.Email{
Address: email.Email,
Address: domain.EmailAddress(email.Email),
Verified: email.IsEmailVerified,
}
}
@@ -39,7 +40,7 @@ func setUpOrgHumanPhoneToDomain(phone *admin_grpc.SetUpOrgRequest_Human_Phone) c
return command.Phone{}
}
return command.Phone{
Number: phone.Phone,
Number: domain.PhoneNumber(phone.Phone),
Verified: phone.IsPhoneVerified,
}
}

View File

@@ -10,6 +10,6 @@ import (
func UpdateMyEmailToDomain(ctx context.Context, email *auth.SetMyEmailRequest) *domain.Email {
return &domain.Email{
ObjectRoot: ctxToObjectRoot(ctx),
EmailAddress: email.Email,
EmailAddress: domain.EmailAddress(email.Email),
}
}

View File

@@ -10,6 +10,6 @@ import (
func UpdateMyPhoneToDomain(ctx context.Context, phone *auth.SetMyPhoneRequest) *domain.Phone {
return &domain.Phone{
ObjectRoot: ctxToObjectRoot(ctx),
PhoneNumber: phone.Phone,
PhoneNumber: domain.PhoneNumber(phone.Phone),
}
}

View File

@@ -208,7 +208,7 @@ func AddHumanUserRequestToAddHuman(req *mgmt_pb.AddHumanUserRequest) *command.Ad
NickName: req.Profile.NickName,
DisplayName: req.Profile.DisplayName,
Email: command.Email{
Address: req.Email.Email,
Address: domain.EmailAddress(req.Email.Email),
Verified: req.Email.IsEmailVerified,
},
PreferredLanguage: lang,
@@ -221,7 +221,7 @@ func AddHumanUserRequestToAddHuman(req *mgmt_pb.AddHumanUserRequest) *command.Ad
}
if req.Phone != nil {
human.Phone = command.Phone{
Number: req.Phone.Phone,
Number: domain.PhoneNumber(req.Phone.Phone),
Verified: req.Phone.IsPhoneVerified,
}
}
@@ -446,7 +446,7 @@ func (s *Server) ResendHumanInitialization(ctx context.Context, req *mgmt_pb.Res
if err != nil {
return nil, err
}
details, err := s.command.ResendInitialMail(ctx, req.UserId, req.Email, authz.GetCtxData(ctx).OrgID, initCodeGenerator)
details, err := s.command.ResendInitialMail(ctx, req.UserId, domain.EmailAddress(req.Email), authz.GetCtxData(ctx).OrgID, initCodeGenerator)
if err != nil {
return nil, err
}

View File

@@ -91,37 +91,6 @@ func ListUserMetadataToDomain(req *mgmt_pb.ListUserMetadataRequest) (*query.User
}, nil
}
func AddHumanUserRequestToDomain(req *mgmt_pb.AddHumanUserRequest) *domain.Human {
h := &domain.Human{
Username: req.UserName,
}
preferredLanguage, err := language.Parse(req.Profile.PreferredLanguage)
logging.Log("MANAG-M029f").OnError(err).Debug("language malformed")
h.Profile = &domain.Profile{
FirstName: req.Profile.FirstName,
LastName: req.Profile.LastName,
NickName: req.Profile.NickName,
DisplayName: req.Profile.DisplayName,
PreferredLanguage: preferredLanguage,
Gender: user_grpc.GenderToDomain(req.Profile.Gender),
}
h.Email = &domain.Email{
EmailAddress: req.Email.Email,
IsEmailVerified: req.Email.IsEmailVerified,
}
if req.Phone != nil {
h.Phone = &domain.Phone{
PhoneNumber: req.Phone.Phone,
IsPhoneVerified: req.Phone.IsPhoneVerified,
}
}
if req.InitialPassword != "" {
h.Password = &domain.Password{SecretString: req.InitialPassword, ChangeRequired: true}
}
return h
}
func ImportHumanUserRequestToDomain(req *mgmt_pb.ImportHumanUserRequest) (human *domain.Human, passwordless bool, links []*domain.UserIDPLink) {
human = &domain.Human{
Username: req.UserName,
@@ -137,12 +106,12 @@ func ImportHumanUserRequestToDomain(req *mgmt_pb.ImportHumanUserRequest) (human
Gender: user_grpc.GenderToDomain(req.Profile.Gender),
}
human.Email = &domain.Email{
EmailAddress: req.Email.Email,
EmailAddress: domain.EmailAddress(req.Email.Email),
IsEmailVerified: req.Email.IsEmailVerified,
}
if req.Phone != nil {
human.Phone = &domain.Phone{
PhoneNumber: req.Phone.Phone,
PhoneNumber: domain.PhoneNumber(req.Phone.Phone),
IsPhoneVerified: req.Phone.IsPhoneVerified,
}
}
@@ -199,7 +168,7 @@ func UpdateHumanEmailRequestToDomain(ctx context.Context, req *mgmt_pb.UpdateHum
AggregateID: req.UserId,
ResourceOwner: authz.GetCtxData(ctx).OrgID,
},
EmailAddress: req.Email,
EmailAddress: domain.EmailAddress(req.Email),
IsEmailVerified: req.IsEmailVerified,
}
}
@@ -207,7 +176,7 @@ func UpdateHumanEmailRequestToDomain(ctx context.Context, req *mgmt_pb.UpdateHum
func UpdateHumanPhoneRequestToDomain(req *mgmt_pb.UpdateHumanPhoneRequest) *domain.Phone {
return &domain.Phone{
ObjectRoot: models.ObjectRoot{AggregateID: req.UserId},
PhoneNumber: req.Phone,
PhoneNumber: domain.PhoneNumber(req.Phone),
IsPhoneVerified: req.IsPhoneVerified,
}
}

View File

@@ -59,7 +59,7 @@ func CreateInstancePbToSetupInstance(req *system_pb.CreateInstanceRequest, defau
func createInstancePbToAddHuman(req *system_pb.CreateInstanceRequest_Human, defaultHuman command.AddHuman, userLoginMustBeDomain bool, org, externalDomain string) *command.AddHuman {
user := defaultHuman
if req.Email != nil {
user.Email.Address = req.Email.Email
user.Email.Address = domain.EmailAddress(req.Email.Email)
user.Email.Verified = req.Email.IsEmailVerified
}
if req.Profile != nil {
@@ -164,7 +164,7 @@ func AddInstancePbToSetupInstance(req *system_pb.AddInstanceRequest, defaultInst
instance.Org.Human = new(command.AddHuman)
}
if req.OwnerEmail.Email != "" {
instance.Org.Human.Email.Address = req.OwnerEmail.Email
instance.Org.Human.Email.Address = domain.EmailAddress(req.OwnerEmail.Email)
instance.Org.Human.Email.Verified = req.OwnerEmail.IsEmailVerified
}
if req.OwnerProfile != nil {

View File

@@ -58,11 +58,11 @@ func HumanToPb(view *query.Human, assetPrefix, owner string) *user_pb.Human {
AvatarUrl: domain.AvatarURL(assetPrefix, owner, view.AvatarKey),
},
Email: &user_pb.Email{
Email: view.Email,
Email: string(view.Email),
IsEmailVerified: view.IsEmailVerified,
},
Phone: &user_pb.Phone{
Phone: view.Phone,
Phone: string(view.Phone),
IsPhoneVerified: view.IsPhoneVerified,
},
}
@@ -91,7 +91,7 @@ func ProfileToPb(profile *query.Profile, assetPrefix string) *user_pb.Profile {
func EmailToPb(email *query.Email) *user_pb.Email {
return &user_pb.Email{
Email: email.Email,
Email: string(email.Email),
IsEmailVerified: email.IsVerified,
}
}
@@ -105,7 +105,7 @@ func PhoneToPb(phone *query.Phone) *user_pb.Phone {
func ModelEmailToPb(email *query.Email) *user_pb.Email {
return &user_pb.Email{
Email: email.Email,
Email: string(email.Email),
IsEmailVerified: email.IsVerified,
}
}

View File

@@ -268,7 +268,7 @@ func (o *OPStorage) setUserinfo(ctx context.Context, userInfo oidc.UserInfoSette
if user.Human == nil {
continue
}
userInfo.SetEmail(user.Human.Email, user.Human.IsEmailVerified)
userInfo.SetEmail(string(user.Human.Email), user.Human.IsEmailVerified)
case oidc.ScopeProfile:
userInfo.SetPreferredUsername(user.PreferredLoginName)
userInfo.SetUpdatedAt(user.ChangeDate)
@@ -287,7 +287,7 @@ func (o *OPStorage) setUserinfo(ctx context.Context, userInfo oidc.UserInfoSette
if user.Human == nil {
continue
}
userInfo.SetPhone(user.Human.Phone, user.Human.IsPhoneVerified)
userInfo.SetPhone(string(user.Human.Phone), user.Human.IsPhoneVerified)
case oidc.ScopeAddress:
//TODO: handle address for human users as soon as implemented
case ScopeUserMetaData:

View File

@@ -154,7 +154,7 @@ func setUserinfo(user *query.User, userinfo models.AttributeSetter, attributes [
if user.Human == nil {
return
}
userinfo.SetEmail(user.Human.Email)
userinfo.SetEmail(string(user.Human.Email))
userinfo.SetSurname(user.Human.LastName)
userinfo.SetGivenName(user.Human.FirstName)
userinfo.SetFullName(user.Human.DisplayName)
@@ -164,7 +164,7 @@ func setUserinfo(user *query.User, userinfo models.AttributeSetter, attributes [
switch attribute {
case provider.AttributeEmail:
if user.Human != nil {
userinfo.SetEmail(user.Human.Email)
userinfo.SetEmail(string(user.Human.Email))
}
case provider.AttributeSurname:
if user.Human != nil {

View File

@@ -55,13 +55,13 @@ func (l *Login) runPostExternalAuthenticationActions(
actions.SetFields("setPreferredUsername", func(username string) {
user.PreferredUsername = username
}),
actions.SetFields("setEmail", func(email string) {
actions.SetFields("setEmail", func(email domain.EmailAddress) {
user.Email = email
}),
actions.SetFields("setEmailVerified", func(verified bool) {
user.IsEmailVerified = verified
}),
actions.SetFields("setPhone", func(phone string) {
actions.SetFields("setPhone", func(phone domain.PhoneNumber) {
user.Phone = phone
}),
actions.SetFields("setPhoneVerified", func(verified bool) {
@@ -222,7 +222,7 @@ func (l *Login) runPreCreationActions(
actions.SetFields("setUsername", func(username string) {
user.Username = username
}),
actions.SetFields("setEmail", func(email string) {
actions.SetFields("setEmail", func(email domain.EmailAddress) {
if user.Email == nil {
user.Email = &domain.Email{}
}
@@ -234,11 +234,11 @@ func (l *Login) runPreCreationActions(
}
user.Email.IsEmailVerified = verified
}),
actions.SetFields("setPhone", func(email string) {
actions.SetFields("setPhone", func(phone domain.PhoneNumber) {
if user.Phone == nil {
user.Phone = &domain.Phone{}
}
user.Phone.PhoneNumber = email
user.Phone.PhoneNumber = phone
}),
actions.SetFields("setPhoneVerified", func(verified bool) {
if user.Phone == nil {

View File

@@ -60,28 +60,28 @@ type externalNotFoundOptionData struct {
ShowUsername bool
ShowUsernameSuffix bool
OrgRegister bool
ExternalEmail string
ExternalEmail domain.EmailAddress
ExternalEmailVerified bool
ExternalPhone string
ExternalPhone domain.PhoneNumber
ExternalPhoneVerified bool
}
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"`
ExternalIDPConfigID string `schema:"external-idp-config-id"`
ExternalIDPExtUserID string `schema:"external-idp-ext-user-id"`
ExternalIDPDisplayName string `schema:"external-idp-display-name"`
ExternalEmail domain.EmailAddress `schema:"external-email"`
ExternalEmailVerified bool `schema:"external-email-verified"`
Email domain.EmailAddress `schema:"email"`
Username string `schema:"username"`
Firstname string `schema:"firstname"`
Lastname string `schema:"lastname"`
Nickname string `schema:"nickname"`
ExternalPhone domain.PhoneNumber `schema:"external-phone"`
ExternalPhoneVerified bool `schema:"external-phone-verified"`
Phone domain.PhoneNumber `schema:"phone"`
Language string `schema:"language"`
TermsConfirm bool `schema:"terms-confirm"`
}
// handleExternalLoginStep is called as nextStep
@@ -815,7 +815,7 @@ func mapExternalNotFoundOptionFormDataToLoginUser(formData *externalNotFoundOpti
IDPConfigID: formData.ExternalIDPConfigID,
ExternalUserID: formData.ExternalIDPExtUserID,
PreferredUsername: formData.Username,
DisplayName: formData.Email,
DisplayName: string(formData.Email),
FirstName: formData.Firstname,
LastName: formData.Lastname,
NickName: formData.Nickname,

View File

@@ -16,14 +16,14 @@ const (
)
type registerFormData struct {
Email string `schema:"email"`
Username string `schema:"username"`
Firstname string `schema:"firstname"`
Lastname string `schema:"lastname"`
Language string `schema:"language"`
Password string `schema:"register-password"`
Password2 string `schema:"register-password-confirmation"`
TermsConfirm bool `schema:"terms-confirm"`
Email domain.EmailAddress `schema:"email"`
Username string `schema:"username"`
Firstname string `schema:"firstname"`
Lastname string `schema:"lastname"`
Language string `schema:"language"`
Password string `schema:"register-password"`
Password2 string `schema:"register-password-confirmation"`
TermsConfirm bool `schema:"terms-confirm"`
}
type registerData struct {

View File

@@ -94,7 +94,7 @@ func (l *Login) passLoginHintToRegistration(r *http.Request, authReq *domain.Aut
if authReq == nil {
return data
}
data.Email = authReq.LoginHint
data.Email = domain.EmailAddress(authReq.LoginHint)
domainPolicy, err := l.getOrgDomainPolicy(r, authReq.RequestedOrgID)
if err != nil {
logging.WithFields("authRequest", authReq.ID, "org", authReq.RequestedOrgID).Error("unable to load domain policy for registration loginHint")

View File

@@ -14,14 +14,14 @@ const (
)
type registerOrgFormData struct {
RegisterOrgName string `schema:"orgname"`
Email string `schema:"email"`
Username string `schema:"username"`
Firstname string `schema:"firstname"`
Lastname string `schema:"lastname"`
Password string `schema:"register-password"`
Password2 string `schema:"register-password-confirmation"`
TermsConfirm bool `schema:"terms-confirm"`
RegisterOrgName string `schema:"orgname"`
Email domain.EmailAddress `schema:"email"`
Username string `schema:"username"`
Firstname string `schema:"firstname"`
Lastname string `schema:"lastname"`
Password string `schema:"register-password"`
Password2 string `schema:"register-password-confirmation"`
TermsConfirm bool `schema:"terms-confirm"`
}
type registerOrgData struct {
@@ -121,7 +121,7 @@ func (l *Login) renderRegisterOrg(w http.ResponseWriter, r *http.Request, authRe
func (d registerOrgFormData) toUserDomain() *domain.Human {
if d.Username == "" {
d.Username = d.Email
d.Username = string(d.Email)
}
return &domain.Human{
Username: d.Username,
@@ -140,7 +140,7 @@ func (d registerOrgFormData) toUserDomain() *domain.Human {
func (d registerOrgFormData) toCommandOrg() *command.OrgSetup {
if d.Username == "" {
d.Username = d.Email
d.Username = string(d.Email)
}
return &command.OrgSetup{
Name: d.RegisterOrgName,

View File

@@ -328,6 +328,33 @@ Errors:
Invalid: Userdaten sind ungültig
DomainNotAllowedAsUsername: Domäne ist bereits reserviert und kann nicht verwendet werden
NotAllowedToLink: Der Benutzer darf nicht mit einem externen Login Provider verlinkt werden
Profile:
NotFound: Profil nicht gefunden
NotChanged: Profil nicht verändert
Empty: Profil ist leer
FirstNameEmpty: Vorname im Profil ist leer
LastNameEmpty: Nachname im Profil ist leer
IDMissing: Profil ID fehlt
Email:
NotFound: Email nicht gefunden
Invalid: Email ist ungültig
AlreadyVerified: Email ist bereits verifiziert
NotChanged: Email wurde nicht geändert
Empty: Email ist leer
IDMissing: Email ID fehlt
Phone:
NotFound: Telefonnummer nicht gefunden
Invalid: Telefonnummer ist ungültig
AlreadyVerified: Telefonnummer bereits verifiziert
Empty: Telefonnummer ist leer
NotChanged: Telefonnummer wurde nicht geändert
Address:
NotFound: Adresse nicht gefunden
NotChanged: Adresse wurde nicht geändert
Username:
AlreadyExists: Benutzername ist bereits vergeben
Reserved: Benutzername ist bereits vergeben
Empty: Benutzername ist leer
Password:
ConfirmationWrong: Passwort Bestätigung stimmt nicht überein
Empty: Passwort ist leer

View File

@@ -328,6 +328,33 @@ Errors:
Invalid: Invalid userdata
DomainNotAllowedAsUsername: Domain is already reserved and cannot be used
NotAllowedToLink: User is not allowed to link with external login provider
Profile:
NotFound: Profile not found
NotChanged: Profile not changed
Empty: Profile is empty
FirstNameEmpty: First name in profile is empty
LastNameEmpty: Last name in profile is empty
IDMissing: Profile ID is missing
Email:
NotFound: Email not found
Invalid: Email is invalid
AlreadyVerified: Email is already verified
NotChanged: Email not changed
Empty: Email is empty
IDMissing: Email ID is missing
Phone:
NotFound: Phone not found
Invalid: Phone is invalid
AlreadyVerified: Phone already verified
Empty: Phone is empty
NotChanged: Phone not changed
Address:
NotFound: Address not found
NotChanged: Address not changed
Username:
AlreadyExists: Username already taken
Reserved: Username is already taken
Empty: Username is empty
Password:
ConfirmationWrong: Passwordconfirmation is wrong
Empty: Password is empty

View File

@@ -328,6 +328,33 @@ Errors:
Invalid: Données utilisateur non valides
DomainNotAllowedAsUsername: Le domaine est déjà réservé et ne peut pas être utilisé.
NotAllowedToLink: L'utilisateur n'est pas autorisé à établir un lien avec un fournisseur de connexion externe
Profile:
NotFound: Profil non trouvé
NotChanged: Le profil n'a pas changé
Empty: Profil est vide
FirstNameEmpty: Le prénom dans le profil est vide
LastNameEmpty: Le nom de famille dans le profil est vide
IDMissing: Profil ID manquant
Email:
NotFound: Email non trouvé
Invalid: L'email n'est pas valide
AlreadyVerified: L'adresse électronique est déjà vérifiée
NotChanged: L'adresse électronique n'a pas changé
Empty: Email est vide
IDMissing: Email ID manquant
Phone:
Notfound: Téléphone non trouvé
Invalid: Le téléphone n'est pas valide
AlreadyVerified: Téléphone déjà vérifié
Empty: Téléphone est vide
NotChanged: Téléphone n'a pas changé
Address:
NotFound: Adresse non trouvée
NotChanged: L'adresse n'a pas changé
Username:
AlreadyExists: Nom d'utilisateur déjà pris
Reserved: Le nom d'utilisateur est déjà pris
Empty: Le nom d'utilisateur est vide
Password:
ConfirmationWrong: La confirmation du mot de passe est erronée
Empty: Le mot de passe est vide

View File

@@ -328,6 +328,33 @@ Errors:
Invalid: I dati del utente non sono validi
DomainNotAllowedAsUsername: Il dominio è già riservato e non può essere utilizzato
NotAllowedToLink: L'utente non è autorizzato a collegarsi con un provider di accesso esterno
Profile:
NotFound: Profilo non trovato
NotChanged: Profilo non cambiato
Empty: Profilo è vuoto
FirstNameEmpty: Il nome nel profilo è vuoto
LastNameEmpty: Il cognome nel profilo è vuoto
IDMissing: Profilo ID mancante
Email:
NotFound: Email non trovata
Invalid: L'e-mail non è valida
AlreadyVerified: L'e-mail è già verificata
NotChanged: Email non cambiata
Empty: Email è vuota
IDMissing: Email ID mancante
Phone:
NotFound: Telefono non trovato
Invalid: Il telefono non è valido
AlreadyVerified: Telefono già verificato
Empty: Il telefono è vuoto
NotChanged: Telefono non cambiato
Address:
NotFound: Indirizzo non trovato
NotChanged: Indirizzo non cambiato
Username:
AlreadyExists: Nome utente già preso
Reserved: Il nome utente è già preso
Empty: Il nome utente è vuoto
Password:
ConfirmationWrong: La conferma della password è sbagliata
Empty: La password è vuota

View File

@@ -328,6 +328,33 @@ Errors:
Invalid: Nieprawidłowe dane użytkownika
DomainNotAllowedAsUsername: Domena jest już zarezerwowana i nie może być użyta
NotAllowedToLink: Użytkownik nie jest upoważniony do łączenia z zewnętrznym dostawcą logowania
Profile:
NotFound: Profil nie znaleziony
NotChanged: Profil nie zmieniony
Empty: Profil jest pusty
FirstNameEmpty: Imię w profilu jest puste
LastNameEmpty: Nazwisko w profilu jest puste
IDMissing: Profil ID brakuje
Email:
NotFound: Adres e-mail nie znaleziony
Invalid: Adres e-mail jest nieprawidłowy
AlreadyVerified: Adres e-mail jest już zweryfikowany
NotChanged: Adres e-mail nie zmieniony
Empty: Adres e-mail jest pusty
IDMissing: Adres e-mail ID brakuje
Phone:
NotFound: Numer telefonu nie znaleziony
Invalid: Numer telefonu jest nieprawidłowy
AlreadyVerified: Numer telefonu już zweryfikowany
Empty: Numer telefonu jest pusty
NotChanged: Numer telefonu nie zmieniony
Address:
NotFound: Adres nie znaleziony
NotChanged: Adres nie zmieniony
Username:
AlreadyExists: Nazwa użytkownika jest już zajęta
Reserved: Nazwa użytkownika jest już zajęta
Empty: Nazwa użytkownika jest pusty
Password:
ConfirmationWrong: Potwierdzenie hasła jest niepoprawne
Empty: Hasło jest puste

View File

@@ -328,6 +328,33 @@ Errors:
Invalid: 无效的用户数据
DomainNotAllowedAsUsername: 域名已存在,但无法使用
NotAllowedToLink: 不允许用户使用外部身份提供者注册
Profile:
NotFound: 未找到个人资料
NotChanged: 个人资料未更改
Empty: 简介是空的
FirstNameEmpty: 简介中的名字是空的
LastNameEmpty: 简介中的姓氏是空的
IDMissing: 简介ID丢失
Email:
NotFound: 电子邮件没有找到
Invalid: 电子邮件无效
AlreadyVerified: 电子邮件已经过验证
NotChanged: 电子邮件未更改
Empty: 电子邮件是空的
IDMissing: 电子邮件ID丢失
Phone:
NotFound: 手机号码未找到
Invalid: 手机号码无效
AlreadyVerified: 手机号码已经验证
Empty: 电话号码是空的
NotChanged: 电话号码没有改变
Address:
NotFound: 找不到地址
NotChanged: 地址没有改变
Username:
AlreadyExists: 用户名已被使用
Reserved: 用户名已被使用
Empty: 用户名是空的
Password:
ConfirmationWrong: 密码不一致
Empty: 密码为空