Spaces:
Sleeping
Sleeping
shri-jai
commited on
Commit
·
bf6502c
1
Parent(s):
c7e8cc0
feat: notifying all users
Browse files- .github/workflows/notify.yml +26 -0
- alembic/versions/52828bff621c_updated_leave_status_enum_cancelled.py +31 -0
- src/home/router.py +27 -2
- src/home/schemas.py +5 -0
- src/home/service.py +17 -1
.github/workflows/notify.yml
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: Daily Emotion Check-In Notifications
|
| 2 |
+
|
| 3 |
+
on:
|
| 4 |
+
schedule:
|
| 5 |
+
- cron: "30 3 * * *"
|
| 6 |
+
- cron: "15 11 * * *"
|
| 7 |
+
workflow_dispatch: {}
|
| 8 |
+
|
| 9 |
+
jobs:
|
| 10 |
+
notify:
|
| 11 |
+
runs-on: ubuntu-latest
|
| 12 |
+
|
| 13 |
+
steps:
|
| 14 |
+
- name: Call notify-all endpoint
|
| 15 |
+
run: |
|
| 16 |
+
curl -X POST "http://192.168.0.108:8080/home/notify/all" \
|
| 17 |
+
-H "accept: application/json" \
|
| 18 |
+
-H "Content-Type: application/json" \
|
| 19 |
+
-d '{
|
| 20 |
+
"title": "Jimbal Kae Sambar",
|
| 21 |
+
"body": "Chitu'\''s Sunday party",
|
| 22 |
+
"data": {
|
| 23 |
+
"type": "home_alert",
|
| 24 |
+
"message": "Chitu invited you to Sunday party!"
|
| 25 |
+
}
|
| 26 |
+
}'
|
alembic/versions/52828bff621c_updated_leave_status_enum_cancelled.py
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""updated leave_status enum CANCELLED
|
| 2 |
+
|
| 3 |
+
Revision ID: 52828bff621c
|
| 4 |
+
Revises: d9bb355538fd
|
| 5 |
+
Create Date: 2025-11-25 20:04:09.823594
|
| 6 |
+
|
| 7 |
+
"""
|
| 8 |
+
from typing import Sequence, Union
|
| 9 |
+
|
| 10 |
+
from alembic import op
|
| 11 |
+
import sqlalchemy as sa
|
| 12 |
+
import sqlmodel.sql.sqltypes
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
# revision identifiers, used by Alembic.
|
| 16 |
+
revision: str = '52828bff621c'
|
| 17 |
+
down_revision: Union[str, Sequence[str], None] = 'd9bb355538fd'
|
| 18 |
+
branch_labels: Union[str, Sequence[str], None] = None
|
| 19 |
+
depends_on: Union[str, Sequence[str], None] = None
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def upgrade() -> None:
|
| 23 |
+
"""Upgrade schema."""
|
| 24 |
+
pass
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def downgrade() -> None:
|
| 28 |
+
"""Downgrade schema."""
|
| 29 |
+
# ### commands auto generated by Alembic - please adjust! ###
|
| 30 |
+
pass
|
| 31 |
+
# ### end Alembic commands ###
|
src/home/router.py
CHANGED
|
@@ -6,8 +6,8 @@ from sqlmodel.ext.asyncio.session import AsyncSession
|
|
| 6 |
from src.core.database import get_async_session
|
| 7 |
from src.core.schemas import BaseResponse
|
| 8 |
from src.auth.utils import get_current_user
|
| 9 |
-
from .schemas import EmotionLogCreate, EmotionLogResponse, HomeResponseData
|
| 10 |
-
from .service import add_or_update_emotion, get_emotions, get_home_data
|
| 11 |
|
| 12 |
router = APIRouter(tags=["Home"])
|
| 13 |
|
|
@@ -42,3 +42,28 @@ async def get_user_emotions(
|
|
| 42 |
):
|
| 43 |
data = await get_emotions(user_id, session)
|
| 44 |
return {"status_code": 200, "data": data}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
from src.core.database import get_async_session
|
| 7 |
from src.core.schemas import BaseResponse
|
| 8 |
from src.auth.utils import get_current_user
|
| 9 |
+
from .schemas import EmotionLogCreate, EmotionLogResponse, HomeResponseData, BroadcastNotificationRequest
|
| 10 |
+
from .service import add_or_update_emotion, get_emotions, get_home_data, send_broadcast_notification
|
| 11 |
|
| 12 |
router = APIRouter(tags=["Home"])
|
| 13 |
|
|
|
|
| 42 |
):
|
| 43 |
data = await get_emotions(user_id, session)
|
| 44 |
return {"status_code": 200, "data": data}
|
| 45 |
+
|
| 46 |
+
@router.post("/notify/all")
|
| 47 |
+
async def notify_all_users(
|
| 48 |
+
payload: BroadcastNotificationRequest,
|
| 49 |
+
session: AsyncSession = Depends(get_async_session)
|
| 50 |
+
):
|
| 51 |
+
if payload.data:
|
| 52 |
+
safe_data = {k: str(v) for k, v in payload.data.items()}
|
| 53 |
+
else:
|
| 54 |
+
safe_data = {}
|
| 55 |
+
|
| 56 |
+
from .service import send_broadcast_notification
|
| 57 |
+
|
| 58 |
+
result = await send_broadcast_notification(
|
| 59 |
+
session,
|
| 60 |
+
payload.title,
|
| 61 |
+
payload.body,
|
| 62 |
+
safe_data
|
| 63 |
+
)
|
| 64 |
+
|
| 65 |
+
return {
|
| 66 |
+
"message": "Broadcast sent",
|
| 67 |
+
"devices_notified": result["sent"]
|
| 68 |
+
}
|
| 69 |
+
|
src/home/schemas.py
CHANGED
|
@@ -24,3 +24,8 @@ class HomeResponseData(BaseModel):
|
|
| 24 |
user_name: str
|
| 25 |
philosophy_text: str
|
| 26 |
recent_emotions: List[EmotionLogResponse]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 24 |
user_name: str
|
| 25 |
philosophy_text: str
|
| 26 |
recent_emotions: List[EmotionLogResponse]
|
| 27 |
+
|
| 28 |
+
class BroadcastNotificationRequest(BaseModel):
|
| 29 |
+
title: str
|
| 30 |
+
body: str
|
| 31 |
+
data: dict | None = None
|
src/home/service.py
CHANGED
|
@@ -4,7 +4,8 @@ from sqlmodel import select
|
|
| 4 |
from sqlmodel.ext.asyncio.session import AsyncSession
|
| 5 |
|
| 6 |
from src.core.models import EmotionLogs, Users
|
| 7 |
-
|
|
|
|
| 8 |
from .schemas import EmotionLogCreate, EmotionLogResponse, HomeResponseData
|
| 9 |
|
| 10 |
PHILOSOPHY_TEXT = "Your mind is your greatest asset — train it daily."
|
|
@@ -97,3 +98,18 @@ async def get_emotions(user_id: str, session: AsyncSession):
|
|
| 97 |
)
|
| 98 |
for log in logs
|
| 99 |
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
from sqlmodel.ext.asyncio.session import AsyncSession
|
| 5 |
|
| 6 |
from src.core.models import EmotionLogs, Users
|
| 7 |
+
from src.profile.models import UserDevices
|
| 8 |
+
from src.notifications.fcm import send_fcm
|
| 9 |
from .schemas import EmotionLogCreate, EmotionLogResponse, HomeResponseData
|
| 10 |
|
| 11 |
PHILOSOPHY_TEXT = "Your mind is your greatest asset — train it daily."
|
|
|
|
| 98 |
)
|
| 99 |
for log in logs
|
| 100 |
]
|
| 101 |
+
|
| 102 |
+
async def get_all_device_tokens(session):
|
| 103 |
+
stmt = select(UserDevices.device_token)
|
| 104 |
+
rows = (await session.execute(stmt)).all()
|
| 105 |
+
return [r[0] for r in rows]
|
| 106 |
+
|
| 107 |
+
|
| 108 |
+
async def send_broadcast_notification(session, title, body, data=None):
|
| 109 |
+
tokens = await get_all_device_tokens(session)
|
| 110 |
+
|
| 111 |
+
if not tokens:
|
| 112 |
+
return {"sent": 0}
|
| 113 |
+
|
| 114 |
+
await send_fcm(tokens, title, body, data)
|
| 115 |
+
return {"sent": len(tokens)}
|