1 from django.conf import settings
2 from django.contrib.auth import authenticate, login
3 from django.core.context_processors import csrf
4 from django.conf.urls.defaults import url, patterns, include
5 from django.core.urlresolvers import reverse
6 from django.db.models.base import ModelBase
7 from django.forms.models import model_to_dict
8 from django.http import HttpResponse, HttpResponseRedirect
9 from django.shortcuts import render_to_response
10 from django.template import RequestContext
11 from django.utils import simplejson as json
12 from django.utils.datastructures import SortedDict
13 from django.views.decorators.cache import never_cache
14 from philo.utils import fattr
15 from . import __version__ as gilbert_version
16 from .exceptions import AlreadyRegistered, NotRegistered
17 from .extdirect import ExtAction, ExtRouter
18 from .plugins.auth import Auth
19 from .plugins.models import Models, ModelAdmin
20 from inspect import getargspec
21 from functools import partial, update_wrapper
22 import sys, os, datetime
26 __all__ = ('GilbertSite', 'site')
29 class CoreRouter(ExtRouter):
30 def __init__(self, site):
36 return 'Gilbert.api.plugins'
40 return reverse('%s:router' % self.site.namespace, current_app=self.site.app_name)
52 return list(action.obj for action in self._actions.itervalues())
54 def register_plugin(self, plugin):
55 action = ExtAction(plugin)
56 self._actions[action.name] = action
59 class ModelRouter(ExtRouter):
60 def __init__(self, site, app_label):
62 self.app_label = app_label
67 return 'Gilbert.api.models.%s' % self.app_label
71 return reverse('%s:model_router' % self.site.namespace, current_app=self.site.app_name, kwargs={'app_label': self.app_label})
83 return dict((name, action.obj) for name, action in self._actions.iteritems())
85 def register_admin(self, name, admin):
86 action = ExtAction(admin)
88 self._actions[action.name] = action
91 class GilbertSite(object):
92 version = gilbert_version
94 def __init__(self, namespace='gilbert', app_name='gilbert', title=None):
95 self.namespace = namespace
96 self.app_name = app_name
98 self.title = getattr(settings, 'GILBERT_TITLE', 'Gilbert')
102 self.core_router = CoreRouter(self)
103 self.model_routers = SortedDict()
105 self.register_plugin(Models)
106 self.register_plugin(Auth)
108 def register_plugin(self, plugin):
109 self.core_router.register_plugin(plugin(self))
111 def register_model(self, model_or_iterable, admin_class=ModelAdmin, **admin_attrs):
112 if isinstance(model_or_iterable, ModelBase):
113 model_or_iterable = [model_or_iterable]
114 for model in model_or_iterable:
115 app_label = model._meta.app_label
116 name = model._meta.object_name
118 if app_label not in self.model_routers:
119 self.model_routers[app_label] = ModelRouter(self, app_label)
120 router = self.model_routers[app_label]
123 admin_attrs['__module__'] = __name__
124 admin_class = type('%sAdmin' % model.__name__, (admin_class,), admin_attrs)
126 router.register_admin(name, admin_class(self, model))
128 def has_permission(self, request):
129 return request.user.is_active and request.user.is_staff
131 def protected_view(self, view, login_page=True, cacheable=False):
132 def inner(request, *args, **kwargs):
133 if not self.has_permission(request):
135 return self.login(request)
137 return HttpResponse(status=403)
138 return view(request, *args, **kwargs)
140 inner = never_cache(inner)
141 return update_wrapper(inner, view)
145 urlpatterns = patterns('',
146 url(r'^$', self.protected_view(self.index), name='index'),
147 url(r'^api.js$', self.protected_view(self.api, login_page=False), name='api'),
148 url(r'^icons.css$', self.protected_view(self.icons, login_page=False), name='icons'),
149 url(r'^router$', self.protected_view(self.router, login_page=False), name='router'),
150 url(r'^router/models/(?P<app_label>\w+)$', self.protected_view(self.router, login_page=False), name='model_router'),
152 return (urlpatterns, self.app_name, self.namespace)
154 def login(self, request):
157 'form_url': request.get_full_path(),
159 context.update(csrf(request))
162 if request.session.test_cookie_worked():
163 request.session.delete_test_cookie()
164 username = request.POST.get('username', None)
165 password = request.POST.get('password', None)
166 user = authenticate(username=username, password=password)
168 if user.is_active and user.is_staff:
170 return HttpResponseRedirect(request.get_full_path())
173 'error_message_short': 'Not staff',
174 'error_message': 'You do not have access to this page.',
178 'error_message_short': 'Invalid credentials',
179 'error_message': 'Unable to authenticate using the provided credentials. Please try again.',
183 'error_message_short': 'Cookies disabled',
184 'error_message': 'Please enable cookies, reload this page, and try logging in again.',
187 request.session.set_test_cookie()
188 return render_to_response('gilbert/login.html', context, context_instance=RequestContext(request))
190 def index(self, request):
191 return render_to_response('gilbert/index.html', {
193 'plugins': self.core_router.plugins # needed as the template language will not traverse callables
194 }, context_instance=RequestContext(request))
196 def api(self, request):
200 for app_label, router in self.model_routers.items():
201 if request.user.has_module_perms(app_label):
202 providers.append(router.spec)
203 model_registry[app_label] = dict((model_name, admin) for model_name, admin in router.models.items() if admin.has_permission(request))
205 providers.append(self.core_router.spec)
209 'providers': [json.dumps(provider, separators=(',', ':')) for provider in providers],
210 'model_registry': model_registry,
212 context.update(csrf(request))
214 return render_to_response('gilbert/api.js', context, mimetype='text/javascript')
216 def icons(self, request):
219 for plugin in self.core_router.plugins:
220 icon_names.extend(plugin.icon_names)
222 for router in self.model_routers.values():
223 for admin in router.models.values():
224 icon_names.extend(admin.icon_names)
226 return render_to_response('gilbert/icons.css', {
227 'icon_names': set(icon_names),
228 }, mimetype='text/css')
230 def router(self, request, app_label=None, extra_context=None):
231 if app_label is None:
232 return self.core_router.render_to_response(request)
234 return self.model_routers[app_label].render_to_response(request)