There is now a page for all the webhooks
This commit is contained in:
@ -41,6 +41,7 @@ def should_be_skipped(custom_reader: Reader, entry: Entry) -> bool:
|
|||||||
# blacklist_content: str = get_blacklist_content(custom_reader, feed)
|
# blacklist_content: str = get_blacklist_content(custom_reader, feed)
|
||||||
# TODO: Fix content
|
# TODO: Fix content
|
||||||
# TODO: Check author
|
# TODO: Check author
|
||||||
|
# TODO: Also add support for entry_text
|
||||||
|
|
||||||
if entry.title and blacklist_title and is_word_in_text(blacklist_title, entry.title):
|
if entry.title and blacklist_title and is_word_in_text(blacklist_title, entry.title):
|
||||||
return True
|
return True
|
||||||
|
@ -1,13 +1,18 @@
|
|||||||
|
import json
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
|
from dataclasses import dataclass
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from functools import lru_cache
|
||||||
from typing import Dict, Iterable
|
from typing import Dict, Iterable
|
||||||
|
|
||||||
|
import httpx
|
||||||
import uvicorn
|
import uvicorn
|
||||||
from apscheduler.schedulers.background import BackgroundScheduler
|
from apscheduler.schedulers.background import BackgroundScheduler
|
||||||
from fastapi import FastAPI, Form, HTTPException, Request
|
from fastapi import FastAPI, Form, HTTPException, Request
|
||||||
from fastapi.responses import HTMLResponse
|
from fastapi.responses import HTMLResponse
|
||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
from fastapi.templating import Jinja2Templates
|
from fastapi.templating import Jinja2Templates
|
||||||
|
from httpx import Response
|
||||||
from reader import (
|
from reader import (
|
||||||
Entry,
|
Entry,
|
||||||
EntryCounts,
|
EntryCounts,
|
||||||
@ -87,7 +92,7 @@ async def add_webhook(webhook_name=Form(), webhook_url=Form()):
|
|||||||
return RedirectResponse(url="/", status_code=303)
|
return RedirectResponse(url="/", status_code=303)
|
||||||
|
|
||||||
# TODO: Show this error on the page.
|
# TODO: Show this error on the page.
|
||||||
return {"error": "Webhook already exists."}
|
raise HTTPException(status_code=409, detail="Webhook already exists")
|
||||||
|
|
||||||
|
|
||||||
@app.post("/delete_webhook")
|
@app.post("/delete_webhook")
|
||||||
@ -101,24 +106,25 @@ async def delete_webhook(webhook_url=Form()):
|
|||||||
Returns:
|
Returns:
|
||||||
dict: The feed that was added.
|
dict: The feed that was added.
|
||||||
"""
|
"""
|
||||||
# Remove leading and trailing whitespace.
|
|
||||||
clean_webhook_url: str = webhook_url.strip()
|
|
||||||
|
|
||||||
# Get current webhooks from the database if they exist otherwise use an empty list.
|
# Get current webhooks from the database if they exist otherwise use an empty list.
|
||||||
webhooks: list[dict[str, str]] = list_webhooks(reader)
|
webhooks: list[dict[str, str]] = list_webhooks(reader)
|
||||||
|
|
||||||
# Only add the webhook if it doesn't already exist.
|
# Only add the webhook if it doesn't already exist.
|
||||||
for webhook in webhooks:
|
for webhook in webhooks:
|
||||||
if webhook["url"] == clean_webhook_url:
|
if webhook["url"] in [webhook_url, webhook_url]:
|
||||||
# Add the new webhook to the list of webhooks.
|
# Add the new webhook to the list of webhooks.
|
||||||
webhooks.remove(webhook)
|
webhooks.remove(webhook)
|
||||||
|
|
||||||
|
# Check if it has been removed.
|
||||||
|
if webhook in webhooks:
|
||||||
|
raise HTTPException(status_code=500, detail="Webhook could not be deleted")
|
||||||
|
|
||||||
# Add our new list of webhooks to the database.
|
# Add our new list of webhooks to the database.
|
||||||
reader.set_tag((), "webhooks", webhooks) # type: ignore
|
reader.set_tag((), "webhooks", webhooks) # type: ignore
|
||||||
return RedirectResponse(url="/", status_code=303)
|
return RedirectResponse(url="/", status_code=303)
|
||||||
|
|
||||||
# TODO: Show this error on the page.
|
# TODO: Show this error on the page.
|
||||||
return {"error": "Could not find webhook."}
|
raise HTTPException(status_code=404, detail="Webhook not found")
|
||||||
|
|
||||||
|
|
||||||
@app.post("/add")
|
@app.post("/add")
|
||||||
@ -159,7 +165,7 @@ async def create_feed(feed_url=Form(), webhook_dropdown=Form()):
|
|||||||
|
|
||||||
if not webhook_url:
|
if not webhook_url:
|
||||||
# TODO: Show this error on the page.
|
# TODO: Show this error on the page.
|
||||||
return {"error": "No webhook URL found."}
|
raise HTTPException(status_code=404, detail="Webhook not found")
|
||||||
|
|
||||||
# This is the webhook that will be used to send the feed to Discord.
|
# This is the webhook that will be used to send the feed to Discord.
|
||||||
reader.set_tag(clean_feed_url, "webhook", webhook_url) # type: ignore
|
reader.set_tag(clean_feed_url, "webhook", webhook_url) # type: ignore
|
||||||
@ -617,6 +623,51 @@ def create_html_for_feed(entries: Iterable[Entry]) -> str:
|
|||||||
return html.strip()
|
return html.strip()
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/add_webhook", response_class=HTMLResponse)
|
||||||
|
async def add_webhook_page(request: Request):
|
||||||
|
"""
|
||||||
|
Page for adding a new webhook.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request: The request.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
HTMLResponse: The HTML response.
|
||||||
|
"""
|
||||||
|
return templates.TemplateResponse("add_webhook.html", {"request": request})
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass()
|
||||||
|
class WebhookInfo:
|
||||||
|
custom_name: str
|
||||||
|
url: str
|
||||||
|
type: int | None = None
|
||||||
|
id: str | None = None
|
||||||
|
name: str | None = None
|
||||||
|
avatar: str | None = None
|
||||||
|
channel_id: str | None = None
|
||||||
|
guild_id: str | None = None
|
||||||
|
token: str | None = None
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache()
|
||||||
|
def get_data_from_hook_url(hook_name: str, hook_url: str):
|
||||||
|
our_hook: WebhookInfo = WebhookInfo(custom_name=hook_name, url=hook_url)
|
||||||
|
|
||||||
|
if hook_url:
|
||||||
|
response: Response = httpx.get(hook_url)
|
||||||
|
if response.status_code == 200:
|
||||||
|
webhook_json = json.loads(response.text)
|
||||||
|
our_hook.type = webhook_json["type"] or None
|
||||||
|
our_hook.id = webhook_json["id"] or None
|
||||||
|
our_hook.name = webhook_json["name"] or None
|
||||||
|
our_hook.avatar = webhook_json["avatar"] or None
|
||||||
|
our_hook.channel_id = webhook_json["channel_id"] or None
|
||||||
|
our_hook.guild_id = webhook_json["guild_id"] or None
|
||||||
|
our_hook.token = webhook_json["token"] or None
|
||||||
|
return our_hook
|
||||||
|
|
||||||
|
|
||||||
@app.get("/webhooks", response_class=HTMLResponse)
|
@app.get("/webhooks", response_class=HTMLResponse)
|
||||||
async def get_webhooks(request: Request):
|
async def get_webhooks(request: Request):
|
||||||
"""
|
"""
|
||||||
@ -628,7 +679,21 @@ async def get_webhooks(request: Request):
|
|||||||
Returns:
|
Returns:
|
||||||
HTMLResponse: The HTML response.
|
HTMLResponse: The HTML response.
|
||||||
"""
|
"""
|
||||||
return templates.TemplateResponse("webhooks.html", {"request": request})
|
hooks: Dict[str, str] = reader.get_tag((), "webhooks", "") # type: ignore
|
||||||
|
hooks_with_data = []
|
||||||
|
|
||||||
|
for hook in hooks:
|
||||||
|
hook_url: str = hook["url"] # type: ignore
|
||||||
|
hook_name: str = hook["name"] # type: ignore
|
||||||
|
our_hook: WebhookInfo = get_data_from_hook_url(hook_url=hook_url, hook_name=hook_name)
|
||||||
|
hooks_with_data.append(our_hook)
|
||||||
|
return templates.TemplateResponse(
|
||||||
|
"webhooks.html",
|
||||||
|
{
|
||||||
|
"request": request,
|
||||||
|
"hooks_with_data": hooks_with_data,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/", response_class=HTMLResponse)
|
@app.get("/", response_class=HTMLResponse)
|
||||||
@ -660,7 +725,7 @@ def make_context_index(request: Request):
|
|||||||
"""
|
"""
|
||||||
# Get webhooks name and url from the database.
|
# Get webhooks name and url from the database.
|
||||||
try:
|
try:
|
||||||
hooks: list[dict] = reader.get_tag((), "webhooks")
|
hooks: list[dict] = reader.get_tag((), "webhooks") # type: ignore
|
||||||
except TagNotFoundError:
|
except TagNotFoundError:
|
||||||
hooks = []
|
hooks = []
|
||||||
|
|
||||||
@ -708,7 +773,13 @@ async def remove_feed(feed_url=Form()):
|
|||||||
Returns:
|
Returns:
|
||||||
HTMLResponse: The HTML response.
|
HTMLResponse: The HTML response.
|
||||||
"""
|
"""
|
||||||
reader.delete_feed(feed_url)
|
# Unquote the url
|
||||||
|
unquoted_feed_url: str = urllib.parse.unquote(feed_url)
|
||||||
|
try:
|
||||||
|
reader.delete_feed(unquoted_feed_url)
|
||||||
|
except FeedNotFoundError as e:
|
||||||
|
raise HTTPException(status_code=404, detail="Feed not found") from e
|
||||||
|
|
||||||
reader.update_search()
|
reader.update_search()
|
||||||
|
|
||||||
return RedirectResponse(url="/", status_code=303)
|
return RedirectResponse(url="/", status_code=303)
|
||||||
|
@ -33,6 +33,9 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-text">
|
||||||
|
You can add more feeds <a class="text-muted" href="/add_webhook">here</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- Submit button -->
|
<!-- Submit button -->
|
||||||
<div class="d-md-flex">
|
<div class="d-md-flex">
|
||||||
|
36
discord_rss_bot/templates/add_webhook.html
Normal file
36
discord_rss_bot/templates/add_webhook.html
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% block title %}
|
||||||
|
| Add new webhook
|
||||||
|
{% endblock title %}
|
||||||
|
{% block content %}
|
||||||
|
<div class="p-2 border border-dark">
|
||||||
|
<form action="/add_webhook" method="post">
|
||||||
|
{# Webhook name #}
|
||||||
|
<div class="row pb-2">
|
||||||
|
<label for="webhook_name" class="col-sm-2 col-form-label">Webhook Name</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input name="webhook_name"
|
||||||
|
type="text"
|
||||||
|
class="form-control bg-dark border-dark text-muted"
|
||||||
|
id="webhook_name"
|
||||||
|
placeholder="TheLovinator #RSS"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{# Webhook URL #}
|
||||||
|
<div class="row pb-2">
|
||||||
|
<label for="webhook_url" class="col-sm-2 col-form-label">Webhook URL</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input name="webhook_url"
|
||||||
|
type="text"
|
||||||
|
class="form-control bg-dark border-dark text-muted"
|
||||||
|
id="webhook_url"
|
||||||
|
placeholder="https://discord.com/api/webhooks/1011224189471124054/CQMa4hJN4gz"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{# Submit button #}
|
||||||
|
<div class="d-md-flex">
|
||||||
|
<button class="btn btn-dark btn-sm">Add webhook</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{% endblock content %}
|
@ -17,7 +17,7 @@
|
|||||||
</li>
|
</li>
|
||||||
<li class="nav-item nav-link d-none d-md-block">|</li>
|
<li class="nav-item nav-link d-none d-md-block">|</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/webhooks">Add webhook</a>
|
<a class="nav-link" href="/webhooks">Webhooks</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
{# Search #}
|
{# Search #}
|
||||||
|
@ -1,36 +1,46 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% block title %}
|
{% block title %}
|
||||||
| Add new webhook
|
| Webhooks
|
||||||
{% endblock title %}
|
{% endblock title %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="p-2 border border-dark">
|
{# List all available webhooks #}
|
||||||
<form action="/add_webhook" method="post">
|
<h3>Available webhooks</h3>
|
||||||
{# Webhook name #}
|
<ul class="list-inline">
|
||||||
<div class="row pb-2">
|
<a class="btn btn-primary" href="/add_webhook">Add new</a>
|
||||||
<label for="webhook_name" class="col-sm-2 col-form-label">Webhook Name</label>
|
<br/>
|
||||||
<div class="col-sm-10">
|
{% for hook in hooks_with_data %}
|
||||||
<input name="webhook_name"
|
<div class="p-2 border border-dark text-muted">
|
||||||
type="text"
|
<img src="https://cdn.discordapp.com/avatars/{{ hook.id }}/{{ hook.avatar }}.webp"
|
||||||
class="form-control bg-dark border-dark text-muted"
|
class="img-thumbnail">
|
||||||
id="webhook_name"
|
<h3>{{ hook.custom_name }}</h3>
|
||||||
placeholder="TheLovinator #RSS"/>
|
<li>
|
||||||
</div>
|
<strong>Name</strong>: {{ hook.name }}
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Channel ID</strong>: {{ hook.channel_id }}
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Guild ID</strong>: {{ hook.guild_id }}
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Webhook ID</strong>: {{ hook.id }}
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Webhook token</strong>: {{ hook.token }}
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Webhook type</strong>: {{ hook.type }}
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Webhook URL</strong>: <a href="{{ hook.url }}">{{ hook.url }}</a>
|
||||||
|
</li>
|
||||||
|
<br/>
|
||||||
|
<form action="/delete_webhook" method="post">
|
||||||
|
<input type="hidden" name="webhook_url" value="{{- hook.url -}}"/>
|
||||||
|
<button type="submit" class="btn btn-danger">Delete</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
{# Webhook URL #}
|
<br/>
|
||||||
<div class="row pb-2">
|
{% endfor %}
|
||||||
<label for="webhook_url" class="col-sm-2 col-form-label">Webhook URL</label>
|
</ul>
|
||||||
<div class="col-sm-10">
|
|
||||||
<input name="webhook_url"
|
|
||||||
type="text"
|
|
||||||
class="form-control bg-dark border-dark text-muted"
|
|
||||||
id="webhook_url"
|
|
||||||
placeholder="https://discord.com/api/webhooks/1011224189471124054/CQMa4hJN4gz"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{# Submit button #}
|
|
||||||
<div class="d-md-flex">
|
|
||||||
<button class="btn btn-dark btn-sm">Add webhook</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
Reference in New Issue
Block a user