def plonegroup_contact_transition(contact, event):
    """
        React when a IPloneGroupContact transition is done
    """
    if event.transition and event.transition.id == 'deactivate':
        # check if the transition is selected
        registry = getUtility(IRegistry)
        pp = api.portal.get_tool('portal_properties')
        errors = []
        if contact.UID() in registry[ORGANIZATIONS_REGISTRY]:
            errors.append(_('This contact is selected in configuration'))
        elif pp.site_properties.enable_link_integrity_checks:
            search_value_in_objects(contact, contact.UID(), p_types=[], type_fields={})
            storage = ILinkIntegrityInfo(contact.REQUEST)
            breaches = storage.getIntegrityBreaches()
            if contact in breaches:
                errors.append(_("This contact is used in following content: ${items}",
                                mapping={'items': ', '.join(['<a href="%s" target="_blank">%s</a>'
                                                             % (i.absolute_url(), i.Title())
                                                             for i in breaches[contact]])}))
        if errors:
            smi = IStatusMessage(contact.REQUEST)
            smi.addStatusMessage(_('You cannot deactivate this item !'), type='error')
            smi.addStatusMessage(errors[0], type='error')
            view_url = getMultiAdapter((contact, contact.REQUEST), name=u'plone_context_state').view_url()
            # contact.REQUEST['RESPONSE'].redirect(view_url)
            raise Redirect(view_url)
class PloneGroupUsersGroupsColumn(BaseColumn):
    """Column that displays Plone groups and users linked to an organization."""

    header = _("Groups and users")
    weight = 5
    short = True

    def renderCell(self, item):
        """ """
        plonegroup_organizations = get_registry_organizations()
        org_uid = item.UID
        if org_uid not in plonegroup_organizations:
            return "-"

        suffixes = get_all_suffixes(org_uid)
        group_ids = [
            get_plone_group_id(org_uid, suffix) for suffix in suffixes
        ]
        url_group_ids = '&group_ids='.join(group_ids)
        # use _ for i18ndude machinery
        details_msg = _('Details')
        details_msg = translate(details_msg, context=self.request)
        res = u"<div id=\"group-users\" class=\"collapsible\" onclick=\"toggleDetails(" \
            u"'collapsible-group-users_{0}', toggle_parent_active=false, parent_tag=null, " \
            u"load_view='@@display-group-users?group_ids={1}&short:boolean={2}', base_url='{3}');\"> {4}</div>" \
            u"<div id=\"collapsible-group-users_{0}\" class=\"collapsible-content\" style=\"display: none;\">" \
            u"<div class=\"collapsible-inner-content\">" \
            u"<img src=\"{3}/spinner_small.gif\" /></div></div>".format(
                org_uid, url_group_ids, self.short, self.table.portal_url, details_msg)
        return res
def group_deleted(event):
    """
        Raises exception if group cannot be deleted
    """
    group = event.principal
    portal = api.portal.get()
    request = portal.REQUEST

    parts = group.split('_')
    if len(parts) == 1:
        return
    org_uid = parts[0]
    group_suffix = '_'.join(parts[1:])
    if org_uid in get_registry_organizations(
    ) and group_suffix in get_all_suffixes(org_uid):
        orga = api.content.find(UID=org_uid)[0].getObject()
        api.portal.show_message(message=_(
            "You cannot delete the group '${group}', linked to used organization "
            "'${orga}'.",
            mapping={
                'group': group,
                'orga': safe_unicode(orga.Title())
            }),
                                request=request,
                                type='error')
        raise Redirect(request.get('ACTUAL_URL'))
def adaptPloneGroupDefinition(organization, event):
    """
        Manage an organization change
    """
    # zope.lifecycleevent.ObjectRemovedEvent : delete
    # zope.lifecycleevent.ObjectModifiedEvent : edit, rename
    # is the container who's modified at creation ?
    # bypass if we are removing the Plone Site
    if IContainerModifiedEvent.providedBy(event) or \
       event.object.portal_type == 'Plone Site':
        return
    # is the current organization a part of own organization
    organization_path = '/'.join(organization.getPhysicalPath())
    if not organization_path.startswith(
            get_own_organization_path(
                not_found_value='unfound')):  # can be unfound too
        return
    portal = getSite()
    # when an organization is removed (and its content), we check if it is used in plonegroup configuration
    registry_orgs = get_registry_organizations()
    if IObjectRemovedEvent.providedBy(
            event) and organization.UID() in registry_orgs:
        smi = IStatusMessage(organization.REQUEST)
        smi.addStatusMessage(_('You cannot delete this item !'), type='error')
        smi.addStatusMessage(_(
            "This organization or a contained organization is used in plonegroup "
            "configuration ! Remove it first from the configuration !"),
                             type='error')
        view_url = getMultiAdapter((organization, organization.REQUEST),
                                   name=u'plone_context_state').view_url()
        organization.REQUEST['RESPONSE'].redirect(view_url)
        raise Redirect(view_url)
        return
    pcat = portal.portal_catalog
    brains = pcat(portal_type='organization', path=organization_path)
    changes = False
    for brain in brains:
        orga = brain.getObject()
        orga_uid = orga.UID()
        if orga_uid in registry_orgs:
            if addOrModifyOrganizationGroups(orga, orga_uid):
                changes = True
    if changes:
        invalidate_sopgv_cache()
        invalidate_sov_cache()
        invalidate_soev_cache()
        invalidate_ssoev_cache()
 def group_users(self, group):
     """ """
     res = []
     patterns = {}
     # use _ for i18ndude machinery
     user_tag_title = _('View Plone user')
     user_tag_title = translate(user_tag_title, context=self.request)
     group_tag_title = _('View Plone group')
     group_tag_title = translate(group_tag_title, context=self.request)
     patterns[0] = "<img src='%s/user.png'> " % self.portal_url
     patterns[1] = "<img src='%s/group.png'> " % self.portal_url
     if self.is_manager:
         patterns[0] = "<a class='user-or-group-level-{{index}}' href='{portal_url}/" \
             "@@user-information?userid={{member_id}}' " \
             "title=\"{user_tag_title}\"><acronym>{pattern}</acronym></a> ".format(
             **{'portal_url': self.portal_url,
                'pattern': patterns[0].strip(),
                'user_tag_title': user_tag_title})
         patterns[1] = "<a class='user-or-group-level-{{index}}' href='{portal_url}/" \
             "@@usergroup-groupmembership?groupname={{member_id}}' " \
             "title=\"{group_tag_title}\"><acronym>{pattern}</acronym></a> ".format(
             **{'portal_url': self.portal_url,
                'pattern': patterns[1].strip(),
                'group_tag_title': group_tag_title})
     for index, principal in self._get_groups_and_members(
             group, keep_subgroups=self.is_manager):
         # member may be a user or group
         isGroup = base_hasattr(principal,
                                'isGroup') and principal.isGroup() or 0
         principal_title = principal.getProperty('fullname') or \
             principal.getProperty('title') or principal.getId()
         if self.is_manager:
             principal_title = principal_title + " ({0})".format(
                 principal.id)
         principal_title = "<div class='user-or-group user-or-group-level-{0}'>{1}</div>".format(
             index, principal_title)
         value = patterns[isGroup].format(**{
             'member_id': principal.id,
             'index': index
         }) + principal_title
         res.append((index, principal_title, value))
     # sort on member_title
     res = sorted(res)
     # just keep values
     return "".join([v[2] for v in res])
    def fields(self):
        self.init()  # second init with user recognized
        fields = []
        description = _(
            u'You can <span class="cross_icon">remove</span> an assignment with the '
            u'<span class="cross_icon">cross icon</span>. '
            u'You can <span class="auto_append">add</span> a new assignment with the '
            u'<span class="auto_append">blue line</span>. '
            u'You can <span class="new_line">complete</span> it on the '
            u'<span class="new_line">brown line</span>.')
        self.get_user_manageable_functions()
        for function in self.functions_orgs:
            fld = DGFListField(
                __name__=function,
                title=_(
                    u"Assignments for groups related to '${function}' function",
                    mapping={'function': self.functions[function]}),
                description=description,
                required=False,
                value_type=DictRow(title=u"org_users",
                                   schema=IOrganisationsUsers,
                                   required=False))
            fields.append(fld)
        fields = sorted(fields, key=lambda x: x.title)

        self.get_user_manageable_groups()
        if self.groupids:
            fld = DGFListField(__name__='_groups_',
                               title=_('Global groups assignments.'),
                               description=description,
                               required=False,
                               value_type=DictRow(title=u"users",
                                                  schema=IGroupsUsers,
                                                  required=False))
            fields.insert(0, fld)

        fld = schema.TextLine(
            __name__='_old_values_',
            title=u'not_showed',
            required=False,
        )
        fields.append(fld)

        self.fieldnames = [afield.__name__ for afield in fields]
        return field.Fields(*fields)
class IFunctionSchema(Interface):
    """
        Function identification schema
    """
    fct_id = schema.TextLine(
        title=_("Plone group suffix id"),
        # description=_("Plone group suffix description"),
        required=True)
    fct_title = schema.TextLine(
        title=_("Plone group suffix title"),
        # description=_("Plone group title description"),
        required=True)
    fct_orgs = schema.List(
        title=_("Plone group suffix organizations"),
        description=_("Plone group organizations description"),
        value_type=schema.Choice(
            vocabulary='collective.contact.plonegroup.browser.settings.'
            'SortedSelectedOrganizationsElephantVocabulary'),
        required=True)
    fct_management = schema.Bool(
        title=_("Manageable function groups?"),
        required=False,
        default=False,
    )
    enabled = schema.Bool(
        title=_(u'Enabled?'),
        default=True,
        required=False,
    )
    def __call__(self,
                 context,
                 root_portal_type='organization',
                 root_id=PLONEGROUP_ORG):
        portal = getSite()
        terms = []
        pcat = portal.portal_catalog
        brains = pcat.unrestrictedSearchResults(portal_type=root_portal_type,
                                                id=root_id)
        if not brains:
            terms.append(
                SimpleTerm(
                    None,
                    token="unfound",
                    title=
                    _(u"You must define one '${root_portal_type}' with id '${pgo}' !",
                      mapping={
                          'root_portal_type': root_portal_type,
                          'pgo': root_id,
                      })))
            return SimpleVocabulary(terms)
        elif len(brains) > 1:
            terms.append(
                SimpleTerm(None,
                           token="multifound",
                           title=_(
                               u"You must have only one '${root_portal_type}' "
                               "with id '${pgo}' !",
                               mapping={
                                   'root_portal_type': root_portal_type,
                                   'pgo': root_id
                               })))
            return SimpleVocabulary(terms)

        own_orga = brains[0]._unrestrictedGetObject()
        self.listSubOrganizations(terms, own_orga)

        return SimpleVocabulary(terms)
def plonegroup_contact_transition(contact, event):
    """
        React when a IPloneGroupContact transition is done
    """
    if event.transition and event.transition.id == 'deactivate':
        # check if the transition is selected
        pp = api.portal.get_tool('portal_properties')
        errors = []
        if contact.UID() in get_registry_organizations():
            errors.append(_('This contact is selected in configuration'))
        elif pp.site_properties.enable_link_integrity_checks:
            search_value_in_objects(contact,
                                    contact.UID(),
                                    p_types=[],
                                    type_fields={})
            storage = ILinkIntegrityInfo(contact.REQUEST)
            breaches = storage.getIntegrityBreaches()
            if contact in breaches:
                errors.append(
                    _("This contact is used in following content: ${items}",
                      mapping={
                          'items':
                          ', '.join([
                              '<a href="%s" target="_blank">%s</a>' %
                              (i.absolute_url(), i.Title())
                              for i in breaches[contact]
                          ])
                      }))
        if errors:
            smi = IStatusMessage(contact.REQUEST)
            smi.addStatusMessage(_('You cannot deactivate this item !'),
                                 type='error')
            smi.addStatusMessage(errors[0], type='error')
            view_url = getMultiAdapter((contact, contact.REQUEST),
                                       name=u'plone_context_state').view_url()
            # contact.REQUEST['RESPONSE'].redirect(view_url)
            raise Redirect(view_url)
class PlonegroupActionsColumn(ActionsColumn):
    """ """

    header = _("Actions")
    weight = 20
    params = {
        'useIcons': True,
        'showHistory': False,
        'showActions': True,
        'showOwnDelete': True,
        'showArrows': False,
        'showTransitions': False,
        'showPloneGroupLink': True
    }
    cssClasses = {'td': 'actions-column'}
def group_deleted(event):
    """
        Raises exception if group cannot be deleted
    """
    group = event.principal
    portal = api.portal.get()
    request = portal.REQUEST

    parts = group.split('_')
    if len(parts) == 1:
        return
    group_suffix = '_'.join(parts[1:])
    registry = getUtility(IRegistry)
    if parts[0] in registry[ORGANIZATIONS_REGISTRY] and group_suffix in get_all_suffixes(parts[0]):
        orga = api.content.find(UID=parts[0])[0].getObject()
        api.portal.show_message(message=_("You cannot delete the group '${group}', linked to used organization "
                                          "'${orga}'.", mapping={'group': group, 'orga': safe_unicode(orga.Title())}),
                                request=request, type='error')
        raise Redirect(request.get('ACTUAL_URL'))
class SelectedInPlonegroupColumn(BooleanColumn):
    """Column that displays Yes/No depending on fact that
       organization is selected in plonegroup organizations."""

    header = _("Selected in plonegroup")
    weight = 10

    def renderHeadCell(self):
        """ """
        portal = api.portal.get()
        plonegroup_url = '{0}/@@contact-plonegroup-settings'.format(
            portal.absolute_url())
        return translate("Selected in plonegroup",
                         domain='collective.contact.plonegroup',
                         mapping={'plonegroup_url': plonegroup_url},
                         context=self.request)

    def getValue(self, item):
        """ """
        plonegroup_organizations = get_registry_organizations()
        org_uid = item.UID
        return bool(org_uid in plonegroup_organizations)
class ManageOwnGroupUsers(EditForm):
    """
        Manage own groups users
    """
    label = _(u'Own groups management view')
    description = _(u'Own groups management description')
    successMessage = _(u'Own groups users succesfully updated.')
    noChangesMessage = _(u'No changes were made.')

    def __init__(self, context, request):
        self.context = context
        self.request = request
        self.functions = {}  # will contain function title by function id
        self.functions_orgs = {}  # will contain org list by function id
        self.groupids = {}  # will contain group title by group id
        self.fieldnames = []

    def init(self):
        """ user is now recognized """
        self.current_user = api.user.get_current()
        #        self.current_user = api.user.get(userid='chef')
        self.current_user_id = self.current_user.getId()
        self.current_user_groups = [
            g for g in api.group.get_groups(user=self.current_user) if g
        ]

    def get_manageable_functions(self):
        """ get all manageable functions """
        for fct in get_registry_functions(as_copy=False):
            if fct['fct_management']:
                self.functions[fct['fct_id']] = fct['fct_title']
        return self.functions.keys()

    def get_user_manageable_functions(self):
        """ get user manageable functions """
        manageable_functions = self.get_manageable_functions()
        for group in self.current_user_groups:
            parts = group.id.split('_')
            if len(parts) == 1:
                continue
            group_suffix = '_'.join(parts[1:])
            if group_suffix not in manageable_functions:
                continue
            if group_suffix not in self.functions_orgs:
                self.functions_orgs[group_suffix] = []
            org = get_organization(parts[0])
            if org not in self.functions_orgs[group_suffix]:
                self.functions_orgs[group_suffix].append(
                    get_organization(parts[0]))

    def get_manageable_groups(self):
        """ get selected manageable groups """
        return get_registry_groups_mgt()

    def get_user_manageable_groups(self):
        """ get user manageable groups """
        manageable_groups = self.get_manageable_groups()
        for group in self.current_user_groups:
            if group.id not in manageable_groups:
                continue
            self.groupids[group.id] = group.getProperty('title')

    def getContent(self):
        return GroupsConfigurationAdapter(self)

    @property
    def fields(self):
        self.init()  # second init with user recognized
        fields = []
        description = _(
            u'You can <span class="cross_icon">remove</span> an assignment with the '
            u'<span class="cross_icon">cross icon</span>. '
            u'You can <span class="auto_append">add</span> a new assignment with the '
            u'<span class="auto_append">blue line</span>. '
            u'You can <span class="new_line">complete</span> it on the '
            u'<span class="new_line">brown line</span>.')
        self.get_user_manageable_functions()
        for function in self.functions_orgs:
            fld = DGFListField(
                __name__=function,
                title=_(
                    u"Assignments for groups related to '${function}' function",
                    mapping={'function': self.functions[function]}),
                description=description,
                required=False,
                value_type=DictRow(title=u"org_users",
                                   schema=IOrganisationsUsers,
                                   required=False))
            fields.append(fld)
        fields = sorted(fields, key=lambda x: x.title)

        self.get_user_manageable_groups()
        if self.groupids:
            fld = DGFListField(__name__='_groups_',
                               title=_('Global groups assignments.'),
                               description=description,
                               required=False,
                               value_type=DictRow(title=u"users",
                                                  schema=IGroupsUsers,
                                                  required=False))
            fields.insert(0, fld)

        fld = schema.TextLine(
            __name__='_old_values_',
            title=u'not_showed',
            required=False,
        )
        fields.append(fld)

        self.fieldnames = [afield.__name__ for afield in fields]
        return field.Fields(*fields)

#    def datagridInitialise(self, subform, widget):
#        pass

#    def datagridUpdateWidgets(self, subform, widgets, widget):
#        pass

    def updateWidgets(self):
        super(ManageOwnGroupUsers, self).updateWidgets()
        for wid in self.widgets:
            if wid == '_old_values_':
                self.widgets[wid].mode = HIDDEN_MODE
            else:
                self.widgets[wid].allow_reorder = False
                self.widgets[wid].allow_insert = False
                self.widgets[wid].allow_delete = True
                self.widgets[wid].auto_append = True

    @button.buttonAndHandler(_z3cf('Apply'), name='apply')
    def handleApply(self, action):
        data, errors = self.extractData()
        if errors:
            self.status = self.formErrorsMessage
            return
        changes = False
        users = {}
        old_values = eval(data.pop('_old_values_'))
        for name in old_values:
            try:
                new_value = data[
                    name]  # If the field is not in the data, then go on to the next one
            except KeyError:
                continue
            new_value = set([(dic['group'], dic['user'])
                             for dic in data[name]])
            old_value = set([(dic['group'], dic['user'])
                             for dic in old_values[name]])
            if old_value == new_value:
                continue
            for action, result in (('removed', old_value - new_value),
                                   ('added', new_value - old_value)):
                for (group_id, user_id) in result:
                    if group_id is None or user_id is None:
                        required_message = _(
                            u"There was a problem in added assignments. "
                            u"Don't forget to complete the 2 columns! "
                            u"You have to redo all the manipulations.")
                        api.portal.show_message(message=required_message,
                                                request=self.request,
                                                type='error')
                        raise Redirect(self.request.get('ACTUAL_URL'))
                    if user_id == self.current_user_id:
                        user_message = _(
                            u"You cannot remove your user from a group!")
                        api.portal.show_message(message=user_message,
                                                request=self.request,
                                                type='error')
                        raise Redirect(self.request.get('ACTUAL_URL'))
                    if name != '_groups_':
                        group_id = get_plone_group_id(group_id, name)
                    if group_id not in users:
                        users[group_id] = [
                            u.id
                            for u in api.user.get_users(groupname=group_id)
                        ]
                    if action == 'removed' and user_id in users[group_id]:
                        api.group.remove_user(groupname=group_id,
                                              username=user_id)
                        changes = True
                    elif action == 'added' and user_id not in users[group_id]:
                        api.group.add_user(groupname=group_id,
                                           username=user_id)
                        changes = True
        if changes:
            api.portal.show_message(message=self.successMessage,
                                    request=self.request)
        else:
            api.portal.show_message(message=self.noChangesMessage,
                                    request=self.request,
                                    type='warn')
        self.request.response.redirect(self.request.get('ACTUAL_URL'))

    @button.buttonAndHandler(PMF(u'return_to_view'), name='cancel')
    def handleCancel(self, action):
        self.request.response.redirect(self.request.get('URL1'))
class IOrganizationSchema(Interface):
    """
        Organization identification schema
    """
    org_id = schema.TextLine(title=_("Organization id"), required=True)
    org_title = schema.TextLine(title=_("Organization title"), required=True)
class IContactPlonegroupConfig(Interface):
    """
        Configuration schema
    """

    # plone.registry cannot store schema.Choice different from named vocabularies !
    organizations = schema.List(
        title=_(u'Selected organizations'),
        description=
        _(u"Choose multiple organization levels for which you want to create a plone group."
          ),
        required=True,
        value_type=schema.Choice(
            vocabulary=u'collective.contact.plonegroup.organization_services',
        ))
    widget('organizations', size=15)

    functions = schema.List(
        title=_(u'Function list'),
        description=_(
            u'Each defined function will suffix each organization plone group.'
        ),
        required=True,
        value_type=DictRow(title=_("Function"), schema=IFunctionSchema))
    widget('functions', DataGridFieldFactory, auto_append=False)

    groups_management = schema.List(
        title=_(u'Selected global groups can be managed by a contained user'),
        required=False,
        value_type=schema.Choice(
            vocabulary=u'collective.contact.plonegroup.global_groups'),
    )
    widget('groups_management',
           CheckBoxFieldWidget,
           multiple='multiple',
           size=15)

    @invariant
    def validateSettings(data):
        if not data.organizations:
            raise Invalid(_(u"You must choose at least one organization !"))
        if len(data.organizations) == 1 and data.organizations[0] is None:
            raise Invalid(
                _(u"You must correct the organization error first !"))
        if not data.functions:
            raise Invalid(_(u"You must define at least one function !"))

        # only able to delete a function (suffix) if every linked Plone groups are empty
        stored_suffixes = get_all_suffixes()
        saved_suffixes = [func['fct_id'] for func in data.functions]
        removed_suffixes = list(set(stored_suffixes) - set(saved_suffixes))
        for removed_suffix in removed_suffixes:
            # check that every organizations including not selected
            # linked suffixed Plone group is empty
            for org_uid in get_organizations(only_selected=False,
                                             the_objects=False):
                plone_group_id = get_plone_group_id(org_uid, removed_suffix)
                plone_group = api.group.get(plone_group_id)
                if plone_group and plone_group.getMemberIds():
                    raise Invalid(
                        _(u"can_not_remove_function_every_plone_groups_not_empty",
                          mapping={
                              'removed_function': removed_suffix,
                              'plone_group_id': plone_group_id
                          }))

        # only able to select orgs for an existing function (suffix) if
        # every linked Plone groups of not selected orgs are empty
        stored_functions = get_registry_functions()
        old_functions = {
            dic['fct_id']: {
                'fct_title': dic['fct_title'],
                'fct_orgs': dic['fct_orgs'],
                'enabled': dic['enabled']
            }
            for dic in stored_functions
        }
        new_functions = {
            dic['fct_id']: {
                'fct_title': dic['fct_title'],
                'fct_orgs': dic['fct_orgs'],
                'enabled': dic['enabled']
            }
            for dic in data.functions
        }
        for new_function, new_function_infos in new_functions.items():
            if new_function_infos['fct_orgs'] and \
               old_functions[new_function]['fct_orgs'] != new_function_infos['fct_orgs']:
                # check that Plone group is empty for not selected fct_orgs
                for org_uid in get_organizations(only_selected=False,
                                                 the_objects=False):
                    if org_uid in new_function_infos['fct_orgs']:
                        continue
                    plone_group_id = get_plone_group_id(org_uid, new_function)
                    plone_group = api.group.get(plone_group_id)
                    # use getGroupMembers to ignore '<not found>' users
                    if plone_group and plone_group.getGroupMembers():
                        raise Invalid(
                            _(u"can_not_select_function_orgs_every_other_plone_groups_not_empty",
                              mapping={
                                  'function': new_function,
                                  'plone_group_id': plone_group_id
                              }))
            elif new_function_infos['enabled'] is False:
                # check that Plone groups are all empty
                for org_uid in get_organizations(only_selected=False,
                                                 the_objects=False):
                    plone_group_id = get_plone_group_id(org_uid, new_function)
                    plone_group = api.group.get(plone_group_id)
                    # use getGroupMembers to ignore '<not found>' users
                    if plone_group and plone_group.getGroupMembers():
                        raise Invalid(
                            _(u"can_not_disable_suffix_plone_groups_not_empty",
                              mapping={
                                  'disabled_function': new_function,
                                  'plone_group_id': plone_group_id
                              }))
 def handleApply(self, action):
     data, errors = self.extractData()
     if errors:
         self.status = self.formErrorsMessage
         return
     changes = False
     users = {}
     old_values = eval(data.pop('_old_values_'))
     for name in old_values:
         try:
             new_value = data[
                 name]  # If the field is not in the data, then go on to the next one
         except KeyError:
             continue
         new_value = set([(dic['group'], dic['user'])
                          for dic in data[name]])
         old_value = set([(dic['group'], dic['user'])
                          for dic in old_values[name]])
         if old_value == new_value:
             continue
         for action, result in (('removed', old_value - new_value),
                                ('added', new_value - old_value)):
             for (group_id, user_id) in result:
                 if group_id is None or user_id is None:
                     required_message = _(
                         u"There was a problem in added assignments. "
                         u"Don't forget to complete the 2 columns! "
                         u"You have to redo all the manipulations.")
                     api.portal.show_message(message=required_message,
                                             request=self.request,
                                             type='error')
                     raise Redirect(self.request.get('ACTUAL_URL'))
                 if user_id == self.current_user_id:
                     user_message = _(
                         u"You cannot remove your user from a group!")
                     api.portal.show_message(message=user_message,
                                             request=self.request,
                                             type='error')
                     raise Redirect(self.request.get('ACTUAL_URL'))
                 if name != '_groups_':
                     group_id = get_plone_group_id(group_id, name)
                 if group_id not in users:
                     users[group_id] = [
                         u.id
                         for u in api.user.get_users(groupname=group_id)
                     ]
                 if action == 'removed' and user_id in users[group_id]:
                     api.group.remove_user(groupname=group_id,
                                           username=user_id)
                     changes = True
                 elif action == 'added' and user_id not in users[group_id]:
                     api.group.add_user(groupname=group_id,
                                        username=user_id)
                     changes = True
     if changes:
         api.portal.show_message(message=self.successMessage,
                                 request=self.request)
     else:
         api.portal.show_message(message=self.noChangesMessage,
                                 request=self.request,
                                 type='warn')
     self.request.response.redirect(self.request.get('ACTUAL_URL'))
    def validateSettings(data):
        if not data.organizations:
            raise Invalid(_(u"You must choose at least one organization !"))
        if len(data.organizations) == 1 and data.organizations[0] is None:
            raise Invalid(
                _(u"You must correct the organization error first !"))
        if not data.functions:
            raise Invalid(_(u"You must define at least one function !"))

        # only able to delete a function (suffix) if every linked Plone groups are empty
        stored_suffixes = get_all_suffixes()
        saved_suffixes = [func['fct_id'] for func in data.functions]
        removed_suffixes = list(set(stored_suffixes) - set(saved_suffixes))
        for removed_suffix in removed_suffixes:
            # check that every organizations including not selected
            # linked suffixed Plone group is empty
            for org_uid in get_organizations(only_selected=False,
                                             the_objects=False):
                plone_group_id = get_plone_group_id(org_uid, removed_suffix)
                plone_group = api.group.get(plone_group_id)
                if plone_group and plone_group.getMemberIds():
                    raise Invalid(
                        _(u"can_not_remove_function_every_plone_groups_not_empty",
                          mapping={
                              'removed_function': removed_suffix,
                              'plone_group_id': plone_group_id
                          }))

        # only able to select orgs for an existing function (suffix) if
        # every linked Plone groups of not selected orgs are empty
        stored_functions = get_registry_functions()
        old_functions = {
            dic['fct_id']: {
                'fct_title': dic['fct_title'],
                'fct_orgs': dic['fct_orgs'],
                'enabled': dic['enabled']
            }
            for dic in stored_functions
        }
        new_functions = {
            dic['fct_id']: {
                'fct_title': dic['fct_title'],
                'fct_orgs': dic['fct_orgs'],
                'enabled': dic['enabled']
            }
            for dic in data.functions
        }
        for new_function, new_function_infos in new_functions.items():
            if new_function_infos['fct_orgs'] and \
               old_functions[new_function]['fct_orgs'] != new_function_infos['fct_orgs']:
                # check that Plone group is empty for not selected fct_orgs
                for org_uid in get_organizations(only_selected=False,
                                                 the_objects=False):
                    if org_uid in new_function_infos['fct_orgs']:
                        continue
                    plone_group_id = get_plone_group_id(org_uid, new_function)
                    plone_group = api.group.get(plone_group_id)
                    # use getGroupMembers to ignore '<not found>' users
                    if plone_group and plone_group.getGroupMembers():
                        raise Invalid(
                            _(u"can_not_select_function_orgs_every_other_plone_groups_not_empty",
                              mapping={
                                  'function': new_function,
                                  'plone_group_id': plone_group_id
                              }))
            elif new_function_infos['enabled'] is False:
                # check that Plone groups are all empty
                for org_uid in get_organizations(only_selected=False,
                                                 the_objects=False):
                    plone_group_id = get_plone_group_id(org_uid, new_function)
                    plone_group = api.group.get(plone_group_id)
                    # use getGroupMembers to ignore '<not found>' users
                    if plone_group and plone_group.getGroupMembers():
                        raise Invalid(
                            _(u"can_not_disable_suffix_plone_groups_not_empty",
                              mapping={
                                  'disabled_function': new_function,
                                  'plone_group_id': plone_group_id
                              }))