Source code for coalition.campaigns.models.policy_campaign

"""PolicyCampaign model for advocacy campaigns."""

from typing import TYPE_CHECKING

from django.db import models
from django.utils import timezone
from tinymce.models import HTMLField

from coalition.content.html_sanitizer import HTMLSanitizer

if TYPE_CHECKING:
    from typing import Any

    from .bill import Bill


[docs] class PolicyCampaign(models.Model): """ Represents a policy advocacy campaign that stakeholders can endorse. Campaigns are the central organizing unit of the platform. Each campaign represents a specific policy position that organizations and individuals can publicly endorse. Campaigns can be linked to specific legislation at federal and state levels. The campaign includes public-facing content (title, summary, description) as well as administrative settings for endorsement collection and moderation. """
[docs] name = models.SlugField( unique=True, help_text="Machine-readable name for the campaign", )
[docs] title = models.CharField( max_length=200, help_text="Public-facing title of the campaign", )
[docs] summary = models.TextField( help_text="Brief summary of the campaign's goals and position", )
[docs] description = HTMLField( blank=True, help_text="Additional context/details about the campaign", )
[docs] endorsement_statement = models.TextField( blank=True, help_text="The exact statement that endorsers are agreeing to support", )
[docs] allow_endorsements = models.BooleanField( default=True, help_text="Allow stakeholders to endorse this campaign", )
[docs] endorsement_form_instructions = HTMLField( blank=True, help_text="Custom instructions shown above the endorsement form", )
[docs] created_at = models.DateTimeField( auto_now_add=True, help_text="Timestamp when campaign was created", )
[docs] active = models.BooleanField( default=True, help_text="Whether campaign is active and accepting endorsements", )
[docs] image = models.ForeignKey( "content.Image", on_delete=models.SET_NULL, null=True, blank=True, related_name="campaign_images", help_text="Hero image for the campaign displayed on detail page and cards", )
[docs] class Meta:
[docs] db_table = "campaign"
[docs] def __str__(self) -> str: return self.title
[docs] def current_bills(self) -> "models.QuerySet[Bill]": session = f"{((timezone.now().date().year - 1789) // 2) + 1}th" return self.bills.filter(congress_session=session)
[docs] def save(self, *args: "Any", **kwargs: "Any") -> None: """Sanitize HTML fields before saving to prevent XSS attacks.""" # Sanitize description field if it contains HTML if self.description: self.description = HTMLSanitizer.sanitize(self.description) # Sanitize other HTML fields if self.endorsement_form_instructions: self.endorsement_form_instructions = HTMLSanitizer.sanitize( self.endorsement_form_instructions, ) # Note: summary and endorsement_statement are plain text, but sanitize anyway if self.summary: self.summary = HTMLSanitizer.sanitize_plain_text(self.summary) if self.endorsement_statement: self.endorsement_statement = HTMLSanitizer.sanitize_plain_text( self.endorsement_statement, ) super().save(*args, **kwargs)