Skip to content

Commit

Permalink
Merge pull request #336 from zopefoundation/zmi-fix-broken-objects
Browse files Browse the repository at this point in the history
Fix handling of broken objects in ZMI
  • Loading branch information
viktordick committed Oct 3, 2018
2 parents 4e3e995 + e8a6091 commit 6fba729
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 11 deletions.
41 changes: 41 additions & 0 deletions src/OFS/ObjectManager.py
Expand Up @@ -48,6 +48,7 @@
from zope.interface.interfaces import ComponentLookupError
from zope.lifecycleevent import ObjectAddedEvent
from zope.lifecycleevent import ObjectRemovedEvent
import zope.sequencesort

from App.Common import is_acquired
from App.config import getConfiguration
Expand Down Expand Up @@ -865,6 +866,46 @@ def last_modified(self, ob):
except (DateTimeError, AttributeError):
return ''

security.declareProtected(view_management_screens, 'manage_get_sortedObjects')
def manage_get_sortedObjects(self, sortkey, revkey):
'''
Return dictionaries used for the management page, sorted by sortkey
(which is 'id' or an attribute of the objects). The direction is
determined by rkey, which can be 'asc' for ascending or 'desc' for
descending.
It returns a list of dictionaries, with keys 'id' and 'obj', where 'id'
is the ID of the object as known by the parent and 'obj' is the child
object.
'''
if sortkey not in ['title', 'meta_type', 'get_size', '_p_mtime']:
sortkey = 'id'

items = []
for id, obj in self.objectItems():
item = {'id': id, 'obj': obj}
if sortkey != 'id' and hasattr(obj, sortkey):
# add the attribute by which we need to sort
item[sortkey] = getattr(obj, sortkey)
items.append(item)

if sortkey in ['id', 'title', 'meta_type']:
sort_func = 'strcoll'
else:
sort_func = 'cmp'

sorted_items = zope.sequencesort.sort(
items,
((sortkey, sort_func, revkey), ),
mapping = 1
)

# remove the additional attribute
return [
{'id': item['id'], 'obj': item['obj']}
for item in sorted_items
]



# Don't InitializeClass, there is a specific __class_init__ on ObjectManager
# InitializeClass(ObjectManager)
Expand Down
49 changes: 49 additions & 0 deletions src/OFS/tests/testSorting.py
@@ -0,0 +1,49 @@
# -*- coding: utf-8 -*-
import codecs
import Testing.ZopeTestCase
import Testing.testbrowser
import Zope2.App


class SortingTests(Testing.ZopeTestCase.FunctionalTestCase):
"""Browser testing ..Image.File"""

def setUp(self):
super(SortingTests, self).setUp()

Zope2.App.zcml.load_site(force=True)

uf = self.app.acl_users
uf.userFolderAddUser('manager', 'manager_pass', ['Manager'], [])
self.app.manage_addFolder('sortingTest')
self.app.sortingTest.manage_addFile('File1')
self.app.sortingTest.manage_addFile('File2')
self.app.sortingTest.File1.update_data(u'hällo'.encode('utf-8'))

self.browser = Testing.testbrowser.Browser()
self.browser.addHeader(
'Authorization',
'basic {}'.format(codecs.encode(
b'manager:manager_pass', 'base64').decode()))

def test_sortby(self):
base_url = 'http://localhost/sortingTest/manage_main?skey=%s&rkey=%s'

def do_assert(one_before_two):
one_before_two_found = (
self.browser.contents.find('File2') >
self.browser.contents.find('File1')
)
self.assertEqual(one_before_two, one_before_two_found)

self.browser.open(base_url % ('id', 'asc'))
do_assert(one_before_two=True)

self.browser.open(base_url % ('id', 'desc'))
do_assert(one_before_two=False)

self.browser.open(base_url % ('get_size', 'asc'))
do_assert(one_before_two=False)

self.browser.open(base_url % ('get_size', 'desc'))
do_assert(one_before_two=True)
23 changes: 12 additions & 11 deletions src/OFS/zpt/main.zpt
Expand Up @@ -6,12 +6,11 @@
<form name="objectItems" method="post"
tal:define="
sm modules/AccessControl/SecurityManagement/getSecurityManager;
obs here/objectValues;
skey python:request.get('skey','getId');
skey python:request.get('skey','id');
rkey python:request.get('rkey','asc');
rkey_alt python:request.get('rkey','asc')=='asc' and 'desc' or 'asc';
sort_func python:['nocase','cmp'][skey not in ['getId','meta_type','id','title']];
obs python:sequence.sort(obs, ((skey,sort_func,rkey),) )"
obs python: here.manage_get_sortedObjects(sortkey = skey, revkey = rkey);
"
tal:attributes="action string:${request/URL1}/">

<tal:not-empty condition="obs">
Expand All @@ -36,11 +35,11 @@
</th>
<th scope="col" class="zmi-object-id"
><a title="Sort Ascending by Name"
href="?skey=getId&rkey=asc"
href="?skey=id&rkey=asc"
tal:attributes="
title python:'Sort %s by Name'%( rkey_alt.upper() );
href python:'?skey=getId&rkey=%s'%( rkey_alt );
class python:request.get('skey',None)=='getId' and 'zmi-sort_key' or None"
href python:'?skey=id&rkey=%s'%( rkey_alt );
class python:request.get('skey',None)=='id' and 'zmi-sort_key' or None"
>Name<i class="fa fa-sort"></i></a>
<i class="fa fa-search tablefilter" onclick="$('#tablefilter').focus()"></i>
<input id="tablefilter" name="obj_ids:tokens" type="text"
Expand Down Expand Up @@ -68,13 +67,14 @@
</tr>
</thead>
<tbody>
<tr tal:repeat="ob obs">
<tr tal:repeat="ob_dict obs">
<tal:obj define="ob nocall:ob_dict/obj">
<td class="zmi-object-check text-right"
onclick="$(this).children('input').trigger('click');">
<input type="checkbox"
class="checkbox-list-item"
name="ids:list"
tal:attributes="value python:ob.getId()"
tal:attributes="value ob_dict/id"
onclick="event.stopPropagation();$(this).parent().parent().toggleClass('checked');"
/>
</td>
Expand All @@ -88,8 +88,8 @@
</i>
</td>
<td class="zmi-object-id">
<a tal:attributes="href python:'%s/manage_workspace'%(ob.getId())">
<span tal:replace="python:ob.getId()">Id</span>
<a tal:attributes="href python:'%s/manage_workspace'%(ob_dict['id'])">
<span tal:replace="ob_dict/id">Id</span>
<span class="badge badge-warning"
title="This item has been locked by WebDAV"
tal:condition="ob/wl_isLocked | nothing">
Expand All @@ -107,6 +107,7 @@
<td class="text-right zmi-object-date hidden-xs pl-3"
tal:content="python:here.last_modified(ob)">
</td>
</tal:obj>
</tr>
</tbody>
</table>
Expand Down

0 comments on commit 6fba729

Please sign in to comment.