Skip to content

Commit b0aa5e2

Browse files
fix: add validation to AssignTicketSystemPasswordMutation
- add some related tests - reduce the existing related tests' code duplication refs KK-1412
1 parent 6c2ae0f commit b0aa5e2

File tree

2 files changed

+274
-39
lines changed

2 files changed

+274
-39
lines changed

events/schema.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
from events.models import Enrolment, Event, EventGroup, Occurrence, TicketSystemPassword
3838
from events.ticket_service import check_ticket_validity
3939
from kukkuu.exceptions import (
40+
ApiUsageError,
4041
DataValidationError,
4142
EventAlreadyPublishedError,
4243
EventGroupAlreadyPublishedError,
@@ -824,6 +825,14 @@ def mutate_and_get_payload(cls, root, info, **kwargs):
824825
except (Event.DoesNotExist, Child.DoesNotExist) as e:
825826
raise ObjectDoesNotExistError(e)
826827

828+
if event.ticket_system == Event.INTERNAL:
829+
raise ApiUsageError(
830+
"Password can not be assigned to internal ticket system event"
831+
)
832+
833+
if reason := event.get_enrolment_denied_reason(child):
834+
raise ENROLMENT_DENIED_REASON_TO_GRAPHQL_ERROR[reason]
835+
827836
try:
828837
password = TicketSystemPassword.objects.assign(event=event, child=child)
829838
except NoFreePasswordsError as e:

events/tests/test_api.py

Lines changed: 265 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from parler.utils.context import switch_language
1616

1717
from children.factories import ChildWithGuardianFactory
18+
from children.models import Child
1819
from common.tests.utils import assert_match_error_code, assert_permission_denied
1920
from common.utils import get_global_id
2021
from events.factories import (
@@ -70,6 +71,7 @@
7071
)
7172
from events.ticket_service import check_ticket_validity
7273
from kukkuu.consts import (
74+
API_USAGE_ERROR,
7375
CHILD_ALREADY_JOINED_EVENT_ERROR,
7476
DATA_VALIDATION_ERROR,
7577
EVENT_ALREADY_PUBLISHED_ERROR,
@@ -93,6 +95,7 @@
9395
)
9496
from kukkuu.exceptions import EnrolmentReferenceIdDoesNotExist
9597
from kukkuu.views import SentryGraphQLView
98+
from projects.factories import ProjectFactory
9699
from projects.models import Project
97100
from subscriptions.factories import FreeSpotNotificationSubscriptionFactory
98101
from users.factories import GuardianFactory, UserFactory
@@ -2284,85 +2287,308 @@ def test_import_ticket_system_passwords_invalid_permissions(guardian_api_client)
22842287
assert_match_error_code(executed, PERMISSION_DENIED_ERROR)
22852288

22862289

2287-
def test_assign_ticket_system_password(snapshot, guardian_api_client):
2288-
event = EventFactory(ticket_system=Event.TICKETMASTER, published_at=now())
2290+
def _assign_ticket_system_password(client, event, child) -> dict:
2291+
variables = {
2292+
"input": {
2293+
"eventId": get_global_id(event),
2294+
"childId": get_global_id(child),
2295+
}
2296+
}
2297+
2298+
return client.execute(
2299+
ASSIGN_TICKET_SYSTEM_PASSWORD_MUTATION,
2300+
variables=variables,
2301+
)
2302+
2303+
2304+
def test_assign_ticket_system_password_success(guardian_api_client):
2305+
"""
2306+
Test that a free password can be assigned to a child.
2307+
"""
2308+
event = EventFactory(
2309+
name="Test event", ticket_system=Event.TICKETMASTER, published_at=now()
2310+
)
22892311
child = ChildWithGuardianFactory(
2290-
relationship__guardian__user=guardian_api_client.user.guardian.user
2312+
name="Test child",
2313+
relationship__guardian__user=guardian_api_client.user.guardian.user,
22912314
)
22922315
someone_elses_password = TicketSystemPasswordFactory( # noqa: F841
22932316
event=event, value="FATAL LEAK", assigned_at=now()
22942317
)
22952318
free_password = TicketSystemPasswordFactory(
2296-
event=event, child=None, value="the correct password"
2319+
event=event, child=None, value="The correct password"
22972320
)
22982321
another_free_password = TicketSystemPasswordFactory( # noqa: F841
2299-
event=event, child=None, value="wrong password"
2322+
event=event, child=None, value="Wrong password"
23002323
)
23012324

2302-
variables = {
2303-
"input": {
2304-
"eventId": get_global_id(event),
2305-
"childId": get_global_id(child),
2325+
executed = _assign_ticket_system_password(guardian_api_client, event, child)
2326+
2327+
assert executed == {
2328+
"data": {
2329+
"assignTicketSystemPassword": {
2330+
"child": {"name": "Test child"},
2331+
"event": {"name": "Test event"},
2332+
"password": "The correct password",
2333+
}
23062334
}
23072335
}
23082336

2309-
executed = guardian_api_client.execute(
2310-
ASSIGN_TICKET_SYSTEM_PASSWORD_MUTATION,
2311-
variables=variables,
2312-
)
2313-
2314-
snapshot.assert_match(executed)
23152337
assert child.ticket_system_passwords.get(event=event) == free_password
23162338

2317-
# second mutation should result in password already assigned error
2318-
executed = guardian_api_client.execute(
2319-
ASSIGN_TICKET_SYSTEM_PASSWORD_MUTATION,
2320-
variables=variables,
2339+
2340+
def test_assign_ticket_system_password_already_assigned(guardian_api_client):
2341+
"""
2342+
Test that a password can not be assigned to a child who already has it.
2343+
"""
2344+
event = EventFactory(ticket_system=Event.TICKETMASTER, published_at=now())
2345+
child = ChildWithGuardianFactory(
2346+
relationship__guardian__user=guardian_api_client.user.guardian.user
23212347
)
2348+
used_password = TicketSystemPasswordFactory(
2349+
event=event, child=child, value="Used password"
2350+
)
2351+
free_password = TicketSystemPasswordFactory(
2352+
event=event, child=None, value="Free password"
2353+
)
2354+
assert set(TicketSystemPassword.objects.all()) == {used_password, free_password}
2355+
2356+
executed = _assign_ticket_system_password(guardian_api_client, event, child)
23222357

23232358
assert_match_error_code(executed, TICKET_SYSTEM_PASSWORD_ALREADY_ASSIGNED_ERROR)
23242359

23252360

23262361
def test_assign_ticket_system_password_no_free_passwords(
23272362
guardian_api_client,
23282363
):
2364+
"""
2365+
Test that if there are no free passwords available, then a password can not be
2366+
assigned because of this.
2367+
"""
23292368
event = EventFactory(ticket_system=Event.TICKETMASTER, published_at=now())
23302369
child = ChildWithGuardianFactory(
23312370
relationship__guardian__user=guardian_api_client.user.guardian.user
23322371
)
2333-
someone_elses_password = TicketSystemPasswordFactory( # noqa: F841
2334-
event=event, value="FATAL LEAK", assigned_at=now()
2372+
TicketSystemPasswordFactory(
2373+
event=event, value="Someone else's password", assigned_at=now()
23352374
)
23362375

2337-
variables = {
2338-
"input": {"eventId": get_global_id(event), "childId": get_global_id(child)}
2339-
}
2376+
executed = _assign_ticket_system_password(guardian_api_client, event, child)
23402377

2341-
executed = guardian_api_client.execute(
2342-
ASSIGN_TICKET_SYSTEM_PASSWORD_MUTATION,
2343-
variables=variables,
2378+
assert_match_error_code(executed, NO_FREE_TICKET_SYSTEM_PASSWORDS_ERROR)
2379+
2380+
2381+
def test_assign_ticket_system_password_internal_event(guardian_api_client):
2382+
"""
2383+
Test that a password can not be assigned to an internal ticket system event.
2384+
"""
2385+
event = EventFactory(ticket_system=Event.INTERNAL, published_at=now())
2386+
child = ChildWithGuardianFactory(
2387+
relationship__guardian__user=guardian_api_client.user.guardian.user
23442388
)
23452389

2346-
assert_match_error_code(executed, NO_FREE_TICKET_SYSTEM_PASSWORDS_ERROR)
2390+
executed = _assign_ticket_system_password(guardian_api_client, event, child)
2391+
2392+
assert_match_error_code(executed, API_USAGE_ERROR)
2393+
assert executed["errors"][0]["message"] == (
2394+
"Password can not be assigned to internal ticket system event"
2395+
)
2396+
2397+
2398+
def test_assign_ticket_system_password_not_published_event(guardian_api_client):
2399+
"""
2400+
Test that event that has not been published is not visible to
2401+
AssignTicketSystemPassword mutation.
2402+
"""
2403+
event = EventFactory(ticket_system=Event.TICKETMASTER, published_at=None)
2404+
child = ChildWithGuardianFactory(
2405+
relationship__guardian__user=guardian_api_client.user.guardian.user
2406+
)
2407+
2408+
executed = _assign_ticket_system_password(guardian_api_client, event, child)
2409+
2410+
assert_match_error_code(executed, OBJECT_DOES_NOT_EXIST_ERROR)
2411+
2412+
2413+
def _create_data_for_ticket_system_password_only_externals_enrolment_limit_tests(
2414+
client, enrolment_limit, existing_enrolment_count
2415+
) -> tuple[Event, Child, TicketSystemPassword]:
2416+
"""
2417+
Create test data for testing the AssignTicketSystemPassword mutation
2418+
with only external ticket system events & existing ticket system passwords.
2419+
"""
2420+
project = ProjectFactory(enrolment_limit=enrolment_limit)
2421+
event = EventFactory(
2422+
name="Test event",
2423+
project=project,
2424+
ticket_system=Event.TICKETMASTER,
2425+
published_at=now(),
2426+
)
2427+
child = ChildWithGuardianFactory(
2428+
name="Test child",
2429+
project=project,
2430+
relationship__guardian__user=client.user.guardian.user,
2431+
)
2432+
TicketSystemPasswordFactory.create_batch(
2433+
size=existing_enrolment_count,
2434+
child=child,
2435+
event__project=project,
2436+
event__published_at=now(),
2437+
)
2438+
free_password = TicketSystemPasswordFactory(
2439+
event=event, child=None, value="Free password"
2440+
)
2441+
return event, child, free_password
2442+
2443+
2444+
@pytest.mark.parametrize(
2445+
"enrolment_limit, existing_enrolment_count",
2446+
[
2447+
(1, 0),
2448+
(2, 0),
2449+
(2, 1),
2450+
(3, 0),
2451+
(3, 1),
2452+
(3, 2),
2453+
(10, 1),
2454+
(10, 9),
2455+
(100, 99),
2456+
],
2457+
)
2458+
def test_assign_ticket_system_password_only_externals_enrolment_limit_not_full(
2459+
guardian_api_client, enrolment_limit, existing_enrolment_count
2460+
):
2461+
"""
2462+
Test that a free password can be assigned to a child when the yearly enrolment limit
2463+
has not been reached. Tests without internal event enrolments.
2464+
"""
2465+
event, child, free_password = (
2466+
_create_data_for_ticket_system_password_only_externals_enrolment_limit_tests(
2467+
guardian_api_client, enrolment_limit, existing_enrolment_count
2468+
)
2469+
)
2470+
assert child.ticket_system_passwords.count() == existing_enrolment_count
2471+
assert not Enrolment.objects.exists()
2472+
executed = _assign_ticket_system_password(guardian_api_client, event, child)
2473+
2474+
assert "errors" not in executed
2475+
assert child.ticket_system_passwords.count() == (existing_enrolment_count + 1)
2476+
assert child.ticket_system_passwords.get(event=event) == free_password
2477+
2478+
2479+
@pytest.mark.parametrize(
2480+
"enrolment_limit, existing_enrolment_count",
2481+
[
2482+
(1, 1),
2483+
(1, 2),
2484+
(2, 2),
2485+
(2, 3),
2486+
(3, 3),
2487+
(3, 4),
2488+
(10, 10),
2489+
(20, 30),
2490+
],
2491+
)
2492+
def test_assign_ticket_system_password_only_externals_enrolment_limit_full(
2493+
guardian_api_client,
2494+
enrolment_limit,
2495+
existing_enrolment_count,
2496+
):
2497+
"""
2498+
Test that a free password can not be assigned to a child when the yearly enrolment
2499+
limit has been reached. Tests without internal event enrolments.
2500+
"""
2501+
event, child, free_password = (
2502+
_create_data_for_ticket_system_password_only_externals_enrolment_limit_tests(
2503+
guardian_api_client, enrolment_limit, existing_enrolment_count
2504+
)
2505+
)
2506+
assert child.ticket_system_passwords.count() == existing_enrolment_count
2507+
assert not Enrolment.objects.exists()
2508+
executed = _assign_ticket_system_password(guardian_api_client, event, child)
2509+
2510+
assert_match_error_code(executed, INELIGIBLE_OCCURRENCE_ENROLMENT)
2511+
assert executed["errors"][0]["message"] == "Yearly enrolment limit has been reached"
2512+
assert child.ticket_system_passwords.count() == existing_enrolment_count
2513+
assert not child.ticket_system_passwords.filter(event=event).exists()
2514+
2515+
2516+
def test_assign_ticket_system_password_internal_and_external_enrolment_limit(
2517+
guardian_api_client,
2518+
):
2519+
"""
2520+
Test that a free password can not be assigned to a child when the yearly enrolment
2521+
limit is reached by the sum of both internal and external events.
2522+
"""
2523+
project = ProjectFactory(enrolment_limit=3)
2524+
external_event = EventFactory(
2525+
name="Test event",
2526+
project=project,
2527+
ticket_system=Event.TICKETMASTER,
2528+
published_at=now(),
2529+
)
2530+
another_external_event = EventFactory(
2531+
name="Second test event",
2532+
project=project,
2533+
ticket_system=Event.TICKETMASTER,
2534+
published_at=now(),
2535+
)
2536+
child = ChildWithGuardianFactory(
2537+
name="Test child",
2538+
project=project,
2539+
relationship__guardian__user=guardian_api_client.user.guardian.user,
2540+
)
2541+
TicketSystemPasswordFactory(
2542+
child=child,
2543+
event__project=project,
2544+
event__published_at=now(),
2545+
)
2546+
TicketSystemPasswordFactory(event=external_event, child=None, value="Free password")
2547+
internal_event = EventFactory(
2548+
project=project,
2549+
ticket_system=Event.INTERNAL,
2550+
published_at=now(),
2551+
)
2552+
EnrolmentFactory(
2553+
child=child,
2554+
occurrence__time=now() + timedelta(hours=1),
2555+
occurrence__event=internal_event,
2556+
)
2557+
assert child.enrolments.count() == 1
2558+
assert child.ticket_system_passwords.count() == 1
2559+
assert child.get_enrolment_count(now().year) == 2
2560+
2561+
# Yearly limit has not been reached yet, so should be successful
2562+
executed = _assign_ticket_system_password(
2563+
guardian_api_client, external_event, child
2564+
)
2565+
2566+
assert "errors" not in executed
2567+
assert child.ticket_system_passwords.count() == 2
2568+
assert child.get_enrolment_count(now().year) == 3
2569+
2570+
# Now the yearly limit has been reached, so this should fail
2571+
executed = _assign_ticket_system_password(
2572+
guardian_api_client, another_external_event, child
2573+
)
2574+
2575+
assert_match_error_code(executed, INELIGIBLE_OCCURRENCE_ENROLMENT)
2576+
assert executed["errors"][0]["message"] == "Yearly enrolment limit has been reached"
2577+
assert child.ticket_system_passwords.count() == 2
2578+
assert child.get_enrolment_count(now().year) == 3
23472579

23482580

23492581
def test_assign_ticket_system_password_not_own_child(guardian_api_client):
2582+
"""
2583+
Test that the user does not see someone else's child using
2584+
AssignTicketSystemPassword mutation, and can not assign a password to them.
2585+
"""
23502586
event = EventFactory(ticket_system=Event.TICKETMASTER, published_at=now())
23512587
another_child = ChildWithGuardianFactory()
23522588
some_free_password = TicketSystemPasswordFactory(event=event) # noqa: F841
23532589

2354-
variables = {
2355-
"input": {
2356-
"eventId": get_global_id(event),
2357-
"childId": get_global_id(another_child),
2358-
}
2359-
}
2360-
23612590
# try to assign a password to someone else's child
2362-
executed = guardian_api_client.execute(
2363-
ASSIGN_TICKET_SYSTEM_PASSWORD_MUTATION,
2364-
variables=variables,
2365-
)
2591+
executed = _assign_ticket_system_password(guardian_api_client, event, another_child)
23662592

23672593
assert_match_error_code(executed, OBJECT_DOES_NOT_EXIST_ERROR)
23682594
assert not another_child.ticket_system_passwords.filter(event=event).exists()

0 commit comments

Comments
 (0)