fix: deduplicate account vehicle permissions
This commit is contained in:
@@ -41,20 +41,26 @@ var customerMenuSet = map[string]bool{
|
||||
var adminMenus = []string{"monitor", "vehicles", "tracks", "history", "statistics", "alerts", "access", "operations", "users"}
|
||||
|
||||
type authUser struct {
|
||||
ID uint64 `json:"id"`
|
||||
Username string `json:"username"`
|
||||
DisplayName string `json:"displayName"`
|
||||
UserType string `json:"userType"`
|
||||
Status string `json:"status"`
|
||||
CustomerRef string `json:"customerRef"`
|
||||
TenantRef string `json:"tenantRef"`
|
||||
AuthProvider string `json:"authProvider"`
|
||||
ExternalSubject string `json:"externalSubject,omitempty"`
|
||||
MenuKeys []string `json:"menuKeys"`
|
||||
VehicleVINs []string `json:"vehicleVins"`
|
||||
LastLoginAt *time.Time `json:"lastLoginAt,omitempty"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
ID uint64 `json:"id"`
|
||||
Username string `json:"username"`
|
||||
DisplayName string `json:"displayName"`
|
||||
UserType string `json:"userType"`
|
||||
Status string `json:"status"`
|
||||
CustomerRef string `json:"customerRef"`
|
||||
TenantRef string `json:"tenantRef"`
|
||||
AuthProvider string `json:"authProvider"`
|
||||
ExternalSubject string `json:"externalSubject,omitempty"`
|
||||
MenuKeys []string `json:"menuKeys"`
|
||||
VehicleVINs []string `json:"vehicleVins"`
|
||||
Vehicles []authVehicleGrant `json:"vehicles"`
|
||||
LastLoginAt *time.Time `json:"lastLoginAt,omitempty"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
type authVehicleGrant struct {
|
||||
VIN string `json:"vin"`
|
||||
Plate string `json:"plate"`
|
||||
}
|
||||
|
||||
type localCredential struct {
|
||||
@@ -385,6 +391,7 @@ func (s *authStore) listUsers(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
defer rows.Close()
|
||||
users := []authUser{}
|
||||
allVINs := []string{}
|
||||
for rows.Next() {
|
||||
var user authUser
|
||||
var external sql.NullString
|
||||
@@ -400,11 +407,75 @@ func (s *authStore) listUsers(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
user.MenuKeys = principal.MenuKeys
|
||||
user.VehicleVINs = principal.VehicleVINs
|
||||
allVINs = append(allVINs, principal.VehicleVINs...)
|
||||
users = append(users, user)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
httpx.WriteError(w, http.StatusInternalServerError, "USER_LIST_FAILED", "无法读取账号列表", "", requestTraceID(r))
|
||||
return
|
||||
}
|
||||
vehicleLabels, err := loadAuthVehicleGrants(r.Context(), s.db, normalizeVINs(allVINs))
|
||||
if err != nil {
|
||||
httpx.WriteError(w, http.StatusInternalServerError, "USER_LIST_FAILED", "无法读取车辆权限信息", "", requestTraceID(r))
|
||||
return
|
||||
}
|
||||
for index := range users {
|
||||
users[index].Vehicles = make([]authVehicleGrant, 0, len(users[index].VehicleVINs))
|
||||
for _, vin := range users[index].VehicleVINs {
|
||||
vehicle := vehicleLabels[vin]
|
||||
if vehicle.VIN == "" {
|
||||
vehicle.VIN = vin
|
||||
}
|
||||
users[index].Vehicles = append(users[index].Vehicles, vehicle)
|
||||
}
|
||||
}
|
||||
httpx.WriteOK(w, requestTraceID(r), users)
|
||||
}
|
||||
|
||||
func loadAuthVehicleGrants(ctx context.Context, db *sql.DB, vins []string) (map[string]authVehicleGrant, error) {
|
||||
result := make(map[string]authVehicleGrant, len(vins))
|
||||
for start := 0; start < len(vins); start += 250 {
|
||||
end := start + 250
|
||||
if end > len(vins) {
|
||||
end = len(vins)
|
||||
}
|
||||
part := vins[start:end]
|
||||
placeholders := strings.TrimSuffix(strings.Repeat("?,", len(part)), ",")
|
||||
args := make([]any, 0, len(part)*2)
|
||||
for range 2 {
|
||||
for _, vin := range part {
|
||||
args = append(args, vin)
|
||||
}
|
||||
}
|
||||
query := `SELECT vin, COALESCE(` +
|
||||
`MAX(CASE WHEN source_priority=0 THEN NULLIF(plate,'') END),` +
|
||||
`MAX(CASE WHEN source_priority=1 THEN NULLIF(plate,'') END),'') ` +
|
||||
`FROM (` +
|
||||
`SELECT UPPER(TRIM(vin)) AS vin,plate,0 AS source_priority FROM vehicle_identity_binding WHERE vin IN (` + placeholders + `) ` +
|
||||
`UNION ALL ` +
|
||||
`SELECT UPPER(TRIM(vin)) AS vin,plate,1 AS source_priority FROM vehicle_realtime_snapshot WHERE vin IN (` + placeholders + `)` +
|
||||
`) vehicle_grants GROUP BY vin`
|
||||
rows, err := db.QueryContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for rows.Next() {
|
||||
var vehicle authVehicleGrant
|
||||
if err := rows.Scan(&vehicle.VIN, &vehicle.Plate); err != nil {
|
||||
rows.Close()
|
||||
return nil, err
|
||||
}
|
||||
vehicle.VIN = strings.ToUpper(strings.TrimSpace(vehicle.VIN))
|
||||
vehicle.Plate = strings.TrimSpace(vehicle.Plate)
|
||||
result[vehicle.VIN] = vehicle
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *authStore) createCustomer(w http.ResponseWriter, r *http.Request, actor platform.Principal) {
|
||||
var input userMutation
|
||||
if !decodeAuthJSON(w, r, &input) {
|
||||
|
||||
Reference in New Issue
Block a user