Rewrite aimport_json()

This commit is contained in:
2024-09-21 02:09:21 +02:00
parent e76fc28cfb
commit 2be1191a03
17 changed files with 831 additions and 395 deletions

View File

@ -1,5 +1,6 @@
{
"cSpell.words": [
"adownload",
"aimport",
"allauth",
"appendonly",

View File

@ -73,11 +73,12 @@ async def add_reward_campaign(reward_campaign: dict | None) -> None:
logger.info("Added reward campaign %s", our_reward_campaign)
async def add_drop_campaign(drop_campaign: dict | None) -> None:
async def add_drop_campaign(drop_campaign: dict | None, *, local: bool) -> None:
"""Add a drop campaign to the database.
Args:
drop_campaign (dict): The drop campaign to add.
local (bool): Only update status if we are scraping from the Twitch directly.
"""
if not drop_campaign:
return
@ -101,7 +102,7 @@ async def add_drop_campaign(drop_campaign: dict | None) -> None:
logger.info("Added game %s", game)
our_drop_campaign, created = await DropCampaign.objects.aupdate_or_create(twitch_id=drop_campaign["id"])
await our_drop_campaign.aimport_json(drop_campaign, game)
await our_drop_campaign.aimport_json(drop_campaign, game, scraping_local_files=local)
if created:
logger.info("Added drop campaign %s", our_drop_campaign.twitch_id)
@ -129,14 +130,14 @@ async def add_time_based_drops(drop_campaign: dict, our_drop_campaign: DropCampa
raise NotImplementedError(msg)
our_time_based_drop, created = await TimeBasedDrop.objects.aupdate_or_create(twitch_id=time_based_drop["id"])
await our_time_based_drop.aimport_json(time_based_drop, our_drop_campaign)
await our_time_based_drop.aimport_json(data=time_based_drop, drop_campaign=our_drop_campaign)
if created:
logger.info("Added time-based drop %s", our_time_based_drop.twitch_id)
if our_time_based_drop and time_based_drop.get("benefitEdges"):
for benefit_edge in time_based_drop["benefitEdges"]:
benefit, created = await Benefit.objects.aupdate_or_create(twitch_id=benefit_edge["benefit"])
benefit, created = await Benefit.objects.aupdate_or_create(twitch_id=benefit_edge["benefit"]["id"])
await benefit.aimport_json(benefit_edge["benefit"], our_time_based_drop)
if created:
logger.info("Added benefit %s", benefit.twitch_id)
@ -194,7 +195,7 @@ async def process_json_data(num: int, campaign: dict | None, *, local: bool) ->
await add_reward_campaign(reward_campaign=reward_campaign)
if campaign.get("data", {}).get("user", {}).get("dropCampaign"):
await add_drop_campaign(drop_campaign=campaign["data"]["user"]["dropCampaign"])
await add_drop_campaign(drop_campaign=campaign["data"]["user"]["dropCampaign"], local=local)
if campaign.get("data", {}).get("currentUser", {}).get("dropCampaigns"):
for drop_campaign in campaign["data"]["currentUser"]["dropCampaigns"]:

View File

@ -1,11 +1,16 @@
# Generated by Django 5.1 on 2024-09-01 22:36
from __future__ import annotations
from typing import TYPE_CHECKING
import django.contrib.auth.models
import django.contrib.auth.validators
import django.db.models.deletion
import django.utils.timezone
from django.db import migrations, models
from django.db.migrations.operations.base import Operation
if TYPE_CHECKING:
from django.db.migrations.operations.base import Operation
class Migration(migrations.Migration):

View File

@ -1,7 +1,12 @@
# Generated by Django 5.1 on 2024-09-02 23:28
from __future__ import annotations
from typing import TYPE_CHECKING
from django.db import migrations
from django.db.migrations.operations.base import Operation
if TYPE_CHECKING:
from django.db.migrations.operations.base import Operation
class Migration(migrations.Migration):

View File

@ -1,7 +1,12 @@
# Generated by Django 5.1 on 2024-09-07 19:19
from __future__ import annotations
from typing import TYPE_CHECKING
from django.db import migrations
from django.db.migrations.operations.base import Operation
if TYPE_CHECKING:
from django.db.migrations.operations.base import Operation
class Migration(migrations.Migration):

View File

@ -1,7 +1,12 @@
# Generated by Django 5.1 on 2024-09-09 02:34
from __future__ import annotations
from typing import TYPE_CHECKING
from django.db import migrations, models
from django.db.migrations.operations.base import Operation
if TYPE_CHECKING:
from django.db.migrations.operations.base import Operation
class Migration(migrations.Migration):

View File

@ -0,0 +1,38 @@
# Generated by Django 5.1 on 2024-09-15 19:40
from __future__ import annotations
from typing import TYPE_CHECKING
from django.db import migrations
if TYPE_CHECKING:
from django.db.migrations.operations.base import Operation
class Migration(migrations.Migration):
dependencies: list[tuple[str, str]] = [
("core", "0004_alter_dropcampaign_name_alter_game_box_art_url_and_more"),
]
operations: list[Operation] = [
migrations.AlterModelOptions(
name="benefit",
options={"ordering": ["-twitch_created_at"]},
),
migrations.AlterModelOptions(
name="dropcampaign",
options={"ordering": ["ends_at"]},
),
migrations.AlterModelOptions(
name="reward",
options={"ordering": ["-earnable_until"]},
),
migrations.AlterModelOptions(
name="rewardcampaign",
options={"ordering": ["-starts_at"]},
),
migrations.AlterModelOptions(
name="timebaseddrop",
options={"ordering": ["required_minutes_watched"]},
),
]

View File

@ -0,0 +1,50 @@
# Generated by Django 5.1.1 on 2024-09-16 19:32
from __future__ import annotations
from typing import TYPE_CHECKING
from django.db import migrations, models
import core.models
if TYPE_CHECKING:
from django.db.migrations.operations.base import Operation
class Migration(migrations.Migration):
dependencies: list[tuple[str, str]] = [
("core", "0005_alter_benefit_options_alter_dropcampaign_options_and_more"),
]
operations: list[Operation] = [
migrations.AddField(
model_name="benefit",
name="image",
field=models.ImageField(null=True, upload_to=core.models.get_benefit_image_path),
),
migrations.AddField(
model_name="dropcampaign",
name="image",
field=models.ImageField(null=True, upload_to=core.models.get_drop_campaign_image_path),
),
migrations.AddField(
model_name="game",
name="image",
field=models.ImageField(null=True, upload_to=core.models.get_game_image_path),
),
migrations.AddField(
model_name="reward",
name="banner_image",
field=models.ImageField(null=True, upload_to=core.models.get_reward_banner_image_path),
),
migrations.AddField(
model_name="reward",
name="thumbnail_image",
field=models.ImageField(null=True, upload_to=core.models.get_reward_thumbnail_image_path),
),
migrations.AddField(
model_name="rewardcampaign",
name="image",
field=models.ImageField(null=True, upload_to=core.models.get_reward_image_path),
),
]

View File

@ -0,0 +1,31 @@
# Generated by Django 5.1.1 on 2024-09-21 00:08
from __future__ import annotations
from typing import TYPE_CHECKING
from django.db import migrations, models
if TYPE_CHECKING:
from django.db.migrations.operations.base import Operation
class Migration(migrations.Migration):
dependencies: list[tuple[str, str]] = [
("core", "0006_benefit_image_dropcampaign_image_game_image_and_more"),
]
operations: list[Operation] = [
migrations.AlterModelOptions(
name="game",
options={"ordering": ["name"]},
),
migrations.AlterModelOptions(
name="owner",
options={"ordering": ["name"]},
),
migrations.AlterField(
model_name="game",
name="slug",
field=models.TextField(null=True, unique=True),
),
]

File diff suppressed because it is too large Load Diff

View File

@ -40,9 +40,15 @@ THOUSAND_SEPARATOR = " "
ROOT_URLCONF = "core.urls"
STATIC_URL = "static/"
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
STATICFILES_DIRS: list[Path] = [BASE_DIR / "static"]
STATIC_ROOT: Path = BASE_DIR / "staticfiles"
STATIC_ROOT.mkdir(exist_ok=True)
MEDIA_URL = "/media/"
MEDIA_ROOT: Path = DATA_DIR / "media"
MEDIA_ROOT.mkdir(exist_ok=True)
AUTH_USER_MODEL = "core.User"
if DEBUG:
INTERNAL_IPS: list[str] = ["127.0.0.1"]
@ -135,6 +141,9 @@ DATABASES = {
}
STORAGES: dict[str, dict[str, str]] = {
"default": {
"BACKEND": "django.core.files.storage.FileSystemStorage",
},
"staticfiles": {
"BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage",
},

View File

@ -1,6 +1,7 @@
{% load static %}
<!DOCTYPE html>
<html lang="en" data-bs-theme="dark">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
@ -13,10 +14,8 @@
<link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">
<link rel="stylesheet" href="{% static 'css/style.css' %}">
</head>
<body data-bs-spy="scroll"
data-bs-target=".toc"
data-bs-offset="-200"
tabindex="0">
<body data-bs-spy="scroll" data-bs-target=".toc" data-bs-offset="-200" tabindex="0">
{% include "partials/alerts.html" %}
<article class="container mt-5">
{% include "partials/header.html" %}
@ -25,4 +24,5 @@
</article>
<script src="{% static 'js/bootstrap.min.js' %}"></script>
</body>
</html>

View File

@ -3,7 +3,6 @@
<div class="container">
<h2>{{ game.name }}</h2>
<img src="{{ game.box_art_url }}" alt="{{ game.name }} box art" height="283" width="212">
<h3>Game Details</h3>
<table class="table table-hover table-sm table-striped" cellspacing="0">
<tr>
@ -23,18 +22,17 @@
<td><a href="{{ game.box_art_url }}" target="_blank">{{ game.box_art_url }}</a></td>
</tr>
</table>
<h3>Organization</h3>
<table class="table table-hover table-sm table-striped" cellspacing="0">
<tr>
{% if game.org %}
<td><a href="#">{{ game.org.name }} - <span class="text-muted">{{ game.org.pk }}</span></a></td>
<td><a href="#">{{ game.org.name }} -
<span class="text-muted">{{ game.org.pk }}</span></a></td>
{% else %}
<td>No organization associated with this game.</td>
{% endif %}
</tr>
</table>
<h3>Drop Campaigns</h3>
{% if game.drop_campaigns.all %}
{% for drop_campaign in game.drop_campaigns.all %}
@ -48,18 +46,28 @@
<tr>
<td><img src="{{ drop_campaign.image_url }}" alt="{{ drop_campaign.name }} image"></td>
<td>
<p><strong>Status:</strong> {{ drop_campaign.status }}</p>
<p><strong>Description:</strong> {{ drop_campaign.description }}</p>
<p><strong>Starts at:</strong> {{ drop_campaign.starts_at }}</p>
<p><strong>Ends at:</strong> {{ drop_campaign.ends_at }}</p>
<p><strong>More details:</strong> <a href="{{ drop_campaign.details_url }}"
target="_blank">{{ drop_campaign.details_url }}</a></p>
<p><strong>Account Link:</strong> <a href="{{ drop_campaign.account_link_url }}"
target="_blank">{{ drop_campaign.account_link_url }}</a></p>
<p><strong>Status:</strong>
{{ drop_campaign.status }}
</p>
<p><strong>Description:</strong>
{{ drop_campaign.description }}
</p>
<p><strong>Starts at:</strong>
{{ drop_campaign.starts_at }}
</p>
<p><strong>Ends at:</strong>
{{ drop_campaign.ends_at }}
</p>
<p><strong>More details:</strong>
<a href="{{ drop_campaign.details_url }}" target="_blank">{{ drop_campaign.details_url }}</a>
</p>
<p><strong>Account Link:</strong>
<a href="{{ drop_campaign.account_link_url }}"
target="_blank">{{ drop_campaign.account_link_url }}</a>
</p>
</td>
</tr>
</table>
{% if drop_campaign.drops.all %}
<table class="table table-hover table-sm table-striped" cellspacing="0">
<tr>
@ -75,8 +83,7 @@
<td>{{ item.name }}</td>
<td>{{ item.required_minutes_watched }}</td>
{% for benefit in item.benefits.all %}
<td><img src="{{ benefit.image_url }}" alt="{{ benefit.name }} reward image" height="50" width="50">
</td>
<td><img src="{{ benefit.image_url }}" alt="{{ benefit.name }} reward image" height="50" width="50"></td>
<td>{{ benefit.name }}</td>
{% endfor %}
</tr>
@ -89,6 +96,5 @@
{% else %}
<p>No drop campaigns associated with this game.</p>
{% endif %}
</div>
{% endblock content %}

View File

@ -1,10 +1,6 @@
{% for message in messages %}
<div class="alert alert-dismissible {{ message.tags }} fade show"
role="alert">
<div>{{ message | safe }}</div>
<button type="button"
class="btn-close"
data-bs-dismiss="alert"
aria-label="Close"></button>
</div>
<div class="alert alert-dismissible {{ message.tags }} fade show" role="alert">
<div>{{ message | safe }}</div>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
{% endfor %}

View File

@ -5,7 +5,8 @@
<h2 class="card-title h2">Information</h2>
<div class="mb-3">
<p>
This site allows users to subscribe to Twitch drops notifications. You can choose to be alerted when new drops are found on Twitch or when the drops become available for farming.
This site allows users to subscribe to Twitch drops notifications. You can choose to be alerted
when new drops are found on Twitch or when the drops become available for farming.
</p>
</div>
</div>

View File

@ -1,48 +1,50 @@
{% if webhooks %}
<div class="card mb-4 shadow-sm" id="info-box">
<div class="row g-0">
<div class="col-md-10">
<div class="card-body">
<h2 class="card-title h2">Site news</h2>
<div class="mt-auto">
{% for webhook in webhooks %}
<div class="mt-3">
<img src="{{ webhook.avatar }}?size=32"
alt="{{ webhook.name }}"
class="rounded-circle"
height="32"
width="32">
<a href="{{ webhook.url }}" target="_blank">{{ webhook.name }}</a>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="new-drop-switch-daily">
<label class="form-check-label" for="new-drop-switch-daily">Daily notification of newly added games to TTVdrops</label>
</div>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="new-drop-switch-weekly">
<label class="form-check-label" for="new-drop-switch-weekly">
Weekly notification of newly added games to TTVdrops
</label>
</div>
<br>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="new-org-switch-daily">
<label class="form-check-label" for="new-org-switch-daily">
Daily notification of newly added <abbr title="Organizations are the companies that own the games.">organizations</abbr> to TTVdrops
</label>
</div>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="new-org-switch-weekly">
<label class="form-check-label" for="new-org-switch-weekly">
Weekly notification of newly added <abbr title="Organizations are the companies that own the games.">organizations</abbr> to TTVdrops
</label>
</div>
</div>
{% endfor %}
<div class="card mb-4 shadow-sm" id="info-box">
<div class="row g-0">
<div class="col-md-10">
<div class="card-body">
<h2 class="card-title h2">Site news</h2>
<div class="mt-auto">
{% for webhook in webhooks %}
<div class="mt-3">
<img src="{{ webhook.avatar }}?size=32" alt="{{ webhook.name }}" class="rounded-circle"
height="32" width="32">
<a href="{{ webhook.url }}" target="_blank">{{ webhook.name }}</a>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="new-drop-switch-daily">
<label class="form-check-label" for="new-drop-switch-daily">Daily notification of newly
added games to TTVdrops</label>
</div>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="new-drop-switch-weekly">
<label class="form-check-label" for="new-drop-switch-weekly">
Weekly notification of newly added games to TTVdrops
</label>
</div>
<br>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="new-org-switch-daily">
<label class="form-check-label" for="new-org-switch-daily">
Daily notification of newly added <abbr
title="Organizations are the companies that own the games.">organizations</abbr> to
TTVdrops
</label>
</div>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="new-org-switch-weekly">
<label class="form-check-label" for="new-org-switch-weekly">
Weekly notification of newly added <abbr
title="Organizations are the companies that own the games.">organizations</abbr> to
TTVdrops
</label>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
</div>
{% else %}
<p class="text-muted">No webhooks added yet.</p>
<p class="text-muted">No webhooks added yet.</p>
{% endif %}

View File

@ -1,50 +1,42 @@
{% extends "base.html" %}
{% block content %}
<div class="container">
<h1 class="my-4">Add Discord Webhook</h1>
<div class="card card-body mb-3">
Webhooks will be saved in a cookie and will be sent to the server when you subscribe to a drop.
</div>
<div>
<form method="post" class="needs-validation" novalidate>
{% csrf_token %}
{{ form.non_field_errors }}
<div class="mb-3">
{{ form.webhook_url.errors }}
<label for="{{ form.webhook_url.id_for_label }}" class="form-label">{{ form.webhook_url.label }}</label>
<input type="url"
name="webhook_url"
required=""
class="form-control"
aria-describedby="id_webhook_url_helptext"
id="id_webhook_url">
<div class="form-text text-muted">{{ form.webhook_url.help_text }}</div>
</div>
<button type="submit" class="btn btn-primary">Add Webhook</button>
</form>
</div>
<h2 class="mt-5">Webhooks</h2>
{% if webhooks %}
<div class="list-group">
{% for webhook in webhooks %}
<div class="list-group-item d-flex justify-content-between align-items-center">
<span>
{% if webhook.avatar %}
<img src="https://cdn.discordapp.com/avatars/{{ webhook.id }}/a_{{ webhook.avatar }}.png"
alt="Avatar of {{ webhook.name }}"
class="rounded-circle"
height="32"
width="32">
{% endif %}
<a href="https://discord.com/api/webhooks/{{ webhook.id }}/{{ webhook.token }}"
target="_blank"
class="text-decoration-none">{{ webhook.name }}</a>
</span>
</div>
{% endfor %}
</div>
{% else %}
<div class="alert alert-info">No webhooks added</div>
{% endif %}
<div class="container">
<h1 class="my-4">Add Discord Webhook</h1>
<div class="card card-body mb-3">
Webhooks will be saved in a cookie and will be sent to the server when you subscribe to a drop.
</div>
<div>
<form method="post" class="needs-validation" novalidate>
{% csrf_token %}
{{ form.non_field_errors }}
<div class="mb-3">
{{ form.webhook_url.errors }}
<label for="{{ form.webhook_url.id_for_label }}" class="form-label">{{ form.webhook_url.label }}</label>
<input type="url" name="webhook_url" required="" class="form-control"
aria-describedby="id_webhook_url_helptext" id="id_webhook_url">
<div class="form-text text-muted">{{ form.webhook_url.help_text }}</div>
</div>
<button type="submit" class="btn btn-primary">Add Webhook</button>
</form>
</div>
<h2 class="mt-5">Webhooks</h2>
{% if webhooks %}
<div class="list-group">
{% for webhook in webhooks %}
<div class="list-group-item d-flex justify-content-between align-items-center">
<span>
{% if webhook.avatar %}
<img src="https://cdn.discordapp.com/avatars/{{ webhook.id }}/a_{{ webhook.avatar }}.png"
alt="Avatar of {{ webhook.name }}" class="rounded-circle" height="32" width="32">
{% endif %}
<a href="https://discord.com/api/webhooks/{{ webhook.id }}/{{ webhook.token }}" target="_blank"
class="text-decoration-none">{{ webhook.name }}</a>
</span>
</div>
{% endfor %}
</div>
{% else %}
<div class="alert alert-info">No webhooks added</div>
{% endif %}
</div>
{% endblock content %}