This commit is contained in:
2024-07-10 01:44:33 +02:00
parent ec75ce1ccb
commit 5ebcb665c2
21 changed files with 183 additions and 1328 deletions

View File

@ -1,11 +1,10 @@
from django.contrib import admin
from simple_history.admin import SimpleHistoryAdmin
from .models import DropBenefit, DropCampaign, Game, Organization, TimeBasedDrop
from .models import Drop, DropCampaign, Game, Organization
# https://django-simple-history.readthedocs.io/en/latest/admin.html
admin.site.register(DropBenefit, SimpleHistoryAdmin)
admin.site.register(Drop, SimpleHistoryAdmin)
admin.site.register(DropCampaign, SimpleHistoryAdmin)
admin.site.register(Game, SimpleHistoryAdmin)
admin.site.register(Organization, SimpleHistoryAdmin)
admin.site.register(TimeBasedDrop, SimpleHistoryAdmin)

View File

@ -5,11 +5,10 @@ from django.http import HttpRequest
from ninja import Router, Schema
from .models import (
DropBenefit,
Drop,
DropCampaign,
Game,
Organization,
TimeBasedDrop,
)
router = Router(
@ -98,13 +97,6 @@ def get_games(request: HttpRequest) -> BaseManager[Game]: # noqa: ARG001
return Game.objects.all()
# http://localhost:8000/api/twitch/drop_benefits
@router.get("/drop_benefits", response=list[DropBenefitSchema])
def get_drop_benefits(request: HttpRequest) -> BaseManager[DropBenefit]: # noqa: ARG001
"""Get all drop benefits."""
return DropBenefit.objects.all()
# http://localhost:8000/api/twitch/drop_campaigns
@router.get("/drop_campaigns", response=list[DropCampaignSchema])
def get_drop_campaigns(request: HttpRequest) -> BaseManager[DropCampaign]: # noqa: ARG001
@ -112,8 +104,8 @@ def get_drop_campaigns(request: HttpRequest) -> BaseManager[DropCampaign]: # no
return DropCampaign.objects.all()
# http://localhost:8000/api/twitch/time_based_drops
@router.get("/time_based_drops", response=list[TimeBasedDropSchema])
def get_time_based_drops(request: HttpRequest) -> BaseManager[TimeBasedDrop]: # noqa: ARG001
# http://localhost:8000/api/twitch/drops
@router.get("/drops", response=list[TimeBasedDropSchema])
def get_drops(request: HttpRequest) -> BaseManager[Drop]: # noqa: ARG001
"""Get all time-based drops."""
return TimeBasedDrop.objects.all()
return Drop.objects.all()

View File

@ -11,11 +11,10 @@ from playwright.async_api import Playwright, async_playwright
from playwright.async_api._generated import Response
from twitch_app.models import (
DropBenefit,
Drop,
DropCampaign,
Game,
Organization,
TimeBasedDrop,
)
if TYPE_CHECKING:
@ -35,10 +34,10 @@ if not data_dir:
msg = "DATA_DIR is not set in settings.py"
raise ValueError(msg)
logger: logging.Logger = logging.getLogger("twitch.management.commands.scrape_twitch")
logger: logging.Logger = logging.getLogger(__name__)
async def insert_data(data: dict) -> None: # noqa: PLR0914, C901
async def insert_data(data: dict) -> None: # noqa: C901, PLR0914
"""Insert data into the database.
Args:
@ -52,6 +51,7 @@ async def insert_data(data: dict) -> None: # noqa: PLR0914, C901
user_data["id"]
drop_campaign_data = user_data["dropCampaign"]
if not drop_campaign_data:
logger.debug("No drop campaign data found")
return
# Create or get the organization
@ -62,6 +62,8 @@ async def insert_data(data: dict) -> None: # noqa: PLR0914, C901
)
if created:
logger.debug("Organization created: %s", owner)
else:
logger.debug("Organization found: %s", owner)
# Create or get the game
game_data = drop_campaign_data["game"]
@ -70,6 +72,7 @@ async def insert_data(data: dict) -> None: # noqa: PLR0914, C901
defaults={
"slug": game_data["slug"],
"display_name": game_data["displayName"],
"organization": owner,
},
)
if created:
@ -79,16 +82,15 @@ async def insert_data(data: dict) -> None: # noqa: PLR0914, C901
drop_campaign, created = await sync_to_async(DropCampaign.objects.get_or_create)(
id=drop_campaign_data["id"],
defaults={
"account_link_url": drop_campaign_data["accountLinkURL"],
"description": drop_campaign_data["description"],
"details_url": drop_campaign_data["detailsURL"],
"end_at": drop_campaign_data["endAt"],
"image_url": drop_campaign_data["imageURL"],
"name": drop_campaign_data["name"],
"start_at": drop_campaign_data["startAt"],
"status": drop_campaign_data["status"],
"account_link_url": drop_campaign_data.get("accountLinkURL"),
"description": drop_campaign_data.get("description"),
"details_url": drop_campaign_data.get("detailsURL"),
"end_at": drop_campaign_data.get("endAt"),
"image_url": drop_campaign_data.get("imageURL"),
"name": drop_campaign_data.get("name"),
"start_at": drop_campaign_data.get("startAt"),
"status": drop_campaign_data.get("status"),
"game": game,
"owner": owner,
},
)
if created:
@ -97,62 +99,58 @@ async def insert_data(data: dict) -> None: # noqa: PLR0914, C901
# Create time-based drops
for drop_data in drop_campaign_data["timeBasedDrops"]:
drop_benefit_edges = drop_data["benefitEdges"]
drop_benefits = []
time_based_drop, created = await sync_to_async(Drop.objects.get_or_create)(
id=drop_data["id"],
defaults={
"required_subs": drop_data.get("requiredSubs"),
"end_at": drop_data.get("endAt"),
"name": drop_data.get("name"),
"required_minutes_watched": drop_data.get("requiredMinutesWatched"),
"start_at": drop_data.get("startAt"),
"drop_campaign": drop_campaign,
},
)
if created:
logger.debug("Time-based drop created: %s", time_based_drop)
for edge in drop_benefit_edges:
benefit_data = edge["benefit"]
benefit_owner_data = benefit_data["ownerOrganization"]
benefit_owner, created = await sync_to_async(
org, created = await sync_to_async(
Organization.objects.get_or_create,
)(
id=benefit_owner_data["id"],
defaults={"name": benefit_owner_data["name"]},
)
if created:
logger.debug("Benefit owner created: %s", benefit_owner)
logger.debug("Organization created: %s", org)
benefit_game_data = benefit_data["game"]
benefit_game, created = await sync_to_async(Game.objects.get_or_create)(
id=benefit_game_data["id"],
defaults={"name": benefit_game_data["name"]},
defaults={"display_name": benefit_game_data["name"]},
)
if created:
logger.debug("Benefit game created: %s", benefit_game)
benefit, created = await sync_to_async(DropBenefit.objects.get_or_create)(
id=benefit_data["id"],
# Get the drop to add the data to
drop, created = await sync_to_async(Drop.objects.get_or_create)(
id=drop_data["id"],
defaults={
"created_at": benefit_data["createdAt"],
"entitlement_limit": benefit_data["entitlementLimit"],
"image_asset_url": benefit_data["imageAssetURL"],
"is_ios_available": benefit_data["isIosAvailable"],
"name": benefit_data["name"],
"owner_organization": benefit_owner,
"created_at": benefit_data.get("createdAt"),
"entitlement_limit": benefit_data.get("entitlementLimit"),
"image_asset_url": benefit_data.get("imageAssetURL"),
"is_ios_available": benefit_data.get("isIosAvailable"),
"name": benefit_data.get("name"),
"owner_organization": org,
"game": benefit_game,
},
)
drop_benefits.append(benefit)
if created:
logger.debug("Benefit created: %s", benefit)
time_based_drop, created = await sync_to_async(
TimeBasedDrop.objects.get_or_create,
)(
id=drop_data["id"],
defaults={
"required_subs": drop_data["requiredSubs"],
"end_at": drop_data["endAt"],
"name": drop_data["name"],
"required_minutes_watched": drop_data["requiredMinutesWatched"],
"start_at": drop_data["startAt"],
},
)
await sync_to_async(time_based_drop.benefits.set)(drop_benefits)
await sync_to_async(drop_campaign.time_based_drops.add)(time_based_drop)
if created:
logger.debug("Time-based drop created: %s", time_based_drop)
logger.debug("Drop created: %s", drop)
class Command(BaseCommand):
@ -162,18 +160,20 @@ class Command(BaseCommand):
self,
playwright: Playwright,
) -> list[dict[str, typing.Any]]:
profile_dir: Path = Path(data_dir / "firefox-profile")
profile_dir: Path = Path(data_dir / "chrome-profile")
profile_dir.mkdir(parents=True, exist_ok=True)
logger.debug(
"Launching Firefox browser with user data directory: %s",
"Launching Chrome browser with user data directory: %s",
profile_dir,
)
browser: BrowserContext = await playwright.firefox.launch_persistent_context(
browser: BrowserContext = await playwright.chromium.launch_persistent_context(
user_data_dir=profile_dir,
headless=True,
headless=False,
user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36", # noqa: E501
viewport={"width": 1920, "height": 1080},
)
logger.debug("Launched Firefox browser")
logger.debug("Launched Chrome browser")
page: Page = await browser.new_page()
json_data: list[dict] = []
@ -198,7 +198,7 @@ class Command(BaseCommand):
try:
await page.wait_for_selector(
'div[data-a-target="top-nav-avatar"]',
timeout=30000,
timeout=300000,
)
logged_in = True
logger.info("Logged in to Twitch")
@ -211,6 +211,9 @@ class Command(BaseCommand):
await page.wait_for_load_state("networkidle")
logger.debug("Page loaded. Scraping data...")
# Wait 5 seconds for the page to load
await asyncio.sleep(5)
await browser.close()
for num, campaign in enumerate(json_data, start=1):

View File

@ -1,17 +1,45 @@
# Generated by Django 5.0.6 on 2024-07-01 00:08
# Generated by Django 5.1b1 on 2024-07-09 22:26
import auto_prefetch
import django.db.models.deletion
import django.db.models.functions.text
import django.db.models.manager
from django.db import migrations, models
from django.db.migrations.operations.base import Operation
class Migration(migrations.Migration):
initial = True
dependencies: list[tuple[str, str]] = []
dependencies = []
operations: list[Operation] = [
operations = [
migrations.CreateModel(
name="DropCampaign",
fields=[
("id", models.TextField(primary_key=True, serialize=False)),
("account_link_url", models.URLField(blank=True, null=True)),
("description", models.TextField(blank=True, null=True)),
("details_url", models.URLField(blank=True, null=True)),
("end_at", models.DateTimeField(blank=True, null=True)),
("image_url", models.URLField(blank=True, null=True)),
("name", models.TextField(blank=True, null=True)),
("start_at", models.DateTimeField(blank=True, null=True)),
("status", models.TextField(blank=True, null=True)),
("added_at", models.DateTimeField(auto_now_add=True, null=True)),
("modified_at", models.DateTimeField(auto_now=True, null=True)),
],
options={
"verbose_name": "Drop Campaign",
"verbose_name_plural": "Drop Campaigns",
"ordering": ("name",),
"abstract": False,
"base_manager_name": "prefetch_manager",
},
managers=[
("objects", django.db.models.manager.Manager()),
("prefetch_manager", django.db.models.manager.Manager()),
],
),
migrations.CreateModel(
name="Game",
fields=[
@ -28,10 +56,33 @@ class Migration(migrations.Migration):
output_field=models.TextField(),
),
),
(
"image_url",
models.GeneratedField( # type: ignore # noqa: PGH003
db_persist=True,
expression=django.db.models.functions.text.Concat(
models.Value("https://static-cdn.jtvnw.net/ttv-boxart/"),
"id",
models.Value("_IGDB.jpg"),
),
output_field=models.URLField(),
),
),
("display_name", models.TextField(blank=True, null=True)),
("added_at", models.DateTimeField(auto_now_add=True, null=True)),
("modified_at", models.DateTimeField(auto_now=True, null=True)),
],
options={
"verbose_name": "Game",
"verbose_name_plural": "Games",
"ordering": ("display_name",),
"abstract": False,
"base_manager_name": "prefetch_manager",
},
managers=[
("objects", django.db.models.manager.Manager()),
("prefetch_manager", django.db.models.manager.Manager()),
],
),
migrations.CreateModel(
name="Organization",
@ -41,97 +92,69 @@ class Migration(migrations.Migration):
("added_at", models.DateTimeField(auto_now_add=True, null=True)),
("modified_at", models.DateTimeField(auto_now=True, null=True)),
],
options={
"verbose_name": "Organization",
"verbose_name_plural": "Organizations",
"ordering": ("name",),
"abstract": False,
"base_manager_name": "prefetch_manager",
},
managers=[
("objects", django.db.models.manager.Manager()),
("prefetch_manager", django.db.models.manager.Manager()),
],
),
migrations.CreateModel(
name="DropBenefit",
name="Drop",
fields=[
("id", models.TextField(primary_key=True, serialize=False)),
("created_at", models.DateTimeField(blank=True, null=True)),
("entitlement_limit", models.IntegerField(blank=True, null=True)),
("image_asset_url", models.URLField(blank=True, null=True)),
("is_ios_available", models.BooleanField(blank=True, null=True)),
("name", models.TextField(blank=True, null=True)),
("added_at", models.DateTimeField(auto_now_add=True, null=True)),
("modified_at", models.DateTimeField(auto_now=True, null=True)),
(
"game",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="twitch_app.game",
),
),
(
"owner_organization",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="twitch_app.organization",
),
),
],
),
migrations.CreateModel(
name="TimeBasedDrop",
fields=[
("id", models.TextField(primary_key=True, serialize=False)),
("required_subs", models.IntegerField(blank=True, null=True)),
("end_at", models.DateTimeField(blank=True, null=True)),
("name", models.TextField(blank=True, null=True)),
(
"required_minutes_watched",
models.IntegerField(blank=True, null=True),
),
("required_minutes_watched", models.IntegerField(blank=True, null=True)),
("start_at", models.DateTimeField(blank=True, null=True)),
("added_at", models.DateTimeField(auto_now_add=True, null=True)),
("modified_at", models.DateTimeField(auto_now=True, null=True)),
("benefits", models.ManyToManyField(to="twitch_app.dropbenefit")),
],
),
migrations.CreateModel(
name="DropCampaign",
fields=[
("id", models.TextField(primary_key=True, serialize=False)),
("account_link_url", models.URLField(blank=True, null=True)),
("description", models.TextField(blank=True, null=True)),
("details_url", models.URLField(blank=True, null=True)),
("end_at", models.DateTimeField(blank=True, null=True)),
("image_url", models.URLField(blank=True, null=True)),
("name", models.TextField(blank=True, null=True)),
("start_at", models.DateTimeField(blank=True, null=True)),
("status", models.TextField(blank=True, null=True)),
("added_at", models.DateTimeField(auto_now_add=True, null=True)),
("modified_at", models.DateTimeField(auto_now=True, null=True)),
(
"game",
models.ForeignKey(
"drop_campaign",
auto_prefetch.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="drop_campaigns",
to="twitch_app.game",
related_name="drops",
to="twitch_app.dropcampaign",
),
),
(
"owner",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="drop_campaigns",
to="twitch_app.organization",
),
),
(
"time_based_drops",
models.ManyToManyField(to="twitch_app.timebaseddrop"),
),
],
options={
"verbose_name": "Drop",
"verbose_name_plural": "Drops",
"ordering": ("name",),
"abstract": False,
"base_manager_name": "prefetch_manager",
},
managers=[
("objects", django.db.models.manager.Manager()),
("prefetch_manager", django.db.models.manager.Manager()),
],
),
migrations.CreateModel(
name="User",
fields=[
("id", models.TextField(primary_key=True, serialize=False)),
("added_at", models.DateTimeField(auto_now_add=True, null=True)),
("modified_at", models.DateTimeField(auto_now=True, null=True)),
(
"drop_campaigns",
models.ManyToManyField(to="twitch_app.dropcampaign"),
),
],
migrations.AddField(
model_name="dropcampaign",
name="game",
field=auto_prefetch.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="drop_campaigns",
to="twitch_app.game",
),
),
migrations.AddField(
model_name="game",
name="organization",
field=auto_prefetch.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="games",
to="twitch_app.organization",
),
),
]

View File

@ -1,27 +0,0 @@
# Generated by Django 5.0.6 on 2024-07-01 03:49
import django.db.models.functions.text
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", "0001_initial"),
]
operations: list[Operation] = [
migrations.AddField(
model_name="game",
name="image_url",
field=models.GeneratedField( # type: ignore # noqa: PGH003
db_persist=True,
expression=django.db.models.functions.text.Concat(
models.Value("https://static-cdn.jtvnw.net/ttv-boxart/"),
"id",
models.Value("_IGDB.jpg"),
),
output_field=models.URLField(),
),
),
]

View File

@ -1,308 +0,0 @@
# Generated by Django 5.0.6 on 2024-07-01 15:17
import django.db.models.deletion
import django.db.models.functions.text
import simple_history.models
from django.conf import settings
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", "0002_game_image_url"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations: list[Operation] = [
migrations.CreateModel(
name="HistoricalDropBenefit",
fields=[
("id", models.TextField(db_index=True)),
("created_at", models.DateTimeField(blank=True, null=True)),
("entitlement_limit", models.IntegerField(blank=True, null=True)),
("image_asset_url", models.URLField(blank=True, null=True)),
("is_ios_available", models.BooleanField(blank=True, null=True)),
("name", models.TextField(blank=True, null=True)),
(
"added_at",
models.DateTimeField(blank=True, editable=False, null=True),
),
(
"modified_at",
models.DateTimeField(blank=True, editable=False, null=True),
),
("history_id", models.AutoField(primary_key=True, serialize=False)),
("history_date", models.DateTimeField(db_index=True)),
("history_change_reason", models.CharField(max_length=100, null=True)),
(
"history_type",
models.CharField(
choices=[("+", "Created"), ("~", "Changed"), ("-", "Deleted")],
max_length=1,
),
),
(
"game",
models.ForeignKey(
blank=True,
db_constraint=False,
null=True,
on_delete=django.db.models.deletion.DO_NOTHING,
related_name="+",
to="twitch_app.game",
),
),
(
"history_user",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="+",
to=settings.AUTH_USER_MODEL,
),
),
(
"owner_organization",
models.ForeignKey(
blank=True,
db_constraint=False,
null=True,
on_delete=django.db.models.deletion.DO_NOTHING,
related_name="+",
to="twitch_app.organization",
),
),
],
options={
"verbose_name": "historical drop benefit",
"verbose_name_plural": "historical drop benefits",
"ordering": ("-history_date", "-history_id"),
"get_latest_by": ("history_date", "history_id"),
},
bases=(simple_history.models.HistoricalChanges, models.Model),
),
migrations.CreateModel(
name="HistoricalDropCampaign",
fields=[
("id", models.TextField(db_index=True)),
("account_link_url", models.URLField(blank=True, null=True)),
("description", models.TextField(blank=True, null=True)),
("details_url", models.URLField(blank=True, null=True)),
("end_at", models.DateTimeField(blank=True, null=True)),
("image_url", models.URLField(blank=True, null=True)),
("name", models.TextField(blank=True, null=True)),
("start_at", models.DateTimeField(blank=True, null=True)),
("status", models.TextField(blank=True, null=True)),
(
"added_at",
models.DateTimeField(blank=True, editable=False, null=True),
),
(
"modified_at",
models.DateTimeField(blank=True, editable=False, null=True),
),
("history_id", models.AutoField(primary_key=True, serialize=False)),
("history_date", models.DateTimeField(db_index=True)),
("history_change_reason", models.CharField(max_length=100, null=True)),
(
"history_type",
models.CharField(
choices=[("+", "Created"), ("~", "Changed"), ("-", "Deleted")],
max_length=1,
),
),
(
"game",
models.ForeignKey(
blank=True,
db_constraint=False,
null=True,
on_delete=django.db.models.deletion.DO_NOTHING,
related_name="+",
to="twitch_app.game",
),
),
(
"history_user",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="+",
to=settings.AUTH_USER_MODEL,
),
),
(
"owner",
models.ForeignKey(
blank=True,
db_constraint=False,
null=True,
on_delete=django.db.models.deletion.DO_NOTHING,
related_name="+",
to="twitch_app.organization",
),
),
],
options={
"verbose_name": "historical drop campaign",
"verbose_name_plural": "historical drop campaigns",
"ordering": ("-history_date", "-history_id"),
"get_latest_by": ("history_date", "history_id"),
},
bases=(simple_history.models.HistoricalChanges, models.Model),
),
migrations.CreateModel(
name="HistoricalGame",
fields=[
("id", models.TextField(db_index=True)),
("slug", models.TextField(blank=True, null=True)),
(
"twitch_url",
models.GeneratedField( # type: ignore # noqa: PGH003
db_persist=True,
expression=django.db.models.functions.text.Concat(
models.Value("https://www.twitch.tv/directory/category/"),
"slug",
),
output_field=models.TextField(),
),
),
(
"image_url",
models.GeneratedField( # type: ignore # noqa: PGH003
db_persist=True,
expression=django.db.models.functions.text.Concat(
models.Value("https://static-cdn.jtvnw.net/ttv-boxart/"),
"id",
models.Value("_IGDB.jpg"),
),
output_field=models.URLField(),
),
),
("display_name", models.TextField(blank=True, null=True)),
(
"added_at",
models.DateTimeField(blank=True, editable=False, null=True),
),
(
"modified_at",
models.DateTimeField(blank=True, editable=False, null=True),
),
("history_id", models.AutoField(primary_key=True, serialize=False)),
("history_date", models.DateTimeField(db_index=True)),
("history_change_reason", models.CharField(max_length=100, null=True)),
(
"history_type",
models.CharField(
choices=[("+", "Created"), ("~", "Changed"), ("-", "Deleted")],
max_length=1,
),
),
(
"history_user",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="+",
to=settings.AUTH_USER_MODEL,
),
),
],
options={
"verbose_name": "historical game",
"verbose_name_plural": "historical games",
"ordering": ("-history_date", "-history_id"),
"get_latest_by": ("history_date", "history_id"),
},
bases=(simple_history.models.HistoricalChanges, models.Model),
),
migrations.CreateModel(
name="HistoricalTimeBasedDrop",
fields=[
("id", models.TextField(db_index=True)),
("required_subs", models.IntegerField(blank=True, null=True)),
("end_at", models.DateTimeField(blank=True, null=True)),
("name", models.TextField(blank=True, null=True)),
(
"required_minutes_watched",
models.IntegerField(blank=True, null=True),
),
("start_at", models.DateTimeField(blank=True, null=True)),
(
"added_at",
models.DateTimeField(blank=True, editable=False, null=True),
),
(
"modified_at",
models.DateTimeField(blank=True, editable=False, null=True),
),
("history_id", models.AutoField(primary_key=True, serialize=False)),
("history_date", models.DateTimeField(db_index=True)),
("history_change_reason", models.CharField(max_length=100, null=True)),
(
"history_type",
models.CharField(
choices=[("+", "Created"), ("~", "Changed"), ("-", "Deleted")],
max_length=1,
),
),
(
"history_user",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="+",
to=settings.AUTH_USER_MODEL,
),
),
],
options={
"verbose_name": "historical time based drop",
"verbose_name_plural": "historical time based drops",
"ordering": ("-history_date", "-history_id"),
"get_latest_by": ("history_date", "history_id"),
},
bases=(simple_history.models.HistoricalChanges, models.Model),
),
migrations.CreateModel(
name="HistoricalUser",
fields=[
("id", models.TextField(db_index=True)),
(
"added_at",
models.DateTimeField(blank=True, editable=False, null=True),
),
(
"modified_at",
models.DateTimeField(blank=True, editable=False, null=True),
),
("history_id", models.AutoField(primary_key=True, serialize=False)),
("history_date", models.DateTimeField(db_index=True)),
("history_change_reason", models.CharField(max_length=100, null=True)),
(
"history_type",
models.CharField(
choices=[("+", "Created"), ("~", "Changed"), ("-", "Deleted")],
max_length=1,
),
),
(
"history_user",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="+",
to=settings.AUTH_USER_MODEL,
),
),
],
options={
"verbose_name": "historical user",
"verbose_name_plural": "historical users",
"ordering": ("-history_date", "-history_id"),
"get_latest_by": ("history_date", "history_id"),
},
bases=(simple_history.models.HistoricalChanges, models.Model),
),
]

View File

@ -1,23 +0,0 @@
# Generated by Django 5.0.6 on 2024-07-01 15:23
from django.db import migrations
from django.db.migrations.operations.base import Operation
class Migration(migrations.Migration):
dependencies: list[tuple[str, str]] = [
("twitch_app", "0003_historicaldropbenefit_historicaldropcampaign_and_more"),
]
operations: list[Operation] = [
migrations.RemoveField(
model_name="user",
name="drop_campaigns",
),
migrations.DeleteModel(
name="HistoricalUser",
),
migrations.DeleteModel(
name="User",
),
]

View File

@ -1,92 +0,0 @@
# Generated by Django 5.0.6 on 2024-07-01 15:40
from django.db import migrations
from django.db.migrations.operations.base import Operation
class Migration(migrations.Migration):
dependencies: list[tuple[str, str]] = [
(
"twitch_app",
"0004_remove_user_drop_campaigns_delete_historicaluser_and_more",
),
]
operations: list[Operation] = [
migrations.AlterModelOptions(
name="dropbenefit",
options={
"ordering": ("name",),
"verbose_name": "Drop Benefit",
"verbose_name_plural": "Drop Benefits",
},
),
migrations.AlterModelOptions(
name="dropcampaign",
options={
"ordering": ("name",),
"verbose_name": "Drop Campaign",
"verbose_name_plural": "Drop Campaigns",
},
),
migrations.AlterModelOptions(
name="game",
options={
"ordering": ("display_name",),
"verbose_name": "Game",
"verbose_name_plural": "Games",
},
),
migrations.AlterModelOptions(
name="historicaldropbenefit",
options={
"get_latest_by": ("history_date", "history_id"),
"ordering": ("-history_date", "-history_id"),
"verbose_name": "historical Drop Benefit",
"verbose_name_plural": "historical Drop Benefits",
},
),
migrations.AlterModelOptions(
name="historicaldropcampaign",
options={
"get_latest_by": ("history_date", "history_id"),
"ordering": ("-history_date", "-history_id"),
"verbose_name": "historical Drop Campaign",
"verbose_name_plural": "historical Drop Campaigns",
},
),
migrations.AlterModelOptions(
name="historicalgame",
options={
"get_latest_by": ("history_date", "history_id"),
"ordering": ("-history_date", "-history_id"),
"verbose_name": "historical Game",
"verbose_name_plural": "historical Games",
},
),
migrations.AlterModelOptions(
name="historicaltimebaseddrop",
options={
"get_latest_by": ("history_date", "history_id"),
"ordering": ("-history_date", "-history_id"),
"verbose_name": "historical Time-Based Drop",
"verbose_name_plural": "historical Time-Based Drops",
},
),
migrations.AlterModelOptions(
name="organization",
options={
"ordering": ("name",),
"verbose_name": "Organization",
"verbose_name_plural": "Organizations",
},
),
migrations.AlterModelOptions(
name="timebaseddrop",
options={
"ordering": ("name",),
"verbose_name": "Time-Based Drop",
"verbose_name_plural": "Time-Based Drops",
},
),
]

View File

@ -1,172 +0,0 @@
# Generated by Django 5.0.6 on 2024-07-01 15:44
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", "0005_alter_dropbenefit_options_alter_dropcampaign_options_and_more"),
]
operations: list[Operation] = [
migrations.AlterModelOptions(
name="dropbenefit",
options={
"base_manager_name": "prefetch_manager",
"ordering": ("name",),
"verbose_name": "Drop Benefit",
"verbose_name_plural": "Drop Benefits",
},
),
migrations.AlterModelOptions(
name="dropcampaign",
options={
"base_manager_name": "prefetch_manager",
"ordering": ("name",),
"verbose_name": "Drop Campaign",
"verbose_name_plural": "Drop Campaigns",
},
),
migrations.AlterModelOptions(
name="game",
options={
"base_manager_name": "prefetch_manager",
"ordering": ("display_name",),
"verbose_name": "Game",
"verbose_name_plural": "Games",
},
),
migrations.AlterModelOptions(
name="organization",
options={
"base_manager_name": "prefetch_manager",
"ordering": ("name",),
"verbose_name": "Organization",
"verbose_name_plural": "Organizations",
},
),
migrations.AlterModelOptions(
name="timebaseddrop",
options={
"base_manager_name": "prefetch_manager",
"ordering": ("name",),
"verbose_name": "Time-Based Drop",
"verbose_name_plural": "Time-Based Drops",
},
),
migrations.AlterModelManagers(
name="dropbenefit",
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="organization",
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.AlterField(
model_name="dropbenefit",
name="game",
field=auto_prefetch.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="twitch_app.game"),
),
migrations.AlterField(
model_name="dropbenefit",
name="owner_organization",
field=auto_prefetch.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="twitch_app.organization"),
),
migrations.AlterField(
model_name="dropcampaign",
name="game",
field=auto_prefetch.ForeignKey(
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(
on_delete=django.db.models.deletion.CASCADE,
related_name="drop_campaigns",
to="twitch_app.organization",
),
),
migrations.AlterField(
model_name="historicaldropbenefit",
name="game",
field=auto_prefetch.ForeignKey(
blank=True,
db_constraint=False,
null=True,
on_delete=django.db.models.deletion.DO_NOTHING,
related_name="+",
to="twitch_app.game",
),
),
migrations.AlterField(
model_name="historicaldropbenefit",
name="owner_organization",
field=auto_prefetch.ForeignKey(
blank=True,
db_constraint=False,
null=True,
on_delete=django.db.models.deletion.DO_NOTHING,
related_name="+",
to="twitch_app.organization",
),
),
migrations.AlterField(
model_name="historicaldropcampaign",
name="game",
field=auto_prefetch.ForeignKey(
blank=True,
db_constraint=False,
null=True,
on_delete=django.db.models.deletion.DO_NOTHING,
related_name="+",
to="twitch_app.game",
),
),
migrations.AlterField(
model_name="historicaldropcampaign",
name="owner",
field=auto_prefetch.ForeignKey(
blank=True,
db_constraint=False,
null=True,
on_delete=django.db.models.deletion.DO_NOTHING,
related_name="+",
to="twitch_app.organization",
),
),
]

View File

@ -1,23 +0,0 @@
# Generated by Django 5.0.6 on 2024-07-02 17:11
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", "0006_alter_dropbenefit_options_alter_dropcampaign_options_and_more"),
]
operations: list[Operation] = [
migrations.AlterField(
model_name="dropcampaign",
name="time_based_drops",
field=models.ManyToManyField(related_name="drop_campaigns", to="twitch_app.timebaseddrop"),
),
migrations.AlterField(
model_name="timebaseddrop",
name="benefits",
field=models.ManyToManyField(related_name="time_based_drops", to="twitch_app.dropbenefit"),
),
]

View File

@ -1,33 +0,0 @@
# Generated by Django 5.0.6 on 2024-07-03 21:19
import auto_prefetch
import django.db.models.deletion
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_and_more"),
]
operations: list[Operation] = [
migrations.AlterField(
model_name="dropbenefit",
name="game",
field=auto_prefetch.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="drop_benefits",
to="twitch_app.game",
),
),
migrations.AlterField(
model_name="dropbenefit",
name="owner_organization",
field=auto_prefetch.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="drop_benefits",
to="twitch_app.organization",
),
),
]

View File

@ -3,10 +3,7 @@ from typing import Literal
import auto_prefetch
from django.db import models
from django.db.models import Value
from django.db.models.functions import (
Concat,
)
from simple_history.models import HistoricalRecords
from django.db.models.functions import Concat
class Organization(auto_prefetch.Model):
@ -35,6 +32,11 @@ class Game(auto_prefetch.Model):
For example, MultiVersus.
"""
organization = auto_prefetch.ForeignKey(
Organization,
on_delete=models.CASCADE,
related_name="games",
)
id = models.TextField(primary_key=True)
slug = models.TextField(blank=True, null=True)
twitch_url = models.GeneratedField( # type: ignore # noqa: PGH003
@ -54,7 +56,6 @@ class Game(auto_prefetch.Model):
display_name = models.TextField(blank=True, null=True)
added_at = models.DateTimeField(blank=True, null=True, auto_now_add=True)
modified_at = models.DateTimeField(blank=True, null=True, auto_now=True)
history = HistoricalRecords()
class Meta(auto_prefetch.Model.Meta):
verbose_name: str = "Game"
@ -65,55 +66,29 @@ class Game(auto_prefetch.Model):
return self.display_name or self.slug or self.id
class DropBenefit(auto_prefetch.Model):
"""Information about the drop."""
class Drop(auto_prefetch.Model):
"""The actual drop that is being given out."""
id = models.TextField(primary_key=True)
created_at = models.DateTimeField(blank=True, null=True)
entitlement_limit = models.IntegerField(blank=True, null=True)
image_asset_url = models.URLField(blank=True, null=True)
is_ios_available = models.BooleanField(blank=True, null=True)
name = models.TextField(blank=True, null=True)
owner_organization = auto_prefetch.ForeignKey(
Organization,
on_delete=models.CASCADE,
related_name="drop_benefits",
)
game = auto_prefetch.ForeignKey(Game, on_delete=models.CASCADE, related_name="drop_benefits")
added_at = models.DateTimeField(blank=True, null=True, auto_now_add=True)
modified_at = models.DateTimeField(blank=True, null=True, auto_now=True)
history = HistoricalRecords()
class Meta(auto_prefetch.Model.Meta):
verbose_name: str = "Drop Benefit"
verbose_name_plural: str = "Drop Benefits"
ordering: tuple[Literal["name"]] = ("name",)
def __str__(self) -> str:
return f"{self.owner_organization.name} - {self.game.display_name} - {self.name}"
class TimeBasedDrop(auto_prefetch.Model):
"""The actual drop that is being given out."""
id = models.TextField(primary_key=True)
required_subs = models.IntegerField(blank=True, null=True)
end_at = models.DateTimeField(blank=True, null=True)
name = models.TextField(blank=True, null=True)
required_minutes_watched = models.IntegerField(blank=True, null=True)
start_at = models.DateTimeField(blank=True, null=True)
benefits = models.ManyToManyField(DropBenefit, related_name="time_based_drops")
added_at = models.DateTimeField(blank=True, null=True, auto_now_add=True)
modified_at = models.DateTimeField(blank=True, null=True, auto_now=True)
history = HistoricalRecords()
drop_campaign = auto_prefetch.ForeignKey("DropCampaign", on_delete=models.CASCADE, related_name="drops")
class Meta(auto_prefetch.Model.Meta):
verbose_name: str = "Time-Based Drop"
verbose_name_plural: str = "Time-Based Drops"
verbose_name: str = "Drop"
verbose_name_plural: str = "Drops"
ordering: tuple[Literal["name"]] = ("name",)
def __str__(self) -> str:
return f"{self.benefits.first()} - {self.name}"
return f"{self.name}"
class DropCampaign(auto_prefetch.Model):
@ -136,15 +111,8 @@ class DropCampaign(auto_prefetch.Model):
on_delete=models.CASCADE,
related_name="drop_campaigns",
)
owner = auto_prefetch.ForeignKey(
Organization,
on_delete=models.CASCADE,
related_name="drop_campaigns",
)
time_based_drops = models.ManyToManyField(TimeBasedDrop, related_name="drop_campaigns")
added_at = models.DateTimeField(blank=True, null=True, auto_now_add=True)
modified_at = models.DateTimeField(blank=True, null=True, auto_now=True)
history = HistoricalRecords()
class Meta(auto_prefetch.Model.Meta):
verbose_name: str = "Drop Campaign"
@ -152,4 +120,4 @@ class DropCampaign(auto_prefetch.Model):
ordering: tuple[Literal["name"]] = ("name",)
def __str__(self) -> str:
return f"{self.owner.name} - {self.game.display_name} - {self.name}"
return f"{self.game.display_name} - {self.name}"