diff --git a/gen/mixins/ToolMixin.py b/gen/mixins/ToolMixin.py
index 558de41..3999346 100644
--- a/gen/mixins/ToolMixin.py
+++ b/gen/mixins/ToolMixin.py
@@ -19,7 +19,7 @@ except ImportError:
# Errors -----------------------------------------------------------------------
jsMessages = ('no_elem_selected', 'delete_confirm', 'unlink_confirm',
- 'warn_leave_form')
+ 'unlock_confirm', 'warn_leave_form')
# ------------------------------------------------------------------------------
class ToolMixin(BaseMixin):
diff --git a/gen/mixins/__init__.py b/gen/mixins/__init__.py
index 7646776..fa2986a 100644
--- a/gen/mixins/__init__.py
+++ b/gen/mixins/__init__.py
@@ -229,16 +229,20 @@ class BaseMixin:
if hasattr(self.aq_base, 'locks') and (page in self.locks):
if (user.getId() != self.locks[page][0]): return self.locks[page]
- def removeLock(self, page):
- '''Removes the lock on the current page. This happens after the page has
- been saved: the lock must be released.'''
+ def removeLock(self, page, force=False):
+ '''Removes the lock on the current page. This happens:
+ - after the page has been saved: the lock must be released;
+ - or when an admin wants to force the deletion of a lock that was
+ left on p_page for too long (p_force=True).
+ '''
if page not in self.locks: return
# Raise an error if the user that saves changes is not the one that
- # has locked the page.
- userId = self.getUser().getId()
- if self.locks[page][0] != userId:
- from AccessControl import Unauthorized
- raise Unauthorized('This page was locked by someone else.')
+ # has locked the page (excepted if p_force is True)
+ if not force:
+ userId = self.getUser().getId()
+ if self.locks[page][0] != userId:
+ from AccessControl import Unauthorized
+ raise Unauthorized('This page was locked by someone else.')
# Remove the lock
del self.locks[page]
@@ -251,6 +255,17 @@ class BaseMixin:
(user.getId() == self.locks[page][0]):
del self.locks[page]
+ def onUnlock(self):
+ '''Called when an admin wants to remove a lock that was left for too
+ long by some user.'''
+ rq = self.REQUEST
+ tool = self.getTool()
+ obj = tool.getObject(rq['objectUid'])
+ obj.removeLock(rq['pageName'], force=True)
+ urlBack = self.getUrl(rq['HTTP_REFERER'])
+ self.say(self.translate('unlock_done'))
+ self.goto(urlBack)
+
def onCreateWithoutForm(self):
'''This method is called when a user wants to create a object from a
reference field, automatically (without displaying a form).'''
diff --git a/gen/po.py b/gen/po.py
index 909aaf5..5df7308 100644
--- a/gen/po.py
+++ b/gen/po.py
@@ -73,10 +73,13 @@ appyLabels = [
('object_edit', 'Edit'),
('object_delete', 'Delete'),
('object_unlink', 'Unlink'),
+ ('page_unlock', 'Unlock'),
('delete_confirm', 'Are you sure you want to delete this element?'),
('unlink_confirm', 'Are you sure you want to unlink this element?'),
+ ('unlock_confirm', 'Are you sure you want to unlock this page?'),
('delete_done', 'The element has been deleted.'),
('unlink_done', 'The element has been unlinked.'),
+ ('unlock_done', 'The page has been unlocked.'),
('goto_first', 'Go to top'),
('goto_previous', 'Go to previous'),
('goto_next', 'Go to next'),
diff --git a/gen/ui/appy.js b/gen/ui/appy.js
index 776adec..1b5eca1 100644
--- a/gen/ui/appy.js
+++ b/gen/ui/appy.js
@@ -403,6 +403,13 @@ function onUnlinkObject(sourceUid, fieldName, targetUid) {
askConfirm('form', 'unlinkForm', unlink_confirm);
}
+function onUnlockPage(objectUid, pageName) {
+ f = document.getElementById('unlockForm');
+ f.objectUid.value = objectUid;
+ f.pageName.value = pageName;
+ askConfirm('form', 'unlockForm', unlock_confirm);
+}
+
function createCookie(name, value, days) {
if (days) {
var date = new Date();
diff --git a/gen/ui/page.pt b/gen/ui/page.pt
index c7737b4..860437d 100644
--- a/gen/ui/page.pt
+++ b/gen/ui/page.pt
@@ -31,6 +31,12 @@
+