From e2b8ed0fc407b4cc92558e4a7d2342507977f111 Mon Sep 17 00:00:00 2001 From: Muhammed Zafar Date: Thu, 30 Nov 2023 20:16:10 +0530 Subject: [PATCH 01/36] [FEAT] Discord like role management --- api/dashboard/roles/dash_roles_serializer.py | 53 ++++++- api/dashboard/roles/dash_roles_views.py | 144 +++++++++++++------ api/dashboard/roles/urls.py | 4 +- 3 files changed, 152 insertions(+), 49 deletions(-) diff --git a/api/dashboard/roles/dash_roles_serializer.py b/api/dashboard/roles/dash_roles_serializer.py index 580ab0b4..3bed622d 100644 --- a/api/dashboard/roles/dash_roles_serializer.py +++ b/api/dashboard/roles/dash_roles_serializer.py @@ -7,6 +7,46 @@ from utils.utils import DateTimeUtils +class UserRoleLinkManagementSerializer(serializers.ModelSerializer): + """ + Serializer used by UserRoleLinkManagement API to lists the + details of the user with a specific role + """ + + class Meta: + model = User + fields = ["id", "muid", "fullname"] + + +class RoleAssignmentSerializer(serializers.Serializer): + """ + Used by UserRoleLinkManagement to assign + a role to a large number of users + """ + + role = serializers.PrimaryKeyRelatedField(queryset=Role.objects.all()) + users = serializers.ListField(child=serializers.UUIDField()) + created_by = serializers.PrimaryKeyRelatedField(queryset=User.objects.all()) + + def validate_users(self, attrs): + attrs = set(attrs) + users = User.objects.filter(pk__in=attrs) + if users.count() != len(attrs): + raise serializers.ValidationError("One or more user IDs are invalid.") + else: + return users + + def create(self, validated_data): + users = validated_data.pop("users") + validated_data["created_at"] = DateTimeUtils.get_current_utc_time() + user_roles_to_create = [ + UserRoleLink(user=user, **validated_data) for user in users + ] + # TODO: Implement the user assigning in discord too + UserRoleLink.objects.bulk_create(user_roles_to_create) + return user_roles_to_create + + class RoleDashboardSerializer(serializers.ModelSerializer): updated_by = serializers.CharField(source="updated_by.fullname") created_by = serializers.CharField(source="created_by.fullname") @@ -49,8 +89,6 @@ def create(self, validated_data): return super().create(validated_data) - - class UserRoleSearchSerializer(serializers.ModelSerializer): class Meta: model = User @@ -58,9 +96,9 @@ class Meta: class UserRoleCreateSerializer(serializers.ModelSerializer): - user_id = serializers.CharField(required=True, source="user.id") role_id = serializers.CharField(required=True, source="role.id") + class Meta: model = UserRoleLink fields = ["user_id", "role_id"] @@ -80,11 +118,13 @@ def create(self, validated_data): validated_data["created_at"] = DateTimeUtils.get_current_utc_time() return super().create(validated_data) - + + class UserRoleBulkAssignSerializer(serializers.ModelSerializer): user_id = serializers.CharField(required=True) role_id = serializers.CharField(required=True) created_by_id = serializers.CharField(required=True, allow_null=False) + class Meta: model = UserRoleLink fields = [ @@ -99,7 +139,6 @@ class Meta: def to_representation(self, instance): representation = super().to_representation(instance) - representation['user_id'] = instance.user.fullname if instance.user else None - representation['role_id'] = instance.role.title if instance.role else None + representation["user_id"] = instance.user.fullname if instance.user else None + representation["role_id"] = instance.role.title if instance.role else None return representation - \ No newline at end of file diff --git a/api/dashboard/roles/dash_roles_views.py b/api/dashboard/roles/dash_roles_views.py index f8519ecd..80866c40 100644 --- a/api/dashboard/roles/dash_roles_views.py +++ b/api/dashboard/roles/dash_roles_views.py @@ -13,6 +13,8 @@ from tempfile import NamedTemporaryFile from io import BytesIO from django.http import FileResponse +from django.db.models import Q + class RoleAPI(APIView): authentication_classes = [CustomizePermission] @@ -156,6 +158,66 @@ def get(self, request, role_id): ).get_success_response() +class UserRoleLinkManagement(APIView): + authentication_classes = [CustomizePermission] + """ + This API is creates an interface to help manage the user and role link + by providing support for + - Listing all users with the given role + - Giving a lot of users a specific role + """ + + @role_required([RoleType.ADMIN.value]) + def get(self, request, role_id): + """ + Lists all the users with a given role + """ + users = ( + User.objects.filter(user_role_link_user__role__pk=role_id) + .distinct() + .all() + ) + serialized_users = dash_roles_serializer.UserRoleLinkManagementSerializer( + users, many=True + ) + return CustomResponse(response=serialized_users.data).get_success_response() + + @role_required([RoleType.ADMIN.value]) + def put(self, request, role_id): + """ + Lists all the users without a given role; + used to assign roles + """ + users = ( + User.objects.filter(~Q(user_role_link_user__role__pk=role_id)) + .distinct() + .all() + ) + serialized_users = dash_roles_serializer.UserRoleLinkManagementSerializer( + users, many=True + ) + return CustomResponse(response=serialized_users.data).get_success_response() + + @role_required([RoleType.ADMIN.value]) + def patch(self, request): + """ + Assigns a large bunch of users a certain role + """ + request_data = request.data.copy() + request_data[ + "created_by" + ] = JWTUtils.fetch_user_id(request) + serialized_users = dash_roles_serializer.RoleAssignmentSerializer( + data=request_data + ) + if serialized_users.is_valid(): + serialized_users.save() + return CustomResponse( + general_message="Successfully gave all users the requested role" + ).get_success_response() + return CustomResponse(response=serialized_users.errors).get_failure_response() + + class UserRole(APIView): authentication_classes = [CustomizePermission] @@ -208,36 +270,39 @@ def delete(self, request): general_message="User Role deleted successfully" ).get_success_response() + class RoleBaseTemplateAPI(APIView): authentication_classes = [CustomizePermission] def get(self, request): - wb = load_workbook('./api/dashboard/roles/assets/role_base_template.xlsx') - ws = wb['Data Definitions'] + wb = load_workbook("./api/dashboard/roles/assets/role_base_template.xlsx") + ws = wb["Data Definitions"] - roles = Role.objects.all().values_list('title', flat=True) - data = { - 'role': roles - } + roles = Role.objects.all().values_list("title", flat=True) + data = {"role": roles} # Write data column-wise for col_num, (col_name, col_values) in enumerate(data.items(), start=1): for row, value in enumerate(col_values, start=2): ws.cell(row=row, column=col_num, value=value) - + # Save the file with NamedTemporaryFile() as tmp: - tmp.close() # with statement opened tmp, close it so wb.save can open it + tmp.close() # with statement opened tmp, close it so wb.save can open it wb.save(tmp.name) - with open(tmp.name, 'rb') as f: + with open(tmp.name, "rb") as f: f.seek(0) new_file_object = f.read() - return FileResponse(BytesIO(new_file_object), as_attachment=True, filename='role_base_template.xlsx') - + return FileResponse( + BytesIO(new_file_object), + as_attachment=True, + filename="role_base_template.xlsx", + ) + + class UserRoleBulkAssignAPI(APIView): authentication_classes = [CustomizePermission] @role_required([RoleType.ADMIN.value]) - def post(self, request): try: file_obj = request.FILES["user_roles_list"] @@ -254,17 +319,14 @@ def post(self, request): general_message="Empty csv file." ).get_failure_response() - temp_headers = [ - "muid", - "role" - ] + temp_headers = ["muid", "role"] first_entry = excel_data[0] for key in temp_headers: if key not in first_entry: return CustomResponse( general_message=f"{key} does not exist in the file." ).get_failure_response() - + excel_data = [row for row in excel_data if any(row.values())] valid_rows = [] error_rows = [] @@ -276,7 +338,7 @@ def post(self, request): for row in excel_data[1:]: keys_to_keep = ["muid", "role"] row_keys = list(row.keys()) - + # Remove columns other than "muid" and "role" for key in row_keys: if key not in keys_to_keep: @@ -294,22 +356,19 @@ def post(self, request): else: user_role_link_to_check.add((user, role)) - users = User.objects.filter( - muid__in=users_to_fetch - ).values( - "id", - "muid", - ) - roles = Role.objects.filter( - title__in=roles_to_fetch - ).values( - "id", - "title", - ) - existing_user_role_links = list(UserRoleLink.objects.filter( - user__muid__in=users_to_fetch, - role__title__in=roles_to_fetch - ).values_list('user__muid', 'role__title')) + users = User.objects.filter(muid__in=users_to_fetch).values( + "id", + "muid", + ) + roles = Role.objects.filter(title__in=roles_to_fetch).values( + "id", + "title", + ) + existing_user_role_links = list( + UserRoleLink.objects.filter( + user__muid__in=users_to_fetch, role__title__in=roles_to_fetch + ).values_list("user__muid", "role__title") + ) users_dict = {user["muid"]: user["id"] for user in users} roles_dict = {role["title"]: role["id"] for role in roles} @@ -317,7 +376,7 @@ def post(self, request): user = row.pop("muid") role = row.pop("role") - user_id = users_dict.get(user) + user_id = users_dict.get(user) role_id = roles_dict.get(role) if not user_id: @@ -344,19 +403,22 @@ def post(self, request): row["created_by_id"] = request_user_id valid_rows.append(row) - user_roles_serializer = dash_roles_serializer.UserRoleBulkAssignSerializer(data=valid_rows, many=True) + user_roles_serializer = dash_roles_serializer.UserRoleBulkAssignSerializer( + data=valid_rows, many=True + ) success_data = [] if user_roles_serializer.is_valid(): user_roles_serializer.save() for user_role_data in user_roles_serializer.data: - success_data.append({ - 'user': user_role_data.get('user_id', ''), - 'role': user_role_data.get('role_id', ''), - }) + success_data.append( + { + "user": user_role_data.get("user_id", ""), + "role": user_role_data.get("role_id", ""), + } + ) else: error_rows.append(user_roles_serializer.errors) return CustomResponse( response={"Success": success_data, "Failed": error_rows} ).get_success_response() - diff --git a/api/dashboard/roles/urls.py b/api/dashboard/roles/urls.py index dc0790a9..2b90f8aa 100644 --- a/api/dashboard/roles/urls.py +++ b/api/dashboard/roles/urls.py @@ -6,7 +6,9 @@ urlpatterns = [ path('user-role//', dash_roles_views.UserRoleSearchAPI.as_view(), name='search-user-role'), path('base-template/', dash_roles_views.RoleBaseTemplateAPI.as_view(), name="roles-base-template"), - path('bulk-assign/', dash_roles_views.UserRoleBulkAssignAPI.as_view(), name="user-roles-import"), + path('bulk-assign/', dash_roles_views.UserRoleLinkManagement.as_view(), name="user-roles-assign"), # used to assign a bunch of users a role + path('bulk-assign//', dash_roles_views.UserRoleLinkManagement.as_view(), name="user-roles-list"), # used to get the list of users to assign a role + path('bulk-assign-excel/', dash_roles_views.UserRoleBulkAssignAPI.as_view(), name="user-roles-assign-excel"), path('user-role/', dash_roles_views.UserRole.as_view(), name='create-delete-user-role'), path('', dash_roles_views.RoleAPI.as_view(), name="roles-list"), path('', dash_roles_views.RoleAPI.as_view(), name="roles-create"), From 921d85ee030aedbb8120b9cce39fc18dce687393 Mon Sep 17 00:00:00 2001 From: Muhammed Zafar Date: Thu, 30 Nov 2023 20:19:31 +0530 Subject: [PATCH 02/36] [PATCH] discord like role management verified --- api/dashboard/roles/dash_roles_serializer.py | 1 + 1 file changed, 1 insertion(+) diff --git a/api/dashboard/roles/dash_roles_serializer.py b/api/dashboard/roles/dash_roles_serializer.py index 3bed622d..6cc8e137 100644 --- a/api/dashboard/roles/dash_roles_serializer.py +++ b/api/dashboard/roles/dash_roles_serializer.py @@ -39,6 +39,7 @@ def validate_users(self, attrs): def create(self, validated_data): users = validated_data.pop("users") validated_data["created_at"] = DateTimeUtils.get_current_utc_time() + validated_data["verified"] = True user_roles_to_create = [ UserRoleLink(user=user, **validated_data) for user in users ] From 111a89b495db31778e89e057ab96fb7a17e1c445 Mon Sep 17 00:00:00 2001 From: Muhammed Zafar Date: Thu, 30 Nov 2023 21:09:55 +0530 Subject: [PATCH 03/36] [FEAT] discord like management discord webhook --- api/dashboard/roles/dash_roles_serializer.py | 24 +++++++++++++++----- db/user.py | 3 +++ utils/types.py | 1 + 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/api/dashboard/roles/dash_roles_serializer.py b/api/dashboard/roles/dash_roles_serializer.py index 6cc8e137..e8ceb6a7 100644 --- a/api/dashboard/roles/dash_roles_serializer.py +++ b/api/dashboard/roles/dash_roles_serializer.py @@ -4,7 +4,9 @@ from db.user import Role, User, UserRoleLink from utils.permission import JWTUtils -from utils.utils import DateTimeUtils +from utils.utils import DateTimeUtils, DiscordWebhooks +from utils.types import WebHookActions, WebHookCategory +from django.db.models import Q class UserRoleLinkManagementSerializer(serializers.ModelSerializer): @@ -28,13 +30,17 @@ class RoleAssignmentSerializer(serializers.Serializer): users = serializers.ListField(child=serializers.UUIDField()) created_by = serializers.PrimaryKeyRelatedField(queryset=User.objects.all()) - def validate_users(self, attrs): - attrs = set(attrs) - users = User.objects.filter(pk__in=attrs) + def validate(self, attrs): + data = super().validate(attrs) + attrs = set(attrs["users"]) + users = User.objects.filter( + ~Q(user_role_link_user__role=data["role"]), pk__in=attrs + ) if users.count() != len(attrs): raise serializers.ValidationError("One or more user IDs are invalid.") else: - return users + data["users"] = users + return data def create(self, validated_data): users = validated_data.pop("users") @@ -43,7 +49,13 @@ def create(self, validated_data): user_roles_to_create = [ UserRoleLink(user=user, **validated_data) for user in users ] - # TODO: Implement the user assigning in discord too + + DiscordWebhooks.general_updates( + WebHookCategory.BULK_ROLE.value, + WebHookActions.UPDATE.value, + validated_data["role"].title, + ",".join(list(users.values_list("id", flat=True))), + ) UserRoleLink.objects.bulk_create(user_roles_to_create) return user_roles_to_create diff --git a/db/user.py b/db/user.py index ee9fadaf..8512546c 100644 --- a/db/user.py +++ b/db/user.py @@ -81,6 +81,9 @@ class UserRoleLink(models.Model): class Meta: managed = False db_table = 'user_role_link' + constraints = [ + models.UniqueConstraint(fields=['role', 'user'], name="UserToRole") + ] class Socials(models.Model): diff --git a/utils/types.py b/utils/types.py index 85d05422..28ff8d05 100644 --- a/utils/types.py +++ b/utils/types.py @@ -78,6 +78,7 @@ class WebHookCategory(Enum): USER = 'user' USER_NAME = 'user-name' USER_PROFILE = 'user-profile' + BULK_ROLE = 'bulk-role' class RefferalType(Enum): From f7c456ac1329e737f9c7b8d8804b209266205540 Mon Sep 17 00:00:00 2001 From: Muhammed Zafar Date: Thu, 30 Nov 2023 21:13:26 +0530 Subject: [PATCH 04/36] [PATCH] Added transaction to bulk role mngmnt --- api/dashboard/roles/dash_roles_serializer.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/api/dashboard/roles/dash_roles_serializer.py b/api/dashboard/roles/dash_roles_serializer.py index e8ceb6a7..789107d7 100644 --- a/api/dashboard/roles/dash_roles_serializer.py +++ b/api/dashboard/roles/dash_roles_serializer.py @@ -7,7 +7,7 @@ from utils.utils import DateTimeUtils, DiscordWebhooks from utils.types import WebHookActions, WebHookCategory from django.db.models import Q - +from django.db import transaction class UserRoleLinkManagementSerializer(serializers.ModelSerializer): """ @@ -49,14 +49,14 @@ def create(self, validated_data): user_roles_to_create = [ UserRoleLink(user=user, **validated_data) for user in users ] - - DiscordWebhooks.general_updates( - WebHookCategory.BULK_ROLE.value, - WebHookActions.UPDATE.value, - validated_data["role"].title, - ",".join(list(users.values_list("id", flat=True))), - ) - UserRoleLink.objects.bulk_create(user_roles_to_create) + with transaction.atomic(): + UserRoleLink.objects.bulk_create(user_roles_to_create) + DiscordWebhooks.general_updates( + WebHookCategory.BULK_ROLE.value, + WebHookActions.UPDATE.value, + validated_data["role"].title, + ",".join(list(users.values_list("id", flat=True))), + ) return user_roles_to_create From b5d6283540d46ce246e4920d48436d9fc97b3872 Mon Sep 17 00:00:00 2001 From: anirudh-mk Date: Thu, 30 Nov 2023 21:25:08 +0530 Subject: [PATCH 05/36] feat(lc details ig progress meet report): response changed --- api/dashboard/lc/dash_lc_serializer.py | 46 ++++++++++++++------------ api/dashboard/lc/dash_lc_view.py | 9 ++--- db/task.py | 2 +- 3 files changed, 28 insertions(+), 29 deletions(-) diff --git a/api/dashboard/lc/dash_lc_serializer.py b/api/dashboard/lc/dash_lc_serializer.py index 14c7a2bd..ab48dd73 100644 --- a/api/dashboard/lc/dash_lc_serializer.py +++ b/api/dashboard/lc/dash_lc_serializer.py @@ -5,7 +5,7 @@ from rest_framework import serializers from db.learning_circle import LearningCircle, UserCircleLink, InterestGroup, CircleMeetingLog -from db.task import TaskList, UserIgLink +from db.task import TaskList, UserIgLink, Wallet from db.organization import UserOrganizationLink from db.task import KarmaActivityLog from db.user import User @@ -316,6 +316,7 @@ class LearningCircleHomeSerializer(serializers.ModelSerializer): is_lead = serializers.SerializerMethodField() is_member = serializers.SerializerMethodField() ig_code = serializers.CharField(source='ig.code') + ig_id = serializers.CharField(source='ig.id') previous_meetings = serializers.SerializerMethodField() class Meta: @@ -334,6 +335,7 @@ class Meta: "total_karma", "is_lead", "is_member", + "ig_id", "ig_code", "previous_meetings", ] @@ -398,6 +400,7 @@ def _get_member_info(self, obj, accepted): 'profile_pic': member.user.profile_pic or None, 'karma': total_ig_karma, 'is_lead': member.lead, + 'level': member.user.user_lvl_link_user.level.level_order }) return member_info @@ -606,19 +609,21 @@ def validate_attendees(self, attendees): attendees_list = attendees.split(',') user_id = self.context.get('user_id') - - KarmaActivityLog.objects.bulk_create([ - KarmaActivityLog( - id=uuid.uuid4(), - user_id=user, - karma=Lc.KARMA.value, - task=task, - updated_by_id=user_id, - created_by_id=user_id, - ) - for user in attendees_list - ]) - + for user in attendees_list: + KarmaActivityLog.objects.bulk_create([ + KarmaActivityLog( + id=uuid.uuid4(), + user_id=user, + karma=Lc.KARMA.value, + task=task, + updated_by_id=user_id, + created_by_id=user_id, + ) + ]) + wallet = Wallet.objects.filter(user_id=user).first() + wallet.karma += Lc.KARMA.value + wallet.updated_at = DateTimeUtils.get_current_utc_time() + wallet.save() return attendees @@ -656,17 +661,14 @@ class Meta: ] def get_task_status(self, obj): - ig_id = self.context.get('ig_id') - - user_ig_links = UserIgLink.objects.filter(ig=ig_id).select_related('user') - + user_ig_links = UserIgLink.objects.filter(ig=obj.ig).select_related('user') for user_ig_link in user_ig_links: - if not obj.karma_activity_log_task.filter( + if obj.karma_activity_log_task.filter( user=user_ig_link.user, - peer_approved=True - ).exists(): + peer_approved=True).exists(): + return True + else: return False - return True class AddMemberSerializer(serializers.ModelSerializer): diff --git a/api/dashboard/lc/dash_lc_view.py b/api/dashboard/lc/dash_lc_view.py index 3e96c930..595aa157 100644 --- a/api/dashboard/lc/dash_lc_view.py +++ b/api/dashboard/lc/dash_lc_view.py @@ -403,7 +403,7 @@ def delete(self, request, circle_id): class SingleReportDetailAPI(APIView): - def get(self, request, circle_id, report_id): + def get(self, request, circle_id, report_id=None): circle_meeting_log = CircleMeetingLog.objects.get(id=report_id) serializer = MeetRecordsCreateEditDeleteSerializer( @@ -671,15 +671,12 @@ def put(self, request, circle_id): class IgTaskDetailsAPI(APIView): - def get(self, request, ig_id): - task_list = TaskList.objects.filter(ig=ig_id) + def get(self, request, circle_id): + task_list = TaskList.objects.filter(ig__learning_circle_ig__id=circle_id) serializer = IgTaskDetailsSerializer( task_list, many=True, - context={ - 'ig': ig_id - } ) return CustomResponse( diff --git a/db/task.py b/db/task.py index a18b470e..e8377e3f 100644 --- a/db/task.py +++ b/db/task.py @@ -128,7 +128,7 @@ class Wallet(models.Model): id = models.CharField(primary_key=True, max_length=36, default=uuid.uuid4) user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="wallet_user") karma = models.IntegerField(default=0) - karma_last_update_at = models.DateTimeField(blank=True, null=True, auto_now_add=True) + # karma_last_update_at = models.DateTimeField(blank=True, null=True, auto_now_add=True) coin = models.FloatField(default=0) updated_by = models.ForeignKey(User, on_delete=models.CASCADE, db_column="updated_by", related_name="wallet_updated_by") From d8db3cd2c2f4e8711dc3d8b476964b5c74c9871c Mon Sep 17 00:00:00 2001 From: Adnan Kattekaden Date: Thu, 30 Nov 2023 21:51:13 +0530 Subject: [PATCH 06/36] division error fix --- api/dashboard/college/serializer.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/api/dashboard/college/serializer.py b/api/dashboard/college/serializer.py index eaab3a62..1c1a2936 100644 --- a/api/dashboard/college/serializer.py +++ b/api/dashboard/college/serializer.py @@ -73,7 +73,10 @@ def get_total_karma(self, obj): ).aggregate(total_karma=Sum("karma"))["total_karma"] or 0 ) - - increased_percentage = (total_karma_increased / total_karma_gained) * 100 + try: + increased_percentage = (total_karma_increased / total_karma_gained) * 100 + except Exception as e: + increased_percentage = 0 + return increased_percentage return {'total_karma_gained': total_karma_gained, 'total_karma_increased': total_karma_increased, 'increased_percentage': increased_percentage} From 3840aa24df9cb6ad2ee7f06e4a5e2c72704d8126 Mon Sep 17 00:00:00 2001 From: Ajay Vishnu E Date: Thu, 30 Nov 2023 22:00:13 +0530 Subject: [PATCH 07/36] Discord Moderator API --- .../discord_moderator/discord_mod_views.py | 36 +++++++++++++++++++ api/dashboard/discord_moderator/serializer.py | 25 +++++++++++++ api/dashboard/discord_moderator/urls.py | 9 +++++ api/dashboard/urls.py | 4 ++- 4 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 api/dashboard/discord_moderator/discord_mod_views.py create mode 100644 api/dashboard/discord_moderator/serializer.py create mode 100644 api/dashboard/discord_moderator/urls.py diff --git a/api/dashboard/discord_moderator/discord_mod_views.py b/api/dashboard/discord_moderator/discord_mod_views.py new file mode 100644 index 00000000..59656149 --- /dev/null +++ b/api/dashboard/discord_moderator/discord_mod_views.py @@ -0,0 +1,36 @@ +from rest_framework.views import APIView +from utils.permission import CustomizePermission, JWTUtils, role_required +from utils.response import CustomResponse +from utils.types import RoleType +from utils.utils import CommonUtils +from .serializer import KarmaActivityLogSerializer +from db.task import KarmaActivityLog +from django.utils import timezone +from utils.utils import DateTimeUtils + + +class TaskList(APIView): + authentication_classes = [CustomizePermission] + + def get(self, request): + tasks = KarmaActivityLog.objects.all() + serializer = KarmaActivityLogSerializer(tasks, many=True) + return CustomResponse(response=serializer.data).get_success_response() + + +class PendingTasks(APIView): + authentication_classes = [CustomizePermission] + + def get(self, request): + date = request.query_params.get("date") + if date: + tasks = KarmaActivityLog.objects.filter(created_at = date) + peerpending = tasks.filter(peer_approved = False).count() + appraiserpending = tasks.filter(appraiser_approved = False).count() + data = {'peer-pending':peerpending,'appraiser-pending':appraiserpending} + return CustomResponse(response = data).get_success_response() + + peerpending = KarmaActivityLog.objects.filter(peer_approved = False).count() + appraiserpending = KarmaActivityLog.objects.filter(appraiser_approved = False).count() + data = {'peer-pending':peerpending,'appraiser-pending':appraiserpending} + return CustomResponse(response = data).get_success_response() \ No newline at end of file diff --git a/api/dashboard/discord_moderator/serializer.py b/api/dashboard/discord_moderator/serializer.py new file mode 100644 index 00000000..c90433f3 --- /dev/null +++ b/api/dashboard/discord_moderator/serializer.py @@ -0,0 +1,25 @@ +from rest_framework import serializers +from db.task import KarmaActivityLog + + +class KarmaActivityLogSerializer(serializers.ModelSerializer): + fullname = serializers.CharField(source = 'user.fullname') + task_name = serializers.CharField(source = 'task.title') + status = serializers.SerializerMethodField() + discordlink = serializers.CharField(source = 'task.discord_link') + class Meta: + model = KarmaActivityLog + fields = ['id', 'fullname', 'task_name', 'status', 'discordlink'] + + def get_status(self,obj): + if obj.peer_approved == True and obj.appraiser_approved == True: + return "Karma Awarded" + elif obj.peer_approved== True: + return "Peer Approved" + elif obj.appraiser_approved == True: + return "Appraiser Approved" + else: + return "Pending" + + + diff --git a/api/dashboard/discord_moderator/urls.py b/api/dashboard/discord_moderator/urls.py new file mode 100644 index 00000000..ae21d267 --- /dev/null +++ b/api/dashboard/discord_moderator/urls.py @@ -0,0 +1,9 @@ +from django.urls import path + +from . import discord_mod_views + +urlpatterns = [ + path('tasklist/', discord_mod_views.TaskList.as_view()), + path('pendingcounts/', discord_mod_views.PendingTasks.as_view()), + +] diff --git a/api/dashboard/urls.py b/api/dashboard/urls.py index 3c46702a..7632000b 100644 --- a/api/dashboard/urls.py +++ b/api/dashboard/urls.py @@ -19,5 +19,7 @@ path('dynamic-management/', include('api.dashboard.dynamic_management.urls')), path('error-log/', include('api.dashboard.error_log.urls')), path('affiliation/',include('api.dashboard.affiliation.urls')), - path('channels/',include('api.dashboard.channels.urls')) + path('channels/',include('api.dashboard.channels.urls')), + path('discord-moderator/',include('api.dashboard.discord_moderator.urls')) + ] From bb450dee874b1fbd9c0796314917ed2c9e7cce4d Mon Sep 17 00:00:00 2001 From: Adnan Kattekaden Date: Thu, 30 Nov 2023 22:06:45 +0530 Subject: [PATCH 08/36] url shorner issue fixed --- api/url_shortener/serializers.py | 6 +- api/url_shortener/url_shortener_view.py | 86 ++++++++++++------------- db/url_shortener.py | 46 +++++++------ 3 files changed, 69 insertions(+), 69 deletions(-) diff --git a/api/url_shortener/serializers.py b/api/url_shortener/serializers.py index 5fa3cb29..f43ada1d 100644 --- a/api/url_shortener/serializers.py +++ b/api/url_shortener/serializers.py @@ -4,7 +4,7 @@ from rest_framework import serializers from rest_framework.serializers import ModelSerializer -from db.url_shortener import UrlShortener,UrlShortenerTracker +from db.url_shortener import UrlShortener, UrlShortenerTracker from utils.permission import JWTUtils from utils.utils import DateTimeUtils @@ -55,7 +55,7 @@ def validate_short_url(self, value): class ShowShortenUrlsTrackerSerializer(ModelSerializer): - + class Meta: model = UrlShortenerTracker - fields = ["id","ip_address","device_type","operating_system","browser"] + fields = ["ip_address", "device_type", "operating_system", "browser"] diff --git a/api/url_shortener/url_shortener_view.py b/api/url_shortener/url_shortener_view.py index 78cf8f07..b67e23dc 100644 --- a/api/url_shortener/url_shortener_view.py +++ b/api/url_shortener/url_shortener_view.py @@ -2,8 +2,7 @@ from api.url_shortener.serializers import ( ShowShortenUrlsSerializer, - ShortenUrlsCreateUpdateSerializer, - ShowShortenUrlsTrackerSerializer + ShortenUrlsCreateUpdateSerializer ) from db.url_shortener import UrlShortener, UrlShortenerTracker from utils.permission import CustomizePermission @@ -11,7 +10,6 @@ from utils.response import CustomResponse from utils.types import RoleType from utils.utils import CommonUtils -from django.db.models import Count class UrlShortenerAPI(APIView): @@ -134,45 +132,43 @@ class UrlAnalyticsAPI(APIView): [RoleType.ADMIN.value, RoleType.FELLOW.value, RoleType.ASSOCIATE.value] ) def get(self, request, url_id): - url_tracker_obj = UrlShortener.objects.filter(id=url_id).first() - - if url_tracker_obj is None: - return CustomResponse( - general_message="No URL related data available" - ).get_failure_response() - - queryset = UrlShortenerTracker.objects.filter(url_shortener_id = url_tracker_obj.id) - device_counts = UrlShortenerTracker.objects.values('device_type').annotate(count=Count('device_type')).order_by('device_type') - platform_counts = UrlShortenerTracker.objects.values('operating_system').annotate(count=Count('operating_system')).order_by('operating_system') - browser_counts = UrlShortenerTracker.objects.values('browser').annotate(count=Count('browser')).order_by('browser') - - countset={} - countset[1] = device_counts - countset[2] = platform_counts - countset[3] = browser_counts - - print(countset) - paginated_queryset = CommonUtils.get_paginated_queryset( - queryset, - request, - ["id","ip_address","device_type","operating_system","browser",] - - ) - - serializer = ShowShortenUrlsTrackerSerializer( - paginated_queryset.get("queryset"), - many=True - ) - - return CustomResponse( - general_message="URL Stats", - response=countset - ).paginated_response( - data=serializer.data, - pagination=paginated_queryset.get( - "pagination" - ) - ) - - - + queryset = UrlShortenerTracker.objects.filter(url_shortener__id=url_id) + + browsers = {} + operating_systems = {} + devices = {} + referrer = {} + + for query in queryset: + # Counting browsers + if browsers.get(query.browser): + browsers[query.browser] += 1 + else: + browsers[query.browser] = 1 + + # Counting operating systems + if operating_systems.get(query.operating_system): + operating_systems[query.operating_system] += 1 + else: + operating_systems[query.operating_system] = 1 + + # Counting devices + if devices.get(query.device_type): + devices[query.device_type] += 1 + else: + devices[query.device_type] = 1 + + if referrer.get(query.referrer): + referrer[query.referrer] += 1 + else: + referrer[query.referrer] = 1 + + result = { + 'total_clicks': query.url_shortener.count, + 'browsers': browsers, + 'platforms': operating_systems, + 'devices': devices, + 'sources': referrer, + } + + return CustomResponse(response=result).get_success_response() diff --git a/db/url_shortener.py b/db/url_shortener.py index 73cd2d57..57aae37a 100644 --- a/db/url_shortener.py +++ b/db/url_shortener.py @@ -2,19 +2,22 @@ from db.user import User + # fmt: off # noinspection PyPep8 class UrlShortener(models.Model): - id = models.CharField(primary_key=True, max_length=36) - title = models.CharField(max_length=100) - short_url = models.CharField(unique=True, max_length=100) - long_url = models.CharField(max_length=500) - count = models.IntegerField(blank=True, null=True, default=0) - updated_by = models.ForeignKey(User, on_delete=models.CASCADE, db_column='updated_by', related_name='url_shortener_updated_by') - updated_at = models.DateTimeField(auto_now=True) - created_by = models.ForeignKey(User, on_delete=models.CASCADE, db_column='created_by', related_name='url_shortener_created_by') - created_at = models.DateTimeField(auto_now_add=True) + id = models.CharField(primary_key=True, max_length=36) + title = models.CharField(max_length=100) + short_url = models.CharField(unique=True, max_length=100) + long_url = models.CharField(max_length=500) + count = models.IntegerField(blank=True, null=True, default=0) + updated_by = models.ForeignKey(User, on_delete=models.CASCADE, db_column='updated_by', + related_name='url_shortener_updated_by') + updated_at = models.DateTimeField(auto_now=True) + created_by = models.ForeignKey(User, on_delete=models.CASCADE, db_column='created_by', + related_name='url_shortener_created_by') + created_at = models.DateTimeField(auto_now_add=True) class Meta: managed = False @@ -22,19 +25,20 @@ class Meta: class UrlShortenerTracker(models.Model): - id = models.CharField(primary_key=True, max_length=36) - ip_address = models.CharField(max_length=45) - browser = models.CharField(max_length=255, blank=True, null=True) + id = models.CharField(primary_key=True, max_length=36) + ip_address = models.CharField(max_length=45) + browser = models.CharField(max_length=255, blank=True, null=True) operating_system = models.CharField(max_length=255, blank=True, null=True) - version = models.CharField(max_length=255, blank=True, null=True) - device_type = models.CharField(max_length=255, blank=True, null=True) - url_shortener = models.ForeignKey(UrlShortener, on_delete=models.CASCADE, blank=True, null=True) - city = models.CharField(max_length=36, blank=True, null=True) - region = models.CharField(max_length=36, blank=True, null=True) - country = models.CharField(max_length=36, blank=True, null=True) - location = models.CharField(max_length=36, blank=True, null=True) - referrer = models.CharField(max_length=36, blank=True, null=True) - + version = models.CharField(max_length=255, blank=True, null=True) + device_type = models.CharField(max_length=255, blank=True, null=True) + url_shortener = models.ForeignKey(UrlShortener, on_delete=models.CASCADE, blank=True, null=True, + related_name='url_shortener_tracker_url') + city = models.CharField(max_length=36, blank=True, null=True) + region = models.CharField(max_length=36, blank=True, null=True) + country = models.CharField(max_length=36, blank=True, null=True) + location = models.CharField(max_length=36, blank=True, null=True) + referrer = models.CharField(max_length=36, blank=True, null=True) + created_at = models.DateTimeField(auto_now_add=True) class Meta: managed = False db_table = 'url_shortener_tracker' From 1070cb284446fbe4ae62b3e5d9c35f2575a1993d Mon Sep 17 00:00:00 2001 From: lordgrim Date: Thu, 30 Nov 2023 22:38:21 +0530 Subject: [PATCH 09/36] patch(role): add webhooks to bulk role assign api --- api/dashboard/roles/dash_roles_views.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/api/dashboard/roles/dash_roles_views.py b/api/dashboard/roles/dash_roles_views.py index 80866c40..97e5942c 100644 --- a/api/dashboard/roles/dash_roles_views.py +++ b/api/dashboard/roles/dash_roles_views.py @@ -371,6 +371,7 @@ def post(self, request): ) users_dict = {user["muid"]: user["id"] for user in users} roles_dict = {role["title"]: role["id"] for role in roles} + users_by_role = {role_title: [] for role_title in roles_dict.keys()} for row in excel_data[1:]: user = row.pop("muid") @@ -395,6 +396,7 @@ def post(self, request): row["error"] = f"User {user} already has role {role}" error_rows.append(row) else: + users_by_role[role].append(user_id) request_user_id = JWTUtils.fetch_user_id(request) row["id"] = str(uuid.uuid4()) row["user_id"] = user_id @@ -419,6 +421,14 @@ def post(self, request): else: error_rows.append(user_roles_serializer.errors) + for role,user_set in users_by_role.items(): + DiscordWebhooks.general_updates( + WebHookCategory.BULK_ROLE.value, + WebHookActions.UPDATE.value, + role, + ",".join(user_set) + ) + return CustomResponse( response={"Success": success_data, "Failed": error_rows} ).get_success_response() From e2ab9e354f5c93876aa4ec3f3ee3022aeaf2e6d4 Mon Sep 17 00:00:00 2001 From: Adnan Kattekaden Date: Thu, 30 Nov 2023 23:32:14 +0530 Subject: [PATCH 10/36] campus csv issue fixed --- api/dashboard/campus/campus_views.py | 115 ++++++++++++++++++--------- 1 file changed, 79 insertions(+), 36 deletions(-) diff --git a/api/dashboard/campus/campus_views.py b/api/dashboard/campus/campus_views.py index 38e53eea..eb5aca5f 100644 --- a/api/dashboard/campus/campus_views.py +++ b/api/dashboard/campus/campus_views.py @@ -193,52 +193,95 @@ class CampusStudentDetailsCSVAPI(APIView): def get(self, request): user_id = JWTUtils.fetch_user_id(request) user_org_link = get_user_college_link(user_id) - - start_date, end_date = DateTimeUtils.get_start_and_end_of_previous_month() + is_alumni = request.query_params.get("is_alumni") if user_org_link.org is None: return CustomResponse( general_message="Campus lead has no college" ).get_failure_response() - - rank = ( - Wallet.objects.filter( - user__user_organization_link_user__org=user_org_link.org, - user__user_organization_link_user__org__org_type=OrganizationType.COLLEGE.value, - ) - .distinct() - .order_by("-karma", "-created_at") - .values( - "user_id", - "karma", + if is_alumni: + rank = ( + Wallet.objects.filter( + user__user_organization_link_user__org=user_org_link.org, + user__user_organization_link_user__org__org_type=OrganizationType.COLLEGE.value, + user__user_organization_link_user__is_alumni=is_alumni, + ) + .distinct() + .order_by("-karma", "-created_at") + .values( + "user_id", + "karma", + ) ) - ) - ranks = {user["user_id"]: i + 1 for i, user in enumerate(rank)} + ranks = {user["user_id"]: i + 1 for i, user in enumerate(rank)} - user_org_links = ( - User.objects.filter( - user_organization_link_user__org=user_org_link.org, - user_organization_link_user__org__org_type=OrganizationType.COLLEGE.value, - ) - .distinct() - .annotate( - user_id=F("id"), - karma=F("wallet_user__karma"), - level=F("user_lvl_link_user__level__name"), - join_date=F("created_at"), + user_org_links = ( + User.objects.filter( + user_organization_link_user__org=user_org_link.org, + user_organization_link_user__org__org_type=OrganizationType.COLLEGE.value, + user_organization_link_user__is_alumni=is_alumni, + ) + .distinct() + .annotate( + user_id=F("id"), + email_=F("email"), + mobile_=F("mobile"), + karma=F("wallet_user__karma"), + level=F("user_lvl_link_user__level__name"), + join_date=F("created_at"), + department=F('user_organization_link_user__department__title'), + graduation_year=F("user_organization_link_user__graduation_year"), + is_alumni=F('user_organization_link_user__is_alumni'), + )) + else: + rank = ( + Wallet.objects.filter( + user__user_organization_link_user__org=user_org_link.org, + user__user_organization_link_user__org__org_type=OrganizationType.COLLEGE.value, + ) + .distinct() + .order_by("-karma", "-created_at") + .values( + "user_id", + "karma", + ) ) - .annotate( - is_active=Case( - When( - Q( - karma_activity_log_user__created_at__range=( - start_date, - end_date)), - then=Value("Active")), - default=Value("Not Active") + + ranks = {user["user_id"]: i + 1 for i, user in enumerate(rank)} + + user_org_links = ( + User.objects.filter( + user_organization_link_user__org=user_org_link.org, + user_organization_link_user__org__org_type=OrganizationType.COLLEGE.value, ) - )) + .distinct() + .annotate( + user_id=F("id"), + email_=F("email"), + mobile_=F("mobile"), + karma=F("wallet_user__karma"), + level=F("user_lvl_link_user__level__name"), + join_date=F("created_at"), + department=F('user_organization_link_user__department__title'), + graduation_year=F("user_organization_link_user__graduation_year"), + is_alumni=F('user_organization_link_user__is_alumni'), + )) + + paginated_queryset = CommonUtils.get_paginated_queryset( + user_org_links, + request, + ["first_name", "last_name", "level"], + { + "first_name": "first_name", + "last_name": "last_name", + "muid": "muid", + "karma": "wallet_user__karma", + "level": "user_lvl_link_user__level__level_order", + # "is_active": "karma_activity_log_user__created_at", + "joined_at": "created_at" + }, + ) serializer = serializers.CampusStudentDetailsSerializer( user_org_links, many=True, context={"ranks": ranks} From f1645ec7a2cc1fa65381c3cb49745c7805618714 Mon Sep 17 00:00:00 2001 From: Shaheen Hyder K Date: Thu, 30 Nov 2023 23:41:43 +0530 Subject: [PATCH 11/36] (fix): bug in LC --- api/dashboard/lc/dash_lc_serializer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/dashboard/lc/dash_lc_serializer.py b/api/dashboard/lc/dash_lc_serializer.py index ab48dd73..8560681c 100644 --- a/api/dashboard/lc/dash_lc_serializer.py +++ b/api/dashboard/lc/dash_lc_serializer.py @@ -301,8 +301,8 @@ def create(self, validated_data): validated_data['user_id'] = user_id validated_data['circle_id'] = circle_id validated_data['lead'] = False - validated_data['accepted'] = True - validated_data['accepted_at'] = DateTimeUtils.get_current_utc_time() + validated_data['accepted'] = None + validated_data['accepted_at'] = None validated_data['created_at'] = DateTimeUtils.get_current_utc_time() return UserCircleLink.objects.create(**validated_data) From 728e04dee47a97212b36903463e5aa86bc050b69 Mon Sep 17 00:00:00 2001 From: Adnan Kattekaden Date: Fri, 1 Dec 2023 00:45:35 +0530 Subject: [PATCH 12/36] task issue fixed --- api/dashboard/task/dash_task_serializer.py | 30 ++++++++++++---------- db/task.py | 4 ++- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/api/dashboard/task/dash_task_serializer.py b/api/dashboard/task/dash_task_serializer.py index 692bf38c..6c7dad8f 100644 --- a/api/dashboard/task/dash_task_serializer.py +++ b/api/dashboard/task/dash_task_serializer.py @@ -1,7 +1,8 @@ import uuid + from rest_framework import serializers -from db.task import TaskList, KarmaActivityLog, TaskType +from db.task import TaskList, TaskType from utils.permission import JWTUtils from utils.utils import DateTimeUtils @@ -39,10 +40,11 @@ class Meta: "updated_by", "created_by", "created_at", + "bonus_time", + "bonus_karma", ] def get_total_karma_gainers(self, obj): - return obj.karma_activity_log_task.filter( appraiser_approved=True ).count() @@ -68,6 +70,8 @@ class Meta: "event", "updated_by", "created_by", + "bonus_karma", + "bonus_time", ) @@ -121,25 +125,26 @@ def validate_usage_count(self, value): if value is None: return 1 return value - + def validate_variable_karma(self, value): if value is None: return False return value + class TasktypeSerializer(serializers.ModelSerializer): - updated_by=serializers.CharField(source='updated_by.fullname') - created_by=serializers.CharField(source='created_by.fullname') + updated_by = serializers.CharField(source='updated_by.fullname') + created_by = serializers.CharField(source='created_by.fullname') class Meta: model = TaskType - fields = ["id", "title","updated_by","updated_at","created_by","created_at"] + fields = ["id", "title", "updated_by", "updated_at", "created_by", "created_at"] -class TaskTypeCreateUpdateSerializer(serializers.ModelSerializer): +class TaskTypeCreateUpdateSerializer(serializers.ModelSerializer): class Meta: - model=TaskType - fields=["title"] + model = TaskType + fields = ["title"] def create(self, validated_data): user_id = self.context.get("user_id") @@ -151,15 +156,12 @@ def create(self, validated_data): created_by_id=user_id, created_at=DateTimeUtils.get_current_utc_time(), ) + def update(self, instance, validated_data): updated_title = validated_data.get("title") instance.title = updated_title user_id = JWTUtils.fetch_user_id(self.context.get("request")) instance.updated_by_id = user_id - instance.updated_at=DateTimeUtils.get_current_utc_time(), + instance.updated_at = DateTimeUtils.get_current_utc_time(), instance.save() return instance - - - - diff --git a/db/task.py b/db/task.py index e8377e3f..729fdc29 100644 --- a/db/task.py +++ b/db/task.py @@ -114,6 +114,8 @@ class TaskList(models.Model): active = models.BooleanField(default=True) variable_karma = models.BooleanField(default=False) usage_count = models.IntegerField(default=1) + bonus_time = models.DateTimeField(blank=True, null=True) + bonus_karma = models.IntegerField(blank=True, null=True) updated_by = models.ForeignKey(User, models.DO_NOTHING, db_column="updated_by", related_name="task_list_updated_by") updated_at = models.DateTimeField(auto_now=True) created_by = models.ForeignKey(User, models.DO_NOTHING, db_column="created_by", related_name="task_list_created_by") @@ -128,7 +130,7 @@ class Wallet(models.Model): id = models.CharField(primary_key=True, max_length=36, default=uuid.uuid4) user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="wallet_user") karma = models.IntegerField(default=0) - # karma_last_update_at = models.DateTimeField(blank=True, null=True, auto_now_add=True) + karma_last_update_at = models.DateTimeField(blank=True, null=True, auto_now=True) coin = models.FloatField(default=0) updated_by = models.ForeignKey(User, on_delete=models.CASCADE, db_column="updated_by", related_name="wallet_updated_by") From 1b1f5a1e8016648f04b2d32830c1d87df99097f1 Mon Sep 17 00:00:00 2001 From: Adnan Kattekaden Date: Fri, 1 Dec 2023 00:58:59 +0530 Subject: [PATCH 13/36] task issue fixed --- api/dashboard/campus/campus_views.py | 18 ++++++++++-------- api/dashboard/campus/serializers.py | 8 ++++---- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/api/dashboard/campus/campus_views.py b/api/dashboard/campus/campus_views.py index eb5aca5f..74fc8b3e 100644 --- a/api/dashboard/campus/campus_views.py +++ b/api/dashboard/campus/campus_views.py @@ -1,5 +1,5 @@ from django.db.models import Count, F -from django.db.models import Q, Case, When, Value +from django.db.models import Q from rest_framework.views import APIView from db.organization import UserOrganizationLink @@ -8,7 +8,7 @@ from utils.permission import CustomizePermission, JWTUtils, role_required from utils.response import CustomResponse from utils.types import OrganizationType, RoleType -from utils.utils import CommonUtils, DateTimeUtils +from utils.utils import CommonUtils from . import serializers from .dash_campus_helper import get_user_college_link @@ -29,7 +29,7 @@ class CampusDetailsAPI(APIView): authentication_classes = [CustomizePermission] # Use the role_required decorator to specify the allowed roles for this view - @role_required([RoleType.CAMPUS_LEAD.value, RoleType.ENABLER.value, RoleType.LEAD_ENABLER.value]) + @role_required([RoleType.CAMPUS_LEAD.value, RoleType.LEAD_ENABLER.value]) def get(self, request): # Fetch the user's ID from the request using JWTUtils user_id = JWTUtils.fetch_user_id(request) @@ -54,7 +54,7 @@ def get(self, request): class CampusStudentInEachLevelAPI(APIView): authentication_classes = [CustomizePermission] - @role_required([RoleType.CAMPUS_LEAD.value, RoleType.ENABLER.value, RoleType.LEAD_ENABLER.value]) + @role_required([RoleType.CAMPUS_LEAD.value, RoleType.LEAD_ENABLER.value]) def get(self, request): user_id = JWTUtils.fetch_user_id(request) @@ -80,7 +80,7 @@ def get(self, request): class CampusStudentDetailsAPI(APIView): authentication_classes = [CustomizePermission] - @role_required([RoleType.CAMPUS_LEAD.value, RoleType.ENABLER.value, RoleType.LEAD_ENABLER.value]) + @role_required([RoleType.CAMPUS_LEAD.value, RoleType.LEAD_ENABLER.value]) def get(self, request): user_id = JWTUtils.fetch_user_id(request) user_org_link = get_user_college_link(user_id) @@ -121,6 +121,7 @@ def get(self, request): karma=F("wallet_user__karma"), level=F("user_lvl_link_user__level__name"), join_date=F("created_at"), + last_karma_gained=F("wallet_user__karma_last_update_at"), department=F('user_organization_link_user__department__title'), graduation_year=F("user_organization_link_user__graduation_year"), is_alumni=F('user_organization_link_user__is_alumni'), @@ -154,6 +155,7 @@ def get(self, request): karma=F("wallet_user__karma"), level=F("user_lvl_link_user__level__name"), join_date=F("created_at"), + last_karma_gained=F("wallet_user__karma_last_update_at"), department=F('user_organization_link_user__department__title'), graduation_year=F("user_organization_link_user__graduation_year"), is_alumni=F('user_organization_link_user__is_alumni'), @@ -189,7 +191,7 @@ def get(self, request): class CampusStudentDetailsCSVAPI(APIView): authentication_classes = [CustomizePermission] - @role_required([RoleType.CAMPUS_LEAD.value, RoleType.ENABLER.value, RoleType.LEAD_ENABLER.value]) + @role_required([RoleType.CAMPUS_LEAD.value, RoleType.LEAD_ENABLER.value]) def get(self, request): user_id = JWTUtils.fetch_user_id(request) user_org_link = get_user_college_link(user_id) @@ -292,7 +294,7 @@ def get(self, request): class WeeklyKarmaAPI(APIView): authentication_classes = [CustomizePermission] - @role_required([RoleType.CAMPUS_LEAD.value, RoleType.ENABLER.value, RoleType.LEAD_ENABLER.value]) + @role_required([RoleType.CAMPUS_LEAD.value, RoleType.LEAD_ENABLER.value]) def get(self, request): user_id = JWTUtils.fetch_user_id(request) @@ -310,7 +312,7 @@ def get(self, request): class ChangeStudentTypeAPI(APIView): authentication_classes = [CustomizePermission] - @role_required([RoleType.CAMPUS_LEAD.value, RoleType.ENABLER.value, RoleType.LEAD_ENABLER.value]) + @role_required([RoleType.CAMPUS_LEAD.value, RoleType.LEAD_ENABLER.value]) def patch(self, request, member_id): user_id = JWTUtils.fetch_user_id(request) diff --git a/api/dashboard/campus/serializers.py b/api/dashboard/campus/serializers.py index 5f7359a3..b131073f 100644 --- a/api/dashboard/campus/serializers.py +++ b/api/dashboard/campus/serializers.py @@ -15,7 +15,6 @@ class CampusDetailsSerializer(serializers.ModelSerializer): college_name = serializers.ReadOnlyField(source="org.title") campus_code = serializers.ReadOnlyField(source="org.code") campus_zone = serializers.ReadOnlyField(source="org.district.zone.name") - campus_lead = serializers.ReadOnlyField(source="user.fullname") campus_level = serializers.SerializerMethodField() total_karma = serializers.SerializerMethodField() total_members = serializers.SerializerMethodField() @@ -28,7 +27,6 @@ class Meta: model = UserOrganizationLink fields = [ "college_name", - "campus_lead", "campus_code", "campus_zone", "campus_level", @@ -52,7 +50,7 @@ def get_lead(self, obj): enabler = User.objects.filter( user_organization_link_user__org=obj.org, user_organization_link_user__org__org_type=OrganizationType.COLLEGE.value, - user_role_link_user__role__title=RoleType.ENABLER.value, + user_role_link_user__role__title=RoleType.LEAD_ENABLER.value, ).first() if enabler: enabler = enabler.fullname @@ -119,6 +117,7 @@ class CampusStudentDetailsSerializer(serializers.Serializer): level = serializers.CharField() # is_active = serializers.CharField() join_date = serializers.CharField() + last_karma_gained = serializers.CharField() email = serializers.CharField() mobile = serializers.CharField() graduation_year = serializers.CharField() @@ -126,7 +125,8 @@ class CampusStudentDetailsSerializer(serializers.Serializer): is_alumni = serializers.CharField() class Meta: - fields = ("user_id", "email", "mobile", "fullname", "karma", "muid", "rank", "level", "join_date", "is_alumni") + fields = ("user_id", "email", "mobile", "fullname", "karma", "muid", "rank", "level", "join_date", "is_alumni", + "last_karma_update_at") def get_rank(self, obj): ranks = self.context.get("ranks") From 31bba9ae26a3cac6609b8d367bd52f3def4fdc11 Mon Sep 17 00:00:00 2001 From: Adnan Kattekaden Date: Fri, 1 Dec 2023 03:07:49 +0530 Subject: [PATCH 14/36] rank issue fixed --- api/dashboard/campus/serializers.py | 2 +- api/dashboard/profile/profile_serializer.py | 62 ++++++++++++--------- 2 files changed, 38 insertions(+), 26 deletions(-) diff --git a/api/dashboard/campus/serializers.py b/api/dashboard/campus/serializers.py index b131073f..37acc719 100644 --- a/api/dashboard/campus/serializers.py +++ b/api/dashboard/campus/serializers.py @@ -91,7 +91,7 @@ def get_rank(self, obj): UserOrganizationLink.objects.all() .values("org") .annotate(total_karma=Sum("user__wallet_user__karma")) - ) + ).order_by("-user__wallet_user__karma", "user_organization_link_org__org__created_at") rank_dict = { data["org"]: data["total_karma"] if data["total_karma"] is not None else 0 diff --git a/api/dashboard/profile/profile_serializer.py b/api/dashboard/profile/profile_serializer.py index 4a213502..f75f68c4 100644 --- a/api/dashboard/profile/profile_serializer.py +++ b/api/dashboard/profile/profile_serializer.py @@ -1,5 +1,7 @@ import uuid +from decouple import config as decouple_config +from django.core.files.storage import FileSystemStorage from django.db import transaction from django.db.models import F, Sum, Q from rest_framework import serializers @@ -12,11 +14,10 @@ from utils.permission import JWTUtils from utils.types import OrganizationType, RoleType, MainRoles from utils.utils import DateTimeUtils -from django.core.files.storage import FileSystemStorage -from decouple import config as decouple_config BE_DOMAIN_NAME = decouple_config('BE_DOMAIN_NAME') + class UserLogSerializer(ModelSerializer): task_name = serializers.ReadOnlyField(source="task.title") created_date = serializers.CharField(source="created_at") @@ -26,22 +27,23 @@ class Meta: fields = ["task_name", "karma", "created_date"] -class UserShareQrcode(serializers.ModelSerializer): +class UserShareQrcode(serializers.ModelSerializer): profile_pic = serializers.SerializerMethodField() - class Meta: - model = User - fields = ['profile_pic'] + class Meta: + model = User + fields = ['profile_pic'] - def get_profile_pic(self,obj): + def get_profile_pic(self, obj): fs = FileSystemStorage() path = f'user/qr/{obj.id}.png' if fs.exists(path): qrcode_image = f"{self.context.get('request').build_absolute_uri(BE_DOMAIN_NAME)}{fs.url(path)[1:]}" else: - return None + return None return qrcode_image + class UserProfileSerializer(serializers.ModelSerializer): joined = serializers.DateTimeField(source="created_at") level = serializers.CharField(source="user_lvl_link_user.level.name", default=None) @@ -77,8 +79,8 @@ class Meta: "interest_groups", "is_public", ) - - def get_profile_pic(self,obj): + + def get_profile_pic(self, obj): fs = FileSystemStorage() path = f'user/profile/{obj.id}.png' if fs.exists(path): @@ -86,7 +88,7 @@ def get_profile_pic(self,obj): else: profile_pic = obj.profile_pic return profile_pic - + def get_roles(self, obj): return list({link.role.title for link in obj.user_role_link_user.filter(verified=True)}) @@ -115,6 +117,7 @@ def get_college_code(self, obj): return None def get_rank(self, obj): + roles = self.get_roles(obj) user_karma = obj.wallet_user.karma if RoleType.MENTOR.value in roles: @@ -122,27 +125,35 @@ def get_rank(self, obj): user__user_role_link_user__verified=True, user__user_role_link_user__role__title=RoleType.MENTOR.value, karma__gte=user_karma, - ).count() + ).order_by('-karma', '-updated_at', 'created_at') elif RoleType.ENABLER.value in roles: ranks = Wallet.objects.filter( user__user_role_link_user__verified=True, user__user_role_link_user__role__title=RoleType.ENABLER.value, karma__gte=user_karma, - ).count() + ).order_by('-karma', '-updated_at', 'created_at') else: ranks = ( - Wallet.objects.filter(karma__gte=user_karma) - .exclude( - Q( - user__user_role_link_user__role__title__in=[ - RoleType.ENABLER.value, - RoleType.MENTOR.value, - ] - ) - ) - .count() + Wallet.objects.filter(karma__gte=user_karma).order_by('-karma', '-updated_at', 'created_at') ) - return ranks if ranks > 0 else None + + # ranks = ( + # Wallet.objects.filter(karma__gte=user_karma) + # .exclude( + # Q( + # user__user_role_link_user__role__title__in=[ + # RoleType.ENABLER.value, + # RoleType.MENTOR.value, + # ] + # ) + # ).order_by('-karma') + # ) + + count = 0 + for _rank in ranks: + count += 1 + if obj == _rank.user: + return count def get_karma_distribution(self, obj): return ( @@ -237,7 +248,7 @@ def get_rank(self, obj): ).count() else: ranks = ( - Wallet.objects.filter(karma__gte=user_karma,user__user_role_link_user__verified=True) + Wallet.objects.filter(karma__gte=user_karma, user__user_role_link_user__verified=True) .exclude( Q( user__user_role_link_user__role__title__in=[ @@ -256,6 +267,7 @@ def get_karma(self, obj): def get_interest_groups(self, obj): return [ig_link.ig.name for ig_link in UserIgLink.objects.filter(user=obj)] + # is public true then pass the qrcode vice versa delete the image # another api when passing muid is give its corresponding image is returned class ShareUserProfileUpdateSerializer(ModelSerializer): From f73bd653ad813cca3f7c1c1865504f9dc88bc424 Mon Sep 17 00:00:00 2001 From: Adnan Kattekaden Date: Fri, 1 Dec 2023 03:11:52 +0530 Subject: [PATCH 15/36] rank issue fixed --- api/dashboard/campus/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/dashboard/campus/serializers.py b/api/dashboard/campus/serializers.py index 37acc719..7330bed6 100644 --- a/api/dashboard/campus/serializers.py +++ b/api/dashboard/campus/serializers.py @@ -91,7 +91,7 @@ def get_rank(self, obj): UserOrganizationLink.objects.all() .values("org") .annotate(total_karma=Sum("user__wallet_user__karma")) - ).order_by("-user__wallet_user__karma", "user_organization_link_org__org__created_at") + ).order_by("-user__wallet_user__karma") rank_dict = { data["org"]: data["total_karma"] if data["total_karma"] is not None else 0 From 39d7fbe6f35382e0290feb050211e42df91f9452 Mon Sep 17 00:00:00 2001 From: Adnan Kattekaden Date: Fri, 1 Dec 2023 03:16:11 +0530 Subject: [PATCH 16/36] rank issue fixed --- api/dashboard/campus/serializers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/dashboard/campus/serializers.py b/api/dashboard/campus/serializers.py index 7330bed6..9dcb9c62 100644 --- a/api/dashboard/campus/serializers.py +++ b/api/dashboard/campus/serializers.py @@ -88,10 +88,10 @@ def get_total_karma(self, obj): def get_rank(self, obj): org_karma_dict = ( - UserOrganizationLink.objects.all() + UserOrganizationLink.objects.filter(org__org_type=OrganizationType.COLLEGE.value) .values("org") .annotate(total_karma=Sum("user__wallet_user__karma")) - ).order_by("-user__wallet_user__karma") + ).order_by("-user__wallet_user__karma", "user_organization_link_org__org__created_at") rank_dict = { data["org"]: data["total_karma"] if data["total_karma"] is not None else 0 From 24f7fb46d69e9bc8b75b69e3a810358ff2264e67 Mon Sep 17 00:00:00 2001 From: Adnan Kattekaden Date: Fri, 1 Dec 2023 03:18:38 +0530 Subject: [PATCH 17/36] rank issue new optimised --- api/dashboard/campus/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/dashboard/campus/serializers.py b/api/dashboard/campus/serializers.py index 9dcb9c62..4c94bc3f 100644 --- a/api/dashboard/campus/serializers.py +++ b/api/dashboard/campus/serializers.py @@ -91,7 +91,7 @@ def get_rank(self, obj): UserOrganizationLink.objects.filter(org__org_type=OrganizationType.COLLEGE.value) .values("org") .annotate(total_karma=Sum("user__wallet_user__karma")) - ).order_by("-user__wallet_user__karma", "user_organization_link_org__org__created_at") + ).order_by("-total_karma", "org__created_at") rank_dict = { data["org"]: data["total_karma"] if data["total_karma"] is not None else 0 From 3d72123005b3d3e90eaabceac71fc47996c080e9 Mon Sep 17 00:00:00 2001 From: Adnan Kattekaden Date: Fri, 1 Dec 2023 03:38:07 +0530 Subject: [PATCH 18/36] zonal and district dashboard minor fixes --- .../district/dash_district_serializer.py | 18 +++++++++++------- api/dashboard/district/dash_district_views.py | 7 ++++--- api/dashboard/zonal/dash_zonal_serializer.py | 9 +++++++-- api/dashboard/zonal/dash_zonal_views.py | 11 +++++------ 4 files changed, 27 insertions(+), 18 deletions(-) diff --git a/api/dashboard/district/dash_district_serializer.py b/api/dashboard/district/dash_district_serializer.py index fec03301..c28394b0 100644 --- a/api/dashboard/district/dash_district_serializer.py +++ b/api/dashboard/district/dash_district_serializer.py @@ -1,13 +1,12 @@ from datetime import timedelta -from django.db.models import Sum, Count, Q +from django.db.models import Sum from rest_framework import serializers -from django.db.models import Sum, Count, Q, Case, When, IntegerField - from db.organization import UserOrganizationLink, Organization from db.task import KarmaActivityLog, Level from db.user import User +from utils.types import OrganizationType, RoleType from utils.utils import DateTimeUtils @@ -34,10 +33,10 @@ class Meta: def get_rank(self, obj): org_karma_dict = ( - UserOrganizationLink.objects.all() + UserOrganizationLink.objects.filter(org__org_type=OrganizationType.COLLEGE.value) .values("org__district") .annotate(total_karma=Sum("user__wallet_user__karma")) - ) + ).order_by("-total_karma", "org__created_at") rank_dict = { data["org__district"]: data["total_karma"] @@ -57,18 +56,21 @@ def get_rank(self, obj): def get_district_lead(self, obj): user_org_link = UserOrganizationLink.objects.filter( + org__org_type=OrganizationType.COLLEGE.value, org__district=obj.org.district, - user__user_role_link_user__role__title="District Campus Lead", + user__user_role_link_user__role__title=RoleType.DISTRICT_CAMPUS_LEAD.value, ).first() return user_org_link.user.fullname if user_org_link else None def get_karma(self, obj): return UserOrganizationLink.objects.filter( + org__org_type=OrganizationType.COLLEGE.value, org__district=obj.org.district ).aggregate(total_karma=Sum("user__wallet_user__karma"))["total_karma"] def get_total_members(self, obj): return UserOrganizationLink.objects.filter( + org__org_type=OrganizationType.COLLEGE.value, org__district=obj.org.district ).count() @@ -80,6 +82,7 @@ def get_active_members(self, obj): ) - timedelta(days=1) return KarmaActivityLog.objects.filter( + user__user_organization_link_user__org__org_type=OrganizationType.COLLEGE.value, user__user_organization_link_user__org__district=obj.org.district, created_at__range=(start_date, end_date), ).count() @@ -98,7 +101,7 @@ def get_rank(self, obj): keys_list = list(self.context.get("ranks").keys()) position = keys_list.index(obj.id) return position + 1 - + def get_karma(self, obj): return self.context.get("ranks")[obj.id] @@ -114,6 +117,7 @@ def get_students_count(self, obj): district = self.context.get("district") return ( User.objects.filter( + user_organization_link_user__org__org_type=OrganizationType.COLLEGE.value, user_organization_link_user__org__district=district, user_lvl_link_user__level=obj, ) diff --git a/api/dashboard/district/dash_district_views.py b/api/dashboard/district/dash_district_views.py index 7e238740..956d0d3f 100644 --- a/api/dashboard/district/dash_district_views.py +++ b/api/dashboard/district/dash_district_views.py @@ -41,11 +41,12 @@ def get(self, request): org_karma_dict = ( UserOrganizationLink.objects.filter( + org__org_type=OrganizationType.COLLEGE.value, org__district=user_org_link.org.district, verified=True, ) .values("org") - .annotate(total_karma=Sum("user__wallet_user__karma")) + .annotate(total_karma=Sum("user__wallet_user__karma")).order_by('-total_karma', 'org__created_at') ) org_ranks = { @@ -102,7 +103,7 @@ def get(self, request): user__user_organization_link_user__org__org_type=OrganizationType.COLLEGE.value, ) .distinct() - .order_by("-karma", "-created_at") + .order_by("-karma", '-update_at', "created_at") .values( "user_id", "karma", @@ -164,7 +165,7 @@ def get(self, request): user__user_organization_link_user__org__org_type=OrganizationType.COLLEGE.value, ) .distinct() - .order_by("-karma", "-created_at") + .order_by("-karma", '-updated_at', "created_at") .values( "user_id", "karma", diff --git a/api/dashboard/zonal/dash_zonal_serializer.py b/api/dashboard/zonal/dash_zonal_serializer.py index 7845c920..cf975fde 100644 --- a/api/dashboard/zonal/dash_zonal_serializer.py +++ b/api/dashboard/zonal/dash_zonal_serializer.py @@ -6,6 +6,7 @@ from db.organization import UserOrganizationLink, District from db.task import KarmaActivityLog, Level from db.user import User +from utils.types import OrganizationType from utils.utils import DateTimeUtils @@ -30,10 +31,10 @@ class Meta: def get_rank(self, obj): org_karma_dict = ( - UserOrganizationLink.objects.all() + UserOrganizationLink.objects.filter(org__org_type=OrganizationType.COLLEGE.value) .values("org__district__zone") .annotate(total_karma=Sum("user__wallet_user__karma")) - ) + ).order_by("-total_karma", "org__created_at") rank_dict = { data["org__district__zone"]: data["total_karma"] @@ -53,11 +54,13 @@ def get_rank(self, obj): def get_karma(self, obj): return UserOrganizationLink.objects.filter( + org_org_type=OrganizationType.COLLEGE.value, org__district__zone=obj.org.district.zone, ).aggregate(total_karma=Sum("user__wallet_user__karma"))["total_karma"] def get_total_members(self, obj): return UserOrganizationLink.objects.filter( + org_org_type=OrganizationType.COLLEGE.value, org__district__zone=obj.org.district.zone, ).count() @@ -69,6 +72,7 @@ def get_active_members(self, obj): ) - timedelta(days=1) return KarmaActivityLog.objects.filter( + user__user_organization_link_user__org__org_type=OrganizationType.COLLEGE.value, user__user_organization_link_user__org__district__zone=obj.org.district.zone, created_at__range=(start_date, end_date), ).count() @@ -103,6 +107,7 @@ def get_students_count(self, obj): zone = self.context.get("zone") return ( User.objects.filter( + user__user_organization_link_user__org__org_type=OrganizationType.COLLEGE.value, user_organization_link_user__org__district__zone=zone, user_lvl_link_user__level=obj, ) diff --git a/api/dashboard/zonal/dash_zonal_views.py b/api/dashboard/zonal/dash_zonal_views.py index 74d1f1ea..20b3af2a 100644 --- a/api/dashboard/zonal/dash_zonal_views.py +++ b/api/dashboard/zonal/dash_zonal_views.py @@ -10,7 +10,6 @@ from utils.response import CustomResponse from utils.types import OrganizationType, RoleType from utils.utils import CommonUtils - from . import dash_zonal_helper, dash_zonal_serializer @@ -32,7 +31,7 @@ def get(self, request): class ZonalTopThreeDistrictAPI(APIView): authentication_classes = [CustomizePermission] - @role_required([RoleType.ZONAL_CAMPUS_LEAD.value,]) + @role_required([RoleType.ZONAL_CAMPUS_LEAD.value, ]) def get(self, request): user_id = JWTUtils.fetch_user_id(request) @@ -40,6 +39,7 @@ def get(self, request): district_karma_dict = ( UserOrganizationLink.objects.filter( + org__org_type=OrganizationType.COLLEGE.value, org__district__zone=user_org_link.org.district.zone, verified=True, ) @@ -72,9 +72,8 @@ def get(self, request): class ZonalStudentLevelStatusAPI(APIView): authentication_classes = [CustomizePermission] - @role_required([RoleType.ZONAL_CAMPUS_LEAD.value,]) + @role_required([RoleType.ZONAL_CAMPUS_LEAD.value, ]) def get(self, request): - user_id = JWTUtils.fetch_user_id(request) user_org_link = dash_zonal_helper.get_user_college_link(user_id) @@ -103,7 +102,7 @@ def get(self, request): user__user_organization_link_user__org__org_type=OrganizationType.COLLEGE.value, ) .distinct() - .order_by("-karma", "-created_at") + .order_by("-karma", "-updated_at", "created_at") .values( "user_id", "karma", @@ -165,7 +164,7 @@ def get(self, request): user__user_organization_link_user__org__org_type=OrganizationType.COLLEGE.value, ) .distinct() - .order_by("-karma", "-created_at") + .order_by("-karma", "-updated_at", "created_at") .values( "user_id", "karma", From 15b4262e81297ba51c5efc9e90655b11f2964a93 Mon Sep 17 00:00:00 2001 From: Adnan Kattekaden Date: Fri, 1 Dec 2023 03:49:23 +0530 Subject: [PATCH 19/36] college serializer gte fix --- api/dashboard/college/serializer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/dashboard/college/serializer.py b/api/dashboard/college/serializer.py index 1c1a2936..82575441 100644 --- a/api/dashboard/college/serializer.py +++ b/api/dashboard/college/serializer.py @@ -40,7 +40,7 @@ def get_no_of_alumni(self, obj): def get_no_of_lc(self, obj): learning_circle_count = LearningCircle.objects.filter(org=obj.org).count() no_of_lc_increased = LearningCircle.objects.filter(org=obj.org, - created_at__lte=DateTimeUtils.get_current_utc_time() - timedelta( + created_at__gte=DateTimeUtils.get_current_utc_time() - timedelta( days=30)).count() return {'lc_count': learning_circle_count, 'no_of_lc_increased': no_of_lc_increased} @@ -48,7 +48,7 @@ def get_number_of_members(self, obj): member_count = obj.org.user_organization_link_org.all().count() no_of_members_increased = obj.org.user_organization_link_org.filter( - created_at__lte=DateTimeUtils.get_current_utc_time() - timedelta(days=30) + created_at__gte=DateTimeUtils.get_current_utc_time() - timedelta(days=30) ).count() return {'member_count': member_count, 'no_of_members_increased': no_of_members_increased} From 22ae04fbc89f5fcac2631cd7dc9ec81f1cb5a879 Mon Sep 17 00:00:00 2001 From: Shaheen Hyder K Date: Fri, 1 Dec 2023 11:43:46 +0530 Subject: [PATCH 20/36] (fix): rank logic and karma changed for LC --- api/dashboard/lc/dash_lc_serializer.py | 1 + api/dashboard/profile/profile_serializer.py | 21 ++++++++------------- utils/types.py | 2 +- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/api/dashboard/lc/dash_lc_serializer.py b/api/dashboard/lc/dash_lc_serializer.py index 8560681c..4898e92c 100644 --- a/api/dashboard/lc/dash_lc_serializer.py +++ b/api/dashboard/lc/dash_lc_serializer.py @@ -622,6 +622,7 @@ def validate_attendees(self, attendees): ]) wallet = Wallet.objects.filter(user_id=user).first() wallet.karma += Lc.KARMA.value + wallet.karma_last_update_at = DateTimeUtils.get_current_utc_time() wallet.updated_at = DateTimeUtils.get_current_utc_time() wallet.save() return attendees diff --git a/api/dashboard/profile/profile_serializer.py b/api/dashboard/profile/profile_serializer.py index f75f68c4..6e66e609 100644 --- a/api/dashboard/profile/profile_serializer.py +++ b/api/dashboard/profile/profile_serializer.py @@ -133,22 +133,17 @@ def get_rank(self, obj): karma__gte=user_karma, ).order_by('-karma', '-updated_at', 'created_at') else: + # ranks = ( + # Wallet.objects.filter(karma__gte=user_karma).order_by('-karma', '-updated_at', 'created_at') + # ) + ranks = ( - Wallet.objects.filter(karma__gte=user_karma).order_by('-karma', '-updated_at', 'created_at') + Wallet.objects.filter(karma__gte=user_karma) + .exclude( + Q(user__user_role_link_user__role__title__in=[RoleType.ENABLER.value, RoleType.MENTOR.value]) + ).order_by('-karma') ) - # ranks = ( - # Wallet.objects.filter(karma__gte=user_karma) - # .exclude( - # Q( - # user__user_role_link_user__role__title__in=[ - # RoleType.ENABLER.value, - # RoleType.MENTOR.value, - # ] - # ) - # ).order_by('-karma') - # ) - count = 0 for _rank in ranks: count += 1 diff --git a/utils/types.py b/utils/types.py index 28ff8d05..d89c864c 100644 --- a/utils/types.py +++ b/utils/types.py @@ -113,7 +113,7 @@ def get_all_values(cls): class Lc(Enum): - KARMA = 5 + KARMA = 20 TASK_HASHTAG = '#lcmeetreport' From 1ba1dd9b0df69e693f68c0e7716dc83810caa31b Mon Sep 17 00:00:00 2001 From: anirudh-mk Date: Fri, 1 Dec 2023 16:31:30 +0530 Subject: [PATCH 21/36] feat(lc details api): validation added) --- api/dashboard/lc/dash_lc_serializer.py | 4 +++- api/dashboard/lc/dash_lc_view.py | 27 ++++++++++++++++---------- api/dashboard/lc/urls.py | 6 +++--- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/api/dashboard/lc/dash_lc_serializer.py b/api/dashboard/lc/dash_lc_serializer.py index 4898e92c..3863985d 100644 --- a/api/dashboard/lc/dash_lc_serializer.py +++ b/api/dashboard/lc/dash_lc_serializer.py @@ -307,7 +307,7 @@ def create(self, validated_data): return UserCircleLink.objects.create(**validated_data) -class LearningCircleHomeSerializer(serializers.ModelSerializer): +class LearningCircleDetailsSerializer(serializers.ModelSerializer): college = serializers.CharField(source='org.title', allow_null=True) total_karma = serializers.SerializerMethodField() members = serializers.SerializerMethodField() @@ -317,6 +317,7 @@ class LearningCircleHomeSerializer(serializers.ModelSerializer): is_member = serializers.SerializerMethodField() ig_code = serializers.CharField(source='ig.code') ig_id = serializers.CharField(source='ig.id') + ig_name = serializers.CharField(source='ig.name') previous_meetings = serializers.SerializerMethodField() class Meta: @@ -336,6 +337,7 @@ class Meta: "is_lead", "is_member", "ig_id", + "ig_name", "ig_code", "previous_meetings", ] diff --git a/api/dashboard/lc/dash_lc_view.py b/api/dashboard/lc/dash_lc_view.py index 595aa157..a444ccbd 100644 --- a/api/dashboard/lc/dash_lc_view.py +++ b/api/dashboard/lc/dash_lc_view.py @@ -15,7 +15,7 @@ from utils.permission import JWTUtils from utils.response import CustomResponse from utils.utils import send_template_mail, DateTimeUtils -from .dash_lc_serializer import LearningCircleSerializer, LearningCircleCreateSerializer, LearningCircleHomeSerializer, \ +from .dash_lc_serializer import LearningCircleSerializer, LearningCircleCreateSerializer, LearningCircleDetailsSerializer, \ LearningCircleUpdateSerializer, LearningCircleJoinSerializer, \ LearningCircleMainSerializer, LearningCircleNoteSerializer, LearningCircleDataSerializer, \ LearningCircleMemberListSerializer, MeetRecordsCreateEditDeleteSerializer, IgTaskDetailsSerializer, \ @@ -246,27 +246,34 @@ def post(self, request, circle_id): ).get_failure_response() -class LearningCircleHomeApi(APIView): +class LearningCircleDetailsApi(APIView): def get(self, request, circle_id, member_id=None): user_id = JWTUtils.fetch_user_id(request) - if not LearningCircle.objects.filter( - id=circle_id - ).exists(): + user_circle_link = UserCircleLink.objects.filter( + user_id=user_id, + circle_id=circle_id, + accepted=True + ).first() + + if user_circle_link is None: + return CustomResponse( + general_message='your are not a part of this learning circle circle' + ).get_failure_response() + if not LearningCircle.objects.filter(id=circle_id).exists(): return CustomResponse( general_message='Learning Circle not found' ).get_failure_response() - learning_circle = LearningCircle.objects.filter( - id=circle_id - ).first() + learning_circle = LearningCircle.objects.filter(id=circle_id).first() - serializer = LearningCircleHomeSerializer( + serializer = LearningCircleDetailsSerializer( learning_circle, many=False, context={ - "user_id": user_id + "user_id": user_id, + "circle_id": circle_id } ) diff --git a/api/dashboard/lc/urls.py b/api/dashboard/lc/urls.py index baedd6c1..6b81105a 100644 --- a/api/dashboard/lc/urls.py +++ b/api/dashboard/lc/urls.py @@ -3,8 +3,8 @@ from . import dash_lc_view urlpatterns = [ - path('user-list/', dash_lc_view.UserLearningCircleListApi.as_view(), name='main'), # list all lc's of user - path('/details/', dash_lc_view.LearningCircleHomeApi.as_view(), name='lc-detailed'), # individual ls details + path('user-list/', dash_lc_view.UserLearningCircleListApi.as_view(), name='main'), # list all lc's of user + path('/details/', dash_lc_view.LearningCircleDetailsApi.as_view(), name='lc-detailed'), # individual ls details path('/schedule-meet/', dash_lc_view.ScheduleMeetAPI.as_view(), name='schedule-meet'), path('/report/create/', dash_lc_view.SingleReportDetailAPI.as_view(), name='create-report'), path('/report//show/', dash_lc_view.SingleReportDetailAPI.as_view(), name='show-report'), @@ -19,7 +19,7 @@ # TODO: new api for note updation # path('/note/edit/', dash_lc_view.LearningCircleLeadTransfer.as_view(), name='edit-note'), - path('//', dash_lc_view.LearningCircleHomeApi.as_view()), # user accept or reject, also for removal + path('//', dash_lc_view.LearningCircleDetailsApi.as_view()), # user accept or reject, also for removal path('list/', dash_lc_view.LearningCircleMainApi.as_view(), name='list'), # public page listing path('list-all/', dash_lc_view.TotalLearningCircleListApi.as_view(), name='list-all'), # dashboard search listing path('list-all//', dash_lc_view.TotalLearningCircleListApi.as_view(), name='list-all-search'), # dashboard search listing From 22c43b575c6f0d1988edec3ccc5b4fab8a86af27 Mon Sep 17 00:00:00 2001 From: anirudh-mk Date: Fri, 1 Dec 2023 17:36:13 +0530 Subject: [PATCH 22/36] feat:(lc meet record): meet_time validation added --- api/dashboard/lc/dash_lc_serializer.py | 28 ++++++++++++++- api/dashboard/lc/lc_support_functions.py | 43 ++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 api/dashboard/lc/lc_support_functions.py diff --git a/api/dashboard/lc/dash_lc_serializer.py b/api/dashboard/lc/dash_lc_serializer.py index 3863985d..dad4aaf1 100644 --- a/api/dashboard/lc/dash_lc_serializer.py +++ b/api/dashboard/lc/dash_lc_serializer.py @@ -12,7 +12,7 @@ from utils.types import OrganizationType from utils.utils import DateTimeUtils from utils.types import Lc - +from .lc_support_functions import get_today_start_end, get_week_start_end class LearningCircleSerializer(serializers.ModelSerializer): created_by = serializers.CharField(source='created_by.fullname') @@ -629,6 +629,32 @@ def validate_attendees(self, attendees): wallet.save() return attendees + def validate_meet_time(self, meet_time): + circle_id = self.context.get('circle_id') + + start_of_day, end_of_day = get_today_start_end(meet_time) + start_of_week, end_of_week = get_week_start_end(meet_time) + + if CircleMeetingLog.objects.filter( + circle_id=circle_id, + meet_time__range=( + start_of_day, + end_of_day + ) + ).exists(): + raise serializers.ValidationError(f'Another meet already scheduled on {meet_time.date()}') + + if CircleMeetingLog.objects.filter( + circle_id=circle_id, + meet_time__range=( + start_of_week, + end_of_week + ) + ).count() >= 5: + raise serializers.ValidationError('you can create only 5 meeting in a week') + + return meet_time + class ListAllMeetRecordsSerializer(serializers.ModelSerializer): class Meta: diff --git a/api/dashboard/lc/lc_support_functions.py b/api/dashboard/lc/lc_support_functions.py new file mode 100644 index 00000000..9f5528b4 --- /dev/null +++ b/api/dashboard/lc/lc_support_functions.py @@ -0,0 +1,43 @@ +from datetime import datetime, timedelta + + +def get_today_start_end(date_time): + start_of_day = datetime( + date_time.year, + date_time.month, + date_time.day, + 0, + 0, + 0 + ) + end_of_day = datetime( + date_time.year, + date_time.month, + date_time.day, + 23, + 59, + 59 + ) + timedelta(seconds=1) + + return start_of_day, end_of_day + + +def get_week_start_end(date_time): + monday = date_time.weekday() + + start_of_week = date_time - timedelta(days=monday) + + start_of_week = start_of_week.replace( + hour=0, + minute=0, + second=0, + microsecond=0 + ) + end_of_week = start_of_week + timedelta( + days=6, + hours=23, + minutes=59, + seconds=59 + ) + return start_of_week, end_of_week + From 74319869353c3b9fcf335f52bff352dcfd80f34f Mon Sep 17 00:00:00 2001 From: Adnan Kattekaden Date: Fri, 1 Dec 2023 19:25:56 +0530 Subject: [PATCH 23/36] campus sort fields added --- api/dashboard/campus/campus_views.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/api/dashboard/campus/campus_views.py b/api/dashboard/campus/campus_views.py index 74fc8b3e..9589c3ee 100644 --- a/api/dashboard/campus/campus_views.py +++ b/api/dashboard/campus/campus_views.py @@ -172,7 +172,10 @@ def get(self, request): "karma": "wallet_user__karma", "level": "user_lvl_link_user__level__level_order", # "is_active": "karma_activity_log_user__created_at", - "joined_at": "created_at" + "join_date": "created_at", + "email": "email_", + "mobile": "mobile_", + "is_alumni": "is_alumni", }, ) @@ -281,7 +284,10 @@ def get(self, request): "karma": "wallet_user__karma", "level": "user_lvl_link_user__level__level_order", # "is_active": "karma_activity_log_user__created_at", - "joined_at": "created_at" + "join_date": "created_at", + "email": "email_", + "mobile": "mobile_", + "is_alumni": "is_alumni", }, ) From e16f8e123ca10f5cb260c3012218ccf72bceb944 Mon Sep 17 00:00:00 2001 From: Adnan Kattekaden Date: Fri, 1 Dec 2023 20:20:16 +0530 Subject: [PATCH 24/36] campus csv issue fixed --- api/dashboard/campus/campus_views.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/api/dashboard/campus/campus_views.py b/api/dashboard/campus/campus_views.py index 9589c3ee..c531a0bf 100644 --- a/api/dashboard/campus/campus_views.py +++ b/api/dashboard/campus/campus_views.py @@ -235,6 +235,7 @@ def get(self, request): karma=F("wallet_user__karma"), level=F("user_lvl_link_user__level__name"), join_date=F("created_at"), + last_karma_gained=F("wallet_user__karma_last_update_at"), department=F('user_organization_link_user__department__title'), graduation_year=F("user_organization_link_user__graduation_year"), is_alumni=F('user_organization_link_user__is_alumni'), @@ -268,6 +269,7 @@ def get(self, request): karma=F("wallet_user__karma"), level=F("user_lvl_link_user__level__name"), join_date=F("created_at"), + last_karma_gained=F("wallet_user__karma_last_update_at"), department=F('user_organization_link_user__department__title'), graduation_year=F("user_organization_link_user__graduation_year"), is_alumni=F('user_organization_link_user__is_alumni'), From 281dc42088e22fd9c3cd9e640af3975ffcdb2129 Mon Sep 17 00:00:00 2001 From: Adnan Kattekaden Date: Fri, 1 Dec 2023 20:36:16 +0530 Subject: [PATCH 25/36] campus csv issue fixed --- api/dashboard/campus/campus_views.py | 7 +++---- api/dashboard/campus/serializers.py | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/api/dashboard/campus/campus_views.py b/api/dashboard/campus/campus_views.py index c531a0bf..9b68bb2c 100644 --- a/api/dashboard/campus/campus_views.py +++ b/api/dashboard/campus/campus_views.py @@ -179,10 +179,8 @@ def get(self, request): }, ) - serializer = serializers.CampusStudentDetailsSerializer( - paginated_queryset.get("queryset"), many=True, context={"ranks": ranks} - ) - + serializer = serializers.CampusStudentDetailsSerializer(paginated_queryset.get("queryset"), many=True, + context={"ranks": ranks}) return CustomResponse( response={ "data": serializer.data, @@ -204,6 +202,7 @@ def get(self, request): return CustomResponse( general_message="Campus lead has no college" ).get_failure_response() + if is_alumni: rank = ( Wallet.objects.filter( diff --git a/api/dashboard/campus/serializers.py b/api/dashboard/campus/serializers.py index 4c94bc3f..611bf65f 100644 --- a/api/dashboard/campus/serializers.py +++ b/api/dashboard/campus/serializers.py @@ -122,7 +122,7 @@ class CampusStudentDetailsSerializer(serializers.Serializer): mobile = serializers.CharField() graduation_year = serializers.CharField() department = serializers.CharField() - is_alumni = serializers.CharField() + is_alumni = serializers.BooleanField() class Meta: fields = ("user_id", "email", "mobile", "fullname", "karma", "muid", "rank", "level", "join_date", "is_alumni", From c603cdd43faa1bc2acf5ac0659351f7a553b08fd Mon Sep 17 00:00:00 2001 From: Adnan Kattekaden Date: Fri, 1 Dec 2023 22:48:04 +0530 Subject: [PATCH 26/36] Lc enrollment api --- api/common/common_views.py | 175 ++++++++++++++++++++++++++++++++++--- api/common/serializer.py | 13 +++ api/common/urls.py | 2 + utils/utils.py | 48 +++++----- 4 files changed, 206 insertions(+), 32 deletions(-) diff --git a/api/common/common_views.py b/api/common/common_views.py index a0356eaf..6d3fc49e 100644 --- a/api/common/common_views.py +++ b/api/common/common_views.py @@ -1,8 +1,8 @@ import json -import requests + import requests from django.db import models -from django.db.models import Count, Subquery, OuterRef +from django.db.models import Subquery, OuterRef from django.db.models import Sum, F, Case, When, Value, CharField, Count, Q from django.db.models.functions import Coalesce from rest_framework.views import APIView @@ -15,7 +15,7 @@ from utils.response import CustomResponse from utils.types import IntegrationType, OrganizationType, RoleType from utils.utils import CommonUtils -from .serializer import StudentInfoSerializer, CollegeInfoSerializer +from .serializer import StudentInfoSerializer, CollegeInfoSerializer, LearningCircleEnrollmentSerializer class LcDashboardAPI(APIView): @@ -23,7 +23,9 @@ def get(self, request): date = request.query_params.get("date") if date: learning_circle_count = LearningCircle.objects.filter(created_at__gt=date).count() - total_no_enrollment = UserCircleLink.objects.filter(accepted=True, created_at__gt=date).count() + total_no_enrollment = UserCircleLink.objects.filter(accepted=True, + user__user_organization_link_user__org__org_type=OrganizationType.COLLEGE.value, + created_at__gt=date).count() user_circle_link_count = UserCircleLink.objects.filter(created_at__gt=date, circle=OuterRef('pk')).values( 'circle_id').annotate( total_users=Count('id')).values('total_users') @@ -49,7 +51,8 @@ def get(self, request): ) else: learning_circle_count = LearningCircle.objects.all().count() - total_no_enrollment = UserCircleLink.objects.filter(accepted=True).count() + total_no_enrollment = UserCircleLink.objects.filter(accepted=True, + user__user_organization_link_user__org__org_type=OrganizationType.COLLEGE.value).count() user_circle_link_count = UserCircleLink.objects.filter(circle=OuterRef('pk')).values('circle_id').annotate( total_users=Count('id')).values('total_users') @@ -154,7 +157,7 @@ def get(self, request): paginated_queryset = CommonUtils.get_paginated_queryset( student_info, request, - search_fields=["first_name", "last_name", "muid", "circle_name", 'circle_ig', "organisation", "dwms_id", + search_fields=["first_name", "last_name", "muid", "circle_name", 'circle_ig', "organisation", "karma_earned"], sort_fields={"first_name": "first_name", "last_name": "last_name", "muid": "muid", "circle_name": "circle_name", @@ -216,14 +219,22 @@ def get(self, request): LearningCircle.objects.filter(org__org_type=OrganizationType.COLLEGE.value) .values(org_title=F("org__title")) .annotate( - learning_circle_count=Count("id"), user_count=Count("usercirclelink") + learning_circle_count=Count("id"), user_count=Count("user_circle_link_circle") ) .order_by("org_title") ) + paginated_queryset = CommonUtils.get_paginated_queryset( + learning_circles_info, + request, + search_fields=["org_title", "learning_circle_count", "user_count"], + sort_fields={"org_title": "org_title", "learning_circle_count": "learning_circle_count", + "user_count": "user_count"}, + is_pagination=False + ) - learning_circles_info = CollegeInfoSerializer(learning_circles_info, many=True).data + lc_report = CollegeInfoSerializer(paginated_queryset, many=True).data - return CommonUtils.generate_csv(learning_circles_info, "Learning Circle Report") + return CommonUtils.generate_csv(lc_report, "Learning Circle Report") class CollegeWiseLcReport(APIView): @@ -263,6 +274,149 @@ def get(self, request): ) +class HackathonDataAPI(APIView): + + def get(self, request): + hackathon_data = { + 'hackathons': { + 'Beyond Us': { + "Domain": ["Software", "Design (UI,UX)"], + "total_applicants_registered": 374, + "short_listed_candidates": 231, + "total_teams_shortlisted": {"total": 58, "domains": {"Software": 40, "Design (UI,UX)": 18}}, + "no_of_offer_given": {'count': 1, "status": "Offer Rejected by the candidate"}, + "no_of_placements": {"count": 0, "status": None}, + "attended_people": None, + "hackathon_type": "Online", + "location": "Discord" + }, + 'GTA: CodeStorm': { + "Domain": ["Software", "Design (UI/UX)", "Hardware", "Civil"], + "total_applicants_registered": 451, + "short_listed_candidates": 202, + "total_teams_shortlisted": {"total": 62, + "domains": {"Software": 18, "Design (UI/UX)": 17, "Hardware": 18, + "Civil": 9}}, + "no_of_offer_given": {'count': 15, "status": "5 Rejected by the candidates"}, + "no_of_placements": {'count': 10, "status": "2 Full time positions + 8 full time internships"}, + "attended_people": 168, + "hackathon_type": "Offline", + "location": "Kochi", + }, + 'GTA: SandShores': { + "Domain": ["Web Development", "App Development", "AI/ML", "AR/VR"], + "total_applicants_registered": 1765, + "short_listed_candidates": 120, + "total_teams_shortlisted": {"total": 29, + "domains": {"Web Development": 12, "App Development": 7, "AI/ML": 7, + "AR/VR": 3}}, + "no_of_offer_given": {'count': 0, "status": "In Progress"}, + "no_of_placements": {'count': 0, "status": "In Progress"}, + "attended_people": None, + "hackathon_type": "Offline", + "location": "Thrissur", + }, + } + } + pass + + +class LearningCircleEnrollment(APIView): + + def get(self, request): + total_no_enrollment = (UserCircleLink.objects.filter(accepted=True, + user__user_organization_link_user__org__org_type=OrganizationType.COLLEGE.value).values( + first_name=F("user__first_name"), + last_name=F("user__last_name"), + email=F("user__email"), + muid=F("user__muid"), + circle_name=F("circle__name"), + district=F("user__user_organization_link_user__org__district__name"), + circle_ig=F("circle__ig__name"), + organisation=F("user__user_organization_link_user__org__title"), + + ) + .annotate( + karma_earned=Sum( + "user__karma_activity_log_user__task__karma", + filter=Q( + user__karma_activity_log_user__task__ig=F("circle__ig") + ), + ), + dwms_id=Case( + When( + user__integration_authorization_user__integration__name=IntegrationType.KKEM.value, + then=F( + "user__integration_authorization_user__additional_field" + ), + ), + default=Value(None, output_field=CharField()), + output_field=CharField(), + ), + ) + ) + paginated_queryset = CommonUtils.get_paginated_queryset( + total_no_enrollment, + request, + search_fields=["first_name", "last_name", "email", "muid", "circle_name", "district", "circle_ig", + "organisation", "karma_earned"], + sort_fields={"first_name": "first_name", "last_name": "last_name", "email": "email", "muid": "muid", + "circle_name": "circle_name", "district": "district", "circle_ig": "circle_ig", + "organisation": "organisation", "dwms_id": "dwms_id", "karma_earned": "karma_earned"}, + is_pagination=False) + lc_enrollment = LearningCircleEnrollmentSerializer(paginated_queryset, many=True).data + + return CustomResponse(response=lc_enrollment).get_success_response() + + +class LearningCircleEnrollmentCSV(APIView): + def get(self, request): + total_no_enrollment = (UserCircleLink.objects.filter(accepted=True, + user__user_organization_link_user__org__org_type=OrganizationType.COLLEGE.value).values( + first_name=F("user__first_name"), + last_name=F("user__last_name"), + email=F("user__email"), + muid=F("user__muid"), + circle_name=F("circle__name"), + district=F("user__user_organization_link_user__org__district__name"), + circle_ig=F("circle__ig__name"), + organisation=F("user__user_organization_link_user__org__title"), + + ) + .annotate( + karma_earned=Sum( + "user__karma_activity_log_user__task__karma", + filter=Q( + user__karma_activity_log_user__task__ig=F("circle__ig") + ), + ), + dwms_id=Case( + When( + user__integration_authorization_user__integration__name=IntegrationType.KKEM.value, + then=F( + "user__integration_authorization_user__additional_field" + ), + ), + default=Value(None, output_field=CharField()), + output_field=CharField(), + ), + ) + ) + paginated_queryset = CommonUtils.get_paginated_queryset( + total_no_enrollment, + request, + search_fields=["first_name", "last_name", "email", "muid", "circle_name", "district", "circle_ig", + "organisation", "karma_earned"], + sort_fields={"first_name": "first_name", "last_name": "last_name", "email": "email", "muid": "muid", + "circle_name": "circle_name", "district": "district", "circle_ig": "circle_ig", + "organisation": "organisation", "dwms_id": "dwms_id", "karma_earned": "karma_earned"}, + is_pagination=False) + + lc_enrollment = LearningCircleEnrollmentSerializer(paginated_queryset, many=True).data + + return CommonUtils.generate_csv(lc_enrollment, "Learning Enrollment Report") + + class GlobalCountAPI(APIView): def get(self, request): members_count = User.objects.all().count() @@ -361,7 +515,8 @@ def get(self, request): userid_list = [entry['userid'] for entry in user_karma_by_ig] # Fetch user muid and interest group as a list - results = UserIgLink.objects.filter(user__id__in=userid_list).values_list('user__muid', 'ig__name', named=True) + results = UserIgLink.objects.filter(user__id__in=userid_list).values_list('user__muid', 'ig__name', + named=True) # Process the results to create the desired structure user_ig_dict = {} diff --git a/api/common/serializer.py b/api/common/serializer.py index 092a184b..248516e5 100644 --- a/api/common/serializer.py +++ b/api/common/serializer.py @@ -16,3 +16,16 @@ class CollegeInfoSerializer(serializers.Serializer): org_title = serializers.CharField() learning_circle_count = serializers.CharField() user_count = serializers.CharField() + + +class LearningCircleEnrollmentSerializer(serializers.Serializer): + first_name = serializers.CharField() + last_name = serializers.CharField() + muid = serializers.CharField() + email = serializers.CharField() + dwms_id = serializers.CharField(allow_null=True) + circle_name = serializers.CharField() + circle_ig = serializers.CharField() + organisation = serializers.CharField() + district = serializers.CharField(allow_null=True) + karma_earned = serializers.IntegerField() diff --git a/api/common/urls.py b/api/common/urls.py index 032e102d..df276c79 100644 --- a/api/common/urls.py +++ b/api/common/urls.py @@ -8,6 +8,8 @@ path('college-wise-lc-report/', common_views.CollegeWiseLcReport.as_view()), path('college-wise-lc-report/csv/', common_views.CollegeWiseLcReportCSV.as_view()), path('lc-report/csv/', common_views.LcReportDownloadAPI.as_view()), + path('lc-enrollment/', common_views.LearningCircleEnrollment.as_view()), + path('lc-enrollment/csv/', common_views.LearningCircleEnrollmentCSV.as_view()), path('global-count/', common_views.GlobalCountAPI.as_view()), path('gta-sandshore/', common_views.GTASANDSHOREAPI.as_view()), path('profile-pic//', common_views.UserProfilePicAPI.as_view()), diff --git a/utils/utils.py b/utils/utils.py index 3866f87d..2849ea92 100644 --- a/utils/utils.py +++ b/utils/utils.py @@ -17,11 +17,12 @@ from django.http import HttpResponse from django.template.loader import render_to_string + class CommonUtils: @staticmethod def get_paginated_queryset( - queryset: QuerySet, request, search_fields, sort_fields: dict = None - ) -> QuerySet: + queryset: QuerySet, request, search_fields, sort_fields: dict = None, + is_pagination: bool = True) -> QuerySet: if sort_fields is None: sort_fields = {} @@ -44,27 +45,29 @@ def get_paginated_queryset( sort_field_name = f"-{sort_field_name}" queryset = queryset.order_by(sort_field_name) + if is_pagination: + paginator = Paginator(queryset, per_page) + try: + queryset = paginator.page(page) + except PageNotAnInteger: + queryset = paginator.page(1) + except EmptyPage: + queryset = paginator.page(paginator.num_pages) + + return { + "queryset": queryset, + "pagination": { + "count": paginator.count, + "totalPages": paginator.num_pages, + "isNext": queryset.has_next(), + "isPrev": queryset.has_previous(), + "nextPage": queryset.next_page_number() + if queryset.has_next() + else None, + }, + } - paginator = Paginator(queryset, per_page) - try: - queryset = paginator.page(page) - except PageNotAnInteger: - queryset = paginator.page(1) - except EmptyPage: - queryset = paginator.page(paginator.num_pages) - - return { - "queryset": queryset, - "pagination": { - "count": paginator.count, - "totalPages": paginator.num_pages, - "isNext": queryset.has_next(), - "isPrev": queryset.has_previous(), - "nextPage": queryset.next_page_number() - if queryset.has_next() - else None, - }, - } + return queryset @staticmethod def generate_csv(queryset: QuerySet, csv_name: str) -> HttpResponse: @@ -172,6 +175,7 @@ def read_excel_file(self, file_obj): return rows + def send_template_mail( context: dict, subject: str, address: list[str], attachment: str = None): """ From 509543a4635bcad609adecb3835293a79f39f351 Mon Sep 17 00:00:00 2001 From: Ajay Vishnu E Date: Sat, 2 Dec 2023 01:17:53 +0530 Subject: [PATCH 27/36] events table and crud --- api/dashboard/events/events_serializer.py | 36 +++++++++ api/dashboard/events/events_views.py | 98 +++++++++++++++++++++++ api/dashboard/events/urls.py | 9 +++ api/dashboard/urls.py | 3 +- db/task.py | 15 ++++ 5 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 api/dashboard/events/events_serializer.py create mode 100644 api/dashboard/events/events_views.py create mode 100644 api/dashboard/events/urls.py diff --git a/api/dashboard/events/events_serializer.py b/api/dashboard/events/events_serializer.py new file mode 100644 index 00000000..bdf18e82 --- /dev/null +++ b/api/dashboard/events/events_serializer.py @@ -0,0 +1,36 @@ +import uuid +from rest_framework import serializers +from db.task import Events +from utils.utils import DateTimeUtils + + +class EventsListSerializer(serializers.ModelSerializer): + created_by = serializers.CharField(source="created_by.fullname") + updated_by = serializers.CharField(source="updated_by.fullname") + + class Meta: + model = Events + fields = "__all__" + +class EventsCUDSerializer(serializers.ModelSerializer): + class Meta: + model = Events + fields = ['name'] + + def create(self, validated_data): + user_id = self.context.get("user_id") + + validated_data["created_by_id"] = user_id + validated_data["updated_by_id"] = user_id + validated_data["id"] = uuid.uuid4() + return Events.objects.create(**validated_data) + + def update(self, instance, validated_data): + user_id = self.context.get("user_id") + + instance.name = validated_data.get("name", instance.name) + instance.updated_by_id = user_id + instance.updated_at = DateTimeUtils.get_current_utc_time() + instance.save() + + return instance \ No newline at end of file diff --git a/api/dashboard/events/events_views.py b/api/dashboard/events/events_views.py new file mode 100644 index 00000000..bf34a4d0 --- /dev/null +++ b/api/dashboard/events/events_views.py @@ -0,0 +1,98 @@ +from rest_framework.views import APIView +from utils.permission import CustomizePermission, JWTUtils, role_required +from utils.response import CustomResponse +from utils.types import RoleType +from utils.utils import CommonUtils +from .events_serializer import EventsCUDSerializer, EventsListSerializer +from db.task import Events + + +class EventAPI(APIView): + authentication_classes = [CustomizePermission] + + def get(self, request): + events = Events.objects.all() + paginated_queryset = CommonUtils.get_paginated_queryset( + events, + request, + ['id', 'name'] + ) + + serializer = EventsListSerializer( + paginated_queryset.get("queryset"), + many=True + ) + + return CustomResponse().paginated_response( + data=serializer.data, + pagination=paginated_queryset.get( + "pagination" + ) + ) + + + def post(self, request): + user_id = JWTUtils.fetch_user_id(request) + + serializer = EventsCUDSerializer( + data=request.data, + context={ + "user_id": user_id, + } + ) + + if serializer.is_valid(): + serializer.save() + + return CustomResponse( + general_message=f"{request.data.get('name')} Event created successfully", + response=serializer.data + ).get_success_response() + + return CustomResponse( + general_message=serializer.errors, + ).get_failure_response() + + + def put(self, request, event_id): + user_id = JWTUtils.fetch_user_id(request) + + events = Events.objects.filter(id=event_id).first() + + if events is None: + return CustomResponse( + general_message="Invalid Event id" + ).get_failure_response() + + serializer = EventsCUDSerializer( + events, + data=request.data, + context={"user_id": user_id} + ) + + if serializer.is_valid(): + serializer.save() + + return CustomResponse( + general_message=f"{events.name} Edited Successfully" + ).get_success_response() + + return CustomResponse( + message=serializer.errors + ).get_failure_response() + + + def delete(self, request, event_id): + + events = Events.objects.filter(id=event_id).first() + + if events is None: + return CustomResponse( + general_message="Invalid event id" + ).get_failure_response() + + events.delete() + + return CustomResponse( + general_message=f"{events.name} Deleted Successfully" + ).get_success_response() \ No newline at end of file diff --git a/api/dashboard/events/urls.py b/api/dashboard/events/urls.py new file mode 100644 index 00000000..c9c36f2d --- /dev/null +++ b/api/dashboard/events/urls.py @@ -0,0 +1,9 @@ +from django.urls import path + +from . import events_views + +urlpatterns = [ + path('', events_views.EventAPI.as_view()), + path('/', events_views.EventAPI.as_view()), + +] \ No newline at end of file diff --git a/api/dashboard/urls.py b/api/dashboard/urls.py index 7632000b..797c97a2 100644 --- a/api/dashboard/urls.py +++ b/api/dashboard/urls.py @@ -20,6 +20,7 @@ path('error-log/', include('api.dashboard.error_log.urls')), path('affiliation/',include('api.dashboard.affiliation.urls')), path('channels/',include('api.dashboard.channels.urls')), - path('discord-moderator/',include('api.dashboard.discord_moderator.urls')) + path('discord-moderator/',include('api.dashboard.discord_moderator.urls')), + path('events/',include('api.dashboard.events.urls')) ] diff --git a/db/task.py b/db/task.py index 729fdc29..6a4f594b 100644 --- a/db/task.py +++ b/db/task.py @@ -238,3 +238,18 @@ class VoucherLog(models.Model): class Meta: managed = False db_table = "voucher_log" + + +class Events(models.Model): + id = models.CharField(primary_key=True, max_length=36, default=uuid.uuid4) + name = models.CharField(max_length=75) + updated_by = models.ForeignKey(User, on_delete=models.CASCADE, db_column="updated_by", + related_name="event_updated_by") + updated_at = models.DateTimeField(auto_now=True) + created_by = models.ForeignKey(User, on_delete=models.CASCADE, db_column="created_by", + related_name="event_created_by") + created_at = models.DateTimeField(auto_now_add=True) + + class Meta: + managed = False + db_table = "events" From 31b26840c86a08a455f1f7d1e896e7727f3c94a5 Mon Sep 17 00:00:00 2001 From: Adnan Kattekaden Date: Sat, 2 Dec 2023 03:09:52 +0530 Subject: [PATCH 28/36] rank count optimised --- api/dashboard/profile/profile_serializer.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/api/dashboard/profile/profile_serializer.py b/api/dashboard/profile/profile_serializer.py index 6e66e609..ff1682f1 100644 --- a/api/dashboard/profile/profile_serializer.py +++ b/api/dashboard/profile/profile_serializer.py @@ -133,10 +133,6 @@ def get_rank(self, obj): karma__gte=user_karma, ).order_by('-karma', '-updated_at', 'created_at') else: - # ranks = ( - # Wallet.objects.filter(karma__gte=user_karma).order_by('-karma', '-updated_at', 'created_at') - # ) - ranks = ( Wallet.objects.filter(karma__gte=user_karma) .exclude( @@ -144,9 +140,7 @@ def get_rank(self, obj): ).order_by('-karma') ) - count = 0 - for _rank in ranks: - count += 1 + for count, _rank in enumerate(ranks, start=0): if obj == _rank.user: return count From f933571bda5c8756a9db2b994eab875b13cf5686 Mon Sep 17 00:00:00 2001 From: Adnan Kattekaden Date: Sat, 2 Dec 2023 04:29:50 +0530 Subject: [PATCH 29/36] percentaile --- api/dashboard/profile/profile_serializer.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/api/dashboard/profile/profile_serializer.py b/api/dashboard/profile/profile_serializer.py index ff1682f1..c80f425f 100644 --- a/api/dashboard/profile/profile_serializer.py +++ b/api/dashboard/profile/profile_serializer.py @@ -57,6 +57,7 @@ class UserProfileSerializer(serializers.ModelSerializer): interest_groups = serializers.SerializerMethodField() org_district_id = serializers.SerializerMethodField() profile_pic = serializers.SerializerMethodField() + percentile = serializers.SerializerMethodField() class Meta: model = User @@ -78,8 +79,19 @@ class Meta: "profile_pic", "interest_groups", "is_public", + "percentile", ) + def get_percentile(self, obj): + try: + user_count = Wallet.objects.filter(karma__lt=obj.wallet_user.karma).count() + usr_count = User.objects.all().count() + if usr_count == 0: + return 0 + return (user_count * 100) / usr_count + except Exception as e: + return 0 + def get_profile_pic(self, obj): fs = FileSystemStorage() path = f'user/profile/{obj.id}.png' From 17c77a8d3836ed8ce486719fc83458937ddb10dc Mon Sep 17 00:00:00 2001 From: Adnan Kattekaden Date: Sat, 2 Dec 2023 04:36:58 +0530 Subject: [PATCH 30/36] wallet field updated accoding to alter script 1.37 --- db/task.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/task.py b/db/task.py index 6a4f594b..6b30c785 100644 --- a/db/task.py +++ b/db/task.py @@ -130,7 +130,7 @@ class Wallet(models.Model): id = models.CharField(primary_key=True, max_length=36, default=uuid.uuid4) user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="wallet_user") karma = models.IntegerField(default=0) - karma_last_update_at = models.DateTimeField(blank=True, null=True, auto_now=True) + karma_last_updated_at = models.DateTimeField(blank=True, null=True, auto_now=True) coin = models.FloatField(default=0) updated_by = models.ForeignKey(User, on_delete=models.CASCADE, db_column="updated_by", related_name="wallet_updated_by") From a09a1e96bcdc0448163cc0d8cae5968fc7057838 Mon Sep 17 00:00:00 2001 From: Ajay Vishnu E Date: Sat, 2 Dec 2023 16:04:00 +0530 Subject: [PATCH 31/36] affiliation and org edits --- api/dashboard/affiliation/serializers.py | 8 +++++++- api/dashboard/organisation/serializers.py | 7 +++++-- db/organization.py | 4 ++-- mulearnbackend/settings.py | 2 +- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/api/dashboard/affiliation/serializers.py b/api/dashboard/affiliation/serializers.py index 9abb3c62..b615bde1 100644 --- a/api/dashboard/affiliation/serializers.py +++ b/api/dashboard/affiliation/serializers.py @@ -8,10 +8,16 @@ class AffiliationListSerializer(serializers.ModelSerializer): created_by = serializers.CharField(source="created_by.fullname") updated_by = serializers.CharField(source="updated_by.fullname") + organization_count = serializers.SerializerMethodField() class Meta: model = OrgAffiliation - fields = "__all__" + fields = ['id','title','organization_count', 'created_by', 'updated_by'] + + def get_organization_count(self,obj): + return obj.organizations.count() + + class AffiliationCUDSerializer(serializers.ModelSerializer): class Meta: diff --git a/api/dashboard/organisation/serializers.py b/api/dashboard/organisation/serializers.py index c72159d0..13e55c81 100644 --- a/api/dashboard/organisation/serializers.py +++ b/api/dashboard/organisation/serializers.py @@ -13,6 +13,7 @@ Department, OrgKarmaType, OrgKarmaLog, + College ) from utils.permission import JWTUtils from utils.types import OrganizationType @@ -114,8 +115,10 @@ def create(self, validated_data): validated_data["id"] = str(uuid.uuid4()) validated_data["created_by_id"] = user_id validated_data["updated_by_id"] = user_id - - return Organization.objects.create(**validated_data) + orgobj = Organization.objects.create(**validated_data) + if validated_data.get("org_type") == OrganizationType.COLLEGE.value: + College.objects.create(org = orgobj, created_by_id=user_id, updated_by_id = user_id ) + return orgobj def update(self, instance, validated_data): user_id = self.context.get("user_id") diff --git a/db/organization.py b/db/organization.py index b8bb19d7..f41fc6c2 100644 --- a/db/organization.py +++ b/db/organization.py @@ -91,7 +91,7 @@ class Organization(models.Model): title = models.CharField(max_length=100) code = models.CharField(unique=True, max_length=12) org_type = models.CharField(max_length=25) - affiliation = models.ForeignKey(OrgAffiliation, on_delete=models.CASCADE, blank=True, null=True) + affiliation = models.ForeignKey(OrgAffiliation, on_delete=models.CASCADE, blank=True, null=True, related_name='organizations') district = models.ForeignKey(District, on_delete=models.CASCADE, related_name='organization_district') updated_by = models.ForeignKey(User, on_delete=models.CASCADE, db_column='updated_by', related_name='organization_updated_by') @@ -122,7 +122,7 @@ class Meta: class College(models.Model): id = models.CharField(primary_key=True, max_length=36, default=uuid.uuid4()) - level = models.IntegerField() + level = models.IntegerField(default=1) org = models.OneToOneField(Organization, on_delete=models.CASCADE, related_name='college_org', unique=True) updated_by = models.ForeignKey(User, on_delete=models.CASCADE, db_column='updated_by', related_name='college_updated_by') diff --git a/mulearnbackend/settings.py b/mulearnbackend/settings.py index 4d43d0e1..774d6404 100644 --- a/mulearnbackend/settings.py +++ b/mulearnbackend/settings.py @@ -57,7 +57,7 @@ "debug_toolbar.middleware.DebugToolbarMiddleware", "django.middleware.common.CommonMiddleware", "corsheaders.middleware.CorsMiddleware", - # "mulearnbackend.middlewares.UniversalErrorHandlerMiddleware", + "mulearnbackend.middlewares.UniversalErrorHandlerMiddleware", ] ROOT_URLCONF = "mulearnbackend.urls" From 093a81b0384e24f239458f1a6b0a81ece530d9b9 Mon Sep 17 00:00:00 2001 From: Ajay Vishnu E Date: Sat, 2 Dec 2023 16:14:26 +0530 Subject: [PATCH 32/36] affiliation and org edits --- db/organization.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/organization.py b/db/organization.py index f41fc6c2..5a35fd6e 100644 --- a/db/organization.py +++ b/db/organization.py @@ -91,7 +91,7 @@ class Organization(models.Model): title = models.CharField(max_length=100) code = models.CharField(unique=True, max_length=12) org_type = models.CharField(max_length=25) - affiliation = models.ForeignKey(OrgAffiliation, on_delete=models.CASCADE, blank=True, null=True, related_name='organizations') + affiliation = models.ForeignKey(OrgAffiliation, on_delete=models.CASCADE, blank=True, null=True, related_name='organization_affiliation') district = models.ForeignKey(District, on_delete=models.CASCADE, related_name='organization_district') updated_by = models.ForeignKey(User, on_delete=models.CASCADE, db_column='updated_by', related_name='organization_updated_by') From cf8b2357241553b450f658ccb9b1d78292241172 Mon Sep 17 00:00:00 2001 From: Ajay Vishnu E Date: Sat, 2 Dec 2023 16:19:50 +0530 Subject: [PATCH 33/36] affiliation and org edits --- db/organization.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/organization.py b/db/organization.py index 5a35fd6e..2a3def18 100644 --- a/db/organization.py +++ b/db/organization.py @@ -122,7 +122,7 @@ class Meta: class College(models.Model): id = models.CharField(primary_key=True, max_length=36, default=uuid.uuid4()) - level = models.IntegerField(default=1) + level = models.IntegerField(default=0) org = models.OneToOneField(Organization, on_delete=models.CASCADE, related_name='college_org', unique=True) updated_by = models.ForeignKey(User, on_delete=models.CASCADE, db_column='updated_by', related_name='college_updated_by') From 4cdc6a9c445a81c518e32f1fd28ec52fb18be678 Mon Sep 17 00:00:00 2001 From: anirudh-mk Date: Sat, 2 Dec 2023 16:54:21 +0530 Subject: [PATCH 34/36] feat:(lc):ValidateUserMeetCreateAPI, helper function name changed validation function added in helper file --- ...support_functions.py => dash_ig_helper.py} | 23 +++++++ api/dashboard/lc/dash_lc_serializer.py | 3 +- api/dashboard/lc/dash_lc_view.py | 66 +++++++++++++++---- api/dashboard/lc/urls.py | 1 + 4 files changed, 81 insertions(+), 12 deletions(-) rename api/dashboard/lc/{lc_support_functions.py => dash_ig_helper.py} (61%) diff --git a/api/dashboard/lc/lc_support_functions.py b/api/dashboard/lc/dash_ig_helper.py similarity index 61% rename from api/dashboard/lc/lc_support_functions.py rename to api/dashboard/lc/dash_ig_helper.py index 9f5528b4..9128069e 100644 --- a/api/dashboard/lc/lc_support_functions.py +++ b/api/dashboard/lc/dash_ig_helper.py @@ -1,5 +1,7 @@ from datetime import datetime, timedelta +from db.learning_circle import UserCircleLink, LearningCircle + def get_today_start_end(date_time): start_of_day = datetime( @@ -41,3 +43,24 @@ def get_week_start_end(date_time): ) return start_of_week, end_of_week + +def is_learning_circle_member(user_id, circle_id): + user_circle_link = UserCircleLink.objects.filter( + user_id=user_id, + circle_id=circle_id, + accepted=True + ).exists() + + if user_circle_link: + return True + return False + + +def is_valid_learning_circle(circle_id): + learning_circle = LearningCircle.objects.filter( + id=circle_id + ).exists() + + if learning_circle: + return True + return False diff --git a/api/dashboard/lc/dash_lc_serializer.py b/api/dashboard/lc/dash_lc_serializer.py index dad4aaf1..7a2fda4c 100644 --- a/api/dashboard/lc/dash_lc_serializer.py +++ b/api/dashboard/lc/dash_lc_serializer.py @@ -12,7 +12,8 @@ from utils.types import OrganizationType from utils.utils import DateTimeUtils from utils.types import Lc -from .lc_support_functions import get_today_start_end, get_week_start_end +from .dash_ig_helper import get_today_start_end, get_week_start_end + class LearningCircleSerializer(serializers.ModelSerializer): created_by = serializers.CharField(source='created_by.fullname') diff --git a/api/dashboard/lc/dash_lc_view.py b/api/dashboard/lc/dash_lc_view.py index a444ccbd..6181ed36 100644 --- a/api/dashboard/lc/dash_lc_view.py +++ b/api/dashboard/lc/dash_lc_view.py @@ -21,6 +21,8 @@ LearningCircleMemberListSerializer, MeetRecordsCreateEditDeleteSerializer, IgTaskDetailsSerializer, \ ScheduleMeetingSerializer, ListAllMeetRecordsSerializer, AddMemberSerializer +from .dash_ig_helper import is_learning_circle_member, is_valid_learning_circle, get_today_start_end, get_week_start_end + domain = config("FR_DOMAIN_NAME") from_mail = config("FROM_MAIL") @@ -250,23 +252,19 @@ class LearningCircleDetailsApi(APIView): def get(self, request, circle_id, member_id=None): user_id = JWTUtils.fetch_user_id(request) - user_circle_link = UserCircleLink.objects.filter( - user_id=user_id, - circle_id=circle_id, - accepted=True - ).first() - - if user_circle_link is None: + if not is_valid_learning_circle(circle_id): return CustomResponse( - general_message='your are not a part of this learning circle circle' + general_message='invalid learning circle' ).get_failure_response() - if not LearningCircle.objects.filter(id=circle_id).exists(): + if not is_learning_circle_member(user_id, circle_id): return CustomResponse( - general_message='Learning Circle not found' + general_message='unauthorized access' ).get_failure_response() - learning_circle = LearningCircle.objects.filter(id=circle_id).first() + learning_circle = LearningCircle.objects.filter( + id=circle_id + ).first() serializer = LearningCircleDetailsSerializer( learning_circle, @@ -719,3 +717,49 @@ def post(self, request, circle_id): return CustomResponse( message=serializer.errors ).get_failure_response() + + +class ValidateUserMeetCreateAPI(APIView): + def get(self, request, circle_id): + user_id = JWTUtils.fetch_user_id(request) + + if not is_valid_learning_circle(circle_id): + return CustomResponse( + general_message='invalid learning circle' + ).get_failure_response() + + if not is_learning_circle_member(user_id, circle_id): + return CustomResponse( + general_message='unauthorized access' + ).get_failure_response() + + today_date_time = DateTimeUtils.get_current_utc_time() + + start_of_day, end_of_day = get_today_start_end(today_date_time) + start_of_week, end_of_week = get_week_start_end(today_date_time) + + if CircleMeetingLog.objects.filter( + circle_id=circle_id, + meet_time__range=( + start_of_day, + end_of_day + ) + ).exists(): + return CustomResponse( + general_message=f'Another meet already scheduled on {today_date_time.date()}' + ).get_failure_response() + + if CircleMeetingLog.objects.filter( + circle_id=circle_id, + meet_time__range=( + start_of_week, + end_of_week + ) + ).count() >= 5: + return CustomResponse( + general_message='you can create only 5 meeting in a week' + ).get_failure_response() + + return CustomResponse( + general_message='success' + ).get_success_response() diff --git a/api/dashboard/lc/urls.py b/api/dashboard/lc/urls.py index 6b81105a..88002558 100644 --- a/api/dashboard/lc/urls.py +++ b/api/dashboard/lc/urls.py @@ -7,6 +7,7 @@ path('/details/', dash_lc_view.LearningCircleDetailsApi.as_view(), name='lc-detailed'), # individual ls details path('/schedule-meet/', dash_lc_view.ScheduleMeetAPI.as_view(), name='schedule-meet'), path('/report/create/', dash_lc_view.SingleReportDetailAPI.as_view(), name='create-report'), + path('/report/create/validate/', dash_lc_view.ValidateUserMeetCreateAPI.as_view(), name='validate-report'), path('/report//show/', dash_lc_view.SingleReportDetailAPI.as_view(), name='show-report'), path('/add-member/', dash_lc_view.AddMemberAPI.as_view(), name='add-member'), path('create/', dash_lc_view.LearningCircleCreateApi.as_view(), name='create'), From 3567e1ef5d79e803d5ed4a1fca16ffb491ff11e8 Mon Sep 17 00:00:00 2001 From: Ajay Vishnu E Date: Sat, 2 Dec 2023 18:07:58 +0530 Subject: [PATCH 35/36] event description added --- api/dashboard/events/events_serializer.py | 2 +- db/task.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/api/dashboard/events/events_serializer.py b/api/dashboard/events/events_serializer.py index bdf18e82..6220693f 100644 --- a/api/dashboard/events/events_serializer.py +++ b/api/dashboard/events/events_serializer.py @@ -15,7 +15,7 @@ class Meta: class EventsCUDSerializer(serializers.ModelSerializer): class Meta: model = Events - fields = ['name'] + fields = ['name', 'description'] def create(self, validated_data): user_id = self.context.get("user_id") diff --git a/db/task.py b/db/task.py index 6b30c785..a8c524af 100644 --- a/db/task.py +++ b/db/task.py @@ -243,6 +243,7 @@ class Meta: class Events(models.Model): id = models.CharField(primary_key=True, max_length=36, default=uuid.uuid4) name = models.CharField(max_length=75) + description = models.CharField(max_length=200, null=True) updated_by = models.ForeignKey(User, on_delete=models.CASCADE, db_column="updated_by", related_name="event_updated_by") updated_at = models.DateTimeField(auto_now=True) From d89f7123942511bc2afb41d9d42ba613a68cb502 Mon Sep 17 00:00:00 2001 From: anirudh-mk Date: Sat, 2 Dec 2023 18:17:10 +0530 Subject: [PATCH 36/36] fix(lc list api): list api url issue --- api/dashboard/lc/urls.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/api/dashboard/lc/urls.py b/api/dashboard/lc/urls.py index 88002558..970ec5f4 100644 --- a/api/dashboard/lc/urls.py +++ b/api/dashboard/lc/urls.py @@ -4,7 +4,10 @@ urlpatterns = [ path('user-list/', dash_lc_view.UserLearningCircleListApi.as_view(), name='main'), # list all lc's of user + # URL issue + path('list-all//', dash_lc_view.TotalLearningCircleListApi.as_view(), name='list-all-search'), path('/details/', dash_lc_view.LearningCircleDetailsApi.as_view(), name='lc-detailed'), # individual ls details + # dashboard search listing path('/schedule-meet/', dash_lc_view.ScheduleMeetAPI.as_view(), name='schedule-meet'), path('/report/create/', dash_lc_view.SingleReportDetailAPI.as_view(), name='create-report'), path('/report/create/validate/', dash_lc_view.ValidateUserMeetCreateAPI.as_view(), name='validate-report'), @@ -23,7 +26,6 @@ path('//', dash_lc_view.LearningCircleDetailsApi.as_view()), # user accept or reject, also for removal path('list/', dash_lc_view.LearningCircleMainApi.as_view(), name='list'), # public page listing path('list-all/', dash_lc_view.TotalLearningCircleListApi.as_view(), name='list-all'), # dashboard search listing - path('list-all//', dash_lc_view.TotalLearningCircleListApi.as_view(), name='list-all-search'), # dashboard search listing # path('data/', dash_lc_view.LearningCircleDataAPI.as_view(), name='data'), # path('list-members//', dash_lc_view.LearningCircleListMembersApi.as_view(), name='list-members'),