"""Conference and Section models for django-program."""
from django.db import models
from encrypted_fields import EncryptedCharField
[docs]
class Conference(models.Model):
"""A conference event with dates, venue, and integration settings.
The central model that all other apps reference. Stores Pretalx and Stripe
configuration so each conference can be managed independently.
"""
name = models.CharField(max_length=200)
slug = models.SlugField(max_length=200, unique=True)
start_date = models.DateField()
end_date = models.DateField()
timezone = models.CharField(max_length=100, default="UTC")
venue = models.CharField(max_length=300, blank=True, default="")
address = models.CharField(max_length=500, blank=True, default="")
website_url = models.URLField(blank=True, default="")
pretalx_event_slug = models.CharField(max_length=200, blank=True, default="")
stripe_secret_key = EncryptedCharField(max_length=200, blank=True, null=True, default=None)
stripe_publishable_key = EncryptedCharField(max_length=200, blank=True, null=True, default=None)
stripe_webhook_secret = EncryptedCharField(max_length=200, blank=True, null=True, default=None)
total_capacity = models.PositiveIntegerField(
default=0,
help_text="Maximum total tickets across all types. 0 means unlimited.",
)
is_active = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
ordering = ["-start_date"]
def __str__(self) -> str:
return self.name
[docs]
class Section(models.Model):
"""A distinct segment of a conference (e.g. Tutorials, Talks, Sprints).
Sections divide a conference into logical time blocks, each with their own
date range. They are ordered by the ``order`` field for display purposes.
"""
conference = models.ForeignKey(
Conference,
on_delete=models.CASCADE,
related_name="sections",
)
name = models.CharField(max_length=200)
slug = models.SlugField(max_length=200)
start_date = models.DateField()
end_date = models.DateField()
order = models.PositiveIntegerField(default=0)
class Meta:
ordering = ["order", "start_date"]
unique_together = [("conference", "slug")]
def __str__(self) -> str:
return f"{self.name} ({self.conference.slug})"
[docs]
class FeatureFlags(models.Model):
"""Per-conference feature toggle overrides.
Database-backed flags that override the defaults from
``DJANGO_PROGRAM["features"]``. Changes take effect immediately
without server restart. Each conference has at most one row.
All boolean fields are nullable: ``None`` means "use default from
settings", while an explicit ``True`` or ``False`` overrides.
"""
conference = models.OneToOneField(
"program_conference.Conference",
on_delete=models.CASCADE,
related_name="feature_flags",
)
registration_enabled = models.BooleanField(
null=True,
blank=True,
help_text="Override registration toggle. Leave blank to use default from settings.",
)
sponsors_enabled = models.BooleanField(
null=True,
blank=True,
help_text="Override sponsors toggle.",
)
travel_grants_enabled = models.BooleanField(
null=True,
blank=True,
help_text="Override travel grants toggle.",
)
programs_enabled = models.BooleanField(
null=True,
blank=True,
help_text="Override programs/activities toggle.",
)
pretalx_sync_enabled = models.BooleanField(
null=True,
blank=True,
help_text="Override Pretalx sync toggle.",
)
public_ui_enabled = models.BooleanField(
null=True,
blank=True,
help_text="Override public UI toggle.",
)
manage_ui_enabled = models.BooleanField(
null=True,
blank=True,
help_text="Override manage UI toggle.",
)
all_ui_enabled = models.BooleanField(
null=True,
blank=True,
help_text="Master UI switch override.",
)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
verbose_name = "feature flags"
verbose_name_plural = "feature flags"
def __str__(self) -> str:
return f"Feature flags for {self.conference}"