extend notifications
This commit is contained in:
parent
93e9a1990a
commit
c79a908281
@ -3,7 +3,7 @@ import sys
|
|||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
import mysql.connector
|
import mysql.connector
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from routes.api import send_notification
|
from ktvmanager.lib.notifications import send_notification
|
||||||
from ktvmanager.lib.database import get_push_subscriptions, _execute_query
|
from ktvmanager.lib.database import get_push_subscriptions, _execute_query
|
||||||
|
|
||||||
# Add the project root to the Python path
|
# Add the project root to the Python path
|
||||||
@ -33,41 +33,46 @@ def get_all_accounts(db_connection: MySQLConnection) -> List[Dict[str, Any]]:
|
|||||||
return accounts
|
return accounts
|
||||||
|
|
||||||
|
|
||||||
def send_expiry_notifications() -> None:
|
def send_expiry_notifications(app) -> None:
|
||||||
"""
|
"""
|
||||||
Sends notifications to users with accounts expiring in the next 30 days.
|
Sends notifications to users with accounts expiring in the next 30 days.
|
||||||
"""
|
"""
|
||||||
now = datetime.now()
|
with app.app_context():
|
||||||
thirty_days_later = now + timedelta(days=30)
|
now = datetime.now()
|
||||||
now_timestamp = int(now.timestamp())
|
thirty_days_later = now + timedelta(days=30)
|
||||||
thirty_days_later_timestamp = int(thirty_days_later.timestamp())
|
now_timestamp = int(now.timestamp())
|
||||||
|
thirty_days_later_timestamp = int(thirty_days_later.timestamp())
|
||||||
|
|
||||||
query = """
|
query = """
|
||||||
SELECT u.id as user_id, ua.username, ua.expiaryDate
|
SELECT u.id as user_id, ua.username, ua.expiaryDate
|
||||||
FROM users u
|
FROM users u
|
||||||
JOIN userAccounts ua ON u.id = ua.userID
|
JOIN userAccounts ua ON u.id = ua.userID
|
||||||
WHERE ua.expiaryDate BETWEEN %s AND %s
|
WHERE ua.expiaryDate BETWEEN %s AND %s
|
||||||
"""
|
"""
|
||||||
expiring_accounts = _execute_query(query, (now_timestamp, thirty_days_later_timestamp))
|
expiring_accounts = _execute_query(query, (now_timestamp, thirty_days_later_timestamp))
|
||||||
|
|
||||||
for account in expiring_accounts:
|
for account in expiring_accounts:
|
||||||
user_id = account['user_id']
|
expiry_date = datetime.fromtimestamp(account['expiaryDate'])
|
||||||
subscriptions = get_push_subscriptions(user_id)
|
days_to_expiry = (expiry_date - now).days
|
||||||
for sub in subscriptions:
|
|
||||||
# Check if a notification has been sent recently
|
|
||||||
last_notified_query = "SELECT last_notified FROM push_subscriptions WHERE id = %s"
|
|
||||||
last_notified_result = _execute_query(last_notified_query, (sub['id'],))
|
|
||||||
last_notified = last_notified_result[0]['last_notified'] if last_notified_result and last_notified_result[0]['last_notified'] else None
|
|
||||||
|
|
||||||
if last_notified and last_notified > now - timedelta(days=1):
|
if days_to_expiry == 30 or days_to_expiry == 7:
|
||||||
continue
|
user_id = account['user_id']
|
||||||
|
subscriptions = get_push_subscriptions(user_id)
|
||||||
|
for sub in subscriptions:
|
||||||
|
# Check if a notification has been sent recently
|
||||||
|
last_notified_query = "SELECT last_notified FROM push_subscriptions WHERE id = %s"
|
||||||
|
last_notified_result = _execute_query(last_notified_query, (sub['id'],))
|
||||||
|
last_notified = last_notified_result[0]['last_notified'] if last_notified_result and last_notified_result[0]['last_notified'] else None
|
||||||
|
|
||||||
message = f"Your account {account['username']} is due to expire on {datetime.fromtimestamp(account['expiaryDate']).strftime('%d-%m-%Y')}."
|
if last_notified and last_notified.date() == now.date():
|
||||||
send_notification(sub['subscription_json'], message)
|
continue
|
||||||
|
|
||||||
# Update the last notified timestamp
|
message = f"Your account {account['username']} is due to expire in {days_to_expiry} days."
|
||||||
update_last_notified_query = "UPDATE push_subscriptions SET last_notified = %s WHERE id = %s"
|
send_notification(sub['subscription_json'], message)
|
||||||
_execute_query(update_last_notified_query, (now, sub['id']))
|
|
||||||
|
# Update the last notified timestamp
|
||||||
|
update_last_notified_query = "UPDATE push_subscriptions SET last_notified = %s WHERE id = %s"
|
||||||
|
_execute_query(update_last_notified_query, (now, sub['id']))
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
|
17
ktvmanager/lib/notifications.py
Normal file
17
ktvmanager/lib/notifications.py
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
from flask import current_app
|
||||||
|
from pywebpush import webpush, WebPushException
|
||||||
|
|
||||||
|
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": current_app.config["VAPID_CLAIM_EMAIL"]},
|
||||||
|
)
|
||||||
|
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
|
@ -4,6 +4,8 @@ from dotenv import load_dotenv
|
|||||||
from ktvmanager.config import DevelopmentConfig, ProductionConfig
|
from ktvmanager.config import DevelopmentConfig, ProductionConfig
|
||||||
from routes.api import api_blueprint
|
from routes.api import api_blueprint
|
||||||
from ktvmanager.lib.database import initialize_db_pool
|
from ktvmanager.lib.database import initialize_db_pool
|
||||||
|
from ktvmanager.account_checker import send_expiry_notifications
|
||||||
|
from apscheduler.schedulers.background import BackgroundScheduler
|
||||||
|
|
||||||
def create_app():
|
def create_app():
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
@ -17,6 +19,12 @@ def create_app():
|
|||||||
with app.app_context():
|
with app.app_context():
|
||||||
initialize_db_pool()
|
initialize_db_pool()
|
||||||
|
|
||||||
|
# Schedule the daily account check
|
||||||
|
scheduler = BackgroundScheduler()
|
||||||
|
# Pass the app instance to the job
|
||||||
|
scheduler.add_job(func=lambda: send_expiry_notifications(app), trigger="interval", days=1)
|
||||||
|
scheduler.start()
|
||||||
|
|
||||||
# Register blueprints
|
# Register blueprints
|
||||||
app.register_blueprint(api_blueprint)
|
app.register_blueprint(api_blueprint)
|
||||||
|
|
||||||
|
@ -38,4 +38,5 @@ mysql-connector-python
|
|||||||
python-dotenv
|
python-dotenv
|
||||||
python-dotenv
|
python-dotenv
|
||||||
pywebpush==1.13.0
|
pywebpush==1.13.0
|
||||||
stem==1.8.2
|
stem==1.8.2
|
||||||
|
APScheduler==3.10.4
|
@ -18,7 +18,7 @@ import re
|
|||||||
import base64
|
import base64
|
||||||
from cryptography.hazmat.primitives import serialization
|
from cryptography.hazmat.primitives import serialization
|
||||||
from cryptography.hazmat.primitives.asymmetric import ec
|
from cryptography.hazmat.primitives.asymmetric import ec
|
||||||
from pywebpush import webpush, WebPushException
|
from ktvmanager.lib.notifications import send_notification
|
||||||
|
|
||||||
api_blueprint = Blueprint("api", __name__)
|
api_blueprint = Blueprint("api", __name__)
|
||||||
|
|
||||||
@ -196,20 +196,6 @@ def save_subscription(username: str, password: str) -> Response:
|
|||||||
return jsonify({"message": "Subscription saved."})
|
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": current_app.config["VAPID_CLAIM_EMAIL"]},
|
|
||||||
)
|
|
||||||
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"])
|
@api_blueprint.route("/send-expiry-notifications", methods=["POST"])
|
||||||
|
Loading…
x
Reference in New Issue
Block a user