Merge pull request #1466 from ostcar/django_urls
Use django url patterns in angular
This commit is contained in:
commit
146548a309
@ -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
|
||||||
|
@ -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'),
|
||||||
)
|
)
|
||||||
|
@ -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
|
||||||
|
@ -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) {
|
||||||
|
@ -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
|
||||||
|
0
tests/unit/core/__init__.py
Normal file
0
tests/unit/core/__init__.py
Normal file
21
tests/unit/core/test_views.py
Normal file
21
tests/unit/core/test_views.py
Normal 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/'})
|
Loading…
Reference in New Issue
Block a user