Fix issue when adding a date when some votes already exist, Add 400 page
This commit is contained in:
parent
4d58bf529c
commit
986b529794
@ -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(" ")
|
||||||
|
|
||||||
|
@ -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"
|
||||||
|
17
clubhaus/homepage/exceptions.py
Normal file
17
clubhaus/homepage/exceptions.py
Normal 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}"
|
@ -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',
|
||||||
|
),
|
||||||
|
]
|
@ -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 = [
|
||||||
|
16
clubhaus/homepage/templates/homepage/400.html
Normal file
16
clubhaus/homepage/templates/homepage/400.html
Normal 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 %}
|
@ -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>
|
||||||
|
@ -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"))
|
||||||
|
Loading…
Reference in New Issue
Block a user