add event organizer merge tool
This commit is contained in:
@@ -0,0 +1,275 @@
|
||||
import pytest
|
||||
from django.contrib.auth.models import Permission
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.urls import reverse
|
||||
from wagtail.models import ReferenceIndex
|
||||
|
||||
from events.merge_organizers import CUSTOM_VALUE, merge_event_organizers
|
||||
from events.models import EventOrganizer, EventOrganizerLink, EventPage
|
||||
from tests.conftest import AssociationPageFactory, EventPageFactory
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def organizers(db):
|
||||
keeper = EventOrganizer.objects.create(name="Kulturutvalget", slug="kulturutvalget")
|
||||
goner = EventOrganizer.objects.create(name="KU", slug="ku")
|
||||
return keeper, goner
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def editor_client(client, django_user_model):
|
||||
user = django_user_model.objects.create_user(username="editor", password="pw")
|
||||
user.user_permissions.add(Permission.objects.get(codename="access_admin"))
|
||||
client.force_login(user)
|
||||
return client
|
||||
|
||||
|
||||
def test_merge_repoints_event_links_and_deletes_loser(event_index, organizers):
|
||||
keeper, goner = organizers
|
||||
event = EventPageFactory(parent=event_index)
|
||||
EventOrganizerLink.objects.create(event=event, organizer=goner)
|
||||
|
||||
merged = merge_event_organizers(keeper, goner)
|
||||
|
||||
assert merged.pk == keeper.pk
|
||||
assert not EventOrganizer.objects.filter(pk=goner.pk).exists()
|
||||
assert list(event.organizer_links.values_list("organizer_id", flat=True)) == [keeper.pk]
|
||||
|
||||
|
||||
def test_lowest_pk_survives_regardless_of_argument_order(organizers):
|
||||
keeper, goner = organizers
|
||||
|
||||
merged = merge_event_organizers(goner, keeper)
|
||||
|
||||
assert merged.pk == keeper.pk
|
||||
assert not EventOrganizer.objects.filter(pk=goner.pk).exists()
|
||||
|
||||
|
||||
def test_merge_applies_chosen_name_and_slug(organizers):
|
||||
keeper, goner = organizers
|
||||
|
||||
merged = merge_event_organizers(keeper, goner, name="KU", slug="ku")
|
||||
|
||||
assert merged.name == "KU"
|
||||
assert merged.slug == "ku"
|
||||
|
||||
|
||||
def test_merge_keeps_survivor_name_and_slug_by_default(organizers):
|
||||
keeper, goner = organizers
|
||||
|
||||
merged = merge_event_organizers(keeper, goner)
|
||||
|
||||
assert merged.name == "Kulturutvalget"
|
||||
assert merged.slug == "kulturutvalget"
|
||||
|
||||
|
||||
def test_merge_collapses_duplicate_links_on_same_event(event_index, organizers):
|
||||
keeper, goner = organizers
|
||||
event = EventPageFactory(parent=event_index)
|
||||
EventOrganizerLink.objects.create(event=event, organizer=keeper)
|
||||
EventOrganizerLink.objects.create(event=event, organizer=goner)
|
||||
|
||||
merge_event_organizers(keeper, goner)
|
||||
|
||||
assert list(event.organizer_links.values_list("organizer_id", flat=True)) == [keeper.pk]
|
||||
|
||||
|
||||
def test_merge_fills_blank_fields_from_loser(association_index, organizers):
|
||||
keeper, goner = organizers
|
||||
association = AssociationPageFactory(parent=association_index)
|
||||
goner.association = association
|
||||
goner.external_url = "https://example.com"
|
||||
goner.save()
|
||||
|
||||
merged = merge_event_organizers(keeper, goner)
|
||||
|
||||
assert merged.association_id == association.pk
|
||||
assert merged.external_url == "https://example.com"
|
||||
|
||||
|
||||
def test_merge_keeps_survivor_fields_when_set(organizers):
|
||||
keeper, goner = organizers
|
||||
keeper.external_url = "https://keeper.example.com"
|
||||
keeper.save()
|
||||
goner.external_url = "https://goner.example.com"
|
||||
goner.save()
|
||||
|
||||
merged = merge_event_organizers(keeper, goner)
|
||||
|
||||
assert merged.external_url == "https://keeper.example.com"
|
||||
|
||||
|
||||
def test_merge_rewrites_event_page_revisions(event_index, organizers):
|
||||
keeper, goner = organizers
|
||||
event = EventPageFactory(parent=event_index)
|
||||
EventOrganizerLink.objects.create(event=event, organizer=goner)
|
||||
revision = EventPage.objects.get(pk=event.pk).save_revision()
|
||||
assert [link["organizer"] for link in revision.content["organizer_links"]] == [goner.pk]
|
||||
|
||||
merge_event_organizers(keeper, goner)
|
||||
|
||||
revision.refresh_from_db()
|
||||
assert [link["organizer"] for link in revision.content["organizer_links"]] == [keeper.pk]
|
||||
|
||||
|
||||
def test_merge_dedupes_organizers_within_revisions(event_index, organizers):
|
||||
keeper, goner = organizers
|
||||
event = EventPageFactory(parent=event_index)
|
||||
EventOrganizerLink.objects.create(event=event, organizer=keeper)
|
||||
EventOrganizerLink.objects.create(event=event, organizer=goner)
|
||||
revision = EventPage.objects.get(pk=event.pk).save_revision()
|
||||
|
||||
merge_event_organizers(keeper, goner)
|
||||
|
||||
revision.refresh_from_db()
|
||||
assert [link["organizer"] for link in revision.content["organizer_links"]] == [keeper.pk]
|
||||
|
||||
|
||||
def test_merge_updates_reference_index(event_index, organizers):
|
||||
keeper, goner = organizers
|
||||
event = EventPageFactory(parent=event_index)
|
||||
EventOrganizerLink.objects.create(event=event, organizer=goner)
|
||||
ReferenceIndex.create_or_update_for_object(EventPage.objects.get(pk=event.pk))
|
||||
organizer_ct = ContentType.objects.get_for_model(EventOrganizer)
|
||||
assert ReferenceIndex.objects.filter(
|
||||
to_content_type=organizer_ct, to_object_id=str(goner.pk)
|
||||
).exists()
|
||||
|
||||
merge_event_organizers(keeper, goner)
|
||||
|
||||
assert not ReferenceIndex.objects.filter(
|
||||
to_content_type=organizer_ct, to_object_id=str(goner.pk)
|
||||
).exists()
|
||||
assert ReferenceIndex.objects.filter(
|
||||
to_content_type=organizer_ct, to_object_id=str(keeper.pk)
|
||||
).exists()
|
||||
|
||||
|
||||
def test_merge_refuses_same_organizer(organizers):
|
||||
keeper, _ = organizers
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
merge_event_organizers(keeper, keeper)
|
||||
|
||||
|
||||
def test_merge_views_require_superuser(editor_client, organizers):
|
||||
keeper, goner = organizers
|
||||
confirm_url = reverse("events_merge_organizers_confirm")
|
||||
urls = [
|
||||
reverse("events_merge_organizers"),
|
||||
f"{confirm_url}?organizer_a={keeper.pk}&organizer_b={goner.pk}",
|
||||
]
|
||||
|
||||
for url in urls:
|
||||
response = editor_client.get(url)
|
||||
assert response.status_code == 302
|
||||
assert response.url == reverse("wagtailadmin_home")
|
||||
assert EventOrganizer.objects.filter(pk=goner.pk).exists()
|
||||
|
||||
|
||||
def test_select_view_redirects_to_confirm(admin_client, organizers):
|
||||
keeper, goner = organizers
|
||||
|
||||
response = admin_client.post(
|
||||
reverse("events_merge_organizers"),
|
||||
{"organizer_a": keeper.pk, "organizer_b": goner.pk},
|
||||
)
|
||||
|
||||
assert response.status_code == 302
|
||||
confirm_url = reverse("events_merge_organizers_confirm")
|
||||
assert response.url == f"{confirm_url}?organizer_a={keeper.pk}&organizer_b={goner.pk}"
|
||||
|
||||
|
||||
def test_select_view_rejects_same_organizer_twice(admin_client, organizers):
|
||||
keeper, _ = organizers
|
||||
|
||||
response = admin_client.post(
|
||||
reverse("events_merge_organizers"),
|
||||
{"organizer_a": keeper.pk, "organizer_b": keeper.pk},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert "Pick two different organizers." in response.content.decode()
|
||||
|
||||
|
||||
def test_confirm_view_shows_both_organizers(admin_client, organizers):
|
||||
keeper, goner = organizers
|
||||
confirm_url = reverse("events_merge_organizers_confirm")
|
||||
|
||||
response = admin_client.get(f"{confirm_url}?organizer_a={goner.pk}&organizer_b={keeper.pk}")
|
||||
|
||||
content = response.content.decode()
|
||||
assert response.status_code == 200
|
||||
assert "Kulturutvalget" in content
|
||||
assert "KU" in content
|
||||
|
||||
|
||||
def test_confirm_view_rejects_missing_or_equal_organizers(admin_client, organizers):
|
||||
keeper, _ = organizers
|
||||
confirm_url = reverse("events_merge_organizers_confirm")
|
||||
queries = [
|
||||
"",
|
||||
f"?organizer_a={keeper.pk}&organizer_b={keeper.pk}",
|
||||
f"?organizer_a=abc&organizer_b={keeper.pk}",
|
||||
f"?organizer_a={keeper.pk}&organizer_b=999999",
|
||||
]
|
||||
|
||||
for query in queries:
|
||||
response = admin_client.get(confirm_url + query)
|
||||
assert response.status_code == 302
|
||||
assert response.url == reverse("events_merge_organizers")
|
||||
|
||||
|
||||
def test_confirm_view_merges_with_picked_values(admin_client, event_index, organizers):
|
||||
keeper, goner = organizers
|
||||
event = EventPageFactory(parent=event_index)
|
||||
EventOrganizerLink.objects.create(event=event, organizer=goner)
|
||||
confirm_url = reverse("events_merge_organizers_confirm")
|
||||
|
||||
response = admin_client.post(
|
||||
f"{confirm_url}?organizer_a={keeper.pk}&organizer_b={goner.pk}",
|
||||
{"name": goner.name, "name_custom": "", "slug": goner.slug, "slug_custom": ""},
|
||||
)
|
||||
|
||||
assert response.status_code == 302
|
||||
assert response.url == reverse("wagtailsnippets_events_eventorganizer:list")
|
||||
keeper.refresh_from_db()
|
||||
assert keeper.name == "KU"
|
||||
assert keeper.slug == "ku"
|
||||
assert not EventOrganizer.objects.filter(pk=goner.pk).exists()
|
||||
assert list(event.organizer_links.values_list("organizer_id", flat=True)) == [keeper.pk]
|
||||
|
||||
|
||||
def test_confirm_view_merges_with_custom_values(admin_client, organizers):
|
||||
keeper, goner = organizers
|
||||
confirm_url = reverse("events_merge_organizers_confirm")
|
||||
|
||||
response = admin_client.post(
|
||||
f"{confirm_url}?organizer_a={keeper.pk}&organizer_b={goner.pk}",
|
||||
{
|
||||
"name": CUSTOM_VALUE,
|
||||
"name_custom": "Kulturutvalget (KU)",
|
||||
"slug": CUSTOM_VALUE,
|
||||
"slug_custom": "Kulturutvalget KU",
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 302
|
||||
keeper.refresh_from_db()
|
||||
assert keeper.name == "Kulturutvalget (KU)"
|
||||
assert keeper.slug == "kulturutvalget-ku"
|
||||
|
||||
|
||||
def test_confirm_view_requires_custom_value_when_picked(admin_client, organizers):
|
||||
keeper, goner = organizers
|
||||
confirm_url = reverse("events_merge_organizers_confirm")
|
||||
|
||||
response = admin_client.post(
|
||||
f"{confirm_url}?organizer_a={keeper.pk}&organizer_b={goner.pk}",
|
||||
{"name": CUSTOM_VALUE, "name_custom": "", "slug": keeper.slug, "slug_custom": ""},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert EventOrganizer.objects.filter(pk=goner.pk).exists()
|
||||
Reference in New Issue
Block a user