[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