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 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
|
# Copyright (c) 2005-2007
# Authors: KSS Project Contributors (see docs/CREDITS.txt)
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
# 02111-1307, USA.
'''\
Marshal objects
These build up the response and get marshalled to the client
in the defined format
'''
from xml.sax.saxutils import escape as xml_escape
from zope.interface import implements
from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile
from interfaces import IKSSCommands, IKSSCommand, IKSSParam, IKSSCommandView
from unicode_quirks import force_unicode
import zope.component
from parsers import XmlParser, HtmlParser
from pluginregistry import checkRegisteredCommand_old
from pluginregistry import checkRegisteredCommand, checkRegisteredSelector, \
KSSPluginError
class KSSCommands(list):
implements(IKSSCommands)
def addCommand(self, command_name, selector=None, **kw):
command = KSSCommand(command_name, selector=selector, **kw)
self.append(command)
return command
def render(self, request):
'''All methods must use this to return their command set
'''
adapter = zope.component.getMultiAdapter((self, request), IKSSCommandView)
return adapter.render()
class KSSParam:
implements(IKSSParam)
def __init__(self, name, content=''):
self.name = name
self.content = content
def force_content_unicode(self):
# Content must be str with ascii encoding, or unicode!
self.content = force_unicode(self.content)
def getName(self):
return self.name
def getContent(self):
return self.content
class KSSCommand:
implements(IKSSCommand)
def __init__(self, command_name, selector=None, **kw):
try:
checkRegisteredCommand_old(command_name)
except KSSPluginError:
# we expect this is not registered as command, anyway
# so check it as an action.
checkRegisteredCommand(command_name)
else:
# ok. XXX this will be deprecated
# All registerCommand commands are obsolete, by default
import warnings, textwrap
warnings.warn(textwrap.dedent('''\
The usage of the kss command "%s" is deprecated'''
% (command_name, )), DeprecationWarning, 2)
if selector is not None:
if isinstance(selector, basestring):
# the default selector - given just as a string
self.selector = selector
self.selectorType = ''
else:
checkRegisteredSelector(selector.type)
self.selector = selector.value
self.selectorType = selector.type
else:
self.selector = None
self.selectorType = None
self.name = command_name
self.params = []
# Add parameters passed in **kw
for key, value in kw.iteritems():
self.addParam(key, value)
# --
# Different parameter conversions
# --
# REMARK: with the jsonserver product present, you can
# just send complex data types directly with AddParam
def addParam(self, name, content=''):
# Check for the size of the content. Larger than 4K will give
# problems with Firefox (which splits text nodes). Therefore
# we give this special treatment.
if len(content) > 4096:
return self.addCdataParam(name, content)
else:
# Escape all XML characters
return self._addParam(name, content=xml_escape(content))
def _addParam(self, name, content=''):
'Add the param as is'
param = KSSParam(name, content)
self.params.append(param)
return param
#
# Some helpers
#
def addUnicodeParam(self, name, content=u''):
'Add the param as unicode'
self.addParam(name, content)
def addStringParam(self, name, content='', encoding='utf8'):
'Add the param as an encoded string, by default UTF-8'
content = unicode(content, encoding)
self.addUnicodeParam(name, content=content)
def addHtmlParam(self, name, content=''):
'Add the param as an HTML content.'
content = HtmlParser(content)().encode('ascii', 'xmlcharrefreplace')
##self.addParam(name, content=content)
# add html as cdata!
self.addCdataParam(name, content=content)
def addXmlParam(self, name, content=''):
'Add the param as XML content'
content = XmlParser(content)().encode('ascii', 'xmlcharrefreplace')
self._addParam(name, content=content)
def addCdataParam(self, name, content=''):
'Add the param as a CDATA node'
# Replace `>` part of `]]>` with the entity ref so it won't
# accidentally close the CDATA (required by the XML spec)
content = '<![CDATA[%s]]>' % content.replace(']]>', ']]>')
self._addParam(name, content=content)
# --
# Accessors, not sure if we need them
# --
def getName(self):
return self.name
def getSelector(self):
return self.selector
def getSelectorType(self):
return self.selectorType
def getParams(self):
return self.params
class CommandView(object):
'''View of a command.
The render method does actual marshalling
of the commands to be sent to the client.
'''
implements(IKSSCommandView)
def __init__(self, context, request):
self.context = context
self.request = request
# XXX From Zope2.9 we need this.
# Note: We don't use proper views for Five. As our context object
# is not even a proper Zope content. There would be a way to:
#
# - use ZopeTwoPageTemplateFile
# - and, make the object to be proper zope content.
#
# This would be two much ado for nothing, so we just use barefoot
# rendering but as a consequence no path expression, only python:
# is available from the page template.
if not hasattr(self.request, 'debug'):
self.request.debug = None
# Force parameters content to be unicode
for command in context:
for param in command.getParams():
param.force_content_unicode()
# XML output gets rendered via a page template
# XXX note: barefoot rendering, use python: only after zope2.9
# XXX we must have the content type set both here and below
_render = ViewPageTemplateFile('browser/kukitresponse.pt', content_type='text/xml;charset=utf-8')
def render(self):
result = self._render()
# Always output text/xml to make sure browsers but the data in the
# responseXML instead of responseText attribute of the
# XMLHttpRequestobject.
self.request.response.setHeader('Content-type', 'text/xml;charset=utf-8')
return result
|