refactor: replace can_upload boolean with role-based access control
Introduces a three-tier role hierarchy: reader < uploader < admin. - internal/users/role.go: Role type, roleLevel map, AtLeast(min), ParseRole() — new roles added by inserting into roleLevel only - internal/users/store.go: versioned migrations via _schema_version table; v2 migration adds 'role' column and migrates existing can_upload data; SetRole() replaces SetUpload(); Session carries Role instead of CanUpload - internal/web/middleware.go: generic requireRole(minRole) middleware replaces the ad-hoc requireUpload - internal/web/handlers.go: upload routes use requireRole(RoleUploader); listBooks derives canUpload from sess.Role.AtLeast(RoleUploader) - cmd/admin/main.go: user add --role <reader|uploader|admin>, user set-role replaces user set-upload - README, copilot-instructions updated Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
package users
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Role represents a user's access level. Roles are ordered hierarchically:
|
||||
// RoleReader < RoleUploader < RoleAdmin.
|
||||
// New roles can be inserted into roleLevel without changing existing code.
|
||||
type Role string
|
||||
|
||||
const (
|
||||
RoleReader Role = "reader"
|
||||
RoleUploader Role = "uploader"
|
||||
RoleAdmin Role = "admin"
|
||||
)
|
||||
|
||||
// roleLevel defines the hierarchy. Higher = more permissions.
|
||||
var roleLevel = map[Role]int{
|
||||
RoleReader: 0,
|
||||
RoleUploader: 1,
|
||||
RoleAdmin: 2,
|
||||
}
|
||||
|
||||
// AtLeast reports whether r has at least the same privilege level as min.
|
||||
func (r Role) AtLeast(min Role) bool {
|
||||
return roleLevel[r] >= roleLevel[min]
|
||||
}
|
||||
|
||||
// IsValid reports whether r is a known role.
|
||||
func (r Role) IsValid() bool {
|
||||
_, ok := roleLevel[r]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (r Role) String() string { return string(r) }
|
||||
|
||||
// ParseRole parses a role string. Returns an error for unknown values.
|
||||
func ParseRole(s string) (Role, error) {
|
||||
r := Role(s)
|
||||
if !r.IsValid() {
|
||||
return "", fmt.Errorf("unbekannte Rolle %q, gültig: reader, uploader, admin", s)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
Reference in New Issue
Block a user