shri-jai commited on
Commit
bf6502c
·
1 Parent(s): c7e8cc0

feat: notifying all users

Browse files
.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)}