diff --git a/kompassi/events/finncon2026/__init__.py b/kompassi/events/finncon2026/__init__.py new file mode 100755 index 000000000..e69de29bb diff --git a/kompassi/events/finncon2026/forms.py b/kompassi/events/finncon2026/forms.py new file mode 100755 index 000000000..3ac0c1592 --- /dev/null +++ b/kompassi/events/finncon2026/forms.py @@ -0,0 +1,113 @@ +from crispy_forms.layout import Fieldset, Layout +from django import forms + +from kompassi.core.utils import horizontal_form_helper +from kompassi.labour.forms import AlternativeFormMixin +from kompassi.labour.models import JobCategory, Signup + +from .models import SignupExtra + + +class SignupExtraForm(forms.ModelForm): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.helper = horizontal_form_helper() + self.helper.form_tag = False + self.helper.layout = Layout( + "shift_type", + "total_work", + Fieldset( + "Lisätiedot", + "dead_dog", + "ika", + "shirt_size", + "color_wish", + "special_diet", + "special_diet_other", + "prior_experience", + "language_skills", + "free_text", + ), + ) + + class Meta: + model = SignupExtra + fields = ( + "ika", + "shirt_size", + "color_wish", + "dead_dog", + "shift_type", + "total_work", + "special_diet", + "special_diet_other", + "prior_experience", + "language_skills", + "free_text", + ) + widgets = dict( + special_diet=forms.CheckboxSelectMultiple, + ) + + +class OrganizerSignupForm(forms.ModelForm, AlternativeFormMixin): + def __init__(self, *args, **kwargs): + kwargs.pop("event") + kwargs.pop("admin") + super().__init__(*args, **kwargs) + self.helper = horizontal_form_helper() + self.helper.form_tag = False + self.helper.layout = Layout( + Fieldset( + "Tehtävän tiedot", + "job_title", + ), + ) + self.fields["job_title"].help_text = "Mikä on tehtäväsi coniteassa? Printataan badgeen." + + class Meta: + model = Signup + fields = ("job_title",) + widgets = dict( + job_categories=forms.CheckboxSelectMultiple, + ) + + def get_excluded_m2m_field_defaults(self): + return dict(job_categories=JobCategory.objects.filter(event__slug="finncon2026", name="Conitea")) + + +class OrganizerSignupExtraForm(forms.ModelForm, AlternativeFormMixin): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.helper = horizontal_form_helper() + self.helper.form_tag = False + self.helper.layout = Layout( + Fieldset( + "Lisätiedot", + "shirt_size", + "special_diet", + "special_diet_other", + ), + ) + + class Meta: + model = SignupExtra + fields = ( + "shirt_size", + "special_diet", + "special_diet_other", + ) + widgets = dict( + special_diet=forms.CheckboxSelectMultiple, + ) + + def get_excluded_field_defaults(self): + return dict( + shift_type="yli4h", + total_work="yli8h", + prior_experience="", + free_text="Syötetty käyttäen coniitin ilmoittautumislomaketta", + ) + + def get_excluded_m2m_field_defaults(self): + return dict() diff --git a/kompassi/events/finncon2026/management/__init__.py b/kompassi/events/finncon2026/management/__init__.py new file mode 100755 index 000000000..e69de29bb diff --git a/kompassi/events/finncon2026/management/commands/__init__.py b/kompassi/events/finncon2026/management/commands/__init__.py new file mode 100755 index 000000000..e69de29bb diff --git a/kompassi/events/finncon2026/management/commands/setup_finncon2026.py b/kompassi/events/finncon2026/management/commands/setup_finncon2026.py new file mode 100755 index 000000000..9872c6f4a --- /dev/null +++ b/kompassi/events/finncon2026/management/commands/setup_finncon2026.py @@ -0,0 +1,283 @@ +import logging +from datetime import datetime, timedelta + +from dateutil.tz import tzlocal +from django.conf import settings +from django.core.management.base import BaseCommand +from django.utils.timezone import now + +from kompassi.core.models import Event + +logger = logging.getLogger(__name__) + + +class Setup: + def setup(self, test=False): + self.test = test + self.tz = tzlocal() + + self.setup_core() # Event info + + self.setup_labour() # Volunteer init // Form setup + self.setup_intra() # Background admin + + self.setup_program_v2() # Program database + + def setup_core(self): + from kompassi.core.models import Organization, Venue + + self.venue, _ = Venue.objects.get_or_create( + name="Turun yliopisto", + defaults=dict( + name_inessive="Turun yliopistolla", + ), + ) + + self.organization, _ = Organization.objects.get_or_create( + slug="Finncon-yhdistys ry", + defaults=dict( + name="Finncon-yhdistys ry", + homepage_url="http://www.finncon.org/", + ), + ) + + self.event, _ = Event.objects.get_or_create( + slug="finncon2026", + defaults=dict( + name="Finncon 2026", + name_genitive="Finncon 2026 -tapahtuman", + name_illative="Finncon 2026 -tapahtumaan", + name_inessive="Finncon 2026 -tapahtumassa", + homepage_url="http://2026.finncon.org", + organization=self.organization, + start_time=datetime(2026, 7, 10, 10, 0, tzinfo=self.tz), + end_time=datetime(2026, 7, 12, 18, 0, tzinfo=self.tz), + venue=self.venue, + ), + ) + + def setup_labour(self): + from django.contrib.contenttypes.models import ContentType + + from kompassi.labour.models import ( + AlternativeSignupForm, + JobCategory, + LabourEventMeta, + PersonnelClass, + Qualification, + ) + + from ...models import SignupExtra, SpecialDiet + + (labour_admin_group,) = LabourEventMeta.get_or_create_groups(self.event, ["admins"]) + content_type = ContentType.objects.get_for_model(SignupExtra) + + labour_event_meta_defaults = dict( + signup_extra_content_type=content_type, + work_begins=self.event.start_time.replace(hour=8), # Starts at 8: + work_ends=self.event.start_time.replace(hour=22), # Ends at 22: + registration_opens=datetime(2026, 2, 10, 0, 0, tzinfo=self.tz), + registration_closes=datetime(2026, 6, 20, 0, 0, tzinfo=self.tz), # arbitary + admin_group=labour_admin_group, + contact_email="Finnconin työvoimavastaava ", + ) + + if self.test: + t = now() + labour_event_meta_defaults.update( + registration_opens=t - timedelta(days=60), + registration_closes=t + timedelta(days=60), + ) + + labour_event_meta, unused = LabourEventMeta.objects.get_or_create( + event=self.event, + defaults=labour_event_meta_defaults, + ) + + for diet_name in ["Gluteeniton", "Laktoositon", "Maidoton", "Vegaaninen", "Lakto-ovo-vegetaristinen"]: + SpecialDiet.objects.get_or_create(name=diet_name) + + ## organizers -- Responsible PersonnelClass + organizers_personnel_class, created = PersonnelClass.objects.get_or_create( + event=self.event, + slug="vastaava", + defaults=dict( + name="Vastaavat", + app_label="labour", + priority=10, + ), + ) + + ## Volunteer category + volunteer_pc, _ = PersonnelClass.objects.get_or_create( + event=self.event, + slug="vapaaehtoinen", + defaults=dict( + name="Vapaaehtoinen", + app_label="labour", + priority=30, + ), + ) + + ## Basic volunteer code + # voluntary_gategory, v_created = JobCategory.objects.update_or_create( + # event=self.event, + # slug="vapaaehtoinen", + # defaults=dict( + # name="Vänkäri (Vapaaehtoinen)", + # description="Tapahtuman vapaaehtoistehtävät eri osa-alueilla.", + # public=True, + # ), + # ) + # if v_created: + # voluntary_gategory.personnel_classes.set([volunteer_pc]) + + for slug, name, description in [ + ( + "vankari", + "Yleisvänkäri", + "Valmiina auttamaan siellä, missä tarvitaan. Yleisvänkärille hyviä ominaisuuksia ovat esim. oma-aloitteisuus. Yleisvänkäreitä sijoitetaan tapahtuman aikana eri puolille conia ja toiveita oman sijoittumisen suhteen saa esittää. Yleisvänkärille voi tulla myös päivystysvuoro Vänkäriluolassa, jolloin siellä huolehditaan samalla tarjoilujen ylläpidosta ja tilan siisteydestä, sekä lähdetään tarvittaessa sinne missä apua kaivataan.", + ), + ( + "vankarigreen", + "Taukotilavänkäri", + "Löytyykö sinulta hygieniapassi, ruokapuolen osaamista tai intoa oppia näitä taitoja? Haluatko olla varmistamassa, että henkilökunta pysyy virkeänä ja hyvin ravittuna con-päivän ajan? Hae osaksi taukotilatiimiä, joka huolehtii tapahtuman aikana Greenroomin, Vänkäriluolan ja näytteilleasetajien taukopaikan kahvi- ja välipalatatjoiluista, sekä näiden tilojen siisteydestä, kasauksesta ja purusta. Hygieniapassi ei ole pakollinen, mutta yleinen osaaminen ymmärrys elintarviketurvallisuudesta ja esimerkiksi hyvästä käsihygieniasta on. Muita hyviä ominaisuuksia tehtävään ovat omatoimisuus, järjestelmällisyys ja toimeliaisuus, sekä sosiaaliset taidot vuorovaikutettaessa niin taukotilaan levähtämään tulevan henkilökunnan kuin oman tiiminkin kanssa.", + ), + ( + "vankariinfo", + "Infovänkäri", + "Omaatko hyvät vuorovaikutustaidot ja “ellen tiedä niin ei hätää, minä selvitän!” -asenteen? Hae osaksi Finnconin tuikitärkeää infotiimiä huolehtimaan, että niin kävijät kuin henkilökuntakin pysyvät informoituina ja löytävät oikeaan aikaan tiensä perille. Info kokoaa myös sinne tuodut löytötavarat ja luovuttaa ne kyselijöille tavaran tuntomerkkejä vastaan.", + ), + ( + "vankarinarikka", + "Narikkavänkäri", + "Narikassa autat varmistamaan, että kävijöiden isommat kantamukset pysyvät turvassa tapahtuman ajan. Selkeä tehtävä, jossa pärjää omatessaan hyvät vuorovaikutustaidot, sekä ripauksen käytännöllistä loogisuutta.", + ), + ( + "vankaripurku", + "Purku-/rakennusvänkäri", + "Haluatko nauttia itse tapahtumasta rauhassa ja antaa työpanoksesi ennen sen alkua ja/tai tapahtuman päätyttyä? Tule osaksi kasaus- ja purkutiimiä! Hommiin sisältyy monenmoista roudailua, joten kohtuullinen fyysinen kunto ja ergonomiset työtavat ovat tässä tehtävässä paikallaan.", + ), + ( + "vankariohjelma", + "Ohjelmavänkäri", + "Haluaisitko toimia ohjelmapitäjien apuna luentosalissa tai työpajassa? Tehtävässä hyödyksi ovat avulias asenne(jos esimerkiksi pöytiä tai tuoleja pitää järjestää uudelleen tai yleisön kysyjälle viedä mikrofoni), salivänkärillä tekninen osaaminen. Pajavänkäreillä myös käsityöharrastuneisuus voi olla eduksi työpajojen vetäjiä autettaessa.", + ), + ( + "tiiminvetaja", + "Tiiminvetäjä", + "Finncon on iso tapahtuma ja vapaaehtoisia yleensä paljon. Tehtävien jaon helpottamiseksi haussa on myös tiiminvetäjiä toimimaan oman vastuualueensa vänkäreiden tukena tapahtuman aikana yhteistyössä työvoimavastaavan kanssa. Tehtävässä keskeisiä taitoja ovat hyvät vuorovaikutustaidot ja ongelmaratkaisukyky, järjestelmällisyys, aktiivinen ote hommiin ja itsenäinen päätöksentekokyky.", + ), + ]: + jc, created = JobCategory.objects.update_or_create( + event=self.event, + slug=slug, + defaults=dict( + name=name, + description=description, + public=True, + ), + ) + if created: + jc.personnel_classes.set([volunteer_pc]) + + ## Finncon 2026 working group JobCategory + conitea_job_category, created = JobCategory.objects.update_or_create( + event=self.event, + slug="conitea", + defaults=dict( + name="Finncon 2026 conitea", + description="Tapahtuman suunnittelusta ja valmistelusta vastaavan järjestelytyöryhmän jäsen", + public=False, + ), + ) + + if created: + conitea_job_category.personnel_classes.set([organizers_personnel_class]) + + ## "Standard" magic code to initialize the entry ## Needs a older iteration (as most events do inherit from previous) + # for jc_name, qualification_name in [ + # ("Järjestyksenvalvoja", "JV-kortti"), + # ]: + # JobCategory.objects.get(event=self.event, name=jc_name) + # Qualification.objects.get(name=qualification_name) + + valvoja, j_created = JobCategory.objects.update_or_create( + event=self.event, + slug="valvoja", + defaults=dict( + name="Järjestyksenvalvoja", + description='JV-kortti taskussa? Tehtävässä vaaditaan hyviä vuorovaikutustaitoja ja tilannetajua, sekä rauhallisen jämäkkää otetta. Jos et tällä hetkellä omista JV-korttia ja olet sen suorittamassa sen koulutuksen ennen tapahtumaa, mainitse asiasta "Vapaa alue" tekstikentässä!', + public=True, + ), + ) + + if j_created: + valvoja.personnel_classes.set([volunteer_pc]) + qual = Qualification.objects.get(name="JV-kortti") + valvoja.required_qualifications.set([qual]) + + AlternativeSignupForm.objects.get_or_create( + event=self.event, + slug="conitea", + defaults=dict( + title="Conitean ilmoittautumislomake", + signup_form_class_path="events.finncon2026.forms:OrganizerSignupForm", + signup_extra_form_class_path="events.finncon2026.forms:OrganizerSignupExtraForm", + active_from=now(), + active_until=self.event.start_time, + ), + ) + + labour_event_meta.create_groups() ## Must be called + + def setup_intra(self): + from kompassi.intra.models import IntraEventMeta + + (admin_group,) = IntraEventMeta.get_or_create_groups(self.event, ["admins"]) + organizer_group = self.event.labour_event_meta.get_group("vastaava") + IntraEventMeta.objects.update_or_create( + event=self.event, + defaults=dict( + admin_group=admin_group, + organizer_group=organizer_group, + ), + ) + + def setup_program_v2(self): + from kompassi.involvement.models.registry import Registry + from kompassi.program_v2.models.meta import ProgramV2EventMeta + + ## Volunteer registry ### Fairly certain I have actually done this wrong and it does nothing + registry, _created = Registry.objects.get_or_create( + scope=self.organization.scope, + slug="volunteers", + defaults=dict( + title_fi="Finncon 2026 vapaaehtoisrekisteri", + title_en="Volunteers of Finncon2026", + ), + ) + + # Need to do something to make the program just be a link until/unless something is added + (admin_group,) = ProgramV2EventMeta.get_or_create_groups(self.event, ["admins"]) + meta, _ = ProgramV2EventMeta.objects.update_or_create( + event=self.event, + defaults=dict( + admin_group=admin_group, + guide_v2_embedded_url="https://2026.finncon.org/ohjelma/", + contact_email="Finncon 2026 ohjelmatiimi ", + default_registry=Registry.objects.get( + scope=self.event.organization.scope, + slug="volunteers", + ), + ), + ) + meta.ensure() + + +class Command(BaseCommand): + args = "" + help = "Setup finncon2026 specific stuff" + + def handle(self, *args, **opts): + Setup().setup(test=settings.DEBUG) diff --git a/kompassi/events/finncon2026/migrations/0001_initial.py b/kompassi/events/finncon2026/migrations/0001_initial.py new file mode 100755 index 000000000..1e85c09d7 --- /dev/null +++ b/kompassi/events/finncon2026/migrations/0001_initial.py @@ -0,0 +1,146 @@ +# Generated by Django 6.0.2 on 2026-03-22 23:45 + +import django.db.models.deletion +from django.db import migrations, models + +import kompassi.labour.models.signup_extras + + +class Migration(migrations.Migration): + initial = True + + dependencies = [ + ("core", "0043_emailverificationtoken_language_and_more"), + ] + + operations = [ + migrations.CreateModel( + name="SpecialDiet", + fields=[ + ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("name", models.CharField(max_length=63)), + ], + ), + migrations.CreateModel( + name="SignupExtra", + fields=[ + ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("is_active", models.BooleanField(default=True)), + ( + "shift_type", + models.CharField( + choices=[ + ("2h", "2 tunnin vuoroja"), + ("4h", "4 tunnin vuoroja"), + ("yli4h", "Yli 4 tunnin vuoroja"), + ], + help_text="Haluatko tehdä yhden pitkän työvuoron vaiko monta lyhyempää vuoroa?", + max_length=15, + verbose_name="Toivottu työvuoron pituus", + ), + ), + ( + "total_work", + models.CharField( + choices=[("4h", "4–8 tuntia"), ("8h", "8 tuntia"), ("yli8h", "Yli 8 tuntia")], + help_text="Kuinka paljon haluat tehdä töitä yhteensä tapahtuman aikana?", + max_length=15, + verbose_name="Toivottu kokonaistyömäärä", + ), + ), + ( + "shirt_size", + models.CharField( + choices=[ + ("NO_SHIRT", "Ei paitaa"), + ("XS", "XS Unisex"), + ("S", "S Unisex"), + ("M", "M Unisex"), + ("L", "L Unisex"), + ("XL", "XL Unisex"), + ("XXL", "XXL Unisex"), + ("3XL", "3XL Unisex"), + ("4XL", "4XL Unisex"), + ("5XL", "5XL Unisex"), + ("LF_XS", "XS Ladyfit"), + ("LF_S", "S Ladyfit"), + ("LF_M", "M Ladyfit"), + ("LF_L", "L Ladyfit"), + ("LF_XL", "XL Ladyfit"), + ("LF_2XL", "2XL Ladyfit"), + ("LF_3XL", "3XL Ladyfit"), + ], + default="NO_SHIRT", + help_text="Ajoissa ilmoittautuneet vänkärit saavat maksuttoman työvoimapaidan, mikäli ilmoittavat työskentelevänsä vähintään 8 tuntia.", + max_length=8, + verbose_name="Paidan koko", + ), + ), + ( + "dead_dog", + models.BooleanField( + default=False, + help_text="Dead dogit ovat heti tapahtuman jälkeen järjestettävät kestit kaikille täysikäisille työvoimaan kuuluville. Ilmoittautuminen ei ole sitova.", + verbose_name="Osallistun dead dogeihin", + ), + ), + ( + "special_diet_other", + models.TextField( + blank=True, + help_text="Jos noudatat erikoisruokavaliota, jota ei ole yllä olevassa listassa, ilmoita se tässä. Tapahtuman järjestäjä pyrkii ottamaan erikoisruokavaliot huomioon, mutta kaikkia erikoisruokavalioita ei välttämättä pystytä järjestämään.", + verbose_name="Muu erikoisruokavalio", + ), + ), + ( + "prior_experience", + models.TextField( + blank=True, + help_text="Kerro tässä kentässä, jos sinulla on aiempaa kokemusta vastaavista tehtävistä tai muuta sellaista työkokemusta, josta arvioit olevan hyötyä hakemassasi tehtävässä.", + verbose_name="Työkokemus", + ), + ), + ( + "language_skills", + models.TextField( + blank=True, + default="", + help_text="Kerro kielitaidostasi erityisesti suomen, ruotsin ja englannin kielissä.", + verbose_name="Kielitaito", + ), + ), + ( + "free_text", + models.TextField( + blank=True, + help_text="Jos haluat sanoa hakemuksesi käsittelijöille jotain sellaista, jolle ei ole omaa kenttää yllä, käytä tätä kenttää.", + verbose_name="Vapaa alue", + ), + ), + ( + "event", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="%(app_label)s_signup_extras", + to="core.event", + ), + ), + ( + "person", + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + related_name="%(app_label)s_signup_extra", + to="core.person", + ), + ), + ( + "special_diet", + models.ManyToManyField(blank=True, to="finncon2026.specialdiet", verbose_name="Erikoisruokavalio"), + ), + ], + options={ + "abstract": False, + }, + bases=(kompassi.labour.models.signup_extras.SignupExtraMixin, models.Model), + ), + ] diff --git a/kompassi/events/finncon2026/migrations/0002_signupextra_color_wish_signupextra_ika.py b/kompassi/events/finncon2026/migrations/0002_signupextra_color_wish_signupextra_ika.py new file mode 100755 index 000000000..2f8547fc7 --- /dev/null +++ b/kompassi/events/finncon2026/migrations/0002_signupextra_color_wish_signupextra_ika.py @@ -0,0 +1,36 @@ +# Generated by Django 6.0.3 on 2026-03-23 20:57 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("finncon2026", "0001_initial"), + ] + + operations = [ + migrations.AddField( + model_name="signupextra", + name="color_wish", + field=models.TextField( + blank=True, + help_text="Keräämme toivomuksia paidan pohjavärille!(graaffikkomme valitsee suosituimpien värien kesken työvoimapaidan ja conipaidan pohjavärit.)", + verbose_name="Ehdota pohjaväriä työvoimapaille:", + ), + ), + migrations.AddField( + model_name="signupextra", + name="ika", + field=models.IntegerField( + default=42, + validators=[ + django.core.validators.MinValueValidator(15, message="Sinun täytyy olla vähintään 15-vuotias."), + django.core.validators.MaxValueValidator( + 117, message="Maailmassa on uusi vanhin ihminen!(... valitse numero mikä on alle 117)" + ), + ], + verbose_name="Ikä tapahtuman aikana", + ), + ), + ] diff --git a/kompassi/events/finncon2026/migrations/__init__.py b/kompassi/events/finncon2026/migrations/__init__.py new file mode 100755 index 000000000..e69de29bb diff --git a/kompassi/events/finncon2026/models.py b/kompassi/events/finncon2026/models.py new file mode 100755 index 000000000..6d2880feb --- /dev/null +++ b/kompassi/events/finncon2026/models.py @@ -0,0 +1,145 @@ +from django.core.validators import MaxValueValidator, MinValueValidator +from django.db import models + +from kompassi.labour.models import SignupExtraBase + +# Based on the 2023 form, with the addition of a age and color wish for the shirt + +SHIFT_TYPE_CHOICES = [ + ("2h", "2 tunnin vuoroja"), + ("4h", "4 tunnin vuoroja"), + ("yli4h", "Yli 4 tunnin vuoroja"), +] + + +TOTAL_WORK_CHOICES = [ + ("4h", "4–8 tuntia"), + ("8h", "8 tuntia"), + ("yli8h", "Yli 8 tuntia"), +] + + +SHIRT_SIZES = [ + ("NO_SHIRT", "Ei paitaa"), + ("XS", "XS Unisex"), + ("S", "S Unisex"), + ("M", "M Unisex"), + ("L", "L Unisex"), + ("XL", "XL Unisex"), + ("XXL", "XXL Unisex"), + ("3XL", "3XL Unisex"), + ("4XL", "4XL Unisex"), + ("5XL", "5XL Unisex"), + ("LF_XS", "XS Ladyfit"), + ("LF_S", "S Ladyfit"), + ("LF_M", "M Ladyfit"), + ("LF_L", "L Ladyfit"), + ("LF_XL", "XL Ladyfit"), + ("LF_2XL", "2XL Ladyfit"), + ("LF_3XL", "3XL Ladyfit"), +] + + +class SpecialDiet(models.Model): + name = models.CharField(max_length=63) + + def __str__(self): + return self.name + + +class SignupExtra(SignupExtraBase): + shift_type = models.CharField( + max_length=15, + verbose_name="Toivottu työvuoron pituus", + help_text="Haluatko tehdä yhden pitkän työvuoron vaiko monta lyhyempää vuoroa?", + choices=SHIFT_TYPE_CHOICES, + ) + + total_work = models.CharField( + max_length=15, + verbose_name="Toivottu kokonaistyömäärä", + help_text="Kuinka paljon haluat tehdä töitä yhteensä tapahtuman aikana?", + choices=TOTAL_WORK_CHOICES, + ) + + shirt_size = models.CharField( + max_length=8, + choices=SHIRT_SIZES, + default="NO_SHIRT", + verbose_name="Paidan koko", + help_text=( + "Ajoissa ilmoittautuneet vänkärit saavat maksuttoman työvoimapaidan, " + "mikäli ilmoittavat työskentelevänsä vähintään 8 tuntia." + ), + ) + + dead_dog = models.BooleanField( + default=False, + verbose_name="Osallistun dead dogeihin", + help_text=( + "Dead dogit ovat heti tapahtuman jälkeen järjestettävät kestit " + "kaikille täysikäisille työvoimaan kuuluville. Ilmoittautuminen ei ole sitova." + ), + ) + + color_wish = models.TextField( + blank=True, + verbose_name="Ehdota pohjaväriä työvoimapaille:", + help_text=( + "Keräämme toivomuksia paidan pohjavärille!" + "(graaffikkomme valitsee suosituimpien värien kesken työvoimapaidan ja conipaidan pohjavärit.)" + ), + ) + + ika = models.IntegerField( + validators=[ + MinValueValidator(15, message="Sinun täytyy olla vähintään 15-vuotias."), + MaxValueValidator(117, message="Maailmassa on uusi vanhin ihminen!(... valitse numero mikä on alle 117)"), + ], + default=42, + verbose_name="Ikä tapahtuman aikana", + ) + + special_diet = models.ManyToManyField(SpecialDiet, blank=True, verbose_name="Erikoisruokavalio") + + special_diet_other = models.TextField( + blank=True, + verbose_name="Muu erikoisruokavalio", + help_text=( + "Jos noudatat erikoisruokavaliota, jota ei ole yllä olevassa listassa, " + "ilmoita se tässä. Tapahtuman järjestäjä pyrkii ottamaan erikoisruokavaliot " + "huomioon, mutta kaikkia erikoisruokavalioita ei välttämättä pystytä järjestämään." + ), + ) + + prior_experience = models.TextField( + blank=True, + verbose_name="Työkokemus", + help_text=( + "Kerro tässä kentässä, jos sinulla on aiempaa kokemusta vastaavista " + "tehtävistä tai muuta sellaista työkokemusta, josta arvioit olevan hyötyä " + "hakemassasi tehtävässä." + ), + ) + + language_skills = models.TextField( + blank=True, + default="", + verbose_name="Kielitaito", + help_text="Kerro kielitaidostasi erityisesti suomen, ruotsin ja englannin kielissä.", + ) + + free_text = models.TextField( + blank=True, + verbose_name="Vapaa alue", + help_text=( + "Jos haluat sanoa hakemuksesi käsittelijöille jotain sellaista, jolle ei ole " + "omaa kenttää yllä, käytä tätä kenttää." + ), + ) + + @classmethod + def get_form_class(cls): + from .forms import SignupExtraForm + + return SignupExtraForm diff --git a/kompassi/settings.py b/kompassi/settings.py index 4dac2acb5..b56862e83 100644 --- a/kompassi/settings.py +++ b/kompassi/settings.py @@ -287,6 +287,7 @@ "kompassi.events.desucon2026", "kompassi.events.tracon2026", "kompassi.events.kotaeexpo2026", + "kompassi.events.finncon2026", # zombies are obsolete apps that can't be removed due to cross-app references in models "kompassi.zombies.enrollment", "kompassi.zombies.event_log",