Save channels to the database
This commit is contained in:
parent
76891694d3
commit
48783fadc2
5 changed files with 162 additions and 5 deletions
|
|
@ -12,7 +12,7 @@ from django.core.management.base import BaseCommand, CommandError, CommandParser
|
|||
from django.db import transaction
|
||||
from django.utils import timezone
|
||||
|
||||
from twitch.models import DropBenefit, DropBenefitEdge, DropCampaign, Game, Organization, TimeBasedDrop
|
||||
from twitch.models import Channel, DropBenefit, DropBenefitEdge, DropCampaign, Game, Organization, TimeBasedDrop
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from datetime import datetime
|
||||
|
|
@ -97,10 +97,15 @@ class Command(BaseCommand):
|
|||
for p in paths:
|
||||
try:
|
||||
path: Path = Path(p)
|
||||
processed_path: Path = path / processed_dir
|
||||
processed_path.mkdir(exist_ok=True)
|
||||
|
||||
self.validate_path(path)
|
||||
|
||||
# For files, use the parent directory for processed files
|
||||
if path.is_file():
|
||||
processed_path: Path = path.parent / processed_dir
|
||||
else:
|
||||
processed_path: Path = path / processed_dir
|
||||
|
||||
processed_path.mkdir(exist_ok=True)
|
||||
self.process_drops(continue_on_error=continue_on_error, path=path, processed_path=processed_path)
|
||||
|
||||
except CommandError as e:
|
||||
|
|
@ -528,6 +533,10 @@ class Command(BaseCommand):
|
|||
Returns:
|
||||
Returns the DropCampaign object.
|
||||
"""
|
||||
# Extract allow data from campaign_data
|
||||
allow_data = campaign_data.get("allow", {})
|
||||
allow_is_enabled = allow_data.get("isEnabled")
|
||||
|
||||
drop_campaign_defaults: dict[str, Any] = {
|
||||
"game": game,
|
||||
"name": campaign_data.get("name"),
|
||||
|
|
@ -538,6 +547,7 @@ class Command(BaseCommand):
|
|||
"start_at": parse_date(campaign_data.get("startAt") or campaign_data.get("startsAt")),
|
||||
"end_at": parse_date(campaign_data.get("endAt") or campaign_data.get("endsAt")),
|
||||
"is_account_connected": campaign_data.get("self", {}).get("isAccountConnected"),
|
||||
"allow_is_enabled": allow_is_enabled,
|
||||
}
|
||||
# Run .strip() on all string fields to remove leading/trailing whitespace
|
||||
for key, value in drop_campaign_defaults.items():
|
||||
|
|
@ -551,6 +561,33 @@ class Command(BaseCommand):
|
|||
id=campaign_data["id"],
|
||||
defaults=drop_campaign_defaults,
|
||||
)
|
||||
|
||||
# Handle allow_channels (many-to-many relationship)
|
||||
allow_channels: list[dict[str, str]] = allow_data.get("channels", [])
|
||||
if allow_channels:
|
||||
channel_objects: list[Channel] = []
|
||||
for channel_data in allow_channels:
|
||||
channel_defaults: dict[str, str | None] = {
|
||||
"name": channel_data.get("name"),
|
||||
"display_name": channel_data.get("displayName"),
|
||||
}
|
||||
# Run .strip() on all string fields to remove leading/trailing whitespace
|
||||
for key, value in channel_defaults.items():
|
||||
if isinstance(value, str):
|
||||
channel_defaults[key] = value.strip()
|
||||
|
||||
# Filter out None values
|
||||
channel_defaults = {k: v for k, v in channel_defaults.items() if v is not None}
|
||||
|
||||
channel, _ = Channel.objects.update_or_create(
|
||||
id=channel_data["id"],
|
||||
defaults=channel_defaults,
|
||||
)
|
||||
channel_objects.append(channel)
|
||||
|
||||
# Set the many-to-many relationship
|
||||
drop_campaign.allow_channels.set(channel_objects)
|
||||
|
||||
if created:
|
||||
self.stdout.write(self.style.SUCCESS(f"Created new drop campaign: {drop_campaign.name} (ID: {drop_campaign.id})"))
|
||||
return drop_campaign
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
# Generated by Django 5.2.5 on 2025-09-08 17:08
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('twitch', '0012_dropbenefit_search_vector_game_search_vector_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='dropcampaign',
|
||||
name='allow_is_enabled',
|
||||
field=models.BooleanField(default=True, help_text='Whether the campaign allows participation.'),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Channel',
|
||||
fields=[
|
||||
('id', models.CharField(help_text='The unique Twitch identifier for the channel.', max_length=255, primary_key=True, serialize=False, verbose_name='Channel ID')),
|
||||
('name', models.CharField(db_index=True, help_text='The lowercase username of the channel.', max_length=255, verbose_name='Username')),
|
||||
('display_name', models.CharField(db_index=True, help_text='The display name of the channel (with proper capitalization).', max_length=255, 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.AddField(
|
||||
model_name='dropcampaign',
|
||||
name='allow_channels',
|
||||
field=models.ManyToManyField(blank=True, help_text='Channels that are allowed to participate in this campaign.', related_name='allowed_campaigns', to='twitch.channel'),
|
||||
),
|
||||
]
|
||||
|
|
@ -173,6 +173,50 @@ class Game(models.Model):
|
|||
return self.id
|
||||
|
||||
|
||||
class Channel(models.Model):
|
||||
"""Represents a Twitch channel that can participate in drop campaigns."""
|
||||
|
||||
id = models.CharField(
|
||||
max_length=255,
|
||||
primary_key=True,
|
||||
verbose_name="Channel ID",
|
||||
help_text="The unique Twitch identifier for the channel.",
|
||||
)
|
||||
name = models.CharField(
|
||||
max_length=255,
|
||||
db_index=True,
|
||||
verbose_name="Username",
|
||||
help_text="The lowercase username of the channel.",
|
||||
)
|
||||
display_name = models.CharField(
|
||||
max_length=255,
|
||||
db_index=True,
|
||||
verbose_name="Display Name",
|
||||
help_text="The display name of the channel (with proper capitalization).",
|
||||
)
|
||||
|
||||
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.",
|
||||
)
|
||||
|
||||
class Meta:
|
||||
ordering = ["display_name"]
|
||||
indexes: ClassVar[list] = [
|
||||
models.Index(fields=["name"]),
|
||||
models.Index(fields=["display_name"]),
|
||||
]
|
||||
|
||||
def __str__(self) -> str:
|
||||
"""Return a string representation of the channel."""
|
||||
return self.display_name or self.name or self.id
|
||||
|
||||
|
||||
class DropCampaign(models.Model):
|
||||
"""Represents a Twitch drop campaign."""
|
||||
|
||||
|
|
@ -224,6 +268,16 @@ class DropCampaign(models.Model):
|
|||
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.",
|
||||
)
|
||||
allow_channels = models.ManyToManyField(
|
||||
Channel,
|
||||
blank=True,
|
||||
related_name="allowed_campaigns",
|
||||
help_text="Channels that are allowed to participate in this campaign.",
|
||||
)
|
||||
|
||||
# PostgreSQL full-text search field
|
||||
search_vector = SearchVectorField(null=True, blank=True)
|
||||
|
|
|
|||
|
|
@ -532,7 +532,8 @@ def dashboard(request: HttpRequest) -> HttpResponse:
|
|||
Prefetch(
|
||||
"time_based_drops",
|
||||
queryset=TimeBasedDrop.objects.prefetch_related("benefits"),
|
||||
)
|
||||
),
|
||||
"allow_channels",
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue