Free and open source ticket system written in python

init fbl integration

+166 -3
+2 -2
.github/workflows/docker-image.yml
··· 3 3 on: 4 4 push: 5 5 branches: 6 - - "main" 6 + - "fbl-integration" 7 7 - "staging" 8 8 pull_request: 9 - branches: ["main"] 9 + branches: ["fbl-integration"] 10 10 11 11 env: 12 12 REGISTRY: ghcr.io
fbl_integration/__init__.py

This is a binary file and will not be displayed.

+3
fbl_integration/admin.py
··· 1 + from django.contrib import admin 2 + 3 + # Register your models here.
+6
fbl_integration/apps.py
··· 1 + from django.apps import AppConfig 2 + 3 + 4 + class FblIntegrationConfig(AppConfig): 5 + default_auto_field = "django.db.models.BigAutoField" 6 + name = "fbl_integration"
+40
fbl_integration/forms.py
··· 1 + from typing import Any 2 + from django import forms 3 + from django.conf import settings 4 + from django.utils.translation import gettext_lazy as _ 5 + from datetime import datetime 6 + 7 + class FblAuthForm(forms.Form): 8 + badge_number = forms.CharField(required=True) 9 + dob = forms.CharField(required=True) 10 + 11 + def clean(self) -> dict[str, Any]: 12 + cleaned_data = super(FblAuthForm, self).clean() 13 + badge_number = cleaned_data.get("badge_number") 14 + dob = cleaned_data.get("dob") 15 + 16 + if not badge_number: 17 + raise forms.ValidationError( 18 + _("Badge number is required") 19 + ) 20 + 21 + try: 22 + int(badge_number) 23 + except ValueError: 24 + raise forms.ValidationError( 25 + _("Badge number must be a number") 26 + ) 27 + 28 + if not dob: 29 + raise forms.ValidationError( 30 + _("Date of birth is required") 31 + ) 32 + try: 33 + dob = datetime.strptime(dob, "%d/%m/%Y").strftime("%Y-%m-%d") 34 + except ValueError: 35 + raise forms.ValidationError( 36 + _("Date of birth must be in the format DD/MM/YYYY") 37 + ) 38 + cleaned_data["dob"] = dob 39 + 40 + return cleaned_data
fbl_integration/migrations/__init__.py

This is a binary file and will not be displayed.

+3
fbl_integration/models.py
··· 1 + from django.db import models 2 + 3 + # Create your models here.
+31
fbl_integration/templates/fbl_auth_get_code.html
··· 1 + {% extends 'base.html' %} 2 + {% block content %} 3 + {% load i18n %} 4 + <div class="self-center w-full max-w-xl mx-auto"> 5 + <div class="bg-base-200 rounded p-8"> 6 + <p> 7 + {% trans 'We sent you an email that contains a code for your login. Please enter the code in the field below.' %} 8 + </p> 9 + <form method="post" action="/fbl/auth_get_code"> 10 + {% csrf_token %} 11 + 12 + {% if get_code_form.non_field_errors %} 13 + <div role="alert" class="alert alert-error mb-4"> 14 + <svg xmlns="http://www.w3.org/2000/svg" class="hidden sm:block stroke-current shrink-0 h-6 w-6" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M10 10l4 4m0 -4l-4 4" /><path d="M12 3c7.2 0 9 1.8 9 9s-1.8 9 -9 9s-9 -1.8 -9 -9s1.8 -9 9 -9z" /></svg> 15 + <span>{{ get_code_form.non_field_errors }}</span> 16 + </div> 17 + {% endif %} 18 + 19 + <div> 20 + <label class="label"> 21 + <span class="text-base label-text" for="{{ get_code_form.username.id_for_label }}">{% trans 'Verify Code' %}</span> 22 + </label> 23 + <input type="number" name="validation_code" placeholder="000000" class="w-full input input-bordered" /> 24 + </div> 25 + <div class="flex justify-end mt-6"> 26 + <button type="submit" class="btn btn-accent mb-4">{% trans 'Log In' %}</button> 27 + </div> 28 + </form> 29 + </div> 30 + </div> 31 + {% endblock %}
+10
fbl_integration/templates/fbl_auth_start.html
··· 1 + <!-- templates/core/login.html --> 2 + {% extends 'base.html' %} 3 + {% block content %} 4 + {% load i18n %} 5 + <div class="self-center w-full max-w-xl mx-auto"> 6 + <div class="bg-base-200 rounded p-8"> 7 + {% include 'partials/attendee_login.html' with fbl_auth_form=form %} 8 + </div> 9 + </div> 10 + {% endblock %}
+32
fbl_integration/templates/partials/attendee_login.html
··· 1 + {% block attendee_login %} 2 + {% load i18n %} 3 + <form method="post" action="/fbl/auth_start"> 4 + {% csrf_token %} 5 + 6 + {% if fbl_auth_form.non_field_errors %} 7 + <div role="alert" class="alert alert-error mb-4"> 8 + <svg xmlns="http://www.w3.org/2000/svg" class="hidden sm:block stroke-current shrink-0 h-6 w-6" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M10 10l4 4m0 -4l-4 4" /><path d="M12 3c7.2 0 9 1.8 9 9s-1.8 9 -9 9s-9 -1.8 -9 -9s1.8 -9 9 -9z" /></svg> 9 + <span>{{ fbl_auth_form.non_field_errors }}</span> 10 + </div> 11 + {% endif %} 12 + 13 + <div> 14 + <label class="label"> 15 + <span class="text-base label-text" for="{{ fbl_auth_form.username.id_for_label }}">{% trans 'Badge Number' %}</span> 16 + </label> 17 + <input type="number" name="badge_number" placeholder="420" class="w-full input input-bordered" /> 18 + </div> 19 + <script src="https://cdn.jsdelivr.net/npm/@alpinejs/mask@3.x.x/dist/cdn.min.js"></script> 20 + <script src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script> 21 + <label class="form-control w-full"> 22 + <div class="label"> 23 + <span class="text-base label-text" for="{{ fbl_auth_form.dob.id_for_label }}">{% trans 'Date of Birth' %}</span> 24 + </div> 25 + <input type="text" x-mask="99/99/9999" name="dob" placeholder="DD/MM/YYYY" class="w-full input input-bordered"> 26 + </label> 27 + <div class="flex justify-end mt-6"> 28 + <button type="submit" class="btn btn-accent mb-4">{% trans 'Log In with FBL' %}</button> 29 + </div> 30 + </form> 31 + {% if general_login %}<div class="divider">{% trans "I don\'t have a seat for this years FBL" %}</div>{% endif %} 32 + {% endblock %}
+3
fbl_integration/tests.py
··· 1 + from django.test import TestCase 2 + 3 + # Create your tests here.
+8
fbl_integration/urls.py
··· 1 + from django.urls import path 2 + 3 + from .views import fbl_authentication_start, fbl_authentication_get_code 4 + 5 + urlpatterns = [ 6 + path("auth_start", fbl_authentication_start, name="fbl-auth-start"), 7 + path("auth_get_code", fbl_authentication_get_code, name="fbl-auth-get-code") 8 + ]
+19
fbl_integration/views.py
··· 1 + from django.shortcuts import render 2 + from .forms import FblAuthForm 3 + 4 + def fbl_authentication_start(request): 5 + if request.method == "POST": 6 + form = FblAuthForm(request.POST) 7 + if form.is_valid(): 8 + 9 + # set hidden fields with dob and badge number 10 + return render(request, "fbl_auth_get_code.html") 11 + else: 12 + return render(request, "fbl_auth_start.html", {"form": form}) 13 + else: 14 + form = FblAuthForm() 15 + 16 + return render(request, "auth_start.html", {"form": form}) 17 + 18 + def fbl_authentication_get_code(request): 19 + return render(request, "fbl_auth_get_code.html")
+5 -1
paw/settings.py
··· 45 45 "django.contrib.messages", 46 46 "django.contrib.staticfiles", 47 47 "status", 48 + "fbl_integration", 48 49 ] 49 50 50 51 AUTH_USER_MODEL = "core.PawUser" ··· 65 66 TEMPLATES = [ 66 67 { 67 68 "BACKEND": "django.template.backends.django.DjangoTemplates", 68 - "DIRS": [BASE_DIR / 'paw' / 'templates'], 69 + "DIRS": [ 70 + BASE_DIR / 'paw' / 'templates', 71 + BASE_DIR / 'fbl_integration' / 'templates', 72 + ], 69 73 "APP_DIRS": True, 70 74 "OPTIONS": { 71 75 "context_processors": [
+3
paw/templates/core/login.html
··· 9 9 <a href="{% url 'register' %}" class="btn btn-sm btn-neutral">{% trans 'Register Account' %}</a> 10 10 </div> 11 11 <div class="bg-base-200 rounded p-8"> 12 + 13 + {% include 'partials/attendee_login.html' with general_login=True %} 14 + 12 15 <form method="post"> 13 16 {% csrf_token %} 14 17
+1
paw/urls.py
··· 26 26 path("", include("core.urls")), 27 27 path("", include("ticketing.urls")), 28 28 path("status", include("status.urls")), 29 + path("fbl/", include("fbl_integration.urls")), 29 30 ] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) 30 31 31 32 if settings.DEBUG: