From 86953a98292e2867e8b48694b03a4572f730382d Mon Sep 17 00:00:00 2001 From: Joseph Spiros Date: Thu, 26 Aug 2010 06:33:17 -0400 Subject: [PATCH] Implementation of basic conversion between Django forms and ExtJS forms. --- .../gilbert/media/gilbert/Gilbert.api.auth.js | 74 ++++++--------- contrib/gilbert/plugins.py | 91 ++++++++++++++++++- contrib/gilbert/sites.py | 39 ++++---- 3 files changed, 137 insertions(+), 67 deletions(-) diff --git a/contrib/gilbert/media/gilbert/Gilbert.api.auth.js b/contrib/gilbert/media/gilbert/Gilbert.api.auth.js index 877f4f5..dc6aa36 100644 --- a/contrib/gilbert/media/gilbert/Gilbert.api.auth.js +++ b/contrib/gilbert/media/gilbert/Gilbert.api.auth.js @@ -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', diff --git a/contrib/gilbert/plugins.py b/contrib/gilbert/plugins.py index 5760c9a..80ef1ab 100644 --- a/contrib/gilbert/plugins.py +++ b/contrib/gilbert/plugins.py @@ -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): diff --git a/contrib/gilbert/sites.py b/contrib/gilbert/sites.py index b3f0df2..064666b 100644 --- a/contrib/gilbert/sites.py +++ b/contrib/gilbert/sites.py @@ -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(('' % json.dumps(response))) return HttpResponse(json.dumps(response), content_type=('application/json; charset=%s' % settings.DEFAULT_CHARSET)) -- 2.20.1