Package Products :: Package ZenUtils :: Module Ext |
[hide private]
[frames] | no frames]

# Source Code for Module Products.ZenUtils.Ext

      1  ###########################################################################
      2  #
      3  # This program is part of Zenoss Core, an open source monitoring platform.
      4  # Copyright (C) 2007, Zenoss Inc.
      5  #
      6  # This program is free software; you can redistribute it and/or modify it
      7  # under the terms of the GNU General Public License version 2 as published by
      8  # the Free Software Foundation.
      9  #
     10  # For complete information please visit: http://www.zenoss.com/oss/
     11  #
     12  ###########################################################################
     13
     14  # Functions to simplify form submission return values.
     15
     16  import transaction
     17
     18  from Products.ZenUtils.json import json, unjson
     19  from Products.ZenUI3.utils.javascript import JavaScriptSnippet
     20  from Products.Five.browser import BrowserView
     21
     22
     23 -class FormResponse(object):
     24      """
     25      Builds a response for an Ext form.
     26      """
     27      _errors = None
     28      _redirect = None
     29
     30 -    def has_errors(self):
     31          return bool(self._errors)
     32
     33 -    def redirect(self, url):
     34          self._redirect = url
     35
     36 -    def error(self, field_name, error_text):
     37          if self._errors is None:
     38              self._errors = {}
     39          self._errors[field_name] = error_text
     40
     41      @json
     42 -    def get_response(self):
     43          return {
     44              'success':  not self.has_errors(),
     45              'redirect': self._redirect,
     46              'errors':   self._errors or {}
     47          }
     48
     49
     50 -def form_action(f):
     51      """
     52      Decorator for methods that are the targets of Ext form submission.
     53
     54      Provides transaction rollback, so methods can be used as their own
     55      validation without harm.
     56      """
     57      def inner(*args, **kwargs):
     58          savepoint = transaction.savepoint()
     59          result = f(*args, **kwargs)
     60          if isinstance(result, FormResponse):
     61              if result.has_errors():
     62                  savepoint.rollback()
     63              return result.get_response()
     64          return result
     65      return inner
     66
     67
     68 -class DirectRouter(BrowserView):
     69      """
     70      Base class for Ext.Direct routers.
     71
     72      Ext.Direct allows one to create an API that communicates with a single URL,
     73      which then routes requests to the appropriate method. The client-side API
     74      object matches the server-side API object.
     75
     76      This base class parses an Ext.Direct request, which contains the name of
     77      the method and any data that should be passed, and routes the data to the
     78      approriate method. It then receives the output of that call and puts it
     79      into the data structure expected by Ext.Direct.
     80
     81      @rtype JSON
     82      """
     83      _asof = None
     84
     85 -    def _set_asof(self, asof):
     86          self._asof = asof
     87
     88 -    def __call__(self):
     89          body = self.request.get('BODY')
     90          self.data = unjson(body)
     91          method = self.data['method']
     92          data = self.data['data']
     93          if 'asof' in self.data:
     94              self._set_asof(self.data['asof'])
     95          if not data:
     96              data = {}
     97          else:
     98              data = data[0]
     99
    100          # Cast all keys as strings in case of unicode problems
    101          data = dict((str(k), v) for k,v in data.items())
    102
    103          # Call the specified method
    104          result = getattr(self, method)(**data)
    105
    106          self.request.response.setHeader('Content-Type', 'application/json')
    107          return json({
    108              'type':'rpc',
    109              'tid': self.data['tid'],
    110              'action':self.data['action'],
    111              'method':self.data['method'],
    112              'result': result,
    113              'asof': self._asof
    114          })
    115
    116
    117 -class DirectProviderDefinition(JavaScriptSnippet):
    118      """
    119      Turns a L{DirectRouter} subclass into JavaScript object representing the
    120      config of the client-side API.
    121
    122      Inspects the given subclass and retrieves the names of all public methods,
    123      then defines those as actions on the Ext.Direct provider, and creates the
    124      JS that adds the provider.
    125
    126      As this is a JavaScriptSnippet, the resulting code will be included in the
    127      rendered template if the snippet is registered as a viewlet in ZCML and the
    128      appropriate provider is referenced in the template.
    129
    130      See http://extjs.com/products/extjs/direct.php for a full explanation of
    131      protocols and features of Ext.Direct.
    132      """
    133      _router = None
    134      _url = None
    135 -    def snippet(self):
    136          attrs = [a for a in self._router.__dict__.keys() if not a.startswith('_')]
    137          methodtpl = '{name:"%s", len:1}'
    138          methods = ",".join([methodtpl % a for a in attrs])
    139          return """
    140          Ext.onReady(function(){
    141              Ext.Direct.addProvider(
    142                    {
    143                        type: 'remoting',
    144                        url: '%(url)s',
    145                        actions: {
    146                            "%(clsname)s":[
    147                              %(methods)s
    148                            ]
    149                        },
    150                        namespace: 'Zenoss.remote'
    151                    }
    152                );
    153          });
    154          """ % dict(url=self._url, clsname=self._router.__name__, methods=methods)
    155