fix: synchronize update the syncers (#2201)

Signed-off-by: baihhh <2542274498@qq.com>
This commit is contained in:
Baihhh 2023-08-13 22:24:34 +08:00 committed by Yang Luo
parent db4ac60bb6
commit 80b0d26813
6 changed files with 138 additions and 41 deletions

View File

@ -45,7 +45,6 @@ type Syncer struct {
DatabaseType string `xorm:"varchar(100)" json:"databaseType"` DatabaseType string `xorm:"varchar(100)" json:"databaseType"`
Database string `xorm:"varchar(100)" json:"database"` Database string `xorm:"varchar(100)" json:"database"`
Table string `xorm:"varchar(100)" json:"table"` Table string `xorm:"varchar(100)" json:"table"`
TablePrimaryKey string `xorm:"varchar(100)" json:"tablePrimaryKey"`
TableColumns []*TableColumn `xorm:"mediumtext" json:"tableColumns"` TableColumns []*TableColumn `xorm:"mediumtext" json:"tableColumns"`
AffiliationTable string `xorm:"varchar(100)" json:"affiliationTable"` AffiliationTable string `xorm:"varchar(100)" json:"affiliationTable"`
AvatarBaseUrl string `xorm:"varchar(100)" json:"avatarBaseUrl"` 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) { func RunSyncer(syncer *Syncer) {
syncer.initAdapter() syncer.initAdapter()
syncer.syncUsers() syncer.syncUsers()

View File

@ -20,16 +20,24 @@ import (
) )
func (syncer *Syncer) syncUsers() { func (syncer *Syncer) syncUsers() {
if len(syncer.TableColumns) == 0 {
return
}
fmt.Printf("Running syncUsers()..\n") fmt.Printf("Running syncUsers()..\n")
users, userMap, userNameMap := syncer.getUserMap() users, _, _ := syncer.getUserMap()
oUsers, oUserMap, err := syncer.getOriginalUserMap() oUsers, oUserMap, err := syncer.getOriginalUserMap()
if err != nil { if err != nil {
fmt.Printf(err.Error()) fmt.Printf(err.Error())
timestamp := time.Now().Format("2006-01-02 15:04:05") timestamp := time.Now().Format("2006-01-02 15:04:05")
line := fmt.Sprintf("[%s] %s\n", timestamp, err.Error()) line := fmt.Sprintf("[%s] %s\n", timestamp, err.Error())
updateSyncerErrorText(syncer, line) _, err = updateSyncerErrorText(syncer, line)
if err != nil {
panic(err)
}
return return
} }
@ -40,48 +48,68 @@ func (syncer *Syncer) syncUsers() {
_, affiliationMap, err = syncer.getAffiliationMap() _, affiliationMap, err = syncer.getAffiliationMap()
} }
key := syncer.getKey()
myUsers := map[string]*User{}
for _, m := range users {
myUsers[syncer.getUserValue(m, key)] = m
}
newUsers := []*User{} newUsers := []*User{}
for _, oUser := range oUsers { for _, oUser := range oUsers {
id := oUser.Id primary := syncer.getUserValue(oUser, key)
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)
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 == user.PreHash {
if user.Hash != oHash { if user.Hash != oHash {
updatedUser := syncer.createUserFromOriginalUser(oUser, affiliationMap) updatedUser := syncer.createUserFromOriginalUser(oUser, affiliationMap)
updatedUser.Hash = oHash updatedUser.Hash = oHash
updatedUser.PreHash = 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) fmt.Printf("Update from oUser to user: %v\n", updatedUser)
} }
} else { } else {
if user.PreHash == oHash { if user.PreHash == oHash {
if !syncer.IsReadOnly { if !syncer.IsReadOnly {
updatedOUser := syncer.createOriginalUserFromUser(user) 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) fmt.Printf("Update from user to oUser: %v\n", updatedOUser)
} }
// update preHash // update preHash
user.PreHash = user.Hash user.PreHash = user.Hash
SetUserField(user, "pre_hash", user.PreHash) _, err = SetUserField(user, "pre_hash", user.PreHash)
if err != nil {
panic(err)
}
} else { } else {
if user.Hash == oHash { if user.Hash == oHash {
// update preHash // update preHash
user.PreHash = user.Hash user.PreHash = user.Hash
SetUserField(user, "pre_hash", user.PreHash) _, err = SetUserField(user, "pre_hash", user.PreHash)
if err != nil {
panic(err)
}
} else { } else {
updatedUser := syncer.createUserFromOriginalUser(oUser, affiliationMap) updatedUser := syncer.createUserFromOriginalUser(oUser, affiliationMap)
updatedUser.Hash = oHash updatedUser.Hash = oHash
updatedUser.PreHash = 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) fmt.Printf("Update from oUser to user (2nd condition): %v\n", updatedUser)
} }
} }

View File

@ -80,16 +80,6 @@ func (syncer *Syncer) addUser(user *OriginalUser) (bool, error) {
return affected != 0, nil 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 { func (syncer *Syncer) getCasdoorColumns() []string {
res := []string{} res := []string{}
for _, tableColumn := range syncer.TableColumns { for _, tableColumn := range syncer.TableColumns {
@ -102,12 +92,14 @@ func (syncer *Syncer) getCasdoorColumns() []string {
} }
func (syncer *Syncer) updateUser(user *OriginalUser) (bool, error) { func (syncer *Syncer) updateUser(user *OriginalUser) (bool, error) {
key := syncer.getKey()
m := syncer.getMapFromOriginalUser(user) m := syncer.getMapFromOriginalUser(user)
pkValue := m[syncer.TablePrimaryKey] pkValue := m[key]
delete(m, syncer.TablePrimaryKey) delete(m, key)
setString := syncer.getSqlSetStringFromMap(m) 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) res, err := syncer.Ormer.Engine.Exec(sql)
if err != nil { if err != nil {
return false, err return false, err
@ -142,6 +134,34 @@ func (syncer *Syncer) updateUserForOriginalFields(user *User) (bool, error) {
if err != nil { if err != nil {
return false, err 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 return affected != 0, nil
} }

View File

@ -17,6 +17,7 @@ package object
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"reflect"
"strconv" "strconv"
"strings" "strings"
"time" "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 { func (syncer *Syncer) getOriginalUsersFromMap(results []map[string]string) []*OriginalUser {
users := []*OriginalUser{} users := []*OriginalUser{}
for _, result := range results { for _, result := range results {

View File

@ -88,6 +88,17 @@ func CamelToSnakeCase(camel string) string {
return strings.ReplaceAll(buf.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) { func GetOwnerAndNameFromId(id string) (string, string) {
tokens := strings.Split(id, "/") tokens := strings.Split(id, "/")
if len(tokens) != 2 { if len(tokens) != 2 {

View File

@ -313,16 +313,6 @@ class SyncerEditPage extends React.Component {
}} /> }} />
</Col> </Col>
</Row> </Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("syncer:Table primary key"), i18next.t("syncer:Table primary key - Tooltip"))} :
</Col>
<Col span={22} >
<Input value={this.state.syncer.tablePrimaryKey} onChange={e => {
this.updateSyncerField("tablePrimaryKey", e.target.value);
}} />
</Col>
</Row>
<Row style={{marginTop: "20px"}} > <Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}> <Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("syncer:Table columns"), i18next.t("syncer:Table columns - Tooltip"))} : {Setting.getLabel(i18next.t("syncer:Table columns"), i18next.t("syncer:Table columns - Tooltip"))} :