feat: fixes (#228)

* feat: user login names

* fix: user login names

* fix: generate login name
This commit is contained in:
Fabi
2020-06-17 07:25:04 +02:00
committed by GitHub
parent f2cdae9ea3
commit 6fa62ccd0a
31 changed files with 7131 additions and 4888 deletions

View File

@@ -2,11 +2,13 @@ package eventstore
import (
"context"
"github.com/caos/logging"
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/sdk"
org_model "github.com/caos/zitadel/internal/org/model"
org_event "github.com/caos/zitadel/internal/org/repository/eventsourcing"
usr_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
usr_view_model "github.com/caos/zitadel/internal/user/repository/view/model"
"github.com/caos/zitadel/internal/api/auth"
"github.com/caos/zitadel/internal/auth/repository/eventsourcing/view"
@@ -63,7 +65,11 @@ func (repo *UserRepo) Register(ctx context.Context, registerUser *model.User, or
}
func (repo *UserRepo) MyProfile(ctx context.Context) (*model.Profile, error) {
return repo.UserEvents.ProfileByID(ctx, auth.GetCtxData(ctx).UserID)
user, err := repo.UserByID(ctx, auth.GetCtxData(ctx).UserID)
if err != nil {
return nil, err
}
return user.GetProfile(), nil
}
func (repo *UserRepo) ChangeMyProfile(ctx context.Context, profile *model.Profile) (*model.Profile, error) {
@@ -74,7 +80,11 @@ func (repo *UserRepo) ChangeMyProfile(ctx context.Context, profile *model.Profil
}
func (repo *UserRepo) MyEmail(ctx context.Context) (*model.Email, error) {
return repo.UserEvents.EmailByID(ctx, auth.GetCtxData(ctx).UserID)
user, err := repo.UserByID(ctx, auth.GetCtxData(ctx).UserID)
if err != nil {
return nil, err
}
return user.GetEmail(), nil
}
func (repo *UserRepo) ChangeMyEmail(ctx context.Context, email *model.Email) (*model.Email, error) {
@@ -101,7 +111,11 @@ func (repo *UserRepo) ResendMyEmailVerificationMail(ctx context.Context) error {
}
func (repo *UserRepo) MyPhone(ctx context.Context) (*model.Phone, error) {
return repo.UserEvents.PhoneByID(ctx, auth.GetCtxData(ctx).UserID)
user, err := repo.UserByID(ctx, auth.GetCtxData(ctx).UserID)
if err != nil {
return nil, err
}
return user.GetPhone(), nil
}
func (repo *UserRepo) ChangeMyPhone(ctx context.Context, phone *model.Phone) (*model.Phone, error) {
@@ -120,7 +134,11 @@ func (repo *UserRepo) ResendMyPhoneVerificationCode(ctx context.Context) error {
}
func (repo *UserRepo) MyAddress(ctx context.Context) (*model.Address, error) {
return repo.UserEvents.AddressByID(ctx, auth.GetCtxData(ctx).UserID)
user, err := repo.UserByID(ctx, auth.GetCtxData(ctx).UserID)
if err != nil {
return nil, err
}
return user.GetAddress(), nil
}
func (repo *UserRepo) ChangeMyAddress(ctx context.Context, address *model.Address) (*model.Address, error) {
@@ -205,8 +223,23 @@ func (repo *UserRepo) SignOut(ctx context.Context, agentID, userID string) error
return repo.UserEvents.SignOut(ctx, agentID, userID)
}
func (repo *UserRepo) UserByID(ctx context.Context, userID string) (*model.User, error) {
return repo.UserEvents.UserByID(ctx, userID)
func (repo *UserRepo) UserByID(ctx context.Context, id string) (*model.UserView, error) {
user, err := repo.View.UserByID(id)
if err != nil {
return nil, err
}
events, err := repo.UserEvents.UserEventsByID(ctx, id, user.Sequence)
if err != nil {
logging.Log("EVENT-PSoc3").WithError(err).Debug("error retrieving new events")
return usr_view_model.UserToModel(user), nil
}
userCopy := *user
for _, event := range events {
if err := userCopy.AppendEvent(event); err != nil {
return usr_view_model.UserToModel(user), nil
}
}
return usr_view_model.UserToModel(&userCopy), nil
}
func checkIDs(ctx context.Context, obj es_models.ObjectRoot) error {

View File

@@ -101,23 +101,11 @@ func (u *User) fillLoginNames(user *view_model.UserView) (err error) {
if err != nil {
return err
}
user.LoginNames = getLoginNames(policy, user.UserName, org.Domains)
user.SetLoginNames(policy, org.Domains)
user.PreferredLoginName = user.GenerateLoginName(org.GetPrimaryDomain().Domain)
return nil
}
func getLoginNames(policy *org_model.OrgIamPolicy, userName string, domains []*org_model.OrgDomain) []string {
loginNames := make([]string, 0)
if !policy.UserLoginMustBeDomain {
return []string{userName}
}
for _, d := range domains {
if d.Verified {
loginNames = append(loginNames, userName+"@"+d.Domain)
}
}
return loginNames
}
func (u *User) ProcessOrg(event *models.Event) (err error) {
switch event.Type {
case org_es_model.OrgDomainVerified,
@@ -126,6 +114,8 @@ func (u *User) ProcessOrg(event *models.Event) (err error) {
org_es_model.OrgIamPolicyChanged,
org_es_model.OrgIamPolicyRemoved:
return u.fillLoginNamesOnOrgUsers(event)
case org_es_model.OrgDomainPrimarySet:
return u.fillPreferredLoginNamesOnOrgUsers(event)
default:
return u.view.ProcessedUserSequence(event.Sequence)
}
@@ -134,6 +124,7 @@ func (u *User) ProcessOrg(event *models.Event) (err error) {
}
return nil
}
func (u *User) fillLoginNamesOnOrgUsers(event *models.Event) error {
org, err := u.orgEvents.OrgByID(context.Background(), org_model.NewOrg(event.ResourceOwner))
if err != nil {
@@ -148,7 +139,7 @@ func (u *User) fillLoginNamesOnOrgUsers(event *models.Event) error {
return err
}
for _, user := range users {
user.LoginNames = getLoginNames(policy, user.UserName, org.Domains)
user.SetLoginNames(policy, org.Domains)
err := u.view.PutUser(user, event.Sequence)
if err != nil {
return err
@@ -157,6 +148,32 @@ func (u *User) fillLoginNamesOnOrgUsers(event *models.Event) error {
return nil
}
func (u *User) fillPreferredLoginNamesOnOrgUsers(event *models.Event) error {
org, err := u.orgEvents.OrgByID(context.Background(), org_model.NewOrg(event.ResourceOwner))
if err != nil {
return err
}
policy, err := u.orgEvents.GetOrgIamPolicy(context.Background(), event.ResourceOwner)
if err != nil {
return err
}
if !policy.UserLoginMustBeDomain {
return nil
}
users, err := u.view.UsersByOrgID(event.AggregateID)
if err != nil {
return err
}
for _, user := range users {
user.PreferredLoginName = user.GenerateLoginName(org.GetPrimaryDomain().Domain)
err := u.view.PutUser(user, 0)
if err != nil {
return err
}
}
return nil
}
func (p *User) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-is8wa", "id", event.AggregateID).WithError(err).Warn("something went wrong in user handler")
return spooler.HandleError(event, err, p.view.GetLatestUserFailedEvent, p.view.ProcessedUserFailedEvent, p.view.ProcessedUserSequence, p.errorCountUntilSkip)

View File

@@ -25,7 +25,7 @@ type UserRepository interface {
SignOut(ctx context.Context, agentID, userID string) error
UserByID(ctx context.Context, userID string) (*model.User, error)
UserByID(ctx context.Context, userID string) (*model.UserView, error)
}
type myUserRepo interface {

View File

@@ -2,6 +2,7 @@ package eventstore
import (
"context"
"github.com/caos/logging"
"github.com/caos/zitadel/internal/api/auth"
"github.com/caos/zitadel/internal/management/repository/eventsourcing/view"
@@ -20,8 +21,23 @@ type UserRepo struct {
View *view.View
}
func (repo *UserRepo) UserByID(ctx context.Context, id string) (project *usr_model.User, err error) {
return repo.UserEvents.UserByID(ctx, id)
func (repo *UserRepo) UserByID(ctx context.Context, id string) (*usr_model.UserView, error) {
user, err := repo.View.UserByID(id)
if err != nil {
return nil, err
}
events, err := repo.UserEvents.UserEventsByID(ctx, id, user.Sequence)
if err != nil {
logging.Log("EVENT-PSoc3").WithError(err).Debug("error retrieving new events")
return model.UserToModel(user), nil
}
userCopy := *user
for _, event := range events {
if err := userCopy.AppendEvent(event); err != nil {
return model.UserToModel(user), nil
}
}
return model.UserToModel(&userCopy), nil
}
func (repo *UserRepo) CreateUser(ctx context.Context, user *usr_model.User) (*usr_model.User, error) {
@@ -119,7 +135,11 @@ func (repo *UserRepo) RequestSetPassword(ctx context.Context, id string, notifyT
}
func (repo *UserRepo) ProfileByID(ctx context.Context, userID string) (*usr_model.Profile, error) {
return repo.UserEvents.ProfileByID(ctx, userID)
user, err := repo.UserByID(ctx, userID)
if err != nil {
return nil, err
}
return user.GetProfile(), nil
}
func (repo *UserRepo) ChangeProfile(ctx context.Context, profile *usr_model.Profile) (*usr_model.Profile, error) {
@@ -127,7 +147,11 @@ func (repo *UserRepo) ChangeProfile(ctx context.Context, profile *usr_model.Prof
}
func (repo *UserRepo) EmailByID(ctx context.Context, userID string) (*usr_model.Email, error) {
return repo.UserEvents.EmailByID(ctx, userID)
user, err := repo.UserByID(ctx, userID)
if err != nil {
return nil, err
}
return user.GetEmail(), nil
}
func (repo *UserRepo) ChangeEmail(ctx context.Context, email *usr_model.Email) (*usr_model.Email, error) {
@@ -139,7 +163,11 @@ func (repo *UserRepo) CreateEmailVerificationCode(ctx context.Context, userID st
}
func (repo *UserRepo) PhoneByID(ctx context.Context, userID string) (*usr_model.Phone, error) {
return repo.UserEvents.PhoneByID(ctx, userID)
user, err := repo.UserByID(ctx, userID)
if err != nil {
return nil, err
}
return user.GetPhone(), nil
}
func (repo *UserRepo) ChangePhone(ctx context.Context, email *usr_model.Phone) (*usr_model.Phone, error) {
@@ -151,7 +179,11 @@ func (repo *UserRepo) CreatePhoneVerificationCode(ctx context.Context, userID st
}
func (repo *UserRepo) AddressByID(ctx context.Context, userID string) (*usr_model.Address, error) {
return repo.UserEvents.AddressByID(ctx, userID)
user, err := repo.UserByID(ctx, userID)
if err != nil {
return nil, err
}
return user.GetAddress(), nil
}
func (repo *UserRepo) ChangeAddress(ctx context.Context, address *usr_model.Address) (*usr_model.Address, error) {

View File

@@ -39,7 +39,7 @@ func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, ev
&ProjectMember{handler: handler{view, bulkLimit, configs.cycleDuration("ProjectMember"), errorCount}, userEvents: repos.UserEvents},
&ProjectGrantMember{handler: handler{view, bulkLimit, configs.cycleDuration("ProjectGrantMember"), errorCount}, userEvents: repos.UserEvents},
&Application{handler: handler{view, bulkLimit, configs.cycleDuration("Application"), errorCount}, projectEvents: repos.ProjectEvents},
&User{handler: handler{view, bulkLimit, configs.cycleDuration("User"), errorCount}, eventstore: eventstore},
&User{handler: handler{view, bulkLimit, configs.cycleDuration("User"), errorCount}, eventstore: eventstore, orgEvents: repos.OrgEvents},
&UserGrant{handler: handler{view, bulkLimit, configs.cycleDuration("UserGrant"), errorCount}, projectEvents: repos.ProjectEvents, userEvents: repos.UserEvents, orgEvents: repos.OrgEvents},
&Org{handler: handler{view, bulkLimit, configs.cycleDuration("Org"), errorCount}},
&OrgMember{handler: handler{view, bulkLimit, configs.cycleDuration("OrgMember"), errorCount}, userEvents: repos.UserEvents},

View File

@@ -1,6 +1,11 @@
package handler
import (
"context"
es_models "github.com/caos/zitadel/internal/eventstore/models"
org_model "github.com/caos/zitadel/internal/org/model"
org_events "github.com/caos/zitadel/internal/org/repository/eventsourcing"
org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
"time"
@@ -9,13 +14,13 @@ import (
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/eventstore/spooler"
"github.com/caos/zitadel/internal/user/repository/eventsourcing"
view_model "github.com/caos/zitadel/internal/user/repository/view/model"
)
type User struct {
handler
eventstore eventstore.Eventstore
orgEvents *org_events.OrgEventstore
}
const (
@@ -33,15 +38,29 @@ func (p *User) EventQuery() (*models.SearchQuery, error) {
if err != nil {
return nil, err
}
return eventsourcing.UserQuery(sequence), nil
return es_models.NewSearchQuery().
AggregateTypeFilter(es_model.UserAggregate, org_es_model.OrgAggregate).
LatestSequenceFilter(sequence), nil
}
func (p *User) Process(event *models.Event) (err error) {
func (u *User) Process(event *models.Event) (err error) {
switch event.AggregateType {
case es_model.UserAggregate:
return u.ProcessUser(event)
case org_es_model.OrgAggregate:
return u.ProcessOrg(event)
default:
return nil
}
}
func (p *User) ProcessUser(event *models.Event) (err error) {
user := new(view_model.UserView)
switch event.Type {
case es_model.UserAdded,
es_model.UserRegistered:
user.AppendEvent(event)
p.fillLoginNames(user)
case es_model.UserProfileChanged,
es_model.UserEmailChanged,
es_model.UserEmailVerified,
@@ -68,7 +87,89 @@ func (p *User) Process(event *models.Event) (err error) {
if err != nil {
return err
}
return p.view.PutUser(user)
return p.view.PutUser(user, user.Sequence)
}
func (u *User) ProcessOrg(event *models.Event) (err error) {
switch event.Type {
case org_es_model.OrgDomainVerified,
org_es_model.OrgDomainRemoved,
org_es_model.OrgIamPolicyAdded,
org_es_model.OrgIamPolicyChanged,
org_es_model.OrgIamPolicyRemoved:
return u.fillLoginNamesOnOrgUsers(event)
case org_es_model.OrgDomainPrimarySet:
return u.fillPreferredLoginNamesOnOrgUsers(event)
default:
return u.view.ProcessedUserSequence(event.Sequence)
}
if err != nil {
return err
}
return nil
}
func (u *User) fillLoginNamesOnOrgUsers(event *models.Event) error {
org, err := u.orgEvents.OrgByID(context.Background(), org_model.NewOrg(event.ResourceOwner))
if err != nil {
return err
}
policy, err := u.orgEvents.GetOrgIamPolicy(context.Background(), event.ResourceOwner)
if err != nil {
return err
}
users, err := u.view.UsersByOrgID(event.AggregateID)
if err != nil {
return err
}
for _, user := range users {
user.SetLoginNames(policy, org.Domains)
err := u.view.PutUser(user, 0)
if err != nil {
return err
}
}
return nil
}
func (u *User) fillPreferredLoginNamesOnOrgUsers(event *models.Event) error {
org, err := u.orgEvents.OrgByID(context.Background(), org_model.NewOrg(event.ResourceOwner))
if err != nil {
return err
}
policy, err := u.orgEvents.GetOrgIamPolicy(context.Background(), event.ResourceOwner)
if err != nil {
return err
}
if !policy.UserLoginMustBeDomain {
return nil
}
users, err := u.view.UsersByOrgID(event.AggregateID)
if err != nil {
return err
}
for _, user := range users {
user.PreferredLoginName = user.GenerateLoginName(org.GetPrimaryDomain().Domain)
err := u.view.PutUser(user, 0)
if err != nil {
return err
}
}
return nil
}
func (u *User) fillLoginNames(user *view_model.UserView) (err error) {
org, err := u.orgEvents.OrgByID(context.Background(), org_model.NewOrg(user.ResourceOwner))
if err != nil {
return err
}
policy, err := u.orgEvents.GetOrgIamPolicy(context.Background(), user.ResourceOwner)
if err != nil {
return err
}
user.SetLoginNames(policy, org.Domains)
user.PreferredLoginName = user.GenerateLoginName(org.GetPrimaryDomain().Domain)
return nil
}
func (p *User) OnError(event *models.Event, err error) error {

View File

@@ -23,6 +23,10 @@ func (v *View) GetGlobalUserByEmail(email string) (*model.UserView, error) {
return view.GetGlobalUserByEmail(v.Db, userTable, email)
}
func (v *View) UsersByOrgID(orgID string) ([]*model.UserView, error) {
return view.UsersByOrgID(v.Db, userTable, orgID)
}
func (v *View) IsUserUnique(userName, email string) (bool, error) {
return view.IsUserUnique(v.Db, userTable, userName, email)
}
@@ -31,12 +35,15 @@ func (v *View) UserMfas(userID string) ([]*usr_model.MultiFactor, error) {
return view.UserMfas(v.Db, userTable, userID)
}
func (v *View) PutUser(user *model.UserView) error {
func (v *View) PutUser(user *model.UserView, sequence uint64) error {
err := view.PutUser(v.Db, userTable, user)
if err != nil {
return err
}
return v.ProcessedUserSequence(user.Sequence)
if sequence != 0 {
return v.ProcessedUserSequence(sequence)
}
return nil
}
func (v *View) DeleteUser(userID string, eventSequence uint64) error {

View File

@@ -7,7 +7,7 @@ import (
)
type UserRepository interface {
UserByID(ctx context.Context, id string) (*model.User, error)
UserByID(ctx context.Context, id string) (*model.UserView, error)
CreateUser(ctx context.Context, user *model.User) (*model.User, error)
RegisterUser(ctx context.Context, user *model.User, resourceOwner string) (*model.User, error)
DeactivateUser(ctx context.Context, id string) (*model.User, error)

View File

@@ -2,8 +2,8 @@ package model
import (
es_models "github.com/caos/zitadel/internal/eventstore/models"
"strings"
"github.com/golang/protobuf/ptypes/timestamp"
"strings"
)
type Org struct {
@@ -57,6 +57,15 @@ func (o *Org) ContainsDomain(domain *OrgDomain) bool {
return false
}
func (o *Org) GetPrimaryDomain() *OrgDomain {
for _, d := range o.Domains {
if d.Primary {
return d
}
}
return nil
}
func (o *Org) ContainsMember(userID string) bool {
for _, member := range o.Members {
if member.UserID == userID {

View File

@@ -8,13 +8,15 @@ import (
type Profile struct {
es_models.ObjectRoot
UserName string
FirstName string
LastName string
NickName string
DisplayName string
PreferredLanguage language.Tag
Gender Gender
UserName string
FirstName string
LastName string
NickName string
DisplayName string
PreferredLanguage language.Tag
Gender Gender
PreferredLoginName string
LoginNames []string
}
func (p *Profile) IsValid() bool {

View File

@@ -1,6 +1,8 @@
package model
import (
"github.com/caos/zitadel/internal/eventstore/models"
"golang.org/x/text/language"
"time"
req_model "github.com/caos/zitadel/internal/auth_request/model"
@@ -18,6 +20,7 @@ type UserView struct {
PasswordChanged time.Time
LastLogin time.Time
UserName string
PreferredLoginName string
LoginNames []string
FirstName string
LastName string
@@ -121,3 +124,69 @@ func (u *UserView) MfaTypesAllowed(level req_model.MfaLevel) []req_model.MfaType
}
return types
}
func (u *UserView) GetProfile() *Profile {
return &Profile{
ObjectRoot: models.ObjectRoot{
AggregateID: u.ID,
Sequence: u.Sequence,
ResourceOwner: u.ResourceOwner,
CreationDate: u.CreationDate,
ChangeDate: u.ChangeDate,
},
UserName: u.UserName,
FirstName: u.FirstName,
LastName: u.LastName,
NickName: u.NickName,
DisplayName: u.DisplayName,
PreferredLanguage: language.Make(u.PreferredLanguage),
Gender: u.Gender,
PreferredLoginName: u.PreferredLoginName,
LoginNames: u.LoginNames,
}
}
func (u *UserView) GetPhone() *Phone {
return &Phone{
ObjectRoot: models.ObjectRoot{
AggregateID: u.ID,
Sequence: u.Sequence,
ResourceOwner: u.ResourceOwner,
CreationDate: u.CreationDate,
ChangeDate: u.ChangeDate,
},
PhoneNumber: u.Phone,
IsPhoneVerified: u.IsPhoneVerified,
}
}
func (u *UserView) GetEmail() *Email {
return &Email{
ObjectRoot: models.ObjectRoot{
AggregateID: u.ID,
Sequence: u.Sequence,
ResourceOwner: u.ResourceOwner,
CreationDate: u.CreationDate,
ChangeDate: u.ChangeDate,
},
EmailAddress: u.Email,
IsEmailVerified: u.IsEmailVerified,
}
}
func (u *UserView) GetAddress() *Address {
return &Address{
ObjectRoot: models.ObjectRoot{
AggregateID: u.ID,
Sequence: u.Sequence,
ResourceOwner: u.ResourceOwner,
CreationDate: u.CreationDate,
ChangeDate: u.ChangeDate,
},
Country: u.Country,
Locality: u.Locality,
PostalCode: u.PostalCode,
Region: u.Region,
StreetAddress: u.StreetAddress,
}
}

View File

@@ -106,6 +106,9 @@ func (es *UserEventstore) UserEventsByID(ctx context.Context, id string, sequenc
func (es *UserEventstore) PrepareCreateUser(ctx context.Context, user *usr_model.User, pwPolicy *policy_model.PasswordComplexityPolicy, orgIamPolicy *org_model.OrgIamPolicy, resourceOwner string) (*model.User, []*es_models.Aggregate, error) {
err := user.CheckOrgIamPolicy(orgIamPolicy)
if err != nil {
return nil, nil, err
}
if !user.IsValid() {
return nil, nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-9dk45", "User is invalid")
}

View File

@@ -2,6 +2,7 @@ package model
import (
"encoding/json"
org_model "github.com/caos/zitadel/internal/org/model"
"github.com/lib/pq"
"time"
@@ -39,6 +40,7 @@ type UserView struct {
LastLogin time.Time `json:"-" gorm:"column:last_login"`
UserName string `json:"userName" gorm:"column:user_name"`
LoginNames pq.StringArray `json:"-" gorm:"column:login_names"`
PreferredLoginName string `json:"-" gorm:"column:preferred_login_name"`
FirstName string `json:"firstName" gorm:"column:first_name"`
LastName string `json:"lastName" gorm:"column:last_name"`
NickName string `json:"nickName" gorm:"column:nick_name"`
@@ -74,6 +76,7 @@ func UserFromModel(user *model.UserView) *UserView {
LastLogin: user.LastLogin,
UserName: user.UserName,
LoginNames: user.LoginNames,
PreferredLoginName: user.PreferredLoginName,
FirstName: user.FirstName,
LastName: user.LastName,
NickName: user.NickName,
@@ -108,6 +111,8 @@ func UserToModel(user *UserView) *model.UserView {
PasswordChangeRequired: user.PasswordChangeRequired,
PasswordChanged: user.PasswordChanged,
LastLogin: user.LastLogin,
PreferredLoginName: user.PreferredLoginName,
LoginNames: user.LoginNames,
UserName: user.UserName,
FirstName: user.FirstName,
LastName: user.LastName,
@@ -140,6 +145,24 @@ func UsersToModel(users []*UserView) []*model.UserView {
return result
}
func (u *UserView) GenerateLoginName(domain string) string {
return u.UserName + "@" + domain
}
func (u *UserView) SetLoginNames(policy *org_model.OrgIamPolicy, domains []*org_model.OrgDomain) {
loginNames := make([]string, 0)
if !policy.UserLoginMustBeDomain {
u.LoginNames = []string{u.UserName}
return
}
for _, d := range domains {
if d.Verified {
loginNames = append(loginNames, u.GenerateLoginName(d.Domain))
}
}
u.LoginNames = loginNames
}
func (u *UserView) AppendEvent(event *models.Event) (err error) {
u.ChangeDate = event.CreationDate
u.Sequence = event.Sequence