# Generated by Django 5.2.7 on 2025-10-13 00:00 from __future__ import annotations import django.db.models.deletion from django.db import migrations, models class Migration(migrations.Migration): """Initial migration. Args: migrations (migrations.Migration): The base class for all migrations. """ initial = True dependencies = [] operations = [ migrations.CreateModel( name="Game", fields=[ ("id", models.TextField(primary_key=True, serialize=False, verbose_name="Game ID")), ( "slug", models.TextField( blank=True, db_index=True, default="", help_text="Short unique identifier for the game.", max_length=200, verbose_name="Slug" ), ), ("name", models.TextField(blank=True, db_index=True, default="", verbose_name="Name")), ("display_name", models.TextField(blank=True, db_index=True, default="", verbose_name="Display name")), ("box_art", models.URLField(blank=True, default="", max_length=500, verbose_name="Box art URL")), ( "box_art_file", models.FileField(blank=True, help_text="Locally cached box art image served from this site.", null=True, upload_to="games/box_art/"), ), ("added_at", models.DateTimeField(auto_now_add=True, db_index=True, help_text="Timestamp when this game record was created.")), ("updated_at", models.DateTimeField(auto_now=True, help_text="Timestamp when this game record was last updated.")), ], options={ "ordering": ["display_name"], }, ), migrations.CreateModel( name="Channel", fields=[ ( "id", models.TextField(help_text="The unique Twitch identifier for the channel.", primary_key=True, serialize=False, verbose_name="Channel ID"), ), ("name", models.TextField(db_index=True, help_text="The lowercase username of the channel.", verbose_name="Username")), ( "display_name", models.TextField(db_index=True, help_text="The display name of the channel (with proper capitalization).", verbose_name="Display Name"), ), ("added_at", models.DateTimeField(auto_now_add=True, db_index=True, help_text="Timestamp when this channel record was created.")), ("updated_at", models.DateTimeField(auto_now=True, help_text="Timestamp when this channel record was last updated.")), ], options={ "ordering": ["display_name"], "indexes": [ models.Index(fields=["name"], name="twitch_chan_name_15d566_idx"), models.Index(fields=["display_name"], name="twitch_chan_display_2bf213_idx"), ], }, ), migrations.CreateModel( name="DropBenefit", fields=[ ("id", models.TextField(help_text="Unique Twitch identifier for the benefit.", primary_key=True, serialize=False)), ("name", models.TextField(blank=True, db_index=True, default="N/A", help_text="Name of the drop benefit.")), ("image_asset_url", models.URLField(blank=True, default="", help_text="URL to the benefit's image asset.", max_length=500)), ( "image_file", models.FileField(blank=True, help_text="Locally cached benefit image served from this site.", null=True, upload_to="benefits/images/"), ), ( "created_at", models.DateTimeField( db_index=True, help_text="Timestamp when the benefit was created. This is from Twitch API and not auto-generated.", null=True ), ), ("entitlement_limit", models.PositiveIntegerField(default=1, help_text="Maximum number of times this benefit can be earned.")), ("is_ios_available", models.BooleanField(default=False, help_text="Whether the benefit is available on iOS.")), ( "distribution_type", models.TextField(blank=True, db_index=True, default="", help_text="Type of distribution for this benefit.", max_length=50), ), ("added_at", models.DateTimeField(auto_now_add=True, db_index=True, help_text="Timestamp when this benefit record was created.")), ("updated_at", models.DateTimeField(auto_now=True, help_text="Timestamp when this benefit record was last updated.")), ], options={ "ordering": ["-created_at"], "indexes": [ models.Index(fields=["name"], name="twitch_drop_name_7125ff_idx"), models.Index(fields=["created_at"], name="twitch_drop_created_a3563e_idx"), models.Index(fields=["distribution_type"], name="twitch_drop_distrib_08b224_idx"), models.Index(condition=models.Q(("is_ios_available", True)), fields=["is_ios_available"], name="benefit_ios_available_idx"), ], }, ), migrations.CreateModel( name="DropBenefitEdge", fields=[ ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), ("entitlement_limit", models.PositiveIntegerField(default=1, help_text="Max times this benefit can be claimed for this drop.")), ("added_at", models.DateTimeField(auto_now_add=True, db_index=True, help_text="Timestamp when this drop-benefit edge was created.")), ("updated_at", models.DateTimeField(auto_now=True, help_text="Timestamp when this drop-benefit edge was last updated.")), ( "benefit", models.ForeignKey(help_text="The benefit in this relationship.", on_delete=django.db.models.deletion.CASCADE, to="twitch.dropbenefit"), ), ], ), migrations.CreateModel( name="DropCampaign", fields=[ ("id", models.TextField(help_text="Unique Twitch identifier for the campaign.", primary_key=True, serialize=False)), ("name", models.TextField(db_index=True, help_text="Name of the drop campaign.")), ("description", models.TextField(blank=True, help_text="Detailed description of the campaign.")), ("details_url", models.URLField(blank=True, default="", help_text="URL with campaign details.", max_length=500)), ("account_link_url", models.URLField(blank=True, default="", help_text="URL to link a Twitch account for the campaign.", max_length=500)), ("image_url", models.URLField(blank=True, default="", help_text="URL to an image representing the campaign.", max_length=500)), ( "image_file", models.FileField(blank=True, help_text="Locally cached campaign image served from this site.", null=True, upload_to="campaigns/images/"), ), ("start_at", models.DateTimeField(blank=True, db_index=True, help_text="Datetime when the campaign starts.", null=True)), ("end_at", models.DateTimeField(blank=True, db_index=True, help_text="Datetime when the campaign ends.", null=True)), ("is_account_connected", models.BooleanField(default=False, help_text="Indicates if the user account is linked.")), ("allow_is_enabled", models.BooleanField(default=True, help_text="Whether the campaign allows participation.")), ("added_at", models.DateTimeField(auto_now_add=True, db_index=True, help_text="Timestamp when this campaign record was created.")), ("updated_at", models.DateTimeField(auto_now=True, help_text="Timestamp when this campaign record was last updated.")), ( "allow_channels", models.ManyToManyField( blank=True, help_text="Channels that are allowed to participate in this campaign.", related_name="allowed_campaigns", to="twitch.channel", ), ), ( "game", models.ForeignKey( help_text="Game associated with this campaign.", on_delete=django.db.models.deletion.CASCADE, related_name="drop_campaigns", to="twitch.game", verbose_name="Game", ), ), ], options={ "ordering": ["-start_at"], }, ), migrations.CreateModel( name="Organization", fields=[ ( "id", models.TextField( help_text="The unique Twitch identifier for the organization.", primary_key=True, serialize=False, verbose_name="Organization ID" ), ), ("name", models.TextField(db_index=True, help_text="Display name of the organization.", unique=True, verbose_name="Name")), ("added_at", models.DateTimeField(auto_now_add=True, db_index=True, help_text="Timestamp when this organization record was created.")), ("updated_at", models.DateTimeField(auto_now=True, help_text="Timestamp when this organization record was last updated.")), ], options={ "ordering": ["name"], "indexes": [models.Index(fields=["name"], name="twitch_orga_name_febe72_idx")], }, ), migrations.AddField( model_name="game", name="owner", field=models.ForeignKey( blank=True, help_text="The organization that owns this game.", null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="games", to="twitch.organization", verbose_name="Organization", ), ), migrations.CreateModel( name="TimeBasedDrop", fields=[ ("id", models.TextField(help_text="Unique Twitch identifier for the time-based drop.", primary_key=True, serialize=False)), ("name", models.TextField(db_index=True, help_text="Name of the time-based drop.")), ( "required_minutes_watched", models.PositiveIntegerField(blank=True, db_index=True, help_text="Minutes required to watch before earning this drop.", null=True), ), ("required_subs", models.PositiveIntegerField(default=0, help_text="Number of subscriptions required to unlock this drop.")), ("start_at", models.DateTimeField(blank=True, db_index=True, help_text="Datetime when this drop becomes available.", null=True)), ("end_at", models.DateTimeField(blank=True, db_index=True, help_text="Datetime when this drop expires.", null=True)), ("added_at", models.DateTimeField(auto_now_add=True, db_index=True, help_text="Timestamp when this time-based drop record was created.")), ("updated_at", models.DateTimeField(auto_now=True, help_text="Timestamp when this time-based drop record was last updated.")), ( "benefits", models.ManyToManyField( help_text="Benefits unlocked by this drop.", related_name="drops", through="twitch.DropBenefitEdge", to="twitch.dropbenefit" ), ), ( "campaign", models.ForeignKey( help_text="The campaign this drop belongs to.", on_delete=django.db.models.deletion.CASCADE, related_name="time_based_drops", to="twitch.dropcampaign", ), ), ], options={ "ordering": ["start_at"], }, ), migrations.AddField( model_name="dropbenefitedge", name="drop", field=models.ForeignKey( help_text="The time-based drop in this relationship.", on_delete=django.db.models.deletion.CASCADE, to="twitch.timebaseddrop" ), ), migrations.CreateModel( name="TwitchGameData", fields=[ ("id", models.TextField(primary_key=True, serialize=False, verbose_name="Twitch Game ID")), ("name", models.TextField(blank=True, db_index=True, default="", verbose_name="Name")), ( "box_art_url", models.URLField( blank=True, default="", help_text="URL template with {width}x{height} placeholders for the box art image.", max_length=500, verbose_name="Box art URL", ), ), ("igdb_id", models.TextField(blank=True, default="", verbose_name="IGDB ID")), ("added_at", models.DateTimeField(auto_now_add=True, db_index=True, help_text="Record creation time.")), ("updated_at", models.DateTimeField(auto_now=True, help_text="Record last update time.")), ( "game", models.ForeignKey( blank=True, help_text="Optional link to the local Game record for this Twitch game.", null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="twitch_game_data", to="twitch.game", verbose_name="Game", ), ), ], options={ "ordering": ["name"], }, ), migrations.AddIndex( model_name="dropcampaign", index=models.Index(fields=["name"], name="twitch_drop_name_3b70b3_idx"), ), migrations.AddIndex( model_name="dropcampaign", index=models.Index(fields=["start_at", "end_at"], name="twitch_drop_start_a_6e5fb6_idx"), ), migrations.AddIndex( model_name="dropcampaign", index=models.Index( condition=models.Q(("end_at__isnull", False), ("start_at__isnull", False)), fields=["start_at", "end_at"], name="campaign_active_partial_idx" ), ), migrations.AddConstraint( model_name="dropcampaign", constraint=models.CheckConstraint( condition=models.Q(("start_at__isnull", True), ("end_at__isnull", True), ("end_at__gt", models.F("start_at")), _connector="OR"), name="campaign_valid_date_range", ), ), migrations.AddIndex( model_name="game", index=models.Index(fields=["display_name"], name="twitch_game_display_a35ba3_idx"), ), migrations.AddIndex( model_name="game", index=models.Index(fields=["name"], name="twitch_game_name_c92c15_idx"), ), migrations.AddIndex( model_name="game", index=models.Index(fields=["slug"], name="twitch_game_slug_a02d3c_idx"), ), migrations.AddIndex( model_name="game", index=models.Index(condition=models.Q(("owner__isnull", False)), fields=["owner"], name="game_owner_partial_idx"), ), migrations.AddIndex( model_name="timebaseddrop", index=models.Index(fields=["name"], name="twitch_time_name_47c0f4_idx"), ), migrations.AddIndex( model_name="timebaseddrop", index=models.Index(fields=["start_at", "end_at"], name="twitch_time_start_a_c481f1_idx"), ), migrations.AddIndex( model_name="timebaseddrop", index=models.Index(fields=["required_minutes_watched"], name="twitch_time_require_82c30c_idx"), ), migrations.AddIndex( model_name="timebaseddrop", index=models.Index(fields=["campaign", "start_at", "required_minutes_watched"], name="twitch_time_campaig_4cc3b7_idx"), ), migrations.AddConstraint( model_name="timebaseddrop", constraint=models.CheckConstraint( condition=models.Q(("start_at__isnull", True), ("end_at__isnull", True), ("end_at__gt", models.F("start_at")), _connector="OR"), name="drop_valid_date_range", ), ), migrations.AddConstraint( model_name="timebaseddrop", constraint=models.CheckConstraint( condition=models.Q(("required_minutes_watched__isnull", True), ("required_minutes_watched__gte", 0), _connector="OR"), name="drop_positive_minutes", ), ), migrations.AddIndex( model_name="dropbenefitedge", index=models.Index(fields=["drop", "benefit"], name="twitch_drop_drop_id_5a574c_idx"), ), migrations.AddConstraint( model_name="dropbenefitedge", constraint=models.UniqueConstraint(fields=("drop", "benefit"), name="unique_drop_benefit"), ), migrations.AddIndex( model_name="twitchgamedata", index=models.Index(fields=["name"], name="twitch_twit_name_5dda5f_idx"), ), ]