[Checkins] SVN: Products.CMFDefault/trunk/Products/CMFDefault/browser/ - refactored folder contents and members listings
Yvo Schubbe
cvs-admin at zope.org
Fri Jul 20 14:22:17 UTC 2012
Log message for revision 127357:
- refactored folder contents and members listings
Changed:
U Products.CMFDefault/trunk/Products/CMFDefault/browser/content/folder.py
U Products.CMFDefault/trunk/Products/CMFDefault/browser/content/folder_contents.pt
U Products.CMFDefault/trunk/Products/CMFDefault/browser/content/interfaces.py
U Products.CMFDefault/trunk/Products/CMFDefault/browser/content/tests/folder.txt
U Products.CMFDefault/trunk/Products/CMFDefault/browser/content/tests/test_folder.py
U Products.CMFDefault/trunk/Products/CMFDefault/browser/membership/members.pt
U Products.CMFDefault/trunk/Products/CMFDefault/browser/membership/members.py
U Products.CMFDefault/trunk/Products/CMFDefault/browser/membership/members_delete.pt
U Products.CMFDefault/trunk/Products/CMFDefault/browser/membership/tests/members.txt
U Products.CMFDefault/trunk/Products/CMFDefault/browser/membership/tests/test_members.py
-=-
Modified: Products.CMFDefault/trunk/Products/CMFDefault/browser/content/folder.py
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/browser/content/folder.py 2012-07-20 14:11:03 UTC (rev 127356)
+++ Products.CMFDefault/trunk/Products/CMFDefault/browser/content/folder.py 2012-07-20 14:22:14 UTC (rev 127357)
@@ -24,7 +24,6 @@
from ZTUtils import LazyFilter
from .interfaces import IDeltaItem
-from .interfaces import IFolderItem
from Products.CMFCore.interfaces import IDynamicType
from Products.CMFCore.interfaces import IMembershipTool
from Products.CMFDefault.browser.utils import decode
@@ -157,29 +156,23 @@
return _(u'Folder Contents: ${obj_title}',
mapping={'obj_title': self.title()})
- def content_fields(self):
- """Create content field objects only for batched items"""
- show_widgets = self._checkPermission(ViewManagementScreens)
- f = IFolderItem['select']
+ @memoize
+ def listBatchItems(self):
+ """List batched items.
+ """
+ show_checkboxes = self._checkPermission(ViewManagementScreens)
contents = []
b_start = self._getBatchStart()
key, _reverse = self._get_sorting()
- fields = form.FormFields()
for idx, item in enumerate(self._getBatchObj()):
- field = form.FormField(f, 'select', item.id)
- fields += form.FormFields(field)
content = ContentProxy(item)
- if show_widgets:
- content.widget = '{0}.select'.format(content.name)
- else:
- content.widget = None
+ content.checkbox = show_checkboxes
if key == 'position':
content.position = b_start + idx + 1
else:
content.position = '...'
contents.append(content)
- self.listBatchItems = contents
- return fields
+ return tuple(contents)
@memoize
@decode
@@ -205,9 +198,6 @@
"""Create widgets for the folder contents."""
super(ContentsView, self).setUpWidgets(ignore_request)
self.widgets = form.setUpWidgets(
- self.content_fields(), self.prefix, self.context,
- self.request, ignore_request=ignore_request)
- self.widgets += form.setUpWidgets(
self.delta_field, self.prefix, self.context,
self.request, ignore_request=ignore_request)
@@ -248,11 +238,13 @@
items = self.context.contentValues()
return sort(items, ((key, 'cmp', reverse and 'desc' or 'asc'),))
- def _get_ids(self, data):
+ @memoize
+ def _get_ids(self):
"""Identify objects that have been selected"""
- ids = [k[:-7] for k, v in data.items()
- if v is True and k.endswith('.select')]
- return ids
+ ids = self.request.form.get('form.select_ids', [])
+ if isinstance(ids, basestring):
+ ids = [ids]
+ return [ str(id) for id in ids ]
#Action conditions
@memoize
@@ -312,7 +304,7 @@
errors = self.validate(action, data)
if errors:
return errors
- if self._get_ids(data) == []:
+ if self._get_ids() == []:
errors.append(_(u"Please select one or more items first."))
return errors
@@ -321,14 +313,14 @@
"""Redirect to rename view passing the ids of objects to be renamed"""
# currently redirects to a PythonScript
# should be replaced with a dedicated form
- self.request.form['ids'] = self._get_ids(data)
+ self.request.form['ids'] = self._get_ids()
keys = ",".join(self._getNavigationVars().keys() + ['ids'])
# keys = 'b_start, ids, key, reverse'
return self._setRedirect('portal_types', 'object/rename_items', keys)
def handle_cut(self, action, data):
"""Cut the selected objects and put them in the clipboard"""
- ids = self._get_ids(data)
+ ids = self._get_ids()
try:
self.context.manage_cutObjects(ids, self.request)
if len(ids) == 1:
@@ -343,7 +335,7 @@
def handle_copy(self, action, data):
"""Copy the selected objects to the clipboard"""
- ids = self._get_ids(data)
+ ids = self._get_ids()
try:
self.context.manage_copyObjects(ids, self.request)
if len(ids) == 1:
@@ -373,7 +365,7 @@
def handle_delete(self, action, data):
"""Delete the selected objects"""
- ids = self._get_ids(data)
+ ids = self._get_ids()
self.context.manage_delObjects(list(ids))
if len(ids) == 1:
self.status = _(u'Item deleted.')
@@ -383,7 +375,7 @@
def handle_up(self, action, data):
"""Move the selected objects up the selected number of places"""
- ids = self._get_ids(data)
+ ids = self._get_ids()
delta = data.get('delta', 1)
subset_ids = [obj.getId()
for obj in self.context.listFolderContents()]
@@ -402,7 +394,7 @@
def handle_down(self, action, data):
"""Move the selected objects down the selected number of places"""
- ids = self._get_ids(data)
+ ids = self._get_ids()
delta = data.get('delta', 1)
subset_ids = [obj.getId()
for obj in self.context.listFolderContents()]
@@ -421,7 +413,7 @@
def handle_top(self, action, data):
"""Move the selected objects to the top of the page"""
- ids = self._get_ids(data)
+ ids = self._get_ids()
subset_ids = [obj.getId()
for obj in self.context.listFolderContents()]
try:
@@ -439,7 +431,7 @@
def handle_bottom(self, action, data):
"""Move the selected objects to the bottom of the page"""
- ids = self._get_ids(data)
+ ids = self._get_ids()
subset_ids = [obj.getId()
for obj in self.context.listFolderContents()]
try:
Modified: Products.CMFDefault/trunk/Products/CMFDefault/browser/content/folder_contents.pt
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/browser/content/folder_contents.pt 2012-07-20 14:11:03 UTC (rev 127356)
+++ Products.CMFDefault/trunk/Products/CMFDefault/browser/content/folder_contents.pt 2012-07-20 14:22:14 UTC (rev 127357)
@@ -31,8 +31,8 @@
</tr>
<tr tal:repeat="item view/listBatchItems"
tal:attributes="class python: (repeat['item'].even() and 'row-hilite') or None">
- <td><tal:case tal:condition="item/widget"
- tal:content="structure python: view.widgets[item.widget]()">Checkbox</tal:case></td>
+ <td><input name="form.select_ids" type="checkbox" value=""
+ tal:condition="item/checkbox" tal:attributes="value item/name" /></td>
<td><a href="" tal:attributes="href item/url"
tal:condition="item/icon"
><img src="" alt="" border="0"
Modified: Products.CMFDefault/trunk/Products/CMFDefault/browser/content/interfaces.py
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/browser/content/interfaces.py 2012-07-20 14:11:03 UTC (rev 127356)
+++ Products.CMFDefault/trunk/Products/CMFDefault/browser/content/interfaces.py 2012-07-20 14:22:14 UTC (rev 127357)
@@ -14,7 +14,6 @@
"""
from zope.interface import Interface
-from zope.schema import Bool
from zope.schema import Choice
from zope.schema import TextLine
@@ -24,9 +23,6 @@
class IFolderItem(Interface):
"""Schema for folderish objects contents."""
- select = Bool(
- required=False)
-
name = TextLine(
title=u"Name",
required=False,
Modified: Products.CMFDefault/trunk/Products/CMFDefault/browser/content/tests/folder.txt
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/browser/content/tests/folder.txt 2012-07-20 14:11:03 UTC (rev 127356)
+++ Products.CMFDefault/trunk/Products/CMFDefault/browser/content/tests/folder.txt 2012-07-20 14:22:14 UTC (rev 127357)
@@ -87,7 +87,7 @@
Copy the 'Members' subfolder:
- >>> browser.getControl(name='form.Members.select').value = True
+ >>> browser.getControl(name='form.select_ids').value = ('Members',)
>>> browser.getControl('[[cmf_default][Copy]]').click()
>>> '[[cmf_default][Item copied.]]' in browser.contents
True
Modified: Products.CMFDefault/trunk/Products/CMFDefault/browser/content/tests/test_folder.py
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/browser/content/tests/test_folder.py 2012-07-20 14:11:03 UTC (rev 127356)
+++ Products.CMFDefault/trunk/Products/CMFDefault/browser/content/tests/test_folder.py 2012-07-20 14:22:14 UTC (rev 127357)
@@ -81,8 +81,7 @@
def test_list_batch_items(self):
view = ContentsView(self.folder, TestRequest())
view._getNavigationVars = lambda: {}
- view.content_fields()
- self.assertEqual(view.listBatchItems, [])
+ self.assertEqual(view.listBatchItems(), ())
def test_is_orderable(self):
view = ContentsView(self.folder, TestRequest())
@@ -116,16 +115,10 @@
view.validate_items, "", {'foo': 'bar'})
def test_get_ids(self):
- view = ContentsView(self.folder, TestRequest())
- self.assertEqual(view._get_ids({'foo': 'bar'}),
- [])
- self.assertEqual(view._get_ids({'DummyItem1.select': True,
- 'DummyItem2.select': False,
- 'DummyItem3.select': True}),
- ['DummyItem1', 'DummyItem3'])
- self.assertEqual(view._get_ids({'delta': True,
- 'delta': 1}),
- [])
+ request = TestRequest(form={'form.select_ids': ['DummyItem1',
+ 'DummyItem3']})
+ view = ContentsView(self.folder, request)
+ self.assertEqual(view._get_ids(), ['DummyItem1', 'DummyItem3'])
class FolderViewTests(unittest.TestCase):
Modified: Products.CMFDefault/trunk/Products/CMFDefault/browser/membership/members.pt
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/browser/membership/members.pt 2012-07-20 14:11:03 UTC (rev 127356)
+++ Products.CMFDefault/trunk/Products/CMFDefault/browser/membership/members.pt 2012-07-20 14:22:14 UTC (rev 127357)
@@ -22,12 +22,11 @@
<tbody>
<tr tal:repeat="item view/listBatchItems"
tal:attributes="class python: (repeat['item'].even() and 'row-hilite') or None">
- <td tal:content="structure python:view.widgets[item.widget]()"></td>
- <td><a href="" tal:condition="item/home"
- tal:content="item/name"
- tal:attributes="href item/home">User name</a>
- <tal:block condition="not: item/home" replace="item/name" />
- </td>
+ <td><input name="form.select_ids" type="checkbox" value=""
+ tal:attributes="value item/name" /></td>
+ <td><a href="" tal:omit-tag="not: item/home"
+ tal:content="string:${item/fullname} (${item/name})"
+ tal:attributes="href item/home">FULL NAME (ID)</a></td>
<td><a href=""
tal:content="item/email"
tal:attributes="href string:mailto:${item/email}"></a></td>
Modified: Products.CMFDefault/trunk/Products/CMFDefault/browser/membership/members.py
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/browser/membership/members.py 2012-07-20 14:11:03 UTC (rev 127356)
+++ Products.CMFDefault/trunk/Products/CMFDefault/browser/membership/members.py 2012-07-20 14:22:14 UTC (rev 127357)
@@ -17,7 +17,6 @@
from zope.component import getUtility
from zope.formlib import form
from zope.interface import Interface
-from zope.schema import Bool
from zope.schema import Date
from zope.schema import TextLine
@@ -35,9 +34,6 @@
"""Schema for portal members """
- select = Bool(
- required=False)
-
name = TextLine(
title=u"Name",
required=False,
@@ -61,23 +57,21 @@
"""Utility class wrapping a member for display purposes"""
- def __init__(self, member, mtool):
+ def __init__(self, member, mtool, charset):
member_id = member.getId()
- fullname = member.getProperty('fullname')
last_login = member.getProperty('login_time')
never_logged_in = str(last_login).startswith('2000/01/01')
self.login_time = never_logged_in and '---' or last_login.Date()
- self.name = '%s (%s)' % (fullname, member_id)
+ self.name = member_id
+ self.fullname = member.getProperty('fullname').decode(charset)
self.home = mtool.getHomeUrl(member_id, verifyPermission=0)
self.email = member.getProperty('email')
- self.widget = "%s.select" % member_id
class Manage(BatchFormMixin, EditFormBase):
template = ViewPageTemplateFile("members.pt")
delete_template = ViewPageTemplateFile("members_delete.pt")
- guillotine = None
form_fields = form.FormFields()
hidden_fields = form.FormFields(IBatchForm)
@@ -93,9 +87,7 @@
condition='members_exist',
success='handle_select_for_deletion',
failure='handle_failure',
- validator=('validate_items')
- )
- )
+ validator=('validate_items')))
delete_actions = form.Actions(
form.Action(
@@ -105,10 +97,8 @@
failure='handle_failure'),
form.Action(
name='cancel',
- label=_(u'Cancel'),
- success='handle_cancel'
- )
- )
+ label=_(u'Cancel')))
+
actions = manage_actions + delete_actions
label = _(u'Manage Members')
@@ -127,33 +117,35 @@
def members_exist(self, action=None):
return len(self._getBatchObj()) > 0
- def _get_ids(self, data):
+ @memoize
+ def _get_ids(self):
"""Identify objects that have been selected"""
- ids = [k[:-7] for k, v in data.items()
- if v is True and k.endswith('.select')]
- return ids
+ ids = self.request.form.get('form.select_ids', [])
+ if isinstance(ids, basestring):
+ ids = [ids]
+ return [ str(id) for id in ids ]
@memoize
- def member_fields(self):
+ def listBatchItems(self):
"""Create content field objects only for batched items
- Also create pseudo-widget for each item
"""
mtool = getUtility(IMembershipTool)
- f = IMemberItem['select']
+ charset = self._getDefaultCharset()
members = []
- fields = form.FormFields()
for item in self._getBatchObj():
- field = form.FormField(f, 'select', item.getId())
- fields += form.FormFields(field)
- members.append(MemberProxy(item, mtool))
- self.listBatchItems = members
- return fields
+ members.append(MemberProxy(item, mtool, charset))
+ return tuple(members)
+ @memoize
+ def listSelectedItems(self):
+ ids = self._get_ids()
+ members = [ m for m in self.listBatchItems() if m.name in ids ]
+ return tuple(members)
+
def setUpWidgets(self, ignore_request=False):
"""Create widgets for the members"""
super(Manage, self).setUpWidgets(ignore_request)
- self.widgets = form.setUpWidgets(self.member_fields(), self.prefix,
- self.context, self.request, ignore_request=ignore_request)
+ self.widgets = self.hidden_widgets
def validate_items(self, action=None, data=None):
"""Check whether any items have been selected for
@@ -161,7 +153,7 @@
errors = self.validate(action, data)
if errors:
return errors
- if self._get_ids(data) == []:
+ if self._get_ids() == []:
errors.append(_(u"Please select one or more members first."))
return errors
@@ -172,31 +164,17 @@
def handle_select_for_deletion(self, action, data):
"""Identify members to be deleted and redirect to confirmation
template"""
- mtool = getUtility(IMembershipTool)
- charset = self._getDefaultCharset()
- members = []
- for member_id in self._get_ids(data):
- member = mtool.getMemberById(member_id)
- fullname = member.getProperty('fullname').decode(charset)
- members.append(u'{0} ({1})'.format(fullname, member_id))
- self.guillotine = u', '.join(members)
return self.delete_template()
def handle_delete(self, action, data):
"""Delete selected members"""
mtool = getUtility(IMembershipTool)
- mtool.deleteMembers(self._get_ids(data))
+ mtool.deleteMembers(self._get_ids())
self.status = _(u"Selected members deleted.")
self._setRedirect('portal_actions', "global/manage_members",
'{0}.b_start'.format(self.prefix))
- def handle_cancel(self, action, data):
- """Don't delete anyone, return to list"""
- self.status = _(u"Deletion broken off.")
- self._setRedirect('portal_actions', "global/manage_members",
- '{0}.b_start'.format(self.prefix))
-
class Roster(BatchViewBase):
@property
Modified: Products.CMFDefault/trunk/Products/CMFDefault/browser/membership/members_delete.pt
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/browser/membership/members_delete.pt 2012-07-20 14:11:03 UTC (rev 127356)
+++ Products.CMFDefault/trunk/Products/CMFDefault/browser/membership/members_delete.pt 2012-07-20 14:22:14 UTC (rev 127357)
@@ -7,17 +7,25 @@
<form action="." method="post" tal:attributes="action request/ACTUAL_URL">
<tal:block repeat="widget view/hidden_widgets"
replace="structure widget/hidden" />
- <tal:block repeat="widget view/widgets"
- replace="structure widget/hidden" />
-
<p i18n:translate="">The following members - including all their data, home
folders and roles - are selected for deletion:</p>
- <p><strong tal:content="view/guillotine">MEMBERS</strong></p>
-
- <div class="FormButtons">
- <tal:loop tal:repeat="action view/delete_actions"
+ <p><tal:loop tal:repeat="item view/listSelectedItems">
+ <input class="hiddenType" name="form.select_ids" type="hidden" value=""
+ tal:attributes="value item/name" />
+ <strong><a href="" tal:omit-tag="not: item/home"
+ tal:content="string:${item/fullname} (${item/name})"
+ tal:attributes="href item/home">FULL NAME (ID)</a
+ ></strong><tal:case tal:condition="not: repeat/item/end">, </tal:case
+ ></tal:loop></p>
+
+<div class="form">
+<div class="clear"></div>
+
+<div class="buttons">
+ <tal:loop tal:repeat="action view/delete_actions"
tal:replace="structure action/render" />
- </div>
+</div>
+</div>
</form>
</metal:slot>
Modified: Products.CMFDefault/trunk/Products/CMFDefault/browser/membership/tests/members.txt
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/browser/membership/tests/members.txt 2012-07-20 14:11:03 UTC (rev 127356)
+++ Products.CMFDefault/trunk/Products/CMFDefault/browser/membership/tests/members.txt 2012-07-20 14:22:14 UTC (rev 127357)
@@ -40,19 +40,19 @@
True
Click delete with member selected
- >>> browser.getControl(name="form.Bob.select").value = True
+ >>> browser.getControl(name="form.select_ids").value = ('Bob',)
>>> browser.getControl(name="form.actions.select").click()
>>> "[[cmf_default][The following members - including all their data, home folders and roles - are selected for deletion" in browser.contents
True
Cancel deletion
>>> browser.getControl(name="form.actions.cancel").click()
- >>> "[[cmf_default][Deletion broken off.]" in browser.contents
+ >>> "[[cmf_default][Manage Members]" in browser.contents
True
Delete selected member
>>> browser.open("http://localhost/site/@@members.html")
- >>> browser.getControl(name="form.Bob.select").value = True
+ >>> browser.getControl(name="form.select_ids").value = ('Bob',)
>>> browser.getControl(name="form.actions.select").click()
>>> browser.getControl(name="form.actions.delete").click()
>>> "[[cmf_default][Selected members deleted.]" in browser.contents
Modified: Products.CMFDefault/trunk/Products/CMFDefault/browser/membership/tests/test_members.py
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/browser/membership/tests/test_members.py 2012-07-20 14:11:03 UTC (rev 127356)
+++ Products.CMFDefault/trunk/Products/CMFDefault/browser/membership/tests/test_members.py 2012-07-20 14:22:14 UTC (rev 127357)
@@ -111,39 +111,25 @@
self._make_one("Bob")
view = Manage(self.site, TestRequest())
view._getNavigationVars = lambda: {}
- view.member_fields()
- members = view.listBatchItems
+ members = view.listBatchItems()
self.assertTrue(isinstance(members[0], MemberProxy))
- self.assertEqual(members[0].name, 'FULL NAME (Bob)')
+ self.assertEqual(members[0].name, 'Bob')
+ self.assertEqual(members[0].fullname, 'FULL NAME')
self.assertEqual(members[0].home, "HOME_URL/Bob")
def test_get_ids(self):
- view = Manage(self.site, TestRequest())
- self.assertEqual(view._get_ids({'foo': 'bar'}),
- [])
- self.assertEqual(sorted(view._get_ids({'DummyUser1.select': True,
- 'DummyUser2.select': False,
- 'DummyUser3.select': True})),
- ['DummyUser1', 'DummyUser3'])
- self.assertEqual(view._get_ids({'stupid.name.select.select': True}),
- ['stupid.name.select'])
+ request = TestRequest(form={'form.select_ids': ['DummyUser1',
+ 'DummyUser3']})
+ view = Manage(self.site, request)
+ self.assertEqual(view._get_ids(), ['DummyUser1', 'DummyUser3'])
- def test_handle_select_for_deletion(self):
- self._make_one("Alice")
- view = Manage(self.site, TestRequest())
- self.assertEqual(view.guillotine, None)
- # Catch exception raised when template tries to render
- self.assertRaises(AttributeError,
- view.handle_select_for_deletion, None, {"Alice.select": True})
- self.assertEqual(view.guillotine, "FULL NAME (Alice)")
-
def test_handle_delete(self):
self._make_one("Bob")
- view = Manage(self.site, TestRequest())
+ request = TestRequest(form={'form.select_ids': ['Bob']})
+ view = Manage(self.site, request)
self.assertFalse(self.mtool.listMembers() == [])
# Catch exception raised when trying to redirect
- self.assertRaises(TypeError,
- view.handle_delete, None, {"Bob.select": True})
+ self.assertRaises(TypeError, view.handle_delete, None, {})
self.assertTrue(self.mtool.listMembers() == [])
More information about the checkins
mailing list