From 5ee5299a6861ab303d305ba4ec678da57e1a69a3 Mon Sep 17 00:00:00 2001 From: Yang Luo Date: Sun, 19 Dec 2021 22:30:54 +0800 Subject: [PATCH] Improve syncer code. --- object/syncer_public_api.go | 10 ++ object/syncer_sync.go | 9 +- object/syncer_user.go | 58 +++++---- object/syncer_user_test.go | 2 +- object/syncer_util.go | 195 ++++++++++++++++++++++++------ object/user_cred.go | 16 ++- util/string.go | 17 +++ web/src/SyncerTableColumnTable.js | 6 +- 8 files changed, 230 insertions(+), 83 deletions(-) diff --git a/object/syncer_public_api.go b/object/syncer_public_api.go index 6ac6be1e..6d36af20 100644 --- a/object/syncer_public_api.go +++ b/object/syncer_public_api.go @@ -16,6 +16,16 @@ package object import "fmt" +func getDbSyncerForUser(user *User) *Syncer { + syncers := GetSyncers("admin") + for _, syncer := range syncers { + if syncer.Organization == user.Owner && syncer.IsEnabled && syncer.Type == "Database" { + return syncer + } + } + return nil +} + func getEnabledSyncerForOrganization(organization string) *Syncer { syncers := GetSyncers("admin") for _, syncer := range syncers { diff --git a/object/syncer_sync.go b/object/syncer_sync.go index 30061644..8d7ab01b 100644 --- a/object/syncer_sync.go +++ b/object/syncer_sync.go @@ -14,23 +14,20 @@ package object -import ( - "fmt" - "strconv" -) +import "fmt" func (syncer *Syncer) syncUsers() { fmt.Printf("Running syncUsers()..\n") users, userMap := syncer.getUserMap() - oUsers, oUserMap := syncer.getUserMapOriginal() + oUsers, oUserMap := syncer.getOriginalUserMap() fmt.Printf("Users: %d, oUsers: %d\n", len(users), len(oUsers)) _, affiliationMap := syncer.getAffiliationMap() newUsers := []*User{} for _, oUser := range oUsers { - id := strconv.Itoa(oUser.Id) + id := oUser.Id if _, ok := userMap[id]; !ok { newUser := syncer.createUserFromOriginalUser(oUser, affiliationMap) fmt.Printf("New user: %v\n", newUser) diff --git a/object/syncer_user.go b/object/syncer_user.go index 6d1dd863..93fecacb 100644 --- a/object/syncer_user.go +++ b/object/syncer_user.go @@ -16,7 +16,6 @@ package object import ( "fmt" - "strconv" "strings" "time" @@ -24,38 +23,31 @@ import ( "github.com/casbin/casdoor/util" ) -type DbUser struct { - Id int `xorm:"int notnull pk autoincr" json:"id"` - Name string `xorm:"varchar(128)" json:"name"` - Password string `xorm:"varchar(128)" json:"password"` - Cellphone string `xorm:"varchar(128)" json:"cellphone"` - SchoolId int `json:"schoolId"` - Avatar string `xorm:"varchar(128)" json:"avatar"` - Deleted int `xorm:"tinyint(1)" json:"deleted"` -} +type OriginalUser = User -func (syncer *Syncer) getUsersOriginal() []*DbUser { - users := []*DbUser{} - err := syncer.Adapter.Engine.Table(syncer.Table).Asc("id").Find(&users) +func (syncer *Syncer) getOriginalUsers() []*OriginalUser { + sql := fmt.Sprintf("select * from %s", syncer.Table) + results, err := syncer.Adapter.Engine.QueryString(sql) if err != nil { panic(err) } - return users + return syncer.getOriginalUsersFromMap(results) } -func (syncer *Syncer) getUserMapOriginal() ([]*DbUser, map[string]*DbUser) { - users := syncer.getUsersOriginal() +func (syncer *Syncer) getOriginalUserMap() ([]*OriginalUser, map[string]*OriginalUser) { + users := syncer.getOriginalUsers() - m := map[string]*DbUser{} + m := map[string]*OriginalUser{} for _, user := range users { - m[strconv.Itoa(user.Id)] = user + m[user.Id] = user } return users, m } -func (syncer *Syncer) addUser(user *DbUser) bool { - affected, err := syncer.Adapter.Engine.Table(syncer.Table).Insert(user) +func (syncer *Syncer) addUser(user *OriginalUser) bool { + m := syncer.getMapFromOriginalUser(user) + affected, err := syncer.Adapter.Engine.Table(syncer.Table).Insert(m) if err != nil { panic(err) } @@ -63,8 +55,20 @@ func (syncer *Syncer) addUser(user *DbUser) bool { return affected != 0 } -func (syncer *Syncer) updateUser(user *DbUser) bool { - affected, err := syncer.Adapter.Engine.Table(syncer.Table).ID(user.Id).Cols("name", "password", "cellphone", "school_id", "avatar", "deleted").Update(user) +func (syncer *Syncer) getActiveColumns() []string { + res := []string{} + for _, tableColumn := range syncer.TableColumns { + if tableColumn.CasdoorName != "Id" { + res = append(res, tableColumn.Name) + } + } + return res +} + +func (syncer *Syncer) updateUser(user *OriginalUser) bool { + m := syncer.getMapFromOriginalUser(user) + columns := syncer.getActiveColumns() + affected, err := syncer.Adapter.Engine.Table(syncer.Table).ID(user.Id).Cols(columns...).Update(m) if err != nil { panic(err) } @@ -72,8 +76,14 @@ func (syncer *Syncer) updateUser(user *DbUser) bool { return affected != 0 } -func (syncer *Syncer) calculateHash(user *DbUser) string { - s := strings.Join([]string{strconv.Itoa(user.Id), user.Password, user.Name, syncer.getFullAvatarUrl(user.Avatar), user.Cellphone, strconv.Itoa(user.SchoolId)}, "|") +func (syncer *Syncer) calculateHash(user *OriginalUser) string { + values := []string{} + m := syncer.getMapFromOriginalUser(user) + for _, tableColumn := range syncer.TableColumns { + values = append(values, m[tableColumn.Name]) + } + + s := strings.Join(values, "|") return util.GetMd5Hash(s) } diff --git a/object/syncer_user_test.go b/object/syncer_user_test.go index 741cded0..58ab63a9 100644 --- a/object/syncer_user_test.go +++ b/object/syncer_user_test.go @@ -25,7 +25,7 @@ func TestGetUsers(t *testing.T) { syncers := GetSyncers("admin") syncer := syncers[0] syncer.initAdapter() - users := syncer.getUsersOriginal() + users := syncer.getOriginalUsers() for _, user := range users { fmt.Printf("%v\n", user) } diff --git a/object/syncer_util.go b/object/syncer_util.go index 498b0104..796a0e7f 100644 --- a/object/syncer_util.go +++ b/object/syncer_util.go @@ -23,6 +23,10 @@ import ( ) func (syncer *Syncer) getFullAvatarUrl(avatar string) string { + if syncer.AvatarBaseUrl == "" { + return avatar + } + if !strings.HasPrefix(avatar, "https://") { return fmt.Sprintf("%s%s", syncer.AvatarBaseUrl, avatar) } @@ -36,53 +40,164 @@ func (syncer *Syncer) getPartialAvatarUrl(avatar string) string { return avatar } -func (syncer *Syncer) createUserFromOriginalUser(originalUser *DbUser, affiliationMap map[int]string) *User { - affiliation := "" - if originalUser.SchoolId != 0 { - var ok bool - affiliation, ok = affiliationMap[originalUser.SchoolId] +func (syncer *Syncer) createUserFromOriginalUser(originalUser *OriginalUser, affiliationMap map[int]string) *User { + user := *originalUser + user.Owner = syncer.Organization + if user.Name == "" { + user.Name = originalUser.Id + } + if user.CreatedTime == "" { + user.CreatedTime = util.GetCurrentTime() + } + if user.Type == "" { + user.Type = "normal-user" + } + if originalUser.Score != 0 { + affiliation, ok := affiliationMap[originalUser.Score] if !ok { - panic(fmt.Sprintf("SchoolId not found: %d", originalUser.SchoolId)) + panic(fmt.Sprintf("Affiliation not found: %d", originalUser.Score)) } + user.Affiliation = affiliation } + if user.Properties == nil { + user.Properties = map[string]string{} + } + return &user +} - user := &User{ - Owner: syncer.Organization, - Name: strconv.Itoa(originalUser.Id), - CreatedTime: util.GetCurrentTime(), - Id: strconv.Itoa(originalUser.Id), - Type: "normal-user", - Password: originalUser.Password, - DisplayName: originalUser.Name, - Avatar: syncer.getFullAvatarUrl(originalUser.Avatar), - Email: "", - Phone: originalUser.Cellphone, - Address: []string{}, - Affiliation: affiliation, - Score: originalUser.SchoolId, - IsAdmin: false, - IsGlobalAdmin: false, - IsForbidden: originalUser.Deleted != 0, - IsDeleted: false, - Properties: map[string]string{}, - } +func (syncer *Syncer) createOriginalUserFromUser(user *User) *OriginalUser { return user } -func (syncer *Syncer) createOriginalUserFromUser(user *User) *DbUser { - deleted := 0 - if user.IsForbidden { - deleted = 1 +func (syncer *Syncer) setUserByKeyValue(user *User, key string, value string) { + switch key { + case "Name": + user.Name = value + case "CreatedTime": + user.CreatedTime = value + case "UpdatedTime": + user.UpdatedTime = value + case "Id": + user.Id = value + case "Type": + user.Type = value + case "Password": + user.Password = value + case "PasswordSalt": + user.PasswordSalt = value + case "DisplayName": + user.DisplayName = value + case "Avatar": + user.Avatar = syncer.getPartialAvatarUrl(value) + case "PermanentAvatar": + user.PermanentAvatar = value + case "Email": + user.Email = value + case "Phone": + user.Phone = value + case "Location": + user.Location = value + case "Address": + user.Address = []string{value} + case "Affiliation": + user.Affiliation = value + case "Title": + user.Title = value + case "IdCardType": + user.IdCardType = value + case "IdCard": + user.IdCard = value + case "Homepage": + user.Homepage = value + case "Bio": + user.Bio = value + case "Tag": + user.Tag = value + case "Region": + user.Region = value + case "Language": + user.Language = value + case "Gender": + user.Gender = value + case "Birthday": + user.Birthday = value + case "Education": + user.Education = value + case "Score": + user.Score = util.ParseInt(value) + case "Ranking": + user.Ranking = util.ParseInt(value) + case "IsDefaultAvatar": + user.IsDefaultAvatar = util.ParseBool(value) + case "IsOnline": + user.IsOnline = util.ParseBool(value) + case "IsAdmin": + user.IsAdmin = util.ParseBool(value) + case "IsGlobalAdmin": + user.IsGlobalAdmin = util.ParseBool(value) + case "IsForbidden": + user.IsForbidden = util.ParseBool(value) + case "IsDeleted": + user.IsDeleted = util.ParseBool(value) + case "CreatedIp": + user.CreatedIp = value + } +} + +func (syncer *Syncer) getOriginalUsersFromMap(results []map[string]string) []*OriginalUser { + users := []*OriginalUser{} + for _, result := range results { + originalUser := &OriginalUser{} + for _, tableColumn := range syncer.TableColumns { + syncer.setUserByKeyValue(originalUser, tableColumn.CasdoorName, result[tableColumn.Name]) + } + users = append(users, originalUser) + } + return users +} + +func (syncer *Syncer) getMapFromOriginalUser(user *OriginalUser) map[string]string { + m := map[string]string{} + m["Name"] = user.Name + m["CreatedTime"] = user.CreatedTime + m["UpdatedTime"] = user.UpdatedTime + m["Id"] = user.Id + m["Type"] = user.Type + m["Password"] = user.Password + m["PasswordSalt"] = user.PasswordSalt + m["DisplayName"] = user.DisplayName + m["Avatar"] = syncer.getFullAvatarUrl(user.Avatar) + m["PermanentAvatar"] = user.PermanentAvatar + m["Email"] = user.Email + m["Phone"] = user.Phone + m["Location"] = user.Location + m["Address"] = strings.Join(user.Address, "|") + m["Affiliation"] = user.Affiliation + m["Title"] = user.Title + m["IdCardType"] = user.IdCardType + m["IdCard"] = user.IdCard + m["Homepage"] = user.Homepage + m["Bio"] = user.Bio + m["Tag"] = user.Tag + m["Region"] = user.Region + m["Language"] = user.Language + m["Gender"] = user.Gender + m["Birthday"] = user.Birthday + m["Education"] = user.Education + m["Score"] = strconv.Itoa(user.Score) + m["Ranking"] = strconv.Itoa(user.Ranking) + m["IsDefaultAvatar"] = util.BoolToString(user.IsDefaultAvatar) + m["IsOnline"] = util.BoolToString(user.IsOnline) + m["IsAdmin"] = util.BoolToString(user.IsAdmin) + m["IsGlobalAdmin"] = util.BoolToString(user.IsGlobalAdmin) + m["IsForbidden"] = util.BoolToString(user.IsForbidden) + m["IsDeleted"] = util.BoolToString(user.IsDeleted) + m["CreatedIp"] = user.CreatedIp + + m2 := map[string]string{} + for _, tableColumn := range syncer.TableColumns { + m2[tableColumn.CasdoorName] = m[tableColumn.CasdoorName] } - originalUser := &DbUser{ - Id: util.ParseInt(user.Id), - Name: user.DisplayName, - Password: user.Password, - Cellphone: user.Phone, - SchoolId: user.Score, - Avatar: syncer.getPartialAvatarUrl(user.Avatar), - Deleted: deleted, - } - return originalUser + return m2 } diff --git a/object/user_cred.go b/object/user_cred.go index 70dbc203..5e4c7a02 100644 --- a/object/user_cred.go +++ b/object/user_cred.go @@ -14,17 +14,15 @@ package object -import ( - "strconv" - "strings" - - "github.com/casbin/casdoor/cred" - "github.com/casbin/casdoor/util" -) +import "github.com/casbin/casdoor/cred" func calculateHash(user *User) string { - s := strings.Join([]string{user.Id, user.Password, user.DisplayName, user.Avatar, user.Phone, strconv.Itoa(user.Score)}, "|") - return util.GetMd5Hash(s) + syncer := getDbSyncerForUser(user) + if syncer == nil { + return "" + } + + return syncer.calculateHash(user) } func (user *User) UpdateUserHash() { diff --git a/util/string.go b/util/string.go index ab64d7a9..ebd47bd1 100644 --- a/util/string.go +++ b/util/string.go @@ -27,6 +27,10 @@ import ( ) func ParseInt(s string) int { + if s == "" { + return 0 + } + i, err := strconv.Atoi(s) if err != nil { panic(err) @@ -35,6 +39,19 @@ func ParseInt(s string) int { return i } +func ParseBool(s string) bool { + i := ParseInt(s) + return i != 0 +} + +func BoolToString(b bool) string { + if b { + return "1" + } else { + return "0" + } +} + func GetOwnerAndNameFromId(id string) (string, string) { tokens := strings.Split(id, "/") if len(tokens) != 2 { diff --git a/web/src/SyncerTableColumnTable.js b/web/src/SyncerTableColumnTable.js index 304ddea6..61d25d00 100644 --- a/web/src/SyncerTableColumnTable.js +++ b/web/src/SyncerTableColumnTable.js @@ -98,9 +98,9 @@ class SyncerTableColumnTable extends React.Component { return (