diff --git a/clubhaus/clubhaus/settings.py b/clubhaus/clubhaus/settings.py
index c226bfa..f4e6f74 100644
--- a/clubhaus/clubhaus/settings.py
+++ b/clubhaus/clubhaus/settings.py
@@ -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@")
# 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(" ")
diff --git a/clubhaus/clubhaus/urls.py b/clubhaus/clubhaus/urls.py
index d4528fa..dd19822 100644
--- a/clubhaus/clubhaus/urls.py
+++ b/clubhaus/clubhaus/urls.py
@@ -22,3 +22,5 @@ urlpatterns = [
path('', include('homepage.urls')),
path('admin/', admin.site.urls),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
+
+handler400 = "homepage.views.bad_request"
diff --git a/clubhaus/homepage/exceptions.py b/clubhaus/homepage/exceptions.py
new file mode 100644
index 0000000..a8bc423
--- /dev/null
+++ b/clubhaus/homepage/exceptions.py
@@ -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}"
diff --git a/clubhaus/homepage/migrations/0017_remove_eventdatevotes_available.py b/clubhaus/homepage/migrations/0017_remove_eventdatevotes_available.py
new file mode 100644
index 0000000..ceded76
--- /dev/null
+++ b/clubhaus/homepage/migrations/0017_remove_eventdatevotes_available.py
@@ -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',
+ ),
+ ]
diff --git a/clubhaus/homepage/models.py b/clubhaus/homepage/models.py
index b244311..9c2903c 100644
--- a/clubhaus/homepage/models.py
+++ b/clubhaus/homepage/models.py
@@ -45,7 +45,6 @@ class ClubhausEvent(models.Model):
class EventDateVotes(models.Model):
voter = models.ForeignKey(to="VotingUser", on_delete=models.CASCADE)
date = models.ForeignKey(to="EventDate", to_field="date", on_delete=models.CASCADE)
- available = models.BooleanField(blank=False)
class Meta:
constraints = [
diff --git a/clubhaus/homepage/templates/homepage/400.html b/clubhaus/homepage/templates/homepage/400.html
new file mode 100644
index 0000000..afc5eb7
--- /dev/null
+++ b/clubhaus/homepage/templates/homepage/400.html
@@ -0,0 +1,16 @@
+{% extends 'homepage/base.html' %}
+
+{% block main %}
+
+
+
+
Bad Request (400)
+
+
+ {% if exception %}
+
{{ exception }}
+ {% endif %}
+
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/clubhaus/homepage/templates/homepage/events.html b/clubhaus/homepage/templates/homepage/events.html
index f46ee89..b3da3bf 100644
--- a/clubhaus/homepage/templates/homepage/events.html
+++ b/clubhaus/homepage/templates/homepage/events.html
@@ -99,12 +99,11 @@
- {% regroup votes by voter as voter_grouped %}
- {% for indv_voter, indv_votes in voter_grouped %}
+ {% for voter in votes.items %}
- {{ indv_voter.name }} |
- {% for indv_vote in indv_votes %}
- {% if indv_vote.available %}
+ {{ voter.0.name }} |
+ {% for date in voter.1.items %}
+ {% if date.1 %}
|
{% else %}
|
diff --git a/clubhaus/homepage/urls.py b/clubhaus/homepage/urls.py
index 00f548d..4f53a94 100644
--- a/clubhaus/homepage/urls.py
+++ b/clubhaus/homepage/urls.py
@@ -7,4 +7,4 @@ urlpatterns = [
path('event', views.events, name='events'),
path('tobacco', views.tobacco, name='tobacco'),
path('voting', views.voting, name='voting'),
-]
\ No newline at end of file
+]
diff --git a/clubhaus/homepage/views.py b/clubhaus/homepage/views.py
index 8f96df5..3601039 100644
--- a/clubhaus/homepage/views.py
+++ b/clubhaus/homepage/views.py
@@ -1,13 +1,18 @@
import django.utils.timezone
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.urls import reverse
import clubhaus.settings as django_settings
+from .exceptions import RateLimitHit, ProxyUsageDetected
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:
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")
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:
return HttpResponseRedirect(reverse("index"))
@@ -34,7 +50,7 @@ def voting(request: HttpRequest) -> django.http.HttpResponse:
# Proxy use is forbidden
if request.META.get("X-Forwarded-For"):
- return HttpResponseForbidden()
+ raise ProxyUsageDetected()
ip = request.META.get("REMOTE_ADDR")
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.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"))
+ if rate_cache.get(cache_key) > django_settings.IP_RATE_LIMIT_COUNT:
+ raise RateLimitHit()
+
modify_key = request.POST["modifyKey"] or ""
if name := request.POST["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")
for date in event_dates:
- date_in_request = date.date.isoformat() in request.POST
- EventDateVotes.objects.update_or_create(
- voter=user, date=date,
- defaults={"voter": user, "date": date, "available": date_in_request})
+ if date.date.isoformat() in request.POST:
+ EventDateVotes.objects.update_or_create(voter=user, date=date)
+ else:
+ EventDateVotes.objects.filter(voter=user, date=date).delete()
return HttpResponseRedirect(reverse("events"))