Skip to content

Commit

Permalink
- Enable editing all properties via WebDAV
Browse files Browse the repository at this point in the history
  • Loading branch information
dataflake committed Feb 13, 2020
1 parent 2010af2 commit 4e1f92f
Show file tree
Hide file tree
Showing 4 changed files with 218 additions and 9 deletions.
4 changes: 4 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ Changelog
3.3 (unreleased)
----------------

- Enable editing all properties via WebDAV
This is done by copying the full-featured format used by the
``FSZSQLMethod`` class from ``Products.CMFCore``.


3.2 (2020-02-11)
----------------
Expand Down
10 changes: 10 additions & 0 deletions src/Products/ZSQLMethods/Extensions/TestRecord.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#
# TestRecord - Used for ZSQLMethod tests
#


class MyRecord:

def my_uncle(self):
""" Bruce is my uncle """
return 'bruce'
77 changes: 68 additions & 9 deletions src/Shared/DC/ZRDB/DA.py
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,16 @@ def manage_DAVget(self):
"""Get source for WebDAV"""
self.REQUEST.RESPONSE.setHeader('Content-Type',
self.default_content_type)
return '<params>%s</params>\n%s' % (self.arguments_src, self.src)
values = {}
for attr in ('title', 'connection_id', 'arguments_src', 'max_rows_',
'max_cache_', 'cache_time_', 'class_name_', 'class_file_',
'allow_simple_one_argument_traversal', 'src'):
values[attr] = getattr(self, attr)
values['connection_hook'] = self.connection_hook or ''
asoat = self.allow_simple_one_argument_traversal or ''
values['allow_simple_one_argument_traversal'] = asoat

return DA_DAV_TEMPLATE % values

manage_FTPget = manage_DAVget

Expand All @@ -408,20 +417,53 @@ def PUT(self, REQUEST, RESPONSE):
self.dav__init(REQUEST, RESPONSE)
self.dav__simpleifhandler(REQUEST, RESPONSE, refresh=1)
body = REQUEST.get('BODY', '')
parameters = {}
connection_id = self.connection_id
if six.PY3 and isinstance(body, bytes):
body = body.decode('UTF-8')
elif six.PY2 and not isinstance(body, bytes):
body = body.encode('UTF-8')
m = re.match(r'\s*<params>(.*)</params>\s*\n', body, re.I | re.S)

re_expr = r'\s*<dtml-comment>(.*)</dtml-comment>\s*\n'
m = re.match(re_expr, body, re.I | re.S)
if m:
self.arguments_src = m.group(1)
self._arg = parse(self.arguments_src)
lines = [x for x in m.group(1).split('\n') if x]
for line in lines:
pair = line.split(':', 1)
if len(pair) != 2:
continue
parameters[pair[0].strip().lower()] = pair[1].strip()
body = body[m.end():]
template = body
self.src = template
self.template = t = self.template_class(template)
t.cook()
self._v_cache = ({}, Bucket())

# check for required parameters
try:
connection_id = (parameters.get('connection id', '') or
parameters['connection_id'])
except KeyError as e:
raise ValueError('The "%s" parameter is required '
'but was not supplied' % e)

self.manage_edit(parameters.get('title', ''),
connection_id,
parameters.get('arguments', ''),
template=body)

connection_hook = parameters.get('connection_hook', None)
direct = (parameters.get('allow_simple_one_argument_traversal',
'') or '')
if direct:
if direct.lower() in ('0', 'false'):
direct = ''
else:
direct = True
self.manage_advanced(parameters.get('max_rows', 1000),
parameters.get('max_cache', 100),
parameters.get('cache_time', 0),
parameters.get('class_name', ''),
parameters.get('class_file', ''),
connection_hook=connection_hook,
direct=direct)

RESPONSE.setStatus(204)
return RESPONSE

Expand Down Expand Up @@ -781,3 +823,20 @@ def __getattr__(self, name):
class SQLMethodTracebackSupplement:
def __init__(self, sql):
self.object = sql


DA_DAV_TEMPLATE = """\
<dtml-comment>
title : %(title)s
connection id : %(connection_id)s
arguments : %(arguments_src)s
max_rows : %(max_rows_)s
max_cache : %(max_cache_)s
cache_time : %(cache_time_)s
class_name : %(class_name_)s
class_file : %(class_file_)s
connection_hook : %(connection_hook)s
allow_simple_one_argument_traversal : %(allow_simple_one_argument_traversal)s
</dtml-comment>
%(src)s
"""
136 changes: 136 additions & 0 deletions src/Shared/DC/ZRDB/tests/testDA.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
##############################################################################
#
# Copyright (c) 2010 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
#
##############################################################################

import unittest

from Testing.makerequest import makerequest


class TestTM(unittest.TestCase):

def _getTargetClass(self):
from ..DA import DA
return DA

def _makeOne(self, *args, **kw):
return self._getTargetClass()(*args, **kw)

def test_instantiation(self):
da = self._makeOne('test_id', 'Test Title', 'conn_id',
'foo bar', '<dtml-var bar>')
self.assertEqual(da.getId(), 'test_id')
self.assertEqual(da.title, 'Test Title')
self.assertEqual(da.connection_id, 'conn_id')
self.assertEqual(da.arguments_src, 'foo bar')
self.assertEqual(da.src, '<dtml-var bar>')

def test_manage_edit(self):
da = self._makeOne('test_id', 'Test Title', 'conn_id',
'foo bar', '<dtml-var bar>')
da.manage_edit('New Title', 'conn_2', 'bar baz', '<dtml-var baz>')
self.assertEqual(da.getId(), 'test_id')
self.assertEqual(da.title, 'New Title')
self.assertEqual(da.connection_id, 'conn_2')
self.assertEqual(da.arguments_src, 'bar baz')
self.assertEqual(da.src, '<dtml-var baz>')

def test_manage_advanced(self):
klass = self._getTargetClass()
da = self._makeOne('test_id', 'Test Title', 'conn_id',
'foo bar', '<dtml-var bar>')

# Check defaults
self.assertEqual(da.max_rows_, klass.max_rows_)
self.assertEqual(da.max_cache_, klass.max_cache_)
self.assertEqual(da.cache_time_, klass.cache_time_)
self.assertEqual(da.class_name_, klass.class_name_)
self.assertEqual(da.class_file_, klass.class_file_)
self.assertEqual(da.allow_simple_one_argument_traversal,
klass.allow_simple_one_argument_traversal)
self.assertEqual(da.template_class, klass.template_class)
self.assertEqual(da.connection_hook, klass.connection_hook)

da.manage_advanced(5, 50, 10, 'MyRecord', 'ZSQLMethods.TestRecord',
direct=True, connection_hook='foo')
self.assertEqual(da.max_rows_, 5)
self.assertEqual(da.max_cache_, 50)
self.assertEqual(da.cache_time_, 10)
self.assertEqual(da.class_name_, 'MyRecord')
self.assertEqual(da.class_file_, 'ZSQLMethods.TestRecord')
self.assertEqual(da.allow_simple_one_argument_traversal, True)
self.assertEqual(da.template_class, klass.template_class)
self.assertEqual(da.connection_hook, 'foo')

def test_manage_DAVget(self):
da = makerequest(self._makeOne('test_id', 'Test Title', 'conn_id',
'foo bar', '<dtml-var bar>'))
self.assertEqual(da.manage_DAVget(), DEFAULT_DAV_SOURCE)

da.manage_edit('New Title', 'conn_2', 'bar baz', '<dtml-var baz>')
da.manage_advanced(5, 50, 10, 'MyRecord', 'ZSQLMethods.TestRecord',
direct=True, connection_hook='foo')
self.assertEqual(da.manage_DAVget(), CHANGED_DAV_SOURCE)

def test_PUT(self):
klass = self._getTargetClass()
da = makerequest(self._makeOne('test_id', 'Test Title', 'conn_id',
'foo bar', '<dtml-var bar>'))

da.REQUEST.set('BODY', CHANGED_DAV_SOURCE)
da.PUT(da.REQUEST, da.REQUEST.RESPONSE)
self.assertEqual(da.getId(), 'test_id')
self.assertEqual(da.title, 'New Title')
self.assertEqual(da.connection_id, 'conn_2')
self.assertEqual(da.arguments_src, 'bar baz')
self.assertEqual(da.src, '<dtml-var baz>\n')
self.assertEqual(da.max_rows_, 5)
self.assertEqual(da.max_cache_, 50)
self.assertEqual(da.cache_time_, 10)
self.assertEqual(da.class_name_, 'MyRecord')
self.assertEqual(da.class_file_, 'ZSQLMethods.TestRecord')
self.assertEqual(da.allow_simple_one_argument_traversal, True)
self.assertEqual(da.template_class, klass.template_class)
self.assertEqual(da.connection_hook, 'foo')


DEFAULT_DAV_SOURCE = """\
<dtml-comment>
title : Test Title
connection id : conn_id
arguments : foo bar
max_rows : 1000
max_cache : 100
cache_time : 0
class_name :
class_file :
connection_hook :
allow_simple_one_argument_traversal :
</dtml-comment>
<dtml-var bar>
""" # NOQA: W291

CHANGED_DAV_SOURCE = """\
<dtml-comment>
title : New Title
connection id : conn_2
arguments : bar baz
max_rows : 5
max_cache : 50
cache_time : 10
class_name : MyRecord
class_file : ZSQLMethods.TestRecord
connection_hook : foo
allow_simple_one_argument_traversal : True
</dtml-comment>
<dtml-var baz>
"""

0 comments on commit 4e1f92f

Please sign in to comment.