"""Module that provides functionality for group manipulation."""
from plone.api import portal
from plone.api.exc import GroupNotFoundError
from plone.api.exc import UserNotFoundError
from plone.api.user import get as user_get
from plone.api.validation import at_least_one_of
from plone.api.validation import mutually_exclusive_parameters
from plone.api.validation import required_parameters
from Products.PlonePAS.interfaces.plugins import ILocalRolesPlugin
[docs]@required_parameters("groupname")
def create(
groupname=None,
title=None,
description=None,
roles=[],
groups=[],
):
"""Create a group.
:param groupname: [required] Name of the new group.
:type groupname: string
:param title: Title of the new group
:type title: string
:param description: Description of the new group
:type description: string
:param roles: Roles to assign to this group
:type roles: list
:param groups: Groups that belong to this group
:type groups: list
:returns: Newly created group
:rtype: GroupData object
:raises:
ValueError
:Example: :ref:`group-create-example`
"""
group_tool = portal.get_tool("portal_groups")
group_tool.addGroup(
groupname,
roles,
groups,
title=title,
description=description,
)
return group_tool.getGroupById(groupname)
[docs]@required_parameters("groupname")
def get(groupname=None):
"""Get a group.
:param groupname: [required] Name of the group we want to get.
:type groupname: string
:returns: Group
:rtype: GroupData object
:raises:
ValueError
:Example: :ref:`group-get-example`
"""
group_tool = portal.get_tool("portal_groups")
return group_tool.getGroupById(groupname)
[docs]@mutually_exclusive_parameters("username", "user")
def get_groups(username=None, user=None):
"""Get all groups or all groups filtered by user.
Arguments ``username`` and ``user`` are mutually exclusive. You can either
set one or the other, but not both.
:param username: Username of the user for which to return groups. If set,
only return groups that this user is member of.
:type username: string
:param user: User for which to return groups. If set, only return groups
that this user is member of.
:type user: MemberData object
:returns: All groups (optionlly filtered by user)
:rtype: List of GroupData objects
:raises: UserNotFoundError
:Example: :ref:`group-get-all-groups-example`,
:ref:`group-get-users-groups-example`
"""
if username:
user = user_get(username=username)
if not user:
raise UserNotFoundError
group_tool = portal.get_tool("portal_groups")
if user:
try:
groups = group_tool.getGroupsForPrincipal(user)
except AttributeError as e:
# Anonymous users from the Zope acl_users folder will fail on this
if "portal_groups" in str(e):
return []
raise
return [get(groupname=group) for group in groups]
return group_tool.listGroups()
[docs]@mutually_exclusive_parameters("groupname", "group")
@at_least_one_of("groupname", "group")
def delete(groupname=None, group=None):
"""Delete a group.
Arguments ``groupname`` and ``group`` are mutually exclusive. You can
either set one or the other, but not both.
:param groupname: Name of the group to be deleted.
:type groupname: string
:param group: Group object to be deleted.
:type group: GroupData object
:raises:
ValueError
:Example: :ref:`group-delete-example`
"""
group_tool = portal.get_tool("portal_groups")
if group:
groupname = group.id
return group_tool.removeGroup(groupname)
[docs]@mutually_exclusive_parameters("groupname", "group")
@at_least_one_of("groupname", "group")
@mutually_exclusive_parameters("username", "user")
@at_least_one_of("username", "user")
def add_user(groupname=None, group=None, username=None, user=None):
"""Add the user to a group.
Arguments ``groupname`` and ``group`` are mutually exclusive. You can
either set one or the other, but not both.
Arguments ``username`` and ``user`` are mutually exclusive. You can
either set one or the other, but not both.
:param groupname: Name of the group to which to add the user.
:type groupname: string
:param group: Group to which to add the user.
:type group: GroupData object
:param username: Username of the user to add to the group.
:type username: string
:param user: User to add to the group.
:type user: MemberData object
:raises:
ValueError
UserNotFoundError
:Example: :ref:`group-add-user-example`
"""
if username:
user = user_get(username=username)
if not user:
raise UserNotFoundError
user_id = user.id
group_id = groupname or group.id
portal_groups = portal.get_tool("portal_groups")
portal_groups.addPrincipalToGroup(user_id, group_id)
[docs]@mutually_exclusive_parameters("groupname", "group")
@at_least_one_of("groupname", "group")
@mutually_exclusive_parameters("username", "user")
@at_least_one_of("username", "user")
def remove_user(groupname=None, group=None, username=None, user=None):
"""Remove the user from a group.
Arguments ``groupname`` and ``group`` are mutually exclusive. You can
either set one or the other, but not both.
Arguments ``username`` and ``user`` are mutually exclusive. You can either
set one or the other, but not both.
:param groupname: Name of the group to remove the user from.
:type groupname: string
:param group: Group to remove the user from.
:type group: GroupData object
:param username: Username of the user to delete from the group.
:type username: string
:param user: User to delete from the group.
:type user: MemberData object
:raises:
ValueError
UserNotFoundError
:Example: :ref:`group-remove-user-example`
"""
if username:
user = user_get(username=username)
if not user:
raise UserNotFoundError
user_id = user.id
group_id = groupname or group.id
portal_groups = portal.get_tool("portal_groups")
portal_groups.removePrincipalFromGroup(user_id, group_id)
[docs]@mutually_exclusive_parameters("groupname", "group")
@at_least_one_of("groupname", "group")
def get_roles(groupname=None, group=None, obj=None, inherit=True):
"""Get group's site-wide or local roles.
Arguments ``groupname`` and ``group`` are mutually exclusive. You can
either set one or the other, but not both.
:param groupname: Name of the group to get roles from.
:type groupname: string
:param group: Group to get roles from.
:type group: GroupData object
:param obj: If obj is set then return local roles on this context.
:type obj: content object
:param inherit: Show only local roles if False
:type inherit: boolean
:raises:
ValueError
:Example: :ref:`group-get-roles-example`
"""
group_id = groupname or group.id
group = get(groupname=group_id)
if group is None:
raise GroupNotFoundError
group = group.getGroup()
if obj is None:
return group.getRoles()
elif inherit:
# when context obj is available we bypass getRolesInContext method
# from PloneGroup class to use PloneUser class implementation because
# PloneGroup class disables all local roles support
# see: Products.PlonePAS.plugins.group.PloneGroup
roles = super(group.__class__, group).getRolesInContext(obj)
return list(roles)
else:
# get only the local roles on a object
# same as above we use the PloneUser version of getRolesInContext.
# Include roles from adapters granting local roles
roles = set()
pas = portal.get_tool("acl_users")
for _, lrmanager in pas.plugins.listPlugins(ILocalRolesPlugin):
for adapter in lrmanager._getAdapters(obj):
roles.update(adapter.getRoles(group_id))
return list(roles)
[docs]@required_parameters("roles")
@mutually_exclusive_parameters("groupname", "group")
@at_least_one_of("groupname", "group")
def grant_roles(groupname=None, group=None, roles=None, obj=None):
"""Grant roles to a group.
Arguments ``groupname`` and ``group`` are mutually exclusive. You can
either set one or the other, but not both.
:param groupname: Name of the group to grant roles to.
:type groupname: string
:param group: Group to grant roles to.
:type group: GroupData object
:param roles: List of roles to grant
:type roles: list of strings
:param obj: If obj is set then grant local roles on this context.
:type obj: content object
:raises:
ValueError
:Example: :ref:`group-grant-roles-example`
"""
if "Anonymous" in roles or "Authenticated" in roles:
raise ValueError
group_id = groupname or group.id
if obj is None:
actual_roles = get_roles(groupname=group_id)
else:
# only roles persistent on the object, not from other providers
actual_roles = obj.get_local_roles_for_userid(group_id)
actual_roles = [
role for role in actual_roles if role not in ["Anonymous", "Authenticated"]
]
roles = list(set(actual_roles) | set(roles))
portal_groups = portal.get_tool("portal_groups")
if obj is None:
portal_groups.setRolesForGroup(group_id=group_id, roles=roles)
else:
obj.manage_setLocalRoles(group_id, roles)
[docs]@required_parameters("roles")
@mutually_exclusive_parameters("groupname", "group")
@at_least_one_of("groupname", "group")
def revoke_roles(groupname=None, group=None, roles=None, obj=None):
"""Revoke roles from a group.
Arguments ``groupname`` and ``group`` are mutually exclusive. You can
either set one or the other, but not both.
:param groupname: Name of the group to revoke roles to.
:type groupname: string
:param group: Group to revoke roles to.
:type group: GroupData object
:param roles: List of roles to revoke
:type roles: list of strings
:param obj: If obj is set then revoke local roles on this context.
:type obj: content object
:raises:
ValueError
:Example: :ref:`group-revoke-roles-example`
"""
if "Anonymous" in roles or "Authenticated" in roles:
raise ValueError
group_id = groupname or group.id
if obj is None:
actual_roles = get_roles(groupname=group_id)
else:
actual_roles = get_roles(groupname=group_id, obj=obj, inherit=False)
actual_roles = [
role for role in actual_roles if role not in ["Anonymous", "Authenticated"]
]
roles = list(set(actual_roles) - set(roles))
portal_groups = portal.get_tool("portal_groups")
if obj is None:
portal_groups.setRolesForGroup(group_id=group_id, roles=roles)
elif roles:
obj.manage_setLocalRoles(group_id, roles)
else:
obj.manage_delLocalRoles([group_id])