web/views/basecontrollers.py
changeset 8128 0a927fe4541b
parent 8116 6510654269a6
child 8162 d5b02af28125
--- 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')