accounts.fcm_service
FCM (Firebase Cloud Messaging) service for sending notifications to users.
Features:
- Initializes Firebase app using service account credentials.
- Send notification to a single user via FCM token.
- Send notification to multiple users via FCM tokens.
- Memo notification helpers for memo creation and tagging.
Functions:
- send_fcm_to_user(token, title, body, data): Send notification to a single user.
- send_fcm_to_users(tokens, title, body, data): Send notification to multiple users.
- memo_created_notification(info, memoId): Notify approvers and responders when a memo is created.
- memo_tagged_notification(info, tagged_role_name, tagged_role_id, memoId): Notify responders when a memo is tagged to their role.
1""" 2FCM (Firebase Cloud Messaging) service for sending notifications to users. 3 4Features: 5- Initializes Firebase app using service account credentials. 6- Send notification to a single user via FCM token. 7- Send notification to multiple users via FCM tokens. 8- Memo notification helpers for memo creation and tagging. 9 10Functions: 11- send_fcm_to_user(token, title, body, data): Send notification to a single user. 12- send_fcm_to_users(tokens, title, body, data): Send notification to multiple users. 13- memo_created_notification(info, memoId): Notify approvers and responders when a memo is created. 14- memo_tagged_notification(info, tagged_role_name, tagged_role_id, memoId): Notify responders when a memo is tagged to their role. 15""" 16 17import firebase_admin 18from firebase_admin import credentials, messaging 19import os 20from .models import User 21from django.db.models import Q 22 23BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 24FIREBASE_CRED_PATH = os.path.join(BASE_DIR, 'memo-track-firebase-adminsdk-fbsvc-060fb4e2e6.json') 25 26if not firebase_admin._apps: 27 cred = credentials.Certificate(FIREBASE_CRED_PATH) 28 firebase_admin.initialize_app(cred) 29 30def send_fcm_to_user(token: str, title: str, body: str, data: dict = None): 31 """ 32 Send a notification to a single user via FCM token. 33 34 Args: 35 token (str): FCM token of the user. 36 title (str): Notification title. 37 body (str): Notification body. 38 data (dict): Additional data payload. 39 40 Returns: 41 dict: Success or error response. 42 """ 43 if not token: 44 return {"error": "Missing FCM token"} 45 46 message = messaging.Message( 47 notification=messaging.Notification(title=title, body=body), 48 token=token, 49 data=data or {} 50 ) 51 52 try: 53 response = messaging.send(message) 54 return {"success": True, "response": response} 55 except Exception as e: 56 return {"error": str(e)} 57 58def send_fcm_to_users(tokens: list[str], title: str, body: str, data: dict = None): 59 """ 60 Send a notification to multiple users via FCM tokens. 61 62 Args: 63 tokens (list[str]): List of FCM tokens. 64 title (str): Notification title. 65 body (str): Notification body. 66 data (dict): Additional data payload. 67 68 Returns: 69 dict: Success/failure counts and failed tokens. 70 """ 71 if not tokens: 72 return {"error": "No FCM tokens provided"} 73 74 message = messaging.MulticastMessage( 75 notification=messaging.Notification(title=title, body=body), 76 tokens=tokens, 77 data=data or {}, 78 ) 79 80 try: 81 response = messaging.send_each_for_multicast(message) 82 failed_tokens = [] 83 84 for idx, resp in enumerate(response.responses): 85 if not resp.success: 86 failed_tokens.append(tokens[idx]) 87 88 print({ 89 "success": response.success_count, 90 "failure": response.failure_count, 91 "failed_tokens": failed_tokens, 92 }) 93 return { 94 "success": response.success_count, 95 "failure": response.failure_count, 96 "failed_tokens": failed_tokens, 97 } 98 99 except Exception as e: 100 print(f"Error sending FCM messages: {str(e)}") 101 return {"error": str(e)} 102 103def memo_created_notification(info, memoId): 104 """ 105 Send notification to approvers and responders when a memo is created. 106 107 Args: 108 info (dict): Memo info containing block, ward, and role details. 109 memoId (str): Memo ID. 110 111 Returns: 112 dict: FCM send result. 113 """ 114 title = "New Memo Created" 115 body = f"Memo has been created at Block:{info['current_block_name']},floor {info['current_floor']}, ward {info['current_ward_name']}" 116 data = { 117 "type": "memo_created", 118 "memo_id": memoId, 119 } 120 approver_tokens = list( 121 User.objects.filter( 122 is_logged_in=True, 123 current_block=info["current_block_id"], 124 role__is_approver=True 125 ).exclude(Q(fcm_token__isnull=True) | Q(fcm_token='')) 126 .values_list('fcm_token', flat=True) 127 ) 128 129 responder_tokens = list( 130 User.objects.filter( 131 is_logged_in=True, 132 role__id=info["tagged_role_id"] 133 ).exclude(Q(fcm_token__isnull=True) | Q(fcm_token='')) 134 .values_list('fcm_token', flat=True) 135 ) 136 tokens = approver_tokens + responder_tokens 137 print(f"Tokens for notification: {tokens}") 138 if len(tokens) > 0: 139 return send_fcm_to_users(tokens, title, body, data) 140 141def memo_tagged_notification(info, tagged_role_name, tagged_role_id, memoId): 142 """ 143 Send notification to responders when a memo is tagged to their role. 144 145 Args: 146 info (dict): Memo info containing block, ward, and role details. 147 tagged_role_name (str): Name of the tagged role. 148 tagged_role_id (int): ID of the tagged role. 149 memoId (str): Memo ID. 150 151 Returns: 152 dict: FCM send result. 153 """ 154 if not tagged_role_id or not tagged_role_name: 155 return 156 title = f"New Memo Tagged to your role: {tagged_role_name}" 157 body = f"Memo has been tagged to you at Block: {info['current_block_name']}, Floor: {info['current_floor']}, Ward: {info['current_ward_name']}" 158 data = { 159 "type": "memo_created", 160 "memo_id": memoId, 161 } 162 responder_tokens = list( 163 User.objects.filter( 164 is_logged_in=True, 165 role__id=tagged_role_id 166 ).exclude(Q(fcm_token__isnull=True) | Q(fcm_token='')) 167 .values_list('fcm_token', flat=True) 168 ) 169 print(f"Tokens for notification: {responder_tokens}") 170 if len(responder_tokens) > 0: 171 return send_fcm_to_users(responder_tokens, title, body, data)
31def send_fcm_to_user(token: str, title: str, body: str, data: dict = None): 32 """ 33 Send a notification to a single user via FCM token. 34 35 Args: 36 token (str): FCM token of the user. 37 title (str): Notification title. 38 body (str): Notification body. 39 data (dict): Additional data payload. 40 41 Returns: 42 dict: Success or error response. 43 """ 44 if not token: 45 return {"error": "Missing FCM token"} 46 47 message = messaging.Message( 48 notification=messaging.Notification(title=title, body=body), 49 token=token, 50 data=data or {} 51 ) 52 53 try: 54 response = messaging.send(message) 55 return {"success": True, "response": response} 56 except Exception as e: 57 return {"error": str(e)}
Send a notification to a single user via FCM token.
Args: token (str): FCM token of the user. title (str): Notification title. body (str): Notification body. data (dict): Additional data payload.
Returns: dict: Success or error response.
59def send_fcm_to_users(tokens: list[str], title: str, body: str, data: dict = None): 60 """ 61 Send a notification to multiple users via FCM tokens. 62 63 Args: 64 tokens (list[str]): List of FCM tokens. 65 title (str): Notification title. 66 body (str): Notification body. 67 data (dict): Additional data payload. 68 69 Returns: 70 dict: Success/failure counts and failed tokens. 71 """ 72 if not tokens: 73 return {"error": "No FCM tokens provided"} 74 75 message = messaging.MulticastMessage( 76 notification=messaging.Notification(title=title, body=body), 77 tokens=tokens, 78 data=data or {}, 79 ) 80 81 try: 82 response = messaging.send_each_for_multicast(message) 83 failed_tokens = [] 84 85 for idx, resp in enumerate(response.responses): 86 if not resp.success: 87 failed_tokens.append(tokens[idx]) 88 89 print({ 90 "success": response.success_count, 91 "failure": response.failure_count, 92 "failed_tokens": failed_tokens, 93 }) 94 return { 95 "success": response.success_count, 96 "failure": response.failure_count, 97 "failed_tokens": failed_tokens, 98 } 99 100 except Exception as e: 101 print(f"Error sending FCM messages: {str(e)}") 102 return {"error": str(e)}
Send a notification to multiple users via FCM tokens.
Args: tokens (list[str]): List of FCM tokens. title (str): Notification title. body (str): Notification body. data (dict): Additional data payload.
Returns: dict: Success/failure counts and failed tokens.
104def memo_created_notification(info, memoId): 105 """ 106 Send notification to approvers and responders when a memo is created. 107 108 Args: 109 info (dict): Memo info containing block, ward, and role details. 110 memoId (str): Memo ID. 111 112 Returns: 113 dict: FCM send result. 114 """ 115 title = "New Memo Created" 116 body = f"Memo has been created at Block:{info['current_block_name']},floor {info['current_floor']}, ward {info['current_ward_name']}" 117 data = { 118 "type": "memo_created", 119 "memo_id": memoId, 120 } 121 approver_tokens = list( 122 User.objects.filter( 123 is_logged_in=True, 124 current_block=info["current_block_id"], 125 role__is_approver=True 126 ).exclude(Q(fcm_token__isnull=True) | Q(fcm_token='')) 127 .values_list('fcm_token', flat=True) 128 ) 129 130 responder_tokens = list( 131 User.objects.filter( 132 is_logged_in=True, 133 role__id=info["tagged_role_id"] 134 ).exclude(Q(fcm_token__isnull=True) | Q(fcm_token='')) 135 .values_list('fcm_token', flat=True) 136 ) 137 tokens = approver_tokens + responder_tokens 138 print(f"Tokens for notification: {tokens}") 139 if len(tokens) > 0: 140 return send_fcm_to_users(tokens, title, body, data)
Send notification to approvers and responders when a memo is created.
Args: info (dict): Memo info containing block, ward, and role details. memoId (str): Memo ID.
Returns: dict: FCM send result.
142def memo_tagged_notification(info, tagged_role_name, tagged_role_id, memoId): 143 """ 144 Send notification to responders when a memo is tagged to their role. 145 146 Args: 147 info (dict): Memo info containing block, ward, and role details. 148 tagged_role_name (str): Name of the tagged role. 149 tagged_role_id (int): ID of the tagged role. 150 memoId (str): Memo ID. 151 152 Returns: 153 dict: FCM send result. 154 """ 155 if not tagged_role_id or not tagged_role_name: 156 return 157 title = f"New Memo Tagged to your role: {tagged_role_name}" 158 body = f"Memo has been tagged to you at Block: {info['current_block_name']}, Floor: {info['current_floor']}, Ward: {info['current_ward_name']}" 159 data = { 160 "type": "memo_created", 161 "memo_id": memoId, 162 } 163 responder_tokens = list( 164 User.objects.filter( 165 is_logged_in=True, 166 role__id=tagged_role_id 167 ).exclude(Q(fcm_token__isnull=True) | Q(fcm_token='')) 168 .values_list('fcm_token', flat=True) 169 ) 170 print(f"Tokens for notification: {responder_tokens}") 171 if len(responder_tokens) > 0: 172 return send_fcm_to_users(responder_tokens, title, body, data)
Send notification to responders when a memo is tagged to their role.
Args: info (dict): Memo info containing block, ward, and role details. tagged_role_name (str): Name of the tagged role. tagged_role_id (int): ID of the tagged role. memoId (str): Memo ID.
Returns: dict: FCM send result.