diff --git a/base/tasks.py b/base/tasks.py index 65dff3b..fbeca1d 100644 --- a/base/tasks.py +++ b/base/tasks.py @@ -68,10 +68,14 @@ def notify_top_junior(): task to send notification for top leaderboard junior to all junior's :return: """ - junior_points_qs = JuniorPoints.objects.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_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() diff --git a/celerybeat-schedule b/celerybeat-schedule index 4c54db2..f457bb5 100644 Binary files a/celerybeat-schedule and b/celerybeat-schedule differ diff --git a/guardian/views.py b/guardian/views.py index e5b984a..e120681 100644 --- a/guardian/views.py +++ b/guardian/views.py @@ -259,10 +259,14 @@ class TopJuniorListAPIView(viewsets.ModelViewSet): return context def get_queryset(self): - queryset = JuniorPoints.objects.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') + 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): diff --git a/junior/serializers.py b/junior/serializers.py index d3d0b2f..de5f671 100644 --- a/junior/serializers.py +++ b/junior/serializers.py @@ -22,7 +22,7 @@ from account.models import UserEmailOtp, UserNotification 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, +from notifications.constants import (ASSOCIATE_REQUEST, ASSOCIATE_JUNIOR, TASK_ACTION, ) from web_admin.models import ArticleCard @@ -323,7 +323,7 @@ class AddJuniorSerializer(serializers.ModelSerializer): """Notification email""" junior_notification_email.delay(email, full_name, email, password) # push notification - send_notification.delay(JUNIOR_ADDED, None, None, junior_data.auth.id, {}) + send_notification.delay(ASSOCIATE_JUNIOR, None, None, junior_data.auth.id, {}) return junior_data diff --git a/junior/utils.py b/junior/utils.py index 7533017..eac6ac9 100644 --- a/junior/utils.py +++ b/junior/utils.py @@ -70,10 +70,12 @@ def get_junior_leaderboard_rank(junior_obj): :param junior_obj: :return: junior's position/rank """ - queryset = JuniorPoints.objects.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') + 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) diff --git a/junior/views.py b/junior/views.py index 5d23894..5ca50e0 100644 --- a/junior/views.py +++ b/junior/views.py @@ -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 -from notifications.constants import REMOVE_JUNIOR, ARTICLE_REWARD_POINTS +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) @@ -232,6 +232,7 @@ class AddJuniorAPIView(viewsets.ModelViewSet): 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 diff --git a/notifications/constants.py b/notifications/constants.py index 503e0f2..85b0d2d 100644 --- a/notifications/constants.py +++ b/notifications/constants.py @@ -6,19 +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 -PENDING_TASK_EXPIRING = 12 -IN_PROGRESS_TASK_EXPIRING = 13 -TOP_JUNIOR = 14 +TASK_ASSIGNED = 9 +TASK_ACTION = 10 +TASK_REJECTED = 11 +TASK_APPROVED = 12 +PENDING_TASK_EXPIRING = 13 +IN_PROGRESS_TASK_EXPIRING = 14 +TOP_JUNIOR = 15 -NEW_ARTICLE_PUBLISHED = 15 -ARTICLE_REWARD_POINTS = 16 -REMOVE_JUNIOR = 17 +NEW_ARTICLE_PUBLISHED = 16 +ARTICLE_REWARD_POINTS = 17 +REMOVE_JUNIOR = 18 TEST_NOTIFICATION = 99 @@ -53,10 +54,14 @@ NOTIFICATION_DICT = { }, # Juniors will receive notification # once any custodians add them in their account - JUNIOR_ADDED: { + ASSOCIATE_JUNIOR: { "title": "Profile already setup!", "body": "Your guardian has already setup your profile." }, + 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: { diff --git a/notifications/utils.py b/notifications/utils.py index aad37c0..bd2a8bd 100644 --- a/notifications/utils.py +++ b/notifications/utils.py @@ -19,14 +19,13 @@ from junior.models import Junior from notifications.constants import NOTIFICATION_DICT from notifications.models import Notification - 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 @@ -93,7 +92,7 @@ def get_notification_data(notification_type, from_user_id, from_user_type, to_us notification_data['from_user_image'] = from_user_image notification_data.update(extra_data) - to_user = User.objects.get(id=to_user_id) + to_user = User.objects.filter(id=to_user_id).first() return notification_data, push_data, from_user, to_user @@ -135,21 +134,18 @@ def send_notification_multiple_user(notification_type, from_user_id, from_user_t to_user_list = User.objects.filter(junior_profile__is_verified=True, is_superuser=False ).exclude(junior_profile__isnull=True, guardian_profile__isnull=True) - 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_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_data)) + 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) @@ -183,5 +179,3 @@ def send_notification_to_junior(notification_type, from_user_id, to_user_id, ext from_user = Guardian.objects.filter(user_id=from_user_id).first() extra_data['from_user_image'] = from_user.image send_notification(notification_type, from_user_id, to_user_id, extra_data) - - diff --git a/notifications/views.py b/notifications/views.py index 670635a..812502e 100644 --- a/notifications/views.py +++ b/notifications/views.py @@ -52,9 +52,11 @@ 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: """ + notify_task_expiry() + notify_top_junior() send_notification(TEST_NOTIFICATION, None, None, request.auth.payload['user_id'], {}) return custom_response(SUCCESS_CODE["3000"]) @@ -67,12 +69,3 @@ class NotificationViewSet(viewsets.GenericViewSet): """ Notification.objects.filter(id__in=request.data.get('id')).update(is_read=True) return custom_response(SUCCESS_CODE['3039'], response_status=status.HTTP_200_OK) - - @action(methods=['get'], url_path='task', url_name='task', detail=False, - permission_classes=[AllowAny]) - def task(self, request, *args, **kwargs): - """ - notification list - """ - notify_top_junior() - return custom_response(SUCCESS_CODE['3039'], response_status=status.HTTP_200_OK) diff --git a/web_admin/serializers/analytics_serializer.py b/web_admin/serializers/analytics_serializer.py index b0177d7..7871615 100644 --- a/web_admin/serializers/analytics_serializer.py +++ b/web_admin/serializers/analytics_serializer.py @@ -9,7 +9,7 @@ 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 @@ -37,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): @@ -60,6 +60,8 @@ class LeaderboardSerializer(serializers.ModelSerializer): """ leaderboard serializer """ + user_id = serializers.SerializerMethodField() + user_type = serializers.SerializerMethodField() junior = JuniorLeaderboardSerializer() rank = serializers.IntegerField() @@ -68,7 +70,15 @@ 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): diff --git a/web_admin/views/analytics.py b/web_admin/views/analytics.py index 4a010a3..926cd47 100644 --- a/web_admin/views/analytics.py +++ b/web_admin/views/analytics.py @@ -128,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) @@ -199,10 +201,12 @@ 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([ { 'Name': get_user_full_name(junior.junior.auth),