diff --git a/backend/api/conferences/tests/test_query_conference.py b/backend/api/conferences/tests/test_query_conference.py index 04a2fb5c53..030d216028 100644 --- a/backend/api/conferences/tests/test_query_conference.py +++ b/backend/api/conferences/tests/test_query_conference.py @@ -19,6 +19,19 @@ def _query_conference(graphql_client, conference): return graphql_client.query(query, variables={"code": conference.code}) +def test_query_conference_hostname(graphql_client): + conference = ConferenceFactory(hostname="pycon.it") + + query = """query($code: String!) { + conference(code: $code) { + hostname + } + }""" + + result = graphql_client.query(query, variables={"code": conference.code}) + assert result["data"]["conference"]["hostname"] == "pycon.it" + + def test_query_conference_current_day(graphql_client): conference = ConferenceFactory() DayFactory(conference=conference, day=timezone.datetime(2020, 10, 10)) diff --git a/backend/api/conferences/types.py b/backend/api/conferences/types.py index 3d898734f6..c75d451ae6 100644 --- a/backend/api/conferences/types.py +++ b/backend/api/conferences/types.py @@ -154,6 +154,7 @@ class Conference: resolver=make_localized_resolver("introduction") ) code: str + hostname: str start: datetime end: datetime map: Map | None = strawberry.field(resolver=resolve_map) diff --git a/backend/conferences/admin/conference.py b/backend/conferences/admin/conference.py index 2d33891ed0..97f03ca148 100644 --- a/backend/conferences/admin/conference.py +++ b/backend/conferences/admin/conference.py @@ -132,6 +132,7 @@ class ConferenceAdmin( "organizer", "name", "code", + "hostname", "logo", "location", "introduction", diff --git a/backend/conferences/migrations/0058_conference_hostname.py b/backend/conferences/migrations/0058_conference_hostname.py new file mode 100644 index 0000000000..063eb0241f --- /dev/null +++ b/backend/conferences/migrations/0058_conference_hostname.py @@ -0,0 +1,62 @@ +# Generated by Django 5.1.4 on 2026-05-28 17:12 + +from django.db import migrations, models + + +def set_conference_hostnames(apps, schema_editor): + Conference = apps.get_model("conferences", "Conference") + + hostname_mapping = { + "pycon2026": "2026.pycon.it", + "pycon2025": "2025.pycon.it", + "pycon2024": "2024.pycon.it", + "pycon2023": "2023.pycon.it", + "pycon12": "2022.pycon.it", + "pycon11": "2020.pycon.it", + "testconf": "test.pycon.it", + } + + for conference in Conference.objects.all(): + if conference.code in hostname_mapping: + conference.hostname = hostname_mapping[conference.code] + conference.save(update_fields=["hostname"]) + + +def reverse_set_conference_hostnames(apps, schema_editor): + Conference = apps.get_model("conferences", "Conference") + Conference.objects.all().update(hostname="") + + +class Migration(migrations.Migration): + + dependencies = [ + ("conferences", "0057_add_grants_waiting_list_update_deadline_type"), + ] + + operations = [ + # Step 1: Add the field without unique constraint + migrations.AddField( + model_name="conference", + name="hostname", + field=models.CharField( + blank=True, default="", max_length=255, verbose_name="hostname" + ), + ), + # Step 2: Run data migration to set hostnames + migrations.RunPython( + set_conference_hostnames, + reverse_set_conference_hostnames, + ), + # Step 3: Add unique constraint + migrations.AlterField( + model_name="conference", + name="hostname", + field=models.CharField( + blank=True, + default="", + max_length=255, + unique=True, + verbose_name="hostname", + ), + ), + ] diff --git a/backend/conferences/models/conference.py b/backend/conferences/models/conference.py index 397724f190..07e64066b4 100644 --- a/backend/conferences/models/conference.py +++ b/backend/conferences/models/conference.py @@ -29,6 +29,9 @@ class Conference(GeoLocalizedModel, TimeFramedModel, TimeStampedModel): timezone = TimeZoneField() logo = models.ImageField(_("logo"), upload_to=get_upload_to, blank=True) location = models.TextField(_("location"), max_length=1024, blank=True) + hostname = models.CharField( + _("hostname"), max_length=255, blank=True, default="", unique=True + ) topics = models.ManyToManyField( "conferences.Topic", verbose_name=_("topics"), blank=True diff --git a/backend/conferences/tests/factories.py b/backend/conferences/tests/factories.py index 9946f9f50e..da73d2394b 100644 --- a/backend/conferences/tests/factories.py +++ b/backend/conferences/tests/factories.py @@ -26,6 +26,7 @@ class ConferenceFactory(DjangoModelFactory): organizer = factory.SubFactory(OrganizerFactory) name = LanguageFactory("name") code = factory.Sequence(lambda n: "code{}".format(n)) + hostname = factory.Sequence(lambda n: "conference{}.example.com".format(n)) introduction = LanguageFactory("sentence") start = factory.Faker("past_datetime", tzinfo=UTC)