diff --git a/apps/activity/models.py b/apps/activity/models.py index 131cd725..0aefaf59 100644 --- a/apps/activity/models.py +++ b/apps/activity/models.py @@ -130,7 +130,7 @@ class Activity(models.Model): raise ValidationError(_("The end date must be after the start date.")) ret = super().save(*args, **kwargs) - if settings.DEBUG and self.pk and "scripts" in settings.INSTALLED_APPS: + if not settings.DEBUG and self.pk and "scripts" in settings.INSTALLED_APPS: def refresh_activities(): from scripts.management.commands.refresh_activities import Command as RefreshActivitiesCommand RefreshActivitiesCommand.refresh_human_readable_wiki_page("Modification de l'activité " + self.name) diff --git a/apps/activity/tests/test_activities.py b/apps/activity/tests/test_activities.py new file mode 100644 index 00000000..db83fb0e --- /dev/null +++ b/apps/activity/tests/test_activities.py @@ -0,0 +1,176 @@ +# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay +# SPDX-License-Identifier: GPL-3.0-or-later + +from datetime import timedelta + +from django.contrib.auth.models import User +from django.test import TestCase +from django.urls import reverse +from django.utils import timezone + +from activity.models import Activity, ActivityType, Guest, Entry +from member.models import Club + + +class TestActivities(TestCase): + """ + Test activities + """ + fixtures = ('initial',) + + def setUp(self): + self.user = User.objects.create_superuser( + username="admintoto", + password="tototototo", + email="toto@example.com" + ) + self.client.force_login(self.user) + + sess = self.client.session + sess["permission_mask"] = 42 + sess.save() + + self.activity = Activity.objects.create( + name="Activity", + description="This is a test activity\non two very very long lines\nbecause this is very important.", + location="Earth", + activity_type=ActivityType.objects.get(name="Pot"), + creater=self.user, + organizer=Club.objects.get(name="Kfet"), + attendees_club=Club.objects.get(name="Kfet"), + date_start=timezone.now(), + date_end=timezone.now() + timedelta(days=2), + valid=True, + ) + + self.guest = Guest.objects.create( + activity=self.activity, + inviter=self.user.note, + last_name="GUEST", + first_name="Guest", + ) + + def test_activity_list(self): + """ + Display the list of all activities + """ + response = self.client.get(reverse("activity:activity_list")) + self.assertEqual(response.status_code, 200) + + def test_activity_create(self): + """ + Create a new activity + """ + response = self.client.get(reverse("activity:activity_create")) + self.assertEqual(response.status_code, 200) + + response = self.client.post(reverse("activity:activity_create"), data=dict( + name="Activity created", + description="This activity was successfully created.", + location="Earth", + activity_type=ActivityType.objects.get(name="Soirée de club").id, + creater=self.user.id, + organizer=Club.objects.get(name="Kfet").id, + attendees_club=Club.objects.get(name="Kfet").id, + date_start="{:%Y-%m-%d %H:%M}".format(timezone.now()), + date_end="{:%Y-%m-%d %H:%M}".format(timezone.now() + timedelta(days=2)), + valid=True, + )) + self.assertTrue(Activity.objects.filter(name="Activity created").exists()) + activity = Activity.objects.get(name="Activity created") + self.assertRedirects(response, reverse("activity:activity_detail", args=(activity.pk,)), 302, 200) + + def test_activity_detail(self): + """ + Display the detail of an activity + """ + response = self.client.get(reverse("activity:activity_detail", args=(self.activity.pk,))) + self.assertEqual(response.status_code, 200) + + def test_activity_update(self): + """ + Update an activity + """ + response = self.client.get(reverse("activity:activity_update", args=(self.activity.pk,))) + self.assertEqual(response.status_code, 200) + + response = self.client.post(reverse("activity:activity_update", args=(self.activity.pk,)), data=dict( + name=str(self.activity) + " updated", + description="This activity was successfully updated.", + location="Earth", + activity_type=ActivityType.objects.get(name="Autre").id, + creater=self.user.id, + organizer=Club.objects.get(name="Kfet").id, + attendees_club=Club.objects.get(name="Kfet").id, + date_start="{:%Y-%m-%d %H:%M}".format(timezone.now()), + date_end="{:%Y-%m-%d %H:%M}".format(timezone.now() + timedelta(days=2)), + valid=True, + )) + self.assertTrue(Activity.objects.filter(name="Activity updated").exists()) + self.assertRedirects(response, reverse("activity:activity_detail", args=(self.activity.pk,)), 302, 200) + + def test_activity_entry(self): + """ + Create some entries + """ + self.activity.open = True + self.activity.save() + + response = self.client.get(reverse("activity:activity_entry", args=(self.activity.pk,))) + self.assertEqual(response.status_code, 200) + response = self.client.get(reverse("activity:activity_entry", args=(self.activity.pk,)) + "?search=guest") + self.assertEqual(response.status_code, 200) + response = self.client.get(reverse("activity:activity_entry", args=(self.activity.pk,)) + "?search=admin") + self.assertEqual(response.status_code, 200) + + # User entry + response = self.client.post("/api/activity/entry/", data=dict( + activity=self.activity.id, + note=self.user.note.id, + guest="", + )) + self.assertEqual(response.status_code, 201) # 201 = Created + self.assertTrue(Entry.objects.filter(note=self.user.note, guest=None, activity=self.activity).exists()) + + # Guest entry + response = self.client.post("/api/activity/entry/", data=dict( + activity=self.activity.id, + note=self.user.note.id, + guest=self.guest.id, + )) + self.assertEqual(response.status_code, 201) # 201 = Created + self.assertTrue(Entry.objects.filter(note=self.user.note, guest=self.guest.id, activity=self.activity).exists()) + + def test_activity_invite(self): + """ + Try to invite people to an activity + """ + response = self.client.get(reverse("activity:activity_invite", args=(self.activity.pk,))) + self.assertEqual(response.status_code, 200) + + # The activity is started, can't invite + response = self.client.post(reverse("activity:activity_invite", args=(self.activity.pk,)), data=dict( + activity=self.activity.id, + inviter=self.user.note.id, + last_name="GUEST2", + first_name="Guest", + )) + self.assertEqual(response.status_code, 200) + + self.activity.date_start += timedelta(days=1) + self.activity.save() + + response = self.client.post(reverse("activity:activity_invite", args=(self.activity.pk,)), data=dict( + activity=self.activity.id, + inviter=self.user.note.id, + last_name="GUEST2", + first_name="Guest", + )) + self.assertRedirects(response, reverse("activity:activity_detail", args=(self.activity.pk,)), 302, 200) + + def test_activity_ics(self): + """ + Render the ICS calendar + """ + response = self.client.get(reverse("activity:calendar_ics")) + self.assertEqual(response.status_code, 200) diff --git a/apps/activity/views.py b/apps/activity/views.py index f6dae500..7de31b0c 100644 --- a/apps/activity/views.py +++ b/apps/activity/views.py @@ -1,7 +1,7 @@ # Copyright (C) 2018-2020 by BDE ENS Paris-Saclay # SPDX-License-Identifier: GPL-3.0-or-later + from hashlib import md5 -from random import randint from django.conf import settings from django.contrib.auth.mixins import LoginRequiredMixin @@ -11,7 +11,6 @@ from django.db.models import F, Q from django.http import HttpResponse from django.urls import reverse_lazy from django.utils import timezone -from django.utils.crypto import get_random_string from django.utils.translation import gettext_lazy as _ from django.views import View from django.views.generic import DetailView, TemplateView, UpdateView @@ -195,10 +194,10 @@ class ActivityEntryView(LoginRequiredMixin, TemplateView): if pattern[0] != "^": pattern = "^" + pattern guest_qs = guest_qs.filter( - Q(first_name__regex=pattern) - | Q(last_name__regex=pattern) - | Q(inviter__alias__name__regex=pattern) - | Q(inviter__alias__normalized_name__regex=Alias.normalize(pattern)) + Q(first_name__iregex=pattern) + | Q(last_name__iregex=pattern) + | Q(inviter__alias__name__iregex=pattern) + | Q(inviter__alias__normalized_name__iregex=Alias.normalize(pattern)) ) else: guest_qs = guest_qs.none() @@ -231,21 +230,19 @@ class ActivityEntryView(LoginRequiredMixin, TemplateView): if "search" in self.request.GET and self.request.GET["search"]: pattern = self.request.GET["search"] note_qs = note_qs.filter( - Q(note__noteuser__user__first_name__regex=pattern) - | Q(note__noteuser__user__last_name__regex=pattern) - | Q(name__regex=pattern) - | Q(normalized_name__regex=Alias.normalize(pattern)) + Q(note__noteuser__user__first_name__iregex=pattern) + | Q(note__noteuser__user__last_name__iregex=pattern) + | Q(name__iregex=pattern) + | Q(normalized_name__iregex=Alias.normalize(pattern)) ) else: note_qs = note_qs.none() - if settings.DATABASES[note_qs.db]["ENGINE"] == 'django.db.backends.postgresql': - note_qs = note_qs.distinct('note__pk')[:20] - else: - # SQLite doesn't support distinct fields. For compatibility reason (in dev mode), the note list will only - # have distinct aliases rather than distinct notes with a SQLite DB, but it can fill the result page. - # In production mode, please use PostgreSQL. - note_qs = note_qs.distinct()[:20] + # SQLite doesn't support distinct fields. For compatibility reason (in dev mode), the note list will only + # have distinct aliases rather than distinct notes with a SQLite DB, but it can fill the result page. + # In production mode, please use PostgreSQL. + note_qs = note_qs.distinct('note__pk')[:20]\ + if settings.DATABASES[note_qs.db]["ENGINE"] == 'django.db.backends.postgresql' else note_qs.distinct()[:20] return note_qs def get_context_data(self, **kwargs):