mirror of
https://gitlab.com/animath/si/plateforme-corres2math.git
synced 2025-06-22 15:58:21 +02:00
Add a lot of comments
This commit is contained in:
@ -3,6 +3,9 @@ from django.db.models.signals import post_save, pre_save
|
||||
|
||||
|
||||
class RegistrationConfig(AppConfig):
|
||||
"""
|
||||
Registration app contains the detail about users only.
|
||||
"""
|
||||
name = 'registration'
|
||||
|
||||
def ready(self):
|
||||
|
@ -9,6 +9,11 @@ from .models import AdminRegistration, CoachRegistration, StudentRegistration
|
||||
|
||||
|
||||
class SignupForm(UserCreationForm):
|
||||
"""
|
||||
Signup form to registers participants and coaches
|
||||
They can choose the role at the registration.
|
||||
"""
|
||||
|
||||
role = forms.ChoiceField(
|
||||
label=lambda: _("role").capitalize(),
|
||||
choices=lambda: [
|
||||
@ -29,6 +34,10 @@ class SignupForm(UserCreationForm):
|
||||
|
||||
|
||||
class UserForm(forms.ModelForm):
|
||||
"""
|
||||
Replace the default user form to require the first name, last name and the email.
|
||||
The username is always equal to the email.
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields["first_name"].required = True
|
||||
@ -41,12 +50,18 @@ class UserForm(forms.ModelForm):
|
||||
|
||||
|
||||
class StudentRegistrationForm(forms.ModelForm):
|
||||
"""
|
||||
A student can update its class, its school and if it allows Animath to contact him/her later.
|
||||
"""
|
||||
class Meta:
|
||||
model = StudentRegistration
|
||||
fields = ('student_class', 'school', 'give_contact_to_animath',)
|
||||
|
||||
|
||||
class PhotoAuthorizationForm(forms.ModelForm):
|
||||
"""
|
||||
Form to send a photo authorization.
|
||||
"""
|
||||
def clean_photo_authorization(self):
|
||||
file = self.files["photo_authorization"]
|
||||
if file.content_type not in ["application/pdf", "image/png", "image/jpeg"]:
|
||||
@ -63,12 +78,18 @@ class PhotoAuthorizationForm(forms.ModelForm):
|
||||
|
||||
|
||||
class CoachRegistrationForm(forms.ModelForm):
|
||||
"""
|
||||
A coach can tell its professional activity.
|
||||
"""
|
||||
class Meta:
|
||||
model = CoachRegistration
|
||||
fields = ('professional_activity', 'give_contact_to_animath',)
|
||||
|
||||
|
||||
class AdminRegistrationForm(forms.ModelForm):
|
||||
"""
|
||||
Admins can tell everything they want.
|
||||
"""
|
||||
class Meta:
|
||||
model = AdminRegistration
|
||||
fields = ('role', 'give_contact_to_animath',)
|
||||
|
@ -11,6 +11,11 @@ from polymorphic.models import PolymorphicModel
|
||||
|
||||
|
||||
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,
|
||||
@ -28,6 +33,10 @@ class Registration(PolymorphicModel):
|
||||
)
|
||||
|
||||
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 = "[Corres2math] " + str(_("Activate your Correspondances account"))
|
||||
token = email_validation_token.make_token(self.user)
|
||||
uid = urlsafe_base64_encode(force_bytes(self.user.pk))
|
||||
@ -84,6 +93,10 @@ def get_random_filename(instance, filename):
|
||||
|
||||
|
||||
class StudentRegistration(Registration):
|
||||
"""
|
||||
Specific registration for students.
|
||||
They have a team, a student class and a school.
|
||||
"""
|
||||
team = models.ForeignKey(
|
||||
"participation.Team",
|
||||
related_name="students",
|
||||
@ -129,6 +142,10 @@ class StudentRegistration(Registration):
|
||||
|
||||
|
||||
class CoachRegistration(Registration):
|
||||
"""
|
||||
Specific registration for coaches.
|
||||
They have a team and a professional activity.
|
||||
"""
|
||||
team = models.ForeignKey(
|
||||
"participation.Team",
|
||||
related_name="coachs",
|
||||
@ -157,6 +174,10 @@ class CoachRegistration(Registration):
|
||||
|
||||
|
||||
class AdminRegistration(Registration):
|
||||
"""
|
||||
Specific registration for admins.
|
||||
They have a field to justify they status.
|
||||
"""
|
||||
role = models.TextField(
|
||||
verbose_name=_("role of the administrator"),
|
||||
)
|
||||
|
@ -4,6 +4,9 @@ from .models import Registration
|
||||
|
||||
|
||||
class RegistrationIndex(indexes.ModelSearchIndex, indexes.Indexable):
|
||||
"""
|
||||
Registrations are indexed by the user detail.
|
||||
"""
|
||||
text = indexes.NgramField(document=True, use_template=True)
|
||||
|
||||
class Meta:
|
||||
|
@ -5,10 +5,17 @@ from .models import AdminRegistration, Registration
|
||||
|
||||
|
||||
def set_username(instance, **_):
|
||||
"""
|
||||
Ensure that the user username is always equal to the user email address.
|
||||
"""
|
||||
instance.username = instance.email
|
||||
|
||||
|
||||
def send_email_link(instance, **_):
|
||||
"""
|
||||
If the email address got changed, send a new validation link
|
||||
and update the registration status in the team mailing list.
|
||||
"""
|
||||
if instance.pk:
|
||||
old_instance = User.objects.get(pk=instance.pk)
|
||||
if old_instance.email != instance.email:
|
||||
@ -25,5 +32,9 @@ def send_email_link(instance, **_):
|
||||
|
||||
|
||||
def create_admin_registration(instance, **_):
|
||||
"""
|
||||
When a super user got created through console,
|
||||
ensure that an admin registration is created.
|
||||
"""
|
||||
if instance.is_superuser:
|
||||
AdminRegistration.objects.get_or_create(user=instance)
|
||||
|
@ -5,6 +5,9 @@ from .models import Registration
|
||||
|
||||
|
||||
class RegistrationTable(tables.Table):
|
||||
"""
|
||||
Table of all registrations.
|
||||
"""
|
||||
last_name = tables.LinkColumn(
|
||||
'registration:user_detail',
|
||||
args=[tables.A("user_id")],
|
||||
|
@ -10,6 +10,9 @@ from .models import CoachRegistration, Registration, StudentRegistration
|
||||
|
||||
class TestIndexPage(TestCase):
|
||||
def test_index(self) -> None:
|
||||
"""
|
||||
Display the index page, without any right.
|
||||
"""
|
||||
response = self.client.get(reverse("index"))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
@ -29,6 +32,9 @@ class TestRegistration(TestCase):
|
||||
CoachRegistration.objects.create(user=self.coach, professional_activity="Teacher")
|
||||
|
||||
def test_admin_pages(self):
|
||||
"""
|
||||
Check that admin pages are rendering successfully.
|
||||
"""
|
||||
response = self.client.get(reverse("admin:index") + "registration/registration/")
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
@ -45,6 +51,9 @@ class TestRegistration(TestCase):
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_registration(self):
|
||||
"""
|
||||
Ensure that the signup form is working successfully.
|
||||
"""
|
||||
response = self.client.get(reverse("registration:signup"))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
@ -109,6 +118,9 @@ class TestRegistration(TestCase):
|
||||
self.assertRedirects(response, reverse("registration:email_validation_sent"), 302, 200)
|
||||
|
||||
def test_login(self):
|
||||
"""
|
||||
With a registered user, try to log in
|
||||
"""
|
||||
response = self.client.get(reverse("login"))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
@ -127,6 +139,9 @@ class TestRegistration(TestCase):
|
||||
self.assertRedirects(response, reverse("index"), 302, 200)
|
||||
|
||||
def test_user_detail(self):
|
||||
"""
|
||||
Load a user detail page.
|
||||
"""
|
||||
response = self.client.get(reverse("registration:my_account_detail"))
|
||||
self.assertRedirects(response, reverse("registration:user_detail", args=(self.user.pk,)))
|
||||
|
||||
@ -134,6 +149,9 @@ class TestRegistration(TestCase):
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_update_user(self):
|
||||
"""
|
||||
Update the user information, for each type of user.
|
||||
"""
|
||||
for user, data in [(self.user, dict(role="Bot")),
|
||||
(self.student, dict(student_class=11, school="Sky")),
|
||||
(self.coach, dict(professional_activity="God"))]:
|
||||
@ -162,6 +180,9 @@ class TestRegistration(TestCase):
|
||||
self.assertEqual(user.first_name, "Changed")
|
||||
|
||||
def test_upload_photo_authorization(self):
|
||||
"""
|
||||
Try to upload a photo authorization.
|
||||
"""
|
||||
response = self.client.get(reverse("registration:upload_user_photo_authorization",
|
||||
args=(self.student.registration.pk,)))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
@ -19,6 +19,9 @@ from .models import StudentRegistration
|
||||
|
||||
|
||||
class SignupView(CreateView):
|
||||
"""
|
||||
Signup, as a participant or a coach.
|
||||
"""
|
||||
model = User
|
||||
form_class = SignupForm
|
||||
template_name = "registration/signup.html"
|
||||
@ -126,23 +129,34 @@ class UserResendValidationEmailView(LoginRequiredMixin, DetailView):
|
||||
|
||||
|
||||
class MyAccountDetailView(LoginRequiredMixin, RedirectView):
|
||||
"""
|
||||
Redirect to our own profile detail page.
|
||||
"""
|
||||
def get_redirect_url(self, *args, **kwargs):
|
||||
return reverse_lazy("registration:user_detail", args=(self.request.user.pk,))
|
||||
|
||||
|
||||
class UserDetailView(LoginRequiredMixin, DetailView):
|
||||
"""
|
||||
Display the detail about a user.
|
||||
"""
|
||||
|
||||
model = User
|
||||
context_object_name = "user_object"
|
||||
template_name = "registration/user_detail.html"
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
user = request.user
|
||||
# Only an admin or the concerned user can see the information
|
||||
if not user.registration.is_admin and user.pk != kwargs["pk"]:
|
||||
raise PermissionDenied
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
|
||||
class UserUpdateView(LoginRequiredMixin, UpdateView):
|
||||
"""
|
||||
Update the detail about a user and its registration.
|
||||
"""
|
||||
model = User
|
||||
form_class = UserForm
|
||||
template_name = "registration/update_user.html"
|
||||
@ -176,6 +190,9 @@ class UserUpdateView(LoginRequiredMixin, UpdateView):
|
||||
|
||||
|
||||
class UserUploadPhotoAuthorizationView(LoginRequiredMixin, UpdateView):
|
||||
"""
|
||||
A participant can send its photo authorization.
|
||||
"""
|
||||
model = StudentRegistration
|
||||
form_class = PhotoAuthorizationForm
|
||||
template_name = "registration/upload_photo_authorization.html"
|
||||
@ -198,6 +215,9 @@ class UserUploadPhotoAuthorizationView(LoginRequiredMixin, UpdateView):
|
||||
|
||||
|
||||
class PhotoAuthorizationView(LoginRequiredMixin, View):
|
||||
"""
|
||||
Display the sent photo authorization.
|
||||
"""
|
||||
def get(self, request, *args, **kwargs):
|
||||
filename = kwargs["filename"]
|
||||
path = f"media/authorization/photo/{filename}"
|
||||
@ -207,18 +227,21 @@ class PhotoAuthorizationView(LoginRequiredMixin, View):
|
||||
user = request.user
|
||||
if not user.registration.is_admin and user.pk != student.user.pk:
|
||||
raise PermissionDenied
|
||||
# Guess mime type of the file
|
||||
mime = Magic(mime=True)
|
||||
mime_type = mime.from_file(path)
|
||||
ext = mime_type.split("/")[1].replace("jpeg", "jpg")
|
||||
# Replace file name
|
||||
true_file_name = _("Photo authorization of {student}.{ext}").format(student=str(student), ext=ext)
|
||||
return FileResponse(open(path, "rb"), content_type=mime_type, filename=true_file_name)
|
||||
|
||||
|
||||
class UserImpersonateView(LoginRequiredMixin, RedirectView):
|
||||
"""
|
||||
An administrator can log in through this page as someone else, and act as this other person.
|
||||
"""
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
"""
|
||||
An administrator can log in through this page as someone else, and act as this other person.
|
||||
"""
|
||||
if self.request.user.registration.is_admin:
|
||||
if not User.objects.filter(pk=kwargs["pk"]).exists():
|
||||
raise Http404
|
||||
|
Reference in New Issue
Block a user