diff --git a/playlist/models/vote.py b/playlist/models/vote.py index d05712c..e927613 100644 --- a/playlist/models/vote.py +++ b/playlist/models/vote.py @@ -7,3 +7,4 @@ class Vote(models.Model): track = models.ForeignKey('Track', on_delete=models.CASCADE) user = models.ForeignKey(User, on_delete=models.CASCADE) points = models.IntegerField() + skipped = models.BooleanField(default=False) diff --git a/playlist/static/img/download.png b/playlist/static/img/download.png new file mode 100644 index 0000000..5d96a1b Binary files /dev/null and b/playlist/static/img/download.png differ diff --git a/playlist/static/style.css b/playlist/static/style.css index 5442288..d494e70 100644 --- a/playlist/static/style.css +++ b/playlist/static/style.css @@ -457,6 +457,7 @@ input[type="range"]#volume::-webkit-slider-thumb { .undo-wrapper p { flex-grow: 1; padding: 0 5px; + text-align: right; } .undo { @@ -465,6 +466,17 @@ input[type="range"]#volume::-webkit-slider-thumb { background-position: 50% 0; padding: 32px 0 4px 0; height: 50px; + min-width: 40px; +} + +.skip { + background-image: url(img/download.png); + background-repeat: no-repeat; + background-position: 50% 20%; + padding: 32px 0 4px 0; + height: 50px; + min-width: 40px; + margin-left: 5px; } .progress-indicator { diff --git a/playlist/templates/Vote.html b/playlist/templates/Vote.html index adb2646..327b6d6 100644 --- a/playlist/templates/Vote.html +++ b/playlist/templates/Vote.html @@ -41,14 +41,19 @@ Stemmen > +
+ {% if not skipped %} + {% csrf_token %} + + {% endif %} +
+
{% if undo %} - -
{% csrf_token %}

Je hebt {{undo.track}} een score van {{undo.points}} sterren gegeven!

-
{% endif %} +
{% else %} diff --git a/playlist/urls.py b/playlist/urls.py index 28c8394..f7d4d77 100644 --- a/playlist/urls.py +++ b/playlist/urls.py @@ -7,6 +7,7 @@ urlpatterns = [ path('track/', views.NominateView.as_view(), name="nominate"), path('vote/', views.VoteView.as_view(), name="vote"), path('vote/undo', views.UndoView.as_view(), name="undo"), + path('vote/skip', views.SkipView.as_view(), name="skip"), path('settings/', views.SettingsView.as_view(), name="settings"), path('overview/', views.OverView.as_view(), name="overview"), path('overview/playlist', views.PlaylistListView.as_view(), name="playlist-list"), diff --git a/playlist/utils.py b/playlist/utils.py index f0ef518..788beba 100644 --- a/playlist/utils.py +++ b/playlist/utils.py @@ -10,11 +10,18 @@ def from_json(cls, json): return cls.objects.create(**subset) def get_unvoted(user): + """Gets next voting track for user. Returns a pair with track and flag if this was a skipped track""" votes = set(Vote.objects.filter(user=user).values_list('track_id', flat=True)) tracks = set(Track.objects.filter(banter_done=True).values_list('pk', flat=True)) seed(user.username) try: - random_track = choice(list(tracks - votes)) - return Track.objects.get(pk=random_track) + queue = list(tracks - votes) + skipped = False + if not queue: + skipped = True + queue = list(Vote.objects.filter(user=user).filter(skipped=True).values_list('track_id', flat=True)) + random_track = choice(queue) + choice + return (Track.objects.get(pk=random_track), skipped) except IndexError: - return None + return (None, False) diff --git a/playlist/views.py b/playlist/views.py index 79f8aca..c6ae980 100644 --- a/playlist/views.py +++ b/playlist/views.py @@ -26,10 +26,10 @@ class AuthView(View): class VoteView(LoginRequiredMixin, View): def get(self, request, undo=None): - track = get_unvoted(request.user) + (track, skipped) = get_unvoted(request.user) if track and not track.album.image: get_and_dither_image(track.album.image_url, track.album, "image") - return TemplateResponse(request, "Vote.html", {"track": track, "undo": undo}) + return TemplateResponse(request, "Vote.html", {"track": track, "undo": undo, "skipped": skipped}) def post(self, request): (profile,_) = Profile.objects.get_or_create(user=request.user) try: @@ -40,11 +40,14 @@ class VoteView(LoginRequiredMixin, View): score = min(max(1, score), 5) track = Track.objects.get(pk=spotify_id) try: - Vote.objects.get(user=request.user, track=track) + prevote = Vote.objects.get(user=request.user, track=track) except Vote.DoesNotExist: pass else: - raise Exception(f"{request.user} already voted for {track}") + if not prevote.skipped: + raise Exception(f"{request.user} already voted for {track}") + else: + prevote.delete() vote = Vote.objects.create(track=track, user=request.user, points=score) (profile,_) = Profile.objects.get_or_create(user=request.user) profile.last_voted = track @@ -186,6 +189,26 @@ class UndoView(LoginRequiredMixin, View): vote.delete() return HttpResponseRedirect('/vote/') +class SkipView(LoginRequiredMixin, View): + def get(self, request): + return HttpResponseRedirect('/vote/') + def post(self, request): + spotify_id = self.request.POST['spotify_id'] + track = Track.objects.get(pk=spotify_id) + (profile,_) = Profile.objects.get_or_create(user=request.user) + if not profile.can_vote: + raise Exception(f"{request.user} tried to vote after closing for {track}") + vote = None + try: + vote = Vote.objects.get(user=request.user, track=track) + except Vote.DoesNotExist: + pass + profile.last_voted = None + profile.save() + vote = Vote.objects.create(track=track, user=request.user, points=0, skipped=True) + profile.save() + return self.get(request) + class OverView(LoginRequiredMixin, View): def get(self, request): votes = Vote.objects.select_related().distinct()