From e542e3fdc02514961ba917a0dc5610d78a196877 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Reynir=20Bj=C3=B6rnsson?= Date: Mon, 13 Apr 2020 13:59:45 +0200 Subject: [PATCH] Minimal working web app --- config/urls.py | 3 +- schedule/converters.py | 10 +++ schedule/migrations/0001_initial.py | 45 +++++++++++++ .../migrations/0002_auto_20200411_1621.py | 27 ++++++++ schedule/models.py | 12 +++- schedule/templates/schedule/schedule.html | 37 +++++++++++ schedule/urls.py | 12 ++++ schedule/views.py | 63 ++++++++++++++++++- 8 files changed, 204 insertions(+), 5 deletions(-) create mode 100644 schedule/converters.py create mode 100644 schedule/migrations/0001_initial.py create mode 100644 schedule/migrations/0002_auto_20200411_1621.py create mode 100644 schedule/templates/schedule/schedule.html create mode 100644 schedule/urls.py diff --git a/config/urls.py b/config/urls.py index 082579f..fd1d2a2 100644 --- a/config/urls.py +++ b/config/urls.py @@ -14,8 +14,9 @@ Including another URLconf 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin -from django.urls import path +from django.urls import include, path urlpatterns = [ + path('schedule/', include('schedule.urls')), path('admin/', admin.site.urls), ] diff --git a/schedule/converters.py b/schedule/converters.py new file mode 100644 index 0000000..ae926a1 --- /dev/null +++ b/schedule/converters.py @@ -0,0 +1,10 @@ +from datetime import date + +class DateConverter: + regex = '[0-9]{4}-[0-9]{2}-[0-9]{2}' + + def to_python(self, value): + return date.fromisoformat(value) + + def to_url(self, value): + return value.isoformat() diff --git a/schedule/migrations/0001_initial.py b/schedule/migrations/0001_initial.py new file mode 100644 index 0000000..2cead39 --- /dev/null +++ b/schedule/migrations/0001_initial.py @@ -0,0 +1,45 @@ +# Generated by Django 3.0.5 on 2020-04-09 13:11 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Member', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('member_number', models.PositiveIntegerField(blank=True, null=True, unique=True, verbose_name='aoff member number')), + ], + ), + migrations.CreateModel( + name='PickupDate', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('date', models.DateField(verbose_name='date of pickup')), + ], + ), + migrations.CreateModel( + name='Timeslot', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('start', models.TimeField(verbose_name='start of timeslot')), + ], + ), + migrations.CreateModel( + name='Pickup', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('date', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='schedule.PickupDate')), + ('member', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='schedule.Member')), + ('time', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='schedule.Timeslot')), + ], + ), + ] diff --git a/schedule/migrations/0002_auto_20200411_1621.py b/schedule/migrations/0002_auto_20200411_1621.py new file mode 100644 index 0000000..2616c86 --- /dev/null +++ b/schedule/migrations/0002_auto_20200411_1621.py @@ -0,0 +1,27 @@ +# Generated by Django 3.0.5 on 2020-04-11 16:21 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('schedule', '0001_initial'), + ] + + operations = [ + migrations.AlterModelOptions( + name='timeslot', + options={'ordering': ['start']}, + ), + migrations.AlterField( + model_name='member', + name='member_number', + field=models.PositiveIntegerField(blank=True, null=True, verbose_name='aoff member number'), + ), + migrations.AlterField( + model_name='pickupdate', + name='date', + field=models.DateField(unique=True, verbose_name='date of pickup'), + ), + ] diff --git a/schedule/models.py b/schedule/models.py index fe7bcac..0375f97 100644 --- a/schedule/models.py +++ b/schedule/models.py @@ -3,16 +3,24 @@ from django.db import models # Create your models here. class PickupDate(models.Model): - date = models.DateField('date of pickup') + date = models.DateField('date of pickup', unique=True) + + def __str__(self): + return str(self.date) class Timeslot(models.Model): start = models.TimeField('start of timeslot') # open-ended for now + def __str__(self): + return self.start.isoformat(timespec='minutes') + + class Meta: + ordering = ['start'] + class Member(models.Model): member_number = models.PositiveIntegerField( verbose_name='aoff member number', - unique=True, blank=True, null=True, ) diff --git a/schedule/templates/schedule/schedule.html b/schedule/templates/schedule/schedule.html new file mode 100644 index 0000000..83f494e --- /dev/null +++ b/schedule/templates/schedule/schedule.html @@ -0,0 +1,37 @@ + +AOFF + +

Afhentningstidsplan

+

For at minimere kødannelse bedes medlemmer der skal afhente grøntsager om at vælge hvornår de har tænkt sig at afhente sine grøntsager. +Det er hverken bindende eller et krav, men blot en hjælp til vores medlemmer så I kan planlægge afhentning når der er få der skal hente.

+

Det foregår anonymt - andre kan ikke se hvem der henter hvornår. +Vi gemmer en såkaldt 'cookie' i din browser med det eneste formål så hvis du kommer tilbage til siden senere i samme browser kan du opdatere eller fjerne dit valgte afhentningstidspunkt. +Bemærk at du ikke kan ændre afhentningstidspunkt fra en anden browser eller hvis cookien bliver fjernet. +Du kan skrive dit medlemsnummer for at hjælpe administratorer i at rette dine afhentningstidspunkter, men det er ikke et krav.

+ +

Afhentning {{ date }}

+
+ {% csrf_token %} + + + + + + + + {# Action #} + + + {% for timeslot in timeslots %} + + + + + {% endfor %} +
TidspunktRegistrerede afhentninger
{{ timeslot.start | time:"H:i" }}{{ timeslot.sum }} {% if timeslot.own_pickup %}(inklusiv dig){% endif %}{% if timeslot.own_pickup %} + + {% else %} + + {% endif %} +
+
diff --git a/schedule/urls.py b/schedule/urls.py new file mode 100644 index 0000000..9c0bf31 --- /dev/null +++ b/schedule/urls.py @@ -0,0 +1,12 @@ +from django.urls import path, register_converter + +from . import views, converters + +register_converter(converters.DateConverter, 'date') + +app_name = 'schedule' +urlpatterns = [ + path('/', views.schedule, name='schedule'), + path('/submit', views.submit_pickup, name='submit_pickup'), + path('/remove', views.submit_pickup_removal, name='submit_pickup_removal'), +] diff --git a/schedule/views.py b/schedule/views.py index 91ea44a..a5864b3 100644 --- a/schedule/views.py +++ b/schedule/views.py @@ -1,3 +1,62 @@ -from django.shortcuts import render +from django.shortcuts import get_object_or_404, render +from .models import * +from django.http import Http404, HttpResponseRedirect +from django.urls import reverse -# Create your views here. +def schedule(request, date): + date = get_object_or_404(PickupDate, date=date) + member_number = request.POST and request.POST.get('member_number') \ + or None + member_id = request.session.get('member_id') + if member_id is not None: + member = get_object_or_404(Member, pk=member_id) + elif member_number: + member = Member() + request.session['member_id'] = member.id + request.session.set_expiry(0) + else: + member = None + if member_number and member.member_number != member_number: + member.member_number = member_number + member.save() + timeslots = Timeslot.objects.all() + for timeslot in timeslots: + timeslot.sum = len(Pickup.objects.filter(time=timeslot)) + if member: + try: + timeslot.own_pickup = \ + Pickup.objects.filter( + date=date, + time=timeslot, + member=member, + ).exists() + except Pickup.DoesNotExist: + timeslot.own_pickup = False + else: + timeslot.own_pickup = False + + return render(request, 'schedule/schedule.html', + { 'date': date, + 'timeslots': timeslots, + }) + +def submit_pickup(request, date): + date = get_object_or_404(PickupDate, date=date) + request.session.set_expiry(0) + member_id = request.session.get('member_id') + if not member_id: + member = Member(member_number=request.POST.get('member_number')) + member.save() + request.session['member_id'] = member.id + else: + member = get_object_or_404(Member, pk=member_id) + timeslot = get_object_or_404(Timeslot, pk=request.POST.get('timeslot')) + Pickup(date=date, time=timeslot, member=member).save() + return HttpResponseRedirect(reverse('schedule:schedule', args=(date.date,))) + +def submit_pickup_removal(request, date): + date = get_object_or_404(PickupDate, date=date) + member = get_object_or_404(Member, pk=request.session.get('member_id')) + timeslot = get_object_or_404(Timeslot, pk=request.POST.get('timeslot')) + Pickup.objects.filter(date=date, time=timeslot, member=member).delete() + return HttpResponseRedirect(reverse('schedule:schedule', args=(date.date,)))