# Generated by Django 6.0 on 2025-12-11 10:49 import django.db.models.deletion from django.db import migrations from django.db import models class Migration(migrations.Migration): """Initial migration for Twitch-related models.""" initial = True dependencies = [] operations = [ migrations.CreateModel( name="Game", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ( "twitch_id", models.TextField(unique=True, verbose_name="Twitch game ID"), ), ( "slug", models.TextField( blank=True, default="", help_text="Short unique identifier for the game.", max_length=200, verbose_name="Slug", ), ), ("name", models.TextField(blank=True, default="", verbose_name="Name")), ( "display_name", models.TextField( blank=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, 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.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ( "twitch_id", models.TextField( help_text="The unique Twitch identifier for the channel.", unique=True, verbose_name="Channel ID", ), ), ( "name", models.TextField( help_text="The lowercase username of the channel.", verbose_name="Username", ), ), ( "display_name", models.TextField( help_text="The display name of the channel (with proper capitalization).", verbose_name="Display Name", ), ), ( "added_at", models.DateTimeField( auto_now_add=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=["display_name"], name="twitch_chan_display_2bf213_idx", ), models.Index(fields=["name"], name="twitch_chan_name_15d566_idx"), models.Index( fields=["twitch_id"], name="twitch_chan_twitch__c8bbc6_idx", ), models.Index( fields=["added_at"], name="twitch_chan_added_a_5ce7b4_idx", ), models.Index( fields=["updated_at"], name="twitch_chan_updated_828594_idx", ), ], }, ), migrations.CreateModel( name="DropBenefit", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ( "twitch_id", models.TextField( editable=False, help_text="The Twitch ID for this benefit.", unique=True, ), ), ( "name", models.TextField( blank=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( 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, default="", help_text="Type of distribution for this benefit.", max_length=50, ), ), ( "added_at", models.DateTimeField( auto_now_add=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=["-created_at"], name="twitch_drop_created_5d2280_idx", ), models.Index( fields=["twitch_id"], name="twitch_drop_twitch__6eab58_idx", ), models.Index(fields=["name"], name="twitch_drop_name_7125ff_idx"), models.Index( fields=["distribution_type"], name="twitch_drop_distrib_08b224_idx", ), models.Index( fields=["is_ios_available"], name="twitch_drop_is_ios__5f3dcf_idx", ), models.Index( fields=["added_at"], name="twitch_drop_added_a_fba438_idx", ), models.Index( fields=["updated_at"], name="twitch_drop_updated_7aaae3_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, 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.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ( "twitch_id", models.TextField( editable=False, help_text="The Twitch ID for this campaign.", unique=True, ), ), ("name", models.TextField(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, help_text="Datetime when the campaign starts.", null=True, ), ), ( "end_at", models.DateTimeField( blank=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.", ), ), ( "operation_name", models.TextField( blank=True, default="", help_text="The GraphQL operation name used to fetch this campaign data (e.g., 'ViewerDropsDashboard').", ), ), ( "added_at", models.DateTimeField( auto_now_add=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.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ( "twitch_id", models.TextField( editable=False, help_text="The unique Twitch identifier for the organization.", unique=True, verbose_name="Organization ID", ), ), ( "name", models.TextField( help_text="Display name of the organization.", unique=True, verbose_name="Name", ), ), ( "added_at", models.DateTimeField( auto_now_add=True, help_text="Timestamp when this organization record was created.", verbose_name="Added At", ), ), ( "updated_at", models.DateTimeField( auto_now=True, help_text="Timestamp when this organization record was last updated.", verbose_name="Updated At", ), ), ], options={ "ordering": ["name"], "indexes": [ models.Index(fields=["name"], name="twitch_orga_name_febe72_idx"), models.Index( fields=["twitch_id"], name="twitch_orga_twitch__b89b29_idx", ), models.Index( fields=["added_at"], name="twitch_orga_added_a_8297ac_idx", ), models.Index( fields=["updated_at"], name="twitch_orga_updated_d7d431_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.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ( "twitch_id", models.TextField( editable=False, help_text="The Twitch ID for this time-based drop.", unique=True, ), ), ("name", models.TextField(help_text="Name of the time-based drop.")), ( "required_minutes_watched", models.PositiveIntegerField( blank=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, help_text="Datetime when this drop becomes available.", null=True, ), ), ( "end_at", models.DateTimeField( blank=True, help_text="Datetime when this drop expires.", null=True, ), ), ( "added_at", models.DateTimeField( auto_now_add=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.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ( "twitch_id", models.TextField( help_text="The Twitch ID for this game.", unique=True, verbose_name="Twitch Game ID", ), ), ("name", models.TextField(blank=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, 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=["-start_at"], name="twitch_drop_start_a_929f09_idx", ), ), migrations.AddIndex( model_name="dropcampaign", index=models.Index(fields=["end_at"], name="twitch_drop_end_at_6560b0_idx"), ), migrations.AddIndex( model_name="dropcampaign", index=models.Index(fields=["game"], name="twitch_drop_game_id_868e70_idx"), ), migrations.AddIndex( model_name="dropcampaign", index=models.Index( fields=["twitch_id"], name="twitch_drop_twitch__b717a1_idx", ), ), 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=["description"], name="twitch_drop_descrip_5bc290_idx", ), ), migrations.AddIndex( model_name="dropcampaign", index=models.Index( fields=["is_account_connected"], name="twitch_drop_is_acco_7e9078_idx", ), ), migrations.AddIndex( model_name="dropcampaign", index=models.Index( fields=["allow_is_enabled"], name="twitch_drop_allow_i_b64555_idx", ), ), migrations.AddIndex( model_name="dropcampaign", index=models.Index( fields=["operation_name"], name="twitch_drop_operati_8cfeb5_idx", ), ), migrations.AddIndex( model_name="dropcampaign", index=models.Index( fields=["added_at"], name="twitch_drop_added_a_babe28_idx", ), ), migrations.AddIndex( model_name="dropcampaign", index=models.Index( fields=["updated_at"], name="twitch_drop_updated_0df991_idx", ), ), migrations.AddIndex( model_name="dropcampaign", index=models.Index( fields=["game", "-start_at"], name="twitch_drop_game_id_5e9b01_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( fields=["start_at", "end_at", "game"], name="twitch_drop_start_a_b02d4c_idx", ), ), migrations.AddIndex( model_name="dropcampaign", index=models.Index( fields=["end_at", "-start_at"], name="twitch_drop_end_at_81e51b_idx", ), ), 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( fields=["twitch_id"], name="twitch_game_twitch__887f78_idx", ), ), migrations.AddIndex( model_name="game", index=models.Index(fields=["owner"], name="twitch_game_owner_i_398fa9_idx"), ), migrations.AddIndex( model_name="game", index=models.Index( fields=["added_at"], name="twitch_game_added_a_9e7e19_idx", ), ), migrations.AddIndex( model_name="game", index=models.Index( fields=["updated_at"], name="twitch_game_updated_01df03_idx", ), ), migrations.AddIndex( model_name="game", index=models.Index( fields=["owner", "display_name"], name="twitch_game_owner_i_7f9043_idx", ), ), migrations.AddIndex( model_name="timebaseddrop", index=models.Index( fields=["start_at"], name="twitch_time_start_a_13de4a_idx", ), ), migrations.AddIndex( model_name="timebaseddrop", index=models.Index(fields=["end_at"], name="twitch_time_end_at_3df95a_idx"), ), migrations.AddIndex( model_name="timebaseddrop", index=models.Index( fields=["campaign"], name="twitch_time_campaig_bbe349_idx", ), ), migrations.AddIndex( model_name="timebaseddrop", index=models.Index( fields=["twitch_id"], name="twitch_time_twitch__31707a_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=["required_minutes_watched"], name="twitch_time_require_82c30c_idx", ), ), migrations.AddIndex( model_name="timebaseddrop", index=models.Index( fields=["required_subs"], name="twitch_time_require_959431_idx", ), ), migrations.AddIndex( model_name="timebaseddrop", index=models.Index( fields=["added_at"], name="twitch_time_added_a_a7de2e_idx", ), ), migrations.AddIndex( model_name="timebaseddrop", index=models.Index( fields=["updated_at"], name="twitch_time_updated_9e9d9e_idx", ), ), migrations.AddIndex( model_name="timebaseddrop", index=models.Index( fields=["campaign", "start_at"], name="twitch_time_campaig_29ac87_idx", ), ), migrations.AddIndex( model_name="timebaseddrop", index=models.Index( fields=["campaign", "required_minutes_watched"], name="twitch_time_campaig_920ae4_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="dropbenefitedge", index=models.Index(fields=["drop"], name="twitch_drop_drop_id_3a2994_idx"), ), migrations.AddIndex( model_name="dropbenefitedge", index=models.Index( fields=["benefit"], name="twitch_drop_benefit_c92c87_idx", ), ), migrations.AddIndex( model_name="dropbenefitedge", index=models.Index( fields=["entitlement_limit"], name="twitch_drop_entitle_bee3a0_idx", ), ), migrations.AddIndex( model_name="dropbenefitedge", index=models.Index( fields=["added_at"], name="twitch_drop_added_a_2100ba_idx", ), ), migrations.AddIndex( model_name="dropbenefitedge", index=models.Index( fields=["updated_at"], name="twitch_drop_updated_00e3f2_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"), ), migrations.AddIndex( model_name="twitchgamedata", index=models.Index( fields=["twitch_id"], name="twitch_twit_twitch__2207e6_idx", ), ), migrations.AddIndex( model_name="twitchgamedata", index=models.Index(fields=["game"], name="twitch_twit_game_id_0d820a_idx"), ), migrations.AddIndex( model_name="twitchgamedata", index=models.Index( fields=["igdb_id"], name="twitch_twit_igdb_id_161335_idx", ), ), migrations.AddIndex( model_name="twitchgamedata", index=models.Index( fields=["added_at"], name="twitch_twit_added_a_2f4f36_idx", ), ), migrations.AddIndex( model_name="twitchgamedata", index=models.Index( fields=["updated_at"], name="twitch_twit_updated_ca8c4b_idx", ), ), ]