From 80b0d26813cdec29bd8ee27ab04dfe4b00dac57b Mon Sep 17 00:00:00 2001 From: Baihhh <63110802+Baihhh@users.noreply.github.com> Date: Sun, 13 Aug 2023 22:24:34 +0800 Subject: [PATCH] fix: synchronize update the syncers (#2201) Signed-off-by: baihhh <2542274498@qq.com> --- object/syncer.go | 22 +++++++++++++- object/syncer_sync.go | 62 ++++++++++++++++++++++++++++----------- object/syncer_user.go | 46 +++++++++++++++++++++-------- object/syncer_util.go | 28 ++++++++++++++++++ util/string.go | 11 +++++++ web/src/SyncerEditPage.js | 10 ------- 6 files changed, 138 insertions(+), 41 deletions(-) diff --git a/object/syncer.go b/object/syncer.go index cb82e510..23000d22 100644 --- a/object/syncer.go +++ b/object/syncer.go @@ -45,7 +45,6 @@ type Syncer struct { DatabaseType string `xorm:"varchar(100)" json:"databaseType"` Database string `xorm:"varchar(100)" json:"database"` Table string `xorm:"varchar(100)" json:"table"` - TablePrimaryKey string `xorm:"varchar(100)" json:"tablePrimaryKey"` TableColumns []*TableColumn `xorm:"mediumtext" json:"tableColumns"` AffiliationTable string `xorm:"varchar(100)" json:"affiliationTable"` AvatarBaseUrl string `xorm:"varchar(100)" json:"avatarBaseUrl"` @@ -230,6 +229,27 @@ func (syncer *Syncer) getTable() string { } } +func (syncer *Syncer) getKey() string { + key := "id" + hasKey := false + hasId := false + for _, tableColumn := range syncer.TableColumns { + if tableColumn.IsKey { + hasKey = true + key = tableColumn.Name + } + if tableColumn.Name == "id" { + hasId = true + } + } + + if !hasKey && !hasId { + key = syncer.TableColumns[0].Name + } + + return key +} + func RunSyncer(syncer *Syncer) { syncer.initAdapter() syncer.syncUsers() diff --git a/object/syncer_sync.go b/object/syncer_sync.go index 8a54a0a6..035935ff 100644 --- a/object/syncer_sync.go +++ b/object/syncer_sync.go @@ -20,16 +20,24 @@ import ( ) func (syncer *Syncer) syncUsers() { + if len(syncer.TableColumns) == 0 { + return + } + fmt.Printf("Running syncUsers()..\n") - users, userMap, userNameMap := syncer.getUserMap() + users, _, _ := syncer.getUserMap() oUsers, oUserMap, err := syncer.getOriginalUserMap() if err != nil { fmt.Printf(err.Error()) timestamp := time.Now().Format("2006-01-02 15:04:05") line := fmt.Sprintf("[%s] %s\n", timestamp, err.Error()) - updateSyncerErrorText(syncer, line) + _, err = updateSyncerErrorText(syncer, line) + if err != nil { + panic(err) + } + return } @@ -40,48 +48,68 @@ func (syncer *Syncer) syncUsers() { _, affiliationMap, err = syncer.getAffiliationMap() } + key := syncer.getKey() + + myUsers := map[string]*User{} + for _, m := range users { + myUsers[syncer.getUserValue(m, key)] = m + } + newUsers := []*User{} for _, oUser := range oUsers { - id := oUser.Id - if _, ok := userMap[id]; !ok { - if _, ok := userNameMap[oUser.Name]; !ok { - newUser := syncer.createUserFromOriginalUser(oUser, affiliationMap) - fmt.Printf("New user: %v\n", newUser) - newUsers = append(newUsers, newUser) - } - } else { - user := userMap[id] - oHash := syncer.calculateHash(oUser) + primary := syncer.getUserValue(oUser, key) + if _, ok := myUsers[primary]; !ok { + newUser := syncer.createUserFromOriginalUser(oUser, affiliationMap) + fmt.Printf("New user: %v\n", newUser) + newUsers = append(newUsers, newUser) + } else { + user := myUsers[primary] + oHash := syncer.calculateHash(oUser) if user.Hash == user.PreHash { if user.Hash != oHash { updatedUser := syncer.createUserFromOriginalUser(oUser, affiliationMap) updatedUser.Hash = oHash updatedUser.PreHash = oHash - syncer.updateUserForOriginalFields(updatedUser) + _, err = syncer.updateUserForOriginalByFields(updatedUser, key) + if err != nil { + panic(err) + } fmt.Printf("Update from oUser to user: %v\n", updatedUser) } } else { if user.PreHash == oHash { if !syncer.IsReadOnly { updatedOUser := syncer.createOriginalUserFromUser(user) - syncer.updateUser(updatedOUser) + _, err = syncer.updateUser(updatedOUser) + if err != nil { + panic(err) + } fmt.Printf("Update from user to oUser: %v\n", updatedOUser) } // update preHash user.PreHash = user.Hash - SetUserField(user, "pre_hash", user.PreHash) + _, err = SetUserField(user, "pre_hash", user.PreHash) + if err != nil { + panic(err) + } } else { if user.Hash == oHash { // update preHash user.PreHash = user.Hash - SetUserField(user, "pre_hash", user.PreHash) + _, err = SetUserField(user, "pre_hash", user.PreHash) + if err != nil { + panic(err) + } } else { updatedUser := syncer.createUserFromOriginalUser(oUser, affiliationMap) updatedUser.Hash = oHash updatedUser.PreHash = oHash - syncer.updateUserForOriginalFields(updatedUser) + _, err = syncer.updateUserForOriginalByFields(updatedUser, key) + if err != nil { + panic(err) + } fmt.Printf("Update from oUser to user (2nd condition): %v\n", updatedUser) } } diff --git a/object/syncer_user.go b/object/syncer_user.go index 99e67b54..8f0eda28 100644 --- a/object/syncer_user.go +++ b/object/syncer_user.go @@ -80,16 +80,6 @@ func (syncer *Syncer) addUser(user *OriginalUser) (bool, error) { return affected != 0, nil } -/*func (syncer *Syncer) getOriginalColumns() []string { - res := []string{} - for _, tableColumn := range syncer.TableColumns { - if tableColumn.CasdoorName != "Id" { - res = append(res, tableColumn.Name) - } - } - return res -}*/ - func (syncer *Syncer) getCasdoorColumns() []string { res := []string{} for _, tableColumn := range syncer.TableColumns { @@ -102,12 +92,14 @@ func (syncer *Syncer) getCasdoorColumns() []string { } func (syncer *Syncer) updateUser(user *OriginalUser) (bool, error) { + key := syncer.getKey() + m := syncer.getMapFromOriginalUser(user) - pkValue := m[syncer.TablePrimaryKey] - delete(m, syncer.TablePrimaryKey) + pkValue := m[key] + delete(m, key) setString := syncer.getSqlSetStringFromMap(m) - sql := fmt.Sprintf("update %s set %s where %s = %s", syncer.getTable(), setString, syncer.TablePrimaryKey, pkValue) + sql := fmt.Sprintf("update %s set %s where %s = %s", syncer.getTable(), setString, key, pkValue) res, err := syncer.Ormer.Engine.Exec(sql) if err != nil { return false, err @@ -142,6 +134,34 @@ func (syncer *Syncer) updateUserForOriginalFields(user *User) (bool, error) { if err != nil { return false, err } + return affected != 0, nil +} + +func (syncer *Syncer) updateUserForOriginalByFields(user *User, key string) (bool, error) { + var err error + oldUser := User{} + + existed, err := ormer.Engine.Where(key+" = ? and owner = ?", syncer.getUserValue(user, key), user.Owner).Get(&oldUser) + if err != nil { + return false, err + } + if !existed { + return false, nil + } + + if user.Avatar != oldUser.Avatar && user.Avatar != "" { + user.PermanentAvatar, err = getPermanentAvatarUrl(user.Owner, user.Name, user.Avatar, true) + if err != nil { + return false, err + } + } + + columns := syncer.getCasdoorColumns() + columns = append(columns, "affiliation", "hash", "pre_hash") + affected, err := ormer.Engine.Where(key+" = ? and owner = ?", syncer.getUserValue(&oldUser, key), oldUser.Owner).Cols(columns...).Update(user) + if err != nil { + return false, err + } return affected != 0, nil } diff --git a/object/syncer_util.go b/object/syncer_util.go index a0dad5e9..e6c0c4b3 100644 --- a/object/syncer_util.go +++ b/object/syncer_util.go @@ -17,6 +17,7 @@ package object import ( "encoding/json" "fmt" + "reflect" "strconv" "strings" "time" @@ -164,6 +165,33 @@ func (syncer *Syncer) setUserByKeyValue(user *User, key string, value string) { } } +func (syncer *Syncer) getUserValue(user *User, key string) string { + jsonData, _ := json.Marshal(user) + var mapData map[string]interface{} + if err := json.Unmarshal(jsonData, &mapData); err != nil { + fmt.Println("conversion failed:", err) + return user.Id + } + value := mapData[util.SnakeToCamel(key)] + + if str, ok := value.(string); ok { + return str + } else { + if value != nil { + valType := reflect.TypeOf(value) + + typeName := valType.Name() + switch typeName { + case "bool": + return strconv.FormatBool(value.(bool)) + case "int": + return strconv.Itoa(value.(int)) + } + } + return user.Id + } +} + func (syncer *Syncer) getOriginalUsersFromMap(results []map[string]string) []*OriginalUser { users := []*OriginalUser{} for _, result := range results { diff --git a/util/string.go b/util/string.go index 2df12e1f..d173b563 100644 --- a/util/string.go +++ b/util/string.go @@ -88,6 +88,17 @@ func CamelToSnakeCase(camel string) string { return strings.ReplaceAll(buf.String(), " ", "") } +func SnakeToCamel(snake string) string { + words := strings.Split(snake, "_") + for i := range words { + words[i] = strings.ToLower(words[i]) + if i > 0 { + words[i] = strings.Title(words[i]) + } + } + return strings.Join(words, "") +} + func GetOwnerAndNameFromId(id string) (string, string) { tokens := strings.Split(id, "/") if len(tokens) != 2 { diff --git a/web/src/SyncerEditPage.js b/web/src/SyncerEditPage.js index 8ca8e689..0c4670b3 100644 --- a/web/src/SyncerEditPage.js +++ b/web/src/SyncerEditPage.js @@ -313,16 +313,6 @@ class SyncerEditPage extends React.Component { }} /> - - - {Setting.getLabel(i18next.t("syncer:Table primary key"), i18next.t("syncer:Table primary key - Tooltip"))} : - - - { - this.updateSyncerField("tablePrimaryKey", e.target.value); - }} /> - - {Setting.getLabel(i18next.t("syncer:Table columns"), i18next.t("syncer:Table columns - Tooltip"))} :