[gen] Extended the HTTP-XML system to be able to call a method via a HTTP POST containing XML data (SOAP or REST-like).
This commit is contained in:
parent
91e0bd2240
commit
6a83285e64
|
@ -46,7 +46,7 @@ class Phase:
|
||||||
<img src=":url('edit')" title=":_('object_edit')"/></a>
|
<img src=":url('edit')" title=":_('object_edit')"/></a>
|
||||||
<a if="editable and locked">
|
<a if="editable and locked">
|
||||||
<img style="cursor: help"
|
<img style="cursor: help"
|
||||||
var="lockDate=tool.formatDate(locked[1]);
|
var="lockDate=ztool.formatDate(locked[1]);
|
||||||
lockMap={'user':ztool.getUserName(locked[0]), \
|
lockMap={'user':ztool.getUserName(locked[0]), \
|
||||||
'date':lockDate};
|
'date':lockDate};
|
||||||
lockMsg=_('page_locked', mapping=lockMap)"
|
lockMsg=_('page_locked', mapping=lockMap)"
|
||||||
|
|
|
@ -286,6 +286,13 @@ class ZopeInstaller:
|
||||||
if role not in roles: roles.append(role)
|
if role not in roles: roles.append(role)
|
||||||
self.app.__ac_roles__ = tuple(roles)
|
self.app.__ac_roles__ = tuple(roles)
|
||||||
|
|
||||||
|
def patchZope(self):
|
||||||
|
'''Patches some arts of Zope.'''
|
||||||
|
# Disables XMLRPC. This way, Zope can transmit HTTP POSTs containing
|
||||||
|
# XML to Appy without trying to recognize it himself as XMLRPC requests.
|
||||||
|
import ZPublisher.HTTPRequest
|
||||||
|
ZPublisher.HTTPRequest.xmlrpc = FakeXmlrpc()
|
||||||
|
|
||||||
def installDependencies(self):
|
def installDependencies(self):
|
||||||
'''Zope products are installed in alphabetical order. But here, we need
|
'''Zope products are installed in alphabetical order. But here, we need
|
||||||
ZCTextIndex to be installed before our Appy application. So, we cheat
|
ZCTextIndex to be installed before our Appy application. So, we cheat
|
||||||
|
@ -297,6 +304,7 @@ class ZopeInstaller:
|
||||||
def install(self):
|
def install(self):
|
||||||
self.logger.info('is being installed...')
|
self.logger.info('is being installed...')
|
||||||
self.installDependencies()
|
self.installDependencies()
|
||||||
|
self.patchZope()
|
||||||
self.installRoles()
|
self.installRoles()
|
||||||
self.installAppyTypes()
|
self.installAppyTypes()
|
||||||
self.installZopeClasses()
|
self.installZopeClasses()
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
import os, os.path, sys, types, urllib, cgi
|
import os, os.path, sys, types, urllib, cgi
|
||||||
from appy import Object
|
from appy import Object
|
||||||
|
from appy.px import Px
|
||||||
from appy.fields.workflow import UiTransition
|
from appy.fields.workflow import UiTransition
|
||||||
import appy.gen as gen
|
import appy.gen as gen
|
||||||
from appy.gen.utils import *
|
from appy.gen.utils import *
|
||||||
|
@ -479,7 +480,7 @@ class BaseMixin:
|
||||||
def xml(self, action=None):
|
def xml(self, action=None):
|
||||||
'''If no p_action is defined, this method returns the XML version of
|
'''If no p_action is defined, this method returns the XML version of
|
||||||
this object. Else, it calls method named p_action on the
|
this object. Else, it calls method named p_action on the
|
||||||
corresponding Appy wrapper and returns, as XML, the its result.'''
|
corresponding Appy wrapper and returns, as XML, its result.'''
|
||||||
self.REQUEST.RESPONSE.setHeader('Content-Type','text/xml;charset=utf-8')
|
self.REQUEST.RESPONSE.setHeader('Content-Type','text/xml;charset=utf-8')
|
||||||
# Check if the user is allowed to consult this object
|
# Check if the user is allowed to consult this object
|
||||||
if not self.allows('read'):
|
if not self.allows('read'):
|
||||||
|
@ -492,7 +493,13 @@ class BaseMixin:
|
||||||
appyObj = self.appy()
|
appyObj = self.appy()
|
||||||
try:
|
try:
|
||||||
methodRes = getattr(appyObj, action)()
|
methodRes = getattr(appyObj, action)()
|
||||||
res = XmlMarshaller().marshall(methodRes, objectType='appy')
|
if isinstance(methodRes, Px):
|
||||||
|
res = methodRes({'self': self.appy()})
|
||||||
|
elif isinstance(methodRes, file):
|
||||||
|
res = methodRes.read()
|
||||||
|
methodRes.close()
|
||||||
|
else:
|
||||||
|
res = XmlMarshaller().marshall(methodRes, objectType='appy')
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
tb = Traceback.get()
|
tb = Traceback.get()
|
||||||
res = XmlMarshaller().marshall(tb, objectType='appy')
|
res = XmlMarshaller().marshall(tb, objectType='appy')
|
||||||
|
@ -1378,9 +1385,24 @@ class BaseMixin:
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def index_html(self):
|
def index_html(self):
|
||||||
'''Redirects to /view.'''
|
'''Base method called when hitting this object.
|
||||||
|
- The standard behaviour is to redirect to /view.
|
||||||
|
- If a parameter named "do" is present in the request, it is supposed
|
||||||
|
to contain the name of a method to call on this object. In this
|
||||||
|
case, we call this method and return its result as XML.
|
||||||
|
- If method is POST, we consider the request to be XML data, that we
|
||||||
|
marshall to Python, and we call the method in param "do" with, as
|
||||||
|
arg, this marshalled Python object. While this could sound strange
|
||||||
|
to expect a query string containing a param "do" in a HTTP POST,
|
||||||
|
the HTTP spec does not prevent to do it.'''
|
||||||
rq = self.REQUEST
|
rq = self.REQUEST
|
||||||
if rq.has_key('do'):
|
if (rq.REQUEST_METHOD == 'POST') and rq.QUERY_STRING:
|
||||||
|
# A POST method containing XML data.
|
||||||
|
rq.args = XmlUnmarshaller().parse(rq.stdin.getvalue())
|
||||||
|
# Find the name of the method to call.
|
||||||
|
methodName = rq.QUERY_STRING.split('=')[1]
|
||||||
|
return self.xml(action=methodName)
|
||||||
|
elif rq.has_key('do'):
|
||||||
# The user wants to call a method on this object and get its result
|
# The user wants to call a method on this object and get its result
|
||||||
# as XML.
|
# as XML.
|
||||||
return self.xml(action=rq['do'])
|
return self.xml(action=rq['do'])
|
||||||
|
|
|
@ -476,8 +476,9 @@ class AbstractWrapper(object):
|
||||||
<!-- Locked -->
|
<!-- Locked -->
|
||||||
<a if="editable and locked">
|
<a if="editable and locked">
|
||||||
<img style="cursor: help"
|
<img style="cursor: help"
|
||||||
var="lockDate=tool.formatDate(locked[1]);
|
var="lockDate=ztool.formatDate(locked[1]);
|
||||||
lockMap={'user':tool.getUserName(locked[0]),'date':lockDate};
|
lockMap={'user':ztool.getUserName(locked[0]), \
|
||||||
|
'date':lockDate};
|
||||||
lockMsg=_('page_locked', mapping=lockMap)"
|
lockMsg=_('page_locked', mapping=lockMap)"
|
||||||
src=":url('lockedBig')" title=":lockMsg"/></a>
|
src=":url('lockedBig')" title=":lockMsg"/></a>
|
||||||
</td>
|
</td>
|
||||||
|
|
Loading…
Reference in a new issue