Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move usergroups controlpanel (now using z3cform) from p.a.controlpanel to Products.CMFPlone #262

Merged
merged 10 commits into from
Dec 22, 2014
5 changes: 5 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ Changelog
https://github.com/plone/Products.CMFPlone/issues/290
[khink]

- PLIP 10359: Migrate usergroups controlpanel to ``z3c.form`` and move it from
plone.app.controlpanel to Products.CMFPlone. Fix and extend tests and add
robot tests.
[ferewuz]


5.0a3 (2014-11-01)
------------------
Expand Down
12 changes: 11 additions & 1 deletion Products/CMFPlone/controlpanel/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ Overview Control Panel
>>> tz_settings = registry.forInterface(IDateAndTimeSchema, prefix='plone')
>>> tz_settings.portal_timezone = 'UTC'


Markup Control Panel
------------------------

Expand All @@ -158,3 +158,13 @@ Markup Control Panel

>>> markup_settings.default_type = 'text/html'
>>> markup_settings.allowed_types = ('text/html', 'text/x-web-textile')


User and Groups Control Panel
------------------

>>> from Products.CMFPlone.interfaces import IUserGroupsSettingsSchema
>>> usergroups_settings = registry.forInterface(IUserGroupsSettingsSchema, prefix='plone')

>>> usergroups_settings.many_groups = False
>>> usergroups_settings.many_users = False
1 change: 1 addition & 0 deletions Products/CMFPlone/controlpanel/bbb/configure.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@
<adapter factory=".security.SecurityControlPanelAdapter" />
<adapter factory=".site.SiteControlPanelAdapter" />
<adapter factory=".markup.MarkupControlPanelAdapter" />
<adapter factory=".usergroups.UserGroupsSettingsControlPanelAdapter" />

</configure>
35 changes: 35 additions & 0 deletions Products/CMFPlone/controlpanel/bbb/usergroups.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from zope.component import getAdapter
from zope.site.hooks import getSite
from zope.component import adapts
from zope.interface import implements
from Products.CMFCore.utils import getToolByName
from Products.CMFPlone.interfaces import IUserGroupsSettingsSchema
from Products.CMFPlone.interfaces import IPloneSiteRoot


class UserGroupsSettingsControlPanelAdapter(object):

adapts(IPloneSiteRoot)
implements(IUserGroupsSettingsSchema)

def __init__(self, context):
self.context = context
self.portal = getSite()
pprop = getToolByName(context, 'portal_properties')
self.context = pprop.site_properties

def get_many_groups(self):
return self.context.many_groups

def set_many_groups(self, value):
self.context.many_groups = value

many_groups = property(get_many_groups, set_many_groups)

def get_many_users(self):
return self.context.many_users

def set_many_users(self, value):
self.context.many_users = value

many_users = property(get_many_users, set_many_users)
48 changes: 48 additions & 0 deletions Products/CMFPlone/controlpanel/browser/configure.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -123,4 +123,52 @@
permission="plone.app.controlpanel.Markup"
/>

<!-- Usergroup Control Panel -->
<browser:page
name="usergroup-controlpanel"
for="Products.CMFPlone.interfaces.IPloneSiteRoot"
class=".usergroups.UserGroupsSettingsPanelView"
permission="plone.app.controlpanel.UsersAndGroups"
/>

<browser:page
name="usergroup-userprefs"
for="Products.CMFPlone.interfaces.IPloneSiteRoot"
class=".usergroups_usersoverview.UsersOverviewControlPanel"
permission="plone.app.controlpanel.UsersAndGroups"
template="usergroups_usersoverview.pt"
/>

<browser:page
name="usergroup-groupprefs"
for="Products.CMFPlone.interfaces.IPloneSiteRoot"
class=".usergroups_groupsoverview.GroupsOverviewControlPanel"
permission="plone.app.controlpanel.UsersAndGroups"
template="usergroups_groupsoverview.pt"
/>

<browser:page
name="usergroup-groupmembership"
for="Products.CMFPlone.interfaces.IPloneSiteRoot"
class=".usergroups_groupmembership.GroupMembershipControlPanel"
permission="plone.app.controlpanel.UsersAndGroups"
template="usergroups_groupmembership.pt"
/>

<browser:page
name="usergroup-usermembership"
for="Products.CMFPlone.interfaces.IPloneSiteRoot"
class=".usergroups_usermembership.UserMembershipControlPanel"
permission="plone.app.controlpanel.UsersAndGroups"
template="usergroups_usermembership.pt"
/>

<browser:page
name="usergroup-groupdetails"
for="Products.CMFPlone.interfaces.IPloneSiteRoot"
class=".usergroups_groupdetails.GroupDetailsControlPanel"
permission="plone.app.controlpanel.UsersAndGroups"
template="usergroups_groupdetails.pt"
/>

</configure>
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
xmlns:tal="http://xml.zope.org/namespaces/tal"
xmlns:metal="http://xml.zope.org/namespaces/metal"
xmlns:i18n="http://xml.zope.org/namespaces/i18n"
lang="en"
metal:use-macro="here/prefs_main_template/macros/master"
i18n:domain="plone">

<body>

<div metal:fill-slot="prefs_configlet_main">

<a href=""
id="setup-link"
tal:attributes="href string:$portal_url/plone_control_panel"
i18n:translate="">
Site Setup
</a> &rsaquo;

<h1 class="documentFirstHeading" tal:content="view/label">View Title</h1>

<div metal:use-macro="context/global_statusmessage/macros/portal_message">
Portal status message
</div>

<div id="layout-contents">

<div id="edit-bar">
<ul class="contentViews" id="content-views">
<li>
<a href=""
tal:attributes="href string:$portal_url/@@usergroup-userprefs"
i18n:translate="label_users">Users</a>
</li>
<li>
<a href=""
tal:attributes="href string:$portal_url/@@usergroup-groupprefs"
i18n:translate="label_groups">Groups</a>
</li>
<li class="selected">
<a href=""
tal:attributes="href string:$portal_url/@@usergroup-controlpanel"
i18n:translate="label_usergroup_settings">Settings</a>
</li>
<li>
<a href=""
tal:attributes="href string:$portal_url/@@member-registration"
i18n:translate="label_member_registration">Member Registration</a>
</li>
</ul>
<div class="contentActions">&nbsp;</div>
</div>

<span tal:replace="structure view/contents" />
</div>

</div>

</body>
</html>
131 changes: 131 additions & 0 deletions Products/CMFPlone/controlpanel/browser/usergroups.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
from Products.CMFCore.permissions import ManagePortal
from ZTUtils import make_query
from itertools import chain
from Acquisition import aq_inner
from Products.CMFPlone.utils import normalizeString
from zope.component import getAdapter
from Products.CMFPlone.interfaces import ISecuritySchema
from zope.component import getMultiAdapter
from AccessControl import getSecurityManager
from Products.Five.browser import BrowserView
from Products.CMFCore.utils import getToolByName
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
from plone.z3cform import layout
from plone.autoform.form import AutoExtensibleForm
from Products.CMFPlone import PloneMessageFactory as _
from z3c.form import form

from Products.CMFPlone.interfaces import IUserGroupsSettingsSchema


class UserGroupsSettingsControlPanel(AutoExtensibleForm, form.EditForm):
schema = IUserGroupsSettingsSchema
id = "usergroupsettings-control-panel"
label = _("User/Groups settings")
description = _("User and groups settings for this site.")
form_name = _("User/Groups settings")
control_panel_view = "usergroups-controlpanel"


class ControlPanelFormWrapper(layout.FormWrapper):
"""Use this form as the plone.z3cform layout wrapper to get the control
panel layout.
"""

index = ViewPageTemplateFile('controlpanel_usergroups_layout.pt')


UserGroupsSettingsPanelView = layout.wrap_form(
UserGroupsSettingsControlPanel, ControlPanelFormWrapper
)


class UsersGroupsControlPanelView(BrowserView):

@property
def portal_roles(self):
pmemb = getToolByName(aq_inner(self.context), 'portal_membership')
return [r for r in pmemb.getPortalRoles() if r != 'Owner']

@property
def many_users(self):
pprop = getToolByName(aq_inner(self.context), 'portal_properties')
return pprop.site_properties.many_users

@property
def many_groups(self):
pprop = getToolByName(aq_inner(self.context), 'portal_properties')
return pprop.site_properties.many_groups

@property
def email_as_username(self):
return getAdapter(aq_inner(self.context), ISecuritySchema).get_use_email_as_login()

def makeQuery(self, **kw):
return make_query(**kw)

def membershipSearch(self, searchString='', searchUsers=True, searchGroups=True, ignore=[]):
"""Search for users and/or groups, returning actual member and group items
Replaces the now-deprecated prefs_user_groups_search.py script"""
groupResults = userResults = []

gtool = getToolByName(self, 'portal_groups')
mtool = getToolByName(self, 'portal_membership')

searchView = getMultiAdapter((aq_inner(self.context), self.request), name='pas_search')

if searchGroups:
groupResults = searchView.merge(chain(*[searchView.searchGroups(**{field: searchString}) for field in ['id', 'title']]), 'groupid')
groupResults = [gtool.getGroupById(g['id']) for g in groupResults if g['id'] not in ignore]
groupResults.sort(key=lambda x: x is not None and normalizeString(x.getGroupTitleOrName()))

if searchUsers:
userResults = searchView.merge(chain(*[searchView.searchUsers(**{field: searchString}) for field in ['login', 'fullname', 'email']]), 'userid')
userResults = [mtool.getMemberById(u['id']) for u in userResults if u['id'] not in ignore]
userResults.sort(key=lambda x: x is not None and x.getProperty('fullname') is not None and normalizeString(x.getProperty('fullname')) or '')

return groupResults + userResults

def atoi(self, s):
try:
return int(s)
except ValueError:
return 0

@property
def is_zope_manager(self):
return getSecurityManager().checkPermission(ManagePortal, self.context)

# The next two class methods implement the following truth table:
#
# MANY USERS/GROUPS SEARCHING CAN LIST USERS/GROUPS RESULT
# False False False Lists unavailable
# False False True Show all
# False True False Show matching
# False True True Show matching
# True False False Too many to list
# True False True Lists unavailable
# True True False Show matching
# True True True Show matching

# TODO: Maybe have these methods return a text message (instead of a bool)
# corresponding to the actual result, e.g. "Too many to list", "Lists unavailable"

@property
def show_group_listing_warning(self):
if not self.searchString:
acl = getToolByName(self, 'acl_users')
if acl.canListAllGroups():
if self.many_groups:
return True
return False

@property
def show_users_listing_warning(self):
if not self.searchString:
acl = getToolByName(self, 'acl_users')
# XXX Huh? Is canListAllUsers broken?
if not acl.canListAllUsers():
if self.many_users:
return True
return False
Loading