--- a/web/views/basecontrollers.py Fri Dec 09 12:14:11 2011 +0100
+++ b/web/views/basecontrollers.py Fri Dec 16 12:30:12 2011 +0100
@@ -22,20 +22,21 @@
__docformat__ = "restructuredtext en"
_ = unicode
-from logilab.common.date import strptime
+from warnings import warn
+
from logilab.common.deprecation import deprecated
from cubicweb import (NoSelectableObject, ObjectNotFound, ValidationError,
AuthenticationError, typed_eid)
-from cubicweb.utils import UStringIO, json, json_dumps
-from cubicweb.uilib import exc_message
-from cubicweb.selectors import authenticated_user, anonymous_user, match_form_params
-from cubicweb.mail import format_mail
-from cubicweb.web import Redirect, RemoteCallFailed, DirectResponse, facet
+from cubicweb.utils import json_dumps
+from cubicweb.selectors import (authenticated_user, anonymous_user,
+ match_form_params)
+from cubicweb.web import Redirect, RemoteCallFailed
from cubicweb.web.controller import Controller
-from cubicweb.web.views import vid_from_rset, formrenderers
+from cubicweb.web.views import vid_from_rset
+@deprecated('jsonize is deprecated, use AjaxFunction appobjects instead')
def jsonize(func):
"""decorator to sets correct content_type and calls `json_dumps` on
results
@@ -46,6 +47,7 @@
wrapper.__name__ = func.__name__
return wrapper
+@deprecated('xhtmlize is deprecated, use AjaxFunction appobjects instead')
def xhtmlize(func):
"""decorator to sets correct content_type and calls `xmlize` on results"""
def wrapper(self, *args, **kwargs):
@@ -56,6 +58,7 @@
wrapper.__name__ = func.__name__
return wrapper
+@deprecated('check_pageid is deprecated, use AjaxFunction appobjects instead')
def check_pageid(func):
"""decorator which checks the given pageid is found in the
user's session data
@@ -234,7 +237,7 @@
</script>""" % (domid, callback, errback, jsargs, cbargs)
def publish(self, rset=None):
- self._cw.json_request = True
+ self._cw.ajax_request = True
# XXX unclear why we have a separated controller here vs
# js_validate_form on the json controller
status, args, entity = _validate_form(self._cw, self._cw.vreg)
@@ -242,339 +245,18 @@
self._cw.encoding)
return self.response(domid, status, args, entity)
-def optional_kwargs(extraargs):
- if extraargs is None:
- return {}
- # we receive unicode keys which is not supported by the **syntax
- return dict((str(key), value) for key, value in extraargs.iteritems())
-
class JSonController(Controller):
__regid__ = 'json'
def publish(self, rset=None):
- """call js_* methods. Expected form keys:
-
- :fname: the method name without the js_ prefix
- :args: arguments list (json)
-
- note: it's the responsability of js_* methods to set the correct
- response content type
- """
- self._cw.json_request = True
- try:
- fname = self._cw.form['fname']
- func = getattr(self, 'js_%s' % fname)
- except KeyError:
- raise RemoteCallFailed('no method specified')
- except AttributeError:
- raise RemoteCallFailed('no %s method' % fname)
- # no <arg> attribute means the callback takes no argument
- args = self._cw.form.get('arg', ())
- if not isinstance(args, (list, tuple)):
- args = (args,)
- try:
- args = [json.loads(arg) for arg in args]
- except ValueError, exc:
- self.exception('error while decoding json arguments for js_%s: %s (err: %s)',
- fname, args, exc)
- raise RemoteCallFailed(exc_message(exc, self._cw.encoding))
- try:
- result = func(*args)
- except (RemoteCallFailed, DirectResponse):
- raise
- except Exception, exc:
- self.exception('an exception occurred while calling js_%s(%s): %s',
- fname, args, exc)
- raise RemoteCallFailed(exc_message(exc, self._cw.encoding))
- if result is None:
- return ''
- # get unicode on @htmlize methods, encoded string on @jsonize methods
- elif isinstance(result, unicode):
- return result.encode(self._cw.encoding)
- return result
-
- def _rebuild_posted_form(self, names, values, action=None):
- form = {}
- for name, value in zip(names, values):
- # remove possible __action_xxx inputs
- if name.startswith('__action'):
- if action is None:
- # strip '__action_' to get the actual action name
- action = name[9:]
- continue
- # form.setdefault(name, []).append(value)
- if name in form:
- curvalue = form[name]
- if isinstance(curvalue, list):
- curvalue.append(value)
- else:
- form[name] = [curvalue, value]
- else:
- form[name] = value
- # simulate click on __action_%s button to help the controller
- if action:
- form['__action_%s' % action] = u'whatever'
- return form
-
- def _exec(self, rql, args=None, rocheck=True):
- """json mode: execute RQL and return resultset as json"""
- rql = rql.strip()
- if rql.startswith('rql:'):
- rql = rql[4:]
- if rocheck:
- self._cw.ensure_ro_rql(rql)
- try:
- return self._cw.execute(rql, args)
- except Exception, ex:
- self.exception("error in _exec(rql=%s): %s", rql, ex)
- return None
- return None
-
- def _call_view(self, view, paginate=False, **kwargs):
- divid = self._cw.form.get('divid')
- # we need to call pagination before with the stream set
- try:
- stream = view.set_stream()
- except AttributeError:
- stream = UStringIO()
- kwargs['w'] = stream.write
- assert not paginate
- if divid == 'pageContent':
- # ensure divid isn't reused by the view (e.g. table view)
- del self._cw.form['divid']
- # mimick main template behaviour
- stream.write(u'<div id="pageContent">')
- vtitle = self._cw.form.get('vtitle')
- if vtitle:
- stream.write(u'<h1 class="vtitle">%s</h1>\n' % vtitle)
- paginate = True
- nav_html = UStringIO()
- if paginate and not view.handle_pagination:
- view.paginate(w=nav_html.write)
- stream.write(nav_html.getvalue())
- if divid == 'pageContent':
- stream.write(u'<div id="contentmain">')
- view.render(**kwargs)
- extresources = self._cw.html_headers.getvalue(skiphead=True)
- if extresources:
- stream.write(u'<div class="ajaxHtmlHead">\n') # XXX use a widget ?
- stream.write(extresources)
- stream.write(u'</div>\n')
- if divid == 'pageContent':
- stream.write(u'</div>%s</div>' % nav_html.getvalue())
- return stream.getvalue()
-
- @xhtmlize
- def js_view(self):
- # XXX try to use the page-content template
- req = self._cw
- rql = req.form.get('rql')
- if rql:
- rset = self._exec(rql)
- elif 'eid' in req.form:
- rset = self._cw.eid_rset(req.form['eid'])
- else:
- rset = None
- vid = req.form.get('vid') or vid_from_rset(req, rset, self._cw.vreg.schema)
- try:
- view = self._cw.vreg['views'].select(vid, req, rset=rset)
- except NoSelectableObject:
- vid = req.form.get('fallbackvid', 'noresult')
- view = self._cw.vreg['views'].select(vid, req, rset=rset)
- self.validate_cache(view)
- return self._call_view(view, paginate=req.form.pop('paginate', False))
-
- @xhtmlize
- def js_prop_widget(self, propkey, varname, tabindex=None):
- """specific method for CWProperty handling"""
- entity = self._cw.vreg['etypes'].etype_class('CWProperty')(self._cw)
- entity.eid = varname
- entity['pkey'] = propkey
- form = self._cw.vreg['forms'].select('edition', self._cw, entity=entity)
- form.build_context()
- vfield = form.field_by_name('value')
- renderer = formrenderers.FormRenderer(self._cw)
- return vfield.render(form, renderer, tabindex=tabindex) \
- + renderer.render_help(form, vfield)
-
- @xhtmlize
- def js_component(self, compid, rql, registry='components', extraargs=None):
- if rql:
- rset = self._exec(rql)
- else:
- rset = None
- # XXX while it sounds good, addition of the try/except below cause pb:
- # when filtering using facets return an empty rset, the edition box
- # isn't anymore selectable, as expected. The pb is that with the
- # try/except below, we see a "an error occurred" message in the ui, while
- # we don't see it without it. Proper fix would probably be to deal with
- # this by allowing facet handling code to tell to js_component that such
- # error is expected and should'nt be reported.
- #try:
- comp = self._cw.vreg[registry].select(compid, self._cw, rset=rset,
- **optional_kwargs(extraargs))
- #except NoSelectableObject:
- # raise RemoteCallFailed('unselectable')
- return self._call_view(comp, **optional_kwargs(extraargs))
-
- @xhtmlize
- def js_render(self, registry, oid, eid=None,
- selectargs=None, renderargs=None):
- if eid is not None:
- rset = self._cw.eid_rset(eid)
- # XXX set row=0
- elif self._cw.form.get('rql'):
- rset = self._cw.execute(self._cw.form['rql'])
- else:
- rset = None
- view = self._cw.vreg[registry].select(oid, self._cw, rset=rset,
- **optional_kwargs(selectargs))
- return self._call_view(view, **optional_kwargs(renderargs))
-
- @check_pageid
- @xhtmlize
- def js_inline_creation_form(self, peid, petype, ttype, rtype, role, i18nctx):
- view = self._cw.vreg['views'].select('inline-creation', self._cw,
- etype=ttype, rtype=rtype, role=role,
- peid=peid, petype=petype)
- return self._call_view(view, i18nctx=i18nctx)
-
- @jsonize
- def js_validate_form(self, action, names, values):
- return self.validate_form(action, names, values)
-
- def validate_form(self, action, names, values):
- self._cw.form = self._rebuild_posted_form(names, values, action)
- return _validate_form(self._cw, self._cw.vreg)
-
- @xhtmlize
- def js_reledit_form(self):
- req = self._cw
- args = dict((x, req.form[x])
- for x in ('formid', 'rtype', 'role', 'reload', 'action'))
- rset = req.eid_rset(typed_eid(self._cw.form['eid']))
- try:
- args['reload'] = json.loads(args['reload'])
- except ValueError: # not true/false, an absolute url
- assert args['reload'].startswith('http')
- view = req.vreg['views'].select('reledit', req, rset=rset, rtype=args['rtype'])
- return self._call_view(view, **args)
-
- @jsonize
- def js_i18n(self, msgids):
- """returns the translation of `msgid`"""
- return [self._cw._(msgid) for msgid in msgids]
-
- @jsonize
- def js_format_date(self, strdate):
- """returns the formatted date for `msgid`"""
- date = strptime(strdate, '%Y-%m-%d %H:%M:%S')
- return self._cw.format_date(date)
-
- @jsonize
- def js_external_resource(self, resource):
- """returns the URL of the external resource named `resource`"""
- return self._cw.uiprops[resource]
-
- @check_pageid
- @jsonize
- def js_user_callback(self, cbname):
- page_data = self._cw.session.data.get(self._cw.pageid, {})
- try:
- cb = page_data[cbname]
- except KeyError:
- return None
- return cb(self._cw)
-
- @jsonize
- def js_filter_build_rql(self, names, values):
- form = self._rebuild_posted_form(names, values)
- self._cw.form = form
- builder = facet.FilterRQLBuilder(self._cw)
- return builder.build_rql()
-
- @jsonize
- def js_filter_select_content(self, facetids, rql, mainvar):
- # Union unsupported yet
- select = self._cw.vreg.parse(self._cw, rql).children[0]
- filtered_variable = facet.get_filtered_variable(select, mainvar)
- facet.prepare_select(select, filtered_variable)
- update_map = {}
- for fid in facetids:
- fobj = facet.get_facet(self._cw, fid, select, filtered_variable)
- update_map[fid] = fobj.possible_values()
- return update_map
-
- def js_unregister_user_callback(self, cbname):
- self._cw.unregister_callback(self._cw.pageid, cbname)
-
- def js_unload_page_data(self):
- self._cw.session.data.pop(self._cw.pageid, None)
-
- def js_cancel_edition(self, errorurl):
- """cancelling edition from javascript
-
- We need to clear associated req's data :
- - errorurl
- - pending insertions / deletions
- """
- self._cw.cancel_edition(errorurl)
-
- def js_delete_bookmark(self, beid):
- rql = 'DELETE B bookmarked_by U WHERE B eid %(b)s, U eid %(u)s'
- self._cw.execute(rql, {'b': typed_eid(beid), 'u' : self._cw.user.eid})
-
- def js_node_clicked(self, treeid, nodeeid):
- """add/remove eid in treestate cookie"""
- from cubicweb.web.views.treeview import treecookiename
- cookies = self._cw.get_cookie()
- statename = treecookiename(treeid)
- treestate = cookies.get(statename)
- if treestate is None:
- self._cw.set_cookie(statename, nodeeid)
- else:
- marked = set(filter(None, treestate.value.split(':')))
- if nodeeid in marked:
- marked.remove(nodeeid)
- else:
- marked.add(nodeeid)
- self._cw.set_cookie(statename, ':'.join(marked))
-
- @jsonize
- @deprecated("[3.13] use jQuery.cookie(cookiename, cookievalue, {path: '/'}) in js land instead")
- def js_set_cookie(self, cookiename, cookievalue):
- cookiename, cookievalue = str(cookiename), str(cookievalue)
- self._cw.set_cookie(cookiename, cookievalue)
-
- # relations edition stuff ##################################################
-
- def _add_pending(self, eidfrom, rel, eidto, kind):
- key = 'pending_%s' % kind
- pendings = self._cw.session.data.setdefault(key, set())
- pendings.add( (typed_eid(eidfrom), rel, typed_eid(eidto)) )
-
- def _remove_pending(self, eidfrom, rel, eidto, kind):
- key = 'pending_%s' % kind
- pendings = self._cw.session.data[key]
- pendings.remove( (typed_eid(eidfrom), rel, typed_eid(eidto)) )
-
- def js_remove_pending_insert(self, (eidfrom, rel, eidto)):
- self._remove_pending(eidfrom, rel, eidto, 'insert')
-
- def js_add_pending_inserts(self, tripletlist):
- for eidfrom, rel, eidto in tripletlist:
- self._add_pending(eidfrom, rel, eidto, 'insert')
-
- def js_remove_pending_delete(self, (eidfrom, rel, eidto)):
- self._remove_pending(eidfrom, rel, eidto, 'delete')
-
- def js_add_pending_delete(self, (eidfrom, rel, eidto)):
- self._add_pending(eidfrom, rel, eidto, 'delete')
+ warn('[3.15] JSONController is deprecated, use AjaxController instead',
+ DeprecationWarning)
+ ajax_controller = self._cw.vreg['controllers'].select('ajax', self._cw, appli=self.appli)
+ return ajax_controller.publish(rset)
# XXX move to massmailing
-
class MailBugReportController(Controller):
__regid__ = 'reportbug'
__select__ = match_form_params('description')