1 from django.conf.urls.defaults import url, patterns, include
2 from django.core.urlresolvers import reverse
3 from django.shortcuts import render_to_response
4 from django.conf import settings
5 from django.utils import simplejson as json
6 from django.utils.datastructures import SortedDict
8 from django.db.models.base import ModelBase
9 from philo.utils import fattr
10 from .exceptions import AlreadyRegistered, NotRegistered
11 from django.forms.models import model_to_dict
13 from inspect import getargspec
14 from django.views.decorators.cache import never_cache
15 from . import __version__ as gilbert_version
19 from .extdirect import ExtAction, ExtRouter
21 from functools import partial
22 from django.http import HttpResponse, HttpResponseRedirect
23 from django.template import RequestContext
24 from django.core.context_processors import csrf
25 from django.utils.functional import update_wrapper
26 from django.contrib.auth import authenticate, login
27 from .plugins.models import Models, ModelAdmin
28 from .plugins.auth import Auth
31 __all__ = ('GilbertSite', 'site')
34 class CoreRouter(ExtRouter):
35 def __init__(self, site):
41 return 'Gilbert.api.plugins'
45 return reverse('%s:router' % self.site.namespace, current_app=self.site.app_name)
57 return list(action.obj for action in self._actions.itervalues())
59 def register_plugin(self, plugin):
60 action = ExtAction(plugin)
61 self._actions[action.name] = action
64 class ModelRouter(ExtRouter):
65 def __init__(self, site, app_label):
67 self.app_label = app_label
72 return 'Gilbert.api.models.%s' % self.app_label
76 return reverse('%s:model_router' % self.site.namespace, current_app=self.site.app_name, kwargs={'app_label': self.app_label})
88 return dict((name, action.obj) for name, action in self._actions.iteritems())
90 def register_admin(self, name, admin):
91 action = ExtAction(admin)
93 self._actions[action.name] = action
96 class GilbertSite(object):
97 version = gilbert_version
99 def __init__(self, namespace='gilbert', app_name='gilbert', title=None):
100 self.namespace = namespace
101 self.app_name = app_name
103 self.title = getattr(settings, 'GILBERT_TITLE', 'Gilbert')
107 self.core_router = CoreRouter(self)
108 self.model_routers = SortedDict()
110 self.register_plugin(Models)
111 self.register_plugin(Auth)
113 def register_plugin(self, plugin):
114 self.core_router.register_plugin(plugin(self))
116 def register_model(self, model_or_iterable, admin_class=ModelAdmin, **admin_attrs):
117 if isinstance(model_or_iterable, ModelBase):
118 model_or_iterable = [model_or_iterable]
119 for model in model_or_iterable:
120 app_label = model._meta.app_label
121 name = model._meta.object_name
123 if app_label not in self.model_routers:
124 self.model_routers[app_label] = ModelRouter(self, app_label)
125 router = self.model_routers[app_label]
128 admin_attrs['__module__'] = __name__
129 admin_class = type('%sAdmin' % model.__name__, (admin_class,), admin_attrs)
131 router.register_admin(name, admin_class(self, model))
133 def has_permission(self, request):
134 return request.user.is_active and request.user.is_staff
136 def protected_view(self, view, login_page=True, cacheable=False):
137 def inner(request, *args, **kwargs):
138 if not self.has_permission(request):
140 return self.login(request)
142 return HttpResponse(status=403)
143 return view(request, *args, **kwargs)
145 inner = never_cache(inner)
146 return update_wrapper(inner, view)
150 urlpatterns = patterns('',
151 url(r'^$', self.protected_view(self.index), name='index'),
152 url(r'^api.js$', self.protected_view(self.api, login_page=False), name='api'),
153 url(r'^icons.css$', self.protected_view(self.icons, login_page=False), name='icons'),
154 url(r'^router$', self.protected_view(self.router, login_page=False), name='router'),
155 url(r'^router/models/(?P<app_label>\w+)$', self.protected_view(self.router, login_page=False), name='model_router'),
157 return (urlpatterns, self.app_name, self.namespace)
159 def login(self, request):
162 'form_url': request.get_full_path(),
164 context.update(csrf(request))
167 if request.session.test_cookie_worked():
168 request.session.delete_test_cookie()
169 username = request.POST.get('username', None)
170 password = request.POST.get('password', None)
171 user = authenticate(username=username, password=password)
173 if user.is_active and user.is_staff:
175 return HttpResponseRedirect(request.get_full_path())
178 'error_message_short': 'Not staff',
179 'error_message': 'You do not have access to this page.',
183 'error_message_short': 'Invalid credentials',
184 'error_message': 'Unable to authenticate using the provided credentials. Please try again.',
188 'error_message_short': 'Cookies disabled',
189 'error_message': 'Please enable cookies, reload this page, and try logging in again.',
192 request.session.set_test_cookie()
193 return render_to_response('gilbert/login.html', context, context_instance=RequestContext(request))
195 def index(self, request):
196 return render_to_response('gilbert/index.html', {
198 'plugins': self.core_router.plugins # needed as the template language will not traverse callables
199 }, context_instance=RequestContext(request))
201 def api(self, request):
205 for app_label, router in self.model_routers.items():
206 if request.user.has_module_perms(app_label):
207 providers.append(router.spec)
208 model_registry[app_label] = dict((model_name, admin) for model_name, admin in router.models.items() if admin.has_permission(request))
210 providers.append(self.core_router.spec)
214 'providers': [json.dumps(provider, separators=(',', ':')) for provider in providers],
215 'model_registry': model_registry,
217 context.update(csrf(request))
219 return render_to_response('gilbert/api.js', context, mimetype='text/javascript')
221 def icons(self, request):
224 for plugin in self.core_router.plugins:
225 icon_names.extend(plugin.icon_names)
227 for router in self.model_routers.values():
228 for admin in router.models.values():
229 icon_names.extend(admin.icon_names)
231 return render_to_response('gilbert/icons.css', {
232 'icon_names': set(icon_names),
233 }, mimetype='text/css')
235 def router(self, request, app_label=None, extra_context=None):
236 if app_label is None:
237 return self.core_router.render_to_response(request)
239 return self.model_routers[app_label].render_to_response(request)