diff --git a/pretalx_musicrate/forms.py b/pretalx_musicrate/forms.py
index a550d84..553c1e9 100644
--- a/pretalx_musicrate/forms.py
+++ b/pretalx_musicrate/forms.py
@@ -26,7 +26,12 @@ class MusicrateSettingsForm(I18nModelForm):
class Meta:
model = MusicrateSettings
- fields = ("submission_types", "genre_question", "origin_question")
+ fields = (
+ "submission_types",
+ "genre_question",
+ "origin_question",
+ "advance_threshold",
+ )
widgets = {
"submission_types": forms.SelectMultiple(attrs={"class": "select2"}),
"genre_question": forms.Select(attrs={"class": "select2"}),
diff --git a/pretalx_musicrate/migrations/0004_musicratesettings_advance_threshold.py b/pretalx_musicrate/migrations/0004_musicratesettings_advance_threshold.py
new file mode 100644
index 0000000..54776c5
--- /dev/null
+++ b/pretalx_musicrate/migrations/0004_musicratesettings_advance_threshold.py
@@ -0,0 +1,21 @@
+# Generated by Django 4.2.8 on 2023-12-15 16:32
+
+from decimal import Decimal
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("pretalx_musicrate", "0003_musicratesettings_join_token"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="musicratesettings",
+ name="advance_threshold",
+ field=models.DecimalField(
+ decimal_places=2, default=Decimal("0.6"), max_digits=3
+ ),
+ ),
+ ]
diff --git a/pretalx_musicrate/models.py b/pretalx_musicrate/models.py
index 39a5d28..dac3e0a 100644
--- a/pretalx_musicrate/models.py
+++ b/pretalx_musicrate/models.py
@@ -1,3 +1,4 @@
+from decimal import Decimal
from secrets import token_urlsafe
from django.db import models
@@ -40,3 +41,12 @@ class MusicrateSettings(models.Model):
null=True,
)
join_token = models.CharField(max_length=43, default=generate_token)
+ advance_threshold = models.DecimalField(
+ max_digits=3,
+ decimal_places=2,
+ default=Decimal("0.6"),
+ help_text=_(
+ "The fraction of jurors that has to submit a rating before the presenter view automatically advances to the next submission."
+ ),
+ verbose_name=_("Advance Threshold"),
+ )
diff --git a/pretalx_musicrate/static/pretalx_musicrate/may-advance.js b/pretalx_musicrate/static/pretalx_musicrate/may-advance.js
new file mode 100644
index 0000000..92983fa
--- /dev/null
+++ b/pretalx_musicrate/static/pretalx_musicrate/may-advance.js
@@ -0,0 +1,16 @@
+const mayAdvance = (callback) =>
+ fetch("may-advance?")
+ .then(response => response.json())
+ .then(mayAdvance => {
+ if (mayAdvance === true) {
+ callback();
+ }
+ });
+const timeout = setTimeout(() => {
+ setInterval(() => {
+ mayAdvance(() => {
+ location = document.getElementById("next").href;
+ });
+ }, 3000);
+}, 3000);
+mayAdvance(() => clearTimeout(timeout));
diff --git a/pretalx_musicrate/templates/pretalx_musicrate/present.html b/pretalx_musicrate/templates/pretalx_musicrate/present.html
index 4a1870e..35398ad 100644
--- a/pretalx_musicrate/templates/pretalx_musicrate/present.html
+++ b/pretalx_musicrate/templates/pretalx_musicrate/present.html
@@ -1,4 +1,11 @@
{% extends "pretalx_musicrate/submission_base.html" %}
+{% load compress %}
+{% load static %}
{% block submission_content %}
+ {% if next %}
+ {% compress js %}
+
+ {% endcompress %}
+ {% endif %}
{% endblock %}
diff --git a/pretalx_musicrate/templates/pretalx_musicrate/settings.html b/pretalx_musicrate/templates/pretalx_musicrate/settings.html
index 196debd..db894a6 100644
--- a/pretalx_musicrate/templates/pretalx_musicrate/settings.html
+++ b/pretalx_musicrate/templates/pretalx_musicrate/settings.html
@@ -12,6 +12,7 @@
{% bootstrap_field form.submission_types layout='event' %}
{% bootstrap_field form.genre_question layout='event' %}
{% bootstrap_field form.origin_question layout='event' %}
+ {% bootstrap_field form.advance_threshold layout='event' %}
{% include "orga/includes/submit_row.html" %}
{% endblock %}
diff --git a/pretalx_musicrate/templates/pretalx_musicrate/submission_base.html b/pretalx_musicrate/templates/pretalx_musicrate/submission_base.html
index 4be5863..66b9f66 100644
--- a/pretalx_musicrate/templates/pretalx_musicrate/submission_base.html
+++ b/pretalx_musicrate/templates/pretalx_musicrate/submission_base.html
@@ -47,7 +47,7 @@
{{ index }}/{{ count }}
{% endif %}
{% if next and can_continue %}
- {% translate "Next" %} >
+ {% translate "Next" %} >
{% else %}
{% endif %}
diff --git a/pretalx_musicrate/urls.py b/pretalx_musicrate/urls.py
index b2f86cc..8036fde 100644
--- a/pretalx_musicrate/urls.py
+++ b/pretalx_musicrate/urls.py
@@ -1,6 +1,12 @@
from django.urls import include, path
-from .views import JoinView, MusicrateSettingsView, PresenterView, QRCodeView
+from .views import (
+ JoinView,
+ MayAdvanceView,
+ MusicrateSettingsView,
+ PresenterView,
+ QRCodeView,
+)
urlpatterns = [
path(
@@ -14,6 +20,11 @@ urlpatterns = [
[
path("", QRCodeView.as_view(), name="qrcode"),
path("present//", PresenterView.as_view(), name="present"),
+ path(
+ "present//may-advance",
+ MayAdvanceView.as_view(),
+ name="may_advance",
+ ),
path("/", JoinView.as_view(), name="join"),
]
),
diff --git a/pretalx_musicrate/views.py b/pretalx_musicrate/views.py
index 5e73616..96a19d0 100644
--- a/pretalx_musicrate/views.py
+++ b/pretalx_musicrate/views.py
@@ -4,11 +4,12 @@ from operator import itemgetter
from django.contrib import messages
from django.db.models import F, Max, Min, Window
from django.db.models.functions import RowNumber
+from django.http import JsonResponse
from django.shortcuts import redirect
from django.urls import reverse
from django.utils.functional import cached_property
from django.utils.translation import gettext_lazy as _
-from django.views.generic import FormView, TemplateView
+from django.views.generic import FormView, TemplateView, View
from django.views.generic.detail import SingleObjectMixin
from django_context_decorator import context
from pretalx.common.mixins.views import EventPermissionRequired
@@ -189,3 +190,10 @@ class PresenterView(EventPermissionRequired, SubmissionMixin, TemplateView):
def get(self, request, *args, **kwargs):
self.object = self.get_object()
return super().get(request, *args, **kwargs)
+
+
+class MayAdvanceView(EventPermissionRequired, View):
+ permission_required = "orga.view_submissions"
+
+ def get(self, request, *args, **kwargs):
+ return JsonResponse(True, safe=False)