From 6ba3d7d8dbb4b1ebad6e14d06ef657a70259f5fd Mon Sep 17 00:00:00 2001 From: abutalib-kiwi Date: Mon, 25 Sep 2023 11:44:04 +0530 Subject: [PATCH 1/9] token expire time 1 min for testing --- zod_bank/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zod_bank/settings.py b/zod_bank/settings.py index cde1918..f318977 100644 --- a/zod_bank/settings.py +++ b/zod_bank/settings.py @@ -137,7 +137,7 @@ REST_FRAMEWORK = { } # define jwt token SIMPLE_JWT = { - 'ACCESS_TOKEN_LIFETIME': timedelta(hours=2, minutes=59, seconds=59, microseconds=999999), + 'ACCESS_TOKEN_LIFETIME': timedelta(hours=0, minutes=59, seconds=59, microseconds=999999), 'REFRESH_TOKEN_LIFETIME': timedelta(hours=71, minutes=59, seconds=59, microseconds=999999), } From ea02d7f5bb168bcf99dd51c4f099891eabfd94f8 Mon Sep 17 00:00:00 2001 From: abutalib-kiwi Date: Mon, 25 Sep 2023 11:45:50 +0530 Subject: [PATCH 2/9] token expire time 1 min for testing --- zod_bank/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zod_bank/settings.py b/zod_bank/settings.py index f318977..96093b2 100644 --- a/zod_bank/settings.py +++ b/zod_bank/settings.py @@ -137,7 +137,7 @@ REST_FRAMEWORK = { } # define jwt token SIMPLE_JWT = { - 'ACCESS_TOKEN_LIFETIME': timedelta(hours=0, minutes=59, seconds=59, microseconds=999999), + 'ACCESS_TOKEN_LIFETIME': timedelta(hours=0, minutes=0, seconds=59, microseconds=999999), 'REFRESH_TOKEN_LIFETIME': timedelta(hours=71, minutes=59, seconds=59, microseconds=999999), } From 32c35f86490100c966ae498d54f031cd92b2cc46 Mon Sep 17 00:00:00 2001 From: abutalib-kiwi Date: Tue, 26 Sep 2023 17:24:40 +0530 Subject: [PATCH 3/9] added notification type in push data --- notifications/constants.py | 19 +++++++++++++++++++ notifications/views.py | 3 ++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/notifications/constants.py b/notifications/constants.py index c22f246..6917327 100644 --- a/notifications/constants.py +++ b/notifications/constants.py @@ -22,79 +22,93 @@ ARTICLE_REWARD_POINTS = 17 REMOVE_JUNIOR = 18 TEST_NOTIFICATION = 99 + # notification dictionary NOTIFICATION_DICT = { REGISTRATION: { + "notification_type": REGISTRATION, "title": "Successfully registered!", "body": "You have registered successfully. Now login and complete your profile." }, # user will receive notification as soon junior # sign up application using their guardian code for association ASSOCIATE_REQUEST: { + "notification_type": ASSOCIATE_REQUEST, "title": "Associate request!", "body": "You have request from {from_user} to associate with you." }, # Juniors will receive notification when # custodians reject their request for associate ASSOCIATE_REJECTED: { + "notification_type": ASSOCIATE_REJECTED, "title": "Associate request rejected!", "body": "Your request to associate has been rejected by {from_user}." }, # Juniors will receive notification when # custodians approve their request for associate ASSOCIATE_APPROVED: { + "notification_type": ASSOCIATE_APPROVED, "title": "Associate request approved!", "body": "Your request to associate has been approved by {from_user}." }, # Juniors will receive Notifications # for every Points earned by referrals REFERRAL_POINTS: { + "notification_type": REFERRAL_POINTS, "title": "Earn Referral points!", "body": "You earn 5 points for referral." }, # Juniors will receive notification # once any custodians add them in their account ASSOCIATE_JUNIOR: { + "notification_type": ASSOCIATE_JUNIOR, "title": "Profile already setup!", "body": "Your guardian has already setup your profile." }, ASSOCIATE_EXISTING_JUNIOR: { + "notification_type": ASSOCIATE_EXISTING_JUNIOR, "title": "Associated to guardian", "body": "Your are associated to your guardian {from_user}." }, # Juniors will receive Notification # for every Task Assign by Custodians TASK_ASSIGNED: { + "notification_type": TASK_ASSIGNED, "title": "New task assigned!", "body": "{from_user} has assigned you a new task." }, # Guardian will receive notification as soon # as junior send task for approval TASK_ACTION: { + "notification_type": TASK_ACTION, "title": "Task completion approval!", "body": "{from_user} completed their task {task_name}." }, # Juniors will receive notification as soon # as their task is rejected by custodians TASK_REJECTED: { + "notification_type": TASK_REJECTED, "title": "Task completion rejected!", "body": "Your task completion request has been rejected by {from_user}." }, # Juniors will receive notification as soon as their task is approved by custodians # and for every Points earned by Task completion TASK_APPROVED: { + "notification_type": TASK_APPROVED, "title": "Task completion approved!", "body": "Your task completion request has been approved by {from_user}. " "Also you earned 5 points for successful completion." }, # Juniors will receive notification when their task end date about to end PENDING_TASK_EXPIRING: { + "notification_type": PENDING_TASK_EXPIRING, "title": "Task expiring soon!", "body": "Your task {task_name} is expiring soon. Please complete it." }, # User will receive notification when their assigned task is about to end # and juniors have not performed any action IN_PROGRESS_TASK_EXPIRING: { + "notification_type": IN_PROGRESS_TASK_EXPIRING, "title": "Task 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." @@ -102,27 +116,32 @@ NOTIFICATION_DICT = { # Juniors will receive Notification # related to Leaderboard progress TOP_JUNIOR: { + "notification_type": TOP_JUNIOR, "title": "Leaderboard topper!", "body": "{from_user} is on top in leaderboard with {points} points." }, # Juniors will receive notification # when admin add any new financial learnings NEW_ARTICLE_PUBLISHED: { + "notification_type": NEW_ARTICLE_PUBLISHED, "title": "Time to read!", "body": "A new article has been published." }, # Juniors will receive notification when they earn points by reading financial Learning ARTICLE_REWARD_POINTS: { + "notification_type": ARTICLE_REWARD_POINTS, "title": "Article reward points!", "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 REMOVE_JUNIOR: { + "notification_type": REMOVE_JUNIOR, "title": "Disassociate by guardian!", "body": "Your guardian has disassociated you." }, # Test notification TEST_NOTIFICATION: { + "notification_type": TEST_NOTIFICATION, "title": "Test Notification", "body": "This notification is for testing purpose from {from_user}." } diff --git a/notifications/views.py b/notifications/views.py index cec50e4..31fb9c1 100644 --- a/notifications/views.py +++ b/notifications/views.py @@ -58,7 +58,8 @@ class NotificationViewSet(viewsets.GenericViewSet): """ notify_task_expiry() 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'], {}) return custom_response(SUCCESS_CODE["3000"]) From f7bb83cebbf98acae3406713c15db198778a413e Mon Sep 17 00:00:00 2001 From: abutalib-kiwi Date: Tue, 26 Sep 2023 19:11:04 +0530 Subject: [PATCH 4/9] added notification type in serializer --- notifications/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notifications/serializers.py b/notifications/serializers.py index e4fdb05..8635970 100644 --- a/notifications/serializers.py +++ b/notifications/serializers.py @@ -36,7 +36,7 @@ class NotificationListSerializer(serializers.ModelSerializer): class Meta(object): """meta info""" model = Notification - fields = ['id', 'data', 'badge', 'is_read', 'created_at'] + fields = ['id', 'notification_type', 'data', 'badge', 'is_read', 'created_at'] @staticmethod def get_badge(obj): From 251a91294836d7c8e003fa61b2750c3864be94d1 Mon Sep 17 00:00:00 2001 From: abutalib-kiwi Date: Wed, 27 Sep 2023 12:36:28 +0530 Subject: [PATCH 5/9] revert access token time to 3 hrs --- zod_bank/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zod_bank/settings.py b/zod_bank/settings.py index 96093b2..cde1918 100644 --- a/zod_bank/settings.py +++ b/zod_bank/settings.py @@ -137,7 +137,7 @@ REST_FRAMEWORK = { } # define jwt token SIMPLE_JWT = { - 'ACCESS_TOKEN_LIFETIME': timedelta(hours=0, minutes=0, seconds=59, microseconds=999999), + 'ACCESS_TOKEN_LIFETIME': timedelta(hours=2, minutes=59, seconds=59, microseconds=999999), 'REFRESH_TOKEN_LIFETIME': timedelta(hours=71, minutes=59, seconds=59, microseconds=999999), } From 18143e02191ea51034e4ee93022257040a1854ef Mon Sep 17 00:00:00 2001 From: abutalib-kiwi Date: Wed, 27 Sep 2023 19:31:09 +0530 Subject: [PATCH 6/9] modified send push method --- notifications/utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/notifications/utils.py b/notifications/utils.py index a118cd7..8941e5b 100644 --- a/notifications/utils.py +++ b/notifications/utils.py @@ -112,6 +112,7 @@ def send_notification(notification_type, from_user_id, from_user_type, to_user_i def send_push(user, data): """ used to send push notification to specific user """ + data['notification_type'] = str(data['notification_type']) user.fcmdevice_set.filter(active=True).send_message( Message(notification=FirebaseNotification(data['title'], data['body']), data=data) ) @@ -119,6 +120,7 @@ def send_push(user, data): def send_multiple_push(queryset, data): """ 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( Message(notification=FirebaseNotification(data['title'], data['body']), data=data) ) From e121c92fb4b10f17dde0ca30a4cfca92245bdf70 Mon Sep 17 00:00:00 2001 From: abutalib-kiwi Date: Thu, 28 Sep 2023 19:07:14 +0530 Subject: [PATCH 7/9] notification create modified to update or create --- base/tasks.py | 4 ++-- notifications/admin.py | 1 + notifications/utils.py | 15 +++++++++++++-- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/base/tasks.py b/base/tasks.py index 24893fc..ebc6672 100644 --- a/base/tasks.py +++ b/base/tasks.py @@ -13,7 +13,7 @@ from django.db.models import F, Window from django.db.models.functions.window import Rank # 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 junior.models import JuniorPoints 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))]) if pending_tasks := all_pending_tasks.filter(task_status=PENDING): 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}) if in_progress_tasks := all_pending_tasks.filter(task_status=IN_PROGRESS): for task in in_progress_tasks: diff --git a/notifications/admin.py b/notifications/admin.py index c7cc895..4df035a 100644 --- a/notifications/admin.py +++ b/notifications/admin.py @@ -11,3 +11,4 @@ class NotificationAdmin(admin.ModelAdmin): """Notification Admin""" list_display = ['id', 'notification_type', 'notification_to', 'data', 'is_read'] list_filter = ['notification_type'] + search_fields = ['notification_to'] diff --git a/notifications/utils.py b/notifications/utils.py index 8941e5b..0ad6cda 100644 --- a/notifications/utils.py +++ b/notifications/utils.py @@ -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) notification_data['body'] = notification_data['body'].format(from_user=from_user_name, task_name=task_name, points=points) + notification_data['from_user'] = from_user_name notification_data['from_user_image'] = from_user_image @@ -104,8 +105,18 @@ 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, from_user_type, to_user_id, extra_data) 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: send_push(to_user, push_data) From bd7eddb27537415fe0853a2e1a92985c3cc1ff87 Mon Sep 17 00:00:00 2001 From: abutalib-kiwi Date: Fri, 29 Sep 2023 14:58:06 +0530 Subject: [PATCH 8/9] notification mark as read api modified for clear all, list sorting set to updated at field, added same field --- .../migrations/0002_notification_updated_at.py | 18 ++++++++++++++++++ notifications/models.py | 1 + notifications/serializers.py | 2 +- notifications/views.py | 16 ++++++++++++---- 4 files changed, 32 insertions(+), 5 deletions(-) create mode 100644 notifications/migrations/0002_notification_updated_at.py diff --git a/notifications/migrations/0002_notification_updated_at.py b/notifications/migrations/0002_notification_updated_at.py new file mode 100644 index 0000000..7a075fa --- /dev/null +++ b/notifications/migrations/0002_notification_updated_at.py @@ -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), + ), + ] diff --git a/notifications/models.py b/notifications/models.py index 5d6d02c..1fb99e9 100644 --- a/notifications/models.py +++ b/notifications/models.py @@ -18,6 +18,7 @@ class Notification(models.Model): data = models.JSONField(default=dict, blank=True, null=True) is_read = models.BooleanField(default=False) created_at = models.DateTimeField(default=timezone.now) + updated_at = models.DateTimeField(auto_now=True) def __str__(self): """ string representation """ diff --git a/notifications/serializers.py b/notifications/serializers.py index 8635970..2c7dfec 100644 --- a/notifications/serializers.py +++ b/notifications/serializers.py @@ -36,7 +36,7 @@ class NotificationListSerializer(serializers.ModelSerializer): class Meta(object): """meta info""" model = Notification - fields = ['id', 'notification_type', 'data', 'badge', 'is_read', 'created_at'] + fields = ['id', 'notification_type', 'data', 'badge', 'is_read', 'updated_at'] @staticmethod def get_badge(obj): diff --git a/notifications/views.py b/notifications/views.py index 31fb9c1..5fcafe8 100644 --- a/notifications/views.py +++ b/notifications/views.py @@ -33,7 +33,7 @@ class NotificationViewSet(viewsets.GenericViewSet): :return: """ 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() paginated_queryset = paginator.paginate_queryset(queryset, request) serializer = self.serializer_class(paginated_queryset, many=True) @@ -61,6 +61,8 @@ class NotificationViewSet(viewsets.GenericViewSet): 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"]) @action(methods=['patch'], url_path='mark-as-read', url_name='mark-as-read', detail=False, @@ -69,8 +71,14 @@ class NotificationViewSet(viewsets.GenericViewSet): """ notification list """ - if request.query_params.get('all'): - Notification.objects.filter(notification_to_id=request.auth.payload['user_id']).update(is_read=True) - elif request.data.get('id'): + + if request.data.get('id'): 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) From 18a53e1c485c5f297501add91f78c3ac53225ca9 Mon Sep 17 00:00:00 2001 From: abutalib-kiwi Date: Fri, 29 Sep 2023 16:09:22 +0530 Subject: [PATCH 9/9] handled deactivated users for social login --- account/views.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/account/views.py b/account/views.py index a76693e..45e662e 100644 --- a/account/views.py +++ b/account/views.py @@ -90,6 +90,11 @@ class GoogleLoginMixin(object): ERROR_CODE["2071"], 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) elif str(user_type) == '2': guardian_query = Guardian.objects.filter(user=user_data.last()).last() @@ -98,6 +103,11 @@ class GoogleLoginMixin(object): ERROR_CODE["2070"], 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) else: return custom_error_response(