Caucus Groups in C5
Charles Roth, 5/17/2005
Copyright (C) 2005 CaucusCare. All rights reserved. I. Introduction
The way groups are handled in Caucus is completely redone in C5, according to the following principles.II. Opt-out and Opt-in
- Every collection of people is a group. (Groups, conferences, manager privs, etc.)
- Groups can contain subgroups.
- Groups are defined by owner (userid, conf name, etc.) and group name.
- Groups define membership and access level.
- Groups must be usable in simple MySQL "joins" to determine who is in a group, and with what access level.
- Users may opt-out of access to a group.
- Groups may define opt-in access levels.
The last two points are tricky, and are driven by a design decision about conferences. In Caucus 4, each conference has a userlist, and a membership list. The userlist is the list of "invitees"; the membership list is the set of invitees who actually "showed up", so to speak. While distinguishing between the two is useful, in practice it has led to endless confusion, and even more complicated work-arounds such as "force join" and "auto join" for cases where the organizer needs to make people be members. So, in C5, the userlist and the membership become one: the conference group. If your access to the conference group is readonly or higher, you are a member. Period. However, if you don't want to be a member, you can "opt out" of a group. As implemented, it means you can add an opt-out rule to a group that you belong to. If you change your mind (again), you can remove your opt-out rule, and get back your original access. Opt-in is similar. Whoever owns a group can define opt-in access for a set of people. They are not members of the group, but they can choose to add themselves to the group, with whatever access level the owner originally specified. III. The Formal Details
The rest of this document lays out the details and formal definitions of these principles. Take a deep breath and read onward!
- Every collection of people is a group. Groups are groups. Conference user lists are groups. Item access lists (new in C5) are groups. Manager privileges are groups. Etc.
- Groups contain userids, or other groups. Each entry in a group is called a "rule". E.g. a group G that contains userid A, userid B, and group X has three rules, one each for A and B, and one for X. (For now, when a group is contained in another group, it is shown with a preceding "<" as in C4.)
- Userids in groups may have wildcards. The MySQL "LIKE" syntax is used, e.g. "user%" or "%_class" or "abc%xyz". Asterisks in C4 groups are translated to %'s.
- All groups are owned by someone or something. Group names take the form:
owner.name
Owners can be:Note that all userids are lower-case, and all "special" owners are all upper-case. Additional categories of special owners may be added later, such as the C4 "interface" groups that record who was registered under which interface. Currently, everyone can read or use all groups. Userid groups (e.g. "roth.special") can be edited or deleted by the owning userid. Conference groups (e.g. "CONF.demo") can be edited by the matching conference organizers. All groups may be edited by members of "mgr.groups" (the managers with "edit groups" privilege).
- "CONF". E.g. CONF.demo is the userlist for conference "demo".
- "MGR". Special manager groups are owned by "MGR".
- A userid. E.g. "roth.special" is owned by userid "roth".
- Rules define access. Each rule selects a userid or group, and an access level, and whether that is "real" or "optional" access. Access levels are represented internally by integers, and in the user interface by keywords. There is an "out-of-the-box" list of standard access levels, and custom (site) levels may also be added. The standard access levels are:
If a rule lists a userid but no access level, then the default level of "include" is implied. The precise implications of an access level depend on what a group is used for. E.g. for a conference the levels are pretty clear, but for a group that defines manager privs, everything above "exclude" means you have that priv, and everything below means you do not have that priv. Ditto emailing everyone in a group, and so on. If an access level is "optional", then users do not have any access, and are not considered members -- except that they have the ability to add a rule to the group with the "real" equivalent access. (Optional exclude access is probably meaningless -- generally anyone with real access in a group can exclude themselves. This may be prohibited separately at the interface level, e.g. a conference organizer may turn off the ability to for users to exclude themselves.)
Keyword Value Description organizer 40 Full management powers for whatever the group is used in instructor 30 (limited organizer powers) include 20 readonly 10 exclude 0 No access inherit -1 Inherit actual access level from subgroup - Rules may inherit or override. When a rule in group G references another group X (i.e. a subgroup), it is interpreted in one of two ways:
Example:
- If the rule access in G is inherit, then the rules in X are inherited exactly as they are (i.e. as if those rules were copied directly into G).
- Otherwise, the rule in G applies to everyone in X who has readonly or higher access in X.
Group G's rules yield the following access:
Group G
<M include
<F inheritGroup M
alfred readonly
bob include
charlie organizer
dexter excludeGroup F
alice readonly
betty include
charlotte organizer
debby exclude
- Include: alfred, bob, charlie, betty
- Readonly: alice
- Organizer: charlotte
- Exclude wins. Then highest access wins. If more than one rule in a group applies to a userid (including rules from subgroups), then:
Example: if we modified group G above to add two new rules:
- Any exclude rule for that userid wins. (Opt-out acts like exclude.)
- Otherwise, the highest (most privileged) access wins.
dexter include
Then dexter would have include access (because he is effectively not in group M), but debby would still be excluded, because the inherited exclude rule from F wins over the new include rule in G.
debby include- Assume simplicity. The group structure as presented is complex, if thorough. But in most cases, the interface need only present the simplest aspects of the groups. Only if a user chooses to invoke a more complex option (such as wildcards or inheritance or optional access) do the relevant interface options appear. So, for example, most of the time the access rule "include" is assumed when including groups within groups. The "exclude" concept, in particular, adds a lot of complexity. But in general it is only needed to counter the effects of a wild-card match, such as "give everyone access except certain people". In most cases, neither wild-cards nor exclude will be used, and the interface can appear correspondingly simpler.
- Group rules define JOINable groups table. The implementation of the groups rules is done via two tables: 'grouprules' and 'groups'. The rules as described above are recorded in 'grouprules'. The 'groups' table records the relationship between every userid and every group. The idea is that 'groups' can be used in simple MySQL "joins" when a query needs to be restricted by membership in a group. More precisely, each row in 'groups' has a structure something like:
userid varchar group varchar access intThe values in 'groups' are totally derived from the rules in 'grouprules'. Every time a group is changed and the relevant rows in 'grouprules' are changed, all rows in 'groups' that reference the changed group, either directly or through included layers of subgroups, are updated to match. (This also means that any time a new userid is added, any wild-card group rules must be scanned for matches against the new userid, and the 'groups' table similarly updated. Thus, determining group membership and access is very fast and simple, but changing group membership is expensive.) Thus, from our previous example, 'groups' would have a row for (userid='alfred', group='M'), and a row for (userid='alfred', group='G'). This means it is possible (and easy!) to craft queries such asSELECT userid, access FROM groups WHERE group='G'and still get a list of all the userids that belong to group G, and their access level, no matter how many layers of included sub-groups are involved.