Library working:
This commit is contained in:
+1
-1
@@ -7,7 +7,7 @@ class EnsembleAdmin(admin.ModelAdmin):
|
||||
|
||||
class ProjectAdmin(admin.ModelAdmin):
|
||||
|
||||
list_display = ['name', 'ensemble', 'deadline', 'active', 'slug']
|
||||
list_display = ['name', 'ensemble', 'event_date', 'active', 'slug']
|
||||
list_filter = ['ensemble', 'active']
|
||||
|
||||
class SubmissionAdmin(admin.ModelAdmin):
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
# Generated by Django 3.1.1 on 2021-03-21 23:10
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import interface.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
replaces = [('interface', '0001_initial'), ('interface', '0002_auto_20200904_1004'), ('interface', '0003_auto_20200905_0118'), ('interface', '0004_auto_20200905_0127'), ('interface', '0005_auto_20200905_0638'), ('interface', '0006_submission_key'), ('interface', '0007_auto_20200906_1009'), ('interface', '0008_auto_20200906_1122'), ('interface', '0009_auto_20200907_0103'), ('interface', '0010_auto_20200907_0148'), ('interface', '0011_auto_20200907_0234'), ('interface', '0012_remove_ensemble_bucket'), ('interface', '0013_auto_20200907_1455'), ('interface', '0014_auto_20200909_1016'), ('interface', '0015_resource_media_type'), ('interface', '0016_auto_20200910_2025'), ('interface', '0017_auto_20200914_0943'), ('interface', '0018_auto_20200914_1009'), ('interface', '0019_project_owner'), ('interface', '0020_auto_20201003_2103'), ('interface', '0021_project_description')]
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Project',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=100)),
|
||||
('active', models.BooleanField(default=True)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='WikiPage',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('markdown', models.TextField()),
|
||||
('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='wiki_pages', to='interface.project')),
|
||||
('title', models.CharField(default='', max_length=255)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Ensemble',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=100)),
|
||||
('code', models.CharField(default=interface.models.generate_code, max_length=9)),
|
||||
('passphrase', models.CharField(max_length=100)),
|
||||
('admins', models.ManyToManyField(related_name='ensembles', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='project',
|
||||
name='ensemble',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='projects', to='interface.ensemble'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='project',
|
||||
name='deadline',
|
||||
field=models.DateField(blank=True, null=True),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Resource',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=100)),
|
||||
('key', models.CharField(blank=True, max_length=255)),
|
||||
('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='resources', to='interface.project')),
|
||||
('description', models.TextField(blank=True)),
|
||||
('media_type', models.CharField(choices=[('audio', 'Audio'), ('video', 'Video'), ('general', 'General')], default='*', max_length=10)),
|
||||
('visible', models.BooleanField(default=True)),
|
||||
],
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='project',
|
||||
name='owner',
|
||||
field=models.CharField(blank=True, max_length=255),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Submission',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('instrument', models.CharField(max_length=100, verbose_name='Instrument / Voice')),
|
||||
('notes', models.TextField(blank=True)),
|
||||
('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='all_submissions', to='interface.project')),
|
||||
('date', models.DateTimeField(auto_now_add=True)),
|
||||
('complete', models.BooleanField(default=False)),
|
||||
('url', models.CharField(blank=True, max_length=512)),
|
||||
('private', models.BooleanField(default=False)),
|
||||
],
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='project',
|
||||
name='description',
|
||||
field=models.TextField(blank=True),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 3.1.1 on 2021-03-12 02:56
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('interface', '0022_auto_20210303_2043'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='ensemble',
|
||||
name='storage',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='byostorage.userstorage'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,23 @@
|
||||
# Generated by Django 3.1.1 on 2021-03-12 06:12
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('interface', '0023_ensemble_storage'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='project',
|
||||
name='accept_submissions',
|
||||
field=models.BooleanField(default=False, help_text='Allow media submissions from participants'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='project',
|
||||
name='has_items',
|
||||
field=models.BooleanField(default=True, help_text='Enable items to be added from the library'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,23 @@
|
||||
# Generated by Django 3.1.1 on 2021-03-12 06:13
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('interface', '0024_auto_20210312_1712'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='project',
|
||||
old_name='has_items',
|
||||
new_name='enable_library',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='project',
|
||||
old_name='accept_submissions',
|
||||
new_name='enable_submissions',
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 3.1.1 on 2021-03-12 22:26
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('interface', '0025_auto_20210312_1713'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='project',
|
||||
old_name='deadline',
|
||||
new_name='event_date',
|
||||
),
|
||||
]
|
||||
+24
-1
@@ -23,6 +23,18 @@ MEDIA_TYPES = [
|
||||
('general', "General"),
|
||||
]
|
||||
|
||||
def rough_date(d):
|
||||
days = (self.event_date - timezone.now().date()).days
|
||||
in_past = days < 0
|
||||
if in_past:
|
||||
days = abs(days)
|
||||
if days ==0:
|
||||
return "today!"
|
||||
if days >= 7:
|
||||
return in_past, "{0:d} weeks, {1:d} days".format(days / 7, days % 7)
|
||||
return in_past, f"{days} days"
|
||||
|
||||
|
||||
def generate_code(length=9):
|
||||
return "".join([ random.choice('0123456789') for _ in range(length) ])
|
||||
|
||||
@@ -32,6 +44,7 @@ class Ensemble(models.Model):
|
||||
passphrase = models.CharField(max_length=100)
|
||||
admins = models.ManyToManyField('auth.User', related_name='ensembles')
|
||||
slug = models.SlugField(max_length=100, editable=False)
|
||||
storage = models.ForeignKey('byostorage.UserStorage', null=True, on_delete=models.SET_NULL)
|
||||
|
||||
def active_projects(self):
|
||||
return self.projects.filter(active=True)
|
||||
@@ -53,9 +66,11 @@ class Project(models.Model):
|
||||
ensemble = models.ForeignKey(Ensemble, related_name='projects', on_delete=models.CASCADE, null=True)
|
||||
description = models.TextField(blank=True)
|
||||
active = models.BooleanField(default=True)
|
||||
deadline =models.DateField(null=True, blank=True)
|
||||
event_date =models.DateField(null=True, blank=True)
|
||||
owner = models.CharField(max_length=255, blank=True)
|
||||
slug = models.SlugField(max_length=100, editable=False)
|
||||
enable_library = models.BooleanField(default=True, help_text="Enable items to be added from the library")
|
||||
enable_submissions = models.BooleanField(default=False, help_text="Allow media submissions from participants")
|
||||
|
||||
@property
|
||||
def submissions(self):
|
||||
@@ -65,6 +80,14 @@ class Project(models.Model):
|
||||
key = os.path.join(self.slug, object_name)
|
||||
return s3client.generate_presigned_post(BUCKET, key, Fields=fields or {}, Conditions=conditions or [], ExpiresIn=expires)
|
||||
|
||||
@property
|
||||
def days(self):
|
||||
return (self.event_date - timezone.now().date()).days
|
||||
|
||||
@property
|
||||
def has_happened(self):
|
||||
return self.event_date < timezone.now()
|
||||
|
||||
def save(self):
|
||||
if not self.slug:
|
||||
self.slug = slugify(self.name)
|
||||
|
||||
@@ -313,7 +313,8 @@ TD.select-cell {
|
||||
}
|
||||
|
||||
DIV.selected {
|
||||
background-color: #EEE;
|
||||
background-color: var(--gray-blue);
|
||||
color: white;
|
||||
border: 1px solid #999;
|
||||
border-radius: 5px;
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
<!-- Required meta tags -->
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<link rel="icon" type="image/png" href="{% static 'interface/icon.png' %}" />
|
||||
|
||||
<link rel="stylesheet" href="{% static 'interface/css/polyphonic.css' %}"></link>
|
||||
<title>{% block title %}Polyphonic{% endblock %}</title>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
{% extends "base.html" %}
|
||||
{% extends "interface/project_base.html" %}
|
||||
|
||||
{% block content %}
|
||||
{% block page %}
|
||||
<div style="flex-grow: 1">
|
||||
<h1>Projects for {{ ensemble.name }}</h1>
|
||||
<div class="list-group narrow">
|
||||
{% for project in ensemble.active_projects %}
|
||||
<a class="" href="{% url 'project_detail' pk=project.id %}">
|
||||
<a class="" href="{% url 'project_detail' project=project.id %}">
|
||||
<h3>{{ project.name }}</h3>
|
||||
<p><small>
|
||||
{% if project.deadline %}In {{ project.deadline|timeuntil }}<br/>{% endif %}
|
||||
@@ -15,7 +15,7 @@
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div style="text-align: right; margin-top: 10px; color: #999;">
|
||||
<div style="float: right; margin-top: 10px; color: #999;">
|
||||
<small>{{ ensemble.ensemble_code }}</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -10,25 +10,32 @@
|
||||
{% endif %}
|
||||
|
||||
<h1>{{ project.name }}</h1>
|
||||
|
||||
{% block page %}
|
||||
No content
|
||||
{% endblock %}
|
||||
{% if project %}
|
||||
|
||||
<div class="project-links">
|
||||
<div class="pills" role="tablist">
|
||||
<a role="tab" href="{% url 'project_detail' pk=project.id %}">Project info</a>
|
||||
|
||||
{% if project %}
|
||||
<a role="tab" href="{% url 'project_detail' project=project.id %}">Project info</a>
|
||||
{% for page in project.wiki_pages.all %}
|
||||
<a class="nav-link {% if page.id == wiki_id %}active{% endif %}"
|
||||
href="{% url 'wiki' project=project.id pk=page.id %}">{{ page.title }}</a>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if project and project.enable_submissions%}
|
||||
<a role="tab" href="{% url 'resource_list' project=project.pk %}">Resources</a>
|
||||
<!--a role="tab" href="">Record a submission</a-->
|
||||
{% if request.is_admin %}
|
||||
<a role="tab" href="{% url 'submission_list' project=project.id %}">Submissions</a>
|
||||
{% endif %}
|
||||
<a role="tab" href="{% url 'submission_create' project=project.id %}">Send a file</a>
|
||||
{% endif %}
|
||||
|
||||
{% include "library/project_menu.html" %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -2,30 +2,25 @@
|
||||
{% load md2 %}
|
||||
|
||||
|
||||
{% block page %}
|
||||
{% block page %}
|
||||
<div class="narrow">
|
||||
{% if project.deadline %}
|
||||
<h3 class="text-center">In {{ project.deadline|timeuntil }}</h3>
|
||||
{% if project.event_date %}
|
||||
<h3 class="text-center">{{ project.when }}</h3>
|
||||
{% endif %}
|
||||
<p>{{ project.description|markdown }}</p>
|
||||
|
||||
<p>{{ project.description|markdown }}</p>
|
||||
|
||||
{% if project.owner %}
|
||||
<p>Project email: <a href="mailto:{{ project.owner }}">{{ project.owner }}</a></p>
|
||||
<p>Project email: <a href="mailto:{{ project.owner }}">{{ project.owner }}</a></p>
|
||||
{% endif %}
|
||||
{% with sub_count=project.submissions.count %}
|
||||
<p>There have been {{ sub_count }} submission{{ sub_count|pluralize }} so far...</p>
|
||||
{% if sub_count %}
|
||||
<h4>Recent submissions</h4>
|
||||
<table style="width: 100%">
|
||||
<tbody">
|
||||
{% for submission in project.submissions|slice:":5" %}
|
||||
<tr>
|
||||
<td>{{ submission.date|timesince }} ago</td>
|
||||
<td>{{ submission.name }} ({{ submission.instrument }})</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{% if project.enable_submissions %}
|
||||
{% include 'submissions/project_detail.html' %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
{% if project.enable_library %}
|
||||
{% include 'library/project_detail.html' %}
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
from django import template
|
||||
import os.path
|
||||
|
||||
register = template.Library()
|
||||
|
||||
def basename(value):
|
||||
return os.path.basename(value)
|
||||
|
||||
register.filter('basename', basename)
|
||||
+2
-2
@@ -11,8 +11,8 @@ urlpatterns = [
|
||||
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>/submissions.mk', views.ProjectMakefileView.as_view(), name="project_makefile"),
|
||||
path('projects/<int:project>', views.ProjectDetailView.as_view(), name="project_detail"),
|
||||
path('projects/<int:project>/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>/edit', views.WikiEditView.as_view(), name="wiki_edit"),
|
||||
|
||||
+3
-3
@@ -207,10 +207,10 @@ class EnsembleDetailView(EnsembleMixin, DetailView):
|
||||
def get_object(self):
|
||||
return models.Ensemble.objects.get(pk=self.request.ensemble_id)
|
||||
|
||||
class ProjectDetailView(EnsembleMixin, DetailView):
|
||||
class ProjectDetailView(ProjectMixin, DetailView):
|
||||
|
||||
def get_queryset(self):
|
||||
return models.Project.objects.filter(ensemble=self.request.ensemble_id)
|
||||
def get_object(self):
|
||||
return self.get_project()
|
||||
|
||||
class ProjectMakefileView(EnsembleMixin, DetailView):
|
||||
template_name = 'interface/project_submissions.mk'
|
||||
|
||||
Reference in New Issue
Block a user