Package: collective.anotherdynamicgroupsplugin
OverviewProducts.PluggableAuthService provides a “Dynamic Groups Plugin”. You can add “virtual” groups, and
for each of them Membership is established via a predicate, expressed as a TALES expression.This package aims to provide a similar functionality, but in a different way. Once the
“Another Dynamic Groups Plugin” is installed it will lookup registered group providers (technicaly
these are named multi-adapters for the user and the request). Each group provider will provide a
set of groups which the user is a member of. It’s similar toborg.localrolebut for
groups.NoteA group provider can also provide membership for regular (non-virtual) groups.The provided plugin is also a “groups introspection plugin”. It means the “virtual” groups created
are shown in the Plone management UI for groups. Actually, if we don’t do that the@@usergroup-userprefsview breaks.CompatibilityCurrent version was tested with Plone 4.3. Probably it will work for any version in the 4.x series.InstallationThe usual: make the package available in the buildout and have its ZCML loaded. Then you can install
it as a Plone add-on into a Plone Site.UsageOnce the add-on is installed you can add “virtual” groups. These will be the groups dynamically
assigned to the users by the plugin. This can also be done through the ZMI:>>> from collective.anotherdynamicgroupsplugin.util import add_virtual_group
>>> add_virtual_group(group_id='group1', title='Group 1')
>>> add_virtual_group(group_id='group2', title='Group 2')We’ll also add a regular group, since group providers can assign users to these too:>>> from plone import api
>>> api.group.create(groupname='group3', title='Group 3')
<GroupData ...Add some users:>>> for u_id in ('user1', 'user2', 'user3'):
...     api.user.create(username=u_id, email=u_id + '@test.org')
<MemberData ...
<MemberData ...
<MemberData ...Now we create and register the named adapters. The first one just makes everybody a member of
“group1”:>>> from collective.anotherdynamicgroupsplugin.interfaces import IGroupProvider
>>> from zope.component import provideAdapter
>>> from zope.interface import implements
>>> from zope.publisher.interfaces.http import IHTTPRequest
>>> from Products.PluggableAuthService.interfaces.authservice import IBasicUser
>>> class ProvideGroup1ToAll(object):
...     implements(IGroupProvider)
...     def __init__(self, user, request):
...         self.user = user
...         self.request = request
...     def __call__(self):
...         return ['group1']
>>> provideAdapter(
...     ProvideGroup1ToAll,
...     adapts=(IBasicUser, IHTTPRequest),
...     name=ProvideGroup1ToAll.__name__
... )The second adapter makes the user member of the group with correspondent name:>>> class ProvideCorrespondentGroup(object):
...     implements(IGroupProvider)
...     def __init__(self, user, request):
...         self.user = user
...         self.request = request
...     def __call__(self):
...         if not self.user.getId().startswith('user'):
...             return []
...         number = self.user.getId()[-1]
...         return ['group' + number]
>>> provideAdapter(
...     ProvideCorrespondentGroup,
...     adapts=(IBasicUser, IHTTPRequest),
...     name=ProvideCorrespondentGroup.__name__
... )Now let’s check if the groups are correctly assigned to each user:>>> sorted(g.getId() for g in api.group.get_groups(username='user1'))
['AuthenticatedUsers', 'group1']

>>> sorted(g.getId() for g in api.group.get_groups(username='user2'))
['AuthenticatedUsers', 'group1', 'group2']

>>> sorted(g.getId() for g in api.group.get_groups(username='user3'))
['AuthenticatedUsers', 'group1', 'group3']Test clean-up:>>> from zope.component import getGlobalSiteManager
>>> sm = getGlobalSiteManager()
>>> for a in (ProvideGroup1ToAll, ProvideCorrespondentGroup):
...     removed = sm.unregisterAdapter(
...         provided=IGroupProvider,
...         required=(IBasicUser, IHTTPRequest),
...         name=a.__name__
...     )
>>> list(sm.registeredAdapters())
[]Changelog1.0.0 (2015-03-20)Plone 4.3 compatibility.Added documentation stating that membership to regular (non-virtual) groups can also be provided by group providers.0.3 (2012-01-11)Fixed MANIFEST.in.0.2 (2012-01-11)Added MANIFEST.in so the sdist is not broken.0.1 (2012-01-11)First release.