349 lines
9.7 KiB
Python
349 lines
9.7 KiB
Python
# Copyright (C) 2020 by Animath
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
from datetime import date
|
|
|
|
from address.models import AddressField
|
|
from django.contrib.sites.models import Site
|
|
from django.db import models
|
|
from django.template import loader
|
|
from django.urls import reverse_lazy
|
|
from django.utils import timezone
|
|
from django.utils.crypto import get_random_string
|
|
from django.utils.encoding import force_bytes
|
|
from django.utils.http import urlsafe_base64_encode
|
|
from django.utils.translation import gettext_lazy as _
|
|
from phonenumber_field.modelfields import PhoneNumberField
|
|
from polymorphic.models import PolymorphicModel
|
|
from tfjm.tokens import email_validation_token
|
|
|
|
|
|
class Registration(PolymorphicModel):
|
|
"""
|
|
Registrations store extra content that are not asked in the User Model.
|
|
This is specific to the role of the user, see StudentRegistration,
|
|
ClassRegistration or AdminRegistration..
|
|
"""
|
|
user = models.OneToOneField(
|
|
"auth.User",
|
|
on_delete=models.CASCADE,
|
|
verbose_name=_("user"),
|
|
)
|
|
|
|
give_contact_to_animath = models.BooleanField(
|
|
default=False,
|
|
verbose_name=_("Grant Animath to contact me in the future about other actions"),
|
|
)
|
|
|
|
email_confirmed = models.BooleanField(
|
|
default=False,
|
|
verbose_name=_("email confirmed"),
|
|
)
|
|
|
|
def send_email_validation_link(self):
|
|
"""
|
|
The account got created or the email got changed.
|
|
Send an email that contains a link to validate the address.
|
|
"""
|
|
subject = "[TFJM²] " + str(_("Activate your TFJM² account"))
|
|
token = email_validation_token.make_token(self.user)
|
|
uid = urlsafe_base64_encode(force_bytes(self.user.pk))
|
|
site = Site.objects.first()
|
|
message = loader.render_to_string('registration/mails/email_validation_email.txt',
|
|
{
|
|
'user': self.user,
|
|
'domain': site.domain,
|
|
'token': token,
|
|
'uid': uid,
|
|
})
|
|
html = loader.render_to_string('registration/mails/email_validation_email.html',
|
|
{
|
|
'user': self.user,
|
|
'domain': site.domain,
|
|
'token': token,
|
|
'uid': uid,
|
|
})
|
|
self.user.email_user(subject, message, html_message=html)
|
|
|
|
@property
|
|
def type(self): # pragma: no cover
|
|
raise NotImplementedError
|
|
|
|
@property
|
|
def form_class(self): # pragma: no cover
|
|
raise NotImplementedError
|
|
|
|
@property
|
|
def participates(self):
|
|
return isinstance(self, ParticipantRegistration)
|
|
|
|
@property
|
|
def is_admin(self):
|
|
return isinstance(self, AdminRegistration) or self.user.is_superuser
|
|
|
|
@property
|
|
def is_volunteer(self):
|
|
return isinstance(self, VolunteerRegistration)
|
|
|
|
@property
|
|
def matrix_username(self):
|
|
return f"tfjm_{self.user.pk}"
|
|
|
|
def get_absolute_url(self):
|
|
return reverse_lazy("registration:user_detail", args=(self.user_id,))
|
|
|
|
def __str__(self):
|
|
return f"{self.user.first_name} {self.user.last_name}"
|
|
|
|
class Meta:
|
|
verbose_name = _("registration")
|
|
verbose_name_plural = _("registrations")
|
|
|
|
|
|
def get_random_photo_filename(instance, filename):
|
|
return "authorization/photo/" + get_random_string(64)
|
|
|
|
|
|
def get_random_health_filename(instance, filename):
|
|
return "authorization/health/" + get_random_string(64)
|
|
|
|
|
|
def get_random_parental_filename(instance, filename):
|
|
return "authorization/parental/" + get_random_string(64)
|
|
|
|
|
|
class ParticipantRegistration(Registration):
|
|
team = models.ForeignKey(
|
|
"participation.Team",
|
|
related_name="participants",
|
|
on_delete=models.PROTECT,
|
|
blank=True,
|
|
null=True,
|
|
default=None,
|
|
verbose_name=_("team"),
|
|
)
|
|
|
|
birth_date = models.DateField(
|
|
verbose_name=_("birth date"),
|
|
default=date.today,
|
|
)
|
|
|
|
address = AddressField(
|
|
verbose_name=_("address"),
|
|
null=True,
|
|
default=None,
|
|
)
|
|
|
|
phone_number = PhoneNumberField(
|
|
verbose_name=_("phone number"),
|
|
blank=True,
|
|
)
|
|
|
|
photo_authorization = models.FileField(
|
|
verbose_name=_("photo authorization"),
|
|
upload_to=get_random_photo_filename,
|
|
blank=True,
|
|
default="",
|
|
)
|
|
|
|
health_sheet = models.FileField(
|
|
verbose_name=_("health sheet"),
|
|
upload_to=get_random_health_filename,
|
|
blank=True,
|
|
default="",
|
|
)
|
|
|
|
@property
|
|
def under_18(self):
|
|
return (timezone.now().date() - self.birth_date).days < 18 * 365.24
|
|
|
|
@property
|
|
def type(self): # pragma: no cover
|
|
raise NotImplementedError
|
|
|
|
@property
|
|
def form_class(self): # pragma: no cover
|
|
raise NotImplementedError
|
|
|
|
|
|
class StudentRegistration(ParticipantRegistration):
|
|
"""
|
|
Specific registration for students.
|
|
They have a team, a student class and a school.
|
|
"""
|
|
student_class = models.IntegerField(
|
|
choices=[
|
|
(12, _("12th grade")),
|
|
(11, _("11th grade")),
|
|
(10, _("10th grade or lower")),
|
|
],
|
|
verbose_name=_("student class"),
|
|
)
|
|
|
|
school = models.CharField(
|
|
max_length=255,
|
|
verbose_name=_("school"),
|
|
)
|
|
|
|
responsible_name = models.CharField(
|
|
max_length=255,
|
|
verbose_name=_("responsible name"),
|
|
default="",
|
|
)
|
|
|
|
responsible_phone = PhoneNumberField(
|
|
verbose_name=_("responsible phone number"),
|
|
blank=True,
|
|
)
|
|
|
|
responsible_email = models.EmailField(
|
|
verbose_name=_("responsible email address"),
|
|
default="",
|
|
)
|
|
|
|
parental_authorization = models.FileField(
|
|
verbose_name=_("parental authorization"),
|
|
upload_to=get_random_parental_filename,
|
|
blank=True,
|
|
default="",
|
|
)
|
|
|
|
@property
|
|
def type(self):
|
|
return _("student")
|
|
|
|
@property
|
|
def form_class(self):
|
|
from registration.forms import StudentRegistrationForm
|
|
return StudentRegistrationForm
|
|
|
|
class Meta:
|
|
verbose_name = _("student registration")
|
|
verbose_name_plural = _("student registrations")
|
|
|
|
|
|
class CoachRegistration(ParticipantRegistration):
|
|
"""
|
|
Specific registration for coaches.
|
|
They have a team and a professional activity.
|
|
"""
|
|
professional_activity = models.TextField(
|
|
verbose_name=_("professional activity"),
|
|
)
|
|
|
|
@property
|
|
def type(self):
|
|
return _("coach")
|
|
|
|
@property
|
|
def form_class(self):
|
|
from registration.forms import CoachRegistrationForm
|
|
return CoachRegistrationForm
|
|
|
|
class Meta:
|
|
verbose_name = _("coach registration")
|
|
verbose_name_plural = _("coach registrations")
|
|
|
|
|
|
class VolunteerRegistration(Registration):
|
|
"""
|
|
Specific registration for organizers and juries.
|
|
"""
|
|
professional_activity = models.TextField(
|
|
verbose_name=_("professional activity"),
|
|
)
|
|
|
|
@property
|
|
def interesting_tournaments(self) -> set:
|
|
return set(self.organized_tournaments.all()).union(map(lambda pool: pool.tournament, self.jury_in.all()))
|
|
|
|
@property
|
|
def type(self):
|
|
return _('volunteer')
|
|
|
|
@property
|
|
def form_class(self):
|
|
from registration.forms import VolunteerRegistrationForm
|
|
return VolunteerRegistrationForm
|
|
|
|
|
|
class AdminRegistration(VolunteerRegistration):
|
|
"""
|
|
Specific registration for admins.
|
|
They have a field to justify they status.
|
|
"""
|
|
role = models.TextField(
|
|
verbose_name=_("role of the administrator"),
|
|
)
|
|
|
|
@property
|
|
def type(self):
|
|
return _("admin")
|
|
|
|
@property
|
|
def form_class(self):
|
|
from registration.forms import AdminRegistrationForm
|
|
return AdminRegistrationForm
|
|
|
|
class Meta:
|
|
verbose_name = _("admin registration")
|
|
verbose_name_plural = _("admin registrations")
|
|
|
|
|
|
def get_scholarship_filename(instance, filename):
|
|
return f"authorization/scholarship/scholarship_{instance.registration.pk}"
|
|
|
|
|
|
class Payment(models.Model):
|
|
registration = models.OneToOneField(
|
|
ParticipantRegistration,
|
|
on_delete=models.CASCADE,
|
|
related_name="payment",
|
|
verbose_name=_("registration"),
|
|
)
|
|
|
|
type = models.CharField(
|
|
verbose_name=_("type"),
|
|
max_length=16,
|
|
choices=[
|
|
('', _("No payment")),
|
|
('helloasso', "Hello Asso"),
|
|
('scholarship', _("Scholarship")),
|
|
('bank_transfer', _("Bank transfer")),
|
|
('free', _("The tournament is free")),
|
|
],
|
|
blank=True,
|
|
default="",
|
|
)
|
|
|
|
scholarship_file = models.FileField(
|
|
verbose_name=_("scholarship file"),
|
|
help_text=_("only if you have a scholarship."),
|
|
upload_to=get_scholarship_filename,
|
|
blank=True,
|
|
default="",
|
|
)
|
|
|
|
additional_information = models.TextField(
|
|
verbose_name=_("additional information"),
|
|
help_text=_("To help us to find your payment."),
|
|
blank=True,
|
|
default="",
|
|
)
|
|
|
|
valid = models.BooleanField(
|
|
verbose_name=_("valid"),
|
|
null=True,
|
|
default=False,
|
|
)
|
|
|
|
def get_absolute_url(self):
|
|
return reverse_lazy("registration:user_detail", args=(self.registration.user.id,))
|
|
|
|
def __str__(self):
|
|
return _("Payment of {registration}").format(registration=self.registration)
|
|
|
|
class Meta:
|
|
verbose_name = _("payment")
|
|
verbose_name_plural = _("payments")
|