Skip to content

Commit

Permalink
Merge 9b5683e into 07e0478
Browse files Browse the repository at this point in the history
  • Loading branch information
dataflake committed Feb 9, 2020
2 parents 07e0478 + 9b5683e commit c3696a4
Show file tree
Hide file tree
Showing 49 changed files with 4,614 additions and 174 deletions.
7 changes: 5 additions & 2 deletions CHANGES.rst
Expand Up @@ -7,8 +7,11 @@ The change log for the previous version, Zope 2.13, is at
https://zope.readthedocs.io/en/2.13/CHANGES.html


4.1.4 (unreleased)
------------------
4.2 (unreleased)
----------------

- Restore WebDAV support in Zope
(`#744 <https://github.com/zopefoundation/Zope/issues/744>`_)

- Fix sort link URLs on ``manage_main``
(`#748 <https://github.com/zopefoundation/Zope/issues/748>`_)
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Expand Up @@ -29,7 +29,7 @@ def _read_file(filename):
README = _read_file('README.rst')
CHANGES = _read_file('CHANGES.rst')

version = '4.1.4.dev0'
version = '4.2.dev0'


setup(
Expand Down
4 changes: 4 additions & 0 deletions src/App/ApplicationManager.py
Expand Up @@ -21,6 +21,7 @@
from AccessControl.requestmethod import requestmethod
from Acquisition import Implicit
from App.config import getConfiguration
from App.DavLockManager import DavLockManager
from App.Management import Tabs
from App.special_dtml import DTMLFile
from App.Undo import UndoSupport
Expand Down Expand Up @@ -101,6 +102,7 @@ class ConfigurationViewer(Tabs, Traversable, Implicit):
{'label': 'Control Panel', 'action': '../manage_main'},
{'label': 'Databases', 'action': '../Database/manage_main'},
{'label': 'Configuration', 'action': 'manage_main'},
{'label': 'DAV Locks', 'action': '../DavLocks/manage_main'},
)
MANAGE_TABS_NO_BANNER = True

Expand Down Expand Up @@ -145,13 +147,15 @@ class ApplicationManager(Persistent, Tabs, Traversable, Implicit):

Database = DatabaseChooser()
Configuration = ConfigurationViewer()
DavLocks = DavLockManager()

manage = manage_main = DTMLFile('dtml/cpContents', globals())
manage_main._setName('manage_main')
manage_options = (
{'label': 'Control Panel', 'action': 'manage_main'},
{'label': 'Databases', 'action': 'Database/manage_main'},
{'label': 'Configuration', 'action': 'Configuration/manage_main'},
{'label': 'DAV Locks', 'action': 'DavLocks/manage_main'},
)
MANAGE_TABS_NO_BANNER = True

Expand Down
117 changes: 117 additions & 0 deletions src/App/DavLockManager.py
@@ -0,0 +1,117 @@
##############################################################################
#
# 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.SecurityInfo import ClassSecurityInfo
from Acquisition import Implicit
from Acquisition import aq_base
from App.special_dtml import DTMLFile
from OFS.Lockable import wl_isLocked
from OFS.SimpleItem import Item


manage_webdav_locks = 'Manage WebDAV Locks'


class DavLockManager(Item, Implicit):
id = 'DavLockManager'
name = title = 'WebDAV Lock Manager'
meta_type = 'WebDAV Lock Manager'
zmi_icon = 'fa fa-lock'

security = ClassSecurityInfo()

security.declareProtected(manage_webdav_locks, # NOQA: D001
'manage_davlocks')
manage_davlocks = manage_main = manage = DTMLFile(
'dtml/davLockManager', globals())
manage_davlocks._setName('manage_davlocks')
manage_options = ({'label': 'Write Locks', 'action': 'manage_main'}, )

@security.protected(manage_webdav_locks)
def findLockedObjects(self, frompath=''):
app = self.getPhysicalRoot()

if frompath:
if frompath[0] == '/':
frompath = frompath[1:]
# since the above will turn '/' into an empty string, check
# for truth before chopping a final slash
if frompath and frompath[-1] == '/':
frompath = frompath[:-1]

# Now we traverse to the node specified in the 'frompath' if
# the user chose to filter the search, and run a ZopeFind with
# the expression 'wl_isLocked()' to find locked objects.
obj = app.unrestrictedTraverse(frompath)
lockedobjs = self._findapply(obj, path=frompath)

return lockedobjs

@security.private
def unlockObjects(self, paths=[]):
app = self.getPhysicalRoot()

for path in paths:
ob = app.unrestrictedTraverse(path)
ob.wl_clearLocks()

@security.protected(manage_webdav_locks)
def manage_unlockObjects(self, paths=[], REQUEST=None):
" Management screen action to unlock objects. "
if paths:
self.unlockObjects(paths)
if REQUEST is not None:
m = '%s objects unlocked.' % len(paths)
return self.manage_davlocks(self, REQUEST, manage_tabs_message=m)

def _findapply(self, obj, result=None, path=''):
# recursive function to actually dig through and find the locked
# objects.

if result is None:
result = []
base = aq_base(obj)
if not hasattr(base, 'objectItems'):
return result
try:
items = obj.objectItems()
except Exception:
return result

addresult = result.append
for id, ob in items:
if path:
p = '%s/%s' % (path, id)
else:
p = id

dflag = hasattr(ob, '_p_changed') and (ob._p_changed is None)
bs = aq_base(ob)
if wl_isLocked(ob):
li = []
addlockinfo = li.append
for token, lock in ob.wl_lockItems():
addlockinfo({'owner': lock.getCreatorPath(),
'token': token})
addresult((p, li))
dflag = 0
if hasattr(bs, 'objectItems'):
self._findapply(ob, result, p)
if dflag:
ob._p_deactivate()

return result


InitializeClass(DavLockManager)
14 changes: 6 additions & 8 deletions src/App/ImageFile.py
Expand Up @@ -21,7 +21,6 @@
from AccessControl.class_init import InitializeClass
from AccessControl.SecurityInfo import ClassSecurityInfo
from Acquisition import Explicit
from App import bbb
from App.Common import package_home
from App.Common import rfc1123_date
from App.config import getConfiguration
Expand Down Expand Up @@ -121,13 +120,12 @@ def index_html(self, REQUEST, RESPONSE):
RESPONSE.setHeader('Content-Length', str(self.size).replace('L', ''))
return filestream_iterator(self.path, mode='rb')

if bbb.HAS_ZSERVER:
@security.public
def HEAD(self, REQUEST, RESPONSE):
""" """
RESPONSE.setHeader('Content-Type', self.content_type)
RESPONSE.setHeader('Last-Modified', self.lmh)
return ''
@security.public
def HEAD(self, REQUEST, RESPONSE):
""" """
RESPONSE.setHeader('Content-Type', self.content_type)
RESPONSE.setHeader('Last-Modified', self.lmh)
return ''

def __len__(self):
# This is bogus and needed because of the way Python tests truth.
Expand Down
21 changes: 0 additions & 21 deletions src/App/bbb.py

This file was deleted.

106 changes: 106 additions & 0 deletions src/App/dtml/davLockManager.dtml
@@ -0,0 +1,106 @@
<dtml-var manage_page_header>
<dtml-var manage_tabs>

<main class="container-fluid">

<dtml-let from_path="REQUEST.form.get('frompath',None)"
lockedobjs="from_path and findLockedObjects(frompath=from_path) or []">

<p class="form-help">
Use the search form to locate locked items starting from the
provided path.
</p>

<form action="&dtml-URL0;" name="finderform">
<p class="form-help">Search path:
<input type="text" size="14" name="frompath"
value="&dtml.missing-frompath;"
class="form-element" />
<input class="btn btn-primary" type="submit" value="Go"/>
</p>
</form>

<form action="manage_unlockObjects" name="objectItems" method="post">
<input type="hidden" name="frompath" value="&dtml.missing-frompath;" />

<dtml-if lockedobjs>

<table class="table table-striped table-hover table-sm objectItems">

<thead class="thead-light">
<th scope="col" class="zmi-object-check text-right">
<input type="checkbox" id="checkAll" onclick="checkbox_all();" />
</th>
<th scope="col">Path</th>
<th scope="col">Locked by</th>
<th scope="col">Lock token</th>
</thead>

<tbody>
<dtml-in lockedobjs>
<tr>
<td class="zmi-object-check text-right"
onclick="$(this).children('input').trigger('click');">
<input type="checkbox" name="paths:list"
value="&dtml-sequence-key;"
class="checkbox-list-item"
id="cb_&dtml-sequence-index;"
onclick="event.stopPropagation();select_objectitem($(this));"/>
</td>
<td class="zmi-object-id">
<label for="cb_&dtml-sequence-index;">
<a href="/&dtml-sequence-key;/manage_workspace">
/&dtml-sequence-key;
</a>
</label>
</td>
<dtml-in sequence-item mapping>
<td class="zmi-object-id">&dtml-owner;</td>
<td class="zmi-object-id">&dtml-token;</td>
</dtml-in>
</td>
</tr>
</dtml-in lockedobjs>
</tbody>

</table>

<div class="form-group form-inline zmi-controls">
<div class="input-group">
<input class="btn btn-primary" type="submit"
value="Unlock objects" />
</div>
</div>
<dtml-else>
<dtml-if frompath>
<p class="form-help">
Found no locked items under path <em>&dtml-frompath;</em>.
</p>
</dtml-if>
</dtml-if>
</form>

</dtml-let>

</main>

<script>
// +++++++++++++++++++++++++++
// Item Selection
// +++++++++++++++++++++++++++
function checkbox_all() {
var checkboxes = document.getElementsByClassName('checkbox-list-item');
// Toggle Highlighting CSS-Class
if (document.getElementById('checkAll').checked) {
$('table.objectItems tbody tr').addClass('checked');
} else {
$('table.objectItems tbody tr').removeClass('checked');
};
// Set Checkbox like checkAll-Box
for (i = 0; i < checkboxes.length; i++) {
checkboxes[i].checked = document.getElementById('checkAll').checked;
}
};
</script>

<dtml-var manage_page_footer>
8 changes: 5 additions & 3 deletions src/App/dtml/manage_tabs.dtml
Expand Up @@ -68,9 +68,11 @@
<dtml-if "_['sequence-index']!=0 and last==False">
&nbsp;/&nbsp;
</dtml-if>
<dtml-if wl_isLocked
><span class="badge badge-warning"
title="This item has been locked by WebDAV"><i class="fa fa-lock"></i></span>
<dtml-if last>
<dtml-if wl_isLocked
><span class="badge badge-warning"
title="This item has been locked by WebDAV"><i class="fa fa-lock"></i></span>
</dtml-if>
</dtml-if>
</li>
</dtml-in>
Expand Down

0 comments on commit c3696a4

Please sign in to comment.