All checks were successful
Chore App Build, Test, and Push Docker Images / build-and-push (push) Successful in 2m14s
- Implemented push subscription API with tests for subscribing and unsubscribing users. - Created web push notification tests triggered by child actions. - Added digest scheduler to send email digests to users at 9 PM local time. - Developed utility functions for creating and validating digest action tokens. - Integrated web push sender to handle sending notifications to users. - Added service worker for handling push notifications in the frontend. - Created a push opt-in component for user notification preferences. - Implemented tests for the push opt-in component to ensure correct behavior. - Updated frontend services to manage push subscriptions and permissions.
60 lines
2.2 KiB
Python
60 lines
2.2 KiB
Python
from flask import Blueprint, request, jsonify, current_app
|
|
from tinydb import Query
|
|
|
|
from api.utils import get_validated_user_id
|
|
from db.push_subscriptions import upsert_subscription, delete_by_endpoint
|
|
from db.db import users_db
|
|
|
|
push_subscription_api = Blueprint('push_subscription_api', __name__)
|
|
|
|
|
|
@push_subscription_api.route('/push-vapid-key', methods=['GET'])
|
|
def get_vapid_public_key():
|
|
"""Return the VAPID public key for the frontend to use when subscribing."""
|
|
public_key = current_app.config.get('VAPID_PUBLIC_KEY', '')
|
|
return jsonify({'public_key': public_key}), 200
|
|
|
|
|
|
@push_subscription_api.route('/push-subscription', methods=['POST'])
|
|
def subscribe():
|
|
"""Upsert a push subscription for the current user."""
|
|
user_id = get_validated_user_id()
|
|
if not user_id:
|
|
return jsonify({'error': 'Unauthorized', 'code': 'UNAUTHORIZED'}), 401
|
|
|
|
data = request.get_json() or {}
|
|
endpoint = data.get('endpoint')
|
|
keys = data.get('keys')
|
|
timezone_str = data.get('timezone')
|
|
|
|
if not endpoint or not isinstance(keys, dict):
|
|
return jsonify({'error': 'endpoint and keys are required', 'code': 'MISSING_FIELDS'}), 400
|
|
if 'p256dh' not in keys or 'auth' not in keys:
|
|
return jsonify({'error': 'keys must contain p256dh and auth', 'code': 'MISSING_FIELDS'}), 400
|
|
|
|
sub = upsert_subscription(user_id=user_id, endpoint=endpoint, keys=keys)
|
|
|
|
# Update user timezone if provided
|
|
if timezone_str:
|
|
UserQ = Query()
|
|
users_db.update({'timezone': timezone_str}, UserQ.id == user_id)
|
|
|
|
return jsonify({'message': 'Subscription saved', 'id': sub.id}), 200
|
|
|
|
|
|
@push_subscription_api.route('/push-subscription', methods=['DELETE'])
|
|
def unsubscribe():
|
|
"""Remove a push subscription for the current user by endpoint."""
|
|
user_id = get_validated_user_id()
|
|
if not user_id:
|
|
return jsonify({'error': 'Unauthorized', 'code': 'UNAUTHORIZED'}), 401
|
|
|
|
data = request.get_json() or {}
|
|
endpoint = data.get('endpoint')
|
|
|
|
if not endpoint:
|
|
return jsonify({'error': 'endpoint is required', 'code': 'MISSING_FIELDS'}), 400
|
|
|
|
removed = delete_by_endpoint(user_id=user_id, endpoint=endpoint)
|
|
return jsonify({'message': 'Subscription removed', 'removed': removed}), 200
|