diff --git a/lib/access.go b/lib/access.go index 66ff8b5..77b4a85 100644 --- a/lib/access.go +++ b/lib/access.go @@ -329,43 +329,13 @@ func EnsureCategoryEntry(dossierID string, category int) (string, error) { } // CanAccessDossier returns true if accessor can read dossier (for quick checks) -// Falls back to old dossier_access for backward compatibility func CanAccessDossier(accessorID, dossierID string) bool { - // Check new RBAC system first - if CheckAccess(accessorID, dossierID, "", 'r') == nil { - return true - } - - // Fallback: check old dossier_access table - var result []struct { - Status int `db:"status"` - } - err := Query( - "SELECT status FROM dossier_access WHERE accessor_dossier_id = ? AND target_dossier_id = ? AND status = 1", - []any{accessorID, dossierID}, - &result, - ) - return err == nil && len(result) > 0 && result[0].Status == 1 + return CheckAccess(accessorID, dossierID, "", 'r') == nil } // CanManageDossier returns true if accessor can manage permissions for dossier -// Falls back to old dossier_access.can_edit for backward compatibility func CanManageDossier(accessorID, dossierID string) bool { - // Check new RBAC system first - if CheckAccess(accessorID, dossierID, "", 'm') == nil { - return true - } - - // Fallback: check old dossier_access table - var result []struct { - CanEdit int `db:"can_edit"` - } - err := Query( - "SELECT can_edit FROM dossier_access WHERE accessor_dossier_id = ? AND target_dossier_id = ? AND status = 1", - []any{accessorID, dossierID}, - &result, - ) - return err == nil && len(result) > 0 && result[0].CanEdit == 1 + return CheckAccess(accessorID, dossierID, "", 'm') == nil } // GrantAccess creates an access grant diff --git a/lib/v2.go b/lib/v2.go index 98de92f..2f595db 100644 --- a/lib/v2.go +++ b/lib/v2.go @@ -800,6 +800,47 @@ func AccessGrantRemove(ids ...string) error { return nil } +// MigrateOldAccess converts dossier_access entries to access grants (one-time migration) +func MigrateOldAccess() int { + type oldAccess struct { + AccessorID string `db:"accessor_dossier_id"` + TargetID string `db:"target_dossier_id"` + CanEdit int `db:"can_edit"` + } + var entries []oldAccess + err := Query("SELECT accessor_dossier_id, target_dossier_id, can_edit FROM dossier_access WHERE status = 1", nil, &entries) + if err != nil { + return 0 + } + + migrated := 0 + for _, e := range entries { + // Skip self-references (owner access is automatic) + if e.AccessorID == e.TargetID { + continue + } + // Skip if grant already exists + existing, _ := AccessGrantList(&PermissionFilter{DossierID: e.TargetID, GranteeID: e.AccessorID}) + if len(existing) > 0 { + continue + } + // Create root-level grant + ops := "r" + if e.CanEdit == 1 { + ops = "rwdm" + } + AccessGrantWrite(&Access{ + DossierID: e.TargetID, + GranteeID: e.AccessorID, + EntryID: "", + Role: "Migrated", + Ops: ops, + }) + migrated++ + } + return migrated +} + // AccessGrantGet retrieves a single access grant by ID func AccessGrantGet(id string) (*Access, error) { a := &Access{} diff --git a/portal/main.go b/portal/main.go index f91fac5..60cea7f 100644 --- a/portal/main.go +++ b/portal/main.go @@ -2097,6 +2097,12 @@ func main() { fmt.Printf("Warning: could not ensure bridge client: %v\n", err) } fmt.Println("lib.DBInit successful") + lib.ConfigInit() + + // Migrate old dossier_access to new RBAC grants (idempotent) + if n := lib.MigrateOldAccess(); n > 0 { + fmt.Printf("Migrated %d access grants from dossier_access\n", n) + } loadTranslations() lib.TranslateInit("lang") // also init lib translations for CategoryTranslate