diff --git a/interface/models.py b/interface/models.py
index 6eef732..ff72a86 100644
--- a/interface/models.py
+++ b/interface/models.py
@@ -131,5 +131,16 @@ class Submission(models.Model):
slugify(self.instrument)
)
+ @property
+ def short_name(self):
+ _, ext = os.path.splitext(self.download_name)
+ return "{}_{}_{}{}".format(
+ #timezone.localtime(self.date).strftime("%Y%m%d%H%M%S"),
+ slugify(self.name),
+ slugify(self.instrument),
+ self.pk,
+ ext
+ )
+
def __str__(self):
return f"{self.name}: {self.date}"
diff --git a/interface/templates/interface/project_submissions.mk b/interface/templates/interface/project_submissions.mk
new file mode 100644
index 0000000..7bf95c4
--- /dev/null
+++ b/interface/templates/interface/project_submissions.mk
@@ -0,0 +1,11 @@
+
+ALL = {{ targets|join:" " }}
+
+-include "local.mk"
+
+all: ${ALL}
+
+{% for s in submissions %}
+{{ s.name }}:
+ curl -o $@ -L {{ s.url }}
+{% endfor %}
\ No newline at end of file
diff --git a/interface/templates/interface/submission_list.html b/interface/templates/interface/submission_list.html
index c4aa730..8af3f4e 100644
--- a/interface/templates/interface/submission_list.html
+++ b/interface/templates/interface/submission_list.html
@@ -1,6 +1,12 @@
{% extends "interface/project_base.html" %}
{% block page %}
+
+
diff --git a/interface/urls.py b/interface/urls.py
index 88bc0ba..324572c 100644
--- a/interface/urls.py
+++ b/interface/urls.py
@@ -12,6 +12,7 @@ urlpatterns = [
path('', views.EnsembleDetailView.as_view(), name='ensemble_detail'),
path('projects/', views.ProjectDetailView.as_view(), name="project_detail"),
+ path('projects//submissions.mk', views.ProjectMakefileView.as_view(), name="project_makefile"),
path('projects//page/', views.WikiView.as_view(), name="wiki"),
path('projects//page//edit', views.WikiEditView.as_view(), name="wiki_edit"),
@@ -23,6 +24,7 @@ urlpatterns = [
path('projects//submission//upload', views.SubmissionUploadView.as_view(), name="submission_upload"),
path('projects//submission//cancel', views.SubmissionCancelView.as_view(), name="submission_cancel"),
path('projects//submission//complete', views.SubmissionCompleteView.as_view(), name="submission_complete"),
+ path('projects//submission//download', views.SubmissionDownloadView.as_view(), name="submission_download"),
path('projects//submissions', views.SubmissionListView.as_view(), name="submission_list"),
path('projects//resources', views.ResourceListView.as_view(), name="resource_list"),
diff --git a/interface/views.py b/interface/views.py
index e13a015..b829322 100644
--- a/interface/views.py
+++ b/interface/views.py
@@ -6,6 +6,7 @@ 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.core.signing import Signer
from django.contrib import auth
from markdown2 import markdown
@@ -20,6 +21,13 @@ from base64 import b64decode
import logging
logger = logging.getLogger(__name__)
+signer = Signer()
+
+def signed_url(name, **kwargs):
+ url = resolve_url(name, **kwargs)
+ sig = signer.sign(url)
+ return sig.replace(":", "?auth=")
+
class EnsembleMixin(object):
admin_required = False
@@ -28,6 +36,15 @@ class EnsembleMixin(object):
request.ensemble_id = request.session.get('ensemble')
request.is_admin = request.user.is_superuser
+ if 'auth' in request.GET:
+ sig = signer.sign(request.path)
+ if sig[len(request.path)+1:] == request.GET['auth']:
+ logger.info("Allowing auth key")
+ request.is_admin = True
+ return super().dispatch(request, *args, **kwargs)
+ else:
+ raise SuspiciousOperation("Bad auth code")
+
if not request.ensemble_id:
return redirect('register')
@@ -47,8 +64,11 @@ 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)
+ if self.request.is_admin: # can access any ensemble
+ self._project = get_object_or_404(models.Project, pk=self.kwargs['project'])
+ else:
+ self._project = get_object_or_404(models.Project,
+ pk=self.kwargs['project'], ensemble=self.request.ensemble_id)
return self._project
def get_queryset(self):
@@ -192,6 +212,31 @@ class ProjectDetailView(EnsembleMixin, DetailView):
def get_queryset(self):
return models.Project.objects.filter(ensemble=self.request.ensemble_id)
+class ProjectMakefileView(EnsembleMixin, DetailView):
+ template_name = 'interface/project_submissions.mk'
+ content_type = 'text/plain'
+
+ def get_queryset(self):
+ if self.request.is_admin:
+ return models.Project.objects.all()
+
+ return models.Project.objects.filter(ensemble=self.request.ensemble_id)
+
+ def get_context_data(self, **kwargs):
+ data = super().get_context_data(**kwargs)
+
+ data['submissions'] = []
+ data['targets'] = []
+ for s in self.object.submissions:
+ name = s.short_name
+ data['targets'].append(name)
+ data['submissions'].append({
+ 'url': self.request.build_absolute_uri(signed_url('submission_download', project=self.kwargs['pk'], pk=s.pk)),
+ 'name': name,
+ })
+
+ return data
+
class WikiView(ProjectMixin, DetailView):
template_name = 'interface/wiki.html'
model = models.WikiPage
@@ -245,6 +290,13 @@ class SubmissionCompleteView(ProjectMixin, S3CompleteView):
def get_redirect_url(self, **kwargs):
return resolve_url('submission_detail', **self.kwargs)
+class SubmissionDownloadView(ProjectMixin, SingleObjectMixin, RedirectView):
+ model = models.Submission
+ admin_required = True
+
+ def get_redirect_url(self, **kwargs):
+ return self.get_object().download_url
+
class SubmissionDetailView(ProjectMixin, DetailView):
model = models.Submission
@@ -307,6 +359,11 @@ class SubmissionListView(ProjectMixin, ListView):
def get_queryset(self):
return super().get_queryset().filter(complete=True).order_by('-pk')
+ def get_context_data(self, **kwargs):
+ data = super().get_context_data(**kwargs)
+ data['signed_url'] = self.request.build_absolute_uri(signed_url('project_makefile', pk=self.kwargs['project']))
+ return data
+
class ResourceCreateView(ProjectMixin, CreateView):
model = models.Resource
fields = ['name', 'media_type', 'description']