diff --git a/interface/templates/interface/submission_detail.html b/interface/templates/interface/submission_detail.html
index 06a98a7..901e1f9 100644
--- a/interface/templates/interface/submission_detail.html
+++ b/interface/templates/interface/submission_detail.html
@@ -1,4 +1,4 @@
-{% extends "interface/project.html" %}
+{% extends "interface/project_base.html" %}
{% block page %}
diff --git a/interface/templates/interface/submission_upload.html b/interface/templates/interface/submission_upload.html
index cdaf7d3..836102a 100644
--- a/interface/templates/interface/submission_upload.html
+++ b/interface/templates/interface/submission_upload.html
@@ -19,7 +19,7 @@
Cancel
+ href="{{ cancel_url }}">Cancel
@@ -53,8 +53,8 @@ function startUpload(e) {
//$('input[name="file"]').attr('disabled', true);
// patch form to use our ajax policy
- $('input[name="policy"]').val("{{ ajax_post.fields.policy }}");
- $('input[name="signature"]').val("{{ ajax_post.fields.signature }}");
+ $('input[name="policy"]').val("{{ ajax_upload.fields.policy }}");
+ $('input[name="signature"]').val("{{ ajax_upload.fields.signature }}");
$('input[name="success_action_redirect"]').remove();
@@ -81,7 +81,7 @@ function startUpload(e) {
if (xhr.status == 204) {
status.html("Finished upload");
let s3_location = xhr.getResponseHeader("Location");
- location.href += "/complete?location=" + s3_location;
+ location.href = "{{ success_url }}?location=" + s3_location;
} else {
status.html("Something went wrong");
console.log(xhr.responseText);
diff --git a/interface/templates/interface/wiki.html b/interface/templates/interface/wiki.html
index 665bb63..16bfcf7 100644
--- a/interface/templates/interface/wiki.html
+++ b/interface/templates/interface/wiki.html
@@ -1,4 +1,4 @@
-{% extends "interface/project.html" %}
+{% extends "interface/project_base.html" %}
{% block page %}
diff --git a/interface/urls.py b/interface/urls.py
index 758b2cf..b47621a 100644
--- a/interface/urls.py
+++ b/interface/urls.py
@@ -3,12 +3,18 @@ from django.urls import path
from . import views
urlpatterns = [
- path('', views.my_projects, name='my_projects'),
+ path('', views.EnsembleDetailView.as_view(), name='ensemble_detail'),
path('register', views.register, name="register"),
- path('projects/', views.project_page, name="project"),
- path('projects//page/', views.wiki_page, name="wiki"),
- path('projects//submission', views.create_submission, name="create_submission"),
- path('projects//submission/', views.submission, name="submission"),
- path('projects//submission//complete', views.complete_submission, name="complete_submission"),
- path('projects//submission//cancel', views.cancel_submission, name="cancel_submission"),
+ path('projects/', views.ProjectDetailView.as_view(), name="project_detail"),
+ path('projects//page/', views.WikiView.as_view(), name="wiki"),
+
+ path('projects//submission', views.SubmissionCreateView.as_view(), name="submission_create"),
+ path('projects//submission/', views.SubmissionDetailView.as_view(), name="submission_detail"),
+ path('projects//submission//upload', views.SubmissionUploadView.as_view(), name="submission_upload"),
+ path('projects//submission//cancel', views.SubmissionCancelView.as_view(), name="submission_cancel"),
+
+ path('projects//resources', views.ResourceListView.as_view(), name="resource_list"),
+ path('projects//resources/add', views.ResourceCreateView.as_view(), name="resource_create"),
+ path('projects//resources/', views.ResourceUploadView.as_view(), name="resource_upload"),
+ path('projects//resources//complete', views.ResourceCompleteView.as_view(), name="resource_complete"),
]
\ No newline at end of file
diff --git a/interface/views.py b/interface/views.py
index f49d870..d6c9279 100644
--- a/interface/views.py
+++ b/interface/views.py
@@ -1,23 +1,91 @@
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
+from django.views.generic.base import ContextMixin
+from django.http import HttpResponseRedirect
+from django.core.exceptions import SuspiciousOperation
from markdown2 import markdown
from datetime import datetime
from urllib.parse import urlparse
from . import models, forms
-from .decorators import check_allowed
from base64 import b64decode
import logging
logger = logging.getLogger(__name__)
+class EnsembleMixin(object):
+
+ def dispatch(self, request, *args, **kwargs):
+
+ request.ensemble_id = request.session.get('ensemble')
+
+ if not request.ensemble_id:
+ return redirect('register')
+
+ 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):
+
+ 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()
+ return context
+
+class S3CompleteMixin(View):
+ always_set = False
+
+ def get(self, request, *args, **kwargs):
+ self.object = self.get_object()
+
+ if self.always_set or not self.object.key:
+ uri = urlparse(request.GET['location'])
+ self.object.key = uri.path[1:]
+ self.object.save()
+
+ return super().get(request, *args, **kwargs)
-def forbidden(request):
- return render(request, 'interface/forbidden.html', {})
def register(request):
-
+
+ if 'clear' in request.GET:
+ request.session.clear()
+
+
request.ensemble_id = request.session.get('ensemble')
registered = request.session.setdefault('registered', {})
@@ -32,7 +100,7 @@ def register(request):
if ensemble.passphrase == data['passphrase']:
request.session['ensemble'] = ensemble.pk
registered[ensemble.code] = ensemble.pk
- return redirect('my_projects')
+ return redirect('ensemble_detail')
except models.Ensemble.DoesNotExist:
form.add_error(None, "Incorrect code or passphrase")
@@ -46,89 +114,104 @@ def register(request):
return render(request, 'interface/register.html', {'form': form, 'current': current})
-@check_allowed
-def my_projects(request):
- ensemble = get_object_or_404(models.Ensemble, pk=request.ensemble_id)
- context = {'ensemble': ensemble}
- return render(request, 'interface/project_list.html', context)
-
-@check_allowed
-def project_page(request, project_id):
- project = get_object_or_404(models.Project, pk=project_id, ensemble_id=request.ensemble_id)
- context = {'project': project}
- return render(request, 'interface/project.html', context)
-
-@check_allowed
-def wiki_page(request, project_id, wiki_id):
- wiki = get_object_or_404(models.WikiPage, pk=wiki_id, project=project_id, project__ensemble=request.ensemble_id)
- context = {'project': wiki.project, 'wiki': wiki, 'wiki_html': markdown(wiki.markdown)}
- return render(request, 'interface/wiki.html', context)
-
-@check_allowed
-def create_submission(request, project_id):
- project = get_object_or_404(models.Project, pk=project_id, ensemble=request.ensemble_id)
-
- if request.method == 'POST':
- form = forms.SubmissionForm(request.POST)
-
- if form.is_valid():
- s = form.save(commit=False)
- s.project_id = project_id
- s.save()
-
- # cache details for next time
- request.session['name'] = s.name
- request.session['instrument'] = s.instrument
-
- return redirect('submission', project_id=project_id, submission_id=s.pk)
- else:
- initial = { k: request.session.get(k) for k in ('name', 'instrument') }
- form = forms.SubmissionForm(initial=initial)
-
- context = {'project': project, 'form': form}
- return render(request, 'interface/submission_create.html', context)
-
-@check_allowed
-def submission(request, project_id, submission_id):
- project = get_object_or_404(models.Project, pk=project_id, ensemble=request.ensemble_id)
- submission = project.all_submissions.get(pk=submission_id)
-
- if submission.complete:
- context = {'project': project, 'submission': submission}
- if request.user.is_authenticated:
- context['download'] = submission.presigned_url()
- return render(request, 'interface/submission_detail.html', context)
-
+class EnsembleDetailView(EnsembleMixin, DetailView):
- # Need to do an upload
- redirect = request.build_absolute_uri(resolve_url('complete_submission', project_id=project.pk, submission_id=submission.pk))
+ def get_object(self):
+ return models.Ensemble.objects.get(pk=self.request.ensemble_id)
- key = submission.key_template()
- upload = project.presigned_post(key,
- fields={'success_action_redirect': redirect},
- conditions=[["starts-with", "$success_action_redirect", ""]])
+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 SubmissionCreateView(ProjectMixin, CreateView):
+ model = models.Submission
+ fields = ['name', 'instrument', 'notes']
+ 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
+
+ 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 SubmissionDetailView(ProjectMixin, S3CompleteMixin, DetailView):
+ model = models.Submission
- # need an additional presigned without the redirect for ajax submission
- ajax_post = project.presigned_post(key)
- context = {'upload': upload, 'ajax_post': ajax_post, 'project': project, 'submission': submission}
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ if self.request.user.is_authenticated:
+ context['download'] = self.object.presigned_url()
+ return context
- return render(request, 'interface/submission_upload.html', context)
+class SubmissionUploadView(S3UploadMixin, DetailView):
+ template_name = 'interface/submission_upload.html'
+ model = models.Submission
-@check_allowed
-def cancel_submission(request, project_id, submission_id):
- project = get_object_or_404(models.Project, pk=project_id, ensemble=request.ensemble_id)
- submission = project.all_submissions.get(pk=submission_id)
- submission.delete()
- return redirect('project', project_id=project_id)
+ def get_success_url(self):
+ return resolve_url('submission_detail', **self.kwargs)
-@check_allowed
-def complete_submission(request, project_id, submission_id):
- project = get_object_or_404(models.Project, pk=project_id, ensemble=request.ensemble_id)
- s = project.all_submissions.get(pk=submission_id)
- s.complete = True
-
- uri = urlparse(request.GET['location'])
- s.key = uri.path[1:]
-
- s.save()
- return redirect('submission', project_id=project_id, submission_id=submission_id)
\ No newline at end of file
+ def get_cancel_url(self):
+ return resolve_url('submission_cancel', **self.kwargs)
+
+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 ResourceCreateView(ProjectMixin, CreateView):
+ model = models.Resource
+ fields = ['name', 'media_type', 'description']
+ template_name = 'interface/project_form.html'
+ title = "Add a new resource"
+
+ def form_valid(self, form):
+
+ if not self.request.user.is_authenticated:
+ raise SuspiciousOperation("Must be logged in to create resources")
+
+ 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/submission_upload.html'
+
+ 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(S3CompleteMixin, SingleObjectMixin, RedirectView):
+ model = models.Resource
+ always_set = True
+
+ def get_redirect_url(self, **kwargs):
+ return resolve_url('resource_list', project=self.kwargs['project'])
+
+
+class ResourceListView(ProjectMixin, ListView):
+ model = models.Resource
diff --git a/polyphonic/settings.py b/polyphonic/settings.py
index 987c846..2d86a0b 100644
--- a/polyphonic/settings.py
+++ b/polyphonic/settings.py
@@ -25,7 +25,7 @@ SECRET_KEY = '6y#33930^6@c762u(@6+_qx8eu^e8q+4t-(@m60vnjw37k26'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
-ALLOWED_HOSTS = ['localhost', '192.168.100.123']
+ALLOWED_HOSTS = ['localhost', '192.168.100.130']
# Application definition