Use ui-router to handle django urls

See: #1453
This commit is contained in:
Oskar Hahn 2015-02-14 10:10:08 +01:00
parent 962dd209f5
commit 80ca3f2484
7 changed files with 206 additions and 124 deletions

View File

@ -9,11 +9,12 @@ angular.module('OpenSlidesApp.core', [])
var result = {}, var result = {},
views = parent(state); views = parent(state);
if (state.abstract) { if (state.abstract || state.data && state.data.extern) {
return views; return views;
} }
angular.forEach(views, function(config, name) { angular.forEach(views, function(config, name) {
// Sets default values for templateUrl // Sets default values for templateUrl
var patterns = state.name.split('.'), var patterns = state.name.split('.'),
templateUrl, templateUrl,
@ -75,9 +76,9 @@ angular.module('OpenSlidesApp.core', [])
.config(function($stateProvider, $locationProvider) { .config(function($stateProvider, $locationProvider) {
// Core urls // Core urls
$stateProvider.state('dashboard', { $stateProvider.state('dashboard', {
url: '/', url: '/',
templateUrl: 'static/templates/dashboard.html' templateUrl: 'static/templates/dashboard.html'
}); });
$locationProvider.html5Mode(true); $locationProvider.html5Mode(true);
}) })
@ -98,6 +99,30 @@ angular.module('OpenSlidesApp.core', [])
}; };
}) })
.provider('runtimeStates', function($stateProvider) {
this.$get = function($q, $timeout, $state) {
return {
addState: function(name, state) {
$stateProvider.state(name, state);
}
}
}
})
.run(function(runtimeStates, $http) {
$http.get('/core/url_patterns/').then(function(data) {
for (var pattern in data.data) {
runtimeStates.addState(pattern, {
'url': data.data[pattern],
data: {extern: true},
onEnter: function($window) {
$window.location.href = this.url;
}
});
}
});
})
.run(function(DS, autoupdate) { .run(function(DS, autoupdate) {
autoupdate.on_message(function(data) { autoupdate.on_message(function(data) {
// TODO: when MODEL.find() is called after this // TODO: when MODEL.find() is called after this

View File

@ -43,4 +43,9 @@ urlpatterns = patterns(
url(r'tags/$', url(r'tags/$',
views.TagListView.as_view(), views.TagListView.as_view(),
name='core_tag_list'), name='core_tag_list'),
# Ajax Urls
url(r'^core/url_patterns/$',
views.UrlPatternsView.as_view(),
name='core_url_patterns'),
) )

View File

@ -1,27 +1,33 @@
import re
from django.conf import settings from django.conf import settings
from django.contrib import messages from django.contrib import messages
from django.contrib.staticfiles import finders from django.contrib.staticfiles import finders
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.core.urlresolvers import reverse from django.core.urlresolvers import get_resolver, reverse
from django.db import IntegrityError from django.db import IntegrityError
from django.http import HttpResponse
from django.shortcuts import redirect, render_to_response from django.shortcuts import redirect, render_to_response
from django.template import RequestContext from django.template import RequestContext
from django.utils.importlib import import_module from django.utils.importlib import import_module
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from haystack.views import SearchView as _SearchView from haystack.views import SearchView as _SearchView
from django.http import HttpResponse
from openslides import __version__ as openslides_version from openslides import __version__ as openslides_version
from openslides.config.api import config from openslides.config.api import config
from openslides.utils import views as utils_views from openslides.utils import views as utils_views
from openslides.utils.plugins import get_plugin_description, get_plugin_verbose_name, get_plugin_version from openslides.utils.plugins import (
get_plugin_description,
get_plugin_verbose_name,
get_plugin_version,
)
from openslides.utils.rest_api import ModelViewSet from openslides.utils.rest_api import ModelViewSet
from openslides.utils.signals import template_manipulation from openslides.utils.signals import template_manipulation
from openslides.utils.widgets import Widget from openslides.utils.widgets import Widget
from .exceptions import TagException
from .forms import SelectWidgetsForm from .forms import SelectWidgetsForm
from .models import CustomSlide, Tag from .models import CustomSlide, Tag
from .exceptions import TagException
from .serializers import CustomSlideSerializer, TagSerializer from .serializers import CustomSlideSerializer, TagSerializer
@ -338,3 +344,20 @@ class TagViewSet(ModelViewSet):
if (self.action in ('create', 'update', 'destroy') and if (self.action in ('create', 'update', 'destroy') and
not request.user.has_perm('core.can_manage_tags')): not request.user.has_perm('core.can_manage_tags')):
self.permission_denied(request) self.permission_denied(request)
class UrlPatternsView(utils_views.APIView):
"""
Returns a dictonary with all url patterns as json.
"""
URL_KWARGS_REGEX = re.compile(r'%\((\w*)\)s')
http_method_names = ['get']
def get_context_data(self, **context):
result = {}
url_dict = get_resolver(None).reverse_dict
for pattern_name in filter(lambda key: isinstance(key, str), url_dict.keys()):
url = url_dict[pattern_name][0][0][0]
result[pattern_name] = self.URL_KWARGS_REGEX.sub(r':\1', url)
return result

View File

@ -2,82 +2,82 @@ angular.module('OpenSlidesApp.users', [])
.config(function($stateProvider) { .config(function($stateProvider) {
$stateProvider $stateProvider
.state('users', { .state('users', {
url: '/users', url: '/users',
abstract: true, abstract: true,
template: "<ui-view/>", template: "<ui-view/>",
}) })
.state('users.user', { .state('users.user', {
abstract: true, abstract: true,
template: "<ui-view/>", template: "<ui-view/>",
}) })
.state('users.user.list', { .state('users.user.list', {
resolve: { resolve: {
users: function(User) { users: function(User) {
return User.findAll(); return User.findAll();
}
} }
}) }
.state('users.user.create', { })
resolve: { .state('users.user.create', {
groups: function(Group) { resolve: {
return Group.findAll(); groups: function(Group) {
} return Group.findAll();
} }
}) }
.state('users.user.detail', { })
resolve: { .state('users.user.detail', {
user: function(User, $stateParams) { resolve: {
return User.find($stateParams.id); user: function(User, $stateParams) {
} return User.find($stateParams.id);
} }
}) }
.state('users.user.detail.update', { })
views: { .state('users.user.detail.update', {
'@users.user': {} views: {
}, '@users.user': {}
resolve: { },
groups: function(Group) { resolve: {
return Group.findAll(); groups: function(Group) {
} return Group.findAll();
} }
}) }
.state('users.user.csv-import', { })
url: '/csv-import', .state('users.user.csv-import', {
controller: 'UserCSVImportCtrl', url: '/csv-import',
}) controller: 'UserCSVImportCtrl',
// groups })
.state('users.group', { // groups
url: '/groups', .state('users.group', {
abstract: true, url: '/groups',
template: "<ui-view/>", abstract: true,
}) template: "<ui-view/>",
.state('users.group.list', { })
resolve: { .state('users.group.list', {
groups: function(Group) { resolve: {
return Group.findAll(); groups: function(Group) {
} return Group.findAll();
} }
}) }
.state('users.group.create', { })
resolve: { .state('users.group.create', {
groups: function(Group) { resolve: {
return Group.findAll(); groups: function(Group) {
} return Group.findAll();
} }
}) }
.state('users.group.detail', { })
resolve: { .state('users.group.detail', {
group: function(Group, $stateParams) { resolve: {
return Group.find($stateParams.id); group: function(Group, $stateParams) {
} return Group.find($stateParams.id);
} }
}) }
.state('users.group.detail.update', { })
views: { .state('users.group.detail.update', {
'@users.group': {} views: {
} '@users.group': {}
}); }
});
}) })
.factory('operator', function(User, Group) { .factory('operator', function(User, Group) {

View File

@ -28,6 +28,8 @@ from .serializers import (
) )
# Views to generate PDFs
class UsersListPDF(PDFView): class UsersListPDF(PDFView):
""" """
Generate the userliste as PDF. Generate the userliste as PDF.
@ -61,15 +63,7 @@ class UsersPasswordsPDF(PDFView):
users_passwords_to_pdf(pdf) users_passwords_to_pdf(pdf)
class UserCSVImportView(CSVImportView): # Viewsets for the rest api
"""
Import users via CSV.
"""
required_permission = 'users.can_manage'
success_url_name = 'user_list'
template_name = 'users/user_form_csv_import.html'
import_function = staticmethod(import_users)
class UserViewSet(ModelViewSet): class UserViewSet(ModelViewSet):
""" """
@ -136,44 +130,7 @@ class GroupViewSet(ModelViewSet):
return response return response
class UserSettingsView(LoginMixin, UpdateView): # API Views
required_permission = None
template_name = 'users/settings.html'
success_url_name = 'user_settings'
model = User
form_class = UsersettingsForm
url_name_args = []
def get_initial(self):
initial = super().get_initial()
initial['language'] = self.request.session.get('django_language', self.request.LANGUAGE_CODE)
return initial
def form_valid(self, form):
self.request.LANGUAGE_CODE = self.request.session['django_language'] = form.cleaned_data['language']
activate(self.request.LANGUAGE_CODE)
return super().form_valid(form)
def get_object(self):
return self.request.user
class UserPasswordSettingsView(LoginMixin, FormView):
required_permission = None
template_name = 'users/password_change.html'
success_url_name = 'core_dashboard'
form_class = PasswordChangeForm
def form_valid(self, form):
form.save()
messages.success(self.request, _('Password successfully changed.'))
return super().form_valid(form)
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
class UserLoginView(APIView): class UserLoginView(APIView):
""" """
@ -224,3 +181,54 @@ class WhoAmIView(APIView):
return super().get_context_data( return super().get_context_data(
user_id=self.request.user.pk, user_id=self.request.user.pk,
**context) **context)
# Deprecated views. Will be removed after the implementation in angularjs
class UserCSVImportView(CSVImportView):
"""
Import users via CSV.
"""
required_permission = 'users.can_manage'
success_url_name = 'user_list'
template_name = 'users/user_form_csv_import.html'
import_function = staticmethod(import_users)
class UserSettingsView(LoginMixin, UpdateView):
required_permission = None
template_name = 'users/settings.html'
success_url_name = 'user_settings'
model = User
form_class = UsersettingsForm
url_name_args = []
def get_initial(self):
initial = super().get_initial()
initial['language'] = self.request.session.get('django_language', self.request.LANGUAGE_CODE)
return initial
def form_valid(self, form):
self.request.LANGUAGE_CODE = self.request.session['django_language'] = form.cleaned_data['language']
activate(self.request.LANGUAGE_CODE)
return super().form_valid(form)
def get_object(self):
return self.request.user
class UserPasswordSettingsView(LoginMixin, FormView):
required_permission = None
template_name = 'users/password_change.html'
success_url_name = 'core_dashboard'
form_class = PasswordChangeForm
def form_valid(self, form):
form.save()
messages.success(self.request, _('Password successfully changed.'))
return super().form_valid(form)
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs

View File

View File

@ -0,0 +1,21 @@
from unittest import TestCase
from unittest.mock import patch
from openslides.core import views
class TestUrlPatternsView(TestCase):
@patch('openslides.core.views.get_resolver')
def test_get_context_data(self, mock_resolver):
mock_resolver().reverse_dict = {
'url_pattern1': [[['my_url1']]],
'url_pattern2': [[['my_url2/%(kwarg)s/']]],
('not_a_str', ): [[['not_a_str']]]}
view = views.UrlPatternsView()
context = view.get_context_data()
self.assertEqual(
context,
{'url_pattern1': 'my_url1',
'url_pattern2': 'my_url2/:kwarg/'})