Add delete option for votes, add "not voted" votes for later added dates
This commit is contained in:
parent
8d0f520571
commit
8b8868f180
@ -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",)
|
||||||
|
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
),
|
||||||
|
]
|
@ -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 = [
|
||||||
|
@ -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>
|
||||||
|
@ -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"))
|
||||||
|
Loading…
Reference in New Issue
Block a user