mirror of
https://github.com/HamzaSha1/zod-backend.git
synced 2025-08-25 13:49:40 +00:00
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 %}
|
@ -9,36 +9,20 @@ 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 notifications.constants import PENDING_TASK_EXPIRING, IN_PROGRESS_TASK_EXPIRING
|
||||
from notifications.utils import send_notification
|
||||
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):
|
||||
"""
|
||||
used to send otp on email
|
||||
:param email: e-mail
|
||||
:param verification_code: otp
|
||||
"""
|
||||
from_email = settings.EMAIL_FROM_ADDRESS
|
||||
recipient_list = [email]
|
||||
send_templated_mail(
|
||||
template_name='email_reset_verification.email',
|
||||
from_email=from_email,
|
||||
recipient_list=recipient_list,
|
||||
context={
|
||||
'verification_code': verification_code
|
||||
}
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
@shared_task
|
||||
def send_mail(recipient_list, template, context: dict = None):
|
||||
def send_email(recipient_list, template, context: dict = None):
|
||||
"""
|
||||
used to send otp on email
|
||||
:param context:
|
||||
@ -48,7 +32,6 @@ def send_mail(recipient_list, template, context: dict = None):
|
||||
if context is None:
|
||||
context = {}
|
||||
from_email = settings.EMAIL_FROM_ADDRESS
|
||||
recipient_list = recipient_list
|
||||
send_templated_mail(
|
||||
template_name=template,
|
||||
from_email=from_email,
|
||||
@ -77,3 +60,26 @@ def notify_task_expiry():
|
||||
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.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')
|
||||
|
||||
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:
|
||||
to_user_list = [junior_point.junior.auth for junior_point in junior_points_qs]
|
||||
send_notification_multiple_user(TOP_JUNIOR, new_top_position.junior.auth.id, JUNIOR,
|
||||
to_user_list, {'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.
@ -316,10 +316,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"""
|
||||
@ -329,9 +330,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"""
|
||||
|
@ -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
|
||||
@ -242,7 +244,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 +254,18 @@ class TopJuniorListAPIView(viewsets.ModelViewSet):
|
||||
context.update({'view': self})
|
||||
return context
|
||||
|
||||
def get_queryset(self):
|
||||
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')
|
||||
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)
|
||||
|
@ -19,7 +19,7 @@ from base.constants import (PENDING, IN_PROGRESS, REJECTED, REQUESTED, COMPLETED
|
||||
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
|
||||
from notifications.constants import (ASSOCIATE_REQUEST, JUNIOR_ADDED, TASK_ACTION,
|
||||
@ -185,9 +185,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:
|
||||
@ -365,10 +364,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()
|
||||
|
@ -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,19 @@ 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.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')
|
||||
|
||||
junior = next((query for query in queryset if query.junior == junior_obj), None)
|
||||
|
||||
return junior.rank if junior else None
|
||||
|
@ -142,7 +142,7 @@ 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:
|
||||
@ -417,7 +417,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)
|
||||
|
@ -14,6 +14,9 @@ TASK_REJECTED = 10
|
||||
TASK_APPROVED = 11
|
||||
PENDING_TASK_EXPIRING = 12
|
||||
IN_PROGRESS_TASK_EXPIRING = 13
|
||||
|
||||
TOP_JUNIOR = 14
|
||||
|
||||
REMOVE_JUNIOR = 15
|
||||
|
||||
TEST_NOTIFICATION = 99
|
||||
@ -23,38 +26,44 @@ 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
|
||||
# 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
|
||||
# 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
|
||||
# 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
|
||||
# Juniors will receive notification
|
||||
# once any custodians add them in their account
|
||||
JUNIOR_ADDED: {
|
||||
"title": "Profile already setup!",
|
||||
"body": "Your guardian has already setup your profile."
|
||||
},
|
||||
# Juniors will receive Notification for every Task Assign by Custodians
|
||||
# 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": "{from_user} completed her task {task_name}."
|
||||
@ -83,6 +92,11 @@ NOTIFICATION_DICT = {
|
||||
"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 as soon as their custodians remove them from account
|
||||
REMOVE_JUNIOR: {
|
||||
"title": "Disassociate by guardian!",
|
||||
|
@ -115,6 +115,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,
|
||||
to_user_list: list = [], extra_data: dict = {}):
|
||||
"""
|
||||
used to send notification to multiple user for the given notification type
|
||||
"""
|
||||
push_data = NOTIFICATION_DICT[notification_type].copy()
|
||||
notification_data = push_data.copy()
|
||||
points = extra_data.get('points', None)
|
||||
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, points=points)
|
||||
notification_data['body'] = notification_data['body'].format(from_user=from_user_name,
|
||||
points=points)
|
||||
notification_data['from_user'] = from_user_name
|
||||
notification_data['from_user_image'] = from_user_image
|
||||
notification_list = []
|
||||
for user in to_user_list:
|
||||
notification_list.append(Notification(notification_type=notification_type,
|
||||
notification_to=user,
|
||||
notification_from=from_user,
|
||||
data=notification_data))
|
||||
Notification.objects.bulk_create(notification_list)
|
||||
|
||||
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):
|
||||
"""
|
||||
|
@ -11,7 +11,7 @@ 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
|
||||
from base.tasks import notify_task_expiry, notify_top_junior
|
||||
from notifications.constants import TEST_NOTIFICATION
|
||||
from notifications.serializers import RegisterDevice, NotificationListSerializer, ReadNotificationSerializer
|
||||
from notifications.utils import send_notification
|
||||
@ -74,5 +74,5 @@ class NotificationViewSet(viewsets.GenericViewSet):
|
||||
"""
|
||||
notification list
|
||||
"""
|
||||
notify_task_expiry()
|
||||
notify_top_junior()
|
||||
return custom_response(SUCCESS_CODE['3039'], response_status=status.HTTP_200_OK)
|
||||
|
@ -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_mail
|
||||
from base.tasks import send_email
|
||||
|
||||
USER = get_user_model()
|
||||
|
||||
@ -54,7 +54,7 @@ class AdminOTPSerializer(serializers.ModelSerializer):
|
||||
data = {
|
||||
"verification_code": verification_code
|
||||
}
|
||||
send_mail.delay([email], template, data)
|
||||
send_email.delay([email], template, data)
|
||||
|
||||
expiry = timezone.now() + timezone.timedelta(days=1)
|
||||
user_data, created = UserEmailOtp.objects.update_or_create(email=email,
|
||||
|
@ -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'])
|
||||
|
@ -28,8 +28,16 @@ app.config_from_object('django.conf:settings')
|
||||
app.autodiscover_tasks()
|
||||
|
||||
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='13'),
|
||||
},
|
||||
'notify_top_junior': {
|
||||
'task': 'base.tasks.notify_top_junior',
|
||||
'schedule': crontab(minute='0', hour='*/1'),
|
||||
},
|
||||
}
|
||||
@ -39,14 +47,3 @@ app.conf.beat_schedule = {
|
||||
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