Skip to content

Commit

Permalink
Merge branch 'fbl-integration'
Browse files Browse the repository at this point in the history
  • Loading branch information
aottr committed Apr 13, 2024
2 parents 528ec78 + 2f4f29d commit 8fa1ec3
Show file tree
Hide file tree
Showing 24 changed files with 484 additions and 6 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ name: Docker Image CI
on:
push:
branches:
- '**'
- "fbl-integration"
- "staging"
pull_request:
branches:
- '**'
branches: ["fbl-integration"]

env:
REGISTRY: ghcr.io
Expand Down
Empty file added fbl_integration/__init__.py
Empty file.
13 changes: 13 additions & 0 deletions fbl_integration/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from django.contrib import admin
from .models import FblAccount

@admin.register(FblAccount)
class FblAccountAdmin(admin.ModelAdmin):
list_display = ["system_username", "username", "badge_number", "status", "tags_secured", "created_at"]
search_fields = ["badge_number", "username"]
list_filter = ["status"]
readonly_fields = ["badge_number", "account_id", "username", "status", "tags_secured", "created_at"]

def system_username(self, x):
return x.user.username
system_username.short_description = 'System Username'
6 changes: 6 additions & 0 deletions fbl_integration/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class FblIntegrationConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "fbl_integration"
68 changes: 68 additions & 0 deletions fbl_integration/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
from typing import Any
from django import forms
from django.conf import settings
from django.utils.translation import gettext_lazy as _
from datetime import datetime

class FblAuthForm(forms.Form):
badge_number = forms.CharField(required=True)
dob = forms.CharField(required=True)

def clean(self) -> dict[str, Any]:
cleaned_data = super(FblAuthForm, self).clean()
badge_number = cleaned_data.get("badge_number")
dob = cleaned_data.get("dob")

if not badge_number:
raise forms.ValidationError(
_("Badge number is required")
)

try:
int(badge_number)
except ValueError:
raise forms.ValidationError(
_("Badge number must be a number")
)

if not dob:
raise forms.ValidationError(
_("Date of birth is required")
)
try:
dob = datetime.strptime(dob, "%d/%m/%Y").strftime("%Y-%m-%d")
except ValueError:
raise forms.ValidationError(
_("Date of birth must be in the format DD/MM/YYYY")
)
cleaned_data["dob"] = dob

return cleaned_data

class FblAuthCodeForm(FblAuthForm):
validation_code = forms.CharField(required=True)

def clean(self) -> dict[str, Any]:
cleaned_data = super(FblAuthCodeForm, self).clean()
validation_code = cleaned_data.get("validation_code")

if not validation_code:
raise forms.ValidationError(
_("The validation code is required. Please check your emails.")
)

return cleaned_data

class RegistrationCompletionForm(forms.Form):
email = forms.EmailField(required=True)

def clean(self) -> dict[str, Any]:
cleaned_data = super(RegistrationCompletionForm, self).clean()
email = cleaned_data.get("email")

if not email:
raise forms.ValidationError(
_("A Mail is required for notifications.")
)

return cleaned_data
44 changes: 44 additions & 0 deletions fbl_integration/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Generated by Django 5.0.3 on 2024-04-06 18:26

import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

initial = True

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.CreateModel(
name="FblAccount",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("badge_number", models.IntegerField()),
("account_id", models.CharField(max_length=255)),
("username", models.CharField(max_length=255)),
("tags_secured", models.CharField(max_length=255)),
("created_at", models.DateTimeField(auto_now_add=True)),
("status", models.CharField(max_length=64)),
(
"user",
models.OneToOneField(
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
),
],
),
]
Empty file.
35 changes: 35 additions & 0 deletions fbl_integration/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from django.db import models
from core.models import PawUser

class FblAccount(models.Model):
user = models.OneToOneField(PawUser, on_delete=models.CASCADE)
badge_number = models.IntegerField()
account_id = models.CharField(max_length=255)
username = models.CharField(max_length=255)
tags_secured = models.CharField(max_length=255)
created_at = models.DateTimeField(auto_now_add=True)
status = models.CharField(max_length=64)

def tags_list(self):
return self.tags_secured.split(',')

@classmethod
def create_user(cls, username) -> PawUser:
if not PawUser.objects.filter(username=username).exists():
user = PawUser.objects.create(username=username)
else:
counter = 1
while True:
new_username = f"{username}_{counter}"
if not PawUser.objects.filter(username=new_username).exists():
user = PawUser.objects.create(username=new_username)
break
counter += 1

user.set_unusable_password()
user.save()
return user


def __str__(self):
return self.user.username
43 changes: 43 additions & 0 deletions fbl_integration/templates/complete_registration.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{% extends 'base.html' %}
{% block content %}
{% load i18n %}
<div class="self-center w-full max-w-xl mx-auto">
<div class="flex items-center">
<h1 class="text-3xl font-bold p-2">{% trans 'FurryBlacklight Login' %}</h1>
</div>
<div class="bg-base-200 rounded p-8">
<ul class="steps w-full mb-6">
<li class="step step-accent">{% trans 'Authenticate' %}</li>
<li class="step step-accent">{% trans 'Confirm Code' %}</li>
<li class="step step-accent">{% trans 'Account Completion' %}</li>
<li class="step step-success">{% trans 'Done' %}</li>
</ul>

<div role="alert" class="alert alert-info mb-4">
{% trans 'Please set up a mail address. This will be used for notifications.' %}
</div>

<form method="post" action="">
{% csrf_token %}

{% if form.non_field_errors %}
<div role="alert" class="alert alert-error mb-4">
<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>
<span>{{ form.non_field_errors }}</span>
</div>
{% endif %}

<div class="form-control w-full">
<label class="label">
<span class="text-base label-text" for="{{ form.email.id_for_label }}">{% trans 'Mail Address' %}</span>
</label>
<input type="email" name="email" class="w-full input input-bordered" />
</div>

<div class="flex justify-end mt-6">
<button type="submit" class="btn btn-accent mb-4">{% trans 'Save Changes' %}</button>
</div>
</form>
</div>
</div>
{% endblock %}
58 changes: 58 additions & 0 deletions fbl_integration/templates/fbl_auth_get_code.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{% extends 'base.html' %}
{% block content %}
{% load i18n %}
<div class="self-center w-full max-w-xl mx-auto">
<div class="flex items-center">
<h1 class="text-3xl font-bold p-2">{% trans 'FurryBlacklight Login' %}</h1>
<div class="flex-grow"></div>
<a href="{% url 'login' %}" class="btn btn-sm btn-neutral">{% trans 'Go Back' %}</a>
</div>
<div class="bg-base-200 rounded p-8">
<ul class="steps w-full mb-6">
<li class="step step-accent">{% trans 'Authenticate' %}</li>
<li class="step step-accent">{% trans 'Confirm Code' %}</li>
<li class="step">{% trans 'Account Completion' %}</li>
<li class="step step-success">{% trans 'Done' %}</li>
</ul>

<div role="alert" class="alert alert-info mb-4">
{% trans 'We sent you an email that contains a code for your login. Please enter the code in the field below.' %}
</div>
<form method="post" action="/fbl/auth_get_code">
{% csrf_token %}

{% if get_code_form.non_field_errors %}
<div role="alert" class="alert alert-error mb-4">
<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>
<span>{{ get_code_form.non_field_errors }}</span>
</div>
{% endif %}

<div class="form-control w-full">
<label class="label">
<span class="text-base label-text" for="{{ get_code_form.username.id_for_label }}">{% trans 'Badge Number' %}</span>
</label>
<input type="number" name="badge_number" class="w-full input input-bordered" value="{{ get_code_form.badge_number.value }}" readonly />
</div>
<div class="form-control w-full">
<label class="label">
<span class="text-base label-text" for="{{ get_code_form.dob.id_for_label }}">{% trans 'Date of Birth' %}</span>
</label>
<input type="text" name="dob" class="w-full input input-bordered" value="{{ get_code_form.dob.value }}" readonly />
</div>

<script src="https://cdn.jsdelivr.net/npm/@alpinejs/[email protected]/dist/cdn.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/cdn.min.js"></script>
<div class="form-control w-full">
<label class="label">
<span class="text-base label-text" for="{{ get_code_form.username.id_for_label }}">{% trans 'Verify Code' %}</span>
</label>
<input type="text" name="validation_code" x-mask="999999" placeholder="000000" class="w-full input input-bordered text-2xl" />
</div>
<div class="flex justify-end mt-6">
<button type="submit" class="btn btn-accent mb-4">{% trans 'Confirm Code' %}</button>
</div>
</form>
</div>
</div>
{% endblock %}
10 changes: 10 additions & 0 deletions fbl_integration/templates/fbl_auth_start.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!-- templates/core/login.html -->
{% extends 'base.html' %}
{% block content %}
{% load i18n %}
<div class="self-center w-full max-w-xl mx-auto">
<div class="bg-base-200 rounded p-8">
{% include 'partials/attendee_login.html' with fbl_auth_form=form %}
</div>
</div>
{% endblock %}
21 changes: 21 additions & 0 deletions fbl_integration/templates/partials/attendee_info.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{% block attendee_info %}
{% load i18n %}
{% if fbl_account %}
<h2 class="font-semibold text-xs mt-4 mb-2">{% trans 'Rawrgister Info' %}</h2>

<div class="text-sm flex flex-col">
<div class="my-1 flex items-center">
{{ fbl_account.username }} <div class="ml-2 badge badge-accent">#{{ fbl_account.badge_number }}</div>
</div>
<div class="my-1 flex items-center">
<label class="font-semibold text-xs">{% trans 'Status' %}:</label> <div class="ml-2 badge badge-info">{{ fbl_account.status }}</div>
</div>
<div>
<h3 class="font-semibold text-xs my-1">{% trans 'Tags' %}</h3>
{% for tag in fbl_account.tags_list %}
<div class="badge badge-accent badge-outline mr-2">{{ tag }}</div>
{% endfor %}
</div>
</div>
{% endif %}
{% endblock %}
32 changes: 32 additions & 0 deletions fbl_integration/templates/partials/attendee_login.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{% block attendee_login %}
{% load i18n %}
<form method="post" action="/fbl/auth_start">
{% csrf_token %}

{% if fbl_auth_form.non_field_errors %}
<div role="alert" class="alert alert-error mb-4">
<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>
<span>{{ fbl_auth_form.non_field_errors }}</span>
</div>
{% endif %}

<div>
<label class="label">
<span class="text-base label-text" for="{{ fbl_auth_form.username.id_for_label }}">{% trans 'Badge Number' %}</span>
</label>
<input type="number" name="badge_number" placeholder="420" class="w-full input input-bordered" />
</div>
<script src="https://cdn.jsdelivr.net/npm/@alpinejs/[email protected]/dist/cdn.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/cdn.min.js"></script>
<label class="form-control w-full">
<div class="label">
<span class="text-base label-text" for="{{ fbl_auth_form.dob.id_for_label }}">{% trans 'Date of Birth' %}</span>
</div>
<input type="text" x-mask="99/99/9999" name="dob" placeholder="DD/MM/YYYY" class="w-full input input-bordered">
</label>
<div class="flex justify-end mt-6">
<button type="submit" class="btn btn-accent mb-4">{% trans 'Log In with FBL' %}</button>
</div>
</form>
{% if general_login %}<div class="divider">{% trans "I don\'t have a seat for this years FBL" %}</div>{% endif %}
{% endblock %}
Loading

0 comments on commit 8fa1ec3

Please sign in to comment.