Rewrite aimport_json()
This commit is contained in:
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@ -1,5 +1,6 @@
|
||||
{
|
||||
"cSpell.words": [
|
||||
"adownload",
|
||||
"aimport",
|
||||
"allauth",
|
||||
"appendonly",
|
||||
|
@ -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"]:
|
||||
|
@ -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):
|
||||
|
@ -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):
|
||||
|
@ -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):
|
||||
|
@ -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):
|
||||
|
@ -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"]},
|
||||
),
|
||||
]
|
@ -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),
|
||||
),
|
||||
]
|
@ -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),
|
||||
),
|
||||
]
|
831
core/models.py
831
core/models.py
File diff suppressed because it is too large
Load Diff
@ -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",
|
||||
},
|
||||
|
@ -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>
|
||||
|
@ -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 %}
|
||||
|
@ -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 %}
|
||||
|
@ -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>
|
||||
|
@ -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 %}
|
||||
|
@ -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 %}
|
||||
|
Reference in New Issue
Block a user