deadlines

This commit is contained in:
2024-07-19 17:30:36 +02:00
parent 8a7ae9c2f9
commit 5858cee900
8 changed files with 182 additions and 50 deletions
+4 -1
View File
@@ -1,5 +1,5 @@
from django.contrib import admin
from .models import Track, Artist, Album, Background, Vote
from .models import Track, Artist, Album, Background, Vote, Profile
class TrackAdmin(admin.ModelAdmin):
pass
@@ -11,9 +11,12 @@ class BackgroundAdmin(admin.ModelAdmin):
pass
class VoteAdmin(admin.ModelAdmin):
pass
class ProfileAdmin(admin.ModelAdmin):
pass
admin.site.register(Track, TrackAdmin)
admin.site.register(Artist, ArtistAdmin)
admin.site.register(Album, AlbumAdmin)
admin.site.register(Background, BackgroundAdmin)
admin.site.register(Vote, VoteAdmin)
admin.site.register(Profile, ProfileAdmin)
+38 -1
View File
@@ -4,8 +4,12 @@ from .track import Track
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.utils import timezone
from datetime import datetime, timedelta
from datetime import datetime, timedelta, UTC
from ..spotify import spt
import os
from dotenv import load_dotenv
load_dotenv()
NOMINATIONS_PER_DAY = 10
MAX_QUOTA = 22
@@ -43,6 +47,39 @@ class Profile(models.Model):
print(f"Er zijn {elapsed.seconds}s voorbij, je nieuwe quota is {self.quota}")
self.quota_last_updated = timezone.now()
@property
def can_nominate(self):
"""Is this user allowed to nominate at this point in time?"""
end_date = os.getenv('DATE_NOM_END')
if self.user.is_superuser:
return (True,)
if end_date:
end_date = datetime.fromisoformat(end_date)
if end_date <= datetime.now(tz=UTC):
return (False, "over")
if self.quota < 1:
return (False, "quota")
return (True,)
@property
def can_vote(self):
"""Is this user allowed to vote at this point in time?"""
end_date = os.getenv('DATE_VOTE_END')
if self.user.is_superuser or not end_date:
return True
end_date = datetime.fromisoformat(end_date)
if end_date <= datetime.now(tz=UTC):
return False
return True
@property
def vote_end(self):
return os.getenv('DATE_VOTE_END')
@property
def nominate_end(self):
return os.getenv('DATE_NOM_END')
def init_spt(self, code):
"""Initial setting of spotify tokens from user accept code"""
data = spt.get_token_json(
+37
View File
@@ -0,0 +1,37 @@
let timer = null;
function startCountdown(dateString) {
if (timer) clearInterval(timer);
let cd = document.getElementById("countdown")
if (cd) {
cd.classList.remove("hide");
if (dateString == "None") cd.classList.add("hide");
}
const end = new Date(dateString).getTime();
const dayEl = document.getElementById('days');
const hoursEl = document.getElementById('hours');
const minutesEl = document.getElementById('minutes');
const secondsEl = document.getElementById('seconds');
const seconds = 1000;
const minutes = seconds * 60;
const hours = minutes * 60;
const days = hours * 24;
timer = setInterval(updateTime, seconds);
function updateTime() {
if (dayEl) {
let now = new Date().getTime();
const difference = end - now;
if (difference < 0) {
if (timer) clearInterval(timer);
cd.classList.add("hide");
return;
}
dayEl.innerText = Math.floor(difference / days);
hoursEl.innerText = Math.floor( (difference % days) / hours );
minutesEl.innerText = Math.floor( (difference % hours) / minutes );
secondsEl.innerText = Math.floor( (difference % minutes) / seconds );
}
}
updateTime();
}
+22 -3
View File
@@ -7,10 +7,17 @@ Nomineren
{% block main-content %}
<form method="post">
{% csrf_token %}
<p>Vul een spotify link in om een nummer te nomineren.</p>
<input type="text" id="spotify-input" name="spotify_link" placeholder="Spotify-link">
<input type="submit" value="Insturen" {% if user.profile.quota < 1%}disabled{%endif%}>
{% if user.profile.can_nominate.0 %}
<p>Vul een spotify link in om een nummer te nomineren.</p>
<input type="text" id="spotify-input" name="spotify_link" placeholder="Spotify-link">
<input type="submit" value="Insturen" {% if user.profile.quota < 1%}disabled{%endif%}>
{% elif user.profile.can_nominate.1 == 'quota' %}
<p>Je quotum is op. Je zal helaas eventjes moeten wachten met nomineren.</p>
{% elif user.profile.can_nominate.1 == 'over' %}
<p>Het nomineren is voorbij voor dit jaar! Bedankt voor de inzendingen.</p>
{% endif %}
</form>
{% endblock %}
{% block status-bar%}
@@ -23,4 +30,16 @@ Nomineren
</div>
<p class="status-bar-field">{{user.profile.quota_display}} nominaties over.</p>
</div>
<div class="status-bar" id="countdown">
<p class="status-bar-field"><span id="days"></span> dagen</p>
<p class="status-bar-field"><span id="hours"></span> uur</p>
<p class="status-bar-field"><span id="minutes"></span> minuten</p>
<p class="status-bar-field"><span id="seconds"></span> seconden</p>
</div>
<script>
document.body.addEventListener('htmx:load', function(evt) {
//startCountdown("2024-06-25T23:59:59+02:00");
startCountdown("{{user.profile.nominate_end}}");
});
</script>
{% endblock %}
+2 -2
View File
@@ -5,14 +5,14 @@ Overzicht
{% endblock %}
{% block multi-row %}
<menu role="tablist" hx-boost="true" class="multirows">
{% comment %} <menu role="tablist" hx-boost="true" class="multirows">
<li role="tab" aria-selected="true">
<a href="{% url 'overview' %}">Tracks</a>
</li>
<li role="tab">
<a href="{% url 'playlist-list' %}">Playlists</a>
</li>
</menu>
</menu> {% endcomment %}
{% endblock %}
{% block main-content %}
+68 -41
View File
@@ -5,59 +5,86 @@ Stemmen
{% endblock %}
{% block main-content %}
{% if track %}
<div id="vote-box" hx-target="body">
{% if error %}<div class="error">{{ error }}</div>{% endif %}
{% include 'MediaPlayer.html' with track=track %}
{% if user.profile.can_vote %}
{% if track %}
<div id="vote-box" hx-target="body">
{% if error %}<div class="error">{{ error }}</div>{% endif %}
{% include 'MediaPlayer.html' with track=track %}
<div
id="vote-stars"
hx-vals='{"spotify_id": "{{ track.id }}"}'
style="margin-top:10px;"
>
<fieldset>
<legend>Hoeveel sterren geef jij dit?</legend>
<div class="star-wrapper">
<a
hx-vals='{"vote": "1"}'
hx-post="{% url 'vote' %}"
></a>
<a
hx-vals='{"vote": "2"}'
hx-post="{% url 'vote' %}"
></a>
<a
hx-vals='{"vote": "3"}'
hx-post="{% url 'vote' %}"
></a>
<a
hx-vals='{"vote": "4"}'
hx-post="{% url 'vote' %}"
></a>
<a
hx-vals='{"vote": "5"}'
hx-post="{% url 'vote' %}"
></a>
</div>
</fieldset>
<div
id="vote-stars"
hx-vals='{"spotify_id": "{{ track.id }}"}'
style="margin-top:10px;"
>
<fieldset>
<legend>Hoeveel sterren geef jij dit?</legend>
<div class="star-wrapper">
<a
hx-vals='{"vote": "1"}'
hx-post="{% url 'vote' %}"
></a>
<a
hx-vals='{"vote": "2"}'
hx-post="{% url 'vote' %}"
></a>
<a
hx-vals='{"vote": "3"}'
hx-post="{% url 'vote' %}"
></a>
<a
hx-vals='{"vote": "4"}'
hx-post="{% url 'vote' %}"
></a>
<a
hx-vals='{"vote": "5"}'
hx-post="{% url 'vote' %}"
></a>
</div>
</fieldset>
{% if undo %}
<!--<form class="undo-wrapper" method="post" action="{% url 'undo' %}" hx-vals='{"spotify_id": "{{ undo.track.id }}"}' >-->
<div class="undo-wrapper" hx-vals='{"spotify_id": "{{ undo.track.id }}"}' >
{% csrf_token %}
<p>Je hebt {{undo.track}} een score van {{undo.points}} sterren gegeven!</p>
<button class="undo" hx-post="{% url 'undo' %}" >Undo</button>
</div>
{% endif %}
</div>
</div>
{% else %}
<p hx-boost="true">
Je hebt niets meer om te stemmen. Lekker bezig!
<a href="{% url 'nominate' %}">Nomineer zelf iets</a>, als je nog quota hebt.
</p>
{% if undo %}
<!--<form class="undo-wrapper" method="post" action="{% url 'undo' %}" hx-vals='{"spotify_id": "{{ undo.track.id }}"}' >-->
<div class="undo-wrapper" hx-vals='{"spotify_id": "{{ undo.track.id }}"}' >
<div class="undo-wrapper" hx-target="body" hx-vals='{"spotify_id": "{{ undo.track.id }}"}' >
{% csrf_token %}
<p>Je hebt {{undo.track}} een score van {{undo.points}} sterren gegeven!</p>
<button class="undo" hx-post="{% url 'undo' %}" >Undo</button>
</div>
{% endif %}
</div>
</div>
{% endif %}
{% else %}
<p hx-boost="true">
Je hebt niets meer om te stemmen. Lekker bezig!
<a href="{% url 'nominate' %}">Nomineer zelf iets</a>, als je nog quota hebt.
</p>
<p> Stemmen is voorbij. Joe.</p>
{% endif %}
{% endblock %}
{% block clippy %}
{% include "Clippy.html" with body=track.banter img="img/draakje/draakje-headphones3.gif" %}
{% endblock %}
{% block status-bar%}
<div class="status-bar" id="countdown">
<p class="status-bar-field"><span id="days"></span> dagen</p>
<p class="status-bar-field"><span id="hours"></span> uur</p>
<p class="status-bar-field"><span id="minutes"></span> minuten</p>
<p class="status-bar-field"><span id="seconds"></span> seconden</p>
</div>
<script>
document.body.addEventListener('htmx:load', function(evt) {
//startCountdown("2024-08-25T23:59:59+02:00");
startCountdown("{{user.profile.vote_end}}");
});
</script>
{% endblock %}
+1
View File
@@ -2,6 +2,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="{% static 'js/htmx.min.js' %}" defer></script>
<script src="{% static 'js/interact.js' %}" defer></script>
<script src="{% static 'js/countdown.js' %}" defer></script>
<link href="{% static '98.css/style.css' %}" rel="stylesheet" type="text/css" />
<link href="{% static 'style.css'%}" rel="stylesheet" type="text/css" />
<style>
+10 -2
View File
@@ -6,12 +6,17 @@ from django.contrib.auth.mixins import LoginRequiredMixin
from django.db.models import Avg
from django.urls import reverse
import re
import os
from datetime import UTC, datetime
from collections import OrderedDict
from dotenv import load_dotenv
from .models import Track, Artist, Album, Vote, Background, Profile, Playlist
from .utils import from_json, get_unvoted
from .spotify import spt
from .tasks import get_banter, get_and_dither_image
load_dotenv()
class AuthView(View):
def get(self, request):
if request.user.is_authenticated:
@@ -26,7 +31,10 @@ class VoteView(LoginRequiredMixin, View):
get_and_dither_image(track.album.image_url, track.album, "image")
return TemplateResponse(request, "Vote.html", {"track": track, "undo": undo})
def post(self, request):
(profile,_) = Profile.objects.get_or_create(user=request.user)
try:
if not profile.can_vote:
raise Exception(f"{request.user} tried to vote after closing for {track}")
spotify_id = self.request.POST['spotify_id']
score = int(self.request.POST['vote'])
score = min(max(1, score), 5)
@@ -49,10 +57,10 @@ class NominateView(LoginRequiredMixin, View):
def get(self, request):
(profile,_) = Profile.objects.get_or_create(user=request.user)
profile.update_quota()
return TemplateResponse(request, "Nominate.html", {})
return TemplateResponse(request, "Nominate.html", {'end_time': os.getenv('DATE_NOM_END')})
def post(self, request):
(profile,_) = Profile.objects.get_or_create(user=request.user)
if profile.quota < 1:
if not profile.can_nominate[0]:
return TemplateResponse(request, "Nominate.html", {"message_type": "error", "message": "Nee nee nee, dat gaan we dus even niet doen."})
try:
spotify_link = self.request.POST['spotify_link']