-
Notifications
You must be signed in to change notification settings - Fork 96
/
Lockable.py
153 lines (128 loc) · 5.28 KB
/
Lockable.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
from AccessControl.class_init import InitializeClass
from AccessControl.Permissions import webdav_lock_items
from AccessControl.Permissions import webdav_unlock_items
from AccessControl.SecurityInfo import ClassSecurityInfo
from Acquisition import aq_base
from OFS.EtagSupport import EtagSupport
from OFS.interfaces import ILockItem
from OFS.interfaces import IWriteLock
from Persistence import PersistentMapping
from webdav import webdav_manage_locks
from zope.interface import implementer
@implementer(IWriteLock)
class LockableItem(EtagSupport):
"""Implements the WriteLock interface.
"""
# Protect methods using declarative security
security = ClassSecurityInfo()
# Setting default roles for permissions - we want owners of conent
# to be able to lock.
security.setPermissionDefault(webdav_lock_items, ('Manager', 'Owner',))
security.setPermissionDefault(webdav_unlock_items, ('Manager', 'Owner',))
@security.private
def wl_lockmapping(self, killinvalids=0, create=0):
""" if 'killinvalids' is 1, locks who are no longer valid
will be deleted """
try:
locks = getattr(self, '_dav_writelocks', None)
except Exception:
locks = None
if locks is None:
if create:
locks = self._dav_writelocks = PersistentMapping()
else:
# Don't generate a side effect transaction.
locks = {}
return locks
elif killinvalids:
# Delete invalid locks
for token, lock in list(locks.items()):
if not lock.isValid():
del locks[token]
if (not locks) and hasattr(aq_base(self),
'__no_valid_write_locks__'):
self.__no_valid_write_locks__()
return locks
else:
return locks
@security.public
def wl_lockItems(self, killinvalids=0):
return list(self.wl_lockmapping(killinvalids).items())
@security.public
def wl_lockValues(self, killinvalids=0):
return list(self.wl_lockmapping(killinvalids).values())
@security.public
def wl_lockTokens(self, killinvalids=0):
return list(self.wl_lockmapping(killinvalids).keys())
# TODO: Security Declaration
def wl_hasLock(self, token, killinvalids=0):
if not token:
return 0
return token in list(self.wl_lockmapping(killinvalids).keys())
@security.public
def wl_isLocked(self):
# returns true if 'self' is locked at all
# We set 'killinvalids' to 1 to delete all locks who are no longer
# valid (timeout has been exceeded)
locks = self.wl_lockmapping(killinvalids=1)
if list(locks.keys()):
return 1
else:
return 0
@security.protected(webdav_lock_items)
def wl_setLock(self, locktoken, lock):
locks = self.wl_lockmapping(create=1)
if ILockItem.providedBy(lock):
if locktoken == lock.getLockToken():
locks[locktoken] = lock
else:
raise ValueError('Lock tokens do not match')
else:
raise ValueError('Lock does not implement the LockItem Interface')
@security.public
def wl_getLock(self, locktoken):
locks = self.wl_lockmapping(killinvalids=1)
return locks.get(locktoken, None)
@security.protected(webdav_unlock_items)
def wl_delLock(self, locktoken):
locks = self.wl_lockmapping()
if locktoken in locks:
del locks[locktoken]
@security.protected(webdav_manage_locks)
def wl_clearLocks(self):
# Called by lock management machinery to quickly and effectively
# destroy all locks.
try:
locks = self.wl_lockmapping()
locks.clear()
except Exception:
# The locks may be totally messed up, so we'll just delete
# and replace.
if hasattr(self, '_dav_writelocks'):
del self._dav_writelocks
if IWriteLock.providedBy(self):
self._dav_writelocks = PersistentMapping()
# Call into a special hook used by LockNullResources to delete
# themselves. Could be used by other objects who want to deal
# with the state of empty locks.
if hasattr(aq_base(self), '__no_valid_write_locks__'):
self.__no_valid_write_locks__()
InitializeClass(LockableItem)
def wl_isLocked(ob):
""" Returns true if the object is locked, returns 0 if the object
is not locked or does not implement the WriteLockInterface """
return wl_isLockable(ob) and ob.wl_isLocked()
def wl_isLockable(ob):
return IWriteLock.providedBy(ob)