1
0

Add authentication for voting

This commit is contained in:
Marcel Schwarz 2022-08-03 02:07:44 +02:00
parent 293c46631e
commit 242870aab2
10 changed files with 211 additions and 38 deletions

View File

@ -1,7 +1,7 @@
from django.contrib import admin
# Register your models here.
from .models import Tobacco, TobaccoCategory, ClubhausEvent, EventDate, EventDateVotes
from .models import Tobacco, TobaccoCategory, ClubhausEvent, EventDate, EventDateVotes, VotingUser
@admin.register(Tobacco)
@ -23,9 +23,15 @@ class EventDateAdmin(admin.ModelAdmin):
ordering = ("id",)
@admin.register(VotingUser)
class VotingUserAdmin(admin.ModelAdmin):
list_display = ("id", "name", "modify_key")
ordering = ("id",)
@admin.register(EventDateVotes)
class EventDateVotesAdmin(admin.ModelAdmin):
list_display = ("id", "name", "date")
list_display = ("id", "voter", "date")
ordering = ("id",)

View File

@ -0,0 +1,19 @@
# Generated by Django 4.0.5 on 2022-08-02 22:25
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('homepage', '0010_alter_eventdatevotes_unique_together_and_more'),
]
operations = [
migrations.AddField(
model_name='eventdatevotes',
name='modify_key',
field=models.TextField(default=''),
preserve_default=False,
),
]

View File

@ -0,0 +1,41 @@
# Generated by Django 4.0.5 on 2022-08-02 23:07
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('homepage', '0011_eventdatevotes_modify_key'),
]
operations = [
migrations.CreateModel(
name='VotingUser',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
],
),
migrations.RemoveConstraint(
model_name='eventdatevotes',
name='unique_name_date',
),
migrations.RemoveField(
model_name='eventdatevotes',
name='modify_key',
),
migrations.RemoveField(
model_name='eventdatevotes',
name='name',
),
migrations.AddConstraint(
model_name='eventdatevotes',
constraint=models.UniqueConstraint(fields=('date',), name='unique_voter_day'),
),
migrations.AddField(
model_name='eventdatevotes',
name='voter',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='homepage.votinguser'),
),
]

View File

@ -0,0 +1,29 @@
# Generated by Django 4.0.5 on 2022-08-02 23:09
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('homepage', '0012_votinguser_remove_eventdatevotes_unique_name_date_and_more'),
]
operations = [
migrations.AddField(
model_name='votinguser',
name='modify_key',
field=models.CharField(default='', max_length=200),
preserve_default=False,
),
migrations.AddField(
model_name='votinguser',
name='name',
field=models.CharField(default='', max_length=200),
preserve_default=False,
),
migrations.AddConstraint(
model_name='votinguser',
constraint=models.UniqueConstraint(fields=('name', 'modify_key'), name='unique_name_modify_key'),
),
]

View File

@ -0,0 +1,20 @@
# Generated by Django 4.0.5 on 2022-08-02 23:09
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('homepage', '0013_votinguser_modify_key_votinguser_name_and_more'),
]
operations = [
migrations.AlterField(
model_name='eventdatevotes',
name='voter',
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='homepage.votinguser'),
preserve_default=False,
),
]

View File

@ -0,0 +1,21 @@
# Generated by Django 4.0.5 on 2022-08-02 23:35
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('homepage', '0014_alter_eventdatevotes_voter'),
]
operations = [
migrations.RemoveConstraint(
model_name='eventdatevotes',
name='unique_voter_day',
),
migrations.AddConstraint(
model_name='eventdatevotes',
constraint=models.UniqueConstraint(fields=('voter', 'date'), name='unique_voter_day'),
),
]

View File

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

View File

@ -43,13 +43,27 @@ class ClubhausEvent(models.Model):
class EventDateVotes(models.Model):
name = models.CharField(max_length=200, blank=False)
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 = [
models.UniqueConstraint(fields=("name", "date"), name="unique_name_date")
models.UniqueConstraint(fields=("voter", "date"), name="unique_voter_day")
]
def __str__(self):
return f"{self.name} - {self.date.date.isoformat()}"
return f"{self.voter.name}({self.voter.id}) - {self.date.date.isoformat()}"
class VotingUser(models.Model):
name = models.CharField(max_length=200, blank=False)
modify_key = models.CharField(max_length=200, blank=False)
class Meta:
constraints = [
models.UniqueConstraint(fields=("name", "modify_key"), name="unique_name_modify_key")
]
def __str__(self):
return f"{self.name}({self.id})"

View File

@ -99,11 +99,12 @@
</tr>
</thead>
<tbody class="table-group-divider">
{% for voter in votes.items %}
{% regroup votes by voter as voter_grouped %}
{% for indv_voter, indv_votes in voter_grouped %}
<tr>
<td>{{ voter.0 }}</td>
{% for date in voter.1.items %}
{% if date.1 %}
<td>{{ indv_voter.name }}</td>
{% for indv_vote in indv_votes %}
{% if indv_vote.available %}
<td><i class="fs-4 text-success bi-check-circle"></i></td>
{% else %}
<td><i class="fs-4 text-danger bi-x-circle"></i></td>
@ -175,22 +176,29 @@
</div>
<div class="modal-body">
{% csrf_token %}
<div class="mb-3">
<label for="nameInput" class="form-label">Name</label>
<input type="text" class="form-control" id="nameInput" name="name"
{% if request.session.name %} value="{{ request.session.name }}" {% endif %}>
</div>
{% language 'de' %}
{% for dateOption in dates %}
<div class="form-check">
<input class="form-check-input" type="checkbox"
id="{{ dateOption.date.isoformat }}"
name="{{ dateOption.date.isoformat }}">
<label class="form-check-label" for="flexCheckDefault">
<label class="form-check-label" for="{{ dateOption.date.isoformat }}">
{{ dateOption.date|date:'l, d. F H:i' }}
</label>
</div>
{% endfor %}
{% endlanguage %}
<div class="mb-3">
<label for="nameInput" class="form-label">Name</label>
<input type="text" class="form-control" id="nameInput" name="name" required
{% if request.session.name %} value="{{ request.session.name }}" {% endif %}>
</div>
<div class="mb-3">
<label for="modifyKeyInput" class="form-label">Passwort</label>
<input type="text" class="form-control" id="modifyKeyInput" name="modifyKey"
{% if request.session.modifyKey %} value="{{ request.session.modifyKey }}" {% endif %}>
<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>
</div>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary">Abstimmen</button>

View File

@ -1,11 +1,11 @@
import django.utils.timezone
from django.core.cache import cache
from django.http import HttpRequest, HttpResponseRedirect
from django.http import HttpRequest, HttpResponseRedirect, HttpResponseForbidden
from django.shortcuts import render
from django.urls import reverse
from .models import Tobacco, ClubhausEvent, EventDate, EventDateVotes
import clubhaus.settings as django_settings
from .models import Tobacco, ClubhausEvent, EventDate, EventDateVotes, VotingUser
def index(request: HttpRequest) -> django.http.HttpResponse:
@ -22,20 +22,9 @@ def events(request: HttpRequest) -> django.http.HttpResponse:
if len(next_events) == 1:
next_event = next_events[0]
dates = EventDate.objects.filter(event=next_event).order_by("date")
votes = EventDateVotes.objects.filter(date__event=next_event)
votes = EventDateVotes.objects.filter(date__event=next_event).order_by("voter_id", "date")
voter_names = sorted(set(map(lambda v: v.name, votes)))
vote_map = {}
for voter_name in voter_names:
vote_map[voter_name] = {date.date.isoformat(): False for date in dates}
for vote in votes:
v_name = vote.name
v_date = vote.date.date.isoformat()
if v_name in vote_map and v_date in vote_map[v_name]:
vote_map[v_name][v_date] = True
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': votes})
else:
return HttpResponseRedirect(reverse("index"))
@ -54,13 +43,20 @@ 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) < 3:
if name := request.POST["name"]:
request.session["name"] = name
for date in EventDate.objects.filter(event__active=True).order_by("date"):
if date.date.isoformat() in request.POST:
EventDateVotes.objects.update_or_create(name=name, date=date)
else:
EventDateVotes.objects.filter(name=name, date=date).delete()
if request.method != "POST" and rate_cache.get(cache_key) > django_settings.IP_RATE_LIMIT_COUNT:
return HttpResponseRedirect(reverse("events"))
modify_key = request.POST["modifyKey"] or ""
if name := request.POST["name"]:
request.session["name"] = name
request.session["modifyKey"] = 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")
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})
return HttpResponseRedirect(reverse("events"))