Browse Source

fix: notif

master
mortezaei 1 year ago
parent
commit
fc91e716ed
  1. 5
      apps/account/serializers/user.py
  2. 101
      apps/account/tasks.py
  3. 4
      apps/account/urls.py
  4. 56
      apps/account/views/notification.py
  5. 19
      apps/account/views/user.py
  6. 2
      requirements.txt

5
apps/account/serializers/user.py

@ -141,3 +141,8 @@ class UserGuestSerializer(serializers.ModelSerializer):
return data
class UserFCMSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['fcm']

101
apps/account/tasks.py

@ -1,9 +1,108 @@
import time
from config.settings import base as settings
from celery import shared_task
import requests
import json
import logging
import firebase_admin
from firebase_admin import credentials, messaging
import firebase_admin
from firebase_admin import credentials, messaging
from google.oauth2 import service_account
import google.auth.transport.requests
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
# تنظیمات Firebase
data = {
"type": "service_account",
"project_id": "imamjavad-25c31",
"private_key_id": "1edc90fb80a335809c4b04a713403355ff4e8bd0",
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEugIBADANBgkqhkiG9w0BAQEFAASCBKQwggSgAgEAAoIBAQCM57lia6vNNzJL\nYBwFcx49sFPXtrYKkrRhtDN13EOnF2j+y8vlwtqYR6P7HB1l10GyHx3mlN8XpYXN\n24yrTsK6WugqPdWGl/z/BgqHximH+v4NCPQTBr3lemHbTXlEkhNtmaf9zM8IzsXP\nEzD4z5u9hy3AgfZdHKO0isTvxRTuTlpTKU3PQDwiIjfb6Bk8IjfjrDQqWbHLC4am\nidwM5F+L8ecAyhVe/G7IXAflqyi4zVM/hM5FiAknA5FmyfGd9HCxaLkw3Dqtnof8\nqflJmZp0vptT3Lte7ObeUEMoRoT0bZt6DbMBI+w19OIBu0ne0OjLu/1z4CFYoR+r\nAeWGvWCHAgMBAAECgf9HnQx/FY90oO5gtiLdE/pnJxqSMtjEhufRazaDd4vOYKXD\nhLQ5EkFcsij66PnPHiZiC+BfbUpnSIAqrmsliXBSYv4OCELTJU/FovcMfHG7qtU7\nIBjsrw64ISXT+ow1+EEEAWm1eA0WwjmOBTL7CTPJA3l2QXrYu5ki8IDuP1i5UwKu\nSR3kW0+BfsQG0z2q00AjqGnFV9IuDDjcAvu2ojwanM/H+eGB+I/dtpqe87KhbBZ9\nFuKCdYNgRa3Z76mU/2jSyGQ9eyXCX0x0vKpPavkbfir7mJcvCrp+3z0h8ot0u1Mi\nj7IJd9Ot37qUj09obXyInYk8Vnj46lj8+QjdgAECgYEAxj9Fmu9oSgLBLsuYU0kU\nmUcl0HOv3UllKAYX+8Z6L/dR1KKsfSoRWQoyGE1TxXsR/uJ4uQJJZLlHMVSw3mz3\nmOHep3F5TNSM6cfJnh5/NSMoAklOzRZxW/UELcu9vaR+e1QSgBMaNmc3b483pbfs\neVD3CPPWFt2A4lI3Y77jQAECgYEAtfQLcrBYv+SEIrVML6pXrHRC19RwCzmLyC69\n07LyRG2THu26IhOK+aSzLT5FRXTOP1VD+FHfD+AOr2d1oc2HrmgxU0mVio93KSW4\nxDrmBrej1DmVjB7LSqxu7chiD/lBUdFh2Fam8dsiTQtqR02qfcQGLynvEb2yTUbj\n0lTmoIcCgYBWZ7VatgXqXBD+6FXX1v5XYB8nH4UDGb4xF5bUcclHpq/P0acEVpWB\nDWSQGwPsCpvpT6P2XvzGHcrdwV/lUfEIfUmiCV8pEWrpad6CQCCJdG03sePal3GI\n9t1/aFGmmk9WSWpWz/yYwZvzz6QdYnB638ML79rb1GccPWFO5CAAAQKBgA4+Hi9K\nEohi0N0Op/oLMXW0XA8c9/BI/uIalo1dso0crql7HljQgs5r0AK4nx+CtypJ+FoV\nvoo1lbCxPon91qMWUNYeKnCALmmwJDhoC912voI8R7KCLpOXz88ZImPxtOU8qJYQ\nolzINHUncZhHQhM6JunGNIqE+NIHvImYT709AoGALJGUb9jAg/QpSoFKlbp4xrEA\n3G/caXeB+lE19KGZxgADBbWsUsfMI7CxnROZFobCzTdhIE6N+LaAFX/6rn0P6Nf9\nN6w8//442RjkWxtmDgw7lCykXwyLSfrP3Dbzd78gGIBqngPTej9JCc7WJYnnN75M\n5TGjxvmxYqR231/L/p0=\n-----END PRIVATE KEY-----\n",
"client_email": "firebase-adminsdk-fbsvc@imamjavad-25c31.iam.gserviceaccount.com",
"client_id": "103207313184637638669",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-fbsvc%40imamjavad-25c31.iam.gserviceaccount.com",
"universe_domain": "googleapis.com"
}
PROJECT_ID = 'imamjavad-25c31'
BASE_URL = 'https://fcm.googleapis.com'
SCOPES = ['https://www.googleapis.com/auth/firebase.messaging']
FCM_ENDPOINT = f'v1/projects/{PROJECT_ID}/messages:send'
FCM_URL = f'{BASE_URL}/{FCM_ENDPOINT}'
def _get_access_token():
"""Retrieve a valid access token that can be used to authorize requests.
:return: Access token.
"""
credentials = service_account.Credentials.from_service_account_info(
data, scopes=SCOPES)
request = google.auth.transport.requests.Request()
credentials.refresh(request)
return credentials.token
# @shared_task
async def send_notification(ids: list, title: str = None, body: str = None, data=None,
extra_notification_kwargs: dict = None) -> list:
if not ids:
return []
chunked_ids = [ids[i:i + 500] for i in range(0, len(ids), 500)]
responses = []
for chunk in chunked_ids:
access_token = _get_access_token()
headers = {
'Authorization': f'Bearer {access_token}',
'Content-Type': 'application/json',
}
payload = {
'message': {
'token': chunk[0],
'notification': {
'title': title,
'body': body,
},
'data': {k: str(v) for k, v in (data or {}).items()},
'android': {
'priority': 'high',
'notification': {
'title': title,
'body': body,
# 'sound': 'incoming_call_sound',
'color': '#06EEBD',
# 'channel_id': 'incoming_call_channel',
'visibility': 'public',
},
},
}
}
# Send the POST request to FCM API
print(f'=========(send-notif)===******')
response = requests.post(FCM_URL, headers=headers, json=payload)
if response.status_code == 200:
logger.warning('Successfully sent message:', response.json())
responses.append(response.json())
else:
responses.append({'status': 'error', 'message': ""})
logger.error(f'Failed to send message notif')
return responses
@shared_task
def send_otp_code(phone_number, code):

4
apps/account/urls.py

@ -17,8 +17,6 @@ urlpatterns = [
path('location-update/', views.LocationHistoryView.as_view(), name='user-location-history'),
# path('notif/', views.NotificationListView.as_view(), name='user-notif'),
# path('notif/read', views.NotificationReadAllView.as_view(), name='user-notif-read-all'),
# # URL to get user details, supports GET for fetching user profile based on the provided token.
@ -29,11 +27,13 @@ urlpatterns = [
path('notif/', views.NotificationListView.as_view(), name='user-notif'),
path('notif/read', views.NotificationReadAllView.as_view(), name='user-notif-read-all'),
path('notif/send/', views.SendNotificationView.as_view(), name='user-send-notif'),
# # URL to update user details, supports PUT to update user fields like phone or email given a token.
path('profile/update/', views.UserUpdateView.as_view(), name='user-update'),
# # delete user account
path('profile/delete/', views.UserDeleteView.as_view(), name='user-delete'),
path('update-fcm/', views.UpdateFCMView.as_view(), name='update-fcm'),
]

56
apps/account/views/notification.py

@ -5,8 +5,8 @@ from drf_yasg.utils import swagger_auto_schema
from drf_yasg import openapi
from rest_framework.permissions import IsAuthenticated
from apps.account.serializers import NotificationSerializer, NotificationSendSerializer
from apps.account.models import Notification
# from apps.account.fcm_notification import send_notification
from apps.account.models import Notification, User
from apps.account.tasks import send_notification
@ -103,3 +103,55 @@ class NotificationReadAllView(generics.GenericAPIView):
class SendNotificationView(generics.GenericAPIView):
@swagger_auto_schema(
operation_description="Send a notification to a user by user_id.",
tags=['Notifications'],
request_body=openapi.Schema(
type=openapi.TYPE_OBJECT,
required=['user_id', 'title', 'body'],
properties={
'user_id': openapi.Schema(type=openapi.TYPE_INTEGER, description='ID of the user to send notification to'),
'title': openapi.Schema(type=openapi.TYPE_STRING, description='Notification title'),
'body': openapi.Schema(type=openapi.TYPE_STRING, description='Notification body'),
'data': openapi.Schema(type=openapi.TYPE_OBJECT, description='Additional data payload', default={'slam': 'qatreh'}),
},
),
responses={
200: openapi.Response('Notification sent successfully.'),
400: openapi.Response('FCM token not available for this user.'),
404: openapi.Response('User not found.'),
500: openapi.Response('Internal server error.'),
}
)
def post(self, request, *args, **kwargs):
user_id = request.data.get('user_id', 1)
try:
user = User.objects.get(id=user_id)
except User.DoesNotExist:
return Response({'error': 'User not found.'}, status=status.HTTP_404_NOT_FOUND)
notification_title = request.data.get('title', 'test qatreh')
notification_body = request.data.get('body', 'test qatreh body')
data_payload = request.data.get('data', {'slam':'qatreh'})
fcm_token = user.fcm # Ensure that 'fcm' is a field in your User model
if not fcm_token:
return Response({
'error': 'FCM token not available for this user.'
}, status=status.HTTP_400_BAD_REQUEST)
try:
send_notification([fcm_token], notification_title, notification_body, data_payload)
return Response({
'message': 'Notification sent successfully.'
}, status=status.HTTP_200_OK)
except Exception as e:
return Response({
'error': str(e)
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

19
apps/account/views/user.py

@ -23,7 +23,7 @@ from rest_framework.exceptions import ValidationError
from utils.exceptions import InvaliedCodeVrify, ExpiredCodeException, ServiceUnavailableException
from apps.account.models import User
from apps.account.serializers import UserRegisterSerializer, UserProfileSerializer, UserVerifySerializer, UserLoginSerializer, UserRecoverPasswordSerializer, UserResetPasswordSerializer, UserGuestSerializer
from apps.account.serializers import UserRegisterSerializer, UserProfileSerializer, UserVerifySerializer, UserLoginSerializer, UserRecoverPasswordSerializer, UserResetPasswordSerializer, UserGuestSerializer,UserFCMSerializer
from utils.redis import RedisManager
from utils.exceptions import AppAPIException
from utils import send_email, is_valid_email
@ -370,3 +370,20 @@ class UserDeleteView(APIView):
return Response({"detail": "User does not exist."}, status=status.HTTP_404_NOT_FOUND)
class UpdateFCMView(GenericAPIView):
permission_classes = [IsAuthenticated]
serializer_class = UserFCMSerializer
def post(self, request, *args, **kwargs):
user = request.user
fcm_token = request.data.get('fcm')
if not fcm_token:
return Response({"detail": "FCM token is required."}, status=status.HTTP_200_OK)
user.fcm = fcm_token
user.save()
return Response({"detail": "FCM token updated successfully."}, status=status.HTTP_200_OK)

2
requirements.txt

@ -117,6 +117,8 @@ webencodings==0.5.1
whitenoise==6.9.0
wrapt==1.16.0
wsproto==1.2.0
firebase-admin==6.2.0
google-auth==2.6.0
https://yaghoubi:e07059e0ac6be3b0032ded5f65f03363fbd3811f@git.habibapp.com/NewHorizon/django-limitless-dashboard.git/archive/master.zip
https://yaghoubi:e07059e0ac6be3b0032ded5f65f03363fbd3811f@git.habibapp.com/NewHorizon/ajax-datatable.git/archive/master.zip

Loading…
Cancel
Save