rename control → access and add some more stuff
This commit is contained in:
parent
2fcbfe6312
commit
8026b78f42
21 changed files with 183 additions and 169 deletions
|
@ -3,7 +3,7 @@ from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.utils.translation import ugettext_lazy as _
|
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):
|
class AccessOperatorInline(admin.StackedInline):
|
||||||
|
@ -29,7 +29,7 @@ admin.site.register(User, UserAdmin)
|
||||||
class AccessTokenInline(admin.TabularInline):
|
class AccessTokenInline(admin.TabularInline):
|
||||||
model = AccessToken
|
model = AccessToken
|
||||||
show_change_link = True
|
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):
|
def has_add_permission(self, request):
|
||||||
return False
|
return False
|
||||||
|
@ -55,9 +55,9 @@ class AccessTokenInstanceInline(admin.TabularInline):
|
||||||
@admin.register(AccessToken)
|
@admin.register(AccessToken)
|
||||||
class AccessTokenAdmin(admin.ModelAdmin):
|
class AccessTokenAdmin(admin.ModelAdmin):
|
||||||
inlines = (AccessTokenInstanceInline,)
|
inlines = (AccessTokenInstanceInline,)
|
||||||
list_display = ('__str__', 'user', 'permissions', 'author', 'creation_date', 'expires')
|
list_display = ('__str__', 'user', 'permissions', 'author', 'creation_date', 'expires', 'expired')
|
||||||
fields = ('user', 'permissions', 'author', 'creation_date', 'expires')
|
fields = ('user', 'permissions', 'author', 'creation_date', 'expires', 'expired')
|
||||||
readonly_fields = ('user', 'creation_date')
|
readonly_fields = ('user', 'creation_date', 'expired')
|
||||||
|
|
||||||
def has_add_permission(self, request):
|
def has_add_permission(self, request):
|
||||||
return False
|
return False
|
|
@ -1,5 +1,5 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- 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 __future__ import unicode_literals
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
@ -20,8 +20,8 @@ class Migration(migrations.Migration):
|
||||||
name='AccessOperator',
|
name='AccessOperator',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('description', models.TextField(verbose_name='description')),
|
('description', models.TextField(blank=True, null=True, verbose_name='description')),
|
||||||
('can_award_permissions', models.TextField(verbose_name='can award permissions')),
|
('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_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')),
|
('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)),
|
('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',
|
name='AccessToken',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('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')),
|
('description', models.CharField(max_length=200, verbose_name='description')),
|
||||||
('creation_date', models.DateTimeField(auto_now_add=True, verbose_name='creation date')),
|
('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')),
|
('author', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL, verbose_name='creator')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
|
@ -52,8 +53,8 @@ class Migration(migrations.Migration):
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('secret', models.CharField(max_length=42, verbose_name='access secret')),
|
('secret', models.CharField(max_length=42, verbose_name='access secret')),
|
||||||
('creation_date', models.DateTimeField(auto_now_add=True, verbose_name='creation date')),
|
('creation_date', models.DateTimeField(auto_now_add=True, verbose_name='creation date')),
|
||||||
('expipres', models.DateTimeField(null=True)),
|
('expires', 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')),
|
('access_token', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='instances', to='access.AccessToken', verbose_name='Access Token')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name_plural': 'Access Tokens Instance',
|
'verbose_name_plural': 'Access Tokens Instance',
|
||||||
|
@ -64,10 +65,10 @@ class Migration(migrations.Migration):
|
||||||
name='AccessUser',
|
name='AccessUser',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('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')),
|
('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')),
|
('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={
|
options={
|
||||||
'verbose_name_plural': 'Access Users',
|
'verbose_name_plural': 'Access Users',
|
||||||
|
@ -77,6 +78,6 @@ class Migration(migrations.Migration):
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='accesstoken',
|
model_name='accesstoken',
|
||||||
name='user',
|
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'),
|
||||||
),
|
),
|
||||||
]
|
]
|
26
src/c3nav/access/migrations/0002_auto_20161221_1739.py
Normal file
26
src/c3nav/access/migrations/0002_auto_20161221_1739.py
Normal file
|
@ -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,
|
||||||
|
),
|
||||||
|
]
|
|
@ -3,6 +3,8 @@ from datetime import timedelta
|
||||||
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.db import models, transaction
|
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 import timezone
|
||||||
from django.utils.crypto import get_random_string
|
from django.utils.crypto import get_random_string
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
@ -35,6 +37,14 @@ class AccessUser(models.Model):
|
||||||
verbose_name = _('Access User')
|
verbose_name = _('Access User')
|
||||||
verbose_name_plural = _('Access Users')
|
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):
|
def __str__(self):
|
||||||
return self.user_url
|
return self.user_url
|
||||||
|
|
||||||
|
@ -47,11 +57,20 @@ class AccessToken(models.Model):
|
||||||
description = models.CharField(_('description'), max_length=200)
|
description = models.CharField(_('description'), max_length=200)
|
||||||
creation_date = models.DateTimeField(_('creation date'), auto_now_add=True)
|
creation_date = models.DateTimeField(_('creation date'), auto_now_add=True)
|
||||||
expires = models.DateTimeField(null=True, blank=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:
|
class Meta:
|
||||||
verbose_name = _('Access Token')
|
verbose_name = _('Access Token')
|
||||||
verbose_name_plural = _('Access Tokens')
|
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):
|
def new_instance(self):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
for instance in self.instances.filter(expires__isnull=True):
|
for instance in self.instances.filter(expires__isnull=True):
|
14
src/c3nav/access/templates/access/activate.html
Normal file
14
src/c3nav/access/templates/access/activate.html
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{% extends 'access/base.html' %}
|
||||||
|
|
||||||
|
{% load bootstrap3 %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block bodyclass %}login{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% if success %}
|
||||||
|
<div class="alert alert-success">
|
||||||
|
<strong>{% trans 'Your access token was installed on your device!' %}</strong>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
|
@ -9,14 +9,14 @@
|
||||||
<title>c3nav control panel</title>
|
<title>c3nav control panel</title>
|
||||||
{% compress css %}
|
{% compress css %}
|
||||||
<link href="{% static 'bootstrap/css/bootstrap.css' %}" rel="stylesheet">
|
<link href="{% static 'bootstrap/css/bootstrap.css' %}" rel="stylesheet">
|
||||||
<link href="{% static 'control/css/c3nav-control.css' %}" rel="stylesheet">
|
<link href="{% static 'access/css/c3nav-access.css' %}" rel="stylesheet">
|
||||||
{% endcompress %}
|
{% endcompress %}
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="{% block bodyclass %}{% endblock %}">
|
<body class="{% block bodyclass %}{% endblock %}">
|
||||||
|
|
||||||
<div class="container" id="main">
|
<div class="container" id="main">
|
||||||
<h1>c3nav control panel</h1>
|
<h1>c3nav access control</h1>
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</div>
|
</div>
|
3
src/c3nav/access/templates/access/fragment_token.html
Normal file
3
src/c3nav/access/templates/access/fragment_token.html
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
<a href="{{ token.activation_url }}" class="btn btn-default btn-block">{% trans 'Activate token on this device' %}</a>
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends 'control/base.html' %}
|
{% extends 'access/base.html' %}
|
||||||
|
|
||||||
{% load bootstrap3 %}
|
{% load bootstrap3 %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
@ -17,7 +17,7 @@
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<p>{% blocktrans %}This is the non-public backend for creation of auth tokens.{% endblocktrans %}</p>
|
<p>{% blocktrans %}This is the non-public backend for creation of auth tokens.{% endblocktrans %}</p>
|
||||||
|
|
||||||
<p><a class="btn btn-sm btn-default btn-block" href="{% url 'control.prove' %}">
|
<p><a class="btn btn-sm btn-default btn-block" href="{% url 'access.prove' %}">
|
||||||
{% blocktrans %}Prove that you should have access{% endblocktrans %}
|
{% blocktrans %}Prove that you should have access{% endblocktrans %}
|
||||||
</a></p>
|
</a></p>
|
||||||
</form>
|
</form>
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends 'control/base.html' %}
|
{% extends 'access/base.html' %}
|
||||||
|
|
||||||
{% load bootstrap3 %}
|
{% load bootstrap3 %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
@ -14,8 +14,10 @@
|
||||||
{% if success %}
|
{% if success %}
|
||||||
<div class="alert alert-success">
|
<div class="alert alert-success">
|
||||||
<strong>{% trans 'Thanks – you get full access to the map!' %}</strong><br>
|
<strong>{% trans 'Thanks – you get full access to the map!' %}</strong><br>
|
||||||
{{ token }}
|
{% if replaced %}{% trans 'All previous tokens have been invalidated.' %}<br>{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
{% include 'access/fragment_token.html' with token=token %}
|
||||||
|
|
||||||
{% elif hosters %}
|
{% elif hosters %}
|
||||||
{% if error %}
|
{% if error %}
|
||||||
<div class="alert alert-dismissible alert-danger">
|
<div class="alert alert-dismissible alert-danger">
|
||||||
|
@ -23,7 +25,7 @@
|
||||||
{% if error == 'invalid' %}
|
{% if error == 'invalid' %}
|
||||||
<strong>{% trans 'Sorry.' %}</strong> {% trans 'One or more access tokens were not correct.' %}
|
<strong>{% trans 'Sorry.' %}</strong> {% trans 'One or more access tokens were not correct.' %}
|
||||||
{% elif error == 'duplicate' %}
|
{% elif error == 'duplicate' %}
|
||||||
<strong>{% trans 'Sorry.' %}</strong> {% trans 'You already have an access token.' %}
|
<strong>{% trans 'Sorry.' %}</strong> {% trans 'You already have a valid access token.' %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -33,6 +35,11 @@
|
||||||
<input type="password" class="form-control" id="hoster{{ forloop.counter0 }}" name="{{ package.name }}" placeholder="{% trans 'Access Token' %}">
|
<input type="password" class="form-control" id="hoster{{ forloop.counter0 }}" name="{{ package.name }}" placeholder="{% trans 'Access Token' %}">
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
<div class="checkbox">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="replace" value="1"> {% trans 'Invalidate previus token(s).' %}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<button type="submit" class="btn btn-primary btn-block btn-lg">{% trans 'Submit' %}</button>
|
<button type="submit" class="btn btn-primary btn-block btn-lg">{% trans 'Submit' %}</button>
|
||||||
</div>
|
</div>
|
12
src/c3nav/access/urls.py
Normal file
12
src/c3nav/access/urls.py
Normal file
|
@ -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<pk>[0-9]+):(?P<secret>[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'),
|
||||||
|
]
|
76
src/c3nav/access/views.py
Normal file
76
src/c3nav/access/views.py
Normal file
|
@ -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,
|
||||||
|
})
|
|
@ -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'),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -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'),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -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'),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -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'),
|
|
||||||
]
|
|
|
@ -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,
|
|
||||||
})
|
|
|
@ -145,10 +145,10 @@ INSTALLED_APPS = [
|
||||||
'c3nav.api',
|
'c3nav.api',
|
||||||
'rest_framework',
|
'rest_framework',
|
||||||
'c3nav.mapdata',
|
'c3nav.mapdata',
|
||||||
|
'c3nav.access',
|
||||||
'c3nav.routing',
|
'c3nav.routing',
|
||||||
'c3nav.site',
|
'c3nav.site',
|
||||||
'c3nav.editor',
|
'c3nav.editor',
|
||||||
'c3nav.control',
|
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE_CLASSES = [
|
MIDDLEWARE_CLASSES = [
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
from django.conf.urls import include, url
|
from django.conf.urls import include, url
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
|
import c3nav.access.urls
|
||||||
import c3nav.api.urls
|
import c3nav.api.urls
|
||||||
import c3nav.control.urls
|
|
||||||
import c3nav.editor.urls
|
import c3nav.editor.urls
|
||||||
import c3nav.site.urls
|
import c3nav.site.urls
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^control/', include(c3nav.control.urls)),
|
url(r'^access/', include(c3nav.access.urls)),
|
||||||
url(r'^editor/', include(c3nav.editor.urls)),
|
url(r'^editor/', include(c3nav.editor.urls)),
|
||||||
url(r'^api/', include(c3nav.api.urls, namespace='api')),
|
url(r'^api/', include(c3nav.api.urls, namespace='api')),
|
||||||
url(r'^admin/', admin.site.urls),
|
url(r'^admin/', admin.site.urls),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue