// Package idear is the roster for a Rastrillo instance: who is in it, // at what role, and who may change that. It never mints a session, // hashes a password, or renders a sign-in form — it sits on top of // sessions and whichever identity plugin the app already chose. package idear // Role is a member's rank within one instance. It is a string, not an // int, because it round-trips through form posts and database columns // without a mapping table to keep in sync — but that means any string // decodes without error, so every caller that receives one from outside // the package (a form, a query) must run it through ParseRole rather // than trust the cast. type Role string const ( RoleOwner Role = "owner" RoleAdmin Role = "admin" RoleMember Role = "member" ) // rank orders the three roles for comparison; 0 means "not a role; see // Valid" rather than "below Member" so it never wins a comparison it // has no business winning. func rank(r Role) int { switch r { case RoleOwner: return 3 case RoleAdmin: return 2 case RoleMember: return 1 default: return 0 } } // Valid reports whether r is one of the three known roles. func (r Role) Valid() bool { return rank(r) > 0 } // AtLeast reports whether r's rank is at or above min's. Both sides // must be valid roles — an invalid r is never at least anything, not // even an equally invalid min, and an invalid min is never a threshold // anything can clear. Without that second half, two unknown strings // would compare equal by falling through to the same rank(0), and // AtLeast would call garbage "at least" garbage. func (r Role) AtLeast(min Role) bool { if !r.Valid() || !min.Valid() { return false } return rank(r) >= rank(min) } // Title is the display form of r — "Owner", "Admin", "Member" — and // the empty string for anything that isn't a role, so a template that // prints it renders nothing rather than a raw lowercase form value. func (r Role) Title() string { switch r { case RoleOwner: return "Owner" case RoleAdmin: return "Admin" case RoleMember: return "Member" default: return "" } } // ParseRole accepts only the three known lowercase spellings. It is the // one place a string from outside the package (a posted form field, a // query parameter) becomes a Role; everywhere else in idear a Role is // assumed already valid. func ParseRole(s string) (Role, bool) { r := Role(s) if !r.Valid() { return "", false } return r, true }