Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sandbox for Notifications Functionality #452

Open
wants to merge 24 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
6108345
Get basic infra for service workers and notifications up
anantmittal Aug 29, 2023
387dfa6
Fixed documentdb string for mongodb compass
anantmittal Sep 29, 2023
2b19c4e
Merge branch 'develop' of github.com:uwscope/scope-web into notificat…
anantmittal Oct 16, 2023
c24daad
Create notification permissions schema
anantmittal Oct 16, 2023
69dd9ed
Add notification-permissions to patient and document schema
anantmittal Oct 16, 2023
284c384
Add fixture for notification permissions
anantmittal Oct 16, 2023
f73902e
Test notification permissions fixture
anantmittal Oct 16, 2023
cb1ad74
Add database calls for notification persmissions
anantmittal Oct 16, 2023
c122bf0
Add notification permissions to flask
anantmittal Oct 16, 2023
bb3b783
Add database, fixtures, schema, flask, tests for push subscriptions
anantmittal Oct 17, 2023
fcf6dc0
Add pywebpush to setup.py
anantmittal Nov 29, 2023
a37af09
Remove old notification permissions related code
anantmittal Nov 29, 2023
6ab28d4
web_shared: Add push subscription types and service
anantmittal Nov 29, 2023
c9c460e
PatientStore: Add push subscription to store
anantmittal Nov 29, 2023
14f8e05
web_patient: Update service worker code and add notification settings
anantmittal Nov 29, 2023
b53869b
Add invoke task to trigger push notification
anantmittal Nov 29, 2023
bdf3b59
Flask: add/update push subscription
anantmittal Nov 29, 2023
8e77d7f
Update push subscriptions fixtures
anantmittal Nov 29, 2023
b424b2b
Update database layer
anantmittal Nov 29, 2023
3cc04d8
Add web push schema to store webpush responses
anantmittal Nov 29, 2023
f5a7439
Add vapid config to scope_shared
anantmittal Nov 29, 2023
3234215
Merge branch 'develop' of github.com:uwscope/scope-web into notificat…
anantmittal Feb 26, 2024
1fdfb0b
Fix web_patient package.json
anantmittal Feb 26, 2024
a3a2278
Update web_patient yarn.lock file
anantmittal Feb 26, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions scope_shared/scope/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
from scope.config.documentdb import DocumentDBConfig
from scope.config.flask import FlaskClientConfig
from scope.config.flask import FlaskConfig
from scope.config.vapid import VapidKeysConfig
33 changes: 33 additions & 0 deletions scope_shared/scope/config/vapid.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from dataclasses import dataclass
from pathlib import Path
import ruamel.yaml
from typing import Union


@dataclass(frozen=True)
class VapidKeysConfig:
"""
Configuration for vapid keys.
"""

public_key: str
private_key: str
claim_email: str

@staticmethod
def load(config_path: Union[Path, str]):
config_path = Path(config_path)

with open(config_path) as config_file:
yaml = ruamel.yaml.YAML(typ="safe", pure=True)
config_dict = yaml.load(config_file)

return VapidKeysConfig.parse(config_dict)

@staticmethod
def parse(config_dict: dict):
return VapidKeysConfig(
public_key=config_dict["vapid_public_key"],
private_key=config_dict["vapid_private_key"],
claim_email=config_dict["vapid_claim_email"],
)
36 changes: 36 additions & 0 deletions scope_shared/scope/database/database_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import pymongo.collection
import pymongo.database

from typing import List, Optional

import scope.database.date_utils as date_utils
import scope.database.collection_utils
import scope.database.patient.assessments
import scope.database.patient.clinical_history
import scope.database.patient.patient_profile
import scope.database.patient.safety_plan
import scope.database.patient.values_inventory
import scope.enums
import scope.schema
import scope.schema_utils as schema_utils


def get_patient_collections(
*,
database: pymongo.database.Database,
) -> Optional[List[pymongo.collection.Collection]]:
"""
Retrieve all patient collections documents.
"""

collection_names = database.list_collection_names()

patient_collection_names = list(
filter(lambda cn: "patient_" in cn, collection_names)
)

patient_collections: List[pymongo.collection.Collection] = []
for patient_collection_name in patient_collection_names:
patient_collections.append(database.get_collection(patient_collection_name))

return patient_collections
6 changes: 6 additions & 0 deletions scope_shared/scope/database/patient/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@
get_patient_profile,
put_patient_profile,
)
from scope.database.patient.push_subscriptions import (
get_push_subscriptions,
get_push_subscription,
post_push_subscription,
put_push_subscription,
)
from scope.database.patient.scheduled_activities import (
get_scheduled_activities,
get_scheduled_activity,
Expand Down
91 changes: 91 additions & 0 deletions scope_shared/scope/database/patient/push_subscriptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
from typing import List, Optional

import pymongo.collection
import scope.database.collection_utils

DOCUMENT_TYPE = "pushSubscription"
SEMANTIC_SET_ID = "pushSubscriptionId"


def delete_push_subscription(
*,
collection: pymongo.collection.Collection,
set_id: str,
rev: int,
) -> scope.database.collection_utils.SetPutResult:
"""
Delete "push-subscription" document.
"""

return scope.database.collection_utils.delete_set_element(
collection=collection,
document_type=DOCUMENT_TYPE,
set_id=set_id,
rev=rev,
)


def get_push_subscriptions(
*,
collection: pymongo.collection.Collection,
) -> Optional[List[dict]]:
"""
Get list of "pushSubscription" documents.
"""

return scope.database.collection_utils.get_set(
collection=collection,
document_type=DOCUMENT_TYPE,
)


def get_push_subscription(
*,
collection: pymongo.collection.Collection,
set_id: str,
) -> Optional[dict]:
"""
Get "pushSubscription" document.
"""

return scope.database.collection_utils.get_set_element(
collection=collection,
document_type=DOCUMENT_TYPE,
set_id=set_id,
)


def post_push_subscription(
*,
collection: pymongo.collection.Collection,
push_subscription: dict,
) -> scope.database.collection_utils.SetPostResult:
"""
Post "pushSubscription" document.
"""

return scope.database.collection_utils.post_set_element(
collection=collection,
document_type=DOCUMENT_TYPE,
semantic_set_id=SEMANTIC_SET_ID,
document=push_subscription,
)


def put_push_subscription(
*,
collection: pymongo.collection.Collection,
push_subscription: dict,
set_id: str,
) -> scope.database.collection_utils.SetPutResult:
"""
Put "pushSubscription" document.
"""

return scope.database.collection_utils.put_set_element(
collection=collection,
document_type=DOCUMENT_TYPE,
semantic_set_id=SEMANTIC_SET_ID,
set_id=set_id,
document=push_subscription,
)
Empty file.
7 changes: 7 additions & 0 deletions scope_shared/scope/notifications/messages.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import pymongo.collection


def compute_daily_summary(
collection: pymongo.collection.Collection,
):
return "<Create notification message for daily patient summary>"
34 changes: 34 additions & 0 deletions scope_shared/scope/notifications/webpush_handler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"""Module provides a function to trigger a push notification to a web browser."""
import json
import requests
from pywebpush import webpush, WebPushException
import scope.config
from typing import Union


def trigger_push_notification(
vapid_config: scope.config.VapidKeysConfig,
push_subscription: dict,
title: str,
options: dict,
) -> str:
"""Function to trigger a push notification to a web browser."""
try:
subscription_info = {
"endpoint": push_subscription["endpoint"],
"keys": {
"auth": push_subscription["keys"]["auth"],
"p256dh": push_subscription["keys"]["p256dh"],
},
}

response = webpush(
subscription_info=subscription_info,
data=json.dumps({"title": title, "options": options}),
vapid_private_key=vapid_config.private_key,
vapid_claims={"sub": f"mailto:{vapid_config.claim_email}"},
)

return repr(response)
except WebPushException as ex:
return str(ex)
4 changes: 4 additions & 0 deletions scope_shared/scope/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
populate_config_account_schema: Optional[jschon.JSONSchema] = None
provider_identity_schema: Optional[jschon.JSONSchema] = None
provider_identities_schema: Optional[jschon.JSONSchema] = None
push_subscription_schema: Optional[jschon.JSONSchema] = None
push_subscriptions_schema: Optional[jschon.JSONSchema] = None
referral_status_schema: Optional[jschon.JSONSchema] = None
regexes: Optional[jschon.JSONSchema] = None
resource_content_schema: Optional[jschon.JSONSchema] = None
Expand Down Expand Up @@ -100,6 +102,8 @@
"patient_profile_schema": "documents/patient-profile.json",
"provider_identity_schema": "documents/provider-identity.json",
"provider_identities_schema": "documents/provider-identities.json",
"push_subscription_schema": "documents/push-subscription.json",
"push_subscriptions_schema": "documents/push-subscriptions.json",
"safety_plan_schema": "documents/safety-plan.json",
"scheduled_activity_schema": "documents/scheduled-activity.json",
"scheduled_activities_schema": "documents/scheduled-activities.json",
Expand Down
3 changes: 3 additions & 0 deletions scope_shared/scope/schemas/api/patient.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@
"description": "IPatientProfile schema",
"$ref": "/schemas/documents/patient-profile"
},
"pushSubscriptions": {
"$ref": "/schemas/documents/push-subscriptions"
},
"safetyPlan": {
"type": "object",
"description": "ISafetyPlan schema",
Expand Down
3 changes: 3 additions & 0 deletions scope_shared/scope/schemas/document.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@
{
"$ref": "/schemas/documents/patient-profile"
},
{
"$ref": "/schemas/documents/push-subscription"
},
{
"$ref": "/schemas/documents/safety-plan"
},
Expand Down
45 changes: 45 additions & 0 deletions scope_shared/scope/schemas/documents/push-subscription.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://uwscope.org/schemas/documents/push-subscription",
"title": "IPushSubscription",
"description": "IPushSubscription Type",
"type": "object",
"properties": {
"_id": {
"type": "string"
},
"_type": {
"const": "pushSubscription"
},
"_set_id": {
"type": "string"
},
"_rev": {
"type": "number"
},
"pushSubscriptionId": {
"type": "string"
},
"endpoint": {
"type": "string"
},
"expirationTime": {
"type": ["number", "null"]
},
"keys": {
"type": "object",
"properties": {
"p256dh": {
"type": "string"
},
"auth": {
"type": "string"
}
},
"additionalProperties": false,
"required": ["p256dh", "auth"]
}
},
"additionalProperties": false,
"required": ["_type", "endpoint", "expirationTime", "keys"]
}
9 changes: 9 additions & 0 deletions scope_shared/scope/schemas/documents/push-subscriptions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://uwscope.org/schemas/documents/push-subscriptions",
"title": "IPushSubscription[]",
"type": "array",
"items": {
"$ref": "/schemas/documents/push-subscription"
}
}
34 changes: 34 additions & 0 deletions scope_shared/scope/schemas/documents/web-push.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://uwscope.org/schemas/documents/web-push",
"title": "Webpush Details",
"type": "object",
"properties": {
"_id": {
"type": "string"
},
"_type": {
"const": "webpushResponse"
},
"_set_id": {
"type": "string"
},
"_rev": {
"type": "number"
},
"webPushId": {
"type": "string"
},
"message": {
"type": "string"
},
"response": {
"type": "string"
},
"editedDateTime": {
"$ref": "/schemas/utils/datetime#/properties/datetime"
}
},
"additionalProperties": false,
"required": ["_type", "message", "response", "editedDateTime"]
}
9 changes: 9 additions & 0 deletions scope_shared/scope/schemas/documents/web-pushes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://uwscope.org/schemas/documents/web-pushes",
"title": "Webpush Details",
"type": "array",
"items": {
"$ref": "/schemas/documents/web-push"
}
}
Loading