From fddc39d3f09d2c2ad95453c6cd4a159a30546051 Mon Sep 17 00:00:00 2001
From: Christian Henriksen
Date: Wed, 4 Feb 2026 21:03:56 +0100
Subject: [PATCH] Add 'year' property for camp model.
Before we had to do 'camp.camp.lower.year' to get the year, now we can do 'camp.year'
---
src/camps/models.py | 5 +
src/camps/tests.py | 7 +
src/program/views.py | 2 +-
.../copy_tickets_from_camp_to_camp.py | 20 +-
src/tickets/views.py | 2 +-
src/tokens/templates/token_dashboard.html | 4 +-
src/utils/bootstrap/base.py | 189 ++++++++----------
7 files changed, 106 insertions(+), 123 deletions(-)
diff --git a/src/camps/models.py b/src/camps/models.py
index d92a2417e..2e5a67662 100644
--- a/src/camps/models.py
+++ b/src/camps/models.py
@@ -322,6 +322,11 @@ def teardown_days(self):
# convenience properties to access Camp-related stuff easily from the Camp object
+ @property
+ def year(self) -> int:
+ """Return the year of this camp."""
+ return self.camp.lower.year
+
@property
def event_types(self):
"""Return all event types with at least one event in this camp."""
diff --git a/src/camps/tests.py b/src/camps/tests.py
index 871bd05e7..9ed6370e1 100644
--- a/src/camps/tests.py
+++ b/src/camps/tests.py
@@ -213,3 +213,10 @@ def test_participant_count(self) -> None:
child_one_day.save()
assert self.camp.participant_count == 4
+
+ def test_year_of_camp(self) -> None:
+ """Test the property `year` return current year of camp."""
+ expected = self.camp.camp.lower.year
+
+ assert self.camp.year == expected
+
diff --git a/src/program/views.py b/src/program/views.py
index c0a1b827e..1323714a7 100644
--- a/src/program/views.py
+++ b/src/program/views.py
@@ -1085,7 +1085,7 @@ def get(self, *args, **kwargs):
E.version("BornHack Frab XML Generator v2.0"),
E.conference(
E.title(self.camp.title),
- E.acronym(str(self.camp.camp.lower.year)),
+ E.acronym(str(self.camp.year)),
E.start(self.camp.camp.lower.date().isoformat()),
E.end(self.camp.camp.upper.date().isoformat()),
E.days(len(self.camp.get_days("camp"))),
diff --git a/src/shop/management/commands/copy_tickets_from_camp_to_camp.py b/src/shop/management/commands/copy_tickets_from_camp_to_camp.py
index 27033c4be..9c04d74ba 100644
--- a/src/shop/management/commands/copy_tickets_from_camp_to_camp.py
+++ b/src/shop/management/commands/copy_tickets_from_camp_to_camp.py
@@ -2,14 +2,14 @@
import logging
-from django.core.management import call_command
from django.core.management.base import BaseCommand
from django.utils import timezone
from datetime import timedelta
from camps.models import Camp
from tickets.models import TicketType
-from shop.models import Product, SubProductRelation
+from shop.models import Product
+from shop.models import SubProductRelation
logger = logging.getLogger(f"bornhack.{__name__}")
@@ -56,16 +56,16 @@ def handle(self, *args, **options) -> None:
print(f"Created new TicketType {newtt}")
for product in tt.product_set.filter(sub_products__isnull=True):
newprod, created = Product.objects.get_or_create(
- name=product.name.replace(str(fromcamp.camp.lower.year), str(tocamp.camp.lower.year)),
+ name=product.name.replace(str(fromcamp.year), str(tocamp.year)),
ticket_type=newtt,
- slug=product.slug.replace(str(fromcamp.camp.lower.year), str(tocamp.camp.lower.year)),
+ slug=product.slug.replace(str(fromcamp.year), str(tocamp.year)),
defaults={
"price": product.price,
"category": product.category,
- "description": product.description.replace(str(fromcamp.camp.lower.year), str(tocamp.camp.lower.year)),
+ "description": product.description.replace(str(fromcamp.year), str(tocamp.year)),
"available_in": (timezone.now(), tocamp.camp.upper + timedelta(days=30)),
"cost": product.cost,
- "comment": product.comment.replace(str(fromcamp.camp.lower.year), str(tocamp.camp.lower.year)),
+ "comment": product.comment.replace(str(fromcamp.year), str(tocamp.year)),
}
)
if created:
@@ -77,15 +77,15 @@ def handle(self, *args, **options) -> None:
print(product)
# create bundle product
newprod, created = Product.objects.get_or_create(
- name=product.name.replace(str(fromcamp.camp.lower.year), str(tocamp.camp.lower.year)),
- slug=product.slug.replace(str(fromcamp.camp.lower.year), str(tocamp.camp.lower.year)),
+ name=product.name.replace(str(fromcamp.year), str(tocamp.year)),
+ slug=product.slug.replace(str(fromcamp.year), str(tocamp.year)),
defaults={
"price": product.price,
"category": product.category,
- "description": product.description.replace(str(fromcamp.camp.lower.year), str(tocamp.camp.lower.year)),
+ "description": product.description.replace(str(fromcamp.year), str(tocamp.year)),
"available_in": (timezone.now(), tocamp.camp.upper + timedelta(days=30)),
"cost": product.cost,
- "comment": product.comment.replace(str(fromcamp.camp.lower.year), str(tocamp.camp.lower.year)),
+ "comment": product.comment.replace(str(fromcamp.year), str(tocamp.year)),
}
)
for spr in product.sub_product_relations.all():
diff --git a/src/tickets/views.py b/src/tickets/views.py
index 2df2ecc9a..99fb53a8c 100644
--- a/src/tickets/views.py
+++ b/src/tickets/views.py
@@ -65,7 +65,7 @@ def get(self, request, *args, **kwargs):
ticket = self.get_object(*args, **kwargs)
response = HttpResponse(content_type="application/pdf")
response["Content-Disposition"] = (
- f'attachment; filename="BornHack_{ticket.ticket_type.camp.camp.lower.year}_{ticket.shortname}_ticket_{ticket.pk}.pdf"'
+ f'attachment; filename="BornHack_{ticket.ticket_type.camp.year}_{ticket.shortname}_ticket_{ticket.pk}.pdf"'
)
response.write(ticket.generate_pdf().getvalue())
return response
diff --git a/src/tokens/templates/token_dashboard.html b/src/tokens/templates/token_dashboard.html
index a08ed352b..d09dd455a 100644
--- a/src/tokens/templates/token_dashboard.html
+++ b/src/tokens/templates/token_dashboard.html
@@ -65,13 +65,13 @@ How to play?
Token examples:
- BornHack{{ camp.camp.lower.year }}
+ BornHack{{ camp.year }}
cm9sbGllczIwMjR5b3V3aW4K
Ly5caCRLKRHrpiF6SQwe9geUKAxSsLQE
Tokens are hidden or in plain sight physically or virtually on the BornHack venue, online and offline.
- Submit the tokens you find in the field below. You can start with this one: HelloTokenHunters{{ camp.camp.lower.year }}
+ Submit the tokens you find in the field below. You can start with this one: HelloTokenHunters{{ camp.year }}