From: Joseph Spiros Date: Mon, 23 Aug 2010 14:55:49 +0000 (-0400) Subject: Cleanup of Gilbert plugins API and JavaScript. X-Git-Url: http://git.ithinksw.org/philo.git/commitdiff_plain/28f5fd6ebf7094bf3566b41461f4782e96483bfb Cleanup of Gilbert plugins API and JavaScript. --- diff --git a/contrib/gilbert/__init__.py b/contrib/gilbert/__init__.py index d009571..c55f250 100644 --- a/contrib/gilbert/__init__.py +++ b/contrib/gilbert/__init__.py @@ -1,3 +1,6 @@ +__version__ = 'alpha' + + from philo.contrib.gilbert.sites import GilbertSite, site diff --git a/contrib/gilbert/media/gilbert/Gilbert.api.auth.js b/contrib/gilbert/media/gilbert/Gilbert.api.auth.js new file mode 100644 index 0000000..877f4f5 --- /dev/null +++ b/contrib/gilbert/media/gilbert/Gilbert.api.auth.js @@ -0,0 +1,146 @@ +GILBERT_PLUGINS.push(new (function() { + return { + init: function(application) { + if (GILBERT_LOGGED_IN) { + application.on('ready', this.addUserMenu, this, { + single: true, + }); + } else { + application.on('ready', this.showLoginWindow, this, { + single: true, + }); + } + }, + addUserMenu: function(application) { + Gilbert.api.auth.whoami(function(result) { + application.mainmenu.add({ + xtype: 'tbfill', + },{ + xtype: 'tbseparator', + },{ + xtype: 'button', + iconCls: 'user-silhouette', + text: '' + result + '', + menu: [{ + 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(); + }); + } + }); + }, + }], + }) + }); + change_password_window.show(); + }, + },{ + text: 'Log out', + iconCls: 'door-open-out', + handler: function(button, event) { + Gilbert.api.auth.logout(function(result) { + if (result) { + document.location.reload(); + } else { + Ext.MessageBox.alert('Log out failed', 'You have not been logged out. This could mean that your connection with the server has been severed. Please try again.'); + } + }) + } + }], + }); + application.doLayout(); + }); + }, + showLoginWindow: function(application) { + application.mainmenu.hide(); + application.doLayout(); + var login_window = application.createWindow({ + header: false, + closable: false, + resizable: false, + draggable: false, + width: 266, + height: 130, + layout: 'fit', + items: login_form = new Ext.FormPanel({ + frame: true, + bodyStyle: 'padding: 5px 5px 0', + items: [ + { + fieldLabel: 'Username', + name: 'username', + xtype: 'textfield', + }, + { + fieldLabel: 'Password', + name: 'password', + xtype: 'textfield', + inputType: 'password', + } + ], + buttons: [ + { + text: 'Log in', + iconCls: 'door-open-in', + handler: function(button, event) { + var the_form = login_form.getForm().el.dom; + var username = the_form[0].value; + var password = the_form[1].value; + Gilbert.api.auth.login(username, password, function(result) { + if (result) { + document.location.reload(); + } else { + Ext.MessageBox.alert('Log in failed', 'Unable to authenticate using the credentials provided. Please try again.', function() { + login_form.getForm().reset(); + }); + } + }); + } + } + ], + }), + }); + login_window.show(); + }, + } +})()); \ No newline at end of file diff --git a/contrib/gilbert/media/gilbert/Gilbert.lib.js b/contrib/gilbert/media/gilbert/Gilbert.lib.js new file mode 100644 index 0000000..02bdb7b --- /dev/null +++ b/contrib/gilbert/media/gilbert/Gilbert.lib.js @@ -0,0 +1,83 @@ +Ext.ns('Gilbert.lib'); + +Gilbert.lib.Desktop = Ext.extend(Ext.Panel, { + constructor: function(config) { + Gilbert.lib.Desktop.superclass.constructor.call(this, Ext.applyIf(config||{}, { + region: 'center', + border: false, + padding: '5', + bodyStyle: 'background: none;', + })); + }, +}); + +Gilbert.lib.MainMenu = Ext.extend(Ext.Toolbar, { + constructor: function(application) { + var application = this.application = application; + Gilbert.lib.MainMenu.superclass.constructor.call(this, { + region: 'north', + autoHeight: true, + }); + }, +}); + +Gilbert.lib.Application = Ext.extend(Ext.util.Observable, { + constructor: function(config) { + Ext.apply(this, config, { + renderTo: Ext.getBody(), + plugins: [], + + }); + Gilbert.lib.Application.superclass.constructor.call(this); + this.addEvents({ + 'ready': true, + }); + this.init(); + }, + init: function() { + Ext.QuickTips.init(); + + var desktop = this.desktop = new Gilbert.lib.Desktop(); + var mainmenu = this.mainmenu = new Gilbert.lib.MainMenu(this); + var viewport = this.viewport = new Ext.Viewport({ + renderTo: this.renderTo, + layout: 'border', + items: [ + this.mainmenu, + this.desktop, + ], + }); + var windows = this.windows = new Ext.WindowGroup(); + + if (this.plugins) { + if (Ext.isArray(this.plugins)) { + for (var i = 0; i < this.plugins.length; i++) { + this.plugins[i] = this.initPlugin(this.plugins[i]); + } + } else { + this.plugins = this.initPlugin(this.plugins); + } + } + + this.doLayout(); + + this.fireEvent('ready', this); + }, + initPlugin: function(plugin) { + plugin.init(this); + return plugin; + }, + createWindow: function(config, cls) { + var win = new(cls||Ext.Window)(Ext.applyIf(config||{},{ + renderTo: this.desktop.el, + manager: this.windows, + constrainHeader: true, + })); + win.render(this.desktop.el); + return win; + }, + doLayout: function() { + this.mainmenu.doLayout(); + this.viewport.doLayout(); + } +}); \ No newline at end of file diff --git a/contrib/gilbert/options.py b/contrib/gilbert/options.py deleted file mode 100644 index fbdd4e3..0000000 --- a/contrib/gilbert/options.py +++ /dev/null @@ -1,57 +0,0 @@ -from philo.contrib.gilbert.utils import gilbert_method, is_gilbert_method, is_gilbert_class - - -class GilbertClassBase(type): - def __new__(cls, name, bases, attrs): - if 'gilbert_class' not in attrs: - attrs['gilbert_class'] = True - if 'gilbert_class_name' not in attrs: - attrs['gilbert_class_name'] = name - if 'gilbert_class_methods' not in attrs: - gilbert_class_methods = {} - for attr in attrs.values(): - if is_gilbert_method(attr): - gilbert_class_methods[attr.gilbert_method_name] = attr - attrs['gilbert_class_methods'] = gilbert_class_methods - return super(GilbertClassBase, cls).__new__(cls, name, bases, attrs) - - -class GilbertClass(object): - __metaclass__ = GilbertClassBase - - -class GilbertPluginBase(type): - def __new__(cls, name, bases, attrs): - if 'gilbert_plugin' not in attrs: - attrs['gilbert_plugin'] = True - if 'gilbert_plugin_name' not in attrs: - attrs['gilbert_plugin_name'] = name - if 'gilbert_plugin_classes' not in attrs: - gilbert_plugin_classes = {} - for attr_name, attr in attrs.items(): - if is_gilbert_class(attr): - gilbert_plugin_classes[attr_name] = attr - attrs['gilbert_plugin_classes'] = gilbert_plugin_classes - return super(GilbertPluginBase, cls).__new__(cls, name, bases, attrs) - - -class GilbertPlugin(object): - __metaclass__ = GilbertPluginBase - - def __init__(self, site): - self.site = site - - -class GilbertModelAdmin(GilbertClass): - def __init__(self, site, model): - self.site = site - self.model = model - self.gilbert_class_name = model._meta.object_name - - @gilbert_method - def all(self): - return list(self.model._default_manager.all().values()) - - @gilbert_method - def get(self, constraint): - return self.model._default_manager.all().values().get(**constraint) \ No newline at end of file diff --git a/contrib/gilbert/plugins.py b/contrib/gilbert/plugins.py new file mode 100644 index 0000000..5760c9a --- /dev/null +++ b/contrib/gilbert/plugins.py @@ -0,0 +1,84 @@ +from inspect import isclass, getargspec + + +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): + setattr(function, 'gilbert_method', True) + setattr(function, 'name', name or function.__name__) + setattr(function, 'restricted', restricted) + new_argc = argc + if new_argc is None: + args = getargspec(function)[0] + new_argc = len(args) + if new_argc > 0: + if args[0] == 'self': + args = args[1:] + new_argc = new_argc - 1 + if new_argc > 0: + if args[0] == 'request': + args = args[1:] + new_argc = new_argc - 1 + setattr(function, 'argc', new_argc) + return function + if function is not None: + return wrapper(function) + return wrapper + + +class GilbertPluginBase(type): + def __new__(cls, name, bases, attrs): + if 'methods' not in attrs: + methods = [] + for attr in attrs.values(): + if is_gilbert_method(attr): + methods.append(attr.name) + attrs['methods'] = methods + return super(GilbertPluginBase, cls).__new__(cls, name, bases, attrs) + + +class GilbertPlugin(object): + __metaclass__ = GilbertPluginBase + + def __init__(self, site): + self.site = site + + def get_method(self, method_name): + method = getattr(self, method_name, None) + if not is_gilbert_method(method): + return None + return method + + @property + def urls(self): + return [] + + @property + def js(self): + return [] + + @property + def css(self): + return [] + + @property + def fugue_icons(self): + return [] + + +class GilbertModelAdmin(GilbertPlugin): + def __init__(self, site, model): + self.model = model + self.name = model._meta.object_name + super(GilbertModelAdmin, self).__init__(site) + + @gilbert_method + def all(self): + return list(self.model._default_manager.all().values()) + + @gilbert_method + def get(self, constraint): + return self.model._default_manager.all().values().get(**constraint) \ No newline at end of file diff --git a/contrib/gilbert/sites.py b/contrib/gilbert/sites.py index 76c1d9a..b3f0df2 100644 --- a/contrib/gilbert/sites.py +++ b/contrib/gilbert/sites.py @@ -1,6 +1,6 @@ from django.contrib.admin.sites import AdminSite from django.contrib.auth import authenticate, login, logout -from django.conf.urls.defaults import url, patterns +from django.conf.urls.defaults import url, patterns, include from django.core.urlresolvers import reverse from django.shortcuts import render_to_response from django.conf import settings @@ -9,60 +9,75 @@ from django.utils.datastructures import SortedDict from django.http import HttpResponse from django.db.models.base import ModelBase from philo.utils import fattr -from philo.contrib.gilbert.options import GilbertModelAdmin, GilbertPlugin, GilbertClass +from philo.contrib.gilbert.plugins import GilbertModelAdmin, GilbertPlugin, is_gilbert_method, gilbert_method from philo.contrib.gilbert.exceptions import AlreadyRegistered, NotRegistered from django.forms.models import model_to_dict import sys from traceback import format_tb from inspect import getargspec -from philo.contrib.gilbert.utils import is_gilbert_plugin, is_gilbert_class, is_gilbert_method, gilbert_method, call_gilbert_method - +from django.views.decorators.cache import never_cache +from philo.contrib.gilbert import __version__ as gilbert_version +import staticmedia +import os __all__ = ('GilbertSite', 'site') -class GilbertSitePlugin(GilbertPlugin): - class auth(GilbertClass): - @gilbert_method(restricted=False) - def login(self, request, username, password): - user = authenticate(username=username, password=password) - if user is not None and user.is_active: - login(request, user) - return True - else: - return False - - @gilbert_method(restricted=False) - def logout(self, request): - logout(request) +class GilbertAuthPlugin(GilbertPlugin): + name = 'auth' + + @property + def js(self): + return [staticmedia.url('gilbert/Gilbert.api.auth.js')] + + @property + def fugue_icons(self): + return ['user-silhouette', 'key--pencil', 'door-open-out', 'door-open-in'] + + @gilbert_method(restricted=False) + def login(self, request, username, password): + user = authenticate(username=username, password=password) + if user is not None and user.is_active: + login(request, user) 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 + else: return False + + @gilbert_method + def logout(self, request): + logout(request) + 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 + + @gilbert_method + def whoami(self, request): + user = request.user + return user.get_full_name() or user.username class GilbertSite(object): + version = gilbert_version + def __init__(self, namespace='gilbert', app_name='gilbert', title='Gilbert'): self.namespace = namespace self.app_name = app_name self.title = title - self.core_api = GilbertSitePlugin(self) self.model_registry = SortedDict() self.plugin_registry = SortedDict() + self.register_plugin(GilbertAuthPlugin) def register_plugin(self, plugin): - if is_gilbert_plugin(plugin): - if plugin.gilbert_plugin_name in self.plugin_registry: - raise AlreadyRegistered('A plugin named \'%s\' is already registered' % plugin.gilbert_plugin_name) - self.plugin_registry[plugin.gilbert_plugin_name] = plugin(self) - else: - raise ValueError('register_plugin must be provided a valid plugin class or instance') + if plugin.name in self.plugin_registry: + raise AlreadyRegistered('A plugin named \'%s\' is already registered' % plugin.name) + self.plugin_registry[plugin.name] = plugin(self) def register_model(self, model_or_iterable, admin_class=GilbertModelAdmin, **admin_attrs): if isinstance(model_or_iterable, ModelBase): @@ -71,7 +86,7 @@ class GilbertSite(object): if model._meta.app_label not in self.model_registry: self.model_registry[model._meta.app_label] = SortedDict() if model._meta.object_name in self.model_registry[model._meta.app_label]: - raise AlreadyRegistered('The model %s is already registered' % model.__name__) + raise AlreadyRegistered('The model %s.%s is already registered' % (model._meta.app_label, model.__name__)) if admin_attrs: admin_attrs['__module__'] = __name__ admin_class = type('%sAdmin' % model.__name__, (admin_class,), admin_attrs) @@ -82,15 +97,16 @@ class GilbertSite(object): @property def urls(self): - return (patterns('', + urlpatterns = patterns('', url(r'^$', self.index, name='index'), - url(r'^css.css$', self.css, name='css'), - url(r'^api.js$', self.api, name='api'), + url(r'^css$', self.css, name='css'), + url(r'^api$', self.api, name='api'), url(r'^router/?$', self.router, name='router'), - url(r'^models/(?P\w+)/?$', self.router, name='models'), - url(r'^plugins/(?P\w+)/?$', self.router, name='plugins'), + url(r'^router/models/(?P\w+)/?$', self.router, name='models'), url(r'^login$', self.router, name='login'), - ), self.app_name, self.namespace) + ) + + return (urlpatterns, self.app_name, self.namespace) def request_context(self, request, extra_context=None): from django.template import RequestContext @@ -99,16 +115,71 @@ class GilbertSite(object): context.update({'gilbert': self, 'user': request.user, 'logged_in': self.has_permission(request)}) return context + @never_cache def index(self, request, extra_context=None): return render_to_response('gilbert/index.html', context_instance=self.request_context(request, extra_context)) def css(self, request, extra_context=None): - return render_to_response('gilbert/css.css', context_instance=self.request_context(request, extra_context), mimetype='text/css') + icon_names = [] + for plugin in self.plugin_registry.values(): + icon_names.extend(plugin.fugue_icons) + + icons = dict([(icon_name, staticmedia.url('gilbert/fugue-icons/icons/%s.png' % icon_name)) for icon_name in set(icon_names)]) + + context = extra_context or {} + context.update({'icons': icons}) + + return render_to_response('gilbert/styles.css', context_instance=self.request_context(request, context), mimetype='text/css') + @never_cache def api(self, request, extra_context=None): - return render_to_response('gilbert/api.js', context_instance=self.request_context(request, extra_context), mimetype='text/javascript') + providers = [] + for app_label, models in self.model_registry.items(): + app_provider = { + 'namespace': 'Gilbert.api.models.%s' % app_label, + 'url': reverse('%s:models' % self.namespace, current_app=self.app_name, kwargs={'app_label': app_label}), + 'type': 'remoting', + } + model_actions = {} + for model_name, admin in models.items(): + model_methods = [] + for method in [admin.get_method(method_name) for method_name in admin.methods]: + if method.restricted and not self.has_permission(request): + continue + model_methods.append({ + 'name': method.name, + 'len': method.argc, + }) + if model_methods: + model_actions[model_name] = model_methods + if model_actions: + app_provider['actions'] = model_actions + providers.append(app_provider) + + plugin_provider = { + 'namespace': 'Gilbert.api', + 'url': reverse('%s:router' % self.namespace, current_app=self.app_name), + 'type': 'remoting', + } + plugin_actions = {} + for plugin_name, plugin in self.plugin_registry.items(): + plugin_methods = [] + for method in [plugin.get_method(method_name) for method_name in plugin.methods]: + if method.restricted and not self.has_permission(request): + continue + plugin_methods.append({ + 'name': method.name, + 'len': method.argc, + }) + if plugin_methods: + plugin_actions[plugin_name] = plugin_methods + if plugin_actions: + plugin_provider['actions'] = plugin_actions + providers.append(plugin_provider) + + return HttpResponse(''.join(['Ext.Direct.addProvider('+json.dumps(provider, separators=(',', ':'))+');' for provider in providers]), mimetype='text/javascript') - def router(self, request, app_label=None, plugin_name=None, extra_context=None): + def router(self, request, app_label=None, extra_context=None): submitted_form = False if request.META['CONTENT_TYPE'].startswith('application/x-www-form-urlencoded'): submitted_form = True @@ -120,45 +191,35 @@ class GilbertSite(object): 'method': post_dict.pop('extMethod'), 'type': post_dict.pop('extType'), 'tid': post_dict.pop('extTID'), + 'upload': post_dict.pop('extUpload', False), 'data': None, - 'kwdata': post_dict, + 'kwdata': post_dict } - if 'extUpload' in request.POST: - ext_request['upload'] = request.POST['extUpload'] else: ext_request = json.loads(request.raw_post_data) + ext_request['upload'] = False ext_request['kwdata'] = None try: - gilbert_class = None + plugin = None if app_label is not None: try: - gilbert_class = self.model_registry[app_label][ext_request['action']] + plugin = self.model_registry[app_label][ext_request['action']] except KeyError: raise NotImplementedError('A model named \'%s\' has not been registered' % ext_request['action']) - elif plugin_name is not None: - try: - gilbert_plugin = self.plugin_registry[plugin_name] - except KeyError: - raise NotImplementedError('A plugin named \'%s\' has not been registered' % plugin_name) - try: - gilbert_class = gilbert_plugin.gilbert_plugin_classes[ext_request['action']] - except KeyError: - raise NotImplementedError('The plugin named \'%s\' does not provide a class named \'%s\'' % (plugin_name, ext_request['action'])) else: try: - gilbert_class = self.core_api.gilbert_plugin_classes[ext_request['action']] + plugin = self.plugin_registry[ext_request['action']] except KeyError: raise NotImplementedError('Gilbert does not provide a class named \'%s\'' % ext_request['action']) - try: - method = gilbert_class.gilbert_class_methods[ext_request['method']] - except KeyError: - raise NotImplementedError('The class named \'%s\' does not implement a method named \'%\'' % (gilbert_class.gilbert_class_name, ext_request['method'])) - if method.gilbert_method_restricted and not self.has_permission(request): - raise NotImplementedError('The method named \'%s\' is not available' % method.gilbert_method_name) - response = {'type': 'rpc', 'tid': ext_request['tid'], 'action': ext_request['action'], 'method': ext_request['method'], 'result': call_gilbert_method(method, gilbert_class, request, *(ext_request['data'] or []), **(ext_request['kwdata'] or {}))} + method = plugin.get_method(ext_request['method']) + + 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 {}))} 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]} diff --git a/contrib/gilbert/templates/gilbert/api.js b/contrib/gilbert/templates/gilbert/api.js deleted file mode 100644 index 71aaab8..0000000 --- a/contrib/gilbert/templates/gilbert/api.js +++ /dev/null @@ -1,265 +0,0 @@ -{% load staticmedia %} - -Ext.Direct.addProvider({ - 'namespace': 'Gilbert.api', - 'url': '{% url gilbert:router %}', - 'type': 'remoting', - 'actions': {{% for gilbert_class in gilbert.core_api.gilbert_plugin_classes.values %} - '{{ gilbert_class.gilbert_class_name }}': [{% for method in gilbert_class.gilbert_class_methods.values %}{ - 'name': '{{ method.gilbert_method_name }}', - 'len': {{ method.gilbert_method_argc }} - },{% endfor %}],{% endfor %} - } -}); - -{% if not logged_in %} - -Ext.onReady(function() { - var login_form = new Ext.FormPanel({ - frame: true, - bodyStyle: 'padding: 5px 5px 0', - items: [ - { - fieldLabel: 'Username', - name: 'username', - xtype: 'textfield', - }, - { - fieldLabel: 'Password', - name: 'password', - xtype: 'textfield', - inputType: 'password', - } - ], - buttons: [ - { - text: 'Login', - handler: function(sender) { - // document.location.reload(); - var the_form = login_form.getForm().el.dom; - var username = the_form[0].value; - var password = the_form[1].value; - Gilbert.api.auth.login(username, password, function(result) { - if (result) { - document.location.reload(); - } else { - Ext.MessageBox.alert('Login failed', 'Unable to authenticate.', function() { - login_form.getForm().reset(); - }); - } - }); - } - } - ], - }); - var login_window = new Ext.Window({ - title: 'Login', - closable: false, - width: 266, - height: 130, - layout: 'fit', - items: login_form, - }); - login_window.show(); -}); - - -{% else %} - -Ext.ns('Gilbert', 'Gilbert.ui', 'Gilbert.models', 'Gilbert.plugins'); - -{% for app_label, models in gilbert.model_registry.items %}Ext.Direct.addProvider({ - 'namespace': 'Gilbert.models.{{ app_label }}', - 'url': '{% url gilbert:models app_label %}', - 'type': 'remoting', - 'actions': {{% for model_name, admin in models.items %} - '{{ model_name }}': [{% for method in admin.gilbert_class_methods.values %}{ - 'name': '{{ method.gilbert_method_name }}', - 'len': {{ method.gilbert_method_argc }} - },{% endfor %}],{% endfor %} - } -});{% endfor %} -{% for plugin in gilbert.plugin_registry.values %}Ext.Direct.addProvider({ - 'namespace': 'Gilbert.plugins.{{ plugin.gilbert_plugin_name }}', - 'url': '{% url gilbert:plugins plugin.gilbert_plugin_name %}', - 'type': 'remoting', - 'actions': {{% for gilbert_class in plugin.gilbert_plugin_classes %} - '{{ gilbert_class.gilbert_class_name }}': [{% for method in gilbert_class.gilbert_class_methods.values %}{} - 'name': '{{ method.gilbert_method_name }}', - 'len': {{ method.gilbert_method_argc }} - },{% endfor %}],{% endfor %} - } -});{% endfor %} - -Gilbert.ui.Application = function(cfg) { - Ext.apply(this, cfg, { - title: '{{ gilbert.title }}', - }); - this.addEvents({ - 'ready': true, - 'beforeunload': true, - }); - Ext.onReady(this.initApplication, this); -}; - -Ext.extend(Gilbert.ui.Application, Ext.util.Observable, { - initApplication: function() { - - Ext.QuickTips.init(); - - this.desktop = new Ext.Panel({ - region: 'center', - border: false, - padding: '5', - bodyStyle: 'background: none;', - }); - var desktop = this.desktop; - - this.toolbar = new Ext.Toolbar({ - region: 'north', - autoHeight: true, - items: [ - { - xtype: 'tbtext', - text: this.title, - style: 'font-weight: bolder; font-size: larger; text-transform: uppercase;', - }, - { - xtype: 'tbseparator', - } - ] - }); - var toolbar = this.toolbar; - - this.viewport = new Ext.Viewport({ - renderTo: Ext.getBody(), - layout: 'border', - items: [ - toolbar, - desktop, - ], - }); - var viewport = this.viewport; - - var windows = new Ext.WindowGroup(); - - this.createWindow = function(config, cls) { - var win = new(cls || Ext.Window)(Ext.applyIf(config || {}, - { - renderTo: desktop.el, - manager: windows, - constrainHeader: true, - maximizable: true, - })); - win.render(desktop.el); - return win; - }; - var createWindow = this.createWindow; - - if (this.plugins) { - for (var pluginNum = 0; pluginNum < this.plugins.length; pluginNum++) { - this.plugins[pluginNum].initWithApp(this); - }; - }; - - if (this.user) { - var user = this.user; - toolbar.add({ xtype: 'tbfill' }); - toolbar.add({ xtype: 'tbseparator' }); - toolbar.add({ - xtype: 'button', - text: '' + user + '', - style: 'font-weight: bolder !important; font-size: smaller !important; text-transform: uppercase !important;', - menu: [ - { - text: 'Change password', - handler: function(button, event) { - var edit_window = createWindow({ - layout: 'fit', - title: 'Change password', - width: 266, - height: 170, - layout: 'fit', - 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', - handler: function(sender) { - // document.location.reload(); - 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(); - }); - } - }); - } - } - ], - }), - }); - edit_window.show(this); - }, - }, - { - text: 'Log out', - handler: function(button, event) { - Gilbert.api.auth.logout(function(result) { - if (result) { - Ext.MessageBox.alert('Logout successful', 'You have been logged out.', function() { - document.location.reload(); - }); - } else { - Ext.MessageBox.alert('Logout failed', 'A bit odd, you might say.'); - } - }); - }, - }, - ], - }); - }; - - toolbar.doLayout(); - viewport.doLayout(); - }, -}); - -Ext.BLANK_IMAGE_URL = '{% mediaurl "gilbert/extjs/resources/images/default/s.gif" %}'; - -Ext.onReady(function(){ - Gilbert.Application = new Gilbert.ui.Application({ - user: '{% filter force_escape %}{% firstof user.get_full_name user.username %}{% endfilter %}', - plugins: [{% for plugin in gilbert.plugin_registry.values %}{% if plugin.gilbert_plugin_javascript %} - {{ plugin.gilbert_plugin_javascript|safe }}, - {% endif %}{% endfor %}], - }); -}); -{% endif %} \ No newline at end of file diff --git a/contrib/gilbert/templates/gilbert/base.html b/contrib/gilbert/templates/gilbert/base.html deleted file mode 100644 index 61a1c65..0000000 --- a/contrib/gilbert/templates/gilbert/base.html +++ /dev/null @@ -1,21 +0,0 @@ -{% load staticmedia %} - - -{% block head %} - {% block title %}{{ gilbert.title }}{% endblock %} - - {% block css %} - - - - {% endblock %} - - {% block js %} - - - - {% endblock %} - -{% endblock %} -{% block body %}{% endblock %} - diff --git a/contrib/gilbert/templates/gilbert/css.css b/contrib/gilbert/templates/gilbert/css.css deleted file mode 100644 index e69de29..0000000 diff --git a/contrib/gilbert/templates/gilbert/index.html b/contrib/gilbert/templates/gilbert/index.html index a4d9290..23a7e87 100644 --- a/contrib/gilbert/templates/gilbert/index.html +++ b/contrib/gilbert/templates/gilbert/index.html @@ -1 +1,86 @@ -{% extends 'gilbert/base.html' %} \ No newline at end of file +{% load staticmedia %} + + +{% block head %} + {% block title %}{{ gilbert.title }}{% endblock %} + + {% block css %} + + + + {% for plugin in gilbert.plugin_registry.values %}{% for css in plugin.css %} + + {% endfor %}{% endfor %} + {% endblock %} + + {% block js %} + + + + + + + {% for plugin in gilbert.plugin_registry.values %}{% for js in plugin.js %} + + {% endfor %}{% endfor %} + + {% endblock %} + +{% endblock %} +{% block body %}{% endblock %} + diff --git a/contrib/gilbert/templates/gilbert/styles.css b/contrib/gilbert/templates/gilbert/styles.css new file mode 100644 index 0000000..d6d6eba --- /dev/null +++ b/contrib/gilbert/templates/gilbert/styles.css @@ -0,0 +1 @@ +{% for icon, url in icons.items %}.{{icon}}{background:url({{ url }}) no-repeat !important;}{% endfor %} \ No newline at end of file diff --git a/contrib/gilbert/utils.py b/contrib/gilbert/utils.py deleted file mode 100644 index 0e7b071..0000000 --- a/contrib/gilbert/utils.py +++ /dev/null @@ -1,52 +0,0 @@ -from inspect import isclass, getargspec - - -def is_gilbert_plugin(class_or_instance): - from philo.contrib.gilbert.options import GilbertPluginBase, GilbertPlugin - return (isclass(class_or_instance) and issubclass(class_or_instance, GilbertPlugin)) or isinstance(class_or_instance, GilbertPlugin) or (getattr(class_or_instance, '__metaclass__', None) is GilbertPluginBase) or (getattr(class_or_instance, 'gilbert_plugin', False) and (getattr(class_or_instance, 'gilbert_plugin_name', None) is not None) and (getattr(class_or_instance, 'gilbert_plugin_classes', None) is not None)) - - -def is_gilbert_class(class_or_instance): - from philo.contrib.gilbert.options import GilbertClassBase, GilbertClass - return (isclass(class_or_instance) and issubclass(class_or_instance, GilbertClass)) or isinstance(class_or_instance, GilbertClass) or (getattr(class_or_instance, '__metaclass__', None) is GilbertClassBase) or (getattr(class_or_instance, 'gilbert_class', False) and (getattr(class_or_instance, 'gilbert_class_name', None) is not None) and (getattr(class_or_instance, 'gilbert_class_methods', None) is not None)) - - -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): - setattr(function, 'gilbert_method', True) - setattr(function, 'gilbert_method_name', name or function.__name__) - setattr(function, 'gilbert_method_restricted', restricted) - new_argc = argc - if new_argc is None: - args = getargspec(function)[0] - new_argc = len(args) - if new_argc > 0: - if args[0] == 'self': - args = args[1:] - new_argc = new_argc - 1 - if new_argc > 0: - if args[0] == 'request': - args = args[1:] - new_argc = new_argc - 1 - setattr(function, 'gilbert_method_argc', new_argc) - return function - if function is not None: - return wrapper(function) - return wrapper - - -def call_gilbert_method(method, cls, request, *args, **kwargs): - arg_list = getargspec(method)[0] - if len(arg_list) > 0: - if arg_list[0] == 'self': - if len(arg_list) > 1 and arg_list[1] == 'request': - return method(cls, request, *args, **kwargs) - return method(cls, *args, **kwargs) - elif arg_list[0] == 'request': - return method(request, *args, **kwargs) - else: - return method(*args, **kwargs) \ No newline at end of file