diff --git a/stade/core/models/challenge.py b/stade/core/models/challenge.py
index 562d894..7049754 100644
--- a/stade/core/models/challenge.py
+++ b/stade/core/models/challenge.py
@@ -38,6 +38,8 @@ def stats(self):
distinct=True,
),
num_successful_approaches=models.Count('approach', distinct=True),
+ first_submission=models.Min('approach__submission__created'),
+ last_submission=models.Max('approach__submission__created'),
)
.filter(challenge=self)
.order_by('name')
diff --git a/stade/core/static/css/stade/dashboard.css b/stade/core/static/css/stade/dashboard.css
index 57c0224..16025a9 100644
--- a/stade/core/static/css/stade/dashboard.css
+++ b/stade/core/static/css/stade/dashboard.css
@@ -1,3 +1,9 @@
+.submission-timespan {
+ font-size: 13px;
+ font-weight: normal;
+ margin-left: 0.5em;
+}
+
.main-stats {
background: #454545;
color: #fff;
diff --git a/stade/core/templates/partials/task-submission-timespan.html b/stade/core/templates/partials/task-submission-timespan.html
new file mode 100644
index 0000000..7eacd05
--- /dev/null
+++ b/stade/core/templates/partials/task-submission-timespan.html
@@ -0,0 +1,5 @@
+{% if task.first_submission %}
+
+ ({{ task.first_submission|date:"M Y" }} - {% if task.locked %}{{ task.last_submission|date:"M Y" }}{% else %}Present{% endif %})
+
+{% endif %}
diff --git a/stade/core/templates/stats.html b/stade/core/templates/stats.html
index 40fa218..938eb9a 100644
--- a/stade/core/templates/stats.html
+++ b/stade/core/templates/stats.html
@@ -49,6 +49,7 @@
Success/Total
{{ task.name }}
+ {% include "partials/task-submission-timespan.html" %}
@@ -92,6 +93,7 @@
Success/Total
{{ task.name }}
+ {% include "partials/task-submission-timespan.html" %}
diff --git a/stade/core/tests/test_stats.py b/stade/core/tests/test_stats.py
new file mode 100644
index 0000000..5fb6351
--- /dev/null
+++ b/stade/core/tests/test_stats.py
@@ -0,0 +1,35 @@
+from datetime import timedelta
+
+from django.urls import reverse
+from django.utils import timezone
+from django.utils.dateformat import format as date_format
+import pytest
+
+
+@pytest.mark.django_db
+def test_stats_task_submission_timespan(client, task_factory, submission_factory):
+ locked_task = task_factory(locked=True)
+ open_task = task_factory(locked=False)
+ empty_task = task_factory()
+
+ first = submission_factory(approach__task=locked_task)
+ first.created = timezone.now() - timedelta(days=400)
+ first.save()
+ last = submission_factory(approach__task=locked_task)
+ open_submission = submission_factory(approach__task=open_task)
+
+ stats = {t.id: t for t in locked_task.challenge.stats['tasks']}
+ assert stats[locked_task.id].first_submission == first.created
+ assert stats[locked_task.id].last_submission == last.created
+
+ def month(dt):
+ return date_format(timezone.localtime(dt), 'M Y')
+
+ resp = client.get(reverse('stats'))
+ assert resp.status_code == 200
+ content = resp.content.decode()
+
+ assert f'({month(first.created)} - {month(last.created)})' in content
+ assert f'({month(open_submission.created)} - Present)' in content
+ assert content.count('class="submission-timespan"') == 2
+ assert empty_task.name in content