membrane, groups and roles
I am digging around in PlonePAS.
Problem: how do I get my membrane based group to be editable in the groups management interface in configuration?
- In prefs_groups_overviews.cpt in Plone/Products/CMFPlone/skin/plone_prefs a @@pas_search is called to get info on groups
- this pas_search is defined in Products.PlonePAS/browser/search.py (searchGroups)
- in there: enumerators = plugins.listPlugins( IGroupEnumerationPlugin )
- then enumerateGroups in Products.membrane/Products/membrane/plugins/groupmanager.py is called (this implements IGroupEnumerationPlugin)
- this adapts to IGroup, group = IGroup(obj), to Products.membrane.interfaces.group.IGroup to be precise
- which then only fills in the uninteresting bits. I missed something -
- back in it does "group python:acl_users.getGroupById(group_info['groupid'])", and later group.getRoles(). So the real question is:
What is the getGroupById doing?
- One level up from where we are a self.getGroupById.im_func.func_code tells me that this function is defined in Products.PlonePAS/Products/PlonePAS/pas.py :226
- which calls Products.PlonePAS/Products/PlonePAS/tools/groups.py(213)getGroupById()
- "introspectors = self.plugins.listPlugins(IGroupIntrospection)"
- ok, the first introspector hits: <GroupManager at /westapedia/acl_users/source_groups>
- This is not really as expected - I would have hoped that the membrane tool somehow would do it.
- Why does the GroupManager give the wrong results?
- which then calls enumerators = plugins.listPlugins(IGroupEnumerationPlugin) - oh oh
- anyhow, we now know its really a group
- return PloneGroup(group_id, name).__of__(self) - ok, here is where the PloneGroup gets created. Further up in the comments of the code:
"Create group object. For users, this can be done with a plugin, but I don't care to define one for that now. Just uses PloneGroup. But, the code's still here, just commented out."
- further up, Products.PlonePAS-3.12-py2.4.egg/Products/PlonePAS/plugins/group.py(197)_findGroup() : propfinders = plugins.listPlugins(IPropertiesPlugin)
- rolemakers = plugins.listPlugins(IRolesPlugin) - there is a <MembraneRoleManager at /westapedia/acl_users/membrane_roles>, coming last
- this calls unrestrictedSearchResults on <MembraneTool at /westapedia/membrane_tool used for /westapedia/acl_users/membrane_roles>
- uSR(exact_getUserId=principal.getId(),object_implements=IMembraneUserRoles.__identifier__) doesn't return anything. ???
- Ok, so why don't we have a IMembraneUserRoles, and what would be that?
- it is "Used for objects that can provide user roles."
- There are adapters from IRolesProvider to IMembraneUserRoles, so whats IRolesProvider?
"Marks the object as a Membrane roles provider using the default roles computation mechanism defined in the Roles adapter. Objects must also provide or adapt to IUserRoles." Seems to be more for plugins...
- I think this is another rabbit hole, and think that maybe reordering might be enough (back to 1)
- Resorted to implement the following interfaces. This means I put them into _implements_:
- IUserRelated - this has a getUserId. This needs to be set because tools.membrane.getUserId adapts to this interface.
- IUserRoles - getRoles. This is needed because factories.roles.getRolesForPrincipal adapts to this.
- If we reorder the introspectors, we might get better results.
- This I have done in acl_users/plugins
- no difference
- follow down, to see if the first introspector is membrane, and what/why it doesn't deliver anything
- it does hit, and calls Products.membrane-1.1b5-py2.4.egg/Products/membrane/plugins/groupmanager.py(152)getGroupById()
- which calls _createGroup (see 1.7) - so we end up with a PloneGroup again, and all hope now rests on rolemakers = plugins.listPlugins(IRolesPlugin) (see 1.9). And we know that fails.
So, now it shows up in the prefs_groups_overviews (because of 1.13.4, see above).
Now lets make it editable.
- prefs_groups_modify.cpy in Plone/Products/CMFPlone/skin/plone_prefs gets called
- this calls editGroup on portal_groups (Products.PlonePAS.tools.groups)
- this calls self.setRolesForGroup
- this selects rolemanagers(IRoleAssignerPlugin) and calls rmanager.assignRolesToPrincipal(roles, group_id). There is no membrane rolemanger
- Lets see if the normal rolemanager would work
- Products.PlonePAS.plugins.role.GroupAwareRoleManager.assignRolesToPrincipal gets called
- self._principal_roles[ principal_id ] = tuple(roles). What is _principal_roles?
- Its a btree. Seems to store all global roles for all prinicipals. Two ways from here - either have my custom group store the roles in portal_groups, or create a new role manager. Lets look at the rolemanager first
- Why is there no membrane rolemanager available - because it doesn't exist. Only the standard PAS defines a IRoleAssignerPlugin
So either implement a plugin, or have the group object actually use the portal_groups to store the group. This would also mean to include member adding / removing capability, and group adding. For now delay doing this decision - in the end this is user interface polishing.