365 lines
12 KiB
Python
365 lines
12 KiB
Python
from django.shortcuts import render, get_object_or_404, redirect, resolve_url
|
|
from django.views.generic import TemplateView, View, RedirectView
|
|
from django.views.generic.detail import DetailView, SingleObjectMixin
|
|
from django.views.generic.list import ListView
|
|
from django.views.generic.edit import CreateView, UpdateView, FormView
|
|
from django.views.generic.base import ContextMixin
|
|
from django.http import HttpResponseRedirect
|
|
from django.core.exceptions import SuspiciousOperation
|
|
from django.contrib import auth
|
|
|
|
from markdown2 import markdown
|
|
from datetime import datetime
|
|
from urllib.parse import urlparse, urlencode
|
|
import os.path
|
|
|
|
from . import models, forms
|
|
|
|
from base64 import b64decode
|
|
|
|
import logging
|
|
logger = logging.getLogger(__name__)
|
|
|
|
class EnsembleMixin(object):
|
|
admin_required = False
|
|
|
|
def dispatch(self, request, *args, **kwargs):
|
|
|
|
request.ensemble_id = request.session.get('ensemble')
|
|
request.is_admin = request.user.is_superuser
|
|
|
|
if not request.ensemble_id:
|
|
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)
|
|
|
|
class ProjectMixin(EnsembleMixin):
|
|
|
|
def get_project(self):
|
|
if not hasattr(self, '_project'):
|
|
self._project = get_object_or_404(models.Project,
|
|
pk=self.kwargs['project'], ensemble=self.request.ensemble_id)
|
|
return self._project
|
|
|
|
def get_queryset(self):
|
|
return super().get_queryset().filter(project=self.get_project())
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
context['project'] = self.get_project()
|
|
return context
|
|
|
|
class S3UploadMixin(ProjectMixin):
|
|
accept_files = ''
|
|
|
|
def get_accept_files(self):
|
|
return self.accept_files
|
|
|
|
def get_cancel_url(self):
|
|
return self.cancel_url
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
|
|
success_url = self.request.build_absolute_uri(self.get_success_url())
|
|
|
|
key_template = self.object.key_template()
|
|
|
|
project = self.get_project()
|
|
context['upload'] = project.presigned_post(key_template,
|
|
fields={'success_action_redirect': success_url},
|
|
conditions=[["starts-with", "$success_action_redirect", ""]])
|
|
context['ajax_upload'] = project.presigned_post(key_template)
|
|
context['success_url'] = success_url
|
|
context['cancel_url'] = self.get_cancel_url()
|
|
context['accept_files'] = self.accept_files
|
|
return context
|
|
|
|
class S3CompleteView(SingleObjectMixin, RedirectView):
|
|
|
|
def complete(self, key):
|
|
self.object.key = key
|
|
self.object.save()
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
self.object = self.get_object()
|
|
|
|
if 'key' in request.GET:
|
|
self.complete(request.GET['key'])
|
|
elif 'location' in request.GET:
|
|
uri = urlparse(request.GET['location'])
|
|
bucket, key = uri.path[1:].split('/', 1)
|
|
if bucket != models.BUCKET:
|
|
key = uri.path[1:]
|
|
self.complete(key)
|
|
else:
|
|
raise KeyError("No key or location found")
|
|
|
|
return super().get(request, *args, **kwargs)
|
|
|
|
|
|
def register(request):
|
|
|
|
if 'clear' in request.GET:
|
|
request.session.clear()
|
|
|
|
|
|
request.ensemble_id = request.session.get('ensemble')
|
|
registered = request.session.setdefault('registered', {})
|
|
|
|
code = request.GET.get('code', '').replace('-', '')
|
|
|
|
# check if already joined
|
|
if code in registered:
|
|
request.session['ensemble'] = registered[code]
|
|
return redirect('ensemble_detail')
|
|
|
|
if request.user.is_superuser and code:
|
|
request.session['ensemble'] = models.Ensemble.objects.get(code=code).pk
|
|
return redirect('ensemble_detail')
|
|
|
|
if request.method == "POST":
|
|
form = forms.CodeForm(request.POST)
|
|
|
|
if form.is_valid():
|
|
|
|
data = form.cleaned_data
|
|
try:
|
|
ensemble = models.Ensemble.objects.get(code=data['code'].replace('-', ''))
|
|
if ensemble.passphrase == data['passphrase']:
|
|
request.session['ensemble'] = ensemble.pk
|
|
registered[ensemble.code] = ensemble.pk
|
|
return redirect('ensemble_detail')
|
|
except models.Ensemble.DoesNotExist:
|
|
form.add_error(None, "Incorrect code or passphrase")
|
|
|
|
|
|
|
|
else:
|
|
form = forms.CodeForm(initial=request.GET)
|
|
|
|
if request.user.is_superuser:
|
|
current = models.Ensemble.objects.all()
|
|
else:
|
|
current = models.Ensemble.objects.filter(pk__in=registered.values())
|
|
|
|
return render(request, 'interface/register.html', {'form': form, 'current': current})
|
|
|
|
|
|
def on_login(sender, **kwargs):
|
|
user = kwargs['user']
|
|
request = kwargs['request']
|
|
registered = request.session.get('registered', {})
|
|
for e in 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):
|
|
|
|
def dispatch(self, request, *args, **kwargs):
|
|
# capture provided urls
|
|
if 'code' in request.GET:
|
|
return redirect('/register?code={0}'.format(request.GET['code']))
|
|
|
|
return super().dispatch(request, *args, **kwargs)
|
|
|
|
def get_object(self):
|
|
return models.Ensemble.objects.get(pk=self.request.ensemble_id)
|
|
|
|
class ProjectDetailView(EnsembleMixin, DetailView):
|
|
|
|
def get_queryset(self):
|
|
return models.Project.objects.filter(ensemble=self.request.ensemble_id)
|
|
|
|
class WikiView(ProjectMixin, DetailView):
|
|
template_name = 'interface/wiki.html'
|
|
model = models.WikiPage
|
|
|
|
def get_context_data(self, **kwargs):
|
|
data = super().get_context_data(**kwargs)
|
|
data['wiki_html'] = markdown(self.object.markdown)
|
|
return data
|
|
|
|
class WikiCreateView(ProjectMixin, CreateView):
|
|
admin_required = True
|
|
model = models.WikiPage
|
|
fields = ['title', 'markdown']
|
|
|
|
class WikiEditView(ProjectMixin, UpdateView):
|
|
admin_required = True
|
|
model = models.WikiPage
|
|
fields = ['title', 'markdown']
|
|
|
|
class SubmissionCreateView(ProjectMixin, FormView):
|
|
#model = models.Submission
|
|
#fields = ['name', 'instrument', 'url', 'notes']
|
|
form_class = forms.SubmissionForm
|
|
template_name = "interface/submission_create.html"
|
|
|
|
def form_valid(self, form):
|
|
self.object = form.save(commit=False)
|
|
self.object.project = self.get_project()
|
|
self.object.save()
|
|
|
|
self.request.session['name'] = self.object.name
|
|
self.request.session['instrument'] = self.object.instrument
|
|
|
|
if form.cleaned_data['method'] == 'link':
|
|
return redirect('submission_link', project=self.object.project.pk, pk=self.object.pk)
|
|
|
|
return redirect('submission_upload', project=self.object.project.pk, pk=self.object.pk)
|
|
|
|
def get_initial(self):
|
|
return { k: self.request.session.get(k) for k in ('name', 'instrument') }
|
|
|
|
class SubmissionCompleteView(ProjectMixin, S3CompleteView):
|
|
model = models.Submission
|
|
|
|
def complete(self, key):
|
|
self.object.url = key
|
|
self.object.private = False
|
|
self.object.complete = True
|
|
self.object.save()
|
|
|
|
def get_redirect_url(self, **kwargs):
|
|
return resolve_url('submission_detail', **self.kwargs)
|
|
|
|
class SubmissionDetailView(ProjectMixin, DetailView):
|
|
model = models.Submission
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
context['can_download'] = self.request.is_admin
|
|
return context
|
|
|
|
class SubmissionUploadView(S3UploadMixin, DetailView):
|
|
template_name = 'interface/s3_upload.html'
|
|
model = models.Submission
|
|
accept_files = "video/*"
|
|
|
|
def get_success_url(self):
|
|
return resolve_url('submission_complete', **self.kwargs)
|
|
|
|
def get_cancel_url(self):
|
|
return resolve_url('submission_cancel', **self.kwargs)
|
|
|
|
class SubmissionLinkView(ProjectMixin, UpdateView):
|
|
model = models.Submission
|
|
template_name = 'interface/submission_link.html'
|
|
fields = ['url']
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
context['cancel_url'] = self.get_cancel_url()
|
|
return context
|
|
|
|
def get_success_url(self):
|
|
return resolve_url('submission_detail', **self.kwargs)
|
|
|
|
def get_cancel_url(self):
|
|
return resolve_url('submission_cancel', **self.kwargs)
|
|
|
|
def form_valid(self, form):
|
|
self.object = form.save(commit=False)
|
|
self.object.complete = True
|
|
self.object.private = True
|
|
self.object.save()
|
|
return redirect(self.get_success_url())
|
|
|
|
class SubmissionCancelView(ProjectMixin, SingleObjectMixin, View):
|
|
model = models.Submission
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
self.object = self.get_object()
|
|
self.object.delete()
|
|
return redirect('project_detail', pk=kwargs['project'])
|
|
|
|
class SubmissionListView(ProjectMixin, ListView):
|
|
model = models.Submission
|
|
admin_required = True
|
|
|
|
def get_queryset(self):
|
|
return super().get_queryset().filter(complete=True).order_by('-pk')
|
|
|
|
class ResourceCreateView(ProjectMixin, CreateView):
|
|
model = models.Resource
|
|
fields = ['name', 'media_type', 'description']
|
|
template_name = 'interface/project_form.html'
|
|
title = "Add a new resource"
|
|
admin_required = True
|
|
|
|
def form_valid(self, form):
|
|
|
|
self.object = form.save(commit=False)
|
|
self.object.project = self.get_project()
|
|
self.object.save()
|
|
return redirect('resource_upload', project=self.object.project_id, pk=self.object.pk)
|
|
|
|
class ResourceUploadView(S3UploadMixin, DetailView):
|
|
model = models.Resource
|
|
template_name = 'interface/s3_upload.html'
|
|
|
|
def get_accept_files(self):
|
|
return self.object.accept()
|
|
|
|
def get_success_url(self):
|
|
return resolve_url('resource_complete', **self.kwargs)
|
|
|
|
def get_cancel_url(self):
|
|
return resolve_url('resource_list', project=self.kwargs['project'])
|
|
|
|
class ResourceCompleteView(ProjectMixin, S3CompleteView):
|
|
model = models.Resource
|
|
|
|
def get_redirect_url(self, **kwargs):
|
|
return resolve_url('resource_list', project=self.kwargs['project'])
|
|
|
|
|
|
class ResourceListView(ProjectMixin, ListView):
|
|
model = models.Resource
|
|
|
|
def get_queryset(self):
|
|
qs = super().get_queryset()
|
|
if not self.request.is_admin:
|
|
qs = qs.filter(visible=True)
|
|
return qs
|
|
|
|
class ResourceEditView(ProjectMixin, UpdateView):
|
|
admin_required = True
|
|
model = models.Resource
|
|
fields = ['name', 'description', 'visible']
|
|
template_name = 'interface/default_form.html'
|
|
|
|
def get_success_url(self):
|
|
return resolve_url('resource_list', project=self.kwargs['project'])
|
|
|
|
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 |