1
0

Add delete option for votes, add "not voted" votes for later added dates

This commit is contained in:
Marcel Schwarz 2022-08-06 01:09:51 +02:00
parent 8d0f520571
commit 8b8868f180
5 changed files with 81 additions and 30 deletions

View File

@ -31,7 +31,8 @@ class VotingUserAdmin(admin.ModelAdmin):
@admin.register(EventDateVotes) @admin.register(EventDateVotes)
class EventDateVotesAdmin(admin.ModelAdmin): class EventDateVotesAdmin(admin.ModelAdmin):
list_display = ("id", "voter", "date") list_display = ("id", "voter", "date", "available")
list_editable = ('available',)
ordering = ("id",) ordering = ("id",)

View File

@ -0,0 +1,19 @@
# Generated by Django 4.0.5 on 2022-08-05 21:24
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('homepage', '0017_remove_eventdatevotes_available'),
]
operations = [
migrations.AddField(
model_name='eventdatevotes',
name='available',
field=models.BooleanField(default=True),
preserve_default=False,
),
]

View File

@ -45,6 +45,7 @@ class ClubhausEvent(models.Model):
class EventDateVotes(models.Model): class EventDateVotes(models.Model):
voter = models.ForeignKey(to="VotingUser", on_delete=models.CASCADE) voter = models.ForeignKey(to="VotingUser", on_delete=models.CASCADE)
date = models.ForeignKey(to="EventDate", to_field="date", on_delete=models.CASCADE) date = models.ForeignKey(to="EventDate", to_field="date", on_delete=models.CASCADE)
available = models.BooleanField()
class Meta: class Meta:
constraints = [ constraints = [
@ -65,4 +66,4 @@ class VotingUser(models.Model):
] ]
def __str__(self): def __str__(self):
return f"{self.name}({self.id})" return f"{self.name} ({self.id})"

View File

@ -28,6 +28,15 @@
new Date("{{ next_event.date.isoformat }}"), new Date("{{ next_event.date.isoformat }}"),
countdown.DAYS | countdown.HOURS | countdown.MINUTES | countdown.SECONDS); countdown.DAYS | countdown.HOURS | countdown.MINUTES | countdown.SECONDS);
</script> </script>
<script>
const form = document.getElementById('votingForm');
form.onsubmit = (e) => {
const deleteBtn = document.getElementById("deleteMeBtn")
if (e.submitter === deleteBtn) {
document.getElementById("deleteMeInput").value = "1"
}
}
</script>
{% endblock %} {% endblock %}
{% block main %} {% block main %}
@ -61,7 +70,8 @@
<!-- links --> <!-- links -->
<div class="row justify-content-center my-5"> <div class="row justify-content-center my-5">
<div class="col-auto display-6 m-2"> <div class="col-auto display-6 m-2">
<a href="https://open.spotify.com/playlist/00FYaeOKftIb4zWDEShmtD?si=78a7ac31b6f84992" target="_blank"> <a href="https://open.spotify.com/playlist/00FYaeOKftIb4zWDEShmtD?si=78a7ac31b6f84992"
target="_blank">
<span class="badge rounded-pill text-bg-dark"><i class="bi-spotify"></i> Playlist</span> <span class="badge rounded-pill text-bg-dark"><i class="bi-spotify"></i> Playlist</span>
</a> </a>
</div> </div>
@ -103,10 +113,12 @@
<tr> <tr>
<td>{{ voter.0.name }}</td> <td>{{ voter.0.name }}</td>
{% for date in voter.1.items %} {% for date in voter.1.items %}
{% if date.1 %} {% if date.1 == True %}
<td><i class="fs-4 text-success bi-check-circle"></i></td> <td><i class="fs-4 text-success bi-check-circle"></i></td>
{% else %} {% elif date.1 == False %}
<td><i class="fs-4 text-danger bi-x-circle"></i></td> <td><i class="fs-4 text-danger bi-x-circle"></i></td>
{% else %}
<td><i class="fs-4 text-warning bi-question-circle"></i></td>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
</tr> </tr>
@ -167,14 +179,15 @@
aria-hidden="true"> aria-hidden="true">
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content text-bg-dark"> <div class="modal-content text-bg-dark">
<form method="post" action="{% url 'voting' %}"> <form id="votingForm" method="post" action="{% url 'voting' %}">
<div class="modal-header"> <div class="modal-header border-secondary">
<h5 class="modal-title" id="exampleModalLabel">Abstimmung</h5> <h5 class="modal-title" id="exampleModalLabel">Abstimmung</h5>
<button type="button" class="btn-close bg-white" data-bs-dismiss="modal" <button type="button" class="btn-close bg-white" data-bs-dismiss="modal"
aria-label="Close"></button> aria-label="Close"></button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
{% csrf_token %} {% csrf_token %}
<input id="deleteMeInput" type="hidden" name="deleteClicked" value="0">
{% language 'de' %} {% language 'de' %}
{% for dateOption in dates %} {% for dateOption in dates %}
<div class="form-check"> <div class="form-check">
@ -187,20 +200,26 @@
</div> </div>
{% endfor %} {% endfor %}
{% endlanguage %} {% endlanguage %}
<div class="mb-3"> <div class="my-3">
<label for="nameInput" class="form-label">Name</label> <label for="nameInput" class="form-label">Name</label>
<input type="text" class="form-control" id="nameInput" name="name" required <input type="text" class="form-control" id="nameInput" name="name" required
{% if request.session.name %} value="{{ request.session.name }}" {% endif %}> {% if request.session.name %} value="{{ request.session.name }}" {% endif %}>
</div> </div>
<div class="mb-3"> <div>
<label for="modifyKeyInput" class="form-label">Passwort</label> <label for="modifyKeyInput" class="form-label">Parole</label>
<input type="text" class="form-control" id="modifyKeyInput" name="modifyKey" <input type="text" class="form-control" id="modifyKeyInput" name="modifyKey"
{% if request.session.modifyKey %} value="{{ request.session.modifyKey }}" {% endif %}> {% if request.session.modifyKey %}
<div id="modifyKeyHelp" class="form-text">Damit nur du deine Einträge ändern kannst, solltest du ein Passwort vergeben. Tust du dies nicht, kann jeder deine Einträge ändern und löschen!</div> value="{{ request.session.modifyKey }}" {% endif %}>
<div id="modifyKeyHelp" class="form-text">Damit nur du deine Einträge ändern kannst,
solltest du eine Parole vergeben. Tust du dies nicht, kann jeder deine Einträge ändern
und löschen!
</div> </div>
</div> </div>
<div class="modal-footer"> </div>
<button type="submit" class="btn btn-primary">Abstimmen</button> <div class="modal-footer border-secondary">
<button id="submitVoteBtn" type="submit" class="btn btn-primary order-1">Abstimmen</button>
<button id="deleteMeBtn" type="submit" class="btn btn-danger me-auto order-0">Lösche mich
</button>
</div> </div>
</form> </form>
</div> </div>

View File

@ -36,13 +36,13 @@ def events(request: HttpRequest) -> django.http.HttpResponse:
unique_voters = list(set(map(lambda v: v.voter, votes))) unique_voters = list(set(map(lambda v: v.voter, votes)))
vote_map = {} vote_map = {}
for voter in unique_voters: for voter in unique_voters:
vote_map[voter] = {date.date.isoformat(): False for date in dates} vote_map[voter] = {date.date.isoformat(): None for date in dates}
for vote in votes: for vote in votes:
voter = vote.voter voter = vote.voter
v_date = vote.date.date.isoformat() v_date = vote.date.date.isoformat()
if voter in vote_map and v_date in vote_map[voter]: if voter in vote_map and v_date in vote_map[voter]:
vote_map[voter][v_date] = True vote_map[voter][v_date] = vote.available
return render(request, 'homepage/events.html', {'next_event': next_event, "dates": dates, 'votes': vote_map}) return render(request, 'homepage/events.html', {'next_event': next_event, "dates": dates, 'votes': vote_map})
else: else:
@ -56,6 +56,10 @@ def voting(request: HttpRequest) -> django.http.HttpResponse:
if request.META.get("X-Forwarded-For"): if request.META.get("X-Forwarded-For"):
raise ProxyUsageDetected() raise ProxyUsageDetected()
if request.method != "POST":
return HttpResponseRedirect(reverse("events"))
# Check rate limit
ip = request.META.get("REMOTE_ADDR") ip = request.META.get("REMOTE_ADDR")
cache_key = f"voting_block_{ip}" cache_key = f"voting_block_{ip}"
rate_cache: django.core.cache.BaseCache = cache rate_cache: django.core.cache.BaseCache = cache
@ -63,23 +67,30 @@ def voting(request: HttpRequest) -> django.http.HttpResponse:
rate_cache.add(cache_key, 0, django_settings.IP_RATE_LIMIT_TIME) rate_cache.add(cache_key, 0, django_settings.IP_RATE_LIMIT_TIME)
rate_cache.incr(cache_key) rate_cache.incr(cache_key)
if request.method != "POST":
return HttpResponseRedirect(reverse("events"))
if rate_cache.get(cache_key) > django_settings.IP_RATE_LIMIT_COUNT: if rate_cache.get(cache_key) > django_settings.IP_RATE_LIMIT_COUNT:
raise RateLimitHit() raise RateLimitHit()
# check params
if not request.POST["name"]:
return HttpResponseRedirect(reverse("events"))
name = request.POST["name"]
modify_key = request.POST["modifyKey"] or "" modify_key = request.POST["modifyKey"] or ""
if name := request.POST["name"]:
request.session["name"] = name request.session["name"] = name
request.session["modifyKey"] = modify_key request.session["modifyKey"] = modify_key
# handle delete
if request.POST["deleteClicked"] == "1":
VotingUser.objects.filter(name=name, modify_key=modify_key).delete()
return HttpResponseRedirect(reverse("events"))
# handle normal voting
user, _ = VotingUser.objects.get_or_create(name=name, modify_key=modify_key) user, _ = VotingUser.objects.get_or_create(name=name, modify_key=modify_key)
event_dates = EventDate.objects.filter(event__active=True).order_by("date") event_dates = EventDate.objects.filter(event__active=True).order_by("date")
for date in event_dates: for date in event_dates:
if date.date.isoformat() in request.POST: available = date.date.isoformat() in request.POST
EventDateVotes.objects.update_or_create(voter=user, date=date) EventDateVotes.objects.update_or_create(voter=user, date=date, defaults={"available": available})
else:
EventDateVotes.objects.filter(voter=user, date=date).delete()
return HttpResponseRedirect(reverse("events")) return HttpResponseRedirect(reverse("events"))