[FEAT] Push notification integration into core (#1393)

* push notification integration into core

added missing component

fixed bell working on all pages
- made pubkey global template env var
- had to move `get_push_notification_pubkey` to `helpers.py` because of circular reference with `tasks.py`

formay

trying to fix mypy

added py-vapid to requirements

Trying to fix stub mypy issue

* removed key files

* webpush key pair is saved in db `webpush_settings`

* removed lnaddress extension changes

* support for multi user account subscriptions, subscriptions are stored user based

fixed syntax error

fixed syntax error

removed unused line

* fixed subscribed user storage with local storage, no get request required

* method is singular now

* cleanup unsubscribed or expired push subscriptions

fixed flake8 errors

fixed poetry errors

* updating to latest lnbits

formatting, rebase error

fix

* remove unused?

* revert

* relock

* remove

* do not create settings table use adminsettings

mypy

fix

* cleanup old code

* catch case when client tries to recreate existing webpush subscription e.g. on cleared local storage

* show notification bell on user related pages only

* use local storage with one key like array, some refactoring

* fixed crud import

* fixed too long line

* removed unused imports

* ruff

* make webpush editable

* fixed privkey encoding

* fix ruff

* fix migration

---------

Co-authored-by: schneimi <admin@schneimi.de>
Co-authored-by: schneimi <dev@schneimi.de>
Co-authored-by: dni  <office@dnilabs.com>
This commit is contained in:
schneimi
2023-09-11 14:48:49 +01:00
committed by GitHub
co-authored by schneimi schneimi dni ⚡
parent 8f0c1f6a80
commit fb98576431
17 changed files with 571 additions and 21 deletions
+104 -4
View File
@@ -10,10 +10,23 @@ from lnbits import bolt11
from lnbits.core.models import WalletType
from lnbits.db import Connection, Database, Filters, Page
from lnbits.extension_manager import InstallableExtension
from lnbits.settings import AdminSettings, EditableSettings, SuperSettings, settings
from lnbits.settings import (
AdminSettings,
SuperSettings,
WebPushSettings,
settings,
)
from . import db
from .models import BalanceCheck, Payment, PaymentFilters, TinyURL, User, Wallet
from .models import (
BalanceCheck,
Payment,
PaymentFilters,
TinyURL,
User,
Wallet,
WebPushSubscription,
)
# accounts
# --------
@@ -788,8 +801,16 @@ async def delete_admin_settings():
await db.execute("DELETE FROM settings")
async def update_admin_settings(data: EditableSettings):
await db.execute("UPDATE settings SET editable_settings = ?", (json.dumps(data),))
async def update_admin_settings(data: dict):
row = await db.fetchone("SELECT editable_settings FROM settings")
if not row:
return None
editable_settings = json.loads(row["editable_settings"])
for key, value in data.items():
editable_settings[key] = value
await db.execute(
"UPDATE settings SET editable_settings = ?", (json.dumps(editable_settings),)
)
async def update_super_user(super_user: str) -> SuperSettings:
@@ -872,3 +893,82 @@ async def delete_tinyurl(tinyurl_id: str):
"DELETE FROM tiny_url WHERE id = ?",
(tinyurl_id,),
)
# push_notification
# -----------------
async def get_webpush_settings() -> Optional[WebPushSettings]:
row = await db.fetchone("SELECT * FROM webpush_settings")
if not row:
return None
vapid_keypair = json.loads(row["vapid_keypair"])
return WebPushSettings(**vapid_keypair)
async def create_webpush_settings(webpush_settings: dict):
await db.execute(
"INSERT INTO webpush_settings (vapid_keypair) VALUES (?)",
(json.dumps(webpush_settings),),
)
return await get_webpush_settings()
async def get_webpush_subscription(
endpoint: str, user: str
) -> Optional[WebPushSubscription]:
row = await db.fetchone(
"SELECT * FROM webpush_subscriptions WHERE endpoint = ? AND user = ?",
(
endpoint,
user,
),
)
return WebPushSubscription(**dict(row)) if row else None
async def get_webpush_subscriptions_for_user(
user: str,
) -> List[WebPushSubscription]:
rows = await db.fetchall(
"SELECT * FROM webpush_subscriptions WHERE user = ?",
(user,),
)
return [WebPushSubscription(**dict(row)) for row in rows]
async def create_webpush_subscription(
endpoint: str, user: str, data: str, host: str
) -> WebPushSubscription:
await db.execute(
"""
INSERT INTO webpush_subscriptions (endpoint, user, data, host)
VALUES (?, ?, ?, ?)
""",
(
endpoint,
user,
data,
host,
),
)
subscription = await get_webpush_subscription(endpoint, user)
assert subscription, "Newly created webpush subscription couldn't be retrieved"
return subscription
async def delete_webpush_subscription(endpoint: str, user: str) -> None:
await db.execute(
"DELETE FROM webpush_subscriptions WHERE endpoint = ? AND user = ?",
(
endpoint,
user,
),
)
async def delete_webpush_subscriptions(endpoint: str) -> None:
await db.execute(
"DELETE FROM webpush_subscriptions WHERE endpoint = ?", (endpoint,)
)