Skip to content

Commit 0fb963d

Browse files
committed
refactor(convert_role): Improve role conversion logic for legacy formats
- Add new imports: `database/sql`, `encoding/json`, and `conf` package in `convert_role.go`. - Simplify permission entry initialization by removing redundant struct formatting. - Update error logging messages for better clarity. - Replace `op.GetUsers` with direct database access for fetching user roles. - Implement role update logic using `rawDb` and handle legacy int role conversion. - Count the number of users whose roles are updated and log completion. - Introduce `IsLegacyRoleDetected` function to check for legacy role formats. - Modify `cmd/common.go` to invoke role conversion if legacy format is detected.
1 parent 00120cb commit 0fb963d

File tree

2 files changed

+89
-25
lines changed

2 files changed

+89
-25
lines changed

cmd/common.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package cmd
22

33
import (
4+
"github.com/alist-org/alist/v3/internal/bootstrap/patch/v3_46_0"
45
"os"
56
"path/filepath"
67
"strconv"
@@ -16,6 +17,12 @@ func Init() {
1617
bootstrap.InitConfig()
1718
bootstrap.Log()
1819
bootstrap.InitDB()
20+
21+
if v3_46_0.IsLegacyRoleDetected() {
22+
utils.Log.Warnf("Detected legacy role format, executing ConvertLegacyRoles patch early...")
23+
v3_46_0.ConvertLegacyRoles()
24+
}
25+
1926
data.InitData()
2027
bootstrap.InitStreamLimit()
2128
bootstrap.InitIndex()

internal/bootstrap/patch/v3_46_0/convert_role.go

Lines changed: 82 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package v3_46_0
22

33
import (
4+
"database/sql"
5+
"encoding/json"
46
"errors"
7+
"github.com/alist-org/alist/v3/internal/conf"
58
"github.com/alist-org/alist/v3/internal/db"
69
"github.com/alist-org/alist/v3/internal/model"
710
"github.com/alist-org/alist/v3/internal/op"
@@ -83,47 +86,101 @@ func ConvertLegacyRoles() {
8386
}
8487
}
8588

86-
users, _, err := op.GetUsers(1, -1)
89+
rawDb := db.GetDb()
90+
table := conf.Conf.Database.TablePrefix + "users"
91+
rows, err := rawDb.Table(table).Select("id, username, role").Rows()
8792
if err != nil {
8893
utils.Log.Errorf("[convert roles] failed to get users: %v", err)
8994
return
9095
}
96+
defer rows.Close()
9197

92-
for i := range users {
93-
user := users[i]
94-
if user.Role == nil {
98+
var updatedCount int
99+
for rows.Next() {
100+
var id uint
101+
var username string
102+
var rawRole []byte
103+
104+
if err := rows.Scan(&id, &username, &rawRole); err != nil {
105+
utils.Log.Warnf("[convert roles] skip user scan err: %v", err)
95106
continue
96107
}
97-
changed := false
98-
var roles model.Roles
99-
for _, r := range user.Role {
108+
109+
utils.Log.Debugf("[convert roles] user: %s raw role: %s", username, string(rawRole))
110+
111+
if len(rawRole) == 0 {
112+
continue
113+
}
114+
115+
var oldRoles []int
116+
wasSingleInt := false
117+
if err := json.Unmarshal(rawRole, &oldRoles); err != nil {
118+
var single int
119+
if err := json.Unmarshal(rawRole, &single); err != nil {
120+
utils.Log.Warnf("[convert roles] user %s has invalid role: %s", username, string(rawRole))
121+
continue
122+
}
123+
oldRoles = []int{single}
124+
wasSingleInt = true
125+
}
126+
127+
var newRoles model.Roles
128+
for _, r := range oldRoles {
100129
switch r {
101130
case model.ADMIN:
102-
roles = append(roles, int(adminRole.ID))
103-
if int(adminRole.ID) != r {
104-
changed = true
105-
}
131+
newRoles = append(newRoles, int(adminRole.ID))
106132
case model.GUEST:
107-
roles = append(roles, int(guestRole.ID))
108-
if int(guestRole.ID) != r {
109-
changed = true
110-
}
133+
newRoles = append(newRoles, int(guestRole.ID))
111134
case model.GENERAL:
112-
roles = append(roles, int(generalRole.ID))
113-
if int(generalRole.ID) != r {
114-
changed = true
115-
}
135+
newRoles = append(newRoles, int(generalRole.ID))
116136
default:
117-
roles = append(roles, r)
137+
newRoles = append(newRoles, r)
118138
}
119139
}
120-
if changed {
121-
user.Role = roles
122-
if err := db.UpdateUser(&user); err != nil {
123-
utils.Log.Errorf("[convert roles] failed to update user %s: %v", user.Username, err)
140+
141+
if wasSingleInt {
142+
err := rawDb.Table(table).Where("id = ?", id).Update("role", newRoles).Error
143+
if err != nil {
144+
utils.Log.Errorf("[convert roles] failed to update user %s: %v", username, err)
145+
} else {
146+
updatedCount++
147+
utils.Log.Infof("[convert roles] updated user %s: %v → %v", username, oldRoles, newRoles)
124148
}
125149
}
126150
}
127151

128-
utils.Log.Infof("[convert roles] completed role conversion for %d users", len(users))
152+
utils.Log.Infof("[convert roles] completed role conversion for %d users", updatedCount)
153+
}
154+
155+
func IsLegacyRoleDetected() bool {
156+
rawDb := db.GetDb()
157+
table := conf.Conf.Database.TablePrefix + "users"
158+
rows, err := rawDb.Table(table).Select("role").Rows()
159+
if err != nil {
160+
utils.Log.Errorf("[role check] failed to scan user roles: %v", err)
161+
return false
162+
}
163+
defer rows.Close()
164+
165+
for rows.Next() {
166+
var raw sql.RawBytes
167+
if err := rows.Scan(&raw); err != nil {
168+
continue
169+
}
170+
if len(raw) == 0 {
171+
continue
172+
}
173+
174+
var roles []int
175+
if err := json.Unmarshal(raw, &roles); err == nil {
176+
continue
177+
}
178+
179+
var single int
180+
if err := json.Unmarshal(raw, &single); err == nil {
181+
utils.Log.Infof("[role check] detected legacy int role: %d", single)
182+
return true
183+
}
184+
}
185+
return false
129186
}

0 commit comments

Comments
 (0)