diff --git a/accounts/__pycache__/forms.cpython-313.pyc b/accounts/__pycache__/forms.cpython-313.pyc new file mode 100644 index 0000000..29c917a Binary files /dev/null and b/accounts/__pycache__/forms.cpython-313.pyc differ diff --git a/accounts/__pycache__/models.cpython-313.pyc b/accounts/__pycache__/models.cpython-313.pyc index 01b7431..90cbcdd 100644 Binary files a/accounts/__pycache__/models.cpython-313.pyc and b/accounts/__pycache__/models.cpython-313.pyc differ diff --git a/accounts/__pycache__/urls.cpython-313.pyc b/accounts/__pycache__/urls.cpython-313.pyc index 32d90d7..a3046a6 100644 Binary files a/accounts/__pycache__/urls.cpython-313.pyc and b/accounts/__pycache__/urls.cpython-313.pyc differ diff --git a/accounts/__pycache__/views.cpython-313.pyc b/accounts/__pycache__/views.cpython-313.pyc index 62a796b..15cb9fc 100644 Binary files a/accounts/__pycache__/views.cpython-313.pyc and b/accounts/__pycache__/views.cpython-313.pyc differ diff --git a/accounts/forms.py b/accounts/forms.py new file mode 100644 index 0000000..d67316f --- /dev/null +++ b/accounts/forms.py @@ -0,0 +1,22 @@ +from django import forms +from .models import InvitationCode, CustomUser + +class InvitationCodeForm(forms.Form): + code = forms.CharField(max_length=255, label="Einladungscode") + + def clean_code(self): + code = self.cleaned_data.get('code') + try: + invitation_code = InvitationCode.objects.get(code=code) + if not invitation_code.is_valid(): + raise forms.ValidationError("Dieser Einladungscode ist nicht mehr gültig.") + except InvitationCode.DoesNotExist: + raise forms.ValidationError("Ungültiger Einladungscode.") + return code + +class CustomUserCreationForm(forms.ModelForm): + password = forms.CharField(widget=forms.PasswordInput) + birth_date = forms.DateField(input_formats=['%d.%m.%Y'], widget=forms.DateInput(format='%d.%m.%Y')) + class Meta: + model = CustomUser + fields = ('username', 'first_name', 'last_name', 'email', 'birth_date', 'player_number', 'password') diff --git a/accounts/migrations/0001_initial.py b/accounts/migrations/0001_initial.py new file mode 100644 index 0000000..502164f --- /dev/null +++ b/accounts/migrations/0001_initial.py @@ -0,0 +1,58 @@ +# Generated by Django 5.2.6 on 2025-09-30 17:59 + +import django.contrib.auth.models +import django.contrib.auth.validators +import django.db.models.deletion +import django.utils.timezone +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('auth', '0012_alter_user_first_name_max_length'), + ] + + operations = [ + migrations.CreateModel( + name='CustomUser', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('password', models.CharField(max_length=128, verbose_name='password')), + ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), + ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), + ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')), + ('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')), + ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), + ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')), + ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), + ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), + ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), + ('birth_date', models.DateField(blank=True, null=True)), + ('player_number', models.IntegerField(default=999)), + ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')), + ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')), + ], + options={ + 'verbose_name': 'user', + 'verbose_name_plural': 'users', + 'abstract': False, + }, + managers=[ + ('objects', django.contrib.auth.models.UserManager()), + ], + ), + migrations.CreateModel( + name='InvitationCode', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('code', models.CharField(max_length=255, unique=True)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('is_active', models.BooleanField(default=True)), + ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/accounts/migrations/__pycache__/0001_initial.cpython-313.pyc b/accounts/migrations/__pycache__/0001_initial.cpython-313.pyc new file mode 100644 index 0000000..930b79c Binary files /dev/null and b/accounts/migrations/__pycache__/0001_initial.cpython-313.pyc differ diff --git a/accounts/models.py b/accounts/models.py index 71a8362..b4ff1bc 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -1,3 +1,32 @@ +from django.contrib.auth.models import AbstractUser from django.db import models +from django.utils import timezone +import datetime -# Create your models here. +class CustomUser(AbstractUser): + birth_date = models.DateField(null=True, blank=True) + player_number = models.IntegerField(default=999) + + @property + def age(self): + if not self.birth_date: + return None + today = datetime.date.today() + return today.year - self.birth_date.year - ((today.month, today.day) < (self.birth_date.month, self.birth_date.day)) + +class InvitationCode(models.Model): + code = models.CharField(max_length=255, unique=True) + user = models.ForeignKey(CustomUser, on_delete=models.CASCADE, null=True, blank=True) + created_at = models.DateTimeField(auto_now_add=True) + is_active = models.BooleanField(default=True) + + def is_valid(self): + if not self.is_active: + return False + two_weeks_ago = timezone.now() - datetime.timedelta(weeks=2) + if self.created_at < two_weeks_ago: + return False + return True + + def __str__(self): + return self.code \ No newline at end of file diff --git a/accounts/templates/accounts/invitation_code.html b/accounts/templates/accounts/invitation_code.html new file mode 100644 index 0000000..4a4a4bb --- /dev/null +++ b/accounts/templates/accounts/invitation_code.html @@ -0,0 +1,10 @@ +{% extends "base.html" %} + +{% block content %} +