From 780f9b69316bf90891fd4ab8fc850f9d98969744 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89rico=20Andrei?= Date: Fri, 8 Oct 2021 16:51:24 +0200 Subject: [PATCH] Register a fallback @@plone_lock_info view to allow objects without plone.locking behavior to be edited. --- news/3331.fix | 2 ++ plone/locking/browser/locking.py | 20 ++++++++++++++ plone/locking/configure.zcml | 8 ++++++ plone/locking/tests/test_views.py | 44 +++++++++++++++++++++++++++++++ 4 files changed, 74 insertions(+) create mode 100644 news/3331.fix create mode 100644 plone/locking/tests/test_views.py diff --git a/news/3331.fix b/news/3331.fix new file mode 100644 index 0000000..9efab5b --- /dev/null +++ b/news/3331.fix @@ -0,0 +1,2 @@ +Register a fallback @@plone_lock_info view to allow objects without plone.locking behavior to be edited. +[ericof] \ No newline at end of file diff --git a/plone/locking/browser/locking.py b/plone/locking/browser/locking.py index 7f4145e..6453bdc 100644 --- a/plone/locking/browser/locking.py +++ b/plone/locking/browser/locking.py @@ -161,3 +161,23 @@ def _getNiceTimeDifference(self, baseTime): else: dateString = _(u"$d days and $h hours", mapping={'d': days, 'h': hours}) return dateString + + +class LockingInformationFallback(BrowserView): + """Fallback view for Lock information. + + This view exists to return sensible defaults if a content type does + not have the plone.locking behavior active. + """ + + def is_locked(self): + return False + + def is_locked_for_current_user(self): + return False + + def lock_is_stealable(self): + return False + + def lock_info(self): + return None diff --git a/plone/locking/configure.zcml b/plone/locking/configure.zcml index c4890e2..9c8ed2c 100644 --- a/plone/locking/configure.zcml +++ b/plone/locking/configure.zcml @@ -22,4 +22,12 @@ allowed_attributes="is_locked is_locked_for_current_user lock_is_stealable lock_info" /> + + diff --git a/plone/locking/tests/test_views.py b/plone/locking/tests/test_views.py new file mode 100644 index 0000000..412c3b0 --- /dev/null +++ b/plone/locking/tests/test_views.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +from plone.app.testing import setRoles +from plone.app.testing import TEST_USER_ID +from plone.locking.browser.locking import LockingInformation +from plone.locking.browser.locking import LockingInformationFallback +from plone.locking.testing import PLONE_LOCKING_INTEGRATION_TESTING +from plone.dexterity.interfaces import IDexterityFTI +from zope.component import queryUtility + +import unittest + + +class TestLockInfoViewWithoutLocking(unittest.TestCase): + + layer = PLONE_LOCKING_INTEGRATION_TESTING + + view = "@@plone_lock_info" + + def setUp(self): + self.app = self.layer["app"] + self.portal = self.layer["portal"] + + setRoles(self.portal, TEST_USER_ID, ["Manager", "Site Administrator"]) + + self.portal.invokeFactory("News Item", id="news1", title="News Item 1") + self.news = self.portal["news1"] + + # Remove plone.locking from Document content type + fti = queryUtility(IDexterityFTI, name="Document") + behavior_list = [a for a in fti.behaviors if a != "plone.locking"] + fti.behaviors = tuple(behavior_list) + + self.portal.invokeFactory("Document", id="doc1", title="Document 1") + self.doc = self.portal["doc1"] + + def test_browser_view_available_for_content_with_locking_behavior(self): + content = self.news + view = content.restrictedTraverse(self.view) + self.assertIsInstance(view, LockingInformation) + + def test_browser_view_available_for_content_without_locking_behavior(self): + content = self.doc + view = content.restrictedTraverse(self.view) + self.assertIsInstance(view, LockingInformationFallback)