Compare commits
	
		
			2 Commits
		
	
	
		
			93e9a1990a
			...
			211afa3966
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 211afa3966 | |||
| c79a908281 | 
| @ -1,5 +1,5 @@ | |||||||
| [tool.bumpversion] | [tool.bumpversion] | ||||||
| current_version = "1.2.18" | current_version = "1.2.19" | ||||||
| commit = true | commit = true | ||||||
| tag = true | tag = true | ||||||
| tag_name = "{new_version}" | tag_name = "{new_version}" | ||||||
|  | |||||||
| @ -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) | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -39,3 +39,4 @@ 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