From 1a754f7bdcef46db14f3e51d159556acd491749d Mon Sep 17 00:00:00 2001 From: Eli Chadwick Date: Wed, 8 Nov 2023 17:00:12 +0000 Subject: [PATCH 01/20] add eventbrite_url field --- .../0270_trainingrequest_eventbrite_url.py | 18 ++++++++++++++++++ amy/workshops/models.py | 7 +++++++ 2 files changed, 25 insertions(+) create mode 100644 amy/workshops/migrations/0270_trainingrequest_eventbrite_url.py diff --git a/amy/workshops/migrations/0270_trainingrequest_eventbrite_url.py b/amy/workshops/migrations/0270_trainingrequest_eventbrite_url.py new file mode 100644 index 000000000..8a4caf8f0 --- /dev/null +++ b/amy/workshops/migrations/0270_trainingrequest_eventbrite_url.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.20 on 2023-11-08 16:59 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('workshops', '0269_alter_trainingrequest_default_for_text_fields'), + ] + + operations = [ + migrations.AddField( + model_name='trainingrequest', + name='eventbrite_url', + field=models.URLField(blank=True, default='', verbose_name='If you have already registered for an event through Eventbrite, enter the URL of that event.'), + ), + ] diff --git a/amy/workshops/models.py b/amy/workshops/models.py index 9cb8baf22..45c7c5823 100644 --- a/amy/workshops/models.py +++ b/amy/workshops/models.py @@ -2134,6 +2134,13 @@ class TrainingRequest( help_text="A member of our team will check the code and follow up with you if " "there are any problems that require your attention.", ) + eventbrite_url = models.URLField( + null=False, + blank=True, + default="", + verbose_name="If you have already registered for an event through Eventbrite, " + "enter the URL of that event.", + ) personal = models.CharField( max_length=STR_LONG, From 921ae8ed59f4acc2aba6aa01e11cc84c781b15e0 Mon Sep 17 00:00:00 2001 From: Eli Chadwick Date: Wed, 8 Nov 2023 17:00:30 +0000 Subject: [PATCH 02/20] display eventbrite_url field --- amy/extforms/forms.py | 3 +++ amy/templates/includes/trainingrequest_details.html | 2 ++ amy/templates/mailing/training_request.txt | 1 + 3 files changed, 6 insertions(+) diff --git a/amy/extforms/forms.py b/amy/extforms/forms.py index 6b192dadc..15363c3de 100644 --- a/amy/extforms/forms.py +++ b/amy/extforms/forms.py @@ -39,6 +39,7 @@ class Meta: "review_process", "member_code", "member_code_override", + "eventbrite_url", "personal", "family", "email", @@ -150,6 +151,7 @@ def set_accordion(self, layout: Layout) -> None: "preapproved": [ self["member_code"], self["member_code_override"], + self["eventbrite_url"], ], "open": [], # this option doesn't require any additional fields } @@ -163,6 +165,7 @@ def set_accordion(self, layout: Layout) -> None: layout.fields.remove("review_process") layout.fields.remove("member_code") layout.fields.remove("member_code_override") + layout.fields.remove("eventbrite_url") # insert div+field at previously saved position layout.insert( diff --git a/amy/templates/includes/trainingrequest_details.html b/amy/templates/includes/trainingrequest_details.html index 0a626f779..8ded84c3f 100644 --- a/amy/templates/includes/trainingrequest_details.html +++ b/amy/templates/includes/trainingrequest_details.html @@ -30,6 +30,8 @@ Continue with registration code marked as invalid: {{ object.member_code_override|yesno }} {% endif %} + Eventbrite URL: + {{ object.eventbrite_url|default:"—" }} Personal name: {{ object.personal }} Middle name: diff --git a/amy/templates/mailing/training_request.txt b/amy/templates/mailing/training_request.txt index 67cafc4f4..5ebe52d1b 100644 --- a/amy/templates/mailing/training_request.txt +++ b/amy/templates/mailing/training_request.txt @@ -37,6 +37,7 @@ Registration Code: {{ object.member_code|default:"—" }} {% if object.member_code_override %} Continue with registration code marked as invalid: {{object.member_code_override|yesno}} {% endif %} +Eventbrite URL: {{ object.eventbrite_url }} Person: {{object.personal}} {{object.middle}} {{object.family}} <{{object.email}}> Github: {{ object.github|default:"---" }} Occupation: {{ object.get_occupation_display }} {{ object.occupation_other }} From 8f4f013bedd01efea87afc341b919860ffcb992f Mon Sep 17 00:00:00 2001 From: Eli Chadwick Date: Wed, 8 Nov 2023 17:00:41 +0000 Subject: [PATCH 03/20] fake eventbrite urls --- amy/workshops/management/commands/fake_database.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/amy/workshops/management/commands/fake_database.py b/amy/workshops/management/commands/fake_database.py index c850710e5..5341f8bbc 100644 --- a/amy/workshops/management/commands/fake_database.py +++ b/amy/workshops/management/commands/fake_database.py @@ -322,12 +322,14 @@ def fake_training_request(self, person_or_None): underrepresented_choices = TrainingRequest._meta.get_field( "underrepresented" ).choices + eventbrite_url = self.faker.url() if registration_code and randbool(0.5) else "" req = TrainingRequest.objects.create( state=state, person=person_or_None, review_process="preapproved" if registration_code else "open", member_code=registration_code, member_code_override=override_invalid_code, + eventbrite_url=eventbrite_url, personal=person.personal, middle="", family=person.family, From 8c046cafb0568b5df635e11ad8b26ddb1439e451 Mon Sep 17 00:00:00 2001 From: Eli Chadwick Date: Wed, 8 Nov 2023 17:24:28 +0000 Subject: [PATCH 04/20] add filter for eventbrite url --- amy/extrequests/filters.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/amy/extrequests/filters.py b/amy/extrequests/filters.py index febe56965..3bb90a046 100644 --- a/amy/extrequests/filters.py +++ b/amy/extrequests/filters.py @@ -43,6 +43,10 @@ def __init__(self, data=None, *args, **kwargs): field_name="member_code", lookup_expr="icontains", label="Member code" ) + eventbrite_url = django_filters.CharFilter( + field_name="eventbrite_url", lookup_expr="icontains", label="Eventbrite URL" + ) + state = django_filters.ChoiceFilter( label="State", choices=(("pa", "Pending or accepted"),) + TrainingRequest.STATE_CHOICES, From 94c863b30fd1ea32b65ee91fb1bd40bda805e55c Mon Sep 17 00:00:00 2001 From: Eli Chadwick Date: Fri, 10 Nov 2023 10:53:59 +0000 Subject: [PATCH 05/20] get eventbrite id from url --- amy/extrequests/templatetags/eventbrite.py | 16 +++++++++ amy/extrequests/tests/test_template_tags.py | 34 +++++++++++++++++++ .../requests/all_trainingrequests.html | 9 +++++ .../management/commands/fake_database.py | 7 +++- 4 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 amy/extrequests/templatetags/eventbrite.py diff --git a/amy/extrequests/templatetags/eventbrite.py b/amy/extrequests/templatetags/eventbrite.py new file mode 100644 index 000000000..1d11bb910 --- /dev/null +++ b/amy/extrequests/templatetags/eventbrite.py @@ -0,0 +1,16 @@ +from django import template +import regex + +register = template.Library() + +# Eventbrite IDs are long strings of digits (~12 characters) +EVENTBRITE_ID_PATTERN = regex.compile(r"\d{10,}") + + +@register.simple_tag +def eventbrite_id_from_url(url: str) -> str: + if not isinstance(url, str): + return url + + re = regex.search(EVENTBRITE_ID_PATTERN, url) + return re.group() if re else url diff --git a/amy/extrequests/tests/test_template_tags.py b/amy/extrequests/tests/test_template_tags.py index e752ca540..94d5e1e49 100644 --- a/amy/extrequests/tests/test_template_tags.py +++ b/amy/extrequests/tests/test_template_tags.py @@ -2,10 +2,12 @@ from django.test import TestCase +from extrequests.templatetags.eventbrite import eventbrite_id_from_url from amy.extrequests.templatetags.request_membership import ( membership_active, membership_alert_type, ) + from workshops.models import Membership @@ -98,3 +100,35 @@ def test_inactive(self): # Assert self.assertEqual(expected, result) + + +class TestEventbriteIdFromUrl(TestCase): + def test_long_url(self): + # Arrange + url = "https://www.eventbrite.com/e/online-instructor-training-7-8-november-2023-tickets-711575811407?aff=oddtdtcreator" # noqa: line too long + + # Act + result = eventbrite_id_from_url(url) + + # Assert + self.assertEqual(result, "711575811407") + + def test_short_url(self): + # Arrange + url = "https://www.eventbrite.com/e/711575811407" + + # Act + result = eventbrite_id_from_url(url) + + # Assert + self.assertEqual(result, "711575811407") + + def test_admin_url(self): + # Arrange + url = "https://www.eventbrite.com/myevent?eid=711575811407" + + # Act + result = eventbrite_id_from_url(url) + + # Assert + self.assertEqual(result, "711575811407") diff --git a/amy/templates/requests/all_trainingrequests.html b/amy/templates/requests/all_trainingrequests.html index 0690f0ff6..b8d184eab 100644 --- a/amy/templates/requests/all_trainingrequests.html +++ b/amy/templates/requests/all_trainingrequests.html @@ -5,6 +5,7 @@ {% load tags %} {% load state %} {% load static %} +{% load eventbrite %} {% block content %} {% if requests %} @@ -20,6 +21,7 @@ Submitter Reg. Code + Eventbrite ID Affiliation {{ req.member_code|default:"—" }} + + {% if req.eventbrite_url %} + {% eventbrite_id_from_url req.eventbrite_url %} + {% else %} + — + {% endif %} + {{ req.affiliation|default:"—" }} {% if req.person %} diff --git a/amy/workshops/management/commands/fake_database.py b/amy/workshops/management/commands/fake_database.py index 5341f8bbc..b7f3c1f9c 100644 --- a/amy/workshops/management/commands/fake_database.py +++ b/amy/workshops/management/commands/fake_database.py @@ -322,7 +322,12 @@ def fake_training_request(self, person_or_None): underrepresented_choices = TrainingRequest._meta.get_field( "underrepresented" ).choices - eventbrite_url = self.faker.url() if registration_code and randbool(0.5) else "" + eventbrite_url = "" + if registration_code and randbool(0.5): + eventbrite_url = ( + "https://eventbrite.com/fake-" + f"{self.faker.random_number(digits=12, fix_len=True)}" + ) req = TrainingRequest.objects.create( state=state, person=person_or_None, From 34ef28c3b255cb54bc463bf4ba5542299119a527 Mon Sep 17 00:00:00 2001 From: Eli Chadwick Date: Fri, 10 Nov 2023 11:54:48 +0000 Subject: [PATCH 06/20] allow event id or url in filter --- amy/extrequests/filters.py | 19 +++++++++-- amy/extrequests/templatetags/eventbrite.py | 8 ++--- amy/extrequests/tests/test_filters.py | 24 ++++++++++++++ amy/extrequests/tests/test_template_tags.py | 33 ------------------- amy/extrequests/tests/test_utils.py | 35 +++++++++++++++++++++ amy/extrequests/utils.py | 14 +++++++++ 6 files changed, 93 insertions(+), 40 deletions(-) diff --git a/amy/extrequests/filters.py b/amy/extrequests/filters.py index 3bb90a046..b11f3bb39 100644 --- a/amy/extrequests/filters.py +++ b/amy/extrequests/filters.py @@ -7,6 +7,7 @@ import django_filters from extrequests.models import SelfOrganisedSubmission, WorkshopInquiryRequest +from extrequests.utils import get_eventbrite_id_from_url from workshops.fields import Select2Widget from workshops.filters import ( AllCountriesFilter, @@ -43,8 +44,9 @@ def __init__(self, data=None, *args, **kwargs): field_name="member_code", lookup_expr="icontains", label="Member code" ) - eventbrite_url = django_filters.CharFilter( - field_name="eventbrite_url", lookup_expr="icontains", label="Eventbrite URL" + eventbrite_id = django_filters.CharFilter( + label="Eventbrite ID or URL", + method="filter_eventbrite_id", ) state = django_filters.ChoiceFilter( @@ -171,6 +173,19 @@ def filter_member_code_override( return queryset.filter(member_code_override=True) return queryset + def filter_eventbrite_id( + self, queryset: QuerySet, name: str, value: str + ) -> QuerySet: + # user may input the event's ID or its full URL + # events have multiple possible URLs which all contain the ID, + # so filter by the ID if possible + try: + int(value) + except ValueError: + value = get_eventbrite_id_from_url(value) + + return queryset.filter(eventbrite_url__icontains=value) + # ------------------------------------------------------------ # WorkshopRequest related filter and filter methods diff --git a/amy/extrequests/templatetags/eventbrite.py b/amy/extrequests/templatetags/eventbrite.py index 1d11bb910..f8ce6409f 100644 --- a/amy/extrequests/templatetags/eventbrite.py +++ b/amy/extrequests/templatetags/eventbrite.py @@ -1,6 +1,8 @@ from django import template import regex +from extrequests.utils import get_eventbrite_id_from_url + register = template.Library() # Eventbrite IDs are long strings of digits (~12 characters) @@ -9,8 +11,4 @@ @register.simple_tag def eventbrite_id_from_url(url: str) -> str: - if not isinstance(url, str): - return url - - re = regex.search(EVENTBRITE_ID_PATTERN, url) - return re.group() if re else url + return get_eventbrite_id_from_url(url) diff --git a/amy/extrequests/tests/test_filters.py b/amy/extrequests/tests/test_filters.py index 3930540ac..cc1c6e52c 100644 --- a/amy/extrequests/tests/test_filters.py +++ b/amy/extrequests/tests/test_filters.py @@ -63,6 +63,7 @@ def setUp(self) -> None: person=self.ironman, review_process="preapproved", member_code=self.membership.registration_code, + eventbrite_url="https://www.eventbrite.com/e/711575811407", personal="Tony", family="Stark", email="me@stark.com", @@ -112,6 +113,7 @@ def test_fields(self): "invalid_member_code", "affiliation", "location", + "eventbrite_id", "order_by", }, ) @@ -318,6 +320,28 @@ def test_filter_location(self): # Assert self.assertQuerysetEqual(result, [self.request_ironman]) + def test_filter_eventbrite_id__digits(self): + # Arrange + name = "eventbrite_id" + value = "1407" + + # Act + result = self.filterset.filters[name].filter(self.qs, value) + + # Assert + self.assertQuerysetEqual(result, [self.request_ironman]) + + def test_filter_eventbrite_id__url(self): + # Arrange + name = "eventbrite_id" + value = "https://www.eventbrite.com/myevent?eid=711575811407" + + # Act + result = self.filterset.filters[name].filter(self.qs, value) + + # Assert + self.assertQuerysetEqual(result, [self.request_ironman]) + def test_filter_order_by(self): # Arrange filter_name = "order_by" diff --git a/amy/extrequests/tests/test_template_tags.py b/amy/extrequests/tests/test_template_tags.py index 94d5e1e49..e5b447beb 100644 --- a/amy/extrequests/tests/test_template_tags.py +++ b/amy/extrequests/tests/test_template_tags.py @@ -2,7 +2,6 @@ from django.test import TestCase -from extrequests.templatetags.eventbrite import eventbrite_id_from_url from amy.extrequests.templatetags.request_membership import ( membership_active, membership_alert_type, @@ -100,35 +99,3 @@ def test_inactive(self): # Assert self.assertEqual(expected, result) - - -class TestEventbriteIdFromUrl(TestCase): - def test_long_url(self): - # Arrange - url = "https://www.eventbrite.com/e/online-instructor-training-7-8-november-2023-tickets-711575811407?aff=oddtdtcreator" # noqa: line too long - - # Act - result = eventbrite_id_from_url(url) - - # Assert - self.assertEqual(result, "711575811407") - - def test_short_url(self): - # Arrange - url = "https://www.eventbrite.com/e/711575811407" - - # Act - result = eventbrite_id_from_url(url) - - # Assert - self.assertEqual(result, "711575811407") - - def test_admin_url(self): - # Arrange - url = "https://www.eventbrite.com/myevent?eid=711575811407" - - # Act - result = eventbrite_id_from_url(url) - - # Assert - self.assertEqual(result, "711575811407") diff --git a/amy/extrequests/tests/test_utils.py b/amy/extrequests/tests/test_utils.py index 1cc291eea..3fd6dff7e 100644 --- a/amy/extrequests/tests/test_utils.py +++ b/amy/extrequests/tests/test_utils.py @@ -1,9 +1,12 @@ from datetime import date, timedelta +from django.test import TestCase + from extrequests.tests.test_training_request import create_training_request from extrequests.utils import ( MemberCodeValidationError, accept_training_request_and_match_to_event, + get_eventbrite_id_from_url, get_membership_from_training_request_or_raise_error, get_membership_or_none_from_code, get_membership_warnings_after_match, @@ -613,3 +616,35 @@ def test_multiple_warnings(self): # Assert self.assertListEqual(expected, result) + + +class TestGetEventbriteIdFromUrl(TestCase): + def test_long_url(self): + # Arrange + url = "https://www.eventbrite.com/e/online-instructor-training-7-8-november-2023-tickets-711575811407?aff=oddtdtcreator" # noqa: line too long + + # Act + result = get_eventbrite_id_from_url(url) + + # Assert + self.assertEqual(result, "711575811407") + + def test_short_url(self): + # Arrange + url = "https://www.eventbrite.com/e/711575811407" + + # Act + result = get_eventbrite_id_from_url(url) + + # Assert + self.assertEqual(result, "711575811407") + + def test_admin_url(self): + # Arrange + url = "https://www.eventbrite.com/myevent?eid=711575811407" + + # Act + result = get_eventbrite_id_from_url(url) + + # Assert + self.assertEqual(result, "711575811407") diff --git a/amy/extrequests/utils.py b/amy/extrequests/utils.py index 48ba86bec..dfaf60ae5 100644 --- a/amy/extrequests/utils.py +++ b/amy/extrequests/utils.py @@ -1,6 +1,7 @@ from datetime import date from django.core.exceptions import ValidationError +import regex from workshops.models import Event, Membership, Role, Task, TrainingRequest @@ -8,6 +9,9 @@ # Utilities for validating member codes # ---------------------------------------- +# Eventbrite IDs are long strings of digits (~12 characters) +EVENTBRITE_ID_PATTERN = regex.compile(r"\d{10,}") + class MemberCodeValidationError(ValidationError): pass @@ -170,3 +174,13 @@ def get_membership_warnings_after_match( ) return warnings + + +def get_eventbrite_id_from_url(url: str) -> str: + """Given the URL for an Eventbrite event, returns that event's ID. + If the ID can't be found, returns the original URL.""" + if not isinstance(url, str): + return url + + re = regex.search(EVENTBRITE_ID_PATTERN, url) + return re.group() if re else url From 083e771311ff6b7f3f90bf1559324f6026df7894 Mon Sep 17 00:00:00 2001 From: Eli Chadwick Date: Fri, 10 Nov 2023 12:32:11 +0000 Subject: [PATCH 07/20] Revert "never hide requests with invalid codes" This reverts commit caf0cac8949eedfbbf9b099f168757ff633bc99a. --- amy/extrequests/filters.py | 11 +---------- amy/extrequests/tests/test_filters.py | 13 +------------ 2 files changed, 2 insertions(+), 22 deletions(-) diff --git a/amy/extrequests/filters.py b/amy/extrequests/filters.py index b11f3bb39..2ebc636df 100644 --- a/amy/extrequests/filters.py +++ b/amy/extrequests/filters.py @@ -74,7 +74,7 @@ def __init__(self, data=None, *args, **kwargs): invalid_member_code = django_filters.BooleanFilter( label="Member code marked as invalid", - method="filter_member_code_override", + field_name="member_code_override", widget=widgets.CheckboxInput, ) @@ -164,15 +164,6 @@ def filter_non_null_manual_score(self, queryset, name, manual_score): return queryset.filter(score_manual__isnull=False) return queryset - def filter_member_code_override( - self, queryset: QuerySet, name: str, only_overrides: bool - ) -> QuerySet: - """If checked, only show requests where the member code has been - marked as invalid. Otherwise, show all requests.""" - if only_overrides: - return queryset.filter(member_code_override=True) - return queryset - def filter_eventbrite_id( self, queryset: QuerySet, name: str, value: str ) -> QuerySet: diff --git a/amy/extrequests/tests/test_filters.py b/amy/extrequests/tests/test_filters.py index cc1c6e52c..eb76464be 100644 --- a/amy/extrequests/tests/test_filters.py +++ b/amy/extrequests/tests/test_filters.py @@ -276,7 +276,7 @@ def test_filter_nonnull_manual_score(self): # Assert self.assertQuerysetEqual(result, [self.request_blackwidow]) - def test_filter_invalid_member_code__true(self): + def test_filter_invalid_member_code(self): # Arrange filter_name = "invalid_member_code" value = True @@ -287,17 +287,6 @@ def test_filter_invalid_member_code__true(self): # Assert self.assertQuerysetEqual(result, [self.request_blackwidow]) - def test_filter_invalid_member_code__false(self): - # Arrange - filter_name = "invalid_member_code" - value = False - - # Act - result = self.filterset.filters[filter_name].filter(self.qs, value) - - # Assert - self.assertQuerysetEqual(result, TrainingRequest.objects.all()) - def test_filter_affiliation(self): # Arrange name = "affiliation" From b4fc8dc10ae665f92d713d7b30de6d314f9c657d Mon Sep 17 00:00:00 2001 From: Eli Chadwick Date: Fri, 10 Nov 2023 13:10:26 +0000 Subject: [PATCH 08/20] use re not regex --- amy/extrequests/templatetags/eventbrite.py | 4 ---- amy/extrequests/utils.py | 8 ++++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/amy/extrequests/templatetags/eventbrite.py b/amy/extrequests/templatetags/eventbrite.py index f8ce6409f..dd5f42d97 100644 --- a/amy/extrequests/templatetags/eventbrite.py +++ b/amy/extrequests/templatetags/eventbrite.py @@ -1,13 +1,9 @@ from django import template -import regex from extrequests.utils import get_eventbrite_id_from_url register = template.Library() -# Eventbrite IDs are long strings of digits (~12 characters) -EVENTBRITE_ID_PATTERN = regex.compile(r"\d{10,}") - @register.simple_tag def eventbrite_id_from_url(url: str) -> str: diff --git a/amy/extrequests/utils.py b/amy/extrequests/utils.py index dfaf60ae5..50ffdc43d 100644 --- a/amy/extrequests/utils.py +++ b/amy/extrequests/utils.py @@ -1,7 +1,7 @@ from datetime import date +import re from django.core.exceptions import ValidationError -import regex from workshops.models import Event, Membership, Role, Task, TrainingRequest @@ -10,7 +10,7 @@ # ---------------------------------------- # Eventbrite IDs are long strings of digits (~12 characters) -EVENTBRITE_ID_PATTERN = regex.compile(r"\d{10,}") +EVENTBRITE_ID_PATTERN = re.compile(r"\d{10,}") class MemberCodeValidationError(ValidationError): @@ -182,5 +182,5 @@ def get_eventbrite_id_from_url(url: str) -> str: if not isinstance(url, str): return url - re = regex.search(EVENTBRITE_ID_PATTERN, url) - return re.group() if re else url + match = re.search(EVENTBRITE_ID_PATTERN, url) + return match.group() if match else url From 6222621a18b8f043cfb5826b5aa102c89e195805 Mon Sep 17 00:00:00 2001 From: Eli Chadwick Date: Mon, 20 Nov 2023 12:48:46 +0000 Subject: [PATCH 09/20] rebase migration --- .../0268_trainingrequest_eventbrite_url.py | 21 +++++++++++++++++++ .../0270_trainingrequest_eventbrite_url.py | 18 ---------------- 2 files changed, 21 insertions(+), 18 deletions(-) create mode 100644 amy/workshops/migrations/0268_trainingrequest_eventbrite_url.py delete mode 100644 amy/workshops/migrations/0270_trainingrequest_eventbrite_url.py diff --git a/amy/workshops/migrations/0268_trainingrequest_eventbrite_url.py b/amy/workshops/migrations/0268_trainingrequest_eventbrite_url.py new file mode 100644 index 000000000..716884719 --- /dev/null +++ b/amy/workshops/migrations/0268_trainingrequest_eventbrite_url.py @@ -0,0 +1,21 @@ +# Generated by Django 3.2.20 on 2023-11-08 16:59 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("workshops", "0267_alter_trainingrequest_default_for_text_fields"), + ] + + operations = [ + migrations.AddField( + model_name="trainingrequest", + name="eventbrite_url", + field=models.URLField( + blank=True, + default="", + verbose_name="If you have already registered for an event through Eventbrite, enter the URL of that event.", + ), + ), + ] diff --git a/amy/workshops/migrations/0270_trainingrequest_eventbrite_url.py b/amy/workshops/migrations/0270_trainingrequest_eventbrite_url.py deleted file mode 100644 index 8a4caf8f0..000000000 --- a/amy/workshops/migrations/0270_trainingrequest_eventbrite_url.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 3.2.20 on 2023-11-08 16:59 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('workshops', '0269_alter_trainingrequest_default_for_text_fields'), - ] - - operations = [ - migrations.AddField( - model_name='trainingrequest', - name='eventbrite_url', - field=models.URLField(blank=True, default='', verbose_name='If you have already registered for an event through Eventbrite, enter the URL of that event.'), - ), - ] From 16a87a5fbbfd30068528845fb1733bb31c9d68b9 Mon Sep 17 00:00:00 2001 From: Eli Chadwick Date: Mon, 20 Nov 2023 12:49:18 +0000 Subject: [PATCH 10/20] improve naming and comments --- amy/extrequests/filters.py | 16 +++++++++++----- amy/extrequests/templatetags/eventbrite.py | 4 ++-- amy/extrequests/tests/test_utils.py | 8 ++++---- amy/extrequests/utils.py | 7 ++----- 4 files changed, 19 insertions(+), 16 deletions(-) diff --git a/amy/extrequests/filters.py b/amy/extrequests/filters.py index 2ebc636df..e8d38a1c2 100644 --- a/amy/extrequests/filters.py +++ b/amy/extrequests/filters.py @@ -7,7 +7,7 @@ import django_filters from extrequests.models import SelfOrganisedSubmission, WorkshopInquiryRequest -from extrequests.utils import get_eventbrite_id_from_url +from extrequests.utils import get_eventbrite_id_from_url_or_return_input from workshops.fields import Select2Widget from workshops.filters import ( AllCountriesFilter, @@ -167,13 +167,19 @@ def filter_non_null_manual_score(self, queryset, name, manual_score): def filter_eventbrite_id( self, queryset: QuerySet, name: str, value: str ) -> QuerySet: - # user may input the event's ID or its full URL - # events have multiple possible URLs which all contain the ID, - # so filter by the ID if possible + """ + Returns the queryset filtered by an Eventbrite ID or URL. + Events have multiple possible URLs which all contain the ID, so + if a URL is used, the filter will try to extract and filter by the ID. + If no ID can be found, the filter will use the original input. + """ + try: + # if input is an integer, assume it to be a partial or full Eventbrite ID int(value) except ValueError: - value = get_eventbrite_id_from_url(value) + # otherwise, try to extract an ID from the input + value = get_eventbrite_id_from_url_or_return_input(value) return queryset.filter(eventbrite_url__icontains=value) diff --git a/amy/extrequests/templatetags/eventbrite.py b/amy/extrequests/templatetags/eventbrite.py index dd5f42d97..e27c0beff 100644 --- a/amy/extrequests/templatetags/eventbrite.py +++ b/amy/extrequests/templatetags/eventbrite.py @@ -1,10 +1,10 @@ from django import template -from extrequests.utils import get_eventbrite_id_from_url +from extrequests.utils import get_eventbrite_id_from_url_or_return_input register = template.Library() @register.simple_tag def eventbrite_id_from_url(url: str) -> str: - return get_eventbrite_id_from_url(url) + return get_eventbrite_id_from_url_or_return_input(url) diff --git a/amy/extrequests/tests/test_utils.py b/amy/extrequests/tests/test_utils.py index 3fd6dff7e..4718af414 100644 --- a/amy/extrequests/tests/test_utils.py +++ b/amy/extrequests/tests/test_utils.py @@ -6,7 +6,7 @@ from extrequests.utils import ( MemberCodeValidationError, accept_training_request_and_match_to_event, - get_eventbrite_id_from_url, + get_eventbrite_id_from_url_or_return_input, get_membership_from_training_request_or_raise_error, get_membership_or_none_from_code, get_membership_warnings_after_match, @@ -624,7 +624,7 @@ def test_long_url(self): url = "https://www.eventbrite.com/e/online-instructor-training-7-8-november-2023-tickets-711575811407?aff=oddtdtcreator" # noqa: line too long # Act - result = get_eventbrite_id_from_url(url) + result = get_eventbrite_id_from_url_or_return_input(url) # Assert self.assertEqual(result, "711575811407") @@ -634,7 +634,7 @@ def test_short_url(self): url = "https://www.eventbrite.com/e/711575811407" # Act - result = get_eventbrite_id_from_url(url) + result = get_eventbrite_id_from_url_or_return_input(url) # Assert self.assertEqual(result, "711575811407") @@ -644,7 +644,7 @@ def test_admin_url(self): url = "https://www.eventbrite.com/myevent?eid=711575811407" # Act - result = get_eventbrite_id_from_url(url) + result = get_eventbrite_id_from_url_or_return_input(url) # Assert self.assertEqual(result, "711575811407") diff --git a/amy/extrequests/utils.py b/amy/extrequests/utils.py index 50ffdc43d..d4e48deba 100644 --- a/amy/extrequests/utils.py +++ b/amy/extrequests/utils.py @@ -176,11 +176,8 @@ def get_membership_warnings_after_match( return warnings -def get_eventbrite_id_from_url(url: str) -> str: +def get_eventbrite_id_from_url_or_return_input(url: str) -> str: """Given the URL for an Eventbrite event, returns that event's ID. - If the ID can't be found, returns the original URL.""" - if not isinstance(url, str): - return url - + If the ID can't be found, returns the input URL.""" match = re.search(EVENTBRITE_ID_PATTERN, url) return match.group() if match else url From ff64cf6d0b5073daca545d9a62a4603a47885a07 Mon Sep 17 00:00:00 2001 From: Eli Chadwick Date: Mon, 20 Nov 2023 12:58:25 +0000 Subject: [PATCH 11/20] isort --- amy/extrequests/tests/test_template_tags.py | 1 - 1 file changed, 1 deletion(-) diff --git a/amy/extrequests/tests/test_template_tags.py b/amy/extrequests/tests/test_template_tags.py index e5b447beb..e752ca540 100644 --- a/amy/extrequests/tests/test_template_tags.py +++ b/amy/extrequests/tests/test_template_tags.py @@ -6,7 +6,6 @@ membership_active, membership_alert_type, ) - from workshops.models import Membership From b38907c188eb6e0c187457312a7969ab988aa2a5 Mon Sep 17 00:00:00 2001 From: Eli Chadwick Date: Tue, 21 Nov 2023 12:07:48 +0000 Subject: [PATCH 12/20] update help text --- .../migrations/0268_trainingrequest_eventbrite_url.py | 3 ++- amy/workshops/models.py | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/amy/workshops/migrations/0268_trainingrequest_eventbrite_url.py b/amy/workshops/migrations/0268_trainingrequest_eventbrite_url.py index 716884719..42bb67acf 100644 --- a/amy/workshops/migrations/0268_trainingrequest_eventbrite_url.py +++ b/amy/workshops/migrations/0268_trainingrequest_eventbrite_url.py @@ -15,7 +15,8 @@ class Migration(migrations.Migration): field=models.URLField( blank=True, default="", - verbose_name="If you have already registered for an event through Eventbrite, enter the URL of that event.", + verbose_name="Eventbrite URL", + help_text="If you are registering or have registered for a training event through Eventbrite, enter the URL of that event. You can find this on the registration page or in the confirmation email. If you have not yet registered for an event, leave this field blank.", ), ), ] diff --git a/amy/workshops/models.py b/amy/workshops/models.py index 45c7c5823..7e193cf78 100644 --- a/amy/workshops/models.py +++ b/amy/workshops/models.py @@ -2138,8 +2138,11 @@ class TrainingRequest( null=False, blank=True, default="", - verbose_name="If you have already registered for an event through Eventbrite, " - "enter the URL of that event.", + verbose_name="Eventbrite URL", + help_text="If you are registering or have registered for a training event " + "through Eventbrite, enter the URL of that event. You can find this on the " + "registration page or in the confirmation email. " + "If you have not yet registered for an event, leave this field blank.", ) personal = models.CharField( From d1689c37f86223c7b9ffab597da1f49974ccd22c Mon Sep 17 00:00:00 2001 From: Eli Chadwick Date: Tue, 21 Nov 2023 12:36:40 +0000 Subject: [PATCH 13/20] add validation for eventbrite urls --- amy/extforms/forms.py | 7 ++++ .../tests/test_training_request_form.py | 40 +++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/amy/extforms/forms.py b/amy/extforms/forms.py index 15363c3de..62491e6ff 100644 --- a/amy/extforms/forms.py +++ b/amy/extforms/forms.py @@ -1,5 +1,6 @@ from datetime import date from typing import Iterable, cast +from urllib.parse import urlparse from captcha.fields import ReCaptchaField from crispy_forms.layout import HTML, Div, Field, Layout @@ -251,6 +252,12 @@ def validate_member_code( return errors + def clean_eventbrite_url(self): + """Check that entered URL includes 'eventbrite' in the domain.""" + eventbrite_url = self.cleaned_data.get("eventbrite_url", "") + if eventbrite_url and "eventbrite" not in urlparse(eventbrite_url).netloc: + raise ValidationError("Must be an Eventbrite URL.") + def clean(self): super().clean() errors = dict() diff --git a/amy/extforms/tests/test_training_request_form.py b/amy/extforms/tests/test_training_request_form.py index a87ca36dc..1d76d39b8 100644 --- a/amy/extforms/tests/test_training_request_form.py +++ b/amy/extforms/tests/test_training_request_form.py @@ -18,6 +18,7 @@ class TestTrainingRequestForm(TestBase): MEMBER_CODE_OVERRIDE_EMAIL_WARNING = ( "A member of our team will check the code and follow up with you" ) + INVALID_EVENTBRITE_URL_ERROR = "Must be an Eventbrite URL." def setUp(self): self._setUpUsersAndLogin() @@ -470,3 +471,42 @@ def test_member_code_validation__code_invalid_override_full_request(self): self.assertNotIn( settings.TEMPLATES[0]["OPTIONS"]["string_if_invalid"], msg.body ) + + def test_eventbrite_url_validation__none(self): + """Should not error if no URL is entered.""" + # Arrange + self.setUpMembership() + data = {"eventbrite_url": ""} + + # Act + rv = self.client.post(reverse("training_request"), data=data) + + # Assert + self.assertEqual(rv.status_code, 200) + self.assertNotContains(rv, self.INVALID_EVENTBRITE_URL_ERROR) + + def test_eventbrite_url_validation__invalid(self): + """Should error if a non-Eventbrite URL is entered.""" + # Arrange + self.setUpMembership() + data = {"eventbrite_url": "https://google.com"} + + # Act + rv = self.client.post(reverse("training_request"), data=data) + + # Assert + self.assertEqual(rv.status_code, 200) + self.assertContains(rv, self.INVALID_EVENTBRITE_URL_ERROR) + + def test_eventbrite_url_validation__valid(self): + """Should not error if an Eventbrite URL is entered.""" + # Arrange + self.setUpMembership() + data = {"eventbrite_url": "https://www.eventbrite.com/e/711576483417"} + + # Act + rv = self.client.post(reverse("training_request"), data=data) + + # Assert + self.assertEqual(rv.status_code, 200) + self.assertNotContains(rv, self.INVALID_EVENTBRITE_URL_ERROR) From 25fbc1f4830ffcc1fffad7eff0838bf31bcfebc4 Mon Sep 17 00:00:00 2001 From: Eli Chadwick Date: Thu, 23 Nov 2023 10:19:52 +0000 Subject: [PATCH 14/20] remove eventbrite column from table --- amy/templates/requests/all_trainingrequests.html | 9 --------- 1 file changed, 9 deletions(-) diff --git a/amy/templates/requests/all_trainingrequests.html b/amy/templates/requests/all_trainingrequests.html index b8d184eab..0690f0ff6 100644 --- a/amy/templates/requests/all_trainingrequests.html +++ b/amy/templates/requests/all_trainingrequests.html @@ -5,7 +5,6 @@ {% load tags %} {% load state %} {% load static %} -{% load eventbrite %} {% block content %} {% if requests %} @@ -21,7 +20,6 @@ Submitter Reg. Code - Eventbrite ID Affiliation {{ req.member_code|default:"—" }} - - {% if req.eventbrite_url %} - {% eventbrite_id_from_url req.eventbrite_url %} - {% else %} - — - {% endif %} - {{ req.affiliation|default:"—" }} {% if req.person %} From 0266a80b579678803b6f0255188044794e511d0a Mon Sep 17 00:00:00 2001 From: Eli Chadwick Date: Thu, 23 Nov 2023 10:20:30 +0000 Subject: [PATCH 15/20] remove unnecessary template tag --- amy/extrequests/templatetags/eventbrite.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/amy/extrequests/templatetags/eventbrite.py b/amy/extrequests/templatetags/eventbrite.py index e27c0beff..4bd3b15fe 100644 --- a/amy/extrequests/templatetags/eventbrite.py +++ b/amy/extrequests/templatetags/eventbrite.py @@ -1,10 +1,3 @@ from django import template -from extrequests.utils import get_eventbrite_id_from_url_or_return_input - register = template.Library() - - -@register.simple_tag -def eventbrite_id_from_url(url: str) -> str: - return get_eventbrite_id_from_url_or_return_input(url) From c813c42e151785bbf87b67b8cb26b84a493c67cb Mon Sep 17 00:00:00 2001 From: Eli Chadwick Date: Thu, 23 Nov 2023 11:20:46 +0000 Subject: [PATCH 16/20] use hostname not netloc --- amy/extforms/forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/amy/extforms/forms.py b/amy/extforms/forms.py index 62491e6ff..21e3dce6c 100644 --- a/amy/extforms/forms.py +++ b/amy/extforms/forms.py @@ -255,7 +255,7 @@ def validate_member_code( def clean_eventbrite_url(self): """Check that entered URL includes 'eventbrite' in the domain.""" eventbrite_url = self.cleaned_data.get("eventbrite_url", "") - if eventbrite_url and "eventbrite" not in urlparse(eventbrite_url).netloc: + if eventbrite_url and "eventbrite" not in urlparse(eventbrite_url).hostname: raise ValidationError("Must be an Eventbrite URL.") def clean(self): From 73f167f7fc22d429baa630da9a83d0e56e319573 Mon Sep 17 00:00:00 2001 From: Eli Chadwick Date: Thu, 23 Nov 2023 11:26:06 +0000 Subject: [PATCH 17/20] add admin warning if eventbrite url looks wrong --- amy/extrequests/templatetags/eventbrite.py | 10 +++ amy/extrequests/tests/test_template_tags.py | 78 ++++++++++++++++++- amy/extrequests/utils.py | 15 ++++ .../includes/trainingrequest_details.html | 10 ++- 4 files changed, 111 insertions(+), 2 deletions(-) diff --git a/amy/extrequests/templatetags/eventbrite.py b/amy/extrequests/templatetags/eventbrite.py index 4bd3b15fe..c124c7cad 100644 --- a/amy/extrequests/templatetags/eventbrite.py +++ b/amy/extrequests/templatetags/eventbrite.py @@ -1,3 +1,13 @@ +import re + from django import template +from extrequests.utils import EVENTBRITE_URL_PATTERN + register = template.Library() + + +@register.simple_tag +def url_matches_eventbrite_format(url: str) -> bool: + match = re.search(EVENTBRITE_URL_PATTERN, url) + return match is not None diff --git a/amy/extrequests/tests/test_template_tags.py b/amy/extrequests/tests/test_template_tags.py index e752ca540..33ee44db4 100644 --- a/amy/extrequests/tests/test_template_tags.py +++ b/amy/extrequests/tests/test_template_tags.py @@ -2,7 +2,8 @@ from django.test import TestCase -from amy.extrequests.templatetags.request_membership import ( +from extrequests.templatetags.eventbrite import url_matches_eventbrite_format +from extrequests.templatetags.request_membership import ( membership_active, membership_alert_type, ) @@ -98,3 +99,78 @@ def test_inactive(self): # Assert self.assertEqual(expected, result) + + +class TestUrlMatchesEventbriteFormat(TestCase): + def test_long_url(self): + # Arrange + url = "https://www.eventbrite.com/e/online-instructor-training-7-8-november-2023-tickets-711575811407?aff=oddtdtcreator" # noqa: line too long + + # Act + result = url_matches_eventbrite_format(url) + + # Assert + self.assertTrue(result) + + def test_short_url(self): + # Arrange + url = "www.eventbrite.com/e/711575811407" + + # Act + result = url_matches_eventbrite_format(url) + + # Assert + self.assertTrue(result) + + def test_localised_url__couk(self): + # Arrange + url = "https://www.eventbrite.co.uk/e/711575811407" + + # Act + result = url_matches_eventbrite_format(url) + + # Assert + self.assertTrue(result) + + def test_localised_url__fr(self): + # Arrange + url = "https://www.eventbrite.fr/711575811407" + + # Act + result = url_matches_eventbrite_format(url) + + # Assert + self.assertTrue(result) + + def test_admin_url(self): + """Admin url should fail - we don't expect trainees to provide this format""" + # Arrange + url = "https://www.eventbrite.com/myevent?eid=711575811407" + + # Act + result = url_matches_eventbrite_format(url) + + # Assert + self.assertFalse(result) + + def test_non_eventbrite_url(self): + """URLs outside the Eventbrite domain should fail.""" + # Arrange + url = "https://carpentries.org/instructor-training/123123123123/" + + # Act + result = url_matches_eventbrite_format(url) + + # Assert + self.assertFalse(result) + + def test_empty_string(self): + """Empty string should fail.""" + # Arrange + url = "" + + # Act + result = url_matches_eventbrite_format(url) + + # Assert + self.assertFalse(result) diff --git a/amy/extrequests/utils.py b/amy/extrequests/utils.py index d4e48deba..ee8355c77 100644 --- a/amy/extrequests/utils.py +++ b/amy/extrequests/utils.py @@ -12,6 +12,21 @@ # Eventbrite IDs are long strings of digits (~12 characters) EVENTBRITE_ID_PATTERN = re.compile(r"\d{10,}") +# regex to cover known forms of Eventbrite URL that trainees could provide +# https://www.eventbrite.com/e/event-name-123456789012 +# https://www.eventbrite.com/e/123456789012 +# plus a possible query at the end e.g. ?aff=oddtdtcreator +# and considering localised domains such as .co.uk and .fr +EVENTBRITE_URL_PATTERN = re.compile( + r"^(https?:\/\/)?" # optional https:// + r"www\.eventbrite\." + r"(com|co\.uk|[a-z]{2})" # possible domains - .com, .co.uk, 2-letter country domain + r"\/e\/" # /e/ should always be present at start of path + r"[a-z0-9\-]+" # optional event-name + r"\d{10,}" # event ID + r"($|\?)", # end of string or beginning of query (?) +) + class MemberCodeValidationError(ValidationError): pass diff --git a/amy/templates/includes/trainingrequest_details.html b/amy/templates/includes/trainingrequest_details.html index 8ded84c3f..c42406860 100644 --- a/amy/templates/includes/trainingrequest_details.html +++ b/amy/templates/includes/trainingrequest_details.html @@ -1,5 +1,6 @@ {% load state %} {% load utils %} +{% load eventbrite %} @@ -31,7 +32,14 @@ {% endif %} - + From 6b3a35380fd89b8fd8de4ea2c9fcac80b270318b Mon Sep 17 00:00:00 2001 From: Eli Chadwick Date: Thu, 23 Nov 2023 11:33:10 +0000 Subject: [PATCH 18/20] move eventbrite utils closer together --- amy/extrequests/utils.py | 41 ++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/amy/extrequests/utils.py b/amy/extrequests/utils.py index ee8355c77..6d08d0cab 100644 --- a/amy/extrequests/utils.py +++ b/amy/extrequests/utils.py @@ -9,24 +9,6 @@ # Utilities for validating member codes # ---------------------------------------- -# Eventbrite IDs are long strings of digits (~12 characters) -EVENTBRITE_ID_PATTERN = re.compile(r"\d{10,}") - -# regex to cover known forms of Eventbrite URL that trainees could provide -# https://www.eventbrite.com/e/event-name-123456789012 -# https://www.eventbrite.com/e/123456789012 -# plus a possible query at the end e.g. ?aff=oddtdtcreator -# and considering localised domains such as .co.uk and .fr -EVENTBRITE_URL_PATTERN = re.compile( - r"^(https?:\/\/)?" # optional https:// - r"www\.eventbrite\." - r"(com|co\.uk|[a-z]{2})" # possible domains - .com, .co.uk, 2-letter country domain - r"\/e\/" # /e/ should always be present at start of path - r"[a-z0-9\-]+" # optional event-name - r"\d{10,}" # event ID - r"($|\?)", # end of string or beginning of query (?) -) - class MemberCodeValidationError(ValidationError): pass @@ -191,6 +173,29 @@ def get_membership_warnings_after_match( return warnings +# ---------------------------------------- +# Utilities for Eventbrite URLs +# ---------------------------------------- + +# Eventbrite IDs are long strings of digits (~12 characters) +EVENTBRITE_ID_PATTERN = re.compile(r"\d{10,}") + +# regex to cover known forms of Eventbrite URL that trainees could provide +# https://www.eventbrite.com/e/event-name-123456789012 +# https://www.eventbrite.com/e/123456789012 +# plus a possible query at the end e.g. ?aff=oddtdtcreator +# and considering localised domains such as .co.uk and .fr +EVENTBRITE_URL_PATTERN = re.compile( + r"^(https?:\/\/)?" # optional https:// + r"www\.eventbrite\." + r"(com|co\.uk|[a-z]{2})" # possible domains - .com, .co.uk, 2-letter country domain + r"\/e\/" # /e/ should always be present at start of path + r"[a-z0-9\-]+" # optional event-name + r"\d{10,}" # event ID + r"($|\?)", # end of string or beginning of query (?) +) + + def get_eventbrite_id_from_url_or_return_input(url: str) -> str: """Given the URL for an Eventbrite event, returns that event's ID. If the ID can't be found, returns the input URL.""" From b6502fd6097755f32cf98e2df66e18fd9b7eea5e Mon Sep 17 00:00:00 2001 From: Eli Chadwick Date: Thu, 23 Nov 2023 11:35:21 +0000 Subject: [PATCH 19/20] Revert "Revert "never hide requests with invalid codes"" This reverts commit 083e771311ff6b7f3f90bf1559324f6026df7894. --- amy/extrequests/filters.py | 11 ++++++++++- amy/extrequests/tests/test_filters.py | 13 ++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/amy/extrequests/filters.py b/amy/extrequests/filters.py index e8d38a1c2..b49c8f086 100644 --- a/amy/extrequests/filters.py +++ b/amy/extrequests/filters.py @@ -74,7 +74,7 @@ def __init__(self, data=None, *args, **kwargs): invalid_member_code = django_filters.BooleanFilter( label="Member code marked as invalid", - field_name="member_code_override", + method="filter_member_code_override", widget=widgets.CheckboxInput, ) @@ -164,6 +164,15 @@ def filter_non_null_manual_score(self, queryset, name, manual_score): return queryset.filter(score_manual__isnull=False) return queryset + def filter_member_code_override( + self, queryset: QuerySet, name: str, only_overrides: bool + ) -> QuerySet: + """If checked, only show requests where the member code has been + marked as invalid. Otherwise, show all requests.""" + if only_overrides: + return queryset.filter(member_code_override=True) + return queryset + def filter_eventbrite_id( self, queryset: QuerySet, name: str, value: str ) -> QuerySet: diff --git a/amy/extrequests/tests/test_filters.py b/amy/extrequests/tests/test_filters.py index eb76464be..cc1c6e52c 100644 --- a/amy/extrequests/tests/test_filters.py +++ b/amy/extrequests/tests/test_filters.py @@ -276,7 +276,7 @@ def test_filter_nonnull_manual_score(self): # Assert self.assertQuerysetEqual(result, [self.request_blackwidow]) - def test_filter_invalid_member_code(self): + def test_filter_invalid_member_code__true(self): # Arrange filter_name = "invalid_member_code" value = True @@ -287,6 +287,17 @@ def test_filter_invalid_member_code(self): # Assert self.assertQuerysetEqual(result, [self.request_blackwidow]) + def test_filter_invalid_member_code__false(self): + # Arrange + filter_name = "invalid_member_code" + value = False + + # Act + result = self.filterset.filters[filter_name].filter(self.qs, value) + + # Assert + self.assertQuerysetEqual(result, TrainingRequest.objects.all()) + def test_filter_affiliation(self): # Arrange name = "affiliation" From d2457c9c83d9b39cca5f8bb2c2b6e4822e9a553c Mon Sep 17 00:00:00 2001 From: Eli Chadwick Date: Thu, 23 Nov 2023 11:46:34 +0000 Subject: [PATCH 20/20] fix typo --- amy/extrequests/tests/test_template_tags.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/amy/extrequests/tests/test_template_tags.py b/amy/extrequests/tests/test_template_tags.py index 33ee44db4..411b746ef 100644 --- a/amy/extrequests/tests/test_template_tags.py +++ b/amy/extrequests/tests/test_template_tags.py @@ -134,7 +134,7 @@ def test_localised_url__couk(self): def test_localised_url__fr(self): # Arrange - url = "https://www.eventbrite.fr/711575811407" + url = "https://www.eventbrite.fr/e/711575811407" # Act result = url_matches_eventbrite_format(url)
Submission date:{{ object.member_code_override|yesno }}
Eventbrite URL:{{ object.eventbrite_url|default:"—" }}
{{ object.eventbrite_url|default:"—" }} + {% url_matches_eventbrite_format object.eventbrite_url as url_format_valid %} + {% if object.eventbrite_url and not url_format_valid %} +
+ This URL doesn't match known Eventbrite URLs. Please use caution if copying this link. +
+ {% endif %} +
Personal name: {{ object.personal }}
Middle name: