mirror of
https://github.com/HamzaSha1/zod-backend.git
synced 2025-07-15 10:05:21 +00:00
notification set up and celery configuration
This commit is contained in:
@ -16,3 +16,22 @@ services:
|
||||
command: bash -c "pip install -r requirements.txt && python manage.py collectstatic --noinput && python manage.py migrate && gunicorn zod_bank.wsgi -b 0.0.0.0:8000 -t 300 --log-level=info"
|
||||
volumes:
|
||||
- .:/usr/src/app
|
||||
|
||||
broker:
|
||||
image: rabbitmq:3.7
|
||||
container_name: rabbitmq
|
||||
volumes:
|
||||
- .:/usr/src/app
|
||||
ports:
|
||||
- 5673:5673
|
||||
|
||||
worker:
|
||||
build: .
|
||||
image: celery
|
||||
container_name: dev_celery
|
||||
restart: "always"
|
||||
command: bash -c " celery -A zod_bank.celery worker --concurrency=1 -B -l DEBUG -E"
|
||||
volumes:
|
||||
- .:/usr/src/app
|
||||
depends_on:
|
||||
- broker
|
||||
|
@ -1,11 +1,11 @@
|
||||
"""Views of Guardian"""
|
||||
"""Third party Django app"""
|
||||
|
||||
# django imports
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework import viewsets, status
|
||||
from rest_framework.pagination import PageNumberPagination
|
||||
from django.contrib.auth.models import User
|
||||
from django.utils import timezone
|
||||
"""Import Django app"""
|
||||
|
||||
# Import guardian's model,
|
||||
# Import junior's model,
|
||||
@ -19,7 +19,6 @@ from django.utils import timezone
|
||||
# Import account's serializer
|
||||
# Import account's task
|
||||
|
||||
|
||||
from .serializers import (UserSerializer, CreateGuardianSerializer, TaskSerializer, TaskDetailsSerializer,
|
||||
TopJuniorSerializer, ApproveJuniorSerializer, ApproveTaskSerializer)
|
||||
from .models import Guardian, JuniorTask
|
||||
@ -31,6 +30,8 @@ from account.utils import custom_response, custom_error_response
|
||||
from base.messages import ERROR_CODE, SUCCESS_CODE
|
||||
from base.constants import NUMBER
|
||||
from .utils import upload_image_to_alibaba
|
||||
from notifications.constants import REGISTRATION
|
||||
from notifications.utils import send_notification
|
||||
|
||||
""" Define APIs """
|
||||
# Define Signup API,
|
||||
@ -62,6 +63,7 @@ class SignupViewset(viewsets.ModelViewSet):
|
||||
user_type=str(request.data['user_type']), expired_at=expiry)
|
||||
"""Send email to the register user"""
|
||||
send_otp_email(request.data['email'], otp)
|
||||
send_notification(REGISTRATION, None, request.auth.payload['user_id'], {})
|
||||
return custom_response(SUCCESS_CODE['3001'],
|
||||
response_status=status.HTTP_200_OK)
|
||||
return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST)
|
||||
|
@ -3,4 +3,10 @@ notification admin file
|
||||
"""
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
from notifications.models import Notification
|
||||
|
||||
|
||||
@admin.register(Notification)
|
||||
class NotificationAdmin(admin.ModelAdmin):
|
||||
"""Notification Admin"""
|
||||
list_display = ['id', 'notification_type', 'notification_to', 'data', 'is_read']
|
||||
|
16
notifications/constants.py
Normal file
16
notifications/constants.py
Normal file
@ -0,0 +1,16 @@
|
||||
"""
|
||||
notification constants file
|
||||
"""
|
||||
REGISTRATION = 1
|
||||
TEST_NOTIFICATION = 99
|
||||
|
||||
NOTIFICATION_DICT = {
|
||||
REGISTRATION: {
|
||||
"title": "Successfully registered!",
|
||||
"body": "You have registered successfully. Now login and complete your profile."
|
||||
},
|
||||
TEST_NOTIFICATION: {
|
||||
"title": "Test Notification",
|
||||
"body": "This notification is for testing purpose"
|
||||
}
|
||||
}
|
30
notifications/migrations/0001_initial.py
Normal file
30
notifications/migrations/0001_initial.py
Normal file
@ -0,0 +1,30 @@
|
||||
# Generated by Django 4.2.2 on 2023-07-19 07:40
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Notification',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('notification_type', models.CharField(blank=True, max_length=50, null=True)),
|
||||
('data', models.JSONField(blank=True, default=dict, null=True)),
|
||||
('is_read', models.BooleanField(default=False)),
|
||||
('created_at', models.DateTimeField(default=django.utils.timezone.now)),
|
||||
('notification_from', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='from_notification', to=settings.AUTH_USER_MODEL)),
|
||||
('notification_to', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='to_notification', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
]
|
@ -1,6 +1,24 @@
|
||||
"""
|
||||
notification models file
|
||||
"""
|
||||
# django imports
|
||||
from django.db import models
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.utils import timezone
|
||||
|
||||
# Create your models here.
|
||||
USER = get_user_model()
|
||||
|
||||
|
||||
class Notification(models.Model):
|
||||
""" used to save the notifications """
|
||||
notification_type = models.CharField(max_length=50, blank=True, null=True)
|
||||
notification_to = models.ForeignKey(USER, related_name='to_notification', on_delete=models.CASCADE)
|
||||
notification_from = models.ForeignKey(USER, related_name='from_notification', on_delete=models.SET_NULL,
|
||||
blank=True, null=True)
|
||||
data = models.JSONField(default=dict, blank=True, null=True)
|
||||
is_read = models.BooleanField(default=False)
|
||||
created_at = models.DateTimeField(default=timezone.now)
|
||||
|
||||
def __str__(self):
|
||||
""" string representation """
|
||||
return f"{self.notification_to.id} | {self.notification_to.email}"
|
||||
|
@ -1,12 +1,25 @@
|
||||
"""
|
||||
notifications utils file
|
||||
"""
|
||||
import constant as constant
|
||||
# third party imports
|
||||
from fcm_django.models import FCMDevice
|
||||
from celery import shared_task
|
||||
from firebase_admin.messaging import Message, Notification as FirebaseNotification
|
||||
|
||||
# django imports
|
||||
from django.contrib.auth import get_user_model
|
||||
|
||||
from account.models import UserNotification
|
||||
from notifications.constants import NOTIFICATION_DICT
|
||||
from notifications.models import Notification
|
||||
|
||||
# local imports
|
||||
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
def register_fcm_token(user_id, registration_id, device_id, device_type):
|
||||
""" used to register the fcm device token"""
|
||||
device, _ = FCMDevice.objects.update_or_create(device_id=device_id,
|
||||
@ -25,3 +38,35 @@ def remove_fcm_token(user_id: int, access_token: str, registration_id) -> None:
|
||||
FCMDevice.objects.filter(user_id=user_id).delete()
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
|
||||
def get_basic_detail(notification_type, from_user_id, to_user_id):
|
||||
""" used to get the basic details """
|
||||
notification_data = NOTIFICATION_DICT[notification_type]
|
||||
from_user = User.objects.get(id=from_user_id) if from_user_id else None
|
||||
to_user = User.objects.get(id=to_user_id)
|
||||
return notification_data, from_user, to_user
|
||||
|
||||
|
||||
@shared_task()
|
||||
def send_notification(notification_type, from_user_id, to_user_id, extra_data):
|
||||
""" used to send the push for the given notification type """
|
||||
(notification_data, from_user, to_user) = get_basic_detail(notification_type, from_user_id, to_user_id)
|
||||
print(notification_data, to_user)
|
||||
user_notification_type = UserNotification.objects.filter(user=to_user).first()
|
||||
# data = notification_data.data
|
||||
data = notification_data
|
||||
Notification.objects.create(notification_type=notification_type, notification_from=from_user,
|
||||
notification_to=to_user, data=data)
|
||||
if user_notification_type.push_notification:
|
||||
data.update({'badge': Notification.objects.filter(notification_to=to_user, is_read=False).count()})
|
||||
send_push(to_user, data)
|
||||
|
||||
|
||||
def send_push(user, data):
|
||||
""" used to send push notification to specific user """
|
||||
# if user.push_notification:
|
||||
notification_data = data.pop('data', None)
|
||||
user.fcmdevice_set.filter(active=True).send_message(
|
||||
Message(notification=FirebaseNotification(data['title'], data['body']), data=notification_data)
|
||||
)
|
||||
|
@ -8,9 +8,12 @@ from rest_framework.decorators import action
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
|
||||
# local imports
|
||||
from account.utils import custom_response
|
||||
from base.messages import SUCCESS_CODE
|
||||
from notifications.constants import TEST_NOTIFICATION
|
||||
from notifications.serializers import RegisterDevice
|
||||
from notifications.utils import send_notification
|
||||
|
||||
|
||||
class NotificationViewSet(viewsets.GenericViewSet):
|
||||
@ -28,3 +31,12 @@ class NotificationViewSet(viewsets.GenericViewSet):
|
||||
serializer.is_valid(raise_exception=True)
|
||||
serializer.save()
|
||||
return custom_response(SUCCESS_CODE["3000"])
|
||||
|
||||
@action(methods=['get'], detail=False, url_path='test', url_name='test', serializer_class=None)
|
||||
def send_test_notification(self, request):
|
||||
"""
|
||||
to send test notification
|
||||
:return:
|
||||
"""
|
||||
send_notification.delay(TEST_NOTIFICATION, None, request.auth.payload['user_id'], {})
|
||||
return custom_response(SUCCESS_CODE["3000"])
|
||||
|
13
zod-bank-fcm-credentials.json
Normal file
13
zod-bank-fcm-credentials.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"type": "service_account",
|
||||
"project_id": "zod-bank-ebb2a",
|
||||
"private_key_id": "f1115f1b1fece77ba7a119b70e2502ce0777a7d4",
|
||||
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCvLWEobyVN7D4+\nSZ4NwcugwuVk9MV7CjhQGB8lqzf/1Z0plBytjpjM75+orFk5n2tnOgTxsWCqR1R7\nLry4x2QH3HgJebd/TZTIyfepcAeuzUVhq9prgWVRsvxjpihMPZufA/Q1GEX5TBwX\nEasBW91Qwas2NBhUrzotnUBxOshVB4zCo3Ls9dbAN9O2O6paUMvcofSsRZ9XkB6P\nFFKy6nbQ3Bo+Lw3ntUfG1JQgkkxto2Vudiiq6J2dE6Eih2acEhEezQoJVpkMK+si\nlGp88T3j8nTx3o6ol99ke+3ZejPVE5sUbuhokSV/tS1Goy3whP+ys9lQtIyt3/mJ\nlmkoB9ShAgMBAAECggEAAk3H0GFF08C3EBWyDqH5dbLXbtH92e/UeNAMNcV4mGbY\n5GKGFywmEVmg2N22EPqa/s+Y6QxxrD9u9G1+EhbnIIx7olOBkScJ9C0c9CWztCon\ntPaofd1E1cI7I7UfVTg2ZLAHrBN4H70eadYc4va8bBtHj0EHYONz7S8sEBQ1Qna2\nIQuCEWY6MzhwCNEFIJd8ikd0GnkAJCuInK3F+2c37kugdgjRKxkTIfWmhNIfyWn3\ngoui5wltuuDKETVj9VUMyN6P7kffIJzS4mMRm/9F92scpPRbK+X1TrHpFsO826oP\nUuSBi5oOZYNyAvMBXGdnemoUNtAE+xg4kqwYJu5T0QKBgQDlbO08yH5MSLUxXZfL\nkCYg1mCUC4ySpL/qVFNuyvY+ex9gIg6gj4vEpK8s1lt0yvxrTng/MXxMMg7o9dO8\nmSlv/665twk/7NfkexJPWs1ph+54tud3Sa0TiVw6U5ObPMr1EYc7RnoELDR9Exc1\nUDJB+T3f3SGJicZn4pALyx132wKBgQDDd9lhqWLXJeG7JkInhLywuSVmnk077hY8\nxAfHqlO+/EEkM/YBtUvtC4KNiSkVftQwSM80NRiHlPvlWZ0G8l9RAfM/xxL/XUq6\nOu1fW1uJuukJgXFePV9SQLzfgd1fk1f/dKuiPSNhCzgTD7dFks0Ip6FD6/PCdN7x\neqRUqDccMwKBgQCTk1mW+7CiCTLkKjv2KScdgEhncnZd7bO1W8C/R7bVwgUQpVeb\nWDqjpvs3cDssCVYNAFDA9Wfq61hD6bzlV/AbpvARbfd5MzQ8OB4zBUmUVGfFJoIF\nbVLzeivlKNWNybETqs6+Bjt+a6Dnw1vuY0OwxE5Urb1g50rEkCvwKhsueQKBgQDB\nUt3rG46oX80cPkCbuUquNs/o6JRWu6m+u9s9/RYLBI6g8ctT8S2A6ytaNNgvbFsM\nzlYwunriTdW9Bp6p6jmfcyBUad4+NtTbz8BJ2Z91Xylwv1eS73xBa8nh/R0nlCEq\nhQfj1DgTmPcC0z5eT0z+TFzRQqK6JsEBcFzrZdvrxQKBgQDGEtWElG5XoDwnwO5e\nmfFLRKHfG+Xa6FChl2eeDIGOxv/Y6SMwT68t0gtnDFQGtcIMvC+kC/1Rv1v8yrOD\nCzEToh91Fw1c1eayNnsLq07qYnVWoMa7xFFSDhtBAnepqlU+81qaDvp+yILTIYSP\nwUuk3NpdJs2LkMetm5zJC9PJ2w==\n-----END PRIVATE KEY-----\n",
|
||||
"client_email": "firebase-adminsdk-umcph@zod-bank-ebb2a.iam.gserviceaccount.com",
|
||||
"client_id": "102629742363778142120",
|
||||
"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-umcph%40zod-bank-ebb2a.iam.gserviceaccount.com",
|
||||
"universe_domain": "googleapis.com"
|
||||
}
|
34
zod_bank/celery.py
Normal file
34
zod_bank/celery.py
Normal file
@ -0,0 +1,34 @@
|
||||
"""
|
||||
Celery Basic configuration
|
||||
"""
|
||||
|
||||
# python imports
|
||||
import os
|
||||
|
||||
# third party imports
|
||||
from celery import Celery
|
||||
from dotenv import load_dotenv
|
||||
from celery.schedules import crontab
|
||||
|
||||
# OR, the same with increased verbosity:
|
||||
load_dotenv(verbose=True)
|
||||
|
||||
env_path = os.path.join(os.path.abspath(os.path.join('.env', os.pardir)), '.env')
|
||||
|
||||
load_dotenv(dotenv_path=env_path)
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', os.getenv('SETTINGS'))
|
||||
|
||||
# celery app
|
||||
app = Celery()
|
||||
|
||||
app.config_from_object('django.conf:settings')
|
||||
|
||||
# Load task modules from all registered Django apps.
|
||||
app.autodiscover_tasks()
|
||||
|
||||
|
||||
@app.task(bind=True)
|
||||
def debug_task(self):
|
||||
""" celery debug task """
|
||||
print(f'Request: {self.request!r}')
|
Reference in New Issue
Block a user