Implementation of basic conversion between Django forms and ExtJS forms.
authorJoseph Spiros <joseph.spiros@ithinksw.com>
Thu, 26 Aug 2010 10:33:17 +0000 (06:33 -0400)
committerJoseph Spiros <joseph.spiros@ithinksw.com>
Thu, 26 Aug 2010 10:33:17 +0000 (06:33 -0400)
contrib/gilbert/media/gilbert/Gilbert.api.auth.js
contrib/gilbert/plugins.py
contrib/gilbert/sites.py

index 877f4f5..dc6aa36 100644 (file)
@@ -25,54 +25,36 @@ GILBERT_PLUGINS.push(new (function() {
                                                text: 'Change password',
                                                iconCls: 'key--pencil',
                                                handler: function(button, event) {
-                                                       var change_password_window = application.createWindow({
-                                                               layout: 'fit',
-                                                               resizable: false,
-                                                               title: 'Change password',
-                                                               iconCls: 'key--pencil',
-                                                               width: 266,
-                                                               height: 170,
-                                                               items: change_password_form = new Ext.FormPanel({
-                                                                       frame: true,
-                                                                       bodyStyle: 'padding: 5px 5px 0',
-                                                                       items: [{
-                                                                               fieldLabel: 'Current password',
-                                                                               name: 'current_password',
-                                                                               xtype: 'textfield',
-                                                                               inputType: 'password',
-                                                                       },{
-                                                                               fieldLabel: 'New password',
-                                                                               name: 'new_password',
-                                                                               xtype: 'textfield',
-                                                                               inputType: 'password',
-                                                                       },{
-                                                                               fieldLabel: 'New password (confirm)',
-                                                                               name: 'new_password_confirm',
-                                                                               xtype: 'textfield',
-                                                                               inputType: 'password',
-                                                                       }],
-                                                                       buttons: [{
-                                                                               text: 'Change password',
-                                                                               iconCls: 'key--pencil',
-                                                                               handler: function(button, event) {
-                                                                                       var the_form = change_password_form.getForm().el.dom;
-                                                                                       var current_password = the_form[0].value;
-                                                                                       var new_password = the_form[1].value;
-                                                                                       var new_password_confirm = the_form[2].value;
-                                                                                       Gilbert.api.auth.passwd(current_password, new_password, new_password_confirm, function(result) {
-                                                                                               if (result) {
-                                                                                                       Ext.MessageBox.alert('Password changed', 'Your password has been changed.');
-                                                                                               } else {
-                                                                                                       Ext.MessageBox.alert('Password unchanged', 'Unable to change your password.', function() {
-                                                                                                               change_password_form.getForm().reset();
-                                                                                                       });
-                                                                                               }
-                                                                                       });
+                                                       Gilbert.api.auth.get_passwd_form(function(formspec) {
+                                                               var change_password_window = application.createWindow({
+                                                                       layout: 'fit',
+                                                                       resizable: false,
+                                                                       title: 'Change password',
+                                                                       iconCls: 'key--pencil',
+                                                                       width: 266,
+                                                                       height: 170,
+                                                                       items: change_password_form = new Ext.FormPanel(Ext.applyIf({
+                                                                               frame: true,
+                                                                               bodyStyle: 'padding: 5px 5px 0',
+                                                                               buttons: [{
+                                                                                       text: 'Change password',
+                                                                                       iconCls: 'key--pencil',
+                                                                                       handler: function(button, event) {
+                                                                                               change_password_form.getForm().submit({
+                                                                                                       success: function(form, action) {
+                                                                                                               Ext.MessageBox.alert('Password changed', 'Your password has been changed.');
+                                                                                                       },
+                                                                                               });
+                                                                                       },
+                                                                               }],
+                                                                               api: {
+                                                                                       submit: Gilbert.api.auth.submit_passwd_form,
                                                                                },
-                                                                       }],
-                                                               })
+                                                                       }, formspec))
+                                                               });
+                                                               change_password_window.show();
                                                        });
-                                                       change_password_window.show();
+                                                       
                                                },
                                        },{
                                                text: 'Log out',
index 5760c9a..80ef1ab 100644 (file)
@@ -1,14 +1,97 @@
 from inspect import isclass, getargspec
+from functools import wraps
+from django.utils.encoding import force_unicode
+from django.forms.widgets import Widget, Input, HiddenInput, FileInput, DateInput, TimeInput, Textarea, CheckboxInput, Select, SelectMultiple
+from django.forms.fields import FileField
+from django.forms.forms import BaseForm
+
+
+def _render_ext(self, name, value):
+       ext_spec = {'name': name}
+       if value is not None:
+               ext_spec['value'] = value
+       if isinstance(self, Input):
+               if isinstance(self, HiddenInput):
+                       ext_spec['xtype'] = 'hidden'
+               elif isinstance(self, FileInput):
+                       ext_spec['xtype'] = 'fileuploadfield'
+               elif isinstance(self, DateInput):
+                       ext_spec['xtype'] = 'datefield'
+               elif isinstance(self, TimeInput):
+                       ext_spec['xtype'] = 'timefield'
+               else:
+                       ext_spec['xtype'] = 'textfield'
+                       ext_spec['inputType'] = self.input_type
+       elif isinstance(self, Textarea):
+               ext_spec['xtype'] = 'textarea'
+       elif isinstance(self, CheckboxInput):
+               ext_spec['xtype'] = 'checkbox'
+       elif isinstance(self, Select):
+               ext_spec['xtype'] = 'combo'
+               ext_spec['store'] = self.choices
+               ext_spec['typeAhead'] = True
+               if isinstance(self, SelectMultiple):
+                       pass
+       if ext_spec:
+               return ext_spec
+       return None
+
+
+Widget.render_ext = _render_ext
+
+
+def _as_ext(self):
+       ext_spec = {}
+       
+       fields = []
+       for bf in self:
+               if bf.label:
+                       label = force_unicode(bf.label)
+               else:
+                       label = ''
+               
+               if bf.field.show_hidden_initial:
+                       only_initial = True
+               else:
+                       only_initial = False
+               
+               widget = bf.field.widget
+               
+               if not self.is_bound:
+                       data = self.initial.get(bf.name, bf.field.initial)
+                       if callable(data):
+                               data = data()
+               else:
+                       if isinstance(bf.field, FileField) and bf.data is None:
+                               data = self.initial.get(bf.name, bf.field.initial)
+                       else:
+                               data = bf.data
+               if not only_initial:
+                       name = bf.html_name
+               else:
+                       name = bf.html_initial_name
+               
+               rendered = widget.render_ext(name, data)
+               if rendered is not None:
+                       rendered['fieldLabel'] = label
+                       fields.append(rendered)
+       ext_spec['items'] = fields
+       ext_spec['labelSeparator'] = self.label_suffix
+       return ext_spec
+
+
+BaseForm.as_ext = _as_ext
 
 
 def is_gilbert_method(function):
        return getattr(function, 'gilbert_method', False)
 
 
-def gilbert_method(function=None, name=None, argc=None, restricted=True):
-       def wrapper(function):
+def gilbert_method(function=None, name=None, argc=None, form_handler=False, restricted=True):
+       def setter(function):
                setattr(function, 'gilbert_method', True)
                setattr(function, 'name', name or function.__name__)
+               setattr(function, 'form_handler', form_handler)
                setattr(function, 'restricted', restricted)
                new_argc = argc
                if new_argc is None:
@@ -25,8 +108,8 @@ def gilbert_method(function=None, name=None, argc=None, restricted=True):
                setattr(function, 'argc', new_argc)
                return function
        if function is not None:
-               return wrapper(function)
-       return wrapper
+               return setter(function)
+       return setter
 
 
 class GilbertPluginBase(type):
index b3f0df2..064666b 100644 (file)
@@ -49,13 +49,19 @@ class GilbertAuthPlugin(GilbertPlugin):
                return True
        
        @gilbert_method
-       def passwd(self, request, current_password, new_password, new_password_confirm):
-               user = request.user
-               if user.check_password(current_password) and (new_password == new_password_confirm):
-                       user.set_password(new_password)
-                       user.save()
-                       return True
-               return False
+       def get_passwd_form(self, request):
+               from django.contrib.auth.forms import PasswordChangeForm
+               return PasswordChangeForm(request.user).as_ext()
+       
+       @gilbert_method(form_handler=True)
+       def submit_passwd_form(self, request):
+               from django.contrib.auth.forms import PasswordChangeForm
+               form = PasswordChangeForm(request.user, data=request.POST)
+               if form.is_valid():
+                       form.save()
+                       return {'success': True}
+               else:
+                       return {'success': False, 'errors': form.errors}
        
        @gilbert_method
        def whoami(self, request):
@@ -149,6 +155,7 @@ class GilbertSite(object):
                                        model_methods.append({
                                                'name': method.name,
                                                'len': method.argc,
+                                               'formHandler': method.form_handler,
                                        })
                                if model_methods:
                                        model_actions[model_name] = model_methods
@@ -170,6 +177,7 @@ class GilbertSite(object):
                                plugin_methods.append({
                                        'name': method.name,
                                        'len': method.argc,
+                                       'formHandler': method.form_handler,
                                })
                        if plugin_methods:
                                plugin_actions[plugin_name] = plugin_methods
@@ -185,20 +193,17 @@ class GilbertSite(object):
                        submitted_form = True
                
                if submitted_form:
-                       post_dict = dict(request.POST)
                        ext_request = {
-                               'action': post_dict.pop('extAction'),
-                               'method': post_dict.pop('extMethod'),
-                               'type': post_dict.pop('extType'),
-                               'tid': post_dict.pop('extTID'),
-                               'upload': post_dict.pop('extUpload', False),
+                               'action': request.POST.get('extAction'),
+                               'method': request.POST.get('extMethod'),
+                               'type': request.POST.get('extType'),
+                               'tid': request.POST.get('extTID'),
+                               'upload': request.POST.get('extUpload', False),
                                'data': None,
-                               'kwdata': post_dict
                        }
                else:
                        ext_request = json.loads(request.raw_post_data)
                        ext_request['upload'] = False
-                       ext_request['kwdata'] = None
                
                try:
                        plugin = None
@@ -219,12 +224,12 @@ class GilbertSite(object):
                        if method is None or (method.restricted and not self.has_permission(request)):
                                raise NotImplementedError('The method named \'%s\' is not available' % method.name)
                        
-                       response = {'type': 'rpc', 'tid': ext_request['tid'], 'action': ext_request['action'], 'method': ext_request['method'], 'result': method(request, *(ext_request['data'] or []), **(ext_request['kwdata'] or {}))}
+                       response = {'type': 'rpc', 'tid': ext_request['tid'], 'action': ext_request['action'], 'method': ext_request['method'], 'result': method(request, *(ext_request['data'] or []))}
                except:
                        exc_type, exc_value, exc_traceback = sys.exc_info()
                        response = {'type': 'exception', 'tid': ext_request['tid'], 'message': ('%s: %s' % (exc_type, exc_value)), 'where': format_tb(exc_traceback)[0]}
                
-               if submitted_form:
+               if submitted_form and ext_request['upload'] is True:
                        return HttpResponse(('<html><body><textarea>%s</textarea></body></html>' % json.dumps(response)))
                return HttpResponse(json.dumps(response), content_type=('application/json; charset=%s' % settings.DEFAULT_CHARSET))