mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2026-02-05 06:05:18 -05:00
Based on the git diff provided, here's a concise and descriptive commit message:
feat: add passkey authentication and enhance user preferences - Add passkey login security event type with fingerprint icon - Include request and site context in email confirmation for backend - Add user_id exact match filter to prevent incorrect user lookups - Enable PATCH method for updating user preferences via API - Add moderation_preferences support to user settings - Optimize ticket queries with select_related and prefetch_related This commit introduces passkey authentication tracking, improves user profile filtering accuracy, and extends the preferences API to support updates. Query optimizations reduce database hits for ticket listings.
This commit is contained in:
@@ -238,6 +238,186 @@ PARKS_COMPANY_ROLES = [
|
||||
),
|
||||
]
|
||||
|
||||
# ============================================================================
|
||||
# Person/Entity Type Choices (for Company model)
|
||||
# ============================================================================
|
||||
PERSON_TYPES = [
|
||||
RichChoice(
|
||||
value="INDIVIDUAL",
|
||||
label="Individual",
|
||||
description="Single person or sole proprietor",
|
||||
metadata={"color": "blue", "icon": "user", "css_class": "bg-blue-100 text-blue-800", "sort_order": 1},
|
||||
category=ChoiceCategory.CLASSIFICATION,
|
||||
),
|
||||
RichChoice(
|
||||
value="FIRM",
|
||||
label="Firm",
|
||||
description="Professional services firm",
|
||||
metadata={"color": "indigo", "icon": "briefcase", "css_class": "bg-indigo-100 text-indigo-800", "sort_order": 2},
|
||||
category=ChoiceCategory.CLASSIFICATION,
|
||||
),
|
||||
RichChoice(
|
||||
value="ORGANIZATION",
|
||||
label="Organization",
|
||||
description="Non-profit or member organization",
|
||||
metadata={"color": "green", "icon": "users", "css_class": "bg-green-100 text-green-800", "sort_order": 3},
|
||||
category=ChoiceCategory.CLASSIFICATION,
|
||||
),
|
||||
RichChoice(
|
||||
value="CORPORATION",
|
||||
label="Corporation",
|
||||
description="Incorporated business entity",
|
||||
metadata={"color": "purple", "icon": "building", "css_class": "bg-purple-100 text-purple-800", "sort_order": 4},
|
||||
category=ChoiceCategory.CLASSIFICATION,
|
||||
),
|
||||
RichChoice(
|
||||
value="PARTNERSHIP",
|
||||
label="Partnership",
|
||||
description="Business partnership",
|
||||
metadata={"color": "orange", "icon": "handshake", "css_class": "bg-orange-100 text-orange-800", "sort_order": 5},
|
||||
category=ChoiceCategory.CLASSIFICATION,
|
||||
),
|
||||
RichChoice(
|
||||
value="GOVERNMENT",
|
||||
label="Government Entity",
|
||||
description="Government agency or public entity",
|
||||
metadata={"color": "gray", "icon": "landmark", "css_class": "bg-gray-100 text-gray-800", "sort_order": 6},
|
||||
category=ChoiceCategory.CLASSIFICATION,
|
||||
),
|
||||
]
|
||||
|
||||
# ============================================================================
|
||||
# Company Status Choices
|
||||
# ============================================================================
|
||||
COMPANY_STATUSES = [
|
||||
RichChoice(
|
||||
value="ACTIVE",
|
||||
label="Active",
|
||||
description="Company is currently operating",
|
||||
metadata={
|
||||
"color": "green",
|
||||
"icon": "check-circle",
|
||||
"css_class": "bg-green-100 text-green-800",
|
||||
"sort_order": 1,
|
||||
"is_active": True,
|
||||
},
|
||||
category=ChoiceCategory.STATUS,
|
||||
),
|
||||
RichChoice(
|
||||
value="DEFUNCT",
|
||||
label="Defunct",
|
||||
description="Company no longer exists",
|
||||
metadata={
|
||||
"color": "red",
|
||||
"icon": "x-circle",
|
||||
"css_class": "bg-red-100 text-red-800",
|
||||
"sort_order": 2,
|
||||
"is_active": False,
|
||||
},
|
||||
category=ChoiceCategory.STATUS,
|
||||
),
|
||||
RichChoice(
|
||||
value="MERGED",
|
||||
label="Merged",
|
||||
description="Company merged with another entity",
|
||||
metadata={
|
||||
"color": "purple",
|
||||
"icon": "git-merge",
|
||||
"css_class": "bg-purple-100 text-purple-800",
|
||||
"sort_order": 3,
|
||||
"is_active": False,
|
||||
},
|
||||
category=ChoiceCategory.STATUS,
|
||||
),
|
||||
RichChoice(
|
||||
value="ACQUIRED",
|
||||
label="Acquired",
|
||||
description="Company was acquired by another entity",
|
||||
metadata={
|
||||
"color": "blue",
|
||||
"icon": "arrow-right-circle",
|
||||
"css_class": "bg-blue-100 text-blue-800",
|
||||
"sort_order": 4,
|
||||
"is_active": False,
|
||||
},
|
||||
category=ChoiceCategory.STATUS,
|
||||
),
|
||||
RichChoice(
|
||||
value="RENAMED",
|
||||
label="Renamed",
|
||||
description="Company changed its name",
|
||||
metadata={
|
||||
"color": "yellow",
|
||||
"icon": "edit",
|
||||
"css_class": "bg-yellow-100 text-yellow-800",
|
||||
"sort_order": 5,
|
||||
"is_active": True,
|
||||
},
|
||||
category=ChoiceCategory.STATUS,
|
||||
),
|
||||
RichChoice(
|
||||
value="DORMANT",
|
||||
label="Dormant",
|
||||
description="Company is inactive but not dissolved",
|
||||
metadata={
|
||||
"color": "gray",
|
||||
"icon": "pause-circle",
|
||||
"css_class": "bg-gray-100 text-gray-800",
|
||||
"sort_order": 6,
|
||||
"is_active": False,
|
||||
},
|
||||
category=ChoiceCategory.STATUS,
|
||||
),
|
||||
]
|
||||
|
||||
# ============================================================================
|
||||
# Date Precision Choices (for parks domain - founding dates, opening dates, etc.)
|
||||
# ============================================================================
|
||||
DATE_PRECISION = [
|
||||
RichChoice(
|
||||
value="exact",
|
||||
label="Exact Date",
|
||||
description="Date is known exactly",
|
||||
metadata={"color": "green", "icon": "calendar", "sort_order": 1, "format": "YYYY-MM-DD"},
|
||||
category=ChoiceCategory.CLASSIFICATION,
|
||||
),
|
||||
RichChoice(
|
||||
value="month",
|
||||
label="Month and Year",
|
||||
description="Only month and year are known",
|
||||
metadata={"color": "blue", "icon": "calendar", "sort_order": 2, "format": "YYYY-MM"},
|
||||
category=ChoiceCategory.CLASSIFICATION,
|
||||
),
|
||||
RichChoice(
|
||||
value="year",
|
||||
label="Year Only",
|
||||
description="Only the year is known",
|
||||
metadata={"color": "yellow", "icon": "calendar", "sort_order": 3, "format": "YYYY"},
|
||||
category=ChoiceCategory.CLASSIFICATION,
|
||||
),
|
||||
RichChoice(
|
||||
value="decade",
|
||||
label="Decade",
|
||||
description="Only the decade is known",
|
||||
metadata={"color": "orange", "icon": "calendar", "sort_order": 4, "format": "YYYYs"},
|
||||
category=ChoiceCategory.CLASSIFICATION,
|
||||
),
|
||||
RichChoice(
|
||||
value="century",
|
||||
label="Century",
|
||||
description="Only the century is known",
|
||||
metadata={"color": "gray", "icon": "calendar", "sort_order": 5, "format": "YYc"},
|
||||
category=ChoiceCategory.CLASSIFICATION,
|
||||
),
|
||||
RichChoice(
|
||||
value="approximate",
|
||||
label="Approximate",
|
||||
description="Date is approximate/estimated",
|
||||
metadata={"color": "gray", "icon": "help-circle", "sort_order": 6, "format": "~YYYY"},
|
||||
category=ChoiceCategory.CLASSIFICATION,
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
def register_parks_choices():
|
||||
"""Register all parks domain choices with the global registry"""
|
||||
@@ -266,6 +446,31 @@ def register_parks_choices():
|
||||
metadata={"domain": "parks", "type": "company_role"},
|
||||
)
|
||||
|
||||
register_choices(
|
||||
name="person_types",
|
||||
choices=PERSON_TYPES,
|
||||
domain="parks",
|
||||
description="Person/entity type classifications",
|
||||
metadata={"domain": "parks", "type": "person_type"},
|
||||
)
|
||||
|
||||
register_choices(
|
||||
name="company_statuses",
|
||||
choices=COMPANY_STATUSES,
|
||||
domain="parks",
|
||||
description="Company operational status options",
|
||||
metadata={"domain": "parks", "type": "company_status"},
|
||||
)
|
||||
|
||||
register_choices(
|
||||
name="date_precision",
|
||||
choices=DATE_PRECISION,
|
||||
domain="parks",
|
||||
description="Date precision options for parks domain",
|
||||
metadata={"domain": "parks", "type": "date_precision"},
|
||||
)
|
||||
|
||||
|
||||
# Auto-register choices when module is imported
|
||||
register_parks_choices()
|
||||
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
# Generated by Django 5.2.10 on 2026-01-10 22:01
|
||||
|
||||
import apps.core.choices.fields
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("parks", "0032_add_logo_image_id"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="company",
|
||||
name="founded_date_precision",
|
||||
field=apps.core.choices.fields.RichChoiceField(
|
||||
allow_deprecated=False,
|
||||
blank=True,
|
||||
choice_group="date_precision",
|
||||
choices=[
|
||||
("exact", "Exact Date"),
|
||||
("month", "Month and Year"),
|
||||
("year", "Year Only"),
|
||||
("decade", "Decade"),
|
||||
("century", "Century"),
|
||||
("approximate", "Approximate"),
|
||||
],
|
||||
domain="parks",
|
||||
help_text="Precision of the founding date",
|
||||
max_length=20,
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="company",
|
||||
name="person_type",
|
||||
field=apps.core.choices.fields.RichChoiceField(
|
||||
allow_deprecated=False,
|
||||
blank=True,
|
||||
choice_group="person_types",
|
||||
choices=[
|
||||
("INDIVIDUAL", "Individual"),
|
||||
("FIRM", "Firm"),
|
||||
("ORGANIZATION", "Organization"),
|
||||
("CORPORATION", "Corporation"),
|
||||
("PARTNERSHIP", "Partnership"),
|
||||
("GOVERNMENT", "Government Entity"),
|
||||
],
|
||||
domain="parks",
|
||||
help_text="Type of entity (individual, firm, organization, etc.)",
|
||||
max_length=20,
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="company",
|
||||
name="status",
|
||||
field=apps.core.choices.fields.RichChoiceField(
|
||||
allow_deprecated=False,
|
||||
choice_group="company_statuses",
|
||||
choices=[
|
||||
("ACTIVE", "Active"),
|
||||
("DEFUNCT", "Defunct"),
|
||||
("MERGED", "Merged"),
|
||||
("ACQUIRED", "Acquired"),
|
||||
("RENAMED", "Renamed"),
|
||||
("DORMANT", "Dormant"),
|
||||
],
|
||||
default="ACTIVE",
|
||||
domain="parks",
|
||||
help_text="Current operational status of the company",
|
||||
max_length=20,
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="companyevent",
|
||||
name="founded_date_precision",
|
||||
field=apps.core.choices.fields.RichChoiceField(
|
||||
allow_deprecated=False,
|
||||
blank=True,
|
||||
choice_group="date_precision",
|
||||
choices=[
|
||||
("exact", "Exact Date"),
|
||||
("month", "Month and Year"),
|
||||
("year", "Year Only"),
|
||||
("decade", "Decade"),
|
||||
("century", "Century"),
|
||||
("approximate", "Approximate"),
|
||||
],
|
||||
domain="parks",
|
||||
help_text="Precision of the founding date",
|
||||
max_length=20,
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="companyevent",
|
||||
name="person_type",
|
||||
field=apps.core.choices.fields.RichChoiceField(
|
||||
allow_deprecated=False,
|
||||
blank=True,
|
||||
choice_group="person_types",
|
||||
choices=[
|
||||
("INDIVIDUAL", "Individual"),
|
||||
("FIRM", "Firm"),
|
||||
("ORGANIZATION", "Organization"),
|
||||
("CORPORATION", "Corporation"),
|
||||
("PARTNERSHIP", "Partnership"),
|
||||
("GOVERNMENT", "Government Entity"),
|
||||
],
|
||||
domain="parks",
|
||||
help_text="Type of entity (individual, firm, organization, etc.)",
|
||||
max_length=20,
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="companyevent",
|
||||
name="status",
|
||||
field=apps.core.choices.fields.RichChoiceField(
|
||||
allow_deprecated=False,
|
||||
choice_group="company_statuses",
|
||||
choices=[
|
||||
("ACTIVE", "Active"),
|
||||
("DEFUNCT", "Defunct"),
|
||||
("MERGED", "Merged"),
|
||||
("ACQUIRED", "Acquired"),
|
||||
("RENAMED", "Renamed"),
|
||||
("DORMANT", "Dormant"),
|
||||
],
|
||||
default="ACTIVE",
|
||||
domain="parks",
|
||||
help_text="Current operational status of the company",
|
||||
max_length=20,
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="park",
|
||||
name="closing_date_precision",
|
||||
field=apps.core.choices.fields.RichChoiceField(
|
||||
allow_deprecated=False,
|
||||
blank=True,
|
||||
choice_group="date_precision",
|
||||
choices=[
|
||||
("exact", "Exact Date"),
|
||||
("month", "Month and Year"),
|
||||
("year", "Year Only"),
|
||||
("decade", "Decade"),
|
||||
("century", "Century"),
|
||||
("approximate", "Approximate"),
|
||||
],
|
||||
default="exact",
|
||||
domain="parks",
|
||||
help_text="Precision of the closing date",
|
||||
max_length=20,
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="park",
|
||||
name="opening_date_precision",
|
||||
field=apps.core.choices.fields.RichChoiceField(
|
||||
allow_deprecated=False,
|
||||
blank=True,
|
||||
choice_group="date_precision",
|
||||
choices=[
|
||||
("exact", "Exact Date"),
|
||||
("month", "Month and Year"),
|
||||
("year", "Year Only"),
|
||||
("decade", "Decade"),
|
||||
("century", "Century"),
|
||||
("approximate", "Approximate"),
|
||||
],
|
||||
default="exact",
|
||||
domain="parks",
|
||||
help_text="Precision of the opening date",
|
||||
max_length=20,
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="parkevent",
|
||||
name="closing_date_precision",
|
||||
field=apps.core.choices.fields.RichChoiceField(
|
||||
allow_deprecated=False,
|
||||
blank=True,
|
||||
choice_group="date_precision",
|
||||
choices=[
|
||||
("exact", "Exact Date"),
|
||||
("month", "Month and Year"),
|
||||
("year", "Year Only"),
|
||||
("decade", "Decade"),
|
||||
("century", "Century"),
|
||||
("approximate", "Approximate"),
|
||||
],
|
||||
default="exact",
|
||||
domain="parks",
|
||||
help_text="Precision of the closing date",
|
||||
max_length=20,
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="parkevent",
|
||||
name="opening_date_precision",
|
||||
field=apps.core.choices.fields.RichChoiceField(
|
||||
allow_deprecated=False,
|
||||
blank=True,
|
||||
choice_group="date_precision",
|
||||
choices=[
|
||||
("exact", "Exact Date"),
|
||||
("month", "Month and Year"),
|
||||
("year", "Year Only"),
|
||||
("decade", "Decade"),
|
||||
("century", "Century"),
|
||||
("approximate", "Approximate"),
|
||||
],
|
||||
default="exact",
|
||||
domain="parks",
|
||||
help_text="Precision of the opening date",
|
||||
max_length=20,
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -26,34 +26,20 @@ class Company(TrackedModel):
|
||||
description = models.TextField(blank=True, help_text="Detailed company description")
|
||||
website = models.URLField(blank=True, help_text="Company website URL")
|
||||
|
||||
# Person/Entity Type (ported from legacy thrillwiki-87)
|
||||
PERSON_TYPES = [
|
||||
("INDIVIDUAL", "Individual"),
|
||||
("FIRM", "Firm"),
|
||||
("ORGANIZATION", "Organization"),
|
||||
("CORPORATION", "Corporation"),
|
||||
("PARTNERSHIP", "Partnership"),
|
||||
("GOVERNMENT", "Government Entity"),
|
||||
]
|
||||
person_type = models.CharField(
|
||||
# Person/Entity Type - using RichChoiceField
|
||||
person_type = RichChoiceField(
|
||||
choice_group="person_types",
|
||||
domain="parks",
|
||||
max_length=20,
|
||||
choices=PERSON_TYPES,
|
||||
blank=True,
|
||||
help_text="Type of entity (individual, firm, organization, etc.)",
|
||||
)
|
||||
|
||||
# Company Status (ported from legacy)
|
||||
COMPANY_STATUSES = [
|
||||
("ACTIVE", "Active"),
|
||||
("DEFUNCT", "Defunct"),
|
||||
("MERGED", "Merged"),
|
||||
("ACQUIRED", "Acquired"),
|
||||
("RENAMED", "Renamed"),
|
||||
("DORMANT", "Dormant"),
|
||||
]
|
||||
status = models.CharField(
|
||||
# Company Status - using RichChoiceField
|
||||
status = RichChoiceField(
|
||||
choice_group="company_statuses",
|
||||
domain="parks",
|
||||
max_length=20,
|
||||
choices=COMPANY_STATUSES,
|
||||
default="ACTIVE",
|
||||
help_text="Current operational status of the company",
|
||||
)
|
||||
@@ -61,17 +47,10 @@ class Company(TrackedModel):
|
||||
# Founding Information (enhanced from just founded_year)
|
||||
founded_year = models.PositiveIntegerField(blank=True, null=True, help_text="Year the company was founded")
|
||||
founded_date = models.DateField(blank=True, null=True, help_text="Full founding date if known")
|
||||
DATE_PRECISION_CHOICES = [
|
||||
("exact", "Exact Date"),
|
||||
("month", "Month and Year"),
|
||||
("year", "Year Only"),
|
||||
("decade", "Decade"),
|
||||
("century", "Century"),
|
||||
("approximate", "Approximate"),
|
||||
]
|
||||
founded_date_precision = models.CharField(
|
||||
founded_date_precision = RichChoiceField(
|
||||
choice_group="date_precision",
|
||||
domain="parks",
|
||||
max_length=20,
|
||||
choices=DATE_PRECISION_CHOICES,
|
||||
blank=True,
|
||||
help_text="Precision of the founding date",
|
||||
)
|
||||
|
||||
@@ -54,31 +54,19 @@ class Park(StateMachineMixin, TrackedModel):
|
||||
|
||||
# Details
|
||||
opening_date = models.DateField(null=True, blank=True, help_text="Opening date")
|
||||
opening_date_precision = models.CharField(
|
||||
opening_date_precision = RichChoiceField(
|
||||
choice_group="date_precision",
|
||||
domain="parks",
|
||||
max_length=20,
|
||||
choices=[
|
||||
("exact", "Exact Date"),
|
||||
("month", "Month and Year"),
|
||||
("year", "Year Only"),
|
||||
("decade", "Decade"),
|
||||
("century", "Century"),
|
||||
("approximate", "Approximate"),
|
||||
],
|
||||
default="exact",
|
||||
blank=True,
|
||||
help_text="Precision of the opening date",
|
||||
)
|
||||
closing_date = models.DateField(null=True, blank=True, help_text="Closing date")
|
||||
closing_date_precision = models.CharField(
|
||||
closing_date_precision = RichChoiceField(
|
||||
choice_group="date_precision",
|
||||
domain="parks",
|
||||
max_length=20,
|
||||
choices=[
|
||||
("exact", "Exact Date"),
|
||||
("month", "Month and Year"),
|
||||
("year", "Year Only"),
|
||||
("decade", "Decade"),
|
||||
("century", "Century"),
|
||||
("approximate", "Approximate"),
|
||||
],
|
||||
default="exact",
|
||||
blank=True,
|
||||
help_text="Precision of the closing date",
|
||||
|
||||
Reference in New Issue
Block a user