Got admin user login working

This commit is contained in:
Tris 2020-09-14 13:34:53 +10:00
parent 65d5c9631c
commit d1698a958c
12 changed files with 145 additions and 12 deletions

View File

@ -0,0 +1,25 @@
# Generated by Django 3.1.1 on 2020-09-13 23:43
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('interface', '0016_auto_20200910_2025'),
]
operations = [
migrations.AddField(
model_name='ensemble',
name='admins',
field=models.ManyToManyField(to=settings.AUTH_USER_MODEL),
),
migrations.AlterField(
model_name='submission',
name='instrument',
field=models.CharField(max_length=100, verbose_name='Instrument / Voice'),
),
]

View File

@ -0,0 +1,25 @@
# Generated by Django 3.1.1 on 2020-09-14 00:09
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('interface', '0017_auto_20200914_0943'),
]
operations = [
migrations.AddField(
model_name='resource',
name='visible',
field=models.BooleanField(default=True),
),
migrations.AlterField(
model_name='ensemble',
name='admins',
field=models.ManyToManyField(related_name='ensembles', to=settings.AUTH_USER_MODEL),
),
]

View File

@ -28,6 +28,7 @@ class Ensemble(models.Model):
name = models.CharField(max_length=100) name = models.CharField(max_length=100)
code = models.CharField(max_length=9, default=generate_code) code = models.CharField(max_length=9, default=generate_code)
passphrase = models.CharField(max_length=100) passphrase = models.CharField(max_length=100)
admins = models.ManyToManyField('auth.User', related_name='ensembles')
def active_projects(self): def active_projects(self):
return self.projects.filter(active=True) return self.projects.filter(active=True)
@ -62,6 +63,7 @@ class Resource(models.Model):
description = models.TextField(blank=True) description = models.TextField(blank=True)
key = models.CharField(max_length=255, blank=True) key = models.CharField(max_length=255, blank=True)
media_type = models.CharField(max_length=10, choices=MEDIA_TYPES, default='*') media_type = models.CharField(max_length=10, choices=MEDIA_TYPES, default='*')
visible = models.BooleanField(default=True)
def key_template(self): def key_template(self):
return "{}/${{filename}}".format(slugify(self.name)) return "{}/${{filename}}".format(slugify(self.name))

View File

@ -29,12 +29,9 @@
Ensembles</span></a> Ensembles</span></a>
</li> </li>
{% endif %} {% endif %}
{% if request.is_admin %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href=""><i class="fas fa-question"></i> <span class="">About</span></a> <a href="{% url 'manage' %}"><i class="fas fa-user-lock"></i></a>
</li>
{% if request.user.is_authenticated %}
<li class="nav-item">
<a href="/admin"><i class="fas fa-key"></i></a>
</li> </li>
{% endif %} {% endif %}
</ul> </ul>

View File

@ -0,0 +1,20 @@
{% extends "base.html" %}
{% block content %}
<div class="narrow">
<h3>Manage {{ ensemble.name }}</h3>
<p>
Joining code for participants:<br/>
<a href="{{ ensemble_url }}">{{ ensemble_url }}</a>
</p>
<p>
Sorry, not much you can do here yet.
<ul>
<li>Should be able to create new projects.</li>
</ul>
<br/>
Logged in as {{ request.user }} [<a href="{% url 'logout' %}">Logout</a>]
</p>
</div>
{% endblock %}

View File

@ -11,7 +11,7 @@
<tr> <tr>
<td>{{ submission.date|timesince }} ago</td> <td>{{ submission.date|timesince }} ago</td>
<td>{{ submission.name }} ({{ submission.instrument }})</td> <td>{{ submission.name }} ({{ submission.instrument }})</td>
{% if request.user.is_authenticated %} {% if request.is_admin %}
<td> <td>
<a href="{% url 'submission_detail' project=project.pk pk=submission.pk %}"><i class="fas fa-info-circle"></i></a> <a href="{% url 'submission_detail' project=project.pk pk=submission.pk %}"><i class="fas fa-info-circle"></i></a>
&nbsp; &nbsp;

View File

@ -1,6 +1,9 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block content %} {% block content %}
{% if not request.user.is_authenticated %}
<a href="{% url 'login' %}" style="float: right"><i class="fa fa-key"></i></a>
{% endif %}
<div style="display: flex"> <div style="display: flex">
{% if current %} {% if current %}
<div> <div>

View File

@ -14,7 +14,7 @@
<i class="fas fa-download"></i> Download <i class="fas fa-download"></i> Download
</a> </a>
{% endif %} {% endif %}
{% if request.user.is_authenticated %} {% if request.is_admin %}
<a href="{% url 'resource_upload' project=project.pk pk=resource.pk %}"> <a href="{% url 'resource_upload' project=project.pk pk=resource.pk %}">
<i class="fas fa-upload"></i> Upload <i class="fas fa-upload"></i> Upload
</a> </a>
@ -28,7 +28,7 @@
{% endwith %} {% endwith %}
{% endfor %} {% endfor %}
</div> </div>
{% if request.user.is_authenticated %} {% if request.is_admin %}
<div class="admin-actions"> <div class="admin-actions">
<a href="{% url 'resource_create' project=project.pk %}"><i class="fas fa-plus-circle"></i> Add new</a> <a href="{% url 'resource_create' project=project.pk %}"><i class="fas fa-plus-circle"></i> Add new</a>
</div> </div>

View File

@ -0,0 +1,11 @@
{% extends "base.html" %}
{% block content %}
<form method="POST" class="vertical">
{% csrf_token %}
{{ form }}
<div class="form-actions">
<button type="submit">Login</button>
</div>
</form>
{% endblock %}

View File

@ -1,10 +1,16 @@
from django.urls import path from django.urls import path
from django.contrib.auth import views as auth_views
from . import views from . import views
urlpatterns = [ urlpatterns = [
path('', views.EnsembleDetailView.as_view(), name='ensemble_detail'),
path('login', auth_views.LoginView.as_view(), name='login'),
path('logout', views.logout, name='logout'),
path('register', views.register, name="register"), path('register', views.register, name="register"),
path('manage', views.ManageView.as_view(), name="manage"),
path('', views.EnsembleDetailView.as_view(), name='ensemble_detail'),
path('projects/<int:pk>', views.ProjectDetailView.as_view(), name="project_detail"), path('projects/<int:pk>', views.ProjectDetailView.as_view(), name="project_detail"),
path('projects/<int:project>/page/<int:pk>', views.WikiView.as_view(), name="wiki"), path('projects/<int:project>/page/<int:pk>', views.WikiView.as_view(), name="wiki"),

View File

@ -6,6 +6,7 @@ from django.views.generic.edit import CreateView
from django.views.generic.base import ContextMixin from django.views.generic.base import ContextMixin
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.core.exceptions import SuspiciousOperation from django.core.exceptions import SuspiciousOperation
from django.contrib import auth
from markdown2 import markdown from markdown2 import markdown
from datetime import datetime from datetime import datetime
@ -19,14 +20,26 @@ import logging
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class EnsembleMixin(object): class EnsembleMixin(object):
admin_required = False
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
request.ensemble_id = request.session.get('ensemble') request.ensemble_id = request.session.get('ensemble')
request.is_admin = request.user.is_superuser
if not request.ensemble_id: if not request.ensemble_id:
return redirect('register') return redirect('register')
if not request.is_admin and request.user.is_authenticated:
try:
request.user.ensembles.get(pk=request.ensemble_id)
request.is_admin = True
except models.Ensemble.DoesNotExist:
pass
if self.admin_required and not request.is_admin:
return redirect('login')
return super().dispatch(request, *args, **kwargs) return super().dispatch(request, *args, **kwargs)
class ProjectMixin(EnsembleMixin): class ProjectMixin(EnsembleMixin):
@ -134,6 +147,24 @@ def register(request):
return render(request, 'interface/register.html', {'form': form, 'current': current}) return render(request, 'interface/register.html', {'form': form, 'current': current})
def on_login(sender, **kwargs):
request = kwargs['request']
registered = request.session.get('registered', {})
for e in kwargs['user'].ensembles.all():
if not e.code in registered:
registered[e.code] = e.pk
request.session['registered'] = registered
auth.signals.user_logged_in.connect(on_login)
def logout(request):
ensemble = request.session.get('ensemble')
registered = request.session.get('registered', {})
auth.logout(request)
request.session['ensemble'] = ensemble
request.session['registered'] = registered
return redirect('/')
class EnsembleDetailView(EnsembleMixin, DetailView): class EnsembleDetailView(EnsembleMixin, DetailView):
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
@ -188,7 +219,7 @@ class SubmissionDetailView(ProjectMixin, S3CompleteMixin, DetailView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
if self.request.user.is_authenticated: if self.request.is_admin:
context['download'] = self.object.presigned_url() context['download'] = self.object.presigned_url()
return context return context
@ -219,7 +250,7 @@ class ResourceCreateView(ProjectMixin, CreateView):
def form_valid(self, form): def form_valid(self, form):
if not self.request.user.is_authenticated: if not self.request.is_admin:
raise SuspiciousOperation("Must be logged in to create resources") raise SuspiciousOperation("Must be logged in to create resources")
self.object = form.save(commit=False) self.object = form.save(commit=False)
@ -250,3 +281,16 @@ class ResourceCompleteView(S3CompleteMixin, SingleObjectMixin, RedirectView):
class ResourceListView(ProjectMixin, ListView): class ResourceListView(ProjectMixin, ListView):
model = models.Resource model = models.Resource
def get_queryset(self):
return super().get_queryset().filter(visible=True)
class ManageView(EnsembleMixin, TemplateView):
template_name = 'interface/manage.html'
admin_required = True
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['ensemble'] = models.Ensemble.objects.get(pk=self.request.ensemble_id)
context['ensemble_url'] = self.request.build_absolute_uri('/?code={0}'.format(context['ensemble'].ensemble_code()))
return context

View File

@ -99,7 +99,7 @@ AUTH_PASSWORD_VALIDATORS = [
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
}, },
] ]
LOGIN_REDIRECT_URL = "/"
# Internationalization # Internationalization
# https://docs.djangoproject.com/en/3.1/topics/i18n/ # https://docs.djangoproject.com/en/3.1/topics/i18n/