From 02ca1d1efea87eb9ff78897219c31474841320a3 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sat, 14 Nov 2020 21:28:01 +0100 Subject: [PATCH 01/10] Fix matrix bot avatar --- .../management/commands/fix_matrix_channels.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/participation/management/commands/fix_matrix_channels.py b/apps/participation/management/commands/fix_matrix_channels.py index 764b41e..ec7802b 100644 --- a/apps/participation/management/commands/fix_matrix_channels.py +++ b/apps/participation/management/commands/fix_matrix_channels.py @@ -16,10 +16,8 @@ class Command(BaseCommand): if not os.path.isfile(".matrix_avatar"): stat_file = os.stat("corres2math/static/logo.png") with open("corres2math/static/logo.png", "rb") as f: - resp, _ = Matrix.upload(f, filename="logo.png", content_type="image/png", - filesize=stat_file.st_size) - if not hasattr(resp, "content_uri"): - raise Exception(resp) + resp = Matrix.upload(f, filename="logo.png", content_type="image/png", + filesize=stat_file.st_size)[0][0] avatar_uri = resp.content_uri with open(".matrix_avatar", "w") as f: f.write(avatar_uri) From 10932d1cc50809c4646498b378401267c40cf4dd Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sat, 14 Nov 2020 22:18:35 +0100 Subject: [PATCH 02/10] Create more mailing lists --- .../management/commands/fix_sympa_lists.py | 39 +++++++++++++++++++ apps/participation/models.py | 11 ++++++ apps/participation/views.py | 5 +++ 3 files changed, 55 insertions(+) create mode 100644 apps/participation/management/commands/fix_sympa_lists.py diff --git a/apps/participation/management/commands/fix_sympa_lists.py b/apps/participation/management/commands/fix_sympa_lists.py new file mode 100644 index 0000000..f558a8a --- /dev/null +++ b/apps/participation/management/commands/fix_sympa_lists.py @@ -0,0 +1,39 @@ +from django.db.models import Q + +from corres2math.lists import get_sympa_client +from django.core.management import BaseCommand +from participation.models import Team +from registration.models import CoachRegistration, StudentRegistration + + +class Command(BaseCommand): + def handle(self, *args, **options): + """ + Create Sympa mailing lists and register teams. + """ + sympa = get_sympa_client() + + sympa.create_list("equipes", "Équipes des Correspondances", "hotline", + "Liste de diffusion pour contacter toutes les équipes validées des Correspondances.", + "education", raise_error=False) + sympa.create_list("equipes-non-valides", "Équipes des Correspondances", "hotline", + "Liste de diffusion pour contacter toutes les équipes non-validées des Correspondances.", + "education", raise_error=False) + + for problem in range(1, 4): + sympa.create_list(f"probleme-{problem}", + f"Équipes des Correspondances participant au problème {problem}", "hotline", + f"Liste de diffusion pour contacter les équipes participant au problème {problem}" + f" des Correspondances.", "education", raise_error=False) + + for team in Team.objects.filter(participation__valid=True).all(): + sympa.subscribe(team.email, "equipes", f"Equipe {team.name}", True, True) + sympa.subscribe(team.email, f"probleme-{team.participation.problem}", f"Equipe {team.name}", True) + + for team in Team.objects.filter(Q(participation__valid=False) | Q(participation__valid__isnull=True)).all(): + sympa.subscribe(team.email, "equipes-non-valides", f"Equipe {team.name}", True) + + for student in StudentRegistration.objects.filter(team__isnull=False).all(): + sympa.subscribe(student.user.email, f"equipe-{student.team.trigram.lower}", True, f"{student}") + for coach in CoachRegistration.objects.filter(team__isnull=False).all(): + sympa.subscribe(coach.user.email, f"equipe-{coach.team.trigram.lower}", True, f"{coach}") diff --git a/apps/participation/models.py b/apps/participation/models.py index 8b6af3e..3c64a7e 100644 --- a/apps/participation/models.py +++ b/apps/participation/models.py @@ -65,11 +65,22 @@ class Team(models.Model): "education", raise_error=False, ) + if self.participation.valid: + get_sympa_client().subscribe(self.email, "equipes", False, f"Equipe {self.name}") + get_sympa_client().subscribe(self.email, f"probleme-{self.participation.problem}", False, + f"Equipe {self.name}") + else: + get_sympa_client().subscribe(self.email, "equipes-non-valides", False) def delete_mailing_list(self): """ Drop the Sympa mailing list, if the team is empty or if the trigram changed. """ + if self.participation.valid: + get_sympa_client().unsubscribe(self.email, "equipes", False) + get_sympa_client().unsubscribe(self.email, f"probleme-{self.participation.problem}", False) + else: + get_sympa_client().unsubscribe(self.email, "equipes-non-valides", False) get_sympa_client().delete_list(f"equipe-{self.trigram}") def save(self, *args, **kwargs): diff --git a/apps/participation/views.py b/apps/participation/views.py index de74762..f83a37b 100644 --- a/apps/participation/views.py +++ b/apps/participation/views.py @@ -223,6 +223,11 @@ class TeamDetailView(LoginRequiredMixin, FormMixin, ProcessFormView, DetailView) mail_plain = render_to_string("participation/mails/team_validated.txt", mail_context) mail_html = render_to_string("participation/mails/team_validated.html", mail_context) send_mail("[Corres2math] Équipe validée", mail_plain, None, [self.object.email], html_message=mail_html) + + get_sympa_client().subscribe(self.object.email, "equipes", False, f"Equipe {self.object.name}") + get_sympa_client().unsubscribe(self.object.email, "equipes-non-valides", False) + get_sympa_client().subscribe(self.object.email, f"probleme-{self.object.participation.problem}", False, + f"Equipe {self.object.name}") elif "invalidate" in self.request.POST: self.object.participation.valid = None self.object.participation.save() From 48b34e4362bb70548ea0ce01a687619db5d0c71d Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sat, 14 Nov 2020 23:43:42 +0100 Subject: [PATCH 03/10] Ensure that teams have a participation --- apps/participation/models.py | 2 +- apps/participation/signals.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/participation/models.py b/apps/participation/models.py index 3c64a7e..c19f9f8 100644 --- a/apps/participation/models.py +++ b/apps/participation/models.py @@ -65,7 +65,7 @@ class Team(models.Model): "education", raise_error=False, ) - if self.participation.valid: + if self.pk and self.participation.valid: get_sympa_client().subscribe(self.email, "equipes", False, f"Equipe {self.name}") get_sympa_client().subscribe(self.email, f"probleme-{self.participation.problem}", False, f"Equipe {self.name}") diff --git a/apps/participation/signals.py b/apps/participation/signals.py index a7ee7d4..67998d9 100644 --- a/apps/participation/signals.py +++ b/apps/participation/signals.py @@ -2,7 +2,7 @@ from corres2math.lists import get_sympa_client from participation.models import Participation, Team, Video -def create_team_participation(instance, **_): +def create_team_participation(instance, created, **_): """ When a team got created, create an associated team and create Video objects. """ @@ -12,6 +12,8 @@ def create_team_participation(instance, **_): if not participation.synthesis: participation.synthesis = Video.objects.create() participation.save() + if not created: + participation.team.create_mailing_list() def update_mailing_list(instance: Team, **_): From 9867e5e2a828a19f6fae7820651aa81c59b1a0fd Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sat, 14 Nov 2020 23:44:53 +0100 Subject: [PATCH 04/10] Linting --- apps/participation/management/commands/fix_matrix_channels.py | 2 +- apps/participation/management/commands/fix_sympa_lists.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/participation/management/commands/fix_matrix_channels.py b/apps/participation/management/commands/fix_matrix_channels.py index ec7802b..d9459d0 100644 --- a/apps/participation/management/commands/fix_matrix_channels.py +++ b/apps/participation/management/commands/fix_matrix_channels.py @@ -17,7 +17,7 @@ class Command(BaseCommand): stat_file = os.stat("corres2math/static/logo.png") with open("corres2math/static/logo.png", "rb") as f: resp = Matrix.upload(f, filename="logo.png", content_type="image/png", - filesize=stat_file.st_size)[0][0] + filesize=stat_file.st_size)[0][0] avatar_uri = resp.content_uri with open(".matrix_avatar", "w") as f: f.write(avatar_uri) diff --git a/apps/participation/management/commands/fix_sympa_lists.py b/apps/participation/management/commands/fix_sympa_lists.py index f558a8a..63152b5 100644 --- a/apps/participation/management/commands/fix_sympa_lists.py +++ b/apps/participation/management/commands/fix_sympa_lists.py @@ -1,7 +1,6 @@ -from django.db.models import Q - from corres2math.lists import get_sympa_client from django.core.management import BaseCommand +from django.db.models import Q from participation.models import Team from registration.models import CoachRegistration, StudentRegistration From 0fe1f9c34857f909b88194493dffbf3af67b14f5 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sat, 14 Nov 2020 23:50:02 +0100 Subject: [PATCH 05/10] Don't migrate in Dockerfile --- Dockerfile | 4 +--- entrypoint.sh | 5 ++++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index cce2279..ef04fb3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,9 +16,7 @@ RUN pip install -r requirements.txt --no-cache-dir COPY . /code/ RUN python manage.py collectstatic --noinput && \ - python manage.py compilemessages && \ - python manage.py migrate && \ - python manage.py loaddata initial + python manage.py compilemessages # Configure nginx RUN mkdir /run/nginx diff --git a/entrypoint.sh b/entrypoint.sh index 044f92e..0b67ca4 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -2,10 +2,13 @@ crond -l 0 +python manage.py migrate +python manage.py loaddata initial + nginx if [ "$CORRES2MATH_STAGE" = "prod" ]; then gunicorn -b 0.0.0.0:8000 --workers=2 --threads=4 --worker-class=gthread corres2math.wsgi --access-logfile '-' --error-logfile '-'; else - ./manage.py runserver 0.0.0.0:8000; + python manage.py runserver 0.0.0.0:8000; fi From d304c3565c112c9c79130aa7b35fc6002c82a335 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sun, 15 Nov 2020 00:55:25 +0100 Subject: [PATCH 06/10] resolve_room_alias was broken --- corres2math/matrix.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/corres2math/matrix.py b/corres2math/matrix.py index d01e44f..a6265a9 100644 --- a/corres2math/matrix.py +++ b/corres2math/matrix.py @@ -216,7 +216,7 @@ class Matrix: """ client = await cls._get_client() resp = await client.room_resolve_alias(room_alias) - return resp.room_id if resp else None + return resp.room_id if resp and hasattr(resp, "room_id") else None @classmethod @async_to_sync From 2e0028c0638a3a4027ead2eb0dd8ec8ff252f5a2 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sun, 15 Nov 2020 01:14:31 +0100 Subject: [PATCH 07/10] Send display name to Matrix --- apps/registration/fixtures/initial.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/apps/registration/fixtures/initial.json b/apps/registration/fixtures/initial.json index 40afb61..209fc21 100644 --- a/apps/registration/fixtures/initial.json +++ b/apps/registration/fixtures/initial.json @@ -13,5 +13,14 @@ "single_log_out": true, "single_log_out_callback": "" } + }, + { + "model": "cas_server.replaceattributname", + "pk": 1, + "fields": { + "name": "display_name", + "replace": "", + "service_pattern": 1 + } } ] From ece1e800abe27aac70b667e0c0259710f6f4765f Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sun, 15 Nov 2020 01:29:53 +0100 Subject: [PATCH 08/10] Add #flood --- .../management/commands/fix_matrix_channels.py | 14 ++++++++++++++ apps/registration/signals.py | 1 + 2 files changed, 15 insertions(+) diff --git a/apps/participation/management/commands/fix_matrix_channels.py b/apps/participation/management/commands/fix_matrix_channels.py index d9459d0..7ce878c 100644 --- a/apps/participation/management/commands/fix_matrix_channels.py +++ b/apps/participation/management/commands/fix_matrix_channels.py @@ -56,9 +56,20 @@ class Command(BaseCommand): preset=RoomPreset.public_chat, ) + if not async_to_sync(Matrix.resolve_room_alias)("#flood:correspondances-maths.fr"): + Matrix.create_room( + visibility=RoomVisibility.public, + alias="flood", + name="Flood", + topic="Discutez de tout et de rien !", + federate=False, + preset=RoomPreset.public_chat, + ) + Matrix.set_room_avatar("#annonces:correspondances-maths.fr", avatar_uri) Matrix.set_room_avatar("#faq:correspondances-maths.fr", avatar_uri) Matrix.set_room_avatar("#je-cherche-une-equipe:correspondances-maths.fr", avatar_uri) + Matrix.set_room_avatar("#flood:correspondances-maths.fr", avatar_uri) Matrix.set_room_power_level_event("#annonces:correspondances-maths.fr", "events_default", 50) @@ -67,9 +78,12 @@ class Command(BaseCommand): Matrix.invite("#faq:correspondances-maths.fr", f"@{r.matrix_username}:correspondances-maths.fr") Matrix.invite("#je-cherche-une-equipe:correspondances-maths.fr", f"@{r.matrix_username}:correspondances-maths.fr") + Matrix.invite("#flood:correspondances-maths.fr", f"@{r.matrix_username}:correspondances-maths.fr") for admin in AdminRegistration.objects.all(): Matrix.set_room_power_level("#annonces:correspondances-maths.fr", f"@{admin.matrix_username}:correspondances-maths.fr", 95) Matrix.set_room_power_level("#faq:correspondances-maths.fr", f"@{admin.matrix_username}:correspondances-maths.fr", 95) + Matrix.set_room_power_level("#flood:correspondances-maths.fr", + f"@{admin.matrix_username}:correspondances-maths.fr", 95) diff --git a/apps/registration/signals.py b/apps/registration/signals.py index 71b761e..0a6edec 100644 --- a/apps/registration/signals.py +++ b/apps/registration/signals.py @@ -50,3 +50,4 @@ def invite_to_public_rooms(instance: Registration, created: bool, **_): Matrix.invite("#faq:correspondances-maths.fr", f"@{instance.matrix_username}:correspondances-maths.fr") Matrix.invite("#je-cherche-une-equip:correspondances-maths.fr", f"@{instance.matrix_username}:correspondances-maths.fr") + Matrix.invite("#flood:correspondances-maths.fr", f"@{instance.matrix_username}:correspondances-maths.fr") From d3e18a8fbb897033e04133d296ea512b819ec67b Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sun, 15 Nov 2020 01:40:20 +0100 Subject: [PATCH 09/10] We can only register during the first phase --- apps/participation/models.py | 10 ++++------ apps/participation/tests.py | 2 +- apps/registration/forms.py | 6 ++++++ apps/registration/tests.py | 20 ++++++++++++++++++++ 4 files changed, 31 insertions(+), 7 deletions(-) diff --git a/apps/participation/models.py b/apps/participation/models.py index c19f9f8..55e808c 100644 --- a/apps/participation/models.py +++ b/apps/participation/models.py @@ -65,7 +65,7 @@ class Team(models.Model): "education", raise_error=False, ) - if self.pk and self.participation.valid: + if self.pk and self.participation.valid: # pragma: no cover get_sympa_client().subscribe(self.email, "equipes", False, f"Equipe {self.name}") get_sympa_client().subscribe(self.email, f"probleme-{self.participation.problem}", False, f"Equipe {self.name}") @@ -76,7 +76,7 @@ class Team(models.Model): """ Drop the Sympa mailing list, if the team is empty or if the trigram changed. """ - if self.participation.valid: + if self.participation.valid: # pragma: no cover get_sympa_client().unsubscribe(self.email, "equipes", False) get_sympa_client().unsubscribe(self.email, f"probleme-{self.participation.problem}", False) else: @@ -292,10 +292,8 @@ class Phase(models.Model): qs = Phase.objects.filter(start__lte=timezone.now(), end__gte=timezone.now()) if qs.exists(): return qs.get() - qs = Phase.objects.order_by("phase_number").all() - if timezone.now() < qs.first().start: - return qs.first() - return qs.last() + qs = Phase.objects.filter(start__lte=timezone.now()).order_by("phase_number").all() + return qs.last() if qs.exists() else None def __str__(self): return _("Phase {phase_number:d} starts on {start:%Y-%m-%d %H:%M} and ends on {end:%Y-%m-%d %H:%M}")\ diff --git a/apps/participation/tests.py b/apps/participation/tests.py index 4a6d119..ee4fd75 100644 --- a/apps/participation/tests.py +++ b/apps/participation/tests.py @@ -575,7 +575,7 @@ class TestStudentParticipation(TestCase): for i in range(1, 5): Phase.objects.filter(phase_number=i).update(start=timezone.now() + timedelta(days=2 * i), end=timezone.now() + timedelta(days=2 * i + 1)) - self.assertEqual(Phase.current_phase().phase_number, 1) + self.assertEqual(Phase.current_phase(), None) # We are after the end for i in range(1, 5): diff --git a/apps/registration/forms.py b/apps/registration/forms.py index 18d76eb..140002f 100644 --- a/apps/registration/forms.py +++ b/apps/registration/forms.py @@ -4,6 +4,7 @@ from django.contrib.auth.models import User from django.core.exceptions import ValidationError from django.forms import FileInput from django.utils.translation import gettext_lazy as _ +from participation.models import Phase from .models import AdminRegistration, CoachRegistration, StudentRegistration @@ -28,6 +29,11 @@ class SignupForm(UserCreationForm): self.fields["last_name"].required = True self.fields["email"].required = True + def clean(self): + if Phase.current_phase() is None or Phase.current_phase().phase_number >= 2: + self.add_error(None, _("You can't register now.")) + return super().clean() + class Meta: model = User fields = ('first_name', 'last_name', 'email', 'password1', 'password2', 'role',) diff --git a/apps/registration/tests.py b/apps/registration/tests.py index 4c464c9..bc65bb7 100644 --- a/apps/registration/tests.py +++ b/apps/registration/tests.py @@ -1,3 +1,4 @@ +from datetime import timedelta import os from corres2math.tokens import email_validation_token @@ -7,8 +8,10 @@ from django.contrib.sites.models import Site from django.core.management import call_command from django.test import TestCase from django.urls import reverse +from django.utils import timezone from django.utils.encoding import force_bytes from django.utils.http import urlsafe_base64_encode +from participation.models import Phase from .models import AdminRegistration, CoachRegistration, StudentRegistration @@ -84,6 +87,23 @@ class TestRegistration(TestCase): response = self.client.get(reverse("registration:signup")) self.assertEqual(response.status_code, 200) + # After first phase + response = self.client.post(reverse("registration:signup"), data=dict( + last_name="Toto", + first_name="Toto", + email="toto@example.com", + password1="azertyuiopazertyuiop", + password2="azertyuiopazertyuiop", + role="participant", + student_class=12, + school="God", + give_contact_to_animath=False, + )) + self.assertEqual(response.status_code, 200) + + Phase.objects.filter(phase_number__gte=2).update(start=timezone.now() + timedelta(days=1), + end=timezone.now() + timedelta(days=2)) + # Incomplete form response = self.client.post(reverse("registration:signup"), data=dict( last_name="Toto", From 731f8711ff9f3b0fd1a856c4a9cdf772210279bb Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sun, 15 Nov 2020 01:50:12 +0100 Subject: [PATCH 10/10] We can only register during the first phase --- apps/participation/templatetags/__init__.py | 0 apps/participation/templatetags/calendar.py | 12 ++ apps/registration/forms.py | 6 - apps/registration/tests.py | 20 +-- apps/registration/views.py | 10 ++ corres2math/templates/base.html | 10 +- locale/fr/LC_MESSAGES/django.po | 154 ++++++++++---------- 7 files changed, 112 insertions(+), 100 deletions(-) create mode 100644 apps/participation/templatetags/__init__.py create mode 100644 apps/participation/templatetags/calendar.py diff --git a/apps/participation/templatetags/__init__.py b/apps/participation/templatetags/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/apps/participation/templatetags/calendar.py b/apps/participation/templatetags/calendar.py new file mode 100644 index 0000000..62cc0aa --- /dev/null +++ b/apps/participation/templatetags/calendar.py @@ -0,0 +1,12 @@ +from django import template + +from ..models import Phase + + +def current_phase(nb): + phase = Phase.current_phase() + return phase is not None and phase.phase_number == nb + + +register = template.Library() +register.filter("current_phase", current_phase) diff --git a/apps/registration/forms.py b/apps/registration/forms.py index 140002f..18d76eb 100644 --- a/apps/registration/forms.py +++ b/apps/registration/forms.py @@ -4,7 +4,6 @@ from django.contrib.auth.models import User from django.core.exceptions import ValidationError from django.forms import FileInput from django.utils.translation import gettext_lazy as _ -from participation.models import Phase from .models import AdminRegistration, CoachRegistration, StudentRegistration @@ -29,11 +28,6 @@ class SignupForm(UserCreationForm): self.fields["last_name"].required = True self.fields["email"].required = True - def clean(self): - if Phase.current_phase() is None or Phase.current_phase().phase_number >= 2: - self.add_error(None, _("You can't register now.")) - return super().clean() - class Meta: model = User fields = ('first_name', 'last_name', 'email', 'password1', 'password2', 'role',) diff --git a/apps/registration/tests.py b/apps/registration/tests.py index bc65bb7..e43aabc 100644 --- a/apps/registration/tests.py +++ b/apps/registration/tests.py @@ -84,26 +84,16 @@ class TestRegistration(TestCase): """ Ensure that the signup form is working successfully. """ - response = self.client.get(reverse("registration:signup")) - self.assertEqual(response.status_code, 200) - # After first phase - response = self.client.post(reverse("registration:signup"), data=dict( - last_name="Toto", - first_name="Toto", - email="toto@example.com", - password1="azertyuiopazertyuiop", - password2="azertyuiopazertyuiop", - role="participant", - student_class=12, - school="God", - give_contact_to_animath=False, - )) - self.assertEqual(response.status_code, 200) + response = self.client.get(reverse("registration:signup")) + self.assertEqual(response.status_code, 403) Phase.objects.filter(phase_number__gte=2).update(start=timezone.now() + timedelta(days=1), end=timezone.now() + timedelta(days=2)) + response = self.client.get(reverse("registration:signup")) + self.assertEqual(response.status_code, 200) + # Incomplete form response = self.client.post(reverse("registration:signup"), data=dict( last_name="Toto", diff --git a/apps/registration/views.py b/apps/registration/views.py index 91d13b6..7fe6707 100644 --- a/apps/registration/views.py +++ b/apps/registration/views.py @@ -13,6 +13,7 @@ from django.utils.http import urlsafe_base64_decode from django.utils.translation import gettext_lazy as _ from django.views.generic import CreateView, DetailView, RedirectView, TemplateView, UpdateView, View from magic import Magic +from participation.models import Phase from .forms import CoachRegistrationForm, PhotoAuthorizationForm, SignupForm, StudentRegistrationForm, UserForm from .models import StudentRegistration @@ -27,6 +28,15 @@ class SignupView(CreateView): template_name = "registration/signup.html" extra_context = dict(title=_("Sign up")) + def dispatch(self, request, *args, **kwargs): + """ + The signup view is available only during the first phase. + """ + current_phase = Phase.current_phase() + if not current_phase or current_phase.phase_number >= 2: + raise PermissionDenied(_("You can't register now.")) + return super().dispatch(request, *args, **kwargs) + def get_context_data(self, **kwargs): context = super().get_context_data() diff --git a/corres2math/templates/base.html b/corres2math/templates/base.html index 8cd6fc7..b5ece84 100644 --- a/corres2math/templates/base.html +++ b/corres2math/templates/base.html @@ -1,4 +1,4 @@ -{% load static i18n static %} +{% load static i18n static calendar %} {% get_current_language as LANGUAGE_CODE %}{% get_current_language_bidi as LANGUAGE_BIDI %} @@ -122,9 +122,11 @@ {% endif %} {% if not user.is_authenticated %} - + {% if 1|current_phase %} + + {% endif %}