210 lines
6.5 KiB
Python
Raw Permalink Normal View History

2025-07-17 15:41:47 +01:00
from flask import Blueprint, jsonify, Response, request, current_app
2025-07-15 15:45:17 +01:00
from ktvmanager.lib.database import (
get_user_accounts,
get_stream_names,
single_check,
add_account,
delete_account,
get_user_id_from_username,
2025-07-17 15:41:47 +01:00
save_push_subscription,
get_push_subscriptions,
2025-07-15 15:45:17 +01:00
)
from ktvmanager.lib.get_urls import get_latest_urls_from_dns
2025-07-15 09:28:47 +01:00
from ktvmanager.lib.auth import requires_basic_auth, check_login
2025-07-15 15:42:47 +01:00
from ktvmanager.lib.checker import validate_account
2025-07-15 15:45:17 +01:00
from typing import Tuple
2025-07-17 15:41:47 +01:00
import json
from pywebpush import webpush, WebPushException
api_blueprint = Blueprint("api", __name__)
2025-07-15 15:45:17 +01:00
@api_blueprint.route("/getUserAccounts")
@requires_basic_auth
2025-07-15 15:45:17 +01:00
def get_user_accounts_route(username: str, password: str) -> Response:
"""Retrieves all accounts associated with a user.
Args:
username: The username of the user.
password: The password of the user (used for authentication).
Returns:
A Flask JSON response containing the user's accounts or an error message.
"""
user_id = get_user_id_from_username(username)
if user_id:
return get_user_accounts(user_id)
return jsonify({"message": "User not found"}), 404
2025-07-15 15:45:17 +01:00
@api_blueprint.route("/getStreamNames")
@requires_basic_auth
2025-07-15 15:45:17 +01:00
def get_stream_names_route(username: str, password: str) -> Response:
"""Retrieves all stream names.
Args:
username: The username of the user.
password: The password of the user (used for authentication).
Returns:
A Flask JSON response containing the list of stream names.
"""
return get_stream_names()
2025-07-15 15:45:17 +01:00
@api_blueprint.route("/getUserAccounts/streams")
@requires_basic_auth
2025-07-15 15:45:17 +01:00
def get_user_accounts_streams_route(username: str, password: str) -> Response:
"""Retrieves the latest stream URLs from DNS.
Args:
username: The username of the user.
password: The password of the user (used for authentication).
Returns:
A Flask JSON response containing the list of stream URLs.
"""
return jsonify(get_latest_urls_from_dns())
2025-07-15 15:45:17 +01:00
@api_blueprint.route("/singleCheck", methods=["POST"])
@requires_basic_auth
2025-07-15 15:45:17 +01:00
def single_check_route(username: str, password: str) -> Response:
"""Performs a single account check.
Args:
username: The username of the user.
password: The password of the user (used for authentication).
Returns:
A Flask JSON response with the result of the check.
"""
return single_check()
2025-07-15 15:45:17 +01:00
@api_blueprint.route("/addAccount", methods=["POST"])
@requires_basic_auth
2025-07-15 15:45:17 +01:00
def add_account_route(username: str, password: str) -> Response:
"""Adds a new account for the user.
Args:
username: The username of the user.
password: The password of the user (used for authentication).
Returns:
A Flask JSON response confirming the account was added or an error message.
"""
2025-07-14 19:18:47 +01:00
user_id = get_user_id_from_username(username)
return add_account(user_id)
2025-07-15 15:45:17 +01:00
@api_blueprint.route("/deleteAccount", methods=["POST"])
@requires_basic_auth
2025-07-15 15:45:17 +01:00
def delete_account_route(username: str, password: str) -> Response:
"""Deletes an account for the user.
Args:
username: The username of the user.
password: The password of the user (used for authentication).
Returns:
A Flask JSON response confirming the account was deleted or an error message.
"""
2025-07-14 19:18:47 +01:00
user_id = get_user_id_from_username(username)
2025-07-15 09:28:47 +01:00
return delete_account(user_id)
2025-07-15 15:45:17 +01:00
@api_blueprint.route("/validateAccount", methods=["POST"])
@requires_basic_auth
2025-07-15 15:45:17 +01:00
def validate_account_route(username: str, password: str) -> Tuple[Response, int]:
"""Validates an account.
Args:
username: The username of the user.
password: The password of the user (used for authentication).
Returns:
A tuple containing a Flask JSON response and an HTTP status code.
"""
return validate_account()
2025-07-15 15:45:17 +01:00
2025-07-15 09:28:47 +01:00
@api_blueprint.route("/Login")
@requires_basic_auth
2025-07-15 15:45:17 +01:00
def login_route(username: str, password: str) -> Response:
"""Logs a user in.
Args:
username: The username of the user.
password: The password of the user.
Returns:
A Flask JSON response with the result of the login attempt.
"""
2025-07-17 15:41:47 +01:00
return check_login(username, password)
2025-07-17 16:23:16 +01:00
@api_blueprint.route("/vapid-public-key", methods=["GET"])
def vapid_public_key():
"""Provides the VAPID public key."""
public_key = current_app.config["VAPID_PUBLIC_KEY"]
2025-07-17 17:08:14 +01:00
# Clean up the key by removing headers, footers, and all whitespace
public_key = "".join(public_key.replace("-----BEGIN PUBLIC KEY-----", "").replace("-----END PUBLIC KEY-----", "").split())
2025-07-17 16:23:16 +01:00
return jsonify({"public_key": public_key})
2025-07-17 15:41:47 +01:00
@api_blueprint.route("/save-subscription", methods=["POST"])
@requires_basic_auth
def save_subscription(username: str, password: str) -> Response:
"""Saves a push notification subscription.
Args:
username: The username of the user.
password: The password of the user.
Returns:
A Flask JSON response.
"""
user_id = get_user_id_from_username(username)
if not user_id:
return jsonify({"message": "User not found"}), 404
subscription_data = request.get_json()
if not subscription_data:
return jsonify({"message": "No subscription data provided"}), 400
save_push_subscription(user_id, json.dumps(subscription_data))
return jsonify({"message": "Subscription saved."})
def send_notification(subscription_info, message_body):
try:
webpush(
subscription_info=subscription_info,
data=message_body,
vapid_private_key=current_app.config["VAPID_PRIVATE_KEY"],
vapid_claims={"sub": "mailto:your-email@example.com"},
)
except WebPushException as ex:
print(f"Web push error: {ex}")
# You might want to remove the subscription if it's invalid
if ex.response and ex.response.status_code == 410:
print("Subscription is no longer valid, removing from DB.")
# Add logic to remove the subscription from your database
@api_blueprint.route("/send-expiry-notifications", methods=["POST"])
@requires_basic_auth
def send_expiry_notifications_route(username: str, password: str) -> Response:
"""Triggers the sending of expiry notifications.
Args:
username: The username of the user.
password: The password of the user.
Returns:
A Flask JSON response.
"""
from ktvmanager.account_checker import send_expiry_notifications
send_expiry_notifications()
return jsonify({"message": "Expiry notifications sent."})