mirror of
https://github.com/HamzaSha1/zod-backend.git
synced 2026-03-10 22:31:46 +00:00
Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 219bae792e | |||
| df3cab99a5 | |||
| d2242d4c64 | |||
| b7d5916f8e | |||
| 5e17edcf3f | |||
| b6fe943bfc | |||
| 8e529b292d | |||
| 61ca2e7d2d | |||
| 966f94eb1e | |||
| f424c99478 | |||
| 34359360e0 | |||
| 685a822e52 | |||
| e57344e54f | |||
| 235fc9baac | |||
| 3dc8268b07 | |||
| 8be8d56036 | |||
| c79a891c89 | |||
| eb4e09964d | |||
| cf9376663c | |||
| 9891060ee3 | |||
| 5b2ab2275e | |||
| 9b6a84c7d1 | |||
| e9d4fbe373 | |||
| 21b92f8c74 | |||
| b82902081f | |||
| 3a938720dd | |||
| 464899f7d3 | |||
| 8a436bb79f | |||
| 2e0ceb8c92 | |||
| 1a2fd2d3a8 | |||
| 3d06139c4f | |||
| 226ddfa7e6 | |||
| 342f27fc62 | |||
| 624e7a4edb | |||
| 3072bd5cdb | |||
| 930b58cf05 | |||
| 339c49577e | |||
| 09f006eb13 | |||
| cd3b385756 | |||
| ad0b5bfc75 | |||
| f541608656 |
22
account/templates/templated_email/user_deactivate.email
Normal file
22
account/templates/templated_email/user_deactivate.email
Normal file
@ -0,0 +1,22 @@
|
||||
{% extends "templated_email/email_base.email" %}
|
||||
|
||||
{% block subject %}
|
||||
Account Deactivated
|
||||
{% endblock %}
|
||||
|
||||
{% block plain %}
|
||||
<tr>
|
||||
<td style="padding: 0 27px 15px;">
|
||||
<p style="margin: 0; font-size: 16px; line-height: 20px; padding: 36px 0 0; font-weight: 500; color: #1f2532;">
|
||||
Hi User,
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 0 27px 22px;">
|
||||
<p style="margin: 0;font-size: 14px; font-weight: 400; line-height: 21px; color: #1f2532;">
|
||||
Your account has been deactivated by admin. Please reach out to the admin for assistance.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
{% endblock %}
|
||||
@ -94,7 +94,7 @@ def junior_account_update(user_tb):
|
||||
junior_data.is_active = False
|
||||
junior_data.is_verified = False
|
||||
junior_data.guardian_code = None
|
||||
junior_data.guardian_code_status = str(NUMBER['one'])
|
||||
junior_data.guardian_code_status = None
|
||||
junior_data.is_deleted = True
|
||||
junior_data.save()
|
||||
JuniorPoints.objects.filter(junior=junior_data).delete()
|
||||
@ -282,8 +282,9 @@ def generate_code(value, user_id):
|
||||
|
||||
OTP_EXPIRY = timezone.now() + timezone.timedelta(days=1)
|
||||
|
||||
|
||||
def get_user_full_name(user_obj):
|
||||
"""
|
||||
to get user's full name
|
||||
"""
|
||||
return f"{user_obj.first_name} {user_obj.last_name}" if user_obj.last_name else user_obj.first_name
|
||||
return f"{user_obj.first_name} {user_obj.last_name}" if user_obj.first_name or user_obj.last_name else "User"
|
||||
|
||||
@ -546,7 +546,6 @@ class UserEmailVerification(viewsets.ModelViewSet):
|
||||
class ReSendEmailOtp(viewsets.ModelViewSet):
|
||||
"""Send otp on phone"""
|
||||
serializer_class = EmailVerificationSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
http_method_names = ('post',)
|
||||
def create(self, request, *args, **kwargs):
|
||||
"""Param
|
||||
|
||||
@ -109,7 +109,7 @@ ERROR_CODE = {
|
||||
# force update
|
||||
"2079": "Please update your app version for enjoying uninterrupted services",
|
||||
"2080": "Can not add App version",
|
||||
"2081": "You can not add more than 3 guardian",
|
||||
"2081": "A junior can only be associated with a maximum of 3 guardian",
|
||||
# guardian code not exist
|
||||
"2082": "Guardian code does not exist"
|
||||
|
||||
|
||||
@ -1,29 +1,88 @@
|
||||
"""
|
||||
web_admin tasks file
|
||||
"""
|
||||
import datetime
|
||||
|
||||
# third party imports
|
||||
from celery import shared_task
|
||||
from templated_email import send_templated_mail
|
||||
|
||||
# django imports
|
||||
from django.conf import settings
|
||||
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 guardian.models import JuniorTask
|
||||
from junior.models import JuniorPoints
|
||||
from notifications.constants import PENDING_TASK_EXPIRING, IN_PROGRESS_TASK_EXPIRING, NOTIFICATION_DICT, TOP_JUNIOR
|
||||
from notifications.models import Notification
|
||||
from notifications.utils import send_notification, get_from_user_details, send_notification_multiple_user
|
||||
|
||||
|
||||
@shared_task
|
||||
def send_email_otp(email, verification_code):
|
||||
def send_email(recipient_list, template, context: dict = None):
|
||||
"""
|
||||
used to send otp on email
|
||||
:param email: e-mail
|
||||
:param verification_code: otp
|
||||
:param context:
|
||||
:param recipient_list: e-mail list
|
||||
:param template: email template
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
from_email = settings.EMAIL_FROM_ADDRESS
|
||||
recipient_list = [email]
|
||||
send_templated_mail(
|
||||
template_name='email_reset_verification.email',
|
||||
template_name=template,
|
||||
from_email=from_email,
|
||||
recipient_list=recipient_list,
|
||||
context={
|
||||
'verification_code': verification_code
|
||||
}
|
||||
context=context
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
@shared_task()
|
||||
def notify_task_expiry():
|
||||
"""
|
||||
task to send notification for those task which expiring soon
|
||||
:return:
|
||||
"""
|
||||
all_pending_tasks = JuniorTask.objects.filter(
|
||||
task_status__in=[PENDING, IN_PROGRESS],
|
||||
due_date__range=[datetime.datetime.now().date(),
|
||||
(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,
|
||||
{'task_id': task.id})
|
||||
if in_progress_tasks := all_pending_tasks.filter(task_status=IN_PROGRESS):
|
||||
for task in in_progress_tasks:
|
||||
send_notification(IN_PROGRESS_TASK_EXPIRING, task.junior.auth.id, JUNIOR, task.guardian.user.id,
|
||||
{'task_id': task.id})
|
||||
return True
|
||||
|
||||
|
||||
@shared_task()
|
||||
def notify_top_junior():
|
||||
"""
|
||||
task to send notification for top leaderboard junior to all junior's
|
||||
:return:
|
||||
"""
|
||||
junior_points_qs = JuniorPoints.objects.filter(
|
||||
junior__is_verified=True
|
||||
).select_related(
|
||||
'junior', 'junior__auth'
|
||||
).annotate(rank=Window(
|
||||
expression=Rank(),
|
||||
order_by=[F('total_points').desc(), 'junior__created_at'])
|
||||
).order_by('-total_points', 'junior__created_at')
|
||||
|
||||
prev_top_position = junior_points_qs.filter(position=1).first()
|
||||
new_top_position = junior_points_qs.filter(rank=1).first()
|
||||
if prev_top_position != new_top_position:
|
||||
send_notification_multiple_user(TOP_JUNIOR, new_top_position.junior.auth.id, JUNIOR,
|
||||
{'points': new_top_position.total_points})
|
||||
for junior_point in junior_points_qs:
|
||||
junior_point.position = junior_point.rank
|
||||
junior_point.save()
|
||||
return True
|
||||
|
||||
Binary file not shown.
@ -24,13 +24,13 @@ from account.models import UserProfile, UserEmailOtp, UserNotification
|
||||
from account.utils import generate_code
|
||||
from junior.serializers import JuniorDetailSerializer
|
||||
from base.messages import ERROR_CODE, SUCCESS_CODE
|
||||
from base.constants import NUMBER, JUN, ZOD, GRD, Already_register_user
|
||||
from base.constants import NUMBER, JUN, ZOD, GRD, Already_register_user, GUARDIAN
|
||||
from junior.models import Junior, JuniorPoints, JuniorGuardianRelationship
|
||||
from .utils import real_time, convert_timedelta_into_datetime, update_referral_points
|
||||
# notification's constant
|
||||
from notifications.constants import TASK_APPROVED, TASK_REJECTED
|
||||
# send notification function
|
||||
from notifications.utils import send_notification, send_notification_to_junior
|
||||
from notifications.utils import send_notification
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
@ -323,10 +323,11 @@ class TaskDetailsjuniorSerializer(serializers.ModelSerializer):
|
||||
'requested_on', 'rejected_on', 'completed_on',
|
||||
'junior', 'task_status', 'is_active', 'remaining_time', 'created_at','updated_at']
|
||||
|
||||
|
||||
class TopJuniorSerializer(serializers.ModelSerializer):
|
||||
"""Top junior serializer"""
|
||||
junior = JuniorDetailSerializer()
|
||||
position = serializers.IntegerField()
|
||||
position = serializers.SerializerMethodField()
|
||||
|
||||
class Meta(object):
|
||||
"""Meta info"""
|
||||
@ -336,9 +337,13 @@ class TopJuniorSerializer(serializers.ModelSerializer):
|
||||
def to_representation(self, instance):
|
||||
"""Convert instance to representation"""
|
||||
representation = super().to_representation(instance)
|
||||
representation['position'] = instance.position
|
||||
return representation
|
||||
|
||||
@staticmethod
|
||||
def get_position(obj):
|
||||
""" get position/rank """
|
||||
return obj.rank
|
||||
|
||||
|
||||
class GuardianProfileSerializer(serializers.ModelSerializer):
|
||||
"""junior serializer"""
|
||||
@ -397,9 +402,9 @@ class ApproveJuniorSerializer(serializers.ModelSerializer):
|
||||
def create(self, validated_data):
|
||||
"""update guardian code"""
|
||||
instance = self.context['junior']
|
||||
instance.guardian_code = [self.context['guardian_code']]
|
||||
instance.guardian_code_approved = True
|
||||
instance.guardian_code_status = str(NUMBER['two'])
|
||||
guardian_code = self.context['guardian_code']
|
||||
index = instance.guardian_code.index(guardian_code)
|
||||
instance.guardian_code_status[index] = str(NUMBER['two'])
|
||||
instance.save()
|
||||
return instance
|
||||
|
||||
@ -427,8 +432,8 @@ class ApproveTaskSerializer(serializers.ModelSerializer):
|
||||
# update complete time of task
|
||||
# instance.completed_on = real_time()
|
||||
instance.completed_on = timezone.now().astimezone(pytz.utc)
|
||||
send_notification_to_junior.delay(TASK_APPROVED, instance.guardian.user.id, junior_details.auth.id,
|
||||
{'task_id': instance.id})
|
||||
send_notification.delay(TASK_APPROVED, instance.guardian.user.id, GUARDIAN,
|
||||
junior_details.auth.id, {'task_id': instance.id})
|
||||
else:
|
||||
# reject the task
|
||||
instance.task_status = str(NUMBER['three'])
|
||||
@ -436,8 +441,8 @@ class ApproveTaskSerializer(serializers.ModelSerializer):
|
||||
# update reject time of task
|
||||
# instance.rejected_on = real_time()
|
||||
instance.rejected_on = timezone.now().astimezone(pytz.utc)
|
||||
send_notification_to_junior.delay(TASK_REJECTED, instance.guardian.user.id, junior_details.auth.id,
|
||||
{'task_id': instance.id})
|
||||
send_notification.delay(TASK_REJECTED, instance.guardian.user.id, GUARDIAN,
|
||||
junior_details.auth.id, {'task_id': instance.id})
|
||||
instance.save()
|
||||
junior_data.save()
|
||||
return junior_details
|
||||
@ -507,4 +512,7 @@ class GuardianDetailListSerializer(serializers.ModelSerializer):
|
||||
|
||||
def get_guardian_code_status(self,obj):
|
||||
"""guardian code status"""
|
||||
return obj.junior.guardian_code_status
|
||||
if obj.guardian.guardian_code in obj.junior.guardian_code:
|
||||
index = obj.junior.guardian_code.index(obj.guardian.guardian_code)
|
||||
data = obj.junior.guardian_code_status[index]
|
||||
return data
|
||||
|
||||
@ -21,7 +21,7 @@ from zod_bank.celery import app
|
||||
# notification's constant
|
||||
from notifications.constants import REFERRAL_POINTS
|
||||
# send notification function
|
||||
from notifications.utils import send_notification, send_notification_to_junior
|
||||
from notifications.utils import send_notification
|
||||
|
||||
|
||||
# Define upload image on
|
||||
@ -117,7 +117,7 @@ def update_referral_points(referral_code, referral_code_used):
|
||||
junior_query.total_points = junior_query.total_points + NUMBER['five']
|
||||
junior_query.referral_points = junior_query.referral_points + NUMBER['five']
|
||||
junior_query.save()
|
||||
send_notification_to_junior.delay(REFERRAL_POINTS, None, junior_queryset.auth.id, {})
|
||||
send_notification.delay(REFERRAL_POINTS, None, None, junior_queryset.auth.id, {})
|
||||
|
||||
|
||||
|
||||
|
||||
@ -6,6 +6,8 @@
|
||||
# Import PageNumberPagination
|
||||
# Import User
|
||||
# Import timezone
|
||||
from django.db.models import F, Window
|
||||
from django.db.models.functions.window import Rank
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework import viewsets, status
|
||||
from rest_framework.pagination import PageNumberPagination
|
||||
@ -36,10 +38,10 @@ from account.models import UserEmailOtp, UserNotification, UserDeviceDetails
|
||||
from .tasks import generate_otp
|
||||
from account.utils import custom_response, custom_error_response, OTP_EXPIRY, send_otp_email
|
||||
from base.messages import ERROR_CODE, SUCCESS_CODE
|
||||
from base.constants import NUMBER, GUARDIAN_CODE_STATUS
|
||||
from base.constants import NUMBER, GUARDIAN_CODE_STATUS, GUARDIAN
|
||||
from .utils import upload_image_to_alibaba
|
||||
from notifications.constants import REGISTRATION, TASK_ASSIGNED, ASSOCIATE_APPROVED, ASSOCIATE_REJECTED
|
||||
from notifications.utils import send_notification_to_junior
|
||||
from notifications.utils import send_notification
|
||||
|
||||
""" Define APIs """
|
||||
# Define Signup API,
|
||||
@ -177,36 +179,40 @@ class CreateTaskAPIView(viewsets.ModelViewSet):
|
||||
image = request.data['default_image']
|
||||
junior = request.data['junior']
|
||||
junior_id = Junior.objects.filter(id=junior).last()
|
||||
guardian_data = Guardian.objects.filter(user=request.user).last()
|
||||
if (guardian_data.guardian_code not in junior_id.guardian_code or
|
||||
junior_id.guardian_code_status in guardian_code_tuple):
|
||||
return custom_error_response(ERROR_CODE['2078'], response_status=status.HTTP_400_BAD_REQUEST)
|
||||
allowed_extensions = ['.jpg', '.jpeg', '.png']
|
||||
if not any(extension in str(image) for extension in allowed_extensions):
|
||||
return custom_error_response(ERROR_CODE['2048'], response_status=status.HTTP_400_BAD_REQUEST)
|
||||
if not junior.isnumeric():
|
||||
"""junior value must be integer"""
|
||||
return custom_error_response(ERROR_CODE['2047'], response_status=status.HTTP_400_BAD_REQUEST)
|
||||
data = request.data
|
||||
if 'https' in str(image):
|
||||
image_data = image
|
||||
else:
|
||||
filename = f"images/{image}"
|
||||
if image and image.size == NUMBER['zero']:
|
||||
return custom_error_response(ERROR_CODE['2035'], response_status=status.HTTP_400_BAD_REQUEST)
|
||||
image_url = upload_image_to_alibaba(image, filename)
|
||||
image_data = image_url
|
||||
data.pop('default_image')
|
||||
# use TaskSerializer serializer
|
||||
serializer = TaskSerializer(context={"user":request.user, "image":image_data}, data=data)
|
||||
if serializer.is_valid():
|
||||
# save serializer
|
||||
task = serializer.save()
|
||||
if junior_id:
|
||||
guardian_data = Guardian.objects.filter(user=request.user).last()
|
||||
index = junior_id.guardian_code.index(guardian_data.guardian_code)
|
||||
status_index = junior_id.guardian_code_status[index]
|
||||
if status_index == str(NUMBER['three']):
|
||||
return custom_error_response(ERROR_CODE['2078'], response_status=status.HTTP_400_BAD_REQUEST)
|
||||
allowed_extensions = ['.jpg', '.jpeg', '.png']
|
||||
if not any(extension in str(image) for extension in allowed_extensions):
|
||||
return custom_error_response(ERROR_CODE['2048'], response_status=status.HTTP_400_BAD_REQUEST)
|
||||
if not junior.isnumeric():
|
||||
"""junior value must be integer"""
|
||||
return custom_error_response(ERROR_CODE['2047'], response_status=status.HTTP_400_BAD_REQUEST)
|
||||
data = request.data
|
||||
if 'https' in str(image):
|
||||
image_data = image
|
||||
else:
|
||||
filename = f"images/{image}"
|
||||
if image and image.size == NUMBER['zero']:
|
||||
return custom_error_response(ERROR_CODE['2035'], response_status=status.HTTP_400_BAD_REQUEST)
|
||||
image_url = upload_image_to_alibaba(image, filename)
|
||||
image_data = image_url
|
||||
data.pop('default_image')
|
||||
# use TaskSerializer serializer
|
||||
serializer = TaskSerializer(context={"user":request.user, "image":image_data}, data=data)
|
||||
if serializer.is_valid():
|
||||
# save serializer
|
||||
task = serializer.save()
|
||||
|
||||
send_notification_to_junior.delay(TASK_ASSIGNED, request.auth.payload['user_id'],
|
||||
junior_id.auth.id, {'task_id': task.id})
|
||||
return custom_response(SUCCESS_CODE['3018'], serializer.data, response_status=status.HTTP_200_OK)
|
||||
return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST)
|
||||
send_notification.delay(TASK_ASSIGNED, request.auth.payload['user_id'], GUARDIAN,
|
||||
junior_id.auth.id, {'task_id': task.id})
|
||||
return custom_response(SUCCESS_CODE['3018'], serializer.data, response_status=status.HTTP_200_OK)
|
||||
return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST)
|
||||
else:
|
||||
return custom_error_response(ERROR_CODE['2047'], response_status=status.HTTP_400_BAD_REQUEST)
|
||||
except Exception as e:
|
||||
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
@ -242,7 +248,6 @@ class SearchTaskListAPIView(viewsets.ModelViewSet):
|
||||
class TopJuniorListAPIView(viewsets.ModelViewSet):
|
||||
"""Top juniors list
|
||||
No Params"""
|
||||
queryset = JuniorPoints.objects.all()
|
||||
serializer_class = TopJuniorSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
http_method_names = ('get',)
|
||||
@ -253,15 +258,22 @@ class TopJuniorListAPIView(viewsets.ModelViewSet):
|
||||
context.update({'view': self})
|
||||
return context
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = JuniorPoints.objects.filter(
|
||||
junior__is_verified=True
|
||||
).select_related(
|
||||
'junior', 'junior__auth'
|
||||
).annotate(rank=Window(
|
||||
expression=Rank(),
|
||||
order_by=[F('total_points').desc(), 'junior__created_at'])
|
||||
).order_by('-total_points', 'junior__created_at')
|
||||
return queryset
|
||||
|
||||
def list(self, request, *args, **kwargs):
|
||||
"""Fetch junior list of those who complete their tasks"""
|
||||
try:
|
||||
junior_total_points = self.get_queryset().order_by('-total_points')
|
||||
# Update the position field for each JuniorPoints object
|
||||
for index, junior in enumerate(junior_total_points):
|
||||
junior.position = index + 1
|
||||
junior.save()
|
||||
serializer = self.get_serializer(junior_total_points[:NUMBER['fifteen']], many=True)
|
||||
junior_total_points = self.get_queryset()[:15]
|
||||
serializer = self.get_serializer(junior_total_points, many=True)
|
||||
return custom_response(None, serializer.data, response_status=status.HTTP_200_OK)
|
||||
except Exception as e:
|
||||
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
|
||||
@ -294,13 +306,19 @@ class ApproveJuniorAPIView(viewsets.ModelViewSet):
|
||||
if serializer.is_valid():
|
||||
# save serializer
|
||||
serializer.save()
|
||||
send_notification_to_junior.delay(ASSOCIATE_APPROVED, guardian.user.id, junior_queryset.auth.id)
|
||||
send_notification.delay(ASSOCIATE_APPROVED, guardian.user.id, GUARDIAN,
|
||||
junior_queryset.auth.id, {})
|
||||
return custom_response(SUCCESS_CODE['3023'], serializer.data, response_status=status.HTTP_200_OK)
|
||||
else:
|
||||
junior_queryset.guardian_code = None
|
||||
junior_queryset.guardian_code_status = str(NUMBER['one'])
|
||||
if junior_queryset.guardian_code and ('-' in junior_queryset.guardian_code):
|
||||
junior_queryset.guardian_code.remove('-')
|
||||
if junior_queryset.guardian_code_status and ('-' in junior_queryset.guardian_code_status):
|
||||
junior_queryset.guardian_code_status.remove('-')
|
||||
index = junior_queryset.guardian_code.index(guardian.guardian_code)
|
||||
junior_queryset.guardian_code.remove(guardian.guardian_code)
|
||||
junior_queryset.guardian_code_status.pop(index)
|
||||
junior_queryset.save()
|
||||
send_notification_to_junior.delay(ASSOCIATE_REJECTED, guardian.user.id, junior_queryset.auth.id)
|
||||
send_notification.delay(ASSOCIATE_REJECTED, guardian.user.id, GUARDIAN, junior_queryset.auth.id, {})
|
||||
return custom_response(SUCCESS_CODE['3024'], response_status=status.HTTP_200_OK)
|
||||
except Exception as e:
|
||||
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
|
||||
@ -349,7 +367,7 @@ class ApproveTaskAPIView(viewsets.ModelViewSet):
|
||||
return custom_error_response(ERROR_CODE['2038'], response_status=status.HTTP_400_BAD_REQUEST)
|
||||
except Exception as e:
|
||||
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
#
|
||||
class GuardianListAPIView(viewsets.ModelViewSet):
|
||||
"""Guardian list of assosicated junior"""
|
||||
|
||||
|
||||
17
junior/migrations/0030_remove_junior_guardian_code_status.py
Normal file
17
junior/migrations/0030_remove_junior_guardian_code_status.py
Normal file
@ -0,0 +1,17 @@
|
||||
# Generated by Django 4.2.2 on 2023-08-26 08:59
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('junior', '0029_junior_is_deleted'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='junior',
|
||||
name='guardian_code_status',
|
||||
),
|
||||
]
|
||||
19
junior/migrations/0031_junior_guardian_code_status.py
Normal file
19
junior/migrations/0031_junior_guardian_code_status.py
Normal file
@ -0,0 +1,19 @@
|
||||
# Generated by Django 4.2.2 on 2023-08-26 08:59
|
||||
|
||||
import django.contrib.postgres.fields
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('junior', '0030_remove_junior_guardian_code_status'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='junior',
|
||||
name='guardian_code_status',
|
||||
field=django.contrib.postgres.fields.ArrayField(base_field=models.CharField(blank=True, default=None, max_length=10, null=True), null=True, size=None),
|
||||
),
|
||||
]
|
||||
@ -76,9 +76,9 @@ class Junior(models.Model):
|
||||
is_verified = models.BooleanField(default=False)
|
||||
"""guardian code is approved or not"""
|
||||
guardian_code_approved = models.BooleanField(default=False)
|
||||
# guardian code status"""
|
||||
guardian_code_status = models.CharField(max_length=31, choices=GUARDIAN_CODE_STATUS, default='1',
|
||||
null=True, blank=True)
|
||||
# # guardian code status"""
|
||||
guardian_code_status = ArrayField(models.CharField(max_length=10, null=True, blank=True, default=None), null=True,
|
||||
)
|
||||
# Profile created and updated time"""
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
@ -16,13 +16,13 @@ from junior.models import Junior, JuniorPoints, JuniorGuardianRelationship, Juni
|
||||
from guardian.tasks import generate_otp
|
||||
from base.messages import ERROR_CODE, SUCCESS_CODE
|
||||
from base.constants import (PENDING, IN_PROGRESS, REJECTED, REQUESTED, COMPLETED, NUMBER, JUN, ZOD, EXPIRED,
|
||||
GUARDIAN_CODE_STATUS)
|
||||
GUARDIAN_CODE_STATUS, JUNIOR)
|
||||
from guardian.models import Guardian, JuniorTask
|
||||
from account.models import UserEmailOtp, UserNotification
|
||||
from junior.utils import junior_notification_email, junior_approval_mail
|
||||
from junior.utils import junior_notification_email, junior_approval_mail, get_junior_leaderboard_rank
|
||||
from guardian.utils import real_time, update_referral_points, convert_timedelta_into_datetime
|
||||
from notifications.utils import send_notification, send_notification_to_junior, send_notification_to_guardian
|
||||
from notifications.constants import (ASSOCIATE_REQUEST, JUNIOR_ADDED, TASK_ACTION,
|
||||
from notifications.utils import send_notification
|
||||
from notifications.constants import (ASSOCIATE_REQUEST, ASSOCIATE_JUNIOR, TASK_ACTION,
|
||||
)
|
||||
from web_admin.models import ArticleCard
|
||||
|
||||
@ -91,20 +91,24 @@ class CreateJuniorSerializer(serializers.ModelSerializer):
|
||||
# Update guardian code"""
|
||||
# condition for guardian code
|
||||
if guardian_code:
|
||||
if junior.guardian_code and guardian_code:
|
||||
if guardian_code[0] in junior.guardian_code:
|
||||
raise serializers.ValidationError({"error":ERROR_CODE['2076'],"code":"400", "status":"failed"})
|
||||
if not junior.guardian_code:
|
||||
junior.guardian_code = []
|
||||
junior.guardian_code_status = []
|
||||
junior.guardian_code.extend(guardian_code)
|
||||
junior.guardian_code_status.extend(str(NUMBER['three']))
|
||||
elif len(junior.guardian_code) < 3 and len(guardian_code) < 3:
|
||||
junior.guardian_code.extend(guardian_code)
|
||||
junior.guardian_code_status.extend(str(NUMBER['three']))
|
||||
else:
|
||||
raise serializers.ValidationError({"error":ERROR_CODE['2081'],"code":"400", "status":"failed"})
|
||||
guardian_data = Guardian.objects.filter(guardian_code=guardian_code[0]).last()
|
||||
if guardian_data:
|
||||
JuniorGuardianRelationship.objects.get_or_create(guardian=guardian_data, junior=junior)
|
||||
junior.guardian_code_status = str(NUMBER['three'])
|
||||
send_notification.delay(ASSOCIATE_REQUEST, junior.auth.id, JUNIOR, guardian_data.user.id, {})
|
||||
junior_approval_mail.delay(user.email, user.first_name)
|
||||
send_notification_to_guardian.delay(ASSOCIATE_REQUEST, junior.auth.id, guardian_data.user.id, {})
|
||||
|
||||
junior.dob = validated_data.get('dob', junior.dob)
|
||||
junior.passcode = validated_data.get('passcode', junior.passcode)
|
||||
junior.country_name = validated_data.get('country_name', junior.country_name)
|
||||
@ -169,6 +173,7 @@ class JuniorDetailListSerializer(serializers.ModelSerializer):
|
||||
rejected_task = serializers.SerializerMethodField('get_rejected_task')
|
||||
pending_task = serializers.SerializerMethodField('get_pending_task')
|
||||
position = serializers.SerializerMethodField('get_position')
|
||||
guardian_code_status = serializers.SerializerMethodField('get_guardian_code_status')
|
||||
|
||||
|
||||
def get_auth(self, obj):
|
||||
@ -185,9 +190,8 @@ class JuniorDetailListSerializer(serializers.ModelSerializer):
|
||||
return data
|
||||
|
||||
def get_position(self, obj):
|
||||
data = JuniorPoints.objects.filter(junior=obj).last()
|
||||
if data:
|
||||
return data.position
|
||||
return get_junior_leaderboard_rank(obj)
|
||||
|
||||
def get_points(self, obj):
|
||||
data = JuniorPoints.objects.filter(junior=obj).last()
|
||||
if data:
|
||||
@ -214,6 +218,13 @@ class JuniorDetailListSerializer(serializers.ModelSerializer):
|
||||
def get_pending_task(self, obj):
|
||||
data = JuniorTask.objects.filter(junior=obj, task_status=PENDING).count()
|
||||
return data
|
||||
|
||||
def get_guardian_code_status(self, obj):
|
||||
if self.context['guardian_code'] in obj.guardian_code:
|
||||
index = obj.guardian_code.index(self.context['guardian_code'])
|
||||
if obj.guardian_code_status:
|
||||
data = obj.guardian_code_status[index]
|
||||
return data
|
||||
class Meta(object):
|
||||
"""Meta info"""
|
||||
model = Junior
|
||||
@ -297,8 +308,8 @@ class AddJuniorSerializer(serializers.ModelSerializer):
|
||||
referral_code=generate_code(ZOD, user_data.id),
|
||||
referral_code_used=guardian_data.referral_code,
|
||||
is_password_set=False, is_verified=True,
|
||||
guardian_code_status=GUARDIAN_CODE_STATUS[1][0])
|
||||
JuniorGuardianRelationship.objects.get_or_create(guardian=guardian_data, junior=junior_data,
|
||||
guardian_code_status=[str(NUMBER['two'])])
|
||||
JuniorGuardianRelationship.objects.create(guardian=guardian_data, junior=junior_data,
|
||||
relationship=relationship)
|
||||
total_junior = Junior.objects.all().count()
|
||||
JuniorPoints.objects.create(junior=junior_data, position=total_junior)
|
||||
@ -312,7 +323,7 @@ class AddJuniorSerializer(serializers.ModelSerializer):
|
||||
"""Notification email"""
|
||||
junior_notification_email.delay(email, full_name, email, password)
|
||||
# push notification
|
||||
send_notification_to_junior.delay(JUNIOR_ADDED, None, junior_data.auth.id, {})
|
||||
send_notification.delay(ASSOCIATE_JUNIOR, None, None, junior_data.auth.id, {})
|
||||
return junior_data
|
||||
|
||||
|
||||
@ -327,9 +338,11 @@ class RemoveJuniorSerializer(serializers.ModelSerializer):
|
||||
if instance:
|
||||
guardian_code = self.context['guardian_code']
|
||||
instance.is_invited = False
|
||||
if instance.guardian_code and ('-' in instance.guardian_code):
|
||||
instance.guardian_code.remove('-')
|
||||
index = instance.guardian_code.index(guardian_code)
|
||||
instance.guardian_code.remove(guardian_code)
|
||||
if not instance.guardian_code:
|
||||
instance.guardian_code_status = str(NUMBER['one'])
|
||||
instance.guardian_code_status.pop(index)
|
||||
instance.save()
|
||||
return instance
|
||||
|
||||
@ -346,8 +359,8 @@ class CompleteTaskSerializer(serializers.ModelSerializer):
|
||||
instance.task_status = str(NUMBER['four'])
|
||||
instance.is_approved = False
|
||||
instance.save()
|
||||
send_notification_to_guardian.delay(TASK_ACTION, instance.junior.auth.id,
|
||||
instance.guardian.user.id, {'task_id': instance.id})
|
||||
send_notification.delay(TASK_ACTION, instance.junior.auth.id, JUNIOR,
|
||||
instance.guardian.user.id, {'task_id': instance.id})
|
||||
return instance
|
||||
|
||||
class JuniorPointsSerializer(serializers.ModelSerializer):
|
||||
@ -367,10 +380,7 @@ class JuniorPointsSerializer(serializers.ModelSerializer):
|
||||
return obj.junior.id
|
||||
|
||||
def get_position(self, obj):
|
||||
data = JuniorPoints.objects.filter(junior=obj.junior).last()
|
||||
if data:
|
||||
return data.position
|
||||
return 99999
|
||||
return get_junior_leaderboard_rank(obj.junior)
|
||||
def get_points(self, obj):
|
||||
"""total points"""
|
||||
points = JuniorPoints.objects.filter(junior=obj.junior).last()
|
||||
@ -451,13 +461,13 @@ class AddGuardianSerializer(serializers.ModelSerializer):
|
||||
user_type=str(NUMBER['two']), expired_at=expiry_time,
|
||||
is_verified=True)
|
||||
UserNotification.objects.get_or_create(user=user)
|
||||
JuniorGuardianRelationship.objects.get_or_create(guardian=guardian_data, junior=junior_data,
|
||||
JuniorGuardianRelationship.objects.create(guardian=guardian_data, junior=junior_data,
|
||||
relationship=relationship)
|
||||
|
||||
"""Notification email"""
|
||||
junior_notification_email(email, full_name, email, password)
|
||||
junior_approval_mail.delay(email, full_name)
|
||||
send_notification_to_guardian.delay(ASSOCIATE_REQUEST, junior_data.auth.id, guardian_data.user.id, {})
|
||||
send_notification.delay(ASSOCIATE_REQUEST, junior_data.auth.id, JUNIOR, guardian_data.user.id, {})
|
||||
return guardian_data
|
||||
|
||||
class StartTaskSerializer(serializers.ModelSerializer):
|
||||
@ -510,15 +520,15 @@ class RemoveGuardianCodeSerializer(serializers.ModelSerializer):
|
||||
def update(self, instance, validated_data):
|
||||
guardian_code = self.context['guardian_code']
|
||||
if guardian_code in instance.guardian_code:
|
||||
if instance.guardian_code and ('-' in instance.guardian_code):
|
||||
instance.guardian_code.remove('-')
|
||||
if instance.guardian_code_status and ('-' in instance.guardian_code_status):
|
||||
instance.guardian_code_status.remove('-')
|
||||
index = instance.guardian_code.index(guardian_code)
|
||||
instance.guardian_code.remove(guardian_code)
|
||||
instance.guardian_code_status.pop(index)
|
||||
else:
|
||||
raise serializers.ValidationError({"error":ERROR_CODE['2082'],"code":"400", "status":"failed"})
|
||||
if not instance.guardian_code:
|
||||
instance.guardian_code_status = str(NUMBER['one'])
|
||||
elif instance.guardian_code and (len(instance.guardian_code) == 1 and '-' in instance.guardian_code):
|
||||
instance.guardian_code_status = str(NUMBER['one'])
|
||||
else:
|
||||
instance.guardian_code_status = str(NUMBER['two'])
|
||||
instance.save()
|
||||
return instance
|
||||
|
||||
|
||||
@ -5,7 +5,8 @@ from django.conf import settings
|
||||
from templated_email import send_templated_mail
|
||||
from .models import JuniorPoints
|
||||
from base.constants import NUMBER
|
||||
from django.db.models import F
|
||||
from django.db.models import F, Window
|
||||
from django.db.models.functions.window import Rank
|
||||
# junior notification
|
||||
# email for sending email
|
||||
# when guardian create junior profile
|
||||
@ -61,3 +62,21 @@ def update_positions_based_on_points():
|
||||
junior_point.position = position
|
||||
junior_point.save()
|
||||
position += NUMBER['one']
|
||||
|
||||
|
||||
def get_junior_leaderboard_rank(junior_obj):
|
||||
"""
|
||||
to get junior's position/rank
|
||||
:param junior_obj:
|
||||
:return: junior's position/rank
|
||||
"""
|
||||
queryset = JuniorPoints.objects.filter(
|
||||
junior__is_verified=True
|
||||
).select_related('junior', 'junior__auth').annotate(rank=Window(
|
||||
expression=Rank(),
|
||||
order_by=[F('total_points').desc(), 'junior__created_at']
|
||||
)).order_by('-total_points', 'junior__created_at')
|
||||
|
||||
junior = next((query for query in queryset if query.junior == junior_obj), None)
|
||||
|
||||
return junior.rank if junior else None
|
||||
|
||||
@ -42,12 +42,12 @@ from .serializers import (CreateJuniorSerializer, JuniorDetailListSerializer, Ad
|
||||
from guardian.models import Guardian, JuniorTask
|
||||
from guardian.serializers import TaskDetailsSerializer, TaskDetailsjuniorSerializer
|
||||
from base.messages import ERROR_CODE, SUCCESS_CODE
|
||||
from base.constants import NUMBER, ARTICLE_STATUS, none
|
||||
from base.constants import NUMBER, ARTICLE_STATUS, none, GUARDIAN
|
||||
from account.utils import custom_response, custom_error_response
|
||||
from guardian.utils import upload_image_to_alibaba
|
||||
from .utils import update_positions_based_on_points
|
||||
from notifications.utils import send_notification, send_notification_to_junior
|
||||
from notifications.constants import REMOVE_JUNIOR
|
||||
from notifications.utils import send_notification
|
||||
from notifications.constants import REMOVE_JUNIOR, ARTICLE_REWARD_POINTS, ASSOCIATE_EXISTING_JUNIOR
|
||||
from web_admin.models import Article, ArticleSurvey, SurveyOption, ArticleCard
|
||||
from web_admin.serializers.article_serializer import (ArticleSerializer, ArticleListSerializer,
|
||||
StartAssessmentSerializer)
|
||||
@ -99,7 +99,10 @@ class UpdateJuniorProfile(viewsets.ModelViewSet):
|
||||
return custom_response(None, serializer.data, response_status=status.HTTP_200_OK)
|
||||
return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST)
|
||||
except Exception as e:
|
||||
error_detail = e.detail.get('error', None)
|
||||
if e.detail:
|
||||
error_detail = e.detail.get('error', None)
|
||||
else:
|
||||
error_detail = str(e)
|
||||
return custom_error_response(error_detail, response_status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
class ValidateGuardianCode(viewsets.ModelViewSet):
|
||||
@ -142,14 +145,15 @@ class JuniorListAPIView(viewsets.ModelViewSet):
|
||||
def list(self, request, *args, **kwargs):
|
||||
""" junior list"""
|
||||
try:
|
||||
update_positions_based_on_points()
|
||||
# update_positions_based_on_points, function removed
|
||||
guardian_data = Guardian.objects.filter(user__email=request.user).last()
|
||||
# fetch junior object
|
||||
if guardian_data:
|
||||
queryset = self.get_queryset()
|
||||
queryset = queryset.filter(guardian_code__icontains=str(guardian_data.guardian_code))
|
||||
# use JuniorDetailListSerializer serializer
|
||||
serializer = JuniorDetailListSerializer(queryset, many=True)
|
||||
serializer = JuniorDetailListSerializer(queryset, context={"guardian_code":
|
||||
guardian_data.guardian_code}, many=True)
|
||||
return custom_response(None, serializer.data, response_status=status.HTTP_200_OK)
|
||||
return custom_error_response(ERROR_CODE['2045'], response_status=status.HTTP_200_OK)
|
||||
except Exception as e:
|
||||
@ -191,7 +195,7 @@ class AddJuniorAPIView(viewsets.ModelViewSet):
|
||||
return custom_error_response(ERROR_CODE['2077'], response_status=status.HTTP_400_BAD_REQUEST)
|
||||
elif not data:
|
||||
return custom_error_response(ERROR_CODE['2076'], response_status=status.HTTP_400_BAD_REQUEST)
|
||||
if data == "Max":
|
||||
elif data == "Max":
|
||||
return custom_error_response(ERROR_CODE['2081'], response_status=status.HTTP_400_BAD_REQUEST)
|
||||
return custom_response(SUCCESS_CODE['3021'], response_status=status.HTTP_200_OK)
|
||||
# use AddJuniorSerializer serializer
|
||||
@ -219,10 +223,13 @@ class AddJuniorAPIView(viewsets.ModelViewSet):
|
||||
junior.guardian_code.append(guardian.guardian_code)
|
||||
else:
|
||||
return "Max"
|
||||
junior.guardian_code_status = str(NUMBER['two'])
|
||||
junior.guardian_code_status.append(str(NUMBER['two']))
|
||||
junior.save()
|
||||
JuniorGuardianRelationship.objects.get_or_create(guardian=guardian, junior=junior,
|
||||
relationship=str(self.request.data['relationship']))
|
||||
jun_data, created = JuniorGuardianRelationship.objects.get_or_create(guardian=guardian, junior=junior)
|
||||
if jun_data:
|
||||
jun_data.relationship = str(self.request.data['relationship'])
|
||||
jun_data.save()
|
||||
send_notification.delay(ASSOCIATE_EXISTING_JUNIOR, self.request.user.id, GUARDIAN, junior.auth.id, {})
|
||||
return True
|
||||
|
||||
|
||||
@ -320,7 +327,8 @@ class RemoveJuniorAPIView(views.APIView):
|
||||
if serializer.is_valid():
|
||||
# save serializer
|
||||
serializer.save()
|
||||
send_notification_to_junior.delay(REMOVE_JUNIOR, None, junior_queryset.auth.id, {})
|
||||
JuniorGuardianRelationship.objects.filter(guardian=guardian, junior=junior_queryset).delete()
|
||||
send_notification.delay(REMOVE_JUNIOR, None, None, junior_queryset.auth.id, {})
|
||||
return custom_response(SUCCESS_CODE['3022'], serializer.data, response_status=status.HTTP_200_OK)
|
||||
return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST)
|
||||
else:
|
||||
@ -420,7 +428,7 @@ class JuniorPointsListAPIView(viewsets.ModelViewSet):
|
||||
"""Junior Points
|
||||
No Params"""
|
||||
try:
|
||||
update_positions_based_on_points()
|
||||
# update_positions_based_on_points, function removed
|
||||
queryset = JuniorPoints.objects.filter(junior__auth__email=self.request.user).last()
|
||||
# update position of junior
|
||||
serializer = JuniorPointsSerializer(queryset)
|
||||
@ -666,6 +674,8 @@ class CompleteArticleAPIView(views.APIView):
|
||||
is_answer_correct=True).aggregate(
|
||||
total_earn_points=Sum('earn_points'))['total_earn_points']
|
||||
data = {"total_earn_points":total_earn_points}
|
||||
send_notification.delay(ARTICLE_REWARD_POINTS, None, None,
|
||||
request.user.id, {'points': total_earn_points})
|
||||
return custom_response(SUCCESS_CODE['3042'], data, response_status=status.HTTP_200_OK)
|
||||
except Exception as e:
|
||||
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
|
||||
@ -736,6 +746,7 @@ class RemoveGuardianCodeAPIView(views.APIView):
|
||||
def put(self, request, format=None):
|
||||
try:
|
||||
guardian_code = self.request.data.get("guardian_code")
|
||||
guardian_data = Guardian.objects.filter(guardian_code=guardian_code).last()
|
||||
junior_queryset = Junior.objects.filter(auth=self.request.user).last()
|
||||
if junior_queryset:
|
||||
# use RemoveGuardianCodeSerializer serializer
|
||||
@ -744,6 +755,7 @@ class RemoveGuardianCodeAPIView(views.APIView):
|
||||
if serializer.is_valid():
|
||||
# save serializer
|
||||
serializer.save()
|
||||
JuniorGuardianRelationship.objects.filter(guardian=guardian_data, junior=junior_queryset).delete()
|
||||
return custom_response(SUCCESS_CODE['3044'], response_status=status.HTTP_200_OK)
|
||||
return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST)
|
||||
else:
|
||||
|
||||
@ -6,14 +6,20 @@ ASSOCIATE_REQUEST = 3
|
||||
ASSOCIATE_REJECTED = 4
|
||||
ASSOCIATE_APPROVED = 5
|
||||
REFERRAL_POINTS = 6
|
||||
JUNIOR_ADDED = 7
|
||||
ASSOCIATE_JUNIOR = 7
|
||||
ASSOCIATE_EXISTING_JUNIOR = 8
|
||||
|
||||
TASK_ASSIGNED = 8
|
||||
TASK_ACTION = 9
|
||||
TASK_REJECTED = 10
|
||||
TASK_APPROVED = 11
|
||||
TASK_ASSIGNED = 9
|
||||
TASK_ACTION = 10
|
||||
TASK_REJECTED = 11
|
||||
TASK_APPROVED = 12
|
||||
PENDING_TASK_EXPIRING = 13
|
||||
IN_PROGRESS_TASK_EXPIRING = 14
|
||||
TOP_JUNIOR = 15
|
||||
|
||||
REMOVE_JUNIOR = 13
|
||||
NEW_ARTICLE_PUBLISHED = 16
|
||||
ARTICLE_REWARD_POINTS = 17
|
||||
REMOVE_JUNIOR = 18
|
||||
|
||||
TEST_NOTIFICATION = 99
|
||||
|
||||
@ -22,41 +28,54 @@ NOTIFICATION_DICT = {
|
||||
"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: {
|
||||
"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: {
|
||||
"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: {
|
||||
"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
|
||||
# Juniors will receive Notifications
|
||||
# for every Points earned by referrals
|
||||
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
|
||||
JUNIOR_ADDED: {
|
||||
# Juniors will receive notification
|
||||
# once any custodians add them in their account
|
||||
ASSOCIATE_JUNIOR: {
|
||||
"title": "Profile already setup!",
|
||||
"body": "Your guardian has already setup your profile."
|
||||
},
|
||||
# Juniors will receive Notification for every Task Assign by Custodians
|
||||
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: {
|
||||
"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
|
||||
# Guardian will receive notification as soon
|
||||
# as junior send task for approval
|
||||
TASK_ACTION: {
|
||||
"title": "Task completion approval!",
|
||||
"body": "You have request from {from_user} for task completion."
|
||||
"body": "{from_user} completed their task {task_name}."
|
||||
},
|
||||
# Juniors will receive notification as soon as their task is rejected by custodians
|
||||
# Juniors will receive notification as soon
|
||||
# as their task is rejected by custodians
|
||||
TASK_REJECTED: {
|
||||
"title": "Task completion rejected!",
|
||||
"body": "Your task completion request has been rejected by {from_user}."
|
||||
@ -68,11 +87,41 @@ NOTIFICATION_DICT = {
|
||||
"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: {
|
||||
"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: {
|
||||
"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."
|
||||
},
|
||||
# Juniors will receive Notification
|
||||
# related to Leaderboard progress
|
||||
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: {
|
||||
"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: {
|
||||
"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: {
|
||||
"title": "Disassociate by guardian!",
|
||||
"body": "Your guardian has disassociated you."
|
||||
},
|
||||
# Test notification
|
||||
TEST_NOTIFICATION: {
|
||||
"title": "Test Notification",
|
||||
"body": "This notification is for testing purpose from {from_user}."
|
||||
|
||||
@ -8,24 +8,24 @@ from firebase_admin.messaging import Message, Notification as FirebaseNotificati
|
||||
|
||||
# django imports
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.db.models import Q
|
||||
|
||||
# local imports
|
||||
from account.models import UserNotification
|
||||
from account.utils import get_user_full_name
|
||||
from guardian.models import Guardian
|
||||
from base.constants import GUARDIAN, JUNIOR
|
||||
from guardian.models import Guardian, JuniorTask
|
||||
from junior.models import Junior
|
||||
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,
|
||||
defaults={'user_id': user_id, 'type': device_type,
|
||||
device, _ = FCMDevice.objects.update_or_create(user_id=user_id,
|
||||
defaults={'device_id': device_id, 'type': device_type,
|
||||
'active': True,
|
||||
'registration_id': registration_id})
|
||||
return device
|
||||
@ -42,49 +42,72 @@ def remove_fcm_token(user_id: int, access_token: str, registration_id) -> None:
|
||||
print(e)
|
||||
|
||||
|
||||
def get_basic_detail(from_user_id, to_user_id):
|
||||
def get_from_user_details(from_user_id, from_user_type):
|
||||
"""
|
||||
used to get the basic details
|
||||
used to get from user details
|
||||
"""
|
||||
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 from_user, to_user
|
||||
from_user = None
|
||||
from_user_name = None
|
||||
from_user_image = None
|
||||
if from_user_id:
|
||||
if from_user_type == GUARDIAN:
|
||||
guardian = Guardian.objects.filter(user_id=from_user_id).select_related('user').first()
|
||||
from_user = guardian.user
|
||||
from_user_name = get_user_full_name(from_user)
|
||||
from_user_image = guardian.image
|
||||
elif from_user_type == JUNIOR:
|
||||
junior = Junior.objects.filter(auth_id=from_user_id).select_related('auth').first()
|
||||
from_user = junior.auth
|
||||
from_user_name = get_user_full_name(from_user)
|
||||
from_user_image = junior.image
|
||||
return from_user_name, from_user_image, from_user
|
||||
|
||||
|
||||
def get_notification_data(notification_type, from_user, to_user, extra_data):
|
||||
def get_notification_data(notification_type, from_user_id, from_user_type, to_user_id, extra_data):
|
||||
"""
|
||||
get notification and push data
|
||||
:param from_user_type: GUARDIAN or JUNIOR
|
||||
:param notification_type: notification_type
|
||||
:param from_user: from_user obj
|
||||
:param to_user: to_user obj
|
||||
:param from_user_id: from_user obj
|
||||
:param to_user_id: to_user obj
|
||||
:param extra_data: any extra data provided
|
||||
:return: notification and push data
|
||||
"""
|
||||
push_data = NOTIFICATION_DICT[notification_type].copy()
|
||||
notification_data = push_data.copy()
|
||||
notification_data['to_user'] = get_user_full_name(to_user)
|
||||
if from_user:
|
||||
from_user_name = get_user_full_name(from_user)
|
||||
push_data['body'] = push_data['body'].format(from_user=from_user_name)
|
||||
notification_data['body'] = notification_data['body'].format(from_user=from_user_name)
|
||||
notification_data['from_user'] = from_user_name
|
||||
task_name = None
|
||||
points = extra_data.get('points', None)
|
||||
if 'task_id' in extra_data:
|
||||
task = JuniorTask.objects.filter(id=extra_data.get('task_id')).first()
|
||||
task_name = task.task_name
|
||||
extra_data['task_name'] = task_name
|
||||
extra_data['task_image'] = task.image if task.image else task.default_image
|
||||
|
||||
from_user_name, from_user_image, from_user = get_from_user_details(from_user_id, from_user_type)
|
||||
|
||||
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
|
||||
|
||||
notification_data.update(extra_data)
|
||||
|
||||
return notification_data, push_data
|
||||
to_user = User.objects.filter(id=to_user_id).first()
|
||||
return notification_data, push_data, from_user, to_user
|
||||
|
||||
|
||||
def send_notification(notification_type, from_user, to_user, extra_data):
|
||||
@shared_task()
|
||||
def send_notification(notification_type, from_user_id, from_user_type, to_user_id, extra_data):
|
||||
"""
|
||||
used to send the push for the given notification type
|
||||
"""
|
||||
# (from_user, to_user) = get_basic_detail(from_user_id, to_user_id)
|
||||
notification_data, push_data = get_notification_data(notification_type, from_user, to_user, extra_data)
|
||||
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_data.update({'badge': Notification.objects.filter(notification_to=to_user, is_read=False).count()})
|
||||
Notification.objects.create(notification_type=notification_type, notification_from=from_user,
|
||||
notification_to=to_user, data=notification_data)
|
||||
if user_notification_type.push_notification:
|
||||
if user_notification_type and user_notification_type.push_notification:
|
||||
send_push(to_user, push_data)
|
||||
|
||||
|
||||
@ -95,6 +118,39 @@ def send_push(user, data):
|
||||
)
|
||||
|
||||
|
||||
def send_multiple_push(queryset, data):
|
||||
""" used to send same notification to multiple users """
|
||||
FCMDevice.objects.filter(user__in=queryset, active=True).send_message(
|
||||
Message(notification=FirebaseNotification(data['title'], data['body']), data=data)
|
||||
)
|
||||
|
||||
|
||||
@shared_task()
|
||||
def send_notification_multiple_user(notification_type, from_user_id, from_user_type,
|
||||
extra_data: dict = {}):
|
||||
"""
|
||||
used to send notification to multiple user for the given notification type
|
||||
"""
|
||||
to_user_list = User.objects.filter(junior_profile__is_verified=True, is_superuser=False
|
||||
).exclude(junior_profile__isnull=True, guardian_profile__isnull=True)
|
||||
|
||||
notification_data, push_data, from_user, _ = get_notification_data(notification_type, from_user_id,
|
||||
from_user_type, None, extra_data)
|
||||
|
||||
notification_list = []
|
||||
for user in to_user_list:
|
||||
notification_copy_data = notification_data.copy()
|
||||
notification_copy_data.update(
|
||||
{'badge': Notification.objects.filter(notification_to=user, is_read=False).count()})
|
||||
notification_list.append(Notification(notification_type=notification_type,
|
||||
notification_to=user,
|
||||
notification_from=from_user,
|
||||
data=notification_copy_data))
|
||||
Notification.objects.bulk_create(notification_list)
|
||||
to_user_list = to_user_list.filter(user_notification__push_notification=True)
|
||||
send_multiple_push(to_user_list, push_data)
|
||||
|
||||
|
||||
@shared_task()
|
||||
def send_notification_to_guardian(notification_type, from_user_id, to_user_id, extra_data):
|
||||
"""
|
||||
@ -104,14 +160,10 @@ def send_notification_to_guardian(notification_type, from_user_id, to_user_id, e
|
||||
:param extra_data:
|
||||
:return:
|
||||
"""
|
||||
from_user = None
|
||||
if from_user_id:
|
||||
from_user = Junior.objects.filter(auth_id=from_user_id).select_related('auth').first()
|
||||
from_user = Junior.objects.filter(auth_id=from_user_id).first()
|
||||
extra_data['from_user_image'] = from_user.image
|
||||
from_user = from_user.auth
|
||||
to_user = Guardian.objects.filter(user_id=to_user_id).select_related('user').first()
|
||||
extra_data['to_user_image'] = to_user.image
|
||||
send_notification(notification_type, from_user, to_user.user, extra_data)
|
||||
send_notification(notification_type, from_user_id, to_user_id, extra_data)
|
||||
|
||||
|
||||
@shared_task()
|
||||
@ -123,13 +175,7 @@ def send_notification_to_junior(notification_type, from_user_id, to_user_id, ext
|
||||
:param extra_data:
|
||||
:return:
|
||||
"""
|
||||
from_user = None
|
||||
if from_user_id:
|
||||
from_user = Guardian.objects.filter(user_id=from_user_id).select_related('user').first()
|
||||
from_user = Guardian.objects.filter(user_id=from_user_id).first()
|
||||
extra_data['from_user_image'] = from_user.image
|
||||
from_user = from_user.user
|
||||
to_user = Junior.objects.filter(auth_id=to_user_id).select_related('auth').first()
|
||||
extra_data['to_user_image'] = to_user.image
|
||||
send_notification(notification_type, from_user, to_user.auth, extra_data)
|
||||
|
||||
|
||||
send_notification(notification_type, from_user_id, to_user_id, extra_data)
|
||||
|
||||
@ -4,33 +4,39 @@ notifications views file
|
||||
# django imports
|
||||
from django.db.models import Q
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.permissions import IsAuthenticated, AllowAny
|
||||
from rest_framework.response import Response
|
||||
from rest_framework import viewsets, status, views
|
||||
|
||||
# local imports
|
||||
from account.utils import custom_response, custom_error_response
|
||||
from base.messages import SUCCESS_CODE, ERROR_CODE
|
||||
from base.tasks import notify_task_expiry, notify_top_junior
|
||||
from notifications.constants import TEST_NOTIFICATION
|
||||
# Import serializer
|
||||
from notifications.serializers import RegisterDevice, NotificationListSerializer, ReadNotificationSerializer
|
||||
from notifications.utils import send_notification, send_notification_to_guardian, send_notification_to_junior
|
||||
# Import model
|
||||
from notifications.utils import send_notification
|
||||
from notifications.models import Notification
|
||||
|
||||
|
||||
class NotificationViewSet(viewsets.GenericViewSet):
|
||||
""" used to do the notification actions """
|
||||
"""
|
||||
used to do the notification actions
|
||||
"""
|
||||
serializer_class = NotificationListSerializer
|
||||
permission_classes = [IsAuthenticated, ]
|
||||
|
||||
def list(self, request, *args, **kwargs) -> Response:
|
||||
""" list the notifications """
|
||||
"""
|
||||
to list user's notifications
|
||||
:param request:
|
||||
:return:
|
||||
"""
|
||||
queryset = Notification.objects.filter(notification_to_id=request.auth.payload['user_id']
|
||||
).select_related('notification_to').order_by('-id')
|
||||
paginator = self.pagination_class()
|
||||
paginated_queryset = paginator.paginate_queryset(queryset, request)
|
||||
serializer = self.serializer_class(paginated_queryset, many=True)
|
||||
return custom_response(None, serializer.data)
|
||||
return custom_response(None, serializer.data, count=queryset.count())
|
||||
|
||||
@action(methods=['post'], detail=False, url_path='device', url_name='device', serializer_class=RegisterDevice)
|
||||
def fcm_registration(self, request):
|
||||
@ -46,13 +52,13 @@ class NotificationViewSet(viewsets.GenericViewSet):
|
||||
@action(methods=['get'], detail=False, url_path='test', url_name='test')
|
||||
def send_test_notification(self, request):
|
||||
"""
|
||||
to send test notification
|
||||
to test send notification, task expiry, top junior
|
||||
:return:
|
||||
"""
|
||||
send_notification_to_guardian.delay(TEST_NOTIFICATION, None, request.auth.payload['user_id'],
|
||||
{'task_id': None})
|
||||
send_notification_to_junior.delay(TEST_NOTIFICATION, None, request.auth.payload['user_id'],
|
||||
{'task_id': None})
|
||||
notify_task_expiry()
|
||||
notify_top_junior()
|
||||
send_notification(TEST_NOTIFICATION, None, None, request.auth.payload['user_id'],
|
||||
{})
|
||||
return custom_response(SUCCESS_CODE["3000"])
|
||||
|
||||
@action(methods=['patch'], url_path='mark-as-read', url_name='mark-as-read', detail=False,
|
||||
|
||||
@ -7,8 +7,9 @@ from rest_framework import serializers
|
||||
# django imports
|
||||
from django.contrib.auth import get_user_model
|
||||
|
||||
from account.utils import get_user_full_name
|
||||
# local imports
|
||||
from base.constants import USER_TYPE
|
||||
from base.constants import USER_TYPE, JUNIOR
|
||||
|
||||
from junior.models import JuniorPoints, Junior
|
||||
|
||||
@ -36,7 +37,7 @@ class JuniorLeaderboardSerializer(serializers.ModelSerializer):
|
||||
:param obj: junior object
|
||||
:return: full name
|
||||
"""
|
||||
return f"{obj.auth.first_name} {obj.auth.last_name}" if obj.auth.last_name else obj.auth.first_name
|
||||
return get_user_full_name(obj.auth)
|
||||
|
||||
@staticmethod
|
||||
def get_first_name(obj):
|
||||
@ -59,6 +60,8 @@ class LeaderboardSerializer(serializers.ModelSerializer):
|
||||
"""
|
||||
leaderboard serializer
|
||||
"""
|
||||
user_id = serializers.SerializerMethodField()
|
||||
user_type = serializers.SerializerMethodField()
|
||||
junior = JuniorLeaderboardSerializer()
|
||||
rank = serializers.IntegerField()
|
||||
|
||||
@ -67,13 +70,22 @@ class LeaderboardSerializer(serializers.ModelSerializer):
|
||||
meta class
|
||||
"""
|
||||
model = JuniorPoints
|
||||
fields = ('total_points', 'rank', 'junior')
|
||||
fields = ('user_id', 'user_type', 'total_points', 'rank', 'junior')
|
||||
|
||||
@staticmethod
|
||||
def get_user_id(obj):
|
||||
return obj.junior.auth.id
|
||||
|
||||
@staticmethod
|
||||
def get_user_type(obj):
|
||||
return JUNIOR
|
||||
|
||||
|
||||
class UserCSVReportSerializer(serializers.ModelSerializer):
|
||||
"""
|
||||
user csv/xls report serializer
|
||||
"""
|
||||
name = serializers.SerializerMethodField()
|
||||
phone_number = serializers.SerializerMethodField()
|
||||
user_type = serializers.SerializerMethodField()
|
||||
is_active = serializers.SerializerMethodField()
|
||||
@ -84,7 +96,15 @@ class UserCSVReportSerializer(serializers.ModelSerializer):
|
||||
meta class
|
||||
"""
|
||||
model = USER
|
||||
fields = ('first_name', 'last_name', 'email', 'phone_number', 'user_type', 'is_active', 'date_joined')
|
||||
fields = ('name', 'email', 'phone_number', 'user_type', 'is_active', 'date_joined')
|
||||
|
||||
@staticmethod
|
||||
def get_name(obj):
|
||||
"""
|
||||
:param obj: user object
|
||||
:return: full name
|
||||
"""
|
||||
return get_user_full_name(obj)
|
||||
|
||||
@staticmethod
|
||||
def get_phone_number(obj):
|
||||
|
||||
@ -10,6 +10,8 @@ from base.constants import (ARTICLE_SURVEY_POINTS, MAX_ARTICLE_CARD, MIN_ARTICLE
|
||||
# local imports
|
||||
from base.messages import ERROR_CODE
|
||||
from guardian.utils import upload_image_to_alibaba
|
||||
from notifications.constants import NEW_ARTICLE_PUBLISHED
|
||||
from notifications.utils import send_notification_multiple_user
|
||||
from web_admin.models import Article, ArticleCard, SurveyOption, ArticleSurvey, DefaultArticleCardImage
|
||||
from web_admin.utils import pop_id, get_image_url
|
||||
from junior.models import JuniorArticlePoints, JuniorArticle
|
||||
@ -119,11 +121,15 @@ class ArticleSerializer(serializers.ModelSerializer):
|
||||
option = pop_id(option)
|
||||
SurveyOption.objects.create(survey=survey_obj, **option)
|
||||
|
||||
# All juniors will receive notification when admin add any new financial learnings/article
|
||||
send_notification_multiple_user.delay(NEW_ARTICLE_PUBLISHED, None, None, {})
|
||||
|
||||
return article
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
"""
|
||||
to update article and related table
|
||||
:param validated_data:
|
||||
:param instance: article object,
|
||||
:return: article object
|
||||
"""
|
||||
|
||||
@ -14,7 +14,7 @@ from account.models import UserEmailOtp
|
||||
from base.constants import USER_TYPE
|
||||
from base.messages import ERROR_CODE
|
||||
from guardian.tasks import generate_otp
|
||||
from base.tasks import send_email_otp
|
||||
from base.tasks import send_email
|
||||
|
||||
USER = get_user_model()
|
||||
|
||||
@ -48,11 +48,13 @@ class AdminOTPSerializer(serializers.ModelSerializer):
|
||||
:return: user_data
|
||||
"""
|
||||
email = validated_data['email']
|
||||
|
||||
verification_code = generate_otp()
|
||||
|
||||
template = 'email_reset_verification.email'
|
||||
# Send the verification code to the user's email
|
||||
send_email_otp.delay(email, verification_code)
|
||||
data = {
|
||||
"verification_code": verification_code
|
||||
}
|
||||
send_email.delay([email], template, data)
|
||||
|
||||
expiry = timezone.now() + timezone.timedelta(days=1)
|
||||
user_data, created = UserEmailOtp.objects.update_or_create(email=email,
|
||||
|
||||
@ -5,6 +5,7 @@ web_admin user_management serializers file
|
||||
from rest_framework import serializers
|
||||
from django.contrib.auth import get_user_model
|
||||
|
||||
from account.utils import get_user_full_name
|
||||
from base.constants import USER_TYPE, GUARDIAN, JUNIOR
|
||||
# local imports
|
||||
from base.messages import ERROR_CODE, SUCCESS_CODE
|
||||
@ -37,7 +38,7 @@ class UserManagementListSerializer(serializers.ModelSerializer):
|
||||
:param obj: user object
|
||||
:return: full name
|
||||
"""
|
||||
return f"{obj.first_name} {obj.last_name}" if obj.last_name else obj.first_name
|
||||
return get_user_full_name(obj)
|
||||
|
||||
@staticmethod
|
||||
def get_country_code(obj):
|
||||
@ -144,7 +145,7 @@ class GuardianSerializer(serializers.ModelSerializer):
|
||||
:param obj: guardian object
|
||||
:return: full name
|
||||
"""
|
||||
return f"{obj.user.first_name} {obj.user.last_name}" if obj.user.last_name else obj.user.first_name
|
||||
return get_user_full_name(obj.user)
|
||||
|
||||
@staticmethod
|
||||
def get_first_name(obj):
|
||||
@ -222,7 +223,7 @@ class JuniorSerializer(serializers.ModelSerializer):
|
||||
:param obj: junior object
|
||||
:return: full name
|
||||
"""
|
||||
return f"{obj.auth.first_name} {obj.auth.last_name}" if obj.auth.last_name else obj.auth.first_name
|
||||
return get_user_full_name(obj.auth)
|
||||
|
||||
@staticmethod
|
||||
def get_first_name(obj):
|
||||
|
||||
@ -22,7 +22,7 @@ from django.db.models.functions.window import Rank
|
||||
from django.http import HttpResponse
|
||||
|
||||
# local imports
|
||||
from account.utils import custom_response
|
||||
from account.utils import custom_response, get_user_full_name
|
||||
from base.constants import PENDING, IN_PROGRESS, REJECTED, REQUESTED, COMPLETED, EXPIRED, DATE_FORMAT, TASK_STATUS
|
||||
from guardian.models import JuniorTask
|
||||
from guardian.utils import upload_excel_file_to_alibaba
|
||||
@ -107,13 +107,15 @@ class AnalyticsViewSet(GenericViewSet):
|
||||
|
||||
assign_tasks = JuniorTask.objects.filter(
|
||||
created_at__range=[start_date, (end_date + datetime.timedelta(days=1))]
|
||||
).exclude(task_status__in=[PENDING, EXPIRED])
|
||||
)
|
||||
|
||||
data = {
|
||||
'task_completed': assign_tasks.filter(task_status=COMPLETED).count(),
|
||||
'task_pending': assign_tasks.filter(task_status=PENDING).count(),
|
||||
'task_in_progress': assign_tasks.filter(task_status=IN_PROGRESS).count(),
|
||||
'task_requested': assign_tasks.filter(task_status=REQUESTED).count(),
|
||||
'task_rejected': assign_tasks.filter(task_status=REJECTED).count(),
|
||||
'task_expired': assign_tasks.filter(task_status=EXPIRED).count(),
|
||||
}
|
||||
|
||||
return custom_response(None, data)
|
||||
@ -126,10 +128,12 @@ class AnalyticsViewSet(GenericViewSet):
|
||||
:param request:
|
||||
:return:
|
||||
"""
|
||||
queryset = JuniorPoints.objects.prefetch_related('junior', 'junior__auth').annotate(rank=Window(
|
||||
expression=Rank(),
|
||||
order_by=[F('total_points').desc(), 'junior__created_at']
|
||||
)).order_by('-total_points', 'junior__created_at')
|
||||
queryset = JuniorPoints.objects.filter(
|
||||
junior__is_verified=True
|
||||
).select_related('junior', 'junior__auth').annotate(rank=Window(
|
||||
expression=Rank(),
|
||||
order_by=[F('total_points').desc(), 'junior__created_at']
|
||||
)).order_by('-total_points', 'junior__created_at')
|
||||
paginator = CustomPageNumberPagination()
|
||||
paginated_queryset = paginator.paginate_queryset(queryset, request)
|
||||
serializer = self.serializer_class(paginated_queryset, many=True)
|
||||
@ -169,10 +173,9 @@ class AnalyticsViewSet(GenericViewSet):
|
||||
serializer = UserCSVReportSerializer(queryset, many=True)
|
||||
|
||||
df_users = pd.DataFrame([
|
||||
{'Name': f"{user['first_name']} {user['last_name']}",
|
||||
'Email': user['email'], 'Phone Number': user['phone_number'],
|
||||
'User Type': user['user_type'], 'Status': user['is_active'],
|
||||
'Date Joined': user['date_joined']}
|
||||
{'Name': user['name'], 'Email': user['email'],
|
||||
'Phone Number': user['phone_number'], 'User Type': user['user_type'],
|
||||
'Status': user['is_active'], 'Date Joined': user['date_joined']}
|
||||
for user in serializer.data
|
||||
])
|
||||
write_excel_worksheet(worksheet, df_users)
|
||||
@ -181,10 +184,16 @@ class AnalyticsViewSet(GenericViewSet):
|
||||
elif sheet_name == 'Assign Tasks':
|
||||
assign_tasks = JuniorTask.objects.filter(
|
||||
created_at__range=[start_date, (end_date + datetime.timedelta(days=1))]
|
||||
).exclude(task_status__in=[PENDING, EXPIRED])
|
||||
).select_related('junior__auth', 'guardian__user').only('task_name', 'task_status',
|
||||
'junior__auth__first_name',
|
||||
'junior__auth__last_name',
|
||||
'guardian__user__first_name',
|
||||
'guardian__user__last_name',)
|
||||
|
||||
df_tasks = pd.DataFrame([
|
||||
{'Task Name': task.task_name, 'Task Status': dict(TASK_STATUS).get(task.task_status).capitalize()}
|
||||
{'Task Name': task.task_name, 'Assign To': get_user_full_name(task.junior.auth),
|
||||
'Assign By': get_user_full_name(task.guardian.user),
|
||||
'Task Status': dict(TASK_STATUS).get(task.task_status).capitalize()}
|
||||
for task in assign_tasks
|
||||
])
|
||||
|
||||
@ -192,14 +201,15 @@ class AnalyticsViewSet(GenericViewSet):
|
||||
|
||||
# sheet 3 for Juniors Leaderboard and rank
|
||||
elif sheet_name == 'Juniors Leaderboard':
|
||||
queryset = JuniorPoints.objects.prefetch_related('junior', 'junior__auth').annotate(rank=Window(
|
||||
expression=Rank(),
|
||||
order_by=[F('total_points').desc(), 'junior__created_at']
|
||||
)).order_by('-total_points', 'junior__created_at')[:15]
|
||||
queryset = JuniorPoints.objects.filter(
|
||||
junior__is_verified=True
|
||||
).select_related('junior', 'junior__auth').annotate(rank=Window(
|
||||
expression=Rank(),
|
||||
order_by=[F('total_points').desc(), 'junior__created_at']
|
||||
)).order_by('-total_points', 'junior__created_at')[:15]
|
||||
df_leaderboard = pd.DataFrame([
|
||||
{
|
||||
'Junior Name': f"{junior.junior.auth.first_name} {junior.junior.auth.last_name}"
|
||||
if junior.junior.auth.last_name else junior.junior.auth.first_name,
|
||||
'Name': get_user_full_name(junior.junior.auth),
|
||||
'Points': junior.total_points,
|
||||
'Rank': junior.rank
|
||||
}
|
||||
|
||||
@ -12,8 +12,9 @@ from django.db.models import Q
|
||||
|
||||
# local imports
|
||||
from account.utils import custom_response, custom_error_response
|
||||
from base.constants import USER_TYPE
|
||||
from base.constants import USER_TYPE, GUARDIAN, JUNIOR
|
||||
from base.messages import SUCCESS_CODE, ERROR_CODE
|
||||
from base.tasks import send_email
|
||||
from guardian.models import Guardian
|
||||
from junior.models import Junior
|
||||
from web_admin.permission import AdminPermission
|
||||
@ -92,12 +93,14 @@ class UserManagementViewSet(GenericViewSet, mixins.ListModelMixin,
|
||||
if self.request.query_params.get('user_type') not in [dict(USER_TYPE).get('1'), dict(USER_TYPE).get('2')]:
|
||||
return custom_error_response(ERROR_CODE['2067'], status.HTTP_400_BAD_REQUEST)
|
||||
if self.request.query_params.get('user_type') == dict(USER_TYPE).get('2'):
|
||||
guardian = Guardian.objects.filter(user_id=kwargs['pk'], is_verified=True).first()
|
||||
guardian = Guardian.objects.filter(user_id=kwargs['pk'], is_verified=True
|
||||
).select_related('user').first()
|
||||
serializer = GuardianSerializer(guardian,
|
||||
request.data, context={'user_id': kwargs['pk']})
|
||||
|
||||
elif self.request.query_params.get('user_type') == dict(USER_TYPE).get('1'):
|
||||
junior = Junior.objects.filter(auth_id=kwargs['pk'], is_verified=True).select_related('auth').first()
|
||||
junior = Junior.objects.filter(auth_id=kwargs['pk'], is_verified=True
|
||||
).select_related('auth').first()
|
||||
serializer = JuniorSerializer(junior,
|
||||
request.data, context={'user_id': kwargs['pk']})
|
||||
|
||||
@ -113,17 +116,21 @@ class UserManagementViewSet(GenericViewSet, mixins.ListModelMixin,
|
||||
user_type {'guardian' for Guardian, 'junior' for Junior} mandatory
|
||||
:return: success message
|
||||
"""
|
||||
if self.request.query_params.get('user_type') not in [dict(USER_TYPE).get('1'), dict(USER_TYPE).get('2')]:
|
||||
user_type = self.request.query_params.get('user_type')
|
||||
if user_type not in [GUARDIAN, JUNIOR]:
|
||||
return custom_error_response(ERROR_CODE['2067'], status.HTTP_400_BAD_REQUEST)
|
||||
queryset = self.queryset
|
||||
if self.request.query_params.get('user_type') == dict(USER_TYPE).get('2'):
|
||||
user_obj = queryset.filter(id=kwargs['pk']).first()
|
||||
obj = user_obj.guardian_profile.all().first()
|
||||
obj.is_active = False if obj.is_active else True
|
||||
obj.save()
|
||||
elif self.request.query_params.get('user_type') == dict(USER_TYPE).get('1'):
|
||||
user_obj = queryset.filter(id=kwargs['pk']).first()
|
||||
obj = user_obj.junior_profile.all().first()
|
||||
obj.is_active = False if obj.is_active else True
|
||||
obj.save()
|
||||
|
||||
email_template = 'user_deactivate.email'
|
||||
|
||||
if user_type == GUARDIAN:
|
||||
obj = Guardian.objects.filter(user_id=kwargs['pk'], is_verified=True).select_related('user').first()
|
||||
elif user_type == JUNIOR:
|
||||
obj = Junior.objects.filter(auth_id=kwargs['pk'], is_verified=True).select_related('auth').first()
|
||||
|
||||
if obj.is_active:
|
||||
obj.is_active = False
|
||||
send_email([obj.user.email if user_type == GUARDIAN else obj.auth.email], email_template)
|
||||
else:
|
||||
obj.is_active = True
|
||||
obj.save()
|
||||
return custom_response(SUCCESS_CODE['3038'])
|
||||
|
||||
@ -27,19 +27,24 @@ app.config_from_object('django.conf:settings')
|
||||
# Load task modules from all registered Django apps.
|
||||
app.autodiscover_tasks()
|
||||
|
||||
# scheduled task
|
||||
app.conf.beat_schedule = {
|
||||
"expired_task": {
|
||||
"task": "guardian.utils.update_expired_task_status",
|
||||
"schedule": crontab(minute=0, hour=0),
|
||||
},
|
||||
'notify_task_expiry': {
|
||||
'task': 'base.tasks.notify_task_expiry',
|
||||
'schedule': crontab(minute='0', hour='18'),
|
||||
},
|
||||
'notify_top_junior': {
|
||||
'task': 'base.tasks.notify_top_junior',
|
||||
'schedule': crontab(minute='0', hour='*/2'),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@app.task(bind=True)
|
||||
def debug_task(self):
|
||||
""" celery debug task """
|
||||
print(f'Request: {self.request!r}')
|
||||
|
||||
|
||||
"""cron task"""
|
||||
|
||||
|
||||
app.conf.beat_schedule = {
|
||||
"expired_task": {
|
||||
"task": "guardian.utils.update_expired_task_status",
|
||||
"schedule": crontab(minute=0, hour=0),
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user