Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions news/3953.breaking.1
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Move ``plone.app.linkintegrity`` template/views to ``plone.app.layout.views.linkintegrity``
[petschki]
6 changes: 6 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
install_requires=[
"plone.app.content",
"plone.app.dexterity",
"plone.app.linkintegrity",
"plone.app.relationfield",
"plone.app.uuid",
"plone.app.viewletmanager >=1.2",
Expand All @@ -61,13 +62,18 @@
extras_require=dict(
test=[
"plone.app.contenttypes[test]",
"plone.app.linkintegrity",
"plone.app.relationfield",
"plone.app.robotframework",
"plone.app.testing",
"plone.app.textfield",
"plone.browserlayer",
"plone.dexterity",
"plone.locking",
"plone.testing",
"robotsuite",
"z3c.relationfield",
"zc.relation",
"zope.intid",
]
),
Expand Down
4 changes: 2 additions & 2 deletions src/plone/app/layout/analytics/tests/test_doctests.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from plone.app.layout.testing import FUNCTIONAL_TESTING
from plone.app.layout.testing import PLONE_APP_LAYOUT_FUNCTIONAL_TESTING
from plone.testing import layered

import doctest
Expand All @@ -22,7 +22,7 @@ def test_suite():
test,
optionflags=OPTIONFLAGS,
),
layer=FUNCTIONAL_TESTING,
layer=PLONE_APP_LAYOUT_FUNCTIONAL_TESTING,
)
for test in normal_testfiles
]
Expand Down
17 changes: 17 additions & 0 deletions src/plone/app/layout/controlpanels/configure.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,21 @@
xmlns:zcml="http://namespaces.zope.org/zcml"
>

<browser:page
name="delete_confirmation_info"
for="*"
class=".linkintegrity.DeleteConfirmationInfo"
permission="zope2.Public"
layer="plone.app.layout.interfaces.IPloneAppLayoutLayer"
/>

<browser:page
name="updateLinkIntegrityInformation"
for="plone.base.interfaces.IPloneSiteRoot"
class=".linkintegrity.UpdateView"
template="templates/linkintegrity_update.pt"
permission="cmf.ManagePortal"
Comment thread
ale-rt marked this conversation as resolved.
layer="plone.app.layout.interfaces.IPloneAppLayoutLayer"
/>

</configure>
76 changes: 76 additions & 0 deletions src/plone/app/layout/controlpanels/linkintegrity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
from Acquisition import aq_inner
from datetime import datetime
from datetime import timedelta
from plone.app.linkintegrity.browser.info import (
DeleteConfirmationInfo as DeleteConfirmationInfoAPI,
)
from plone.app.linkintegrity.handlers import modifiedContent
from plone.base import PloneMessageFactory as _
from Products.CMFCore.utils import getToolByName
from Products.Five import BrowserView
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
from Products.statusmessages.interfaces import IStatusMessage
from transaction import savepoint
from zExceptions import NotFound

import logging

logger = logging.getLogger(__name__)


class DeleteConfirmationInfo(DeleteConfirmationInfoAPI):
template = ViewPageTemplateFile(
"templates/linkintegrity_delete_confirmation_info.pt"
)


class UpdateView(BrowserView):
"""Iterate over all catalogued items and update linkintegrity-information."""

def __call__(self):
context = aq_inner(self.context)
request = aq_inner(self.request)
if "update" in request.form or "delete_all" in request.form:
starttime = datetime.now()
count = self.update()
duration = timedelta(seconds=(datetime.now() - starttime).seconds)
msg = _(
"linkintegrity_update_info",
default="Link integrity information updated for ${count} "
+ "items in ${time} seconds.",
mapping={"count": count, "time": str(duration)},
)
IStatusMessage(request).add(msg, type="info")
msg = "Updated {} items in {} seconds".format(
count,
str(duration),
)
logger.info(msg)
request.RESPONSE.redirect(getToolByName(context, "portal_url")())
elif "cancel" in request.form:
msg = _("Update cancelled.")
IStatusMessage(request).add(msg, type="info")
request.RESPONSE.redirect(getToolByName(context, "portal_url")())
else:
return self.index()

def update(self):
catalog = getToolByName(self.context, "portal_catalog")
count = 0

for brain in catalog():
try:
obj = brain.getObject()
except (AttributeError, NotFound, KeyError):
msg = "Catalog inconsistency: {0} not found!"
logger.error(msg.format(brain.getPath()), exc_info=1)
continue
try:
modifiedContent(obj, "dummy event parameter")
count += 1
except Exception:
msg = "Error updating linkintegrity-info for {0}."
logger.error(msg.format(obj.absolute_url()), exc_info=1)
if count % 1000 == 0:
savepoint(optimistic=True)
return count
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:i18n="http://xml.zope.org/namespaces/i18n"
xmlns:metal="http://xml.zope.org/namespaces/metal"
xmlns:tal="http://xml.zope.org/namespaces/tal"
lang="en"
xml:lang="en"
tal:omit-tag=""
i18n:domain="plone"
>
<body tal:define="
breaches python:view.breaches;
"
tal:omit-tag=""
>

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

<div id="content-core">

<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 class="breach-container"
tal:repeat="breach breaches"
>

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

<ul>
<li class="breach-item"
tal:repeat="source python:breach['sources']"
>
<tal:visible condition="source/accessible">
<a tal:content="source/title"
tal:attributes="
href source/url;
"
></a>
[<a target="_blank"
tal:attributes="
href string:${source/url}/edit?_authenticator=${token};
"
i18n:translate="linkintegrity_edit_in_new_window"
>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"
></span></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"
></span></strong>
will also be deleted:
</span><br />
<ul>
<li tal:define="
objects view/objects;
"
tal:repeat="item python:range(3) "
>
<span tal:replace="python: breach_count[content][item]"></span>
<span tal:replace="python: objects[item]"></span>
</li>
</ul>
</li>
</ul>

</div>

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

</div>

</div>

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

<head>
<metal:block fill-slot="top_slot"
tal:define="
dummy python:request.set('disable_border',1);
"
/>
</head>

<body>
<metal:main fill-slot="main">

<h1 class="documentFirstHeading"
i18n:translate="linkintegrity_update_title"
>Update link integrity information</h1>

<div id="content-core">

<p i18n:translate="linkintegrity_update_instructions">
Clicking the below button will cause link integrity information to be
updated. This might take a while, especially for bigger sites...
</p>

<form action="updateLinkIntegrityInformation"
method="post"
tal:attributes="
action request/URL;
"
>
<input class="destructive"
name="update"
type="submit"
value="Update"
i18n:attributes="value"
/>
<input class="standalone"
name="cancel"
type="submit"
value="Cancel"
i18n:attributes="value"
/>
</form>

</div>

</metal:main>
</body>
</html>
4 changes: 2 additions & 2 deletions src/plone/app/layout/globals/tests/test_context.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from plone.app.layout.testing import INTEGRATION_TESTING
from plone.app.layout.testing import PLONE_APP_LAYOUT_INTEGRATION_TESTING
from plone.app.testing import setRoles
from plone.app.testing import TEST_USER_ID
from plone.app.testing.helpers import logout
Expand All @@ -16,7 +16,7 @@
class TestContextStateView(unittest.TestCase):
"""Ensure that the basic redirector setup is successful."""

layer = INTEGRATION_TESTING
layer = PLONE_APP_LAYOUT_INTEGRATION_TESTING

def setUp(self):
self.app = self.layer["app"]
Expand Down
6 changes: 3 additions & 3 deletions src/plone/app/layout/globals/tests/test_layout.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from plone.app.layout.testing import INTEGRATION_TESTING
from plone.app.layout.testing import PLONE_APP_LAYOUT_INTEGRATION_TESTING
from plone.app.testing import setRoles
from plone.app.testing import TEST_USER_ID
from plone.app.testing.helpers import logout
Expand All @@ -17,7 +17,7 @@
class TestLayoutView(unittest.TestCase):
"""Tests the global layout view."""

layer = INTEGRATION_TESTING
layer = PLONE_APP_LAYOUT_INTEGRATION_TESTING

def setUp(self):
self.portal = self.layer["portal"]
Expand Down Expand Up @@ -196,7 +196,7 @@ def testBodyClassColMarker(self):
class TestLayoutViewXHR(unittest.TestCase):
"""Tests the global layout view with it's XHR utilities."""

layer = INTEGRATION_TESTING
layer = PLONE_APP_LAYOUT_INTEGRATION_TESTING

def setUp(self):
self.portal = self.layer["portal"]
Expand Down
4 changes: 2 additions & 2 deletions src/plone/app/layout/globals/tests/test_portal.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from plone.app.layout.testing import INTEGRATION_TESTING
from plone.app.layout.testing import PLONE_APP_LAYOUT_INTEGRATION_TESTING
from plone.app.testing import setRoles
from plone.app.testing import TEST_USER_ID
from plone.app.testing.helpers import logout
Expand All @@ -20,7 +20,7 @@
class TestPortalStateView(unittest.TestCase):
"""Ensure that the basic redirector setup is successful."""

layer = INTEGRATION_TESTING
layer = PLONE_APP_LAYOUT_INTEGRATION_TESTING

def setUp(self):
self.portal = self.layer["portal"]
Expand Down
Loading