X-Git-Url: http://git.ithinksw.org/philo.git/blobdiff_plain/c5ec4492ee19b3c624c654d29f04938e748510cd..e47a299b1e562a3e6e16cc3c726b84a5a8f542ef:/contrib/gilbert/sites.py diff --git a/contrib/gilbert/sites.py b/contrib/gilbert/sites.py index 76c1d9a..8f666f9 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,81 @@ 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 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): + 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 +92,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 +103,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,73 +121,128 @@ 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, + 'formHandler': method.form_handler, + }) + 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, + 'formHandler': method.form_handler, + }) + 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 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'), + '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, } - if 'extUpload' in request.POST: - ext_request['upload'] = request.POST['extUpload'] + response = self.handle_ext_request(request, ext_request, app_label) else: - ext_request = json.loads(request.raw_post_data) - ext_request['kwdata'] = None + ext_requests = json.loads(request.raw_post_data) + if type(ext_requests) is dict: + ext_requests['upload'] = False + response = self.handle_ext_request(request, ext_requests, app_label) + else: + responses = [] + for ext_request in ext_requests: + ext_request['upload'] = False + responses.append(self.handle_ext_request(request, ext_request, app_label)) + response = responses + if submitted_form: + if ext_request['upload'] is True: + return HttpResponse(('' % json.dumps(response))) + return HttpResponse(json.dumps(response), content_type=('application/json; charset=%s' % settings.DEFAULT_CHARSET)) + + def handle_ext_request(self, request, ext_request, app_label=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) + + return {'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: - return HttpResponse(('' % json.dumps(response))) - return HttpResponse(json.dumps(response), content_type=('application/json; charset=%s' % settings.DEFAULT_CHARSET)) + return {'type': 'exception', 'tid': ext_request['tid'], 'message': ('%s: %s' % (exc_type, exc_value)), 'where': format_tb(exc_traceback)[0]} site = GilbertSite() \ No newline at end of file