notification set up and celery configuration

This commit is contained in:
abutalib-kiwi
2023-07-19 16:24:53 +05:30
parent 2e7d36485c
commit 3223a2b050
10 changed files with 200 additions and 5 deletions

View File

@ -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

View File

@ -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)

View File

@ -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']

View 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"
}
}

View 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)),
],
),
]

View File

@ -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}"

View File

@ -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)
)

View File

@ -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"])

View 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
View 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}')