From 8026b78f42d6d8ac174e57a8c08a2851406d7d29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laura=20Kl=C3=BCnder?= Date: Wed, 21 Dec 2016 18:47:39 +0100 Subject: [PATCH] =?UTF-8?q?rename=20control=20=E2=86=92=20access=20and=20a?= =?UTF-8?q?dd=20some=20more=20stuff?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/c3nav/{control => access}/__init__.py | 0 src/c3nav/{control => access}/admin.py | 10 +-- .../migrations/0001_initial.py | 21 ++--- .../migrations/0002_auto_20161221_1739.py | 26 +++++++ .../migrations/__init__.py | 0 src/c3nav/{control => access}/models.py | 19 +++++ .../static/access/css/c3nav-access.css} | 0 .../access/templates/access/activate.html | 14 ++++ .../templates/access}/base.html | 4 +- .../templates/access/fragment_token.html | 3 + .../templates/access}/login.html | 4 +- .../templates/access}/prove.html | 13 +++- src/c3nav/access/urls.py | 12 +++ src/c3nav/access/views.py | 76 +++++++++++++++++++ .../migrations/0002_auto_20161220_0158.py | 20 ----- .../migrations/0003_auto_20161220_0214.py | 30 -------- .../migrations/0004_auto_20161220_0253.py | 25 ------ src/c3nav/control/urls.py | 11 --- src/c3nav/control/views.py | 58 -------------- src/c3nav/settings.py | 2 +- src/c3nav/urls.py | 4 +- 21 files changed, 183 insertions(+), 169 deletions(-) rename src/c3nav/{control => access}/__init__.py (100%) rename src/c3nav/{control => access}/admin.py (88%) rename src/c3nav/{control => access}/migrations/0001_initial.py (77%) create mode 100644 src/c3nav/access/migrations/0002_auto_20161221_1739.py rename src/c3nav/{control => access}/migrations/__init__.py (100%) rename src/c3nav/{control => access}/models.py (81%) rename src/c3nav/{control/static/control/css/c3nav-control.css => access/static/access/css/c3nav-access.css} (100%) create mode 100644 src/c3nav/access/templates/access/activate.html rename src/c3nav/{control/templates/control => access/templates/access}/base.html (87%) create mode 100644 src/c3nav/access/templates/access/fragment_token.html rename src/c3nav/{control/templates/control => access/templates/access}/login.html (92%) rename src/c3nav/{control/templates/control => access/templates/access}/prove.html (80%) create mode 100644 src/c3nav/access/urls.py create mode 100644 src/c3nav/access/views.py delete mode 100644 src/c3nav/control/migrations/0002_auto_20161220_0158.py delete mode 100644 src/c3nav/control/migrations/0003_auto_20161220_0214.py delete mode 100644 src/c3nav/control/migrations/0004_auto_20161220_0253.py delete mode 100644 src/c3nav/control/urls.py delete mode 100644 src/c3nav/control/views.py diff --git a/src/c3nav/control/__init__.py b/src/c3nav/access/__init__.py similarity index 100% rename from src/c3nav/control/__init__.py rename to src/c3nav/access/__init__.py diff --git a/src/c3nav/control/admin.py b/src/c3nav/access/admin.py similarity index 88% rename from src/c3nav/control/admin.py rename to src/c3nav/access/admin.py index b339dbba..0fed57aa 100644 --- a/src/c3nav/control/admin.py +++ b/src/c3nav/access/admin.py @@ -3,7 +3,7 @@ from django.contrib.auth.admin import UserAdmin as BaseUserAdmin from django.contrib.auth.models import User from django.utils.translation import ugettext_lazy as _ -from c3nav.control.models import AccessOperator, AccessToken, AccessTokenInstance, AccessUser +from c3nav.access.models import AccessOperator, AccessToken, AccessTokenInstance, AccessUser class AccessOperatorInline(admin.StackedInline): @@ -29,7 +29,7 @@ admin.site.register(User, UserAdmin) class AccessTokenInline(admin.TabularInline): model = AccessToken show_change_link = True - readonly_fields = ('author', 'permissions', 'description', 'creation_date', 'expires') + readonly_fields = ('author', 'permissions', 'description', 'creation_date', 'expires', 'expired') def has_add_permission(self, request): return False @@ -55,9 +55,9 @@ class AccessTokenInstanceInline(admin.TabularInline): @admin.register(AccessToken) class AccessTokenAdmin(admin.ModelAdmin): inlines = (AccessTokenInstanceInline,) - list_display = ('__str__', 'user', 'permissions', 'author', 'creation_date', 'expires') - fields = ('user', 'permissions', 'author', 'creation_date', 'expires') - readonly_fields = ('user', 'creation_date') + list_display = ('__str__', 'user', 'permissions', 'author', 'creation_date', 'expires', 'expired') + fields = ('user', 'permissions', 'author', 'creation_date', 'expires', 'expired') + readonly_fields = ('user', 'creation_date', 'expired') def has_add_permission(self, request): return False diff --git a/src/c3nav/control/migrations/0001_initial.py b/src/c3nav/access/migrations/0001_initial.py similarity index 77% rename from src/c3nav/control/migrations/0001_initial.py rename to src/c3nav/access/migrations/0001_initial.py index 4d97abf9..13d446ea 100644 --- a/src/c3nav/control/migrations/0001_initial.py +++ b/src/c3nav/access/migrations/0001_initial.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Generated by Django 1.10.4 on 2016-12-20 01:43 +# Generated by Django 1.10.4 on 2016-12-21 17:21 from __future__ import unicode_literals from django.conf import settings @@ -20,8 +20,8 @@ class Migration(migrations.Migration): name='AccessOperator', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('description', models.TextField(verbose_name='description')), - ('can_award_permissions', models.TextField(verbose_name='can award permissions')), + ('description', models.TextField(blank=True, null=True, verbose_name='description')), + ('can_award_permissions', models.CharField(max_length=2048, verbose_name='can award permissions')), ('access_from', models.DateTimeField(blank=True, null=True, verbose_name='has access from')), ('access_until', models.DateTimeField(blank=True, null=True, verbose_name='has access until')), ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='operator', to=settings.AUTH_USER_MODEL)), @@ -35,10 +35,11 @@ class Migration(migrations.Migration): name='AccessToken', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('permissions', models.TextField(verbose_name='permissions')), + ('permissions', models.CharField(max_length=2048, verbose_name='permissions')), ('description', models.CharField(max_length=200, verbose_name='description')), ('creation_date', models.DateTimeField(auto_now_add=True, verbose_name='creation date')), - ('expipres', models.DateTimeField(blank=True, null=True)), + ('expires', models.DateTimeField(blank=True, null=True)), + ('expired', models.BooleanField(default=False, verbose_name='is expired')), ('author', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL, verbose_name='creator')), ], options={ @@ -52,8 +53,8 @@ class Migration(migrations.Migration): ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('secret', models.CharField(max_length=42, verbose_name='access secret')), ('creation_date', models.DateTimeField(auto_now_add=True, verbose_name='creation date')), - ('expipres', models.DateTimeField(null=True)), - ('access_token', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='instances', to='control.AccessToken', verbose_name='Access Token')), + ('expires', models.DateTimeField(null=True)), + ('access_token', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='instances', to='access.AccessToken', verbose_name='Access Token')), ], options={ 'verbose_name_plural': 'Access Tokens Instance', @@ -64,10 +65,10 @@ class Migration(migrations.Migration): name='AccessUser', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('user_url', models.CharField(help_text='Usually an URL to a profile somewhere', max_length=200, verbose_name='access name')), + ('user_url', models.CharField(help_text='Usually an URL to a profile somewhere', max_length=200, unique=True, verbose_name='access name')), ('description', models.TextField(blank=True, max_length=200, null=True, verbose_name='description')), ('creation_date', models.DateTimeField(auto_now_add=True, verbose_name='creation date')), - ('author', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='control.AccessOperator', verbose_name='creator')), + ('author', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='access.AccessOperator', verbose_name='creator')), ], options={ 'verbose_name_plural': 'Access Users', @@ -77,6 +78,6 @@ class Migration(migrations.Migration): migrations.AddField( model_name='accesstoken', name='user', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tokens', to='control.AccessUser', verbose_name='Access User'), + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tokens', to='access.AccessUser', verbose_name='Access User'), ), ] diff --git a/src/c3nav/access/migrations/0002_auto_20161221_1739.py b/src/c3nav/access/migrations/0002_auto_20161221_1739.py new file mode 100644 index 00000000..49f42e84 --- /dev/null +++ b/src/c3nav/access/migrations/0002_auto_20161221_1739.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.4 on 2016-12-21 17:39 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('access', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='accesstoken', + name='activated', + field=models.BooleanField(default=False, verbose_name='activated'), + ), + migrations.AddField( + model_name='accesstoken', + name='secret', + field=models.CharField(default='', max_length=42, verbose_name='activation secret'), + preserve_default=False, + ), + ] diff --git a/src/c3nav/control/migrations/__init__.py b/src/c3nav/access/migrations/__init__.py similarity index 100% rename from src/c3nav/control/migrations/__init__.py rename to src/c3nav/access/migrations/__init__.py diff --git a/src/c3nav/control/models.py b/src/c3nav/access/models.py similarity index 81% rename from src/c3nav/control/models.py rename to src/c3nav/access/models.py index 859a4677..e47fe80f 100644 --- a/src/c3nav/control/models.py +++ b/src/c3nav/access/models.py @@ -3,6 +3,8 @@ from datetime import timedelta from django.contrib.auth.models import User from django.db import models, transaction +from django.db.models import Q +from django.urls import reverse from django.utils import timezone from django.utils.crypto import get_random_string from django.utils.translation import ugettext_lazy as _ @@ -35,6 +37,14 @@ class AccessUser(models.Model): verbose_name = _('Access User') verbose_name_plural = _('Access Users') + @property + def valid_tokens(self): + return self.tokens.filter(Q(expired=False) | Q(expires__isnull=False, expires__lt=timezone.now())) + + def new_token(self, **kwargs): + kwargs['secret'] = get_random_string(42, string.ascii_letters + string.digits) + return self.tokens.create(**kwargs) + def __str__(self): return self.user_url @@ -47,11 +57,20 @@ class AccessToken(models.Model): description = models.CharField(_('description'), max_length=200) creation_date = models.DateTimeField(_('creation date'), auto_now_add=True) expires = models.DateTimeField(null=True, blank=True) + expired = models.BooleanField(_('is expired'), default=False) + activated = models.BooleanField(_('activated'), default=False) + secret = models.CharField(_('activation secret'), max_length=42) class Meta: verbose_name = _('Access Token') verbose_name_plural = _('Access Tokens') + @property + def activation_url(self): + if self.activated: + return None + return reverse('access.activate', kwargs={'pk': self.pk, 'secret': self.secret}) + def new_instance(self): with transaction.atomic(): for instance in self.instances.filter(expires__isnull=True): diff --git a/src/c3nav/control/static/control/css/c3nav-control.css b/src/c3nav/access/static/access/css/c3nav-access.css similarity index 100% rename from src/c3nav/control/static/control/css/c3nav-control.css rename to src/c3nav/access/static/access/css/c3nav-access.css diff --git a/src/c3nav/access/templates/access/activate.html b/src/c3nav/access/templates/access/activate.html new file mode 100644 index 00000000..c9b797ef --- /dev/null +++ b/src/c3nav/access/templates/access/activate.html @@ -0,0 +1,14 @@ +{% extends 'access/base.html' %} + +{% load bootstrap3 %} +{% load i18n %} + +{% block bodyclass %}login{% endblock %} + +{% block content %} + {% if success %} +
+ {% trans 'Your access token was installed on your device!' %} +
+ {% endif %} +{% endblock %} diff --git a/src/c3nav/control/templates/control/base.html b/src/c3nav/access/templates/access/base.html similarity index 87% rename from src/c3nav/control/templates/control/base.html rename to src/c3nav/access/templates/access/base.html index 6bbdc38c..d8a088f5 100644 --- a/src/c3nav/control/templates/control/base.html +++ b/src/c3nav/access/templates/access/base.html @@ -9,14 +9,14 @@ c3nav control panel {% compress css %} - + {% endcompress %}
-

c3nav control panel

+

c3nav access control

{% block content %} {% endblock %}
diff --git a/src/c3nav/access/templates/access/fragment_token.html b/src/c3nav/access/templates/access/fragment_token.html new file mode 100644 index 00000000..87cece39 --- /dev/null +++ b/src/c3nav/access/templates/access/fragment_token.html @@ -0,0 +1,3 @@ +{% load i18n %} + +{% trans 'Activate token on this device' %} diff --git a/src/c3nav/control/templates/control/login.html b/src/c3nav/access/templates/access/login.html similarity index 92% rename from src/c3nav/control/templates/control/login.html rename to src/c3nav/access/templates/access/login.html index 43ecbcd0..b848b395 100644 --- a/src/c3nav/control/templates/control/login.html +++ b/src/c3nav/access/templates/access/login.html @@ -1,4 +1,4 @@ -{% extends 'control/base.html' %} +{% extends 'access/base.html' %} {% load bootstrap3 %} {% load i18n %} @@ -17,7 +17,7 @@

{% blocktrans %}This is the non-public backend for creation of auth tokens.{% endblocktrans %}

-

+

{% blocktrans %}Prove that you should have access{% endblocktrans %}

diff --git a/src/c3nav/control/templates/control/prove.html b/src/c3nav/access/templates/access/prove.html similarity index 80% rename from src/c3nav/control/templates/control/prove.html rename to src/c3nav/access/templates/access/prove.html index 213541c4..bd34a6ba 100644 --- a/src/c3nav/control/templates/control/prove.html +++ b/src/c3nav/access/templates/access/prove.html @@ -1,4 +1,4 @@ -{% extends 'control/base.html' %} +{% extends 'access/base.html' %} {% load bootstrap3 %} {% load i18n %} @@ -14,8 +14,10 @@ {% if success %}
{% trans 'Thanks – you get full access to the map!' %}
- {{ token }} + {% if replaced %}{% trans 'All previous tokens have been invalidated.' %}
{% endif %}
+ {% include 'access/fragment_token.html' with token=token %} + {% elif hosters %} {% if error %}
@@ -23,7 +25,7 @@ {% if error == 'invalid' %} {% trans 'Sorry.' %} {% trans 'One or more access tokens were not correct.' %} {% elif error == 'duplicate' %} - {% trans 'Sorry.' %} {% trans 'You already have an access token.' %} + {% trans 'Sorry.' %} {% trans 'You already have a valid access token.' %} {% endif %}
{% endif %} @@ -33,6 +35,11 @@ {% endfor %} +
+ +
diff --git a/src/c3nav/access/urls.py b/src/c3nav/access/urls.py new file mode 100644 index 00000000..3259a946 --- /dev/null +++ b/src/c3nav/access/urls.py @@ -0,0 +1,12 @@ +from django.conf.urls import url +from django.contrib.auth import views as auth_views + +from c3nav.access.views import activate_token, dashboard, prove + +urlpatterns = [ + url(r'^$', dashboard, name='access.dashboard'), + url(r'^prove/$', prove, name='access.prove'), + url(r'^activate/(?P[0-9]+):(?P[a-zA-Z0-9]+)/$', activate_token, name='access.activate'), + url(r'^login/$', auth_views.login, {'template_name': 'access/login.html'}, name='access.login'), + url(r'^logout/$', auth_views.logout, name='access.logout'), +] diff --git a/src/c3nav/access/views.py b/src/c3nav/access/views.py new file mode 100644 index 00000000..ba1673d1 --- /dev/null +++ b/src/c3nav/access/views.py @@ -0,0 +1,76 @@ +from collections import OrderedDict + +from django.contrib.auth.decorators import login_required +from django.db import transaction +from django.shortcuts import get_object_or_404, render + +from c3nav.access.models import AccessToken, AccessUser +from c3nav.editor.hosters import get_hoster_for_package +from c3nav.mapdata.permissions import get_nonpublic_packages + + +@login_required(login_url='/access/login/') +def dashboard(request): + return render(request, 'access/dashboard.html') + + +def prove(request): + hosters = OrderedDict((package, get_hoster_for_package(package)) for package in get_nonpublic_packages()) + + if not hosters or None in hosters.values(): + return render(request, 'access/prove.html', context={'hosters': None}) + + error = None + if request.method == 'POST': + user_id = None + for package, hoster in hosters.items(): + access_token = request.POST.get(package.name) + hoster_user_id = hoster.get_user_id_with_access_token(access_token) + if hoster_user_id is None: + return render(request, 'access/prove.html', context={ + 'hosters': hosters, + 'error': 'invalid', + }) + + if user_id is None: + user_id = hoster_user_id + + replaced = False + with transaction.atomic(): + user = AccessUser.objects.filter(user_url=user_id).first() + if user is not None: + valid_tokens = user.valid_tokens + if valid_tokens.count(): + if request.POST.get('replace') != '1': + return render(request, 'access/prove.html', context={ + 'hosters': hosters, + 'error': 'duplicate', + }) + + for token in valid_tokens: + token.expired = True + token.save() + replaced = True + else: + user = AccessUser.objects.create(user_url=user_id) + + token = user.new_token(permissions=':all', description='automatically created') + return render(request, 'access/prove.html', context={ + 'hosters': hosters, + 'success': True, + 'replaced': replaced, + 'token': token, + }) + + return render(request, 'access/prove.html', context={ + 'hosters': hosters, + 'error': error, + }) + + +def activate_token(request, pk, secret): + token = get_object_or_404(AccessToken, expired=False, id=pk, secret=secret) # noqa + + return render(request, 'access/activate.html', context={ + 'success': True, + }) diff --git a/src/c3nav/control/migrations/0002_auto_20161220_0158.py b/src/c3nav/control/migrations/0002_auto_20161220_0158.py deleted file mode 100644 index 51376a6e..00000000 --- a/src/c3nav/control/migrations/0002_auto_20161220_0158.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.10.4 on 2016-12-20 01:58 -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('control', '0001_initial'), - ] - - operations = [ - migrations.AlterField( - model_name='accessoperator', - name='description', - field=models.TextField(blank=True, null=True, verbose_name='description'), - ), - ] diff --git a/src/c3nav/control/migrations/0003_auto_20161220_0214.py b/src/c3nav/control/migrations/0003_auto_20161220_0214.py deleted file mode 100644 index fc7d7773..00000000 --- a/src/c3nav/control/migrations/0003_auto_20161220_0214.py +++ /dev/null @@ -1,30 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.10.4 on 2016-12-20 02:14 -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('control', '0002_auto_20161220_0158'), - ] - - operations = [ - migrations.RenameField( - model_name='accesstoken', - old_name='expipres', - new_name='expires', - ), - migrations.RenameField( - model_name='accesstokeninstance', - old_name='expipres', - new_name='expires', - ), - migrations.AlterField( - model_name='accessuser', - name='user_url', - field=models.CharField(help_text='Usually an URL to a profile somewhere', max_length=200, unique=True, verbose_name='access name'), - ), - ] diff --git a/src/c3nav/control/migrations/0004_auto_20161220_0253.py b/src/c3nav/control/migrations/0004_auto_20161220_0253.py deleted file mode 100644 index 7be20c2d..00000000 --- a/src/c3nav/control/migrations/0004_auto_20161220_0253.py +++ /dev/null @@ -1,25 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.10.4 on 2016-12-20 02:53 -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('control', '0003_auto_20161220_0214'), - ] - - operations = [ - migrations.AlterField( - model_name='accessoperator', - name='can_award_permissions', - field=models.CharField(max_length=2048, verbose_name='can award permissions'), - ), - migrations.AlterField( - model_name='accesstoken', - name='permissions', - field=models.CharField(max_length=2048, verbose_name='permissions'), - ), - ] diff --git a/src/c3nav/control/urls.py b/src/c3nav/control/urls.py deleted file mode 100644 index d18f897f..00000000 --- a/src/c3nav/control/urls.py +++ /dev/null @@ -1,11 +0,0 @@ -from django.conf.urls import url -from django.contrib.auth import views as auth_views - -from c3nav.control.views import dashboard, prove - -urlpatterns = [ - url(r'^$', dashboard, name='control.dashboard'), - url(r'^prove/$', prove, name='control.prove'), - url(r'^login/$', auth_views.login, {'template_name': 'control/login.html'}, name='site.login'), - url(r'^logout/$', auth_views.logout, name='site.logout'), -] diff --git a/src/c3nav/control/views.py b/src/c3nav/control/views.py deleted file mode 100644 index c233e468..00000000 --- a/src/c3nav/control/views.py +++ /dev/null @@ -1,58 +0,0 @@ -from collections import OrderedDict - -from django.contrib.auth.decorators import login_required -from django.shortcuts import render - -from c3nav.control.models import AccessUser -from c3nav.editor.hosters import get_hoster_for_package -from c3nav.mapdata.permissions import get_nonpublic_packages - - -@login_required(login_url='/control/login/') -def dashboard(request): - return render(request, 'control/dashboard.html') - - -def prove(request): - hosters = OrderedDict((package, get_hoster_for_package(package)) for package in get_nonpublic_packages()) - - if not hosters or None in hosters.values(): - return render(request, 'control/prove.html', context={'hosters': None}) - - error = None - if request.method == 'POST': - user_id = None - for package, hoster in hosters.items(): - access_token = request.POST.get(package.name) - hoster_user_id = hoster.get_user_id_with_access_token(access_token) - if hoster_user_id is None: - return render(request, 'control/prove.html', context={ - 'hosters': hosters, - 'error': 'invalid', - }) - - if user_id is None: - user_id = hoster_user_id - - user = AccessUser.objects.filter(user_url=user_id).first() - if user is not None: - if user.tokens.count(): - return render(request, 'control/prove.html', context={ - 'hosters': hosters, - 'error': 'duplicate', - }) - else: - user = AccessUser.objects.create(user_url=user_id) - token = user.tokens.create(permissions=':all', description='automatically created') - token_instance = token.new_instance() - - return render(request, 'control/prove.html', context={ - 'hosters': hosters, - 'success': True, - 'token': token_instance, - }) - - return render(request, 'control/prove.html', context={ - 'hosters': hosters, - 'error': error, - }) diff --git a/src/c3nav/settings.py b/src/c3nav/settings.py index 7f8d8689..d77432f0 100644 --- a/src/c3nav/settings.py +++ b/src/c3nav/settings.py @@ -145,10 +145,10 @@ INSTALLED_APPS = [ 'c3nav.api', 'rest_framework', 'c3nav.mapdata', + 'c3nav.access', 'c3nav.routing', 'c3nav.site', 'c3nav.editor', - 'c3nav.control', ] MIDDLEWARE_CLASSES = [ diff --git a/src/c3nav/urls.py b/src/c3nav/urls.py index ae06fd3a..e9d7f1c5 100644 --- a/src/c3nav/urls.py +++ b/src/c3nav/urls.py @@ -1,13 +1,13 @@ from django.conf.urls import include, url from django.contrib import admin +import c3nav.access.urls import c3nav.api.urls -import c3nav.control.urls import c3nav.editor.urls import c3nav.site.urls urlpatterns = [ - url(r'^control/', include(c3nav.control.urls)), + url(r'^access/', include(c3nav.access.urls)), url(r'^editor/', include(c3nav.editor.urls)), url(r'^api/', include(c3nav.api.urls, namespace='api')), url(r'^admin/', admin.site.urls),