Files
ebooks/internal/users/role.go
T
arnefandCopilot 817763887a 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>
2026-08-11 19:43:39 +02:00

44 lines
1.0 KiB
Go

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
}