diff --git a/kompassi/core/models/email_verification_token.py b/kompassi/core/models/email_verification_token.py index 72007795c..dccdb5cfd 100644 --- a/kompassi/core/models/email_verification_token.py +++ b/kompassi/core/models/email_verification_token.py @@ -7,7 +7,8 @@ from django.utils.translation import gettext_lazy as _ from kompassi.core.utils.cleanup import register_cleanup -from kompassi.graphql_api.language import DEFAULT_LANGUAGE, to_supported_language +from kompassi.graphql_api.language import DEFAULT_LANGUAGE, SupportedLanguageCode, to_supported_language +from kompassi.involvement.dumpers.section import section from ..utils import url from .one_time_code import OneTimeCode @@ -39,3 +40,13 @@ def render_message_body(self, request): language = DEFAULT_LANGUAGE if language == "sv" else language return render_to_string(f"emails/{language}/core_email_verification_message.eml", vars, request=request) + + def dump_own_data(self, language: SupportedLanguageCode) -> dict: + # TODO how do we localize this? + return section( + title="Sähköpostin vahvistuskoodi", + content={ + "Vahvistettava sähköpostiosoite": self.email, + **super().dump_own_data(language), + }, + ) diff --git a/kompassi/core/models/one_time_code.py b/kompassi/core/models/one_time_code.py index 89d219573..f4e254c2a 100644 --- a/kompassi/core/models/one_time_code.py +++ b/kompassi/core/models/one_time_code.py @@ -7,7 +7,7 @@ from django.utils import timezone from django.utils.translation import gettext_lazy as _ -from kompassi.graphql_api.language import DEFAULT_LANGUAGE, get_language_choices +from kompassi.graphql_api.language import DEFAULT_LANGUAGE, SupportedLanguageCode, get_language_choices logger = logging.getLogger(__name__) @@ -110,3 +110,12 @@ class Meta: indexes = [ models.Index(fields=["person", "state"]), ] + + def dump_own_data(self, language: SupportedLanguageCode) -> dict: + return { + "Koodi": self.code, + "Lähetetty": self.created_at.isoformat(), + "Käytetty": self.used_at.isoformat() if self.used_at else None, + "Tila": self.get_state_display(), # type: ignore + "Kieli": self.get_language_display(), # type: ignore + } diff --git a/kompassi/core/models/password_reset_token.py b/kompassi/core/models/password_reset_token.py index 7a8335159..e6cd286f4 100644 --- a/kompassi/core/models/password_reset_token.py +++ b/kompassi/core/models/password_reset_token.py @@ -6,6 +6,8 @@ from django.utils.timezone import now from kompassi.core.utils.cleanup import register_cleanup +from kompassi.graphql_api.language import SupportedLanguageCode +from kompassi.involvement.dumpers.section import section from ..utils import url from .one_time_code import OneTimeCode @@ -46,3 +48,13 @@ def reset_password(cls, code, new_password): user.keypairs.all().delete() return user + + def dump_own_data(self, language: SupportedLanguageCode) -> dict: + # TODO how do we localize this? + return section( + title="Salasanan palautuskoodi", + content={ + "IP-osoite": self.ip_address, + **super().dump_own_data(language), + }, + ) diff --git a/kompassi/core/models/person.py b/kompassi/core/models/person.py index 4bbea2fe5..c63798d7b 100644 --- a/kompassi/core/models/person.py +++ b/kompassi/core/models/person.py @@ -19,6 +19,7 @@ from django.utils.translation import gettext_lazy as _ from kompassi.graphql_api.language import DEFAULT_LANGUAGE, SupportedLanguageCode +from kompassi.zombies.tickets.utils import format_date from ..utils import calculate_age, format_phone_number, phone_number_validator, pick_attrs from .constants import ( @@ -584,3 +585,23 @@ def with_privacy(self): self._privacy_adapter = BadgePrivacyAdapter(self) return self._privacy_adapter + + def dump_own_data(self, language: SupportedLanguageCode) -> dict: + # TODO how do we localize this? + return { + "ID": self.id, + "Etunimi": self.first_name, + "Sukunimi": self.surname, + "Nick": self.nick, + "Syntymäaika": format_date(self.birth_date) if self.birth_date else None, + "Sähköposti": self.email, + "Puhelin": self.normalized_phone_number, + "Discord": self.discord_handle, + "Kotikunta": self.muncipality, + "Viralliset etunimet": self.official_first_names, + "Sähköposti vahvistettu": self.is_email_verified, + "Saa lähettää tietoa tulevista tapahtumista": self.may_send_info, + "Työskentelyhistorian saa jakaa muiden tapahtumien kanssa": self.allow_work_history_sharing, + "Nimen esitystapa listauksissa": self.get_name_display_style_display(), # type: ignore + "Nimen esitystapa badgeissa": self.get_badge_name_display_style_display(), # type: ignore + } diff --git a/kompassi/events/frostbite2026/management/commands/setup_frostbite2026.py b/kompassi/events/frostbite2026/management/commands/setup_frostbite2026.py index 34e891026..74ac47d92 100644 --- a/kompassi/events/frostbite2026/management/commands/setup_frostbite2026.py +++ b/kompassi/events/frostbite2026/management/commands/setup_frostbite2026.py @@ -49,7 +49,6 @@ def setup(self, test=False): self.tz = tzlocal() self.setup_core() self.setup_labour() - self.setup_access() self.setup_badges() self.setup_intra() self.setup_forms() @@ -262,6 +261,12 @@ def setup_labour(self): ), ) + GroupPrivilege.objects.get_or_create( + group=self.event.labour_event_meta.get_group("accepted"), + privilege=Privilege.objects.get(slug="desuslack"), + defaults=dict(event=self.event), + ) + def setup_badges(self): (badge_admin_group,) = BadgesEventMeta.get_or_create_groups(self.event, ["admins"]) meta, unused = BadgesEventMeta.objects.update_or_create( @@ -272,15 +277,6 @@ def setup_badges(self): ), ) - def setup_access(self): - # Grant accepted workers and programme hosts access to Desucon Slack - privilege = Privilege.objects.get(slug="desuslack") - for group in [ - self.event.labour_event_meta.get_group("accepted"), - # self.event.programme_event_meta.get_group("hosts"), - ]: - GroupPrivilege.objects.get_or_create(group=group, privilege=privilege, defaults=dict(event=self.event)) - def setup_intra(self): (admin_group,) = IntraEventMeta.get_or_create_groups(self.event, ["admins"]) organizer_group = self.event.labour_event_meta.get_group("vastaava") @@ -413,6 +409,7 @@ def setup_program_v2(self): group, created = Group.objects.get_or_create(name=f"{self.event.slug}-program-hosts") log_get_or_create(logger, group, created) + InvolvementToGroupMapping.objects.get_or_create( universe=universe, required_dimensions={ @@ -422,6 +419,12 @@ def setup_program_v2(self): group=group, ) + GroupPrivilege.objects.get_or_create( + group=group, + privilege=Privilege.objects.get(slug="desuslack"), + defaults=dict(event=self.event), + ) + class Command(BaseCommand): args = "" diff --git a/kompassi/involvement/dumpers/__init__.py b/kompassi/involvement/dumpers/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/kompassi/involvement/dumpers/section.py b/kompassi/involvement/dumpers/section.py new file mode 100644 index 000000000..99053ac87 --- /dev/null +++ b/kompassi/involvement/dumpers/section.py @@ -0,0 +1,9 @@ +from typing import Any + + +def section(title: str, content: Any) -> dict: + return { + "type": "Section", + "title": title, + "content": content, + } diff --git a/kompassi/involvement/dumpers/users.py b/kompassi/involvement/dumpers/users.py new file mode 100644 index 000000000..6e7743d18 --- /dev/null +++ b/kompassi/involvement/dumpers/users.py @@ -0,0 +1,52 @@ +from core.models.person import Person +from django.contrib.auth.models import User +from graphql_api.language import SupportedLanguageCode, getattr_message_in_language + +from kompassi.core.models.email_verification_token import EmailVerificationToken +from kompassi.core.models.password_reset_token import PasswordResetToken + +from ..models.registry import Registry +from .section import section + + +def dump_user(user: User, language: SupportedLanguageCode) -> dict: + # NOTE: Do not include fields that are duplicate with Person (non-Person Users don't get to dump data anyway) + # TODO how do we localize this? + return { + "Käyttäjätunnus": user.username, + "Salasana asetettu": user.has_usable_password(), + "Tili aktiivinen": user.is_active, + "Pääsy taka-adminiin": user.is_staff, + "Pääkäyttäjä": user.is_superuser, + "Tili luotu": user.date_joined.isoformat(), + "Viimeisin kirjautuminen": user.last_login.isoformat() if user.last_login else None, + } + + +def dump_users_registry_data( + registry: Registry, + person_or_user: Person | User, + language: SupportedLanguageCode, +) -> dict: + person: Person | None + user: User | None + + if isinstance(person_or_user, User): + person = person_or_user.person # type: ignore + user = person_or_user + else: + person = person_or_user + user = person.user + + if person is None: + raise ValueError("Person data is required for dumping registry data.") + + return section( + title=getattr_message_in_language(registry, "title", language), + content=[ + person.dump_own_data(language) if person else None, + dump_user(user, language) if user else None, + *(token.dump_own_data(language) for token in EmailVerificationToken.objects.filter(person=person)), + *(token.dump_own_data(language) for token in PasswordResetToken.objects.filter(person=person)), + ], + ) diff --git a/kompassi/involvement/dumpers/volunteers.py b/kompassi/involvement/dumpers/volunteers.py new file mode 100644 index 000000000..e69de29bb diff --git a/kompassi/involvement/models/views/__init__.py b/kompassi/involvement/models/views/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/kompassi/involvement/models/views/own_data_dump_view.py b/kompassi/involvement/models/views/own_data_dump_view.py new file mode 100644 index 000000000..73485b811 --- /dev/null +++ b/kompassi/involvement/models/views/own_data_dump_view.py @@ -0,0 +1,19 @@ + + + +def json2html(json_data): + """Convert JSON data to a simple HTML representation.""" + if isinstance(json_data, dict): + html = "