[gen] Added attribute 'xml' on every field allowing to customize the XML marshalling process. [gen] Added new layout 'xml', now different from the 'view' layout, allowing to define which fields are to be dumped in the XML version of some object. [gen] Security fix in ToolMixin::getUser. [gen] Bugfix in Mixin::getUrl. [shared] dav.py: method 'get' can now accept parameters. [shared] xml_parser: changes to the XmlMarshaller (due to XML-related changes).
This commit is contained in:
parent
f055ec1754
commit
c53654a1a1
|
@ -141,7 +141,7 @@ class Field:
|
||||||
layouts, move, indexed, searchable, specificReadPermission,
|
layouts, move, indexed, searchable, specificReadPermission,
|
||||||
specificWritePermission, width, height, maxChars, colspan,
|
specificWritePermission, width, height, maxChars, colspan,
|
||||||
master, masterValue, focus, historized, mapping, label,
|
master, masterValue, focus, historized, mapping, label,
|
||||||
sdefault, scolspan, swidth, sheight, persist):
|
sdefault, scolspan, swidth, sheight, persist, xml):
|
||||||
# The validator restricts which values may be defined. It can be an
|
# The validator restricts which values may be defined. It can be an
|
||||||
# interval (1,None), a list of string values ['choice1', 'choice2'],
|
# interval (1,None), a list of string values ['choice1', 'choice2'],
|
||||||
# a regular expression, a custom function, a Selection instance, etc.
|
# a regular expression, a custom function, a Selection instance, etc.
|
||||||
|
@ -250,6 +250,13 @@ class Field:
|
||||||
# For some fields it is not wanted (ie, fields used only as masters to
|
# For some fields it is not wanted (ie, fields used only as masters to
|
||||||
# update slave's selectable values).
|
# update slave's selectable values).
|
||||||
self.persist = persist
|
self.persist = persist
|
||||||
|
# Standard marshallers are provided for converting values of this field
|
||||||
|
# into XML. If you want to customize the marshalling process, you can
|
||||||
|
# define a method in "xml" that will accept a field value and will
|
||||||
|
# return a possibly different value. Be careful: do not return a chunk
|
||||||
|
# of XML here! Simply return an alternate value, that will be
|
||||||
|
# XML-marshalled.
|
||||||
|
self.xml = xml
|
||||||
|
|
||||||
def init(self, name, klass, appName):
|
def init(self, name, klass, appName):
|
||||||
'''When the application server starts, this secondary constructor is
|
'''When the application server starts, this secondary constructor is
|
||||||
|
@ -351,7 +358,7 @@ class Field:
|
||||||
for r in res:
|
for r in res:
|
||||||
if r == layoutType: return True
|
if r == layoutType: return True
|
||||||
return
|
return
|
||||||
elif res in ('view', 'edit', 'result', 'buttons'):
|
elif res in ('view', 'edit', 'result', 'buttons', 'xml'):
|
||||||
return res == layoutType
|
return res == layoutType
|
||||||
# For showing a field on layout "buttons", the "buttons" layout must
|
# For showing a field on layout "buttons", the "buttons" layout must
|
||||||
# explicitly be returned by the show method.
|
# explicitly be returned by the show method.
|
||||||
|
@ -570,6 +577,12 @@ class Field:
|
||||||
method in string.py).'''
|
method in string.py).'''
|
||||||
return self.getFormattedValue(obj, value, showChanges)
|
return self.getFormattedValue(obj, value, showChanges)
|
||||||
|
|
||||||
|
def getXmlValue(self, obj, value):
|
||||||
|
'''This method allows a developer to customize the value that will be
|
||||||
|
marshalled into XML. It makes use of attribute "xml".'''
|
||||||
|
if not self.xml: return value
|
||||||
|
return self.xml(obj, value)
|
||||||
|
|
||||||
def getIndexType(self):
|
def getIndexType(self):
|
||||||
'''Returns the name of the technical, Zope-level index type for this
|
'''Returns the name of the technical, Zope-level index type for this
|
||||||
field.'''
|
field.'''
|
||||||
|
|
|
@ -59,7 +59,7 @@ class Action(Field):
|
||||||
width=None, height=None, maxChars=None, colspan=1, action=None,
|
width=None, height=None, maxChars=None, colspan=1, action=None,
|
||||||
result='computation', confirm=False, master=None,
|
result='computation', confirm=False, master=None,
|
||||||
masterValue=None, focus=False, historized=False, mapping=None,
|
masterValue=None, focus=False, historized=False, mapping=None,
|
||||||
label=None, icon=None):
|
label=None, icon=None, xml=None):
|
||||||
# Can be a single method or a list/tuple of methods
|
# Can be a single method or a list/tuple of methods
|
||||||
self.action = action
|
self.action = action
|
||||||
# For the 'result' param:
|
# For the 'result' param:
|
||||||
|
@ -80,7 +80,7 @@ class Action(Field):
|
||||||
move, indexed, False, specificReadPermission,
|
move, indexed, False, specificReadPermission,
|
||||||
specificWritePermission, width, height, None, colspan,
|
specificWritePermission, width, height, None, colspan,
|
||||||
master, masterValue, focus, historized, mapping, label,
|
master, masterValue, focus, historized, mapping, label,
|
||||||
None, None, None, None, False)
|
None, None, None, None, False, xml)
|
||||||
self.validable = False
|
self.validable = False
|
||||||
self.renderLabel = False # Label is rendered directly within the button
|
self.renderLabel = False # Label is rendered directly within the button
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,7 @@ class Boolean(Field):
|
||||||
maxChars=None, colspan=1, master=None, masterValue=None,
|
maxChars=None, colspan=1, master=None, masterValue=None,
|
||||||
focus=False, historized=False, mapping=None, label=None,
|
focus=False, historized=False, mapping=None, label=None,
|
||||||
sdefault=False, scolspan=1, swidth=None, sheight=None,
|
sdefault=False, scolspan=1, swidth=None, sheight=None,
|
||||||
persist=True, render='checkbox'):
|
persist=True, render='checkbox', xml=None):
|
||||||
# By default, a boolean is edited via a checkbox. It can also be edited
|
# By default, a boolean is edited via a checkbox. It can also be edited
|
||||||
# via 2 radio buttons (p_render="radios").
|
# via 2 radio buttons (p_render="radios").
|
||||||
self.render = render
|
self.render = render
|
||||||
|
@ -93,7 +93,7 @@ class Boolean(Field):
|
||||||
specificReadPermission, specificWritePermission, width,
|
specificReadPermission, specificWritePermission, width,
|
||||||
height, None, colspan, master, masterValue, focus,
|
height, None, colspan, master, masterValue, focus,
|
||||||
historized, mapping, label, sdefault, scolspan, swidth,
|
historized, mapping, label, sdefault, scolspan, swidth,
|
||||||
sheight, persist)
|
sheight, persist, xml)
|
||||||
self.pythonType = bool
|
self.pythonType = bool
|
||||||
|
|
||||||
def getDefaultLayouts(self):
|
def getDefaultLayouts(self):
|
||||||
|
|
|
@ -210,19 +210,19 @@ class Calendar(Field):
|
||||||
pxEdit = pxSearch = ''
|
pxEdit = pxSearch = ''
|
||||||
|
|
||||||
def __init__(self, eventTypes, eventNameMethod=None, validator=None,
|
def __init__(self, eventTypes, eventNameMethod=None, validator=None,
|
||||||
default=None, show='view', page='main', group=None,
|
default=None, show=('view', 'xml'), page='main', group=None,
|
||||||
layouts=None, move=0, specificReadPermission=False,
|
layouts=None, move=0, specificReadPermission=False,
|
||||||
specificWritePermission=False, width=None, height=300,
|
specificWritePermission=False, width=None, height=300,
|
||||||
colspan=1, master=None, masterValue=None, focus=False,
|
colspan=1, master=None, masterValue=None, focus=False,
|
||||||
mapping=None, label=None, maxEventLength=50,
|
mapping=None, label=None, maxEventLength=50,
|
||||||
otherCalendars=None, additionalInfo=None, startDate=None,
|
otherCalendars=None, additionalInfo=None, startDate=None,
|
||||||
endDate=None, defaultDate=None, preCompute=None,
|
endDate=None, defaultDate=None, preCompute=None,
|
||||||
applicableEvents=None):
|
applicableEvents=None, xml=None):
|
||||||
Field.__init__(self, validator, (0,1), default, show, page, group,
|
Field.__init__(self, validator, (0,1), default, show, page, group,
|
||||||
layouts, move, False, False, specificReadPermission,
|
layouts, move, False, False, specificReadPermission,
|
||||||
specificWritePermission, width, height, None, colspan,
|
specificWritePermission, width, height, None, colspan,
|
||||||
master, masterValue, focus, False, mapping, label, None,
|
master, masterValue, focus, False, mapping, label, None,
|
||||||
None, None, None, True)
|
None, None, None, True, xml)
|
||||||
# eventTypes can be a "static" list or tuple of strings that identify
|
# eventTypes can be a "static" list or tuple of strings that identify
|
||||||
# the types of events that are supported by this calendar. It can also
|
# the types of events that are supported by this calendar. It can also
|
||||||
# be a method that computes such a "dynamic" list or tuple. When
|
# be a method that computes such a "dynamic" list or tuple. When
|
||||||
|
|
|
@ -31,14 +31,13 @@ class Computed(Field):
|
||||||
value=":field.sdefault"/>''')
|
value=":field.sdefault"/>''')
|
||||||
|
|
||||||
def __init__(self, validator=None, multiplicity=(0,1), default=None,
|
def __init__(self, validator=None, multiplicity=(0,1), default=None,
|
||||||
show=('view', 'result'), page='main', group=None,
|
show=None, page='main', group=None, layouts=None, move=0,
|
||||||
layouts=None, move=0, indexed=False, searchable=False,
|
indexed=False, searchable=False, specificReadPermission=False,
|
||||||
specificReadPermission=False, specificWritePermission=False,
|
specificWritePermission=False, width=None, height=None,
|
||||||
width=None, height=None, maxChars=None, colspan=1, method=None,
|
maxChars=None, colspan=1, method=None, formatMethod=None,
|
||||||
formatMethod=None, plainText=False, master=None,
|
plainText=False, master=None, masterValue=None, focus=False,
|
||||||
masterValue=None, focus=False, historized=False, mapping=None,
|
historized=False, mapping=None, label=None, sdefault='',
|
||||||
label=None, sdefault='', scolspan=1, swidth=None, sheight=None,
|
scolspan=1, swidth=None, sheight=None, context=None, xml=None):
|
||||||
context=None):
|
|
||||||
# The Python method used for computing the field value, or a PX.
|
# The Python method used for computing the field value, or a PX.
|
||||||
self.method = method
|
self.method = method
|
||||||
# A specific method for producing the formatted value of this field.
|
# A specific method for producing the formatted value of this field.
|
||||||
|
@ -55,6 +54,13 @@ class Computed(Field):
|
||||||
if isinstance(method, Px):
|
if isinstance(method, Px):
|
||||||
# When field computation is done with a PX, the result is XHTML.
|
# When field computation is done with a PX, the result is XHTML.
|
||||||
self.plainText = False
|
self.plainText = False
|
||||||
|
# Determine default value for "show"
|
||||||
|
if show == None:
|
||||||
|
# XHTML content in a Computed field generally corresponds to some
|
||||||
|
# custom XHTML widget. This is why, by default, we do not render it
|
||||||
|
# in the xml layout.
|
||||||
|
show = self.plainText and ('view', 'result', 'xml') or \
|
||||||
|
('view', 'result')
|
||||||
# If method is a PX, its context can be given in p_context.
|
# If method is a PX, its context can be given in p_context.
|
||||||
self.context = context
|
self.context = context
|
||||||
Field.__init__(self, None, multiplicity, default, show, page, group,
|
Field.__init__(self, None, multiplicity, default, show, page, group,
|
||||||
|
@ -62,7 +68,7 @@ class Computed(Field):
|
||||||
specificReadPermission, specificWritePermission, width,
|
specificReadPermission, specificWritePermission, width,
|
||||||
height, None, colspan, master, masterValue, focus,
|
height, None, colspan, master, masterValue, focus,
|
||||||
historized, mapping, label, sdefault, scolspan, swidth,
|
historized, mapping, label, sdefault, scolspan, swidth,
|
||||||
sheight, False)
|
sheight, False, xml)
|
||||||
self.validable = False
|
self.validable = False
|
||||||
|
|
||||||
def getValue(self, obj):
|
def getValue(self, obj):
|
||||||
|
|
|
@ -170,7 +170,7 @@ class Date(Field):
|
||||||
maxChars=None, colspan=1, master=None, masterValue=None,
|
maxChars=None, colspan=1, master=None, masterValue=None,
|
||||||
focus=False, historized=False, mapping=None, label=None,
|
focus=False, historized=False, mapping=None, label=None,
|
||||||
sdefault=None, scolspan=1, swidth=None, sheight=None,
|
sdefault=None, scolspan=1, swidth=None, sheight=None,
|
||||||
persist=True):
|
persist=True, xml=None):
|
||||||
self.format = format
|
self.format = format
|
||||||
self.calendar = calendar
|
self.calendar = calendar
|
||||||
self.startYear = startYear
|
self.startYear = startYear
|
||||||
|
@ -183,7 +183,7 @@ class Date(Field):
|
||||||
specificReadPermission, specificWritePermission, width,
|
specificReadPermission, specificWritePermission, width,
|
||||||
height, None, colspan, master, masterValue, focus,
|
height, None, colspan, master, masterValue, focus,
|
||||||
historized, mapping, label, sdefault, scolspan, swidth,
|
historized, mapping, label, sdefault, scolspan, swidth,
|
||||||
sheight, persist)
|
sheight, persist, xml)
|
||||||
|
|
||||||
def getCss(self, layoutType, res):
|
def getCss(self, layoutType, res):
|
||||||
# CSS files are only required if the calendar must be shown.
|
# CSS files are only required if the calendar must be shown.
|
||||||
|
|
|
@ -324,14 +324,14 @@ class File(Field):
|
||||||
maxChars=None, colspan=1, master=None, masterValue=None,
|
maxChars=None, colspan=1, master=None, masterValue=None,
|
||||||
focus=False, historized=False, mapping=None, label=None,
|
focus=False, historized=False, mapping=None, label=None,
|
||||||
isImage=False, sdefault='', scolspan=1, swidth=None,
|
isImage=False, sdefault='', scolspan=1, swidth=None,
|
||||||
sheight=None):
|
sheight=None, xml=None):
|
||||||
self.isImage = isImage
|
self.isImage = isImage
|
||||||
Field.__init__(self, validator, multiplicity, default, show, page,
|
Field.__init__(self, validator, multiplicity, default, show, page,
|
||||||
group, layouts, move, indexed, False,
|
group, layouts, move, indexed, False,
|
||||||
specificReadPermission, specificWritePermission, width,
|
specificReadPermission, specificWritePermission, width,
|
||||||
height, None, colspan, master, masterValue, focus,
|
height, None, colspan, master, masterValue, focus,
|
||||||
historized, mapping, label, sdefault, scolspan, swidth,
|
historized, mapping, label, sdefault, scolspan, swidth,
|
||||||
sheight, True)
|
sheight, True, xml)
|
||||||
|
|
||||||
def getRequestValue(self, obj, requestName=None):
|
def getRequestValue(self, obj, requestName=None):
|
||||||
name = requestName or self.name
|
name = requestName or self.name
|
||||||
|
|
|
@ -56,7 +56,8 @@ class Float(Field):
|
||||||
maxChars=13, colspan=1, master=None, masterValue=None,
|
maxChars=13, colspan=1, master=None, masterValue=None,
|
||||||
focus=False, historized=False, mapping=None, label=None,
|
focus=False, historized=False, mapping=None, label=None,
|
||||||
sdefault=('',''), scolspan=1, swidth=None, sheight=None,
|
sdefault=('',''), scolspan=1, swidth=None, sheight=None,
|
||||||
persist=True, precision=None, sep=(',', '.'), tsep=' '):
|
persist=True, precision=None, sep=(',', '.'), tsep=' ',
|
||||||
|
xml=None):
|
||||||
# The precision is the number of decimal digits. This number is used
|
# The precision is the number of decimal digits. This number is used
|
||||||
# for rendering the float, but the internal float representation is not
|
# for rendering the float, but the internal float representation is not
|
||||||
# rounded.
|
# rounded.
|
||||||
|
@ -78,7 +79,7 @@ class Float(Field):
|
||||||
specificReadPermission, specificWritePermission, width,
|
specificReadPermission, specificWritePermission, width,
|
||||||
height, maxChars, colspan, master, masterValue, focus,
|
height, maxChars, colspan, master, masterValue, focus,
|
||||||
historized, mapping, label, sdefault, scolspan, swidth,
|
historized, mapping, label, sdefault, scolspan, swidth,
|
||||||
sheight, persist)
|
sheight, persist, xml)
|
||||||
self.pythonType = float
|
self.pythonType = float
|
||||||
|
|
||||||
def getFormattedValue(self, obj, value, showChanges=False, language=None):
|
def getFormattedValue(self, obj, value, showChanges=False, language=None):
|
||||||
|
|
|
@ -29,11 +29,12 @@ class Info(Field):
|
||||||
indexed=False, searchable=False, specificReadPermission=False,
|
indexed=False, searchable=False, specificReadPermission=False,
|
||||||
specificWritePermission=False, width=None, height=None,
|
specificWritePermission=False, width=None, height=None,
|
||||||
maxChars=None, colspan=1, master=None, masterValue=None,
|
maxChars=None, colspan=1, master=None, masterValue=None,
|
||||||
focus=False, historized=False, mapping=None, label=None):
|
focus=False, historized=False, mapping=None, label=None,
|
||||||
|
xml=None):
|
||||||
Field.__init__(self, None, (0,1), default, show, page, group, layouts,
|
Field.__init__(self, None, (0,1), default, show, page, group, layouts,
|
||||||
move, indexed, False, specificReadPermission,
|
move, indexed, False, specificReadPermission,
|
||||||
specificWritePermission, width, height, None, colspan,
|
specificWritePermission, width, height, None, colspan,
|
||||||
master, masterValue, focus, historized, mapping, label,
|
master, masterValue, focus, historized, mapping, label,
|
||||||
None, None, None, None, False)
|
None, None, None, None, False, xml)
|
||||||
self.validable = False
|
self.validable = False
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
|
@ -53,13 +53,13 @@ class Integer(Field):
|
||||||
maxChars=13, colspan=1, master=None, masterValue=None,
|
maxChars=13, colspan=1, master=None, masterValue=None,
|
||||||
focus=False, historized=False, mapping=None, label=None,
|
focus=False, historized=False, mapping=None, label=None,
|
||||||
sdefault=('',''), scolspan=1, swidth=None, sheight=None,
|
sdefault=('',''), scolspan=1, swidth=None, sheight=None,
|
||||||
persist=True):
|
persist=True, xml=None):
|
||||||
Field.__init__(self, validator, multiplicity, default, show, page,
|
Field.__init__(self, validator, multiplicity, default, show, page,
|
||||||
group, layouts, move, indexed, searchable,
|
group, layouts, move, indexed, searchable,
|
||||||
specificReadPermission, specificWritePermission, width,
|
specificReadPermission, specificWritePermission, width,
|
||||||
height, maxChars, colspan, master, masterValue, focus,
|
height, maxChars, colspan, master, masterValue, focus,
|
||||||
historized, mapping, label, sdefault, scolspan, swidth,
|
historized, mapping, label, sdefault, scolspan, swidth,
|
||||||
sheight, persist)
|
sheight, persist, xml)
|
||||||
self.pythonType = long
|
self.pythonType = long
|
||||||
|
|
||||||
def validateValue(self, obj, value):
|
def validateValue(self, obj, value):
|
||||||
|
|
|
@ -78,12 +78,13 @@ class List(Field):
|
||||||
specificWritePermission=False, width='', height=None,
|
specificWritePermission=False, width='', height=None,
|
||||||
maxChars=None, colspan=1, master=None, masterValue=None,
|
maxChars=None, colspan=1, master=None, masterValue=None,
|
||||||
focus=False, historized=False, mapping=None, label=None,
|
focus=False, historized=False, mapping=None, label=None,
|
||||||
subLayouts=Table('frv', width=None), widths=None):
|
subLayouts=Table('frv', width=None), widths=None, xml=None):
|
||||||
Field.__init__(self, validator, multiplicity, default, show, page,
|
Field.__init__(self, validator, multiplicity, default, show, page,
|
||||||
group, layouts, move, indexed, False,
|
group, layouts, move, indexed, False,
|
||||||
specificReadPermission, specificWritePermission, width,
|
specificReadPermission, specificWritePermission, width,
|
||||||
height, None, colspan, master, masterValue, focus,
|
height, None, colspan, master, masterValue, focus,
|
||||||
historized, mapping, label, None, None, None, None, True)
|
historized, mapping, label, None, None, None, None,
|
||||||
|
True, xml)
|
||||||
self.validable = True
|
self.validable = True
|
||||||
# Tuples of (names, Field instances) determining the format of every
|
# Tuples of (names, Field instances) determining the format of every
|
||||||
# element in the list.
|
# element in the list.
|
||||||
|
|
|
@ -49,12 +49,12 @@ class Ogone(Field):
|
||||||
group=None, layouts=None, move=0, specificReadPermission=False,
|
group=None, layouts=None, move=0, specificReadPermission=False,
|
||||||
specificWritePermission=False, width=None, height=None,
|
specificWritePermission=False, width=None, height=None,
|
||||||
colspan=1, master=None, masterValue=None, focus=False,
|
colspan=1, master=None, masterValue=None, focus=False,
|
||||||
mapping=None, label=None):
|
mapping=None, label=None, xml=None):
|
||||||
Field.__init__(self, None, (0,1), None, show, page, group, layouts,
|
Field.__init__(self, None, (0,1), None, show, page, group, layouts,
|
||||||
move, False, False,specificReadPermission,
|
move, False, False,specificReadPermission,
|
||||||
specificWritePermission, width, height, None, colspan,
|
specificWritePermission, width, height, None, colspan,
|
||||||
master, masterValue, focus, False, mapping, label, None,
|
master, masterValue, focus, False, mapping, label, None,
|
||||||
None, None, None, False)
|
None, None, None, False, xml)
|
||||||
# orderMethod must contain a method returning a dict containing info
|
# orderMethod must contain a method returning a dict containing info
|
||||||
# about the order. Following keys are mandatory:
|
# about the order. Following keys are mandatory:
|
||||||
# * orderID An identifier for the order. Don't use the object UID
|
# * orderID An identifier for the order. Don't use the object UID
|
||||||
|
|
|
@ -158,7 +158,8 @@ class Pod(Field):
|
||||||
template=None, templateName=None, showTemplate=None,
|
template=None, templateName=None, showTemplate=None,
|
||||||
freezeTemplate=None, maxPerRow=5, context=None,
|
freezeTemplate=None, maxPerRow=5, context=None,
|
||||||
stylesMapping={}, formats=None, getChecked=None, mailing=None,
|
stylesMapping={}, formats=None, getChecked=None, mailing=None,
|
||||||
mailingName=None, showMailing=None, mailingInfo=None):
|
mailingName=None, showMailing=None, mailingInfo=None,
|
||||||
|
xml=None):
|
||||||
# Param "template" stores the path to the pod template(s). If there is
|
# Param "template" stores the path to the pod template(s). If there is
|
||||||
# a single template, a string is expected. Else, a list or tuple of
|
# a single template, a string is expected. Else, a list or tuple of
|
||||||
# strings is expected. Every such path must be relative to your
|
# strings is expected. Every such path must be relative to your
|
||||||
|
@ -275,7 +276,7 @@ class Pod(Field):
|
||||||
move, indexed, searchable, specificReadPermission,
|
move, indexed, searchable, specificReadPermission,
|
||||||
specificWritePermission, width, height, None, colspan,
|
specificWritePermission, width, height, None, colspan,
|
||||||
master, masterValue, focus, historized, mapping, label,
|
master, masterValue, focus, historized, mapping, label,
|
||||||
None, None, None, None, True)
|
None, None, None, None, True, xml)
|
||||||
# Param "persist" is set to True but actually, persistence for a pod
|
# Param "persist" is set to True but actually, persistence for a pod
|
||||||
# field is determined by freezing.
|
# field is determined by freezing.
|
||||||
self.validable = False
|
self.validable = False
|
||||||
|
|
|
@ -528,7 +528,7 @@ class Ref(Field):
|
||||||
checkboxes=True, checkboxesDefault=None, sdefault='',
|
checkboxes=True, checkboxesDefault=None, sdefault='',
|
||||||
scolspan=1, swidth=None, sheight=None, sselect=None,
|
scolspan=1, swidth=None, sheight=None, sselect=None,
|
||||||
persist=True, render='list', menuIdMethod=None,
|
persist=True, render='list', menuIdMethod=None,
|
||||||
menuInfoMethod=None, menuUrlMethod=None):
|
menuInfoMethod=None, menuUrlMethod=None, xml=None):
|
||||||
self.klass = klass
|
self.klass = klass
|
||||||
self.attribute = attribute
|
self.attribute = attribute
|
||||||
# May the user add new objects through this ref ? "add" may also contain
|
# May the user add new objects through this ref ? "add" may also contain
|
||||||
|
@ -708,7 +708,7 @@ class Ref(Field):
|
||||||
specificReadPermission, specificWritePermission, width,
|
specificReadPermission, specificWritePermission, width,
|
||||||
height, None, colspan, master, masterValue, focus,
|
height, None, colspan, master, masterValue, focus,
|
||||||
historized, mapping, label, sdefault, scolspan, swidth,
|
historized, mapping, label, sdefault, scolspan, swidth,
|
||||||
sheight, persist)
|
sheight, persist, xml)
|
||||||
self.validable = bool(self.link)
|
self.validable = bool(self.link)
|
||||||
self.checkParameters()
|
self.checkParameters()
|
||||||
|
|
||||||
|
@ -794,6 +794,12 @@ class Ref(Field):
|
||||||
# Return a copy: it can be dangerous to give the real database value.
|
# Return a copy: it can be dangerous to give the real database value.
|
||||||
if res: return list(res)
|
if res: return list(res)
|
||||||
|
|
||||||
|
def getXmlValue(self, obj, value):
|
||||||
|
'''The default XML value for a Ref is the list of tied object URLs.'''
|
||||||
|
# Bypass the default behaviour if a custom method is given
|
||||||
|
if self.xml: return self.xml(obj, value)
|
||||||
|
return ['%s/xml' % tied.o.absolute_url() for tied in value]
|
||||||
|
|
||||||
def getPossibleValues(self, obj, startNumber=None, someObjects=False,
|
def getPossibleValues(self, obj, startNumber=None, someObjects=False,
|
||||||
removeLinked=False):
|
removeLinked=False):
|
||||||
'''This method returns the list of all objects that can be selected
|
'''This method returns the list of all objects that can be selected
|
||||||
|
|
|
@ -381,7 +381,7 @@ class String(Field):
|
||||||
persist=True, transform='none', placeholder=None,
|
persist=True, transform='none', placeholder=None,
|
||||||
styles=('p','h1','h2','h3','h4'), allowImageUpload=True,
|
styles=('p','h1','h2','h3','h4'), allowImageUpload=True,
|
||||||
spellcheck=False, languages=('en',), languagesLayouts=None,
|
spellcheck=False, languages=('en',), languagesLayouts=None,
|
||||||
inlineEdit=False):
|
inlineEdit=False, xml=None):
|
||||||
# According to format, the widget will be different: input field,
|
# According to format, the widget will be different: input field,
|
||||||
# textarea, inline editor... Note that there can be only one String
|
# textarea, inline editor... Note that there can be only one String
|
||||||
# field of format CAPTCHA by page, because the captcha challenge is
|
# field of format CAPTCHA by page, because the captcha challenge is
|
||||||
|
@ -425,7 +425,7 @@ class String(Field):
|
||||||
specificReadPermission, specificWritePermission, width,
|
specificReadPermission, specificWritePermission, width,
|
||||||
height, maxChars, colspan, master, masterValue, focus,
|
height, maxChars, colspan, master, masterValue, focus,
|
||||||
historized, mapping, label, sdefault, scolspan, swidth,
|
historized, mapping, label, sdefault, scolspan, swidth,
|
||||||
sheight, persist)
|
sheight, persist, xml)
|
||||||
self.isSelect = self.isSelection()
|
self.isSelect = self.isSelection()
|
||||||
# If self.isSelect, self.sdefault must be a list of value(s).
|
# If self.isSelect, self.sdefault must be a list of value(s).
|
||||||
if self.isSelect and not sdefault:
|
if self.isSelect and not sdefault:
|
||||||
|
|
|
@ -920,9 +920,9 @@ class ToolMixin(BaseMixin):
|
||||||
# to authentify the user, we ask to identify a user or, if impossible,
|
# to authentify the user, we ask to identify a user or, if impossible,
|
||||||
# a special user.
|
# a special user.
|
||||||
login, password = self.identifyUser(alsoSpecial=not authentify)
|
login, password = self.identifyUser(alsoSpecial=not authentify)
|
||||||
# Stop here if no user was found and authentication was required.
|
# Stop here if no user was found and authentication was required
|
||||||
if authentify and not login: return
|
if authentify and not login: return
|
||||||
# Now, get the User instance.
|
# Now, get the User instance
|
||||||
if source == 'zodb':
|
if source == 'zodb':
|
||||||
# Get the User object, but only if it is a true local user.
|
# Get the User object, but only if it is a true local user.
|
||||||
user = tool.search1('User', noSecurity=True, login=login)
|
user = tool.search1('User', noSecurity=True, login=login)
|
||||||
|
@ -933,11 +933,14 @@ class ToolMixin(BaseMixin):
|
||||||
# Get the user object, be it really local or a copy of a LDAP user.
|
# Get the user object, be it really local or a copy of a LDAP user.
|
||||||
user = tool.search1('User', noSecurity=True, login=login)
|
user = tool.search1('User', noSecurity=True, login=login)
|
||||||
if not user: return
|
if not user: return
|
||||||
# Authentify the user if required.
|
# Authentify the user if required
|
||||||
if authentify:
|
if authentify:
|
||||||
if (user.state == 'inactive') or (not user.checkPassword(password)):
|
if (user.state == 'inactive') or (not user.checkPassword(password)):
|
||||||
# Disable the authentication cookie.
|
# Disable the authentication cookie and remove credentials
|
||||||
|
# stored on the request.
|
||||||
req.RESPONSE.expireCookie('_appy_', path='/')
|
req.RESPONSE.expireCookie('_appy_', path='/')
|
||||||
|
k = 'HTTP_AUTHORIZATION'
|
||||||
|
req._auth = req[k] = req._orig_env[k] = None
|
||||||
return
|
return
|
||||||
# Create an authentication cookie for this user.
|
# Create an authentication cookie for this user.
|
||||||
gutils.writeCookie(login, password, req)
|
gutils.writeCookie(login, password, req)
|
||||||
|
@ -957,7 +960,7 @@ class ToolMixin(BaseMixin):
|
||||||
if jsEnabled and not cookiesEnabled:
|
if jsEnabled and not cookiesEnabled:
|
||||||
msg = self.translate('enable_cookies')
|
msg = self.translate('enable_cookies')
|
||||||
return self.goto(urlBack, msg)
|
return self.goto(urlBack, msg)
|
||||||
# Authenticate the user.
|
# Authenticate the user
|
||||||
if self.getUser(authentify=True) or \
|
if self.getUser(authentify=True) or \
|
||||||
self.getUser(authentify=True, source='ldap'):
|
self.getUser(authentify=True, source='ldap'):
|
||||||
msg = self.translate('login_ok')
|
msg = self.translate('login_ok')
|
||||||
|
|
|
@ -530,7 +530,7 @@ class BaseMixin:
|
||||||
res = XmlMarshaller().marshall(methodRes, objectType='appy')
|
res = XmlMarshaller().marshall(methodRes, objectType='appy')
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
tb = sutils.Traceback.get()
|
tb = sutils.Traceback.get()
|
||||||
res = XmlMarshaller().marshall(tb, objectType='appy')
|
res = XmlMarshaller(rootTag='exception').marshall(tb)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def say(self, msg, type='info'):
|
def say(self, msg, type='info'):
|
||||||
|
@ -1430,10 +1430,12 @@ class BaseMixin:
|
||||||
return layoutType in showValue
|
return layoutType in showValue
|
||||||
|
|
||||||
getUrlDefaults = {'page':True, 'nav':True}
|
getUrlDefaults = {'page':True, 'nav':True}
|
||||||
def getUrl(self, base=None, mode='view', inPopup=False, **kwargs):
|
def getUrl(self, base=None, mode='view', inPopup=False, relative=False,
|
||||||
|
**kwargs):
|
||||||
'''Returns an URL for this object.
|
'''Returns an URL for this object.
|
||||||
* If p_base is None, it will be the base URL for this object
|
* If p_base is None, it will be the base URL for this object
|
||||||
(ie, Zope self.absolute_url()).
|
(ie, Zope self.absolute_url() or an URL this is relative to the
|
||||||
|
root site if p_relative is True).
|
||||||
* p_mode can be "edit", "view" or "raw" (a non-param, base URL)
|
* p_mode can be "edit", "view" or "raw" (a non-param, base URL)
|
||||||
* If p_inPopup is True, the link will be opened in the Appy iframe.
|
* If p_inPopup is True, the link will be opened in the Appy iframe.
|
||||||
An additional param "popup=1" will be added to URL params, in order
|
An additional param "popup=1" will be added to URL params, in order
|
||||||
|
@ -1447,19 +1449,20 @@ class BaseMixin:
|
||||||
# Define the URL suffix
|
# Define the URL suffix
|
||||||
suffix = ''
|
suffix = ''
|
||||||
if mode != 'raw': suffix = '/%s' % mode
|
if mode != 'raw': suffix = '/%s' % mode
|
||||||
# Define base URL if omitted
|
# Define the base URL if omitted
|
||||||
if not base:
|
if not base:
|
||||||
base = self.absolute_url() + suffix
|
base = relative and self.absolute_url_path() or self.absolute_url()
|
||||||
|
base += suffix
|
||||||
existingParams = ''
|
existingParams = ''
|
||||||
else:
|
else:
|
||||||
existingParams = urllib.splitquery(base)[1]
|
existingParams = urllib.splitquery(base)[1]
|
||||||
# If a raw URL is asked, remove any param and suffix.
|
# If a raw URL is asked, remove any param and suffix
|
||||||
if mode == 'raw':
|
if mode == 'raw':
|
||||||
if '?' in base: base = base[:base.index('?')]
|
if '?' in base: base = base[:base.index('?')]
|
||||||
base = base.strip('/')
|
base = base.rstrip('/')
|
||||||
for mode in ('view', 'edit'):
|
for mode in ('view', 'edit'):
|
||||||
if base.endswith(mode):
|
if base.endswith(mode):
|
||||||
base = base[:-len(mode)].strip('/')
|
base = base[:-len(mode)].rstrip('/')
|
||||||
break
|
break
|
||||||
return base
|
return base
|
||||||
# Manage default args
|
# Manage default args
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
import os, re, httplib, sys, stat, urlparse, time, socket, xml.sax
|
import os, re, httplib, sys, stat, urlparse, time, socket, xml.sax
|
||||||
from urllib import quote
|
import urllib
|
||||||
from StringIO import StringIO
|
from StringIO import StringIO
|
||||||
from mimetypes import guess_type
|
from mimetypes import guess_type
|
||||||
from base64 import encodestring
|
from base64 import encodestring
|
||||||
|
@ -19,7 +19,7 @@ class FormDataEncoder:
|
||||||
|
|
||||||
def marshalValue(self, name, value):
|
def marshalValue(self, name, value):
|
||||||
if isinstance(value, basestring):
|
if isinstance(value, basestring):
|
||||||
return '%s=%s' % (name, quote(str(value)))
|
return '%s=%s' % (name, urllib.quote(str(value)))
|
||||||
elif isinstance(value, float):
|
elif isinstance(value, float):
|
||||||
return '%s:float=%s' % (name, value)
|
return '%s:float=%s' % (name, value)
|
||||||
elif isinstance(value, int):
|
elif isinstance(value, int):
|
||||||
|
@ -109,7 +109,13 @@ class HttpResponse:
|
||||||
# Return an unmarshalled version of the XML content, for
|
# Return an unmarshalled version of the XML content, for
|
||||||
# easy use in Python.
|
# easy use in Python.
|
||||||
try:
|
try:
|
||||||
return XmlUnmarshaller(utf8=self.utf8).parse(self.body)
|
parser = XmlUnmarshaller(utf8=self.utf8)
|
||||||
|
res = parser.parse(self.body)
|
||||||
|
if parser.rootTag == 'exception':
|
||||||
|
# This is an exception: "res" contains the traceback
|
||||||
|
raise ResourceError('Distant server exception: ' \
|
||||||
|
'%s' % res)
|
||||||
|
return res
|
||||||
except xml.sax.SAXParseException, se:
|
except xml.sax.SAXParseException, se:
|
||||||
raise ResourceError('Invalid XML response (%s)'%str(se))
|
raise ResourceError('Invalid XML response (%s)'%str(se))
|
||||||
|
|
||||||
|
@ -156,7 +162,7 @@ class Resource:
|
||||||
credentials = '%s:%s' % (self.username, self.password)
|
credentials = '%s:%s' % (self.username, self.password)
|
||||||
credentials = credentials.replace('\012', '')
|
credentials = credentials.replace('\012', '')
|
||||||
headers['Authorization'] = "Basic %s" % encodestring(credentials)
|
headers['Authorization'] = "Basic %s" % encodestring(credentials)
|
||||||
headers['User-Agent'] = 'WebDAV.client'
|
headers['User-Agent'] = 'Appy'
|
||||||
headers['Host'] = self.host
|
headers['Host'] = self.host
|
||||||
headers['Connection'] = 'close'
|
headers['Connection'] = 'close'
|
||||||
headers['Accept'] = '*/*'
|
headers['Accept'] = '*/*'
|
||||||
|
@ -241,9 +247,14 @@ class Resource:
|
||||||
if type =='fileName': body.close()
|
if type =='fileName': body.close()
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def get(self, uri=None, headers={}):
|
def get(self, uri=None, headers={}, params=None):
|
||||||
'''Perform a HTTP GET on the server.'''
|
'''Perform a HTTP GET on the server. Parameters can be given as a dict
|
||||||
|
in p_params.'''
|
||||||
if not uri: uri = self.uri
|
if not uri: uri = self.uri
|
||||||
|
# Encode and append params if given
|
||||||
|
if params:
|
||||||
|
sep = ('?' in uri) and '&' or '?'
|
||||||
|
uri = '%s%s%s' % (uri, sep, urllib.urlencode(params))
|
||||||
return self.send('GET', uri, headers=headers)
|
return self.send('GET', uri, headers=headers)
|
||||||
rss = get
|
rss = get
|
||||||
|
|
||||||
|
|
|
@ -322,6 +322,8 @@ class XmlUnmarshaller(XmlParser):
|
||||||
# knowing that the value is a 'string' is not sufficient).
|
# knowing that the value is a 'string' is not sufficient).
|
||||||
self.conversionFunctions = conversionFunctions
|
self.conversionFunctions = conversionFunctions
|
||||||
self.utf8 = utf8
|
self.utf8 = utf8
|
||||||
|
# Remember the name of the root tag
|
||||||
|
self.rootTag = None
|
||||||
|
|
||||||
def encode(self, value):
|
def encode(self, value):
|
||||||
'''Depending on self.utf8 we may need to encode p_value.'''
|
'''Depending on self.utf8 we may need to encode p_value.'''
|
||||||
|
@ -354,6 +356,9 @@ class XmlUnmarshaller(XmlParser):
|
||||||
previousElem = None
|
previousElem = None
|
||||||
if self.env.currentElem:
|
if self.env.currentElem:
|
||||||
previousElem = self.env.currentElem.name
|
previousElem = self.env.currentElem.name
|
||||||
|
else:
|
||||||
|
# We are walking the root tag
|
||||||
|
self.rootTag = elem
|
||||||
e = XmlParser.startElement(self, elem, attrs)
|
e = XmlParser.startElement(self, elem, attrs)
|
||||||
# Determine the type of the element.
|
# Determine the type of the element.
|
||||||
elemType = 'unicode' # Default value
|
elemType = 'unicode' # Default value
|
||||||
|
@ -668,15 +673,11 @@ class XmlMarshaller:
|
||||||
elif fieldType == 'dict': self.dumpDict(res, value)
|
elif fieldType == 'dict': self.dumpDict(res, value)
|
||||||
elif isRef:
|
elif isRef:
|
||||||
if value:
|
if value:
|
||||||
if self.objectType == 'appy':
|
|
||||||
suffix = '/xml'
|
|
||||||
else:
|
|
||||||
suffix = ''
|
|
||||||
if type(value) in sequenceTypes:
|
if type(value) in sequenceTypes:
|
||||||
for elem in value:
|
for elem in value:
|
||||||
self.dumpField(res, 'url', elem.absolute_url()+suffix)
|
self.dumpField(res, 'url', elem.absolute_url())
|
||||||
else:
|
else:
|
||||||
self.dumpField(res, 'url', value.absolute_url()+suffix)
|
self.dumpField(res, 'url', value.absolute_url())
|
||||||
elif fieldType in ('list', 'tuple'):
|
elif fieldType in ('list', 'tuple'):
|
||||||
# The previous condition must be checked before this one because
|
# The previous condition must be checked before this one because
|
||||||
# referred objects may be stored in lists or tuples, too.
|
# referred objects may be stored in lists or tuples, too.
|
||||||
|
@ -814,27 +815,19 @@ class XmlMarshaller:
|
||||||
self.dumpField(res, field.getName(),field.get(instance),
|
self.dumpField(res, field.getName(),field.get(instance),
|
||||||
fieldType=fieldType)
|
fieldType=fieldType)
|
||||||
elif objectType == 'appy':
|
elif objectType == 'appy':
|
||||||
for field in instance.getAppyTypes('view', None):
|
# Dump base attributes
|
||||||
|
for name in ('created', 'creator', 'modified'):
|
||||||
|
self.dumpField(res, name, getattr(instance, name))
|
||||||
|
for field in instance.getAppyTypes('xml', None):
|
||||||
# Dump only needed fields
|
# Dump only needed fields
|
||||||
if (field.type == 'Computed') and not field.plainText:
|
|
||||||
# Ignore fields used for producing custom chunks of HTML
|
|
||||||
# within the web UI.
|
|
||||||
continue
|
|
||||||
if field.name in self.fieldsToExclude: continue
|
if field.name in self.fieldsToExclude: continue
|
||||||
if (type(self.fieldsToMarshall) in sequenceTypes) \
|
if (type(self.fieldsToMarshall) in sequenceTypes) \
|
||||||
and (field.name not in self.fieldsToMarshall): continue
|
and (field.name not in self.fieldsToMarshall): continue
|
||||||
# Determine field type and value
|
# Determine field type and value
|
||||||
fieldType = 'basic'
|
fieldType = (field.type == 'File') and 'file' or 'basic'
|
||||||
if field.type == 'File':
|
v = field.getXmlValue(instance, field.getValue(instance))
|
||||||
fieldType = 'file'
|
|
||||||
v = field.getValue(instance)
|
|
||||||
elif field.type == 'Ref':
|
|
||||||
fieldType = 'ref'
|
|
||||||
v = field.getValue(instance, appy=False)
|
|
||||||
else:
|
|
||||||
v = field.getValue(instance)
|
|
||||||
self.dumpField(res, field.name, v, fieldType=fieldType)
|
self.dumpField(res, field.name, v, fieldType=fieldType)
|
||||||
# Dump the object history.
|
# Dump the object history
|
||||||
if hasattr(instance.aq_base, 'workflow_history'):
|
if hasattr(instance.aq_base, 'workflow_history'):
|
||||||
histTag = self.getTagName('history')
|
histTag = self.getTagName('history')
|
||||||
eventTag = self.getTagName('event')
|
eventTag = self.getTagName('event')
|
||||||
|
|
Loading…
Reference in a new issue