Merge pull request #343 from KiwiTechLLC/dev

Dev into qa
This commit is contained in:
Abu Talib
2023-09-29 18:27:22 +05:30
committed by GitHub
9 changed files with 81 additions and 10 deletions

View File

@ -90,6 +90,11 @@ class GoogleLoginMixin(object):
ERROR_CODE["2071"], ERROR_CODE["2071"],
response_status=status.HTTP_400_BAD_REQUEST response_status=status.HTTP_400_BAD_REQUEST
) )
if not junior_query.is_active:
return custom_error_response(
ERROR_CODE["2075"],
response_status=status.HTTP_404_NOT_FOUND
)
serializer = JuniorSerializer(junior_query) serializer = JuniorSerializer(junior_query)
elif str(user_type) == '2': elif str(user_type) == '2':
guardian_query = Guardian.objects.filter(user=user_data.last()).last() guardian_query = Guardian.objects.filter(user=user_data.last()).last()
@ -98,6 +103,11 @@ class GoogleLoginMixin(object):
ERROR_CODE["2070"], ERROR_CODE["2070"],
response_status=status.HTTP_400_BAD_REQUEST response_status=status.HTTP_400_BAD_REQUEST
) )
if not guardian_query.is_active:
return custom_error_response(
ERROR_CODE["2075"],
response_status=status.HTTP_404_NOT_FOUND
)
serializer = GuardianSerializer(guardian_query) serializer = GuardianSerializer(guardian_query)
else: else:
return custom_error_response( return custom_error_response(

View File

@ -13,7 +13,7 @@ from django.db.models import F, Window
from django.db.models.functions.window import Rank from django.db.models.functions.window import Rank
# local imports # local imports
from base.constants import PENDING, IN_PROGRESS, JUNIOR from base.constants import PENDING, IN_PROGRESS, JUNIOR, GUARDIAN
from guardian.models import JuniorTask from guardian.models import JuniorTask
from junior.models import JuniorPoints from junior.models import JuniorPoints
from notifications.constants import PENDING_TASK_EXPIRING, IN_PROGRESS_TASK_EXPIRING, NOTIFICATION_DICT, TOP_JUNIOR from notifications.constants import PENDING_TASK_EXPIRING, IN_PROGRESS_TASK_EXPIRING, NOTIFICATION_DICT, TOP_JUNIOR
@ -53,7 +53,7 @@ def notify_task_expiry():
(datetime.datetime.now().date() + datetime.timedelta(days=1))]) (datetime.datetime.now().date() + datetime.timedelta(days=1))])
if pending_tasks := all_pending_tasks.filter(task_status=PENDING): if pending_tasks := all_pending_tasks.filter(task_status=PENDING):
for task in pending_tasks: for task in pending_tasks:
send_notification(PENDING_TASK_EXPIRING, None, None, task.junior.auth_id, send_notification(PENDING_TASK_EXPIRING, task.guardian.user_id, GUARDIAN, task.junior.auth_id,
{'task_id': task.id}) {'task_id': task.id})
if in_progress_tasks := all_pending_tasks.filter(task_status=IN_PROGRESS): if in_progress_tasks := all_pending_tasks.filter(task_status=IN_PROGRESS):
for task in in_progress_tasks: for task in in_progress_tasks:

View File

@ -11,3 +11,4 @@ class NotificationAdmin(admin.ModelAdmin):
"""Notification Admin""" """Notification Admin"""
list_display = ['id', 'notification_type', 'notification_to', 'data', 'is_read'] list_display = ['id', 'notification_type', 'notification_to', 'data', 'is_read']
list_filter = ['notification_type'] list_filter = ['notification_type']
search_fields = ['notification_to']

View File

@ -22,79 +22,93 @@ ARTICLE_REWARD_POINTS = 17
REMOVE_JUNIOR = 18 REMOVE_JUNIOR = 18
TEST_NOTIFICATION = 99 TEST_NOTIFICATION = 99
# notification dictionary # notification dictionary
NOTIFICATION_DICT = { NOTIFICATION_DICT = {
REGISTRATION: { REGISTRATION: {
"notification_type": REGISTRATION,
"title": "Successfully registered!", "title": "Successfully registered!",
"body": "You have registered successfully. Now login and complete your profile." "body": "You have registered successfully. Now login and complete your profile."
}, },
# user will receive notification as soon junior # user will receive notification as soon junior
# sign up application using their guardian code for association # sign up application using their guardian code for association
ASSOCIATE_REQUEST: { ASSOCIATE_REQUEST: {
"notification_type": ASSOCIATE_REQUEST,
"title": "Associate request!", "title": "Associate request!",
"body": "You have request from {from_user} to associate with you." "body": "You have request from {from_user} to associate with you."
}, },
# Juniors will receive notification when # Juniors will receive notification when
# custodians reject their request for associate # custodians reject their request for associate
ASSOCIATE_REJECTED: { ASSOCIATE_REJECTED: {
"notification_type": ASSOCIATE_REJECTED,
"title": "Associate request rejected!", "title": "Associate request rejected!",
"body": "Your request to associate has been rejected by {from_user}." "body": "Your request to associate has been rejected by {from_user}."
}, },
# Juniors will receive notification when # Juniors will receive notification when
# custodians approve their request for associate # custodians approve their request for associate
ASSOCIATE_APPROVED: { ASSOCIATE_APPROVED: {
"notification_type": ASSOCIATE_APPROVED,
"title": "Associate request approved!", "title": "Associate request approved!",
"body": "Your request to associate has been approved by {from_user}." "body": "Your request to associate has been approved by {from_user}."
}, },
# Juniors will receive Notifications # Juniors will receive Notifications
# for every Points earned by referrals # for every Points earned by referrals
REFERRAL_POINTS: { REFERRAL_POINTS: {
"notification_type": REFERRAL_POINTS,
"title": "Earn Referral points!", "title": "Earn Referral points!",
"body": "You earn 5 points for referral." "body": "You earn 5 points for referral."
}, },
# Juniors will receive notification # Juniors will receive notification
# once any custodians add them in their account # once any custodians add them in their account
ASSOCIATE_JUNIOR: { ASSOCIATE_JUNIOR: {
"notification_type": ASSOCIATE_JUNIOR,
"title": "Profile already setup!", "title": "Profile already setup!",
"body": "Your guardian has already setup your profile." "body": "Your guardian has already setup your profile."
}, },
ASSOCIATE_EXISTING_JUNIOR: { ASSOCIATE_EXISTING_JUNIOR: {
"notification_type": ASSOCIATE_EXISTING_JUNIOR,
"title": "Associated to guardian", "title": "Associated to guardian",
"body": "Your are associated to your guardian {from_user}." "body": "Your are associated to your guardian {from_user}."
}, },
# Juniors will receive Notification # Juniors will receive Notification
# for every Task Assign by Custodians # for every Task Assign by Custodians
TASK_ASSIGNED: { TASK_ASSIGNED: {
"notification_type": TASK_ASSIGNED,
"title": "New task assigned!", "title": "New task assigned!",
"body": "{from_user} has assigned you a new task." "body": "{from_user} has assigned you a new task."
}, },
# Guardian will receive notification as soon # Guardian will receive notification as soon
# as junior send task for approval # as junior send task for approval
TASK_ACTION: { TASK_ACTION: {
"notification_type": TASK_ACTION,
"title": "Task completion approval!", "title": "Task completion approval!",
"body": "{from_user} completed their task {task_name}." "body": "{from_user} completed their task {task_name}."
}, },
# Juniors will receive notification as soon # Juniors will receive notification as soon
# as their task is rejected by custodians # as their task is rejected by custodians
TASK_REJECTED: { TASK_REJECTED: {
"notification_type": TASK_REJECTED,
"title": "Task completion rejected!", "title": "Task completion rejected!",
"body": "Your task completion request has been rejected by {from_user}." "body": "Your task completion request has been rejected by {from_user}."
}, },
# Juniors will receive notification as soon as their task is approved by custodians # Juniors will receive notification as soon as their task is approved by custodians
# and for every Points earned by Task completion # and for every Points earned by Task completion
TASK_APPROVED: { TASK_APPROVED: {
"notification_type": TASK_APPROVED,
"title": "Task completion approved!", "title": "Task completion approved!",
"body": "Your task completion request has been approved by {from_user}. " "body": "Your task completion request has been approved by {from_user}. "
"Also you earned 5 points for successful completion." "Also you earned 5 points for successful completion."
}, },
# Juniors will receive notification when their task end date about to end # Juniors will receive notification when their task end date about to end
PENDING_TASK_EXPIRING: { PENDING_TASK_EXPIRING: {
"notification_type": PENDING_TASK_EXPIRING,
"title": "Task expiring soon!", "title": "Task expiring soon!",
"body": "Your task {task_name} is expiring soon. Please complete it." "body": "Your task {task_name} is expiring soon. Please complete it."
}, },
# User will receive notification when their assigned task is about to end # User will receive notification when their assigned task is about to end
# and juniors have not performed any action # and juniors have not performed any action
IN_PROGRESS_TASK_EXPIRING: { IN_PROGRESS_TASK_EXPIRING: {
"notification_type": IN_PROGRESS_TASK_EXPIRING,
"title": "Task expiring soon!", "title": "Task expiring soon!",
"body": "{from_user} didn't take any action on assigned task {task_name} and it's expiring soon. " "body": "{from_user} didn't take any action on assigned task {task_name} and it's expiring soon. "
"Please assist to complete it." "Please assist to complete it."
@ -102,27 +116,32 @@ NOTIFICATION_DICT = {
# Juniors will receive Notification # Juniors will receive Notification
# related to Leaderboard progress # related to Leaderboard progress
TOP_JUNIOR: { TOP_JUNIOR: {
"notification_type": TOP_JUNIOR,
"title": "Leaderboard topper!", "title": "Leaderboard topper!",
"body": "{from_user} is on top in leaderboard with {points} points." "body": "{from_user} is on top in leaderboard with {points} points."
}, },
# Juniors will receive notification # Juniors will receive notification
# when admin add any new financial learnings # when admin add any new financial learnings
NEW_ARTICLE_PUBLISHED: { NEW_ARTICLE_PUBLISHED: {
"notification_type": NEW_ARTICLE_PUBLISHED,
"title": "Time to read!", "title": "Time to read!",
"body": "A new article has been published." "body": "A new article has been published."
}, },
# Juniors will receive notification when they earn points by reading financial Learning # Juniors will receive notification when they earn points by reading financial Learning
ARTICLE_REWARD_POINTS: { ARTICLE_REWARD_POINTS: {
"notification_type": ARTICLE_REWARD_POINTS,
"title": "Article reward points!", "title": "Article reward points!",
"body": "You are rewarded with {points} points for reading article and answering questions. " "body": "You are rewarded with {points} points for reading article and answering questions. "
}, },
# Juniors will receive notification as soon as their custodians remove them from account # Juniors will receive notification as soon as their custodians remove them from account
REMOVE_JUNIOR: { REMOVE_JUNIOR: {
"notification_type": REMOVE_JUNIOR,
"title": "Disassociate by guardian!", "title": "Disassociate by guardian!",
"body": "Your guardian has disassociated you." "body": "Your guardian has disassociated you."
}, },
# Test notification # Test notification
TEST_NOTIFICATION: { TEST_NOTIFICATION: {
"notification_type": TEST_NOTIFICATION,
"title": "Test Notification", "title": "Test Notification",
"body": "This notification is for testing purpose from {from_user}." "body": "This notification is for testing purpose from {from_user}."
} }

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2.2 on 2023-09-29 07:00
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('notifications', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='notification',
name='updated_at',
field=models.DateTimeField(auto_now=True),
),
]

View File

@ -18,6 +18,7 @@ class Notification(models.Model):
data = models.JSONField(default=dict, blank=True, null=True) data = models.JSONField(default=dict, blank=True, null=True)
is_read = models.BooleanField(default=False) is_read = models.BooleanField(default=False)
created_at = models.DateTimeField(default=timezone.now) created_at = models.DateTimeField(default=timezone.now)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self): def __str__(self):
""" string representation """ """ string representation """

View File

@ -36,7 +36,7 @@ class NotificationListSerializer(serializers.ModelSerializer):
class Meta(object): class Meta(object):
"""meta info""" """meta info"""
model = Notification model = Notification
fields = ['id', 'data', 'badge', 'is_read', 'created_at'] fields = ['id', 'notification_type', 'data', 'badge', 'is_read', 'updated_at']
@staticmethod @staticmethod
def get_badge(obj): def get_badge(obj):

View File

@ -88,6 +88,7 @@ def get_notification_data(notification_type, from_user_id, from_user_type, to_us
push_data['body'] = push_data['body'].format(from_user=from_user_name, task_name=task_name, points=points) push_data['body'] = push_data['body'].format(from_user=from_user_name, task_name=task_name, points=points)
notification_data['body'] = notification_data['body'].format(from_user=from_user_name, notification_data['body'] = notification_data['body'].format(from_user=from_user_name,
task_name=task_name, points=points) task_name=task_name, points=points)
notification_data['from_user'] = from_user_name notification_data['from_user'] = from_user_name
notification_data['from_user_image'] = from_user_image notification_data['from_user_image'] = from_user_image
@ -104,14 +105,25 @@ def send_notification(notification_type, from_user_id, from_user_type, to_user_i
notification_data, push_data, from_user, to_user = get_notification_data(notification_type, from_user_id, notification_data, push_data, from_user, to_user = get_notification_data(notification_type, from_user_id,
from_user_type, to_user_id, extra_data) from_user_type, to_user_id, extra_data)
user_notification_type = UserNotification.objects.filter(user=to_user).first() user_notification_type = UserNotification.objects.filter(user=to_user).first()
Notification.objects.create(notification_type=notification_type, notification_from=from_user,
notification_to=to_user, data=notification_data) # notification create method changed on 28sep as per changes required
task_id = extra_data['task_id'] if 'task_id' in extra_data else None
Notification.objects.update_or_create(data__has_key='task_id', data__task_id=task_id,
notification_from=from_user, notification_to=to_user,
defaults={
'notification_type': notification_type,
'notification_from': from_user,
'notification_to': to_user,
'data': notification_data
})
if user_notification_type and user_notification_type.push_notification: if user_notification_type and user_notification_type.push_notification:
send_push(to_user, push_data) send_push(to_user, push_data)
def send_push(user, data): def send_push(user, data):
""" used to send push notification to specific user """ """ used to send push notification to specific user """
data['notification_type'] = str(data['notification_type'])
user.fcmdevice_set.filter(active=True).send_message( user.fcmdevice_set.filter(active=True).send_message(
Message(notification=FirebaseNotification(data['title'], data['body']), data=data) Message(notification=FirebaseNotification(data['title'], data['body']), data=data)
) )
@ -119,6 +131,7 @@ def send_push(user, data):
def send_multiple_push(queryset, data): def send_multiple_push(queryset, data):
""" used to send same notification to multiple users """ """ used to send same notification to multiple users """
data['notification_type'] = str(data['notification_type'])
FCMDevice.objects.filter(user__in=queryset, active=True).send_message( FCMDevice.objects.filter(user__in=queryset, active=True).send_message(
Message(notification=FirebaseNotification(data['title'], data['body']), data=data) Message(notification=FirebaseNotification(data['title'], data['body']), data=data)
) )

View File

@ -33,7 +33,7 @@ class NotificationViewSet(viewsets.GenericViewSet):
:return: :return:
""" """
queryset = Notification.objects.filter(notification_to_id=request.auth.payload['user_id'] queryset = Notification.objects.filter(notification_to_id=request.auth.payload['user_id']
).select_related('notification_to').order_by('-id') ).select_related('notification_to').order_by('-updated_at', '-id')
paginator = CustomPageNumberPagination() paginator = CustomPageNumberPagination()
paginated_queryset = paginator.paginate_queryset(queryset, request) paginated_queryset = paginator.paginate_queryset(queryset, request)
serializer = self.serializer_class(paginated_queryset, many=True) serializer = self.serializer_class(paginated_queryset, many=True)
@ -58,8 +58,11 @@ class NotificationViewSet(viewsets.GenericViewSet):
""" """
notify_task_expiry() notify_task_expiry()
notify_top_junior() notify_top_junior()
send_notification(TEST_NOTIFICATION, None, None, request.auth.payload['user_id'], notification_type = request.query_params.get('type', TEST_NOTIFICATION)
send_notification(int(notification_type), None, None, request.auth.payload['user_id'],
{}) {})
if notification_type and request.query_params.get('clear_all'):
Notification.objects.filter(notification_type=notification_type).delete()
return custom_response(SUCCESS_CODE["3000"]) return custom_response(SUCCESS_CODE["3000"])
@action(methods=['patch'], url_path='mark-as-read', url_name='mark-as-read', detail=False, @action(methods=['patch'], url_path='mark-as-read', url_name='mark-as-read', detail=False,
@ -68,8 +71,14 @@ class NotificationViewSet(viewsets.GenericViewSet):
""" """
notification list notification list
""" """
if request.query_params.get('all'):
Notification.objects.filter(notification_to_id=request.auth.payload['user_id']).update(is_read=True) if request.data.get('id'):
elif request.data.get('id'):
Notification.objects.filter(id__in=request.data.get('id')).update(is_read=True) Notification.objects.filter(id__in=request.data.get('id')).update(is_read=True)
elif request.query_params.get('mark_all'):
Notification.objects.filter(notification_to_id=request.auth.payload['user_id']).update(is_read=True)
elif request.query_params.get('clear_all'):
Notification.objects.filter(notification_to_id=request.auth.payload['user_id']).delete()
return custom_response(SUCCESS_CODE['3039'], response_status=status.HTTP_200_OK) return custom_response(SUCCESS_CODE['3039'], response_status=status.HTTP_200_OK)