1
0

Fix issue when adding a date when some votes already exist, Add 400 page

This commit is contained in:
Marcel Schwarz 2022-08-03 21:00:33 +02:00
parent 4d58bf529c
commit 986b529794
9 changed files with 85 additions and 16 deletions

View File

@ -24,7 +24,7 @@ BASE_DIR = Path(__file__).resolve().parent.parent
SECRET_KEY = os.getenv("SECRET_KEY", "django-insecure-!@gqe(nmv4ylos+2p14nk+&8h$j7g%=n4sdrwqzvr6!8ee$y9@") SECRET_KEY = os.getenv("SECRET_KEY", "django-insecure-!@gqe(nmv4ylos+2p14nk+&8h$j7g%=n4sdrwqzvr6!8ee$y9@")
# SECURITY WARNING: don't run with debug turned on in production! # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = os.getenv("DEBUG_MODE", True) DEBUG = os.getenv("DEBUG_MODE", "True") == "True"
ALLOWED_HOSTS = os.getenv("ALLOWED_HOSTS", "* 192.168.235.51 127.0.0.1 localhost 192.168.0.52 192.168.235.35").split(" ") ALLOWED_HOSTS = os.getenv("ALLOWED_HOSTS", "* 192.168.235.51 127.0.0.1 localhost 192.168.0.52 192.168.235.35").split(" ")

View File

@ -22,3 +22,5 @@ urlpatterns = [
path('', include('homepage.urls')), path('', include('homepage.urls')),
path('admin/', admin.site.urls), path('admin/', admin.site.urls),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
handler400 = "homepage.views.bad_request"

View File

@ -0,0 +1,17 @@
from django.core import exceptions
class RateLimitHit(exceptions.SuspiciousOperation):
def __init__(self):
self.text = "You made to many request in a short period of time! Please try again later"
def __str__(self):
return f"{self.__class__.__name__}: {self.text}"
class ProxyUsageDetected(exceptions.SuspiciousOperation):
def __init__(self):
self.text = "It appears you are using a proxy! We don't want you to do that!"
def __str__(self):
return f"{self.__class__.__name__}: {self.text}"

View File

@ -0,0 +1,17 @@
# Generated by Django 4.0.5 on 2022-08-03 17:45
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('homepage', '0016_eventdatevotes_available'),
]
operations = [
migrations.RemoveField(
model_name='eventdatevotes',
name='available',
),
]

View File

@ -45,7 +45,6 @@ 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(blank=False)
class Meta: class Meta:
constraints = [ constraints = [

View File

@ -0,0 +1,16 @@
{% extends 'homepage/base.html' %}
{% block main %}
<div class="d-flex h-100 mx-3">
<main class="d-flex flex-column flex-grow-1 w-100 my-5 mx-auto text-white" style="max-width: 42rem">
<div class="row">
<h1>Bad Request (400)</h1>
</div>
<div class="row">
{% if exception %}
<h6>{{ exception }}</h6>
{% endif %}
</div>
</main>
</div>
{% endblock %}

View File

@ -99,12 +99,11 @@
</tr> </tr>
</thead> </thead>
<tbody class="table-group-divider"> <tbody class="table-group-divider">
{% regroup votes by voter as voter_grouped %} {% for voter in votes.items %}
{% for indv_voter, indv_votes in voter_grouped %}
<tr> <tr>
<td>{{ indv_voter.name }}</td> <td>{{ voter.0.name }}</td>
{% for indv_vote in indv_votes %} {% for date in voter.1.items %}
{% if indv_vote.available %} {% if date.1 %}
<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 %} {% else %}
<td><i class="fs-4 text-danger bi-x-circle"></i></td> <td><i class="fs-4 text-danger bi-x-circle"></i></td>

View File

@ -7,4 +7,4 @@ urlpatterns = [
path('event', views.events, name='events'), path('event', views.events, name='events'),
path('tobacco', views.tobacco, name='tobacco'), path('tobacco', views.tobacco, name='tobacco'),
path('voting', views.voting, name='voting'), path('voting', views.voting, name='voting'),
] ]

View File

@ -1,13 +1,18 @@
import django.utils.timezone import django.utils.timezone
from django.core.cache import cache from django.core.cache import cache
from django.http import HttpRequest, HttpResponseRedirect, HttpResponseForbidden from django.http import HttpRequest, HttpResponseRedirect
from django.shortcuts import render from django.shortcuts import render
from django.urls import reverse from django.urls import reverse
import clubhaus.settings as django_settings import clubhaus.settings as django_settings
from .exceptions import RateLimitHit, ProxyUsageDetected
from .models import Tobacco, ClubhausEvent, EventDate, EventDateVotes, VotingUser from .models import Tobacco, ClubhausEvent, EventDate, EventDateVotes, VotingUser
def bad_request(request, exception, template_name="homepage/400.html"):
return render(request, template_name, context={"exception": exception}, status=400)
def index(request: HttpRequest) -> django.http.HttpResponse: def index(request: HttpRequest) -> django.http.HttpResponse:
return render(request, 'homepage/index.html', {}) return render(request, 'homepage/index.html', {})
@ -24,7 +29,18 @@ def events(request: HttpRequest) -> django.http.HttpResponse:
dates = EventDate.objects.filter(event=next_event).order_by("date") dates = EventDate.objects.filter(event=next_event).order_by("date")
votes = EventDateVotes.objects.filter(date__event=next_event).order_by("voter_id", "date") votes = EventDateVotes.objects.filter(date__event=next_event).order_by("voter_id", "date")
return render(request, 'homepage/events.html', {'next_event': next_event, "dates": dates, 'votes': votes}) unique_voters = list(set(map(lambda v: v.voter, votes)))
vote_map = {}
for voter in unique_voters:
vote_map[voter] = {date.date.isoformat(): False for date in dates}
for vote in votes:
voter = vote.voter
v_date = vote.date.date.isoformat()
if voter in vote_map and v_date in vote_map[voter]:
vote_map[voter][v_date] = True
return render(request, 'homepage/events.html', {'next_event': next_event, "dates": dates, 'votes': vote_map})
else: else:
return HttpResponseRedirect(reverse("index")) return HttpResponseRedirect(reverse("index"))
@ -34,7 +50,7 @@ def voting(request: HttpRequest) -> django.http.HttpResponse:
# Proxy use is forbidden # Proxy use is forbidden
if request.META.get("X-Forwarded-For"): if request.META.get("X-Forwarded-For"):
return HttpResponseForbidden() raise ProxyUsageDetected()
ip = request.META.get("REMOTE_ADDR") ip = request.META.get("REMOTE_ADDR")
cache_key = f"voting_block_{ip}" cache_key = f"voting_block_{ip}"
@ -43,9 +59,12 @@ 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" and rate_cache.get(cache_key) > django_settings.IP_RATE_LIMIT_COUNT: if request.method != "POST":
return HttpResponseRedirect(reverse("events")) return HttpResponseRedirect(reverse("events"))
if rate_cache.get(cache_key) > django_settings.IP_RATE_LIMIT_COUNT:
raise RateLimitHit()
modify_key = request.POST["modifyKey"] or "" modify_key = request.POST["modifyKey"] or ""
if name := request.POST["name"]: if name := request.POST["name"]:
request.session["name"] = name request.session["name"] = name
@ -54,9 +73,9 @@ def voting(request: HttpRequest) -> django.http.HttpResponse:
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:
date_in_request = date.date.isoformat() in request.POST if date.date.isoformat() in request.POST:
EventDateVotes.objects.update_or_create( EventDateVotes.objects.update_or_create(voter=user, date=date)
voter=user, date=date, else:
defaults={"voter": user, "date": date, "available": date_in_request}) EventDateVotes.objects.filter(voter=user, date=date).delete()
return HttpResponseRedirect(reverse("events")) return HttpResponseRedirect(reverse("events"))