Skip to content

Commit

Permalink
Do recursive check and more verbose reporting
Browse files Browse the repository at this point in the history
  • Loading branch information
karalics authored and tomgross committed Dec 10, 2016
1 parent de15b7e commit 2a4ac39
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 46 deletions.
5 changes: 4 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ Breaking changes:

New features:

- *add item here*
- Information about contents within a selected folder for deletion.
This information contains number of deleted objects,
number of subfolders and number of published objects.
[karalics]

Bug fixes:

Expand Down
97 changes: 62 additions & 35 deletions plone/app/linkintegrity/browser/delete_confirmation_info.pt
Original file line number Diff line number Diff line change
@@ -1,53 +1,80 @@
<tal:block
tal:define="breaches python:view.breaches"
tal:condition="breaches"
tal:define="breaches python:view.breaches;"
i18n:domain="plone">

<h2 i18n:translate="linkintegrity_breaches_title">Potential link breakage</h2>

<h2 tal:condition="breaches" i18n:translate="linkintegrity_breaches_title">Potential link breakage</h2>

<div id="content-core">
<p i18n:translate="linkintegrity_instructions">

<p tal:condition="breaches" i18n:translate="linkintegrity_instructions">
By deleting this item, you will break links that exist in the items listed
below. If this is indeed what you want to do, we recommend that you remove
these references first.
</p>

<div tal:define="token context/@@authenticator/token">
<article tal:repeat="breach breaches" class="breach-container">

<tal:target tal:define="target breach/target">
<header><a href="${target/url}" tal:content="target/title" /></header>
<p>
<span i18n:translate="linkintegrity_is_referenced">
This <span i18n:name="portal_type" tal:content="target/type_title" />
is referenced by the following items:
</span>
</p>
</tal:target>

<ul>
<li tal:repeat="source python:breach['sources']" class="breach-item">
<tal:visible condition="source/accessible">
<a tal:attributes="href source/url" tal:content="source/title" />
[<a tal:attributes="href string:${source/url}/edit?_authenticator=${token}"
i18n:translate="linkintegrity_edit_in_new_window"
target="_blank">Edit in new window</a>]
</tal:visible>
<tal:private condition="not: source/accessible"
i18n:translate="linkintegrity_item_not_accessible">
The item is not accessible.
</tal:private>
</li>
</ul>

</article>

<br />
<article tal:repeat="breach breaches" class="breach-container">

<tal:target tal:define="target breach/target">
<header><a href="${target/url}" tal:content="target/title" /></header>
<p>
<span i18n:translate="linkintegrity_is_referenced">
This <span i18n:name="portal_type" tal:content="target/type_title" />
is referenced by the following items:
</span>
</p>
</tal:target>

<ul>
<li tal:repeat="source python:breach['sources']" class="breach-item">
<tal:visible condition="source/accessible">
<a tal:attributes="href source/url" tal:content="source/title" />
[<a tal:attributes="href string:${source/url}/edit?_authenticator=${token}"
i18n:translate="linkintegrity_edit_in_new_window"
target="_blank">Edit in new window</a>]
</tal:visible>
<tal:private condition="not: source/accessible"
i18n:translate="linkintegrity_item_not_accessible">
The item is not accessible.
</tal:private>
</li>
</ul>

</article>

<div tal:define="breach_count view/breach_count" tal:condition="breach_count">

<h2 i18n:translate="deleting_overview" >Deleting overview</h2>
<p>
<span tal:define="refs python:len(breach_count)"
i18n:translate="selected_folders_with_content">
Number of selected, non-empty folders: <strong><span tal:replace="refs" i18n:name="refs" /></strong>
</span>
</p>
<ul>
<li tal:repeat="content python:breach_count">
<span i18n:translate="deleting_contents"> Following content within
<strong><span tal:replace="content" i18n:name="content" /></strong> will also be deleted:
</span><br>
<ul>
<li tal:define="objects python:['Objects in all', 'Folders', 'Published objects'] "
tal:repeat="item python:range(3) "
i18n:translate="" >
<span tal:replace="python: breach_count[content][item]" />
<span i18n:translate="" tal:replace="python: objects[item]" />
</li>
</ul>
</li>
</ul>



</div>

<p i18n:translate="linkintegrity_delete_anyway">
Would you like to delete it anyway?
</p>

</div>
</div>
</tal:block>
35 changes: 25 additions & 10 deletions plone/app/linkintegrity/browser/info.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
class DeleteConfirmationInfo(BrowserView):

template = ViewPageTemplateFile('delete_confirmation_info.pt')
breach_count = {}

def __init__(self, context, request):
self.linkintegrity_enabled = linkintegrity_enabled()
Expand All @@ -41,26 +42,38 @@ def get_breaches(self, items=None):
or their children (if a object is a folder) will be ignored.
"""
if items is None:

items = [self.context]
catalog = getToolByName(self.context, 'portal_catalog')
results = []
uids_to_ignore = []
uids_visited = set()
self.breach_count = {}
for obj in items:
obj_path = '/'.join(obj.getPhysicalPath())
brains_to_delete = catalog(path={'query': obj_path})
# add the current items uid and all its childrens uids to the
# list of uids that are ignored
uids_to_ignore.extend([i.UID for i in brains_to_delete])
for breach in self.get_breaches_for_item(obj):
add_breach = False
for source in breach['sources']:
# Only add the breach if one the sources is not in the
# list of items that are to be deleted.
if source['uid'] not in uids_to_ignore:
add_breach = True
if add_breach:
results.append(breach)
for brain_to_delete in brains_to_delete:
obj_to_delete = brain_to_delete.getObject()
for breach in self.get_breaches_for_item(obj):
add_breach = False
for source in breach['sources']:
# Only add the breach if one the sources is not in the
# list of items that are to be deleted.
if source['uid'] not in uids_to_ignore and \
source['uid'] not in uids_visited:
add_breach = True
uids_visited.add(source['uid'])
break
if add_breach:
results.append(breach)
if IFolder.providedBy(obj):
count = len(catalog(path={'query': obj_path}))
count_dirs = len(catalog(path={'query': obj_path}, is_folderish=True))
count_public = len(catalog(path={'query': obj_path}, review_state='published'))
if count:
self.breach_count[obj_path]=[count, count_dirs, count_public]

# Cleanup: Some breaches where added before it was known
# that their source will be deleted too.
Expand All @@ -76,6 +89,7 @@ def get_breaches(self, items=None):
results.remove(result)
return results


def get_breaches_for_item(self, obj=None):
"""Get breaches for one object and its children.
Expand Down Expand Up @@ -153,3 +167,4 @@ def get_portal_type_title(self, obj):

def is_accessible(self, obj):
return _checkPermission(AccessContentsInformation, obj)

10 changes: 10 additions & 0 deletions plone/app/linkintegrity/tests/test_functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,16 @@ def test_removal_via_zmi(self):
self.browser.getControl('Delete').click()
self.assertNotIn('doc2', self.portal.objectIds())

def test_warn_about_content(self):
folder1 = self.portal.folder1
doc1 = self.portal.folder1.doc1
self.browser.open('{0:s}/delete_confirmation?_authenticator={1:s}'.format(
folder1.absolute_url(), self._get_token(folder1)))
self.assertIn('Number of selected', self.browser.contents)
self.assertIn('2 Objects in all', self.browser.contents)
self.assertIn('1 Folders', self.browser.contents)
self.assertIn('0 Published objects', self.browser.contents)


class FunctionalReferenceDXTestCase(DXBaseTestCase, ReferenceTestCase):
"""Functional reference testcase for dx content types"""
Expand Down

0 comments on commit 2a4ac39

Please sign in to comment.