Fix scraper and other things

This commit is contained in:
2024-08-01 16:52:14 +02:00
parent 7ac017e4ca
commit 9252e41a15
7 changed files with 410 additions and 58 deletions

View File

@ -10,12 +10,12 @@
</div> </div>
<div class="col-md-10"> <div class="col-md-10">
<div class="card-body"> <div class="card-body">
<h2 class="card-title h5">{{ campaign.name }}</h2> <h2 class="card-title h5" id="#reward-{{ campaign.id }}">
<a href="#campaign-{{ campaign.id }}" class="plain-text-item">{{ campaign.name }}</a>
</h2>
<p class="card-text text-muted">{{ campaign.summary }}</p> <p class="card-text text-muted">{{ campaign.summary }}</p>
<p> <p class="mb-2 text-muted">
Starts at: <abbr title="{{ campaign.starts_at|date:'l d F H:i e' }}">{{ campaign.starts_at }}</abbr> Ends in: <abbr title="{{ campaign.starts_at|date:'l d F H:i' }} - {{ campaign.ends_at|date:'l d F H:i e' }}">{{ campaign.ends_at|timeuntil }}</abbr>
<br>
Ends at: <abbr title="{{ campaign.ends_at|date:'l d F H:i e' }}">{{ campaign.ends_at|timeuntil }}</abbr>
</p> </p>
<a href="{{ campaign.external_url }}" <a href="{{ campaign.external_url }}"
class="btn btn-primary" class="btn btn-primary"
@ -40,10 +40,6 @@
loading="lazy"> loading="lazy">
<div> <div>
<strong>{{ reward.name }}</strong> <strong>{{ reward.name }}</strong>
<br>
<a href="{{ reward.redemption_url }}"
class="btn btn-sm btn-link"
target="_blank">Redeem</a>
</div> </div>
</div> </div>
{% endfor %} {% endfor %}

View File

@ -0,0 +1,12 @@
<div class="position-sticky d-none d-lg-block toc">
<div class="card">
<div class="card-body">
<div id="toc-list" class="list-group">
{% for campaign in reward_campaigns %}
<a class="list-group-item list-group-item-action plain-text-item"
href="#reward-{{ campaign.id }}">{{ campaign }}</a>
{% endfor %}
</div>
</div>
</div>
</div>

View File

@ -3,6 +3,8 @@
{% block content %} {% block content %}
<div class="container mt-4"> <div class="container mt-4">
<div class="row"> <div class="row">
<div class="col-lg-3">{% include "partials/reward_campaigns_toc.html" %}</div>
<div class="col-lg-9">
<h2>Reward Campaigns</h2> <h2>Reward Campaigns</h2>
<div> <div>
{% for campaign in reward_campaigns %} {% for campaign in reward_campaigns %}
@ -11,4 +13,5 @@
</div> </div>
</div> </div>
</div> </div>
</div>
{% endblock content %} {% endblock content %}

View File

@ -279,6 +279,8 @@ async def add_drop_campaign(json_data: dict) -> None:
# Add channels to Allow # Add channels to Allow
if allow: if allow:
channel_data: list[dict] = allow_data.get("channels", []) channel_data: list[dict] = allow_data.get("channels", [])
if channel_data:
for json_channel in channel_data: for json_channel in channel_data:
channel, _ = await add_or_get_channel(json_channel) channel, _ = await add_or_get_channel(json_channel)
if channel: if channel:
@ -446,13 +448,13 @@ async def add_reward_campaign(json_data: dict) -> None:
defaults={ defaults={
"name": campaign.get("name"), "name": campaign.get("name"),
"brand": campaign.get("brand"), "brand": campaign.get("brand"),
"starts_at": campaign.get("startAt"), "starts_at": campaign.get("startsAt"),
"ends_at": campaign.get("endAt"), "ends_at": campaign.get("endsAt"),
"status": campaign.get("status"), "status": campaign.get("status"),
"summary": campaign.get("summary"), "summary": campaign.get("summary"),
"instructions": campaign.get("instructions"), "instructions": campaign.get("instructions"),
"external_url": campaign.get("externalURL"), "external_url": campaign.get("externalURL"),
"reward_value_url_params": campaign.get("rewardValueURLParams"), "reward_value_url_param": campaign.get("rewardValueURLParam"),
"about_url": campaign.get("aboutURL"), "about_url": campaign.get("aboutURL"),
"is_sitewide": campaign.get("isSitewide"), "is_sitewide": campaign.get("isSitewide"),
"game": game, "game": game,
@ -477,7 +479,7 @@ class Command(BaseCommand):
self, self,
playwright: Playwright, playwright: Playwright,
) -> list[dict[str, typing.Any]]: ) -> list[dict[str, typing.Any]]:
args = [] args: list[str] = []
# disable navigator.webdriver:true flag # disable navigator.webdriver:true flag
args.append("--disable-blink-features=AutomationControlled") args.append("--disable-blink-features=AutomationControlled")
@ -546,13 +548,15 @@ class Command(BaseCommand):
if "rewardCampaignsAvailableToUser" in campaign["data"]: if "rewardCampaignsAvailableToUser" in campaign["data"]:
await add_reward_campaign(campaign) await add_reward_campaign(campaign)
if "dropCampaign" in campaign.get("data", {}).get("user", {}): # noqa: SIM102 if "dropCampaign" in campaign.get("data", {}).get("user", {}):
if not campaign["data"]["user"]["dropCampaign"]: if not campaign["data"]["user"]["dropCampaign"]:
logger.warning("No drop campaign found")
continue continue
await add_drop_campaign(campaign)
if "dropCampaigns" in campaign.get("data", {}).get("user", {}): if "dropCampaigns" in campaign.get("data", {}).get("user", {}):
msg = "Multiple dropCampaigns not supported" for drop_campaign in campaign["data"]["user"]["dropCampaigns"]:
raise NotImplementedError(msg) await add_drop_campaign(drop_campaign)
return json_data return json_data

View File

@ -0,0 +1,278 @@
# Generated by Django 5.1rc1 on 2024-08-01 14:27
import auto_prefetch
import django.db.models.deletion
import django.db.models.manager
from django.db import migrations
from django.db.migrations.operations.base import Operation
class Migration(migrations.Migration):
dependencies: list[tuple[str, str]] = [
("twitch_app", "0007_alter_dropcampaign_time_based_drops"),
]
operations: list[Operation] = [
migrations.AlterModelOptions(
name="allow",
options={"base_manager_name": "prefetch_manager"},
),
migrations.AlterModelOptions(
name="benefit",
options={"base_manager_name": "prefetch_manager"},
),
migrations.AlterModelOptions(
name="benefitedge",
options={"base_manager_name": "prefetch_manager"},
),
migrations.AlterModelOptions(
name="channel",
options={"base_manager_name": "prefetch_manager"},
),
migrations.AlterModelOptions(
name="dropcampaign",
options={"base_manager_name": "prefetch_manager"},
),
migrations.AlterModelOptions(
name="game",
options={"base_manager_name": "prefetch_manager"},
),
migrations.AlterModelOptions(
name="image",
options={"base_manager_name": "prefetch_manager"},
),
migrations.AlterModelOptions(
name="owner",
options={"base_manager_name": "prefetch_manager"},
),
migrations.AlterModelOptions(
name="reward",
options={"base_manager_name": "prefetch_manager"},
),
migrations.AlterModelOptions(
name="rewardcampaign",
options={"base_manager_name": "prefetch_manager"},
),
migrations.AlterModelOptions(
name="timebaseddrop",
options={"base_manager_name": "prefetch_manager"},
),
migrations.AlterModelOptions(
name="unlockrequirements",
options={"base_manager_name": "prefetch_manager"},
),
migrations.AlterModelManagers(
name="allow",
managers=[
("objects", django.db.models.manager.Manager()),
("prefetch_manager", django.db.models.manager.Manager()),
],
),
migrations.AlterModelManagers(
name="benefit",
managers=[
("objects", django.db.models.manager.Manager()),
("prefetch_manager", django.db.models.manager.Manager()),
],
),
migrations.AlterModelManagers(
name="benefitedge",
managers=[
("objects", django.db.models.manager.Manager()),
("prefetch_manager", django.db.models.manager.Manager()),
],
),
migrations.AlterModelManagers(
name="channel",
managers=[
("objects", django.db.models.manager.Manager()),
("prefetch_manager", django.db.models.manager.Manager()),
],
),
migrations.AlterModelManagers(
name="dropcampaign",
managers=[
("objects", django.db.models.manager.Manager()),
("prefetch_manager", django.db.models.manager.Manager()),
],
),
migrations.AlterModelManagers(
name="game",
managers=[
("objects", django.db.models.manager.Manager()),
("prefetch_manager", django.db.models.manager.Manager()),
],
),
migrations.AlterModelManagers(
name="image",
managers=[
("objects", django.db.models.manager.Manager()),
("prefetch_manager", django.db.models.manager.Manager()),
],
),
migrations.AlterModelManagers(
name="owner",
managers=[
("objects", django.db.models.manager.Manager()),
("prefetch_manager", django.db.models.manager.Manager()),
],
),
migrations.AlterModelManagers(
name="reward",
managers=[
("objects", django.db.models.manager.Manager()),
("prefetch_manager", django.db.models.manager.Manager()),
],
),
migrations.AlterModelManagers(
name="rewardcampaign",
managers=[
("objects", django.db.models.manager.Manager()),
("prefetch_manager", django.db.models.manager.Manager()),
],
),
migrations.AlterModelManagers(
name="timebaseddrop",
managers=[
("objects", django.db.models.manager.Manager()),
("prefetch_manager", django.db.models.manager.Manager()),
],
),
migrations.AlterModelManagers(
name="unlockrequirements",
managers=[
("objects", django.db.models.manager.Manager()),
("prefetch_manager", django.db.models.manager.Manager()),
],
),
migrations.AlterField(
model_name="benefit",
name="game",
field=auto_prefetch.ForeignKey(
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="benefits",
to="twitch_app.game",
),
),
migrations.AlterField(
model_name="benefit",
name="owner_organization",
field=auto_prefetch.ForeignKey(
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="benefits",
to="twitch_app.owner",
),
),
migrations.AlterField(
model_name="benefitedge",
name="benefit",
field=auto_prefetch.ForeignKey(
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="benefit_edges",
to="twitch_app.benefit",
),
),
migrations.AlterField(
model_name="dropcampaign",
name="allow",
field=auto_prefetch.ForeignKey(
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="drop_campaigns",
to="twitch_app.allow",
),
),
migrations.AlterField(
model_name="dropcampaign",
name="game",
field=auto_prefetch.ForeignKey(
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="drop_campaigns",
to="twitch_app.game",
),
),
migrations.AlterField(
model_name="dropcampaign",
name="owner",
field=auto_prefetch.ForeignKey(
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="drop_campaigns",
to="twitch_app.owner",
),
),
migrations.AlterField(
model_name="reward",
name="banner_image",
field=auto_prefetch.ForeignKey(
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="banner_rewards",
to="twitch_app.image",
),
),
migrations.AlterField(
model_name="reward",
name="thumbnail_image",
field=auto_prefetch.ForeignKey(
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="thumbnail_rewards",
to="twitch_app.image",
),
),
migrations.AlterField(
model_name="rewardcampaign",
name="game",
field=auto_prefetch.ForeignKey(
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="reward_campaigns",
to="twitch_app.game",
),
),
migrations.AlterField(
model_name="rewardcampaign",
name="image",
field=auto_prefetch.ForeignKey(
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="reward_campaigns",
to="twitch_app.image",
),
),
migrations.AlterField(
model_name="rewardcampaign",
name="unlock_requirements",
field=auto_prefetch.ForeignKey(
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="reward_campaigns",
to="twitch_app.unlockrequirements",
),
),
migrations.AlterField(
model_name="timebaseddrop",
name="game",
field=auto_prefetch.ForeignKey(
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="time_based_drops",
to="twitch_app.game",
),
),
migrations.AlterField(
model_name="timebaseddrop",
name="owner_organization",
field=auto_prefetch.ForeignKey(
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="time_based_drops",
to="twitch_app.owner",
),
),
]

View File

@ -0,0 +1,48 @@
# Generated by Django 5.1rc1 on 2024-08-01 14:48
from django.db import migrations, models
from django.db.migrations.operations.base import Operation
class Migration(migrations.Migration):
dependencies: list[tuple[str, str]] = [
("twitch_app", "0008_alter_allow_options_alter_benefit_options_and_more"),
]
operations: list[Operation] = [
migrations.AlterField(
model_name="benefit",
name="entitlement_limit",
field=models.TextField(null=True),
),
migrations.AlterField(
model_name="benefitedge",
name="entitlement_limit",
field=models.TextField(null=True),
),
migrations.AlterField(
model_name="channel",
name="id",
field=models.TextField(primary_key=True, serialize=False),
),
migrations.AlterField(
model_name="owner",
name="id",
field=models.TextField(primary_key=True, serialize=False),
),
migrations.AlterField(
model_name="timebaseddrop",
name="entitlement_limit",
field=models.TextField(null=True),
),
migrations.AlterField(
model_name="unlockrequirements",
name="minute_watched_goal",
field=models.TextField(null=True),
),
migrations.AlterField(
model_name="unlockrequirements",
name="subs_goal",
field=models.TextField(null=True),
),
]

View File

@ -1,7 +1,8 @@
import auto_prefetch
from django.db import models from django.db import models
class Game(models.Model): class Game(auto_prefetch.Model):
"""The game that the reward is for. """The game that the reward is for.
Used for reward campaigns (buy subs) and drop campaigns (watch games). Used for reward campaigns (buy subs) and drop campaigns (watch games).
@ -33,7 +34,7 @@ class Game(models.Model):
return f"https://www.twitch.tv/directory/game/{self.slug}" return f"https://www.twitch.tv/directory/game/{self.slug}"
class Image(models.Model): class Image(auto_prefetch.Model):
"""An image model representing URLs and type. """An image model representing URLs and type.
Attributes: Attributes:
@ -54,7 +55,7 @@ class Image(models.Model):
return self.image1_x_url or "Unknown" return self.image1_x_url or "Unknown"
class Reward(models.Model): class Reward(auto_prefetch.Model):
"""The actual reward you get when you complete the requirements. """The actual reward you get when you complete the requirements.
Attributes: Attributes:
@ -88,8 +89,13 @@ class Reward(models.Model):
id = models.TextField(primary_key=True) id = models.TextField(primary_key=True)
name = models.TextField(null=True, blank=True) name = models.TextField(null=True, blank=True)
banner_image = models.ForeignKey(Image, related_name="banner_rewards", on_delete=models.CASCADE, null=True) banner_image = auto_prefetch.ForeignKey(Image, related_name="banner_rewards", on_delete=models.CASCADE, null=True)
thumbnail_image = models.ForeignKey(Image, related_name="thumbnail_rewards", on_delete=models.CASCADE, null=True) thumbnail_image = auto_prefetch.ForeignKey(
Image,
related_name="thumbnail_rewards",
on_delete=models.CASCADE,
null=True,
)
earnable_until = models.DateTimeField(null=True) earnable_until = models.DateTimeField(null=True)
redemption_instructions = models.TextField(null=True, blank=True) redemption_instructions = models.TextField(null=True, blank=True)
redemption_url = models.URLField(null=True, blank=True) redemption_url = models.URLField(null=True, blank=True)
@ -99,7 +105,7 @@ class Reward(models.Model):
return self.name or "Unknown" return self.name or "Unknown"
class UnlockRequirements(models.Model): class UnlockRequirements(auto_prefetch.Model):
"""Requirements to unlock a reward. """Requirements to unlock a reward.
Attributes: Attributes:
@ -115,15 +121,15 @@ class UnlockRequirements(models.Model):
} }
""" """
subs_goal = models.PositiveBigIntegerField(null=True) subs_goal = models.TextField(null=True)
minute_watched_goal = models.PositiveBigIntegerField(null=True) minute_watched_goal = models.TextField(null=True)
typename = models.TextField(null=True, blank=True) typename = models.TextField(null=True, blank=True)
def __str__(self) -> str: def __str__(self) -> str:
return f"{self.subs_goal} subs and {self.minute_watched_goal} minutes watched" return f"{self.subs_goal} subs and {self.minute_watched_goal} minutes watched"
class RewardCampaign(models.Model): class RewardCampaign(auto_prefetch.Model):
"""Represents a reward campaign. """Represents a reward campaign.
Attributes: Attributes:
@ -207,14 +213,14 @@ class RewardCampaign(models.Model):
reward_value_url_param = models.TextField(null=True, blank=True) reward_value_url_param = models.TextField(null=True, blank=True)
about_url = models.URLField(null=True, blank=True) about_url = models.URLField(null=True, blank=True)
is_sitewide = models.BooleanField(null=True) is_sitewide = models.BooleanField(null=True)
game = models.ForeignKey(Game, on_delete=models.CASCADE, related_name="reward_campaigns", null=True) game = auto_prefetch.ForeignKey(Game, on_delete=models.CASCADE, related_name="reward_campaigns", null=True)
unlock_requirements = models.ForeignKey( unlock_requirements = auto_prefetch.ForeignKey(
UnlockRequirements, UnlockRequirements,
on_delete=models.CASCADE, on_delete=models.CASCADE,
related_name="reward_campaigns", related_name="reward_campaigns",
null=True, null=True,
) )
image = models.ForeignKey(Image, on_delete=models.CASCADE, related_name="reward_campaigns", null=True) image = auto_prefetch.ForeignKey(Image, on_delete=models.CASCADE, related_name="reward_campaigns", null=True)
rewards = models.ManyToManyField(Reward, related_name="reward_campaigns") rewards = models.ManyToManyField(Reward, related_name="reward_campaigns")
typename = models.TextField(null=True, blank=True) typename = models.TextField(null=True, blank=True)
@ -222,7 +228,7 @@ class RewardCampaign(models.Model):
return self.name or "Unknown" return self.name or "Unknown"
class Channel(models.Model): class Channel(auto_prefetch.Model):
"""Represents a Twitch channel. """Represents a Twitch channel.
Attributes: Attributes:
@ -240,7 +246,7 @@ class Channel(models.Model):
} }
""" """
id = models.PositiveBigIntegerField(primary_key=True) id = models.TextField(primary_key=True)
display_name = models.TextField(null=True, blank=True) display_name = models.TextField(null=True, blank=True)
name = models.TextField(null=True, blank=True) name = models.TextField(null=True, blank=True)
typename = models.TextField(null=True, blank=True) typename = models.TextField(null=True, blank=True)
@ -252,7 +258,7 @@ class Channel(models.Model):
return f"https://www.twitch.tv/{self.name}" return f"https://www.twitch.tv/{self.name}"
class Allow(models.Model): class Allow(auto_prefetch.Model):
"""List of channels that you can watch to earn rewards. """List of channels that you can watch to earn rewards.
Attributes: Attributes:
@ -283,7 +289,7 @@ class Allow(models.Model):
return f"{self.channels.count()} channels" return f"{self.channels.count()} channels"
class Owner(models.Model): class Owner(auto_prefetch.Model):
"""Represents the owner of the reward campaign. """Represents the owner of the reward campaign.
Attributes: Attributes:
@ -294,14 +300,14 @@ class Owner(models.Model):
JSON example: JSON example:
"game": { "game": {
"id": "491487", "id": "491487", # Can also be a string like 'c57a089c-088f-4402-b02d-c13281b3397e'
"slug": "dead-by-daylight", "slug": "dead-by-daylight",
"displayName": "Dead by Daylight", "displayName": "Dead by Daylight",
"__typename": "Game" "__typename": "Game"
}," },"
""" """
id = models.PositiveBigIntegerField(primary_key=True) id = models.TextField(primary_key=True)
slug = models.TextField(null=True, blank=True) slug = models.TextField(null=True, blank=True)
display_name = models.TextField(null=True, blank=True) display_name = models.TextField(null=True, blank=True)
typename = models.TextField(null=True, blank=True) typename = models.TextField(null=True, blank=True)
@ -313,7 +319,7 @@ class Owner(models.Model):
return f"https://www.twitch.tv/{self.slug}" return f"https://www.twitch.tv/{self.slug}"
class Benefit(models.Model): class Benefit(auto_prefetch.Model):
"""Represents a benefit that you can earn. """Represents a benefit that you can earn.
Attributes: Attributes:
@ -351,19 +357,19 @@ class Benefit(models.Model):
id = models.TextField(primary_key=True) id = models.TextField(primary_key=True)
created_at = models.DateTimeField(null=True) created_at = models.DateTimeField(null=True)
entitlement_limit = models.PositiveBigIntegerField(null=True) entitlement_limit = models.TextField(null=True)
game = models.ForeignKey(Game, on_delete=models.CASCADE, related_name="benefits", null=True) game = auto_prefetch.ForeignKey(Game, on_delete=models.CASCADE, related_name="benefits", null=True)
image_asset_url = models.URLField(null=True, blank=True) image_asset_url = models.URLField(null=True, blank=True)
is_ios_available = models.BooleanField(null=True) is_ios_available = models.BooleanField(null=True)
name = models.TextField(null=True, blank=True) name = models.TextField(null=True, blank=True)
owner_organization = models.ForeignKey(Owner, on_delete=models.CASCADE, related_name="benefits", null=True) owner_organization = auto_prefetch.ForeignKey(Owner, on_delete=models.CASCADE, related_name="benefits", null=True)
typename = models.TextField(null=True, blank=True) typename = models.TextField(null=True, blank=True)
def __str__(self) -> str: def __str__(self) -> str:
return self.name or "Unknown" return self.name or "Unknown"
class BenefitEdge(models.Model): class BenefitEdge(auto_prefetch.Model):
"""Represents a benefit edge. """Represents a benefit edge.
Attributes: Attributes:
@ -400,8 +406,8 @@ class BenefitEdge(models.Model):
], ],
""" """
benefit = models.ForeignKey(Benefit, on_delete=models.CASCADE, related_name="benefit_edges", null=True) benefit = auto_prefetch.ForeignKey(Benefit, on_delete=models.CASCADE, related_name="benefit_edges", null=True)
entitlement_limit = models.PositiveBigIntegerField(null=True) entitlement_limit = models.TextField(null=True)
typename = models.TextField(null=True, blank=True) typename = models.TextField(null=True, blank=True)
def __str__(self) -> str: def __str__(self) -> str:
@ -409,7 +415,7 @@ class BenefitEdge(models.Model):
return f"{benefit_name} - {self.entitlement_limit}" return f"{benefit_name} - {self.entitlement_limit}"
class TimeBasedDrop(models.Model): class TimeBasedDrop(auto_prefetch.Model):
"""Represents a time-based drop. """Represents a time-based drop.
Attributes: Attributes:
@ -459,19 +465,24 @@ class TimeBasedDrop(models.Model):
id = models.TextField(primary_key=True) id = models.TextField(primary_key=True)
created_at = models.DateTimeField(null=True) created_at = models.DateTimeField(null=True)
entitlement_limit = models.PositiveBigIntegerField(null=True) entitlement_limit = models.TextField(null=True)
game = models.ForeignKey(Game, on_delete=models.CASCADE, related_name="time_based_drops", null=True) game = auto_prefetch.ForeignKey(Game, on_delete=models.CASCADE, related_name="time_based_drops", null=True)
image_asset_url = models.URLField(null=True, blank=True) image_asset_url = models.URLField(null=True, blank=True)
is_ios_available = models.BooleanField(null=True) is_ios_available = models.BooleanField(null=True)
name = models.TextField(null=True, blank=True) name = models.TextField(null=True, blank=True)
owner_organization = models.ForeignKey(Owner, on_delete=models.CASCADE, related_name="time_based_drops", null=True) owner_organization = auto_prefetch.ForeignKey(
Owner,
on_delete=models.CASCADE,
related_name="time_based_drops",
null=True,
)
typename = models.TextField(null=True, blank=True) typename = models.TextField(null=True, blank=True)
def __str__(self) -> str: def __str__(self) -> str:
return self.name or "Unknown" return self.name or "Unknown"
class DropCampaign(models.Model): class DropCampaign(auto_prefetch.Model):
"""Represents a drop campaign. """Represents a drop campaign.
Attributes: Attributes:
@ -492,16 +503,16 @@ class DropCampaign(models.Model):
""" """
id = models.TextField(primary_key=True) id = models.TextField(primary_key=True)
allow = models.ForeignKey(Allow, on_delete=models.CASCADE, related_name="drop_campaigns", null=True) allow = auto_prefetch.ForeignKey(Allow, on_delete=models.CASCADE, related_name="drop_campaigns", null=True)
account_link_url = models.URLField(null=True, blank=True) account_link_url = models.URLField(null=True, blank=True)
description = models.TextField(null=True, blank=True) description = models.TextField(null=True, blank=True)
details_url = models.URLField(null=True, blank=True) details_url = models.URLField(null=True, blank=True)
ends_at = models.DateTimeField(null=True) ends_at = models.DateTimeField(null=True)
# event_based_drops = ???? # event_based_drops = ????
game = models.ForeignKey(Game, on_delete=models.CASCADE, related_name="drop_campaigns", null=True) game = auto_prefetch.ForeignKey(Game, on_delete=models.CASCADE, related_name="drop_campaigns", null=True)
image_url = models.URLField(null=True, blank=True) image_url = models.URLField(null=True, blank=True)
name = models.TextField(null=True, blank=True) name = models.TextField(null=True, blank=True)
owner = models.ForeignKey(Owner, on_delete=models.CASCADE, related_name="drop_campaigns", null=True) owner = auto_prefetch.ForeignKey(Owner, on_delete=models.CASCADE, related_name="drop_campaigns", null=True)
starts_at = models.DateTimeField(null=True) starts_at = models.DateTimeField(null=True)
status = models.TextField(null=True, blank=True) status = models.TextField(null=True, blank=True)
time_based_drops = models.ManyToManyField(TimeBasedDrop, related_name="drop_campaigns") time_based_drops = models.ManyToManyField(TimeBasedDrop, related_name="drop_campaigns")