feat: 完善用户治理与登录白名单

This commit is contained in:
richjohnrambo
2026-09-08 10:55:26 +08:00
parent d239bd9ad0
commit 8116fb6fe8
8 changed files with 196 additions and 8 deletions
+28 -3
View File
@@ -270,12 +270,13 @@ func internalAdminQuerySpec(resource string) (*internalQuerySpec, bool) {
func usersInternalQuerySpec() *internalQuerySpec {
return &internalQuerySpec{
Select: `SELECT CAST(u.id AS CHAR) AS user_id,u.username,u.phone,u.state,u.stateat AS state_at,u.access,u.lastseen AS last_seen,u.useragent AS user_agent,u.public,u.trusted,
p.nickname,p.public_account,p.gender,p.region,p.avatar_file_id,p.signature,sec.auth_version,sec.password_updated_at,u.createdat AS created_at,u.updatedat AS updated_at,
p.nickname,p.public_account,p.gender,p.region,p.avatar_file_id,COALESCE(avatar.location,'') AS avatar,p.signature,sec.auth_version,sec.password_updated_at,u.createdat AS created_at,u.updatedat AS updated_at,
CASE WHEN EXISTS(SELECT 1 FROM im_registration_invite_uses AS invite_use WHERE invite_use.user_id=u.id) THEN 'invite_code' WHEN COALESCE(u.phone,'')<>'' THEN 'mobile' ELSE 'admin' END AS register_type,
(SELECT JSON_ARRAYAGG(JSON_OBJECT('method',c.method,'value',c.value,'done',c.done,'updated_at',c.updatedat)) FROM im_credentials AS c WHERE c.userid=u.id AND c.deletedat IS NULL) AS credentials`,
From: "FROM im_users AS u LEFT JOIN im_user_profiles AS p ON p.user_id=u.id LEFT JOIN im_user_security AS sec ON sec.user_id=u.id",
From: "FROM im_users AS u LEFT JOIN im_user_profiles AS p ON p.user_id=u.id LEFT JOIN im_user_security AS sec ON sec.user_id=u.id LEFT JOIN im_fileuploads AS avatar ON avatar.id=CAST(p.avatar_file_id AS UNSIGNED) AND p.avatar_file_id REGEXP '^[0-9]+$'",
DefaultSort: "ORDER BY u.id DESC",
DetailKey: "u.id",
Filters: []internalQueryFilter{{"user_id", "u.id", "=", "uid"}, {"nickname", "p.nickname", "LIKE", "string"}, {"auth_name", "u.username", "LIKE", "string"}, {"state", "u.state", "=", "int"}, {"created_at_start", "u.createdat", ">=", "time"}, {"created_at_end", "u.createdat", "<=", "time"}, {"last_seen_start", "u.lastseen", ">=", "time"}, {"last_seen_end", "u.lastseen", "<=", "time"}},
Filters: []internalQueryFilter{{"user_id", "u.id", "=", "uid"}, {"user_ids", "u.id", "IN", "uid_list"}, {"keyword", "CONCAT_WS(' ',u.username,p.nickname,u.phone)", "LIKE", "string"}, {"nickname", "p.nickname", "LIKE", "string"}, {"auth_name", "u.username", "LIKE", "string"}, {"state", "u.state", "=", "int"}, {"created_at_start", "u.createdat", ">=", "time"}, {"created_at_end", "u.createdat", "<=", "time"}, {"last_seen_start", "u.lastseen", ">=", "time"}, {"last_seen_end", "u.lastseen", "<=", "time"}},
}
}
@@ -404,6 +405,16 @@ func buildInternalAdminListQuery(req *http.Request, spec *internalQuerySpec, sco
if err != nil {
return "", "", nil, 0, 0, err
}
if filter.Kind == "uid_list" {
ids := value.([]any)
placeholders := make([]string, len(ids))
for i := range ids {
placeholders[i] = "?"
}
where = append(where, filter.Column+" IN ("+strings.Join(placeholders, ",")+")")
args = append(args, ids...)
continue
}
op := filter.Op
if op == "" {
op = "="
@@ -430,6 +441,20 @@ func internalAdminFilterValue(_ string, raw, kind string) (any, error) {
return id, nil
case "int":
return strconv.ParseInt(raw, 10, 64)
case "uid_list":
parts := strings.Split(raw, ",")
if len(parts) == 0 || len(parts) > 5000 {
return nil, types.ErrMalformed
}
ids := make([]any, 0, len(parts))
for _, part := range parts {
id, ok := parseInternalAdminDBID(strings.TrimSpace(part))
if !ok {
return nil, types.ErrMalformed
}
ids = append(ids, id)
}
return ids, nil
default:
return raw, nil
}