Implemented makefile building #6
@ -131,5 +131,16 @@ class Submission(models.Model):
|
|||||||
slugify(self.instrument)
|
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):
|
def __str__(self):
|
||||||
return f"{self.name}: {self.date}"
|
return f"{self.name}: {self.date}"
|
||||||
|
|||||||
11
interface/templates/interface/project_submissions.mk
Normal file
11
interface/templates/interface/project_submissions.mk
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
ALL = {{ targets|join:" " }}
|
||||||
|
|
||||||
|
-include "local.mk"
|
||||||
|
|
||||||
|
all: ${ALL}
|
||||||
|
|
||||||
|
{% for s in submissions %}
|
||||||
|
{{ s.name }}:
|
||||||
|
curl -o $@ -L {{ s.url }}
|
||||||
|
{% endfor %}
|
||||||
@ -1,6 +1,12 @@
|
|||||||
{% extends "interface/project_base.html" %}
|
{% extends "interface/project_base.html" %}
|
||||||
|
|
||||||
{% block page %}
|
{% block page %}
|
||||||
|
|
||||||
|
<div class="admin-tools">
|
||||||
|
<a href="{{ signed_url }}">
|
||||||
|
<i class="fas fa-list"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
<table style="max-width: 800px; margin: 10pt auto;">
|
<table style="max-width: 800px; margin: 10pt auto;">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
@ -12,6 +12,7 @@ urlpatterns = [
|
|||||||
|
|
||||||
path('', views.EnsembleDetailView.as_view(), name='ensemble_detail'),
|
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:pk>/submissions.mk', views.ProjectMakefileView.as_view(), name="project_makefile"),
|
||||||
|
|
||||||
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"),
|
||||||
path('projects/<int:project>/page/<int:pk>/edit', views.WikiEditView.as_view(), name="wiki_edit"),
|
path('projects/<int:project>/page/<int:pk>/edit', views.WikiEditView.as_view(), name="wiki_edit"),
|
||||||
@ -23,6 +24,7 @@ urlpatterns = [
|
|||||||
path('projects/<int:project>/submission/<int:pk>/upload', views.SubmissionUploadView.as_view(), name="submission_upload"),
|
path('projects/<int:project>/submission/<int:pk>/upload', views.SubmissionUploadView.as_view(), name="submission_upload"),
|
||||||
path('projects/<int:project>/submission/<int:pk>/cancel', views.SubmissionCancelView.as_view(), name="submission_cancel"),
|
path('projects/<int:project>/submission/<int:pk>/cancel', views.SubmissionCancelView.as_view(), name="submission_cancel"),
|
||||||
path('projects/<int:project>/submission/<int:pk>/complete', views.SubmissionCompleteView.as_view(), name="submission_complete"),
|
path('projects/<int:project>/submission/<int:pk>/complete', views.SubmissionCompleteView.as_view(), name="submission_complete"),
|
||||||
|
path('projects/<int:project>/submission/<int:pk>/download', views.SubmissionDownloadView.as_view(), name="submission_download"),
|
||||||
path('projects/<int:project>/submissions', views.SubmissionListView.as_view(), name="submission_list"),
|
path('projects/<int:project>/submissions', views.SubmissionListView.as_view(), name="submission_list"),
|
||||||
|
|
||||||
path('projects/<int:project>/resources', views.ResourceListView.as_view(), name="resource_list"),
|
path('projects/<int:project>/resources', views.ResourceListView.as_view(), name="resource_list"),
|
||||||
|
|||||||
@ -6,6 +6,7 @@ from django.views.generic.edit import CreateView, UpdateView, FormView
|
|||||||
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.core.signing import Signer
|
||||||
from django.contrib import auth
|
from django.contrib import auth
|
||||||
|
|
||||||
from markdown2 import markdown
|
from markdown2 import markdown
|
||||||
@ -20,6 +21,13 @@ from base64 import b64decode
|
|||||||
import logging
|
import logging
|
||||||
logger = logging.getLogger(__name__)
|
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):
|
class EnsembleMixin(object):
|
||||||
admin_required = False
|
admin_required = False
|
||||||
|
|
||||||
@ -28,6 +36,15 @@ class EnsembleMixin(object):
|
|||||||
request.ensemble_id = request.session.get('ensemble')
|
request.ensemble_id = request.session.get('ensemble')
|
||||||
request.is_admin = request.user.is_superuser
|
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:
|
if not request.ensemble_id:
|
||||||
return redirect('register')
|
return redirect('register')
|
||||||
|
|
||||||
@ -47,8 +64,11 @@ class ProjectMixin(EnsembleMixin):
|
|||||||
|
|
||||||
def get_project(self):
|
def get_project(self):
|
||||||
if not hasattr(self, '_project'):
|
if not hasattr(self, '_project'):
|
||||||
self._project = get_object_or_404(models.Project,
|
if self.request.is_admin: # can access any ensemble
|
||||||
pk=self.kwargs['project'], ensemble=self.request.ensemble_id)
|
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
|
return self._project
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
@ -192,6 +212,31 @@ class ProjectDetailView(EnsembleMixin, DetailView):
|
|||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return models.Project.objects.filter(ensemble=self.request.ensemble_id)
|
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):
|
class WikiView(ProjectMixin, DetailView):
|
||||||
template_name = 'interface/wiki.html'
|
template_name = 'interface/wiki.html'
|
||||||
model = models.WikiPage
|
model = models.WikiPage
|
||||||
@ -245,6 +290,13 @@ class SubmissionCompleteView(ProjectMixin, S3CompleteView):
|
|||||||
def get_redirect_url(self, **kwargs):
|
def get_redirect_url(self, **kwargs):
|
||||||
return resolve_url('submission_detail', **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):
|
class SubmissionDetailView(ProjectMixin, DetailView):
|
||||||
model = models.Submission
|
model = models.Submission
|
||||||
|
|
||||||
@ -307,6 +359,11 @@ class SubmissionListView(ProjectMixin, ListView):
|
|||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return super().get_queryset().filter(complete=True).order_by('-pk')
|
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):
|
class ResourceCreateView(ProjectMixin, CreateView):
|
||||||
model = models.Resource
|
model = models.Resource
|
||||||
fields = ['name', 'media_type', 'description']
|
fields = ['name', 'media_type', 'description']
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user