From 2d7152f27e0a8830cc12116d6f7ce9008375bdf4 Mon Sep 17 00:00:00 2001 From: jelanmathewjames <72068016+jelanmathewjames@users.noreply.github.com> Date: Fri, 3 Nov 2023 22:51:02 +0530 Subject: [PATCH 01/32] changing routing import after django setup --- mulearnbackend/asgi.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mulearnbackend/asgi.py b/mulearnbackend/asgi.py index b72de73d..16ed8083 100644 --- a/mulearnbackend/asgi.py +++ b/mulearnbackend/asgi.py @@ -14,11 +14,11 @@ from channels.routing import ProtocolTypeRouter, URLRouter -from .routing import urlpatterns - os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mulearnbackend.settings') django.setup() +from .routing import urlpatterns + application = ProtocolTypeRouter({ 'http': get_asgi_application(), 'websocket': URLRouter( From 75c9512333f5c3e208ccba92771f63d8ed153269 Mon Sep 17 00:00:00 2001 From: Muhammed Zafar Date: Sat, 4 Nov 2023 02:27:24 +0530 Subject: [PATCH 02/32] [PATCH] Minor patch --- api/dashboard/organisation/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/dashboard/organisation/serializers.py b/api/dashboard/organisation/serializers.py index a665a281..bbe869e2 100644 --- a/api/dashboard/organisation/serializers.py +++ b/api/dashboard/organisation/serializers.py @@ -256,7 +256,7 @@ class OrganizationMergerSerializer(serializers.Serializer): }, ) - def validate_source_code(self, attrs): + def validate_source_org(self, attrs): if self.instance.code == attrs.code: raise serializers.ValidationError( "You can't merge an organization into itself." From 3177cc5b5a33dfcea2d458ef28d5749aacafe09d Mon Sep 17 00:00:00 2001 From: anirudh-mk Date: Sat, 4 Nov 2023 17:36:40 +0530 Subject: [PATCH 03/32] optim:LearningCircleMainApi --- api/dashboard/lc/dash_lc_serializer.py | 100 ++++++++++++------------- api/dashboard/lc/dash_lc_view.py | 67 +++++++++-------- 2 files changed, 80 insertions(+), 87 deletions(-) diff --git a/api/dashboard/lc/dash_lc_serializer.py b/api/dashboard/lc/dash_lc_serializer.py index e2f246cd..e56a2bee 100644 --- a/api/dashboard/lc/dash_lc_serializer.py +++ b/api/dashboard/lc/dash_lc_serializer.py @@ -43,6 +43,52 @@ def get_member_count(self, obj): ).count() +class LearningCircleMainSerializer(serializers.ModelSerializer): + ig_name = serializers.CharField(source='ig.name') + member_count = serializers.SerializerMethodField() + members = serializers.SerializerMethodField() + lead_name = serializers.SerializerMethodField() + + class Meta: + model = LearningCircle + fields = [ + 'name', + 'ig_name', + 'member_count', + 'members', + 'meet_place', + 'meet_time', + 'lead_name' + ] + + def get_lead_name(self, obj): + user_circle_link = obj.user_circle_link_circle.filter( + circle=obj, + accepted=1, + lead=True + ).first() + + return user_circle_link.user.fullname if user_circle_link else None + + def get_member_count(self, obj): + return obj.user_circle_link_circle.filter( + circle=obj, + accepted=1 + ).count() + + def get_members(self, obj): + user_circle_link = obj.user_circle_link_circle.filter( + circle=obj, + accepted=1 + ) + return [ + { + 'username': f'{member.user.fullname}' + } + for member in user_circle_link + ] + + class LearningCircleCreateSerializer(serializers.ModelSerializer): class Meta: @@ -391,60 +437,6 @@ def update(self, instance, validated_data): return instance -class LearningCircleMainSerializer(serializers.ModelSerializer): - ig_name = serializers.SerializerMethodField() - member_count = serializers.SerializerMethodField() - members = serializers.SerializerMethodField() - lead_name = serializers.SerializerMethodField() - - class Meta: - model = LearningCircle - fields = [ - 'name', - 'ig_name', - 'member_count', - 'members', - 'meet_place', - 'meet_time', - 'lead_name' - ] - - def get_lead_name(self, obj): - user_circle_link = UserCircleLink.objects.filter( - circle=obj, - accepted=1, - lead=True - ).first() - - if user_circle_link: - user = user_circle_link.user - return f'{user.first_name} {user.last_name}' - return None - - def get_ig_name(self, obj): - return obj.ig.name if obj.ig else None - - def get_member_count(self, obj): - return UserCircleLink.objects.filter( - circle=obj, - accepted=1 - ).count() - - def get_members(self, obj): - members = UserCircleLink.objects.filter( - circle=obj, - accepted=1 - ) - return [ - { - 'username': f'{member.user.first_name} {member.user.last_name}' - if member.user.last_name - else member.user.first_name, - } - for member in members - ] - - class LearningCircleDataSerializer(serializers.ModelSerializer): interest_group = serializers.SerializerMethodField() college = serializers.SerializerMethodField() diff --git a/api/dashboard/lc/dash_lc_view.py b/api/dashboard/lc/dash_lc_view.py index c6cdd00a..d884ca10 100644 --- a/api/dashboard/lc/dash_lc_view.py +++ b/api/dashboard/lc/dash_lc_view.py @@ -50,6 +50,40 @@ def get(self, request): # Lists user's learning circle ).get_success_response() +class LearningCircleMainApi(APIView): + def post(self, request): + all_circles = LearningCircle.objects.all() + ig_id = request.data.get('ig_id') + org_id = request.data.get('org_id') + district_id = request.data.get('district_id') + + if district_id: + all_circles = all_circles.filter(org__district_id=district_id) + + if org_id: + all_circles = all_circles.filter(org_id=org_id) + + if ig_id: + all_circles = all_circles.filter(ig_id=ig_id) + + if ig_id or org_id or district_id: + serializer = LearningCircleMainSerializer( + all_circles, + many=True + ) + else: + random_circles = all_circles.order_by('?')[:9] + + serializer = LearningCircleMainSerializer( + random_circles, + many=True + ) + + return CustomResponse( + response=serializer.data + ).get_success_response() + + class TotalLearningCircleListApi(APIView): def post(self, request, circle_code=None): user_id = JWTUtils.fetch_user_id(request) @@ -409,39 +443,6 @@ def delete(self, request, circle_id): return CustomResponse(general_message='Left').get_success_response() -class LearningCircleMainApi(APIView): - def post(self, request): - all_circles = LearningCircle.objects.all() - ig_id = request.data.get('ig_id') - org_id = request.data.get('org_id') - district_id = request.data.get('district_id') - - if district_id: - all_circles = all_circles.filter(org__district_id=district_id) - - if org_id: - all_circles = all_circles.filter(org_id=org_id) - - if ig_id: - all_circles = all_circles.filter(ig_id=ig_id) - - if ig_id or org_id or district_id: - serializer = LearningCircleMainSerializer( - all_circles, - many=True - ) - else: - random_circles = all_circles.order_by('?')[:9] - - serializer = LearningCircleMainSerializer( - random_circles, - many=True - ) - - return CustomResponse( - response=serializer.data - ).get_success_response() - class LearningCircleDataAPI(APIView): """ From 13f6d633e415adee7ede8d9db8695a6361d16a16 Mon Sep 17 00:00:00 2001 From: anirudh-mk Date: Sat, 4 Nov 2023 18:05:20 +0530 Subject: [PATCH 04/32] optim:LearningCircleDataAPI --- api/dashboard/lc/dash_lc_serializer.py | 56 +++++++++++++------------- api/dashboard/lc/dash_lc_view.py | 47 +++++++++++---------- 2 files changed, 51 insertions(+), 52 deletions(-) diff --git a/api/dashboard/lc/dash_lc_serializer.py b/api/dashboard/lc/dash_lc_serializer.py index e56a2bee..70cdcfd1 100644 --- a/api/dashboard/lc/dash_lc_serializer.py +++ b/api/dashboard/lc/dash_lc_serializer.py @@ -89,6 +89,34 @@ def get_members(self, obj): ] +class LearningCircleDataSerializer(serializers.ModelSerializer): + interest_group = serializers.SerializerMethodField() + college = serializers.SerializerMethodField() + learning_circle = serializers.SerializerMethodField() + total_no_of_users = serializers.SerializerMethodField() + + class Meta: + model = LearningCircle + fields = [ + "interest_group", + "college", + "learning_circle", + "total_no_of_users" + ] + + def get_interest_group(self, obj): + return obj.values('ig_id').distinct().count() + + def get_total_no_of_users(self, obj): + return UserCircleLink.objects.all().count() + + def get_learning_circle(self, obj): + return obj.count() + + def get_college(self, obj): + return obj.values('org_id').distinct().count() + + class LearningCircleCreateSerializer(serializers.ModelSerializer): class Meta: @@ -437,34 +465,6 @@ def update(self, instance, validated_data): return instance -class LearningCircleDataSerializer(serializers.ModelSerializer): - interest_group = serializers.SerializerMethodField() - college = serializers.SerializerMethodField() - learning_circle = serializers.SerializerMethodField() - total_no_of_users = serializers.SerializerMethodField() - - class Meta: - model = LearningCircle - fields = [ - "interest_group", - "college", - "learning_circle", - "total_no_of_users" - ] - - def get_total_no_of_users(self, obj): - return UserCircleLink.objects.all().count() - - def get_learning_circle(self, obj): - return LearningCircle.objects.all().count() - - def get_college(self, obj): - return LearningCircle.objects.values('org_id').distinct().count() - - def get_interest_group(self, obj): - return LearningCircle.objects.values('ig_id').distinct().count() - - class LearningCircleMemberlistSerializer(serializers.ModelSerializer): members = serializers.SerializerMethodField() diff --git a/api/dashboard/lc/dash_lc_view.py b/api/dashboard/lc/dash_lc_view.py index d884ca10..50ad2bbc 100644 --- a/api/dashboard/lc/dash_lc_view.py +++ b/api/dashboard/lc/dash_lc_view.py @@ -84,6 +84,29 @@ def post(self, request): ).get_success_response() +class LearningCircleDataAPI(APIView): + """ + API endpoint for retrieving basic data about all learning circles. + + Endpoint: /api/v1/dashboard/lc/data/ (GET) + + Returns: + CustomResponse: A custom response containing data about all learning circles. + """ + + def get(self, request): + learning_circle = LearningCircle.objects.all() + + serializer = LearningCircleDataSerializer( + learning_circle, + many=False + ) + + return CustomResponse( + response=serializer.data + ).get_success_response() + + class TotalLearningCircleListApi(APIView): def post(self, request, circle_code=None): user_id = JWTUtils.fetch_user_id(request) @@ -443,30 +466,6 @@ def delete(self, request, circle_id): return CustomResponse(general_message='Left').get_success_response() - -class LearningCircleDataAPI(APIView): - """ - API endpoint for retrieving basic data about all learning circles. - - Endpoint: /api/v1/dashboard/lc/data/ (GET) - - Returns: - CustomResponse: A custom response containing data about all learning circles. - """ - - def get(self, request): - all_circles = LearningCircle.objects.all() - - serializer = LearningCircleDataSerializer( - all_circles, - many=False - ) - - return CustomResponse( - response=serializer.data - ).get_success_response() - - class LearningCircleListMembersApi(APIView): def get(self, request, circle_id): learning_circle = LearningCircle.objects.filter( From e9f04d3a81271329abf4e7c798b71d35f730ddfb Mon Sep 17 00:00:00 2001 From: anirudh-mk Date: Sat, 4 Nov 2023 19:11:43 +0530 Subject: [PATCH 05/32] optim:LearningCircleListMembersApi --- api/dashboard/lc/dash_lc_serializer.py | 96 +++++++++++++------------- api/dashboard/lc/dash_lc_view.py | 44 ++++++------ 2 files changed, 70 insertions(+), 70 deletions(-) diff --git a/api/dashboard/lc/dash_lc_serializer.py b/api/dashboard/lc/dash_lc_serializer.py index 70cdcfd1..03231ff9 100644 --- a/api/dashboard/lc/dash_lc_serializer.py +++ b/api/dashboard/lc/dash_lc_serializer.py @@ -89,34 +89,6 @@ def get_members(self, obj): ] -class LearningCircleDataSerializer(serializers.ModelSerializer): - interest_group = serializers.SerializerMethodField() - college = serializers.SerializerMethodField() - learning_circle = serializers.SerializerMethodField() - total_no_of_users = serializers.SerializerMethodField() - - class Meta: - model = LearningCircle - fields = [ - "interest_group", - "college", - "learning_circle", - "total_no_of_users" - ] - - def get_interest_group(self, obj): - return obj.values('ig_id').distinct().count() - - def get_total_no_of_users(self, obj): - return UserCircleLink.objects.all().count() - - def get_learning_circle(self, obj): - return obj.count() - - def get_college(self, obj): - return obj.values('org_id').distinct().count() - - class LearningCircleCreateSerializer(serializers.ModelSerializer): class Meta: @@ -215,6 +187,54 @@ def create(self, validated_data): return lc +class LearningCircleMemberListSerializer(serializers.ModelSerializer): + members = serializers.SerializerMethodField() + + class Meta: + model = LearningCircle + fields = [ + 'members', + ] + + def get_members(self, obj): + user_circle_link = obj.user_circle_link_circle.filter(circle=obj, accepted=True) + return [ + { + 'full_name': f'{member.user.fullname}', + 'discord_id': member.user.discord_id, + } + for member in user_circle_link + ] + + +class LearningCircleDataSerializer(serializers.ModelSerializer): + interest_group = serializers.SerializerMethodField() + college = serializers.SerializerMethodField() + learning_circle = serializers.SerializerMethodField() + total_no_of_users = serializers.SerializerMethodField() + + class Meta: + model = LearningCircle + fields = [ + "interest_group", + "college", + "learning_circle", + "total_no_of_users" + ] + + def get_interest_group(self, obj): + return obj.values('ig_id').distinct().count() + + def get_total_no_of_users(self, obj): + return UserCircleLink.objects.all().count() + + def get_learning_circle(self, obj): + return obj.count() + + def get_college(self, obj): + return obj.values('org_id').distinct().count() + + class LearningCircleHomeSerializer(serializers.ModelSerializer): college = serializers.CharField(source='org.title', allow_null=True) total_karma = serializers.SerializerMethodField() @@ -465,26 +485,6 @@ def update(self, instance, validated_data): return instance -class LearningCircleMemberlistSerializer(serializers.ModelSerializer): - members = serializers.SerializerMethodField() - - class Meta: - model = LearningCircle - fields = [ - 'members', - ] - - def get_members(self, obj): - members = UserCircleLink.objects.filter(circle=obj, accepted=True) - return [ - { - 'full_name': f'{member.user.first_name} {member.user.last_name}' if member.user.last_name else member.user.first_name, - 'discord_id': member.user.discord_id, - } - for member in members - ] - - class MeetCreateEditDeleteSerializer(serializers.ModelSerializer): class Meta: diff --git a/api/dashboard/lc/dash_lc_view.py b/api/dashboard/lc/dash_lc_view.py index 50ad2bbc..c71df9b5 100644 --- a/api/dashboard/lc/dash_lc_view.py +++ b/api/dashboard/lc/dash_lc_view.py @@ -16,7 +16,7 @@ from .dash_lc_serializer import LearningCircleSerializer, LearningCircleCreateSerializer, LearningCircleHomeSerializer, \ LearningCircleUpdateSerializer, LearningCircleJoinSerializer, LearningCircleCreateEditDeleteSerializer, \ LearningCircleMainSerializer, LearningCircleNoteSerializer, LearningCircleDataSerializer, \ - LearningCircleMemberlistSerializer, MeetCreateEditDeleteSerializer + LearningCircleMemberListSerializer, MeetCreateEditDeleteSerializer domain = config("FR_DOMAIN_NAME") from_mail = config("FROM_MAIL") @@ -180,6 +180,27 @@ def post(self, request): ).get_failure_response() +class LearningCircleListMembersApi(APIView): + def get(self, request, circle_id): + learning_circle = LearningCircle.objects.filter( + id=circle_id + ) + + if learning_circle is None: + return CustomResponse( + general_message='Learning Circle Not Exists' + ).get_failure_response() + + serializer = LearningCircleMemberListSerializer( + learning_circle, + many=True + ) + + return CustomResponse( + response=serializer.data + ).get_success_response() + + class LearningCircleJoinApi(APIView): def post(self, request, circle_id): user_id = JWTUtils.fetch_user_id(request) @@ -466,27 +487,6 @@ def delete(self, request, circle_id): return CustomResponse(general_message='Left').get_success_response() -class LearningCircleListMembersApi(APIView): - def get(self, request, circle_id): - learning_circle = LearningCircle.objects.filter( - id=circle_id - ) - - if learning_circle is None: - return CustomResponse( - general_message='Learning Circle Not Exists' - ).get_failure_response() - - serializer = LearningCircleMemberlistSerializer( - learning_circle, - many=True - ) - - return CustomResponse( - response=serializer.data - ).get_success_response() - - class LearningCircleInviteLeadAPI(APIView): def post(self, request): From 189ded7d768b9c289a4762903bbfd085d4e8fdc6 Mon Sep 17 00:00:00 2001 From: anirudh-mk Date: Sat, 4 Nov 2023 19:26:01 +0530 Subject: [PATCH 06/32] optim:LearningCircleJoinSerializer --- api/dashboard/lc/dash_lc_serializer.py | 78 ++++++++++++------- api/dashboard/lc/dash_lc_view.py | 102 +++++++++++++------------ 2 files changed, 101 insertions(+), 79 deletions(-) diff --git a/api/dashboard/lc/dash_lc_serializer.py b/api/dashboard/lc/dash_lc_serializer.py index 03231ff9..46030ba9 100644 --- a/api/dashboard/lc/dash_lc_serializer.py +++ b/api/dashboard/lc/dash_lc_serializer.py @@ -207,6 +207,55 @@ def get_members(self, obj): ] +class LearningCircleJoinSerializer(serializers.ModelSerializer): + class Meta: + model = UserCircleLink + fields = [] + + def create(self, validated_data): + user_id = self.context.get('user_id') + circle_id = self.context.get('circle_id') + no_of_entry = UserCircleLink.objects.filter( + circle_id=circle_id, + accepted=True + ).count() + + ig_id = LearningCircle.objects.get(pk=circle_id).ig_id + + if entry := UserCircleLink.objects.filter( + circle_id=circle_id, + user_id=user_id + ).first(): + + raise serializers.ValidationError( + "Cannot send another request at the moment" + ) + + if UserCircleLink.objects.filter( + user_id=user_id, + circle_id__ig_id=ig_id, + accepted=True + ).exists(): + + raise serializers.ValidationError( + "Already a member of learning circle with same interest group" + ) + + if no_of_entry >= 5: + raise serializers.ValidationError( + "Maximum member count reached" + ) + + validated_data['id'] = uuid.uuid4() + validated_data['user_id'] = user_id + validated_data['circle_id'] = circle_id + validated_data['lead'] = False + validated_data['accepted'] = None + validated_data['accepted_at'] = None + validated_data['created_at'] = DateTimeUtils.get_current_utc_time() + return UserCircleLink.objects.create(**validated_data) + + class LearningCircleDataSerializer(serializers.ModelSerializer): interest_group = serializers.SerializerMethodField() college = serializers.SerializerMethodField() @@ -396,35 +445,6 @@ def get_previous_meetings(self, obj): return previous_meetings -class LearningCircleJoinSerializer(serializers.ModelSerializer): - class Meta: - model = UserCircleLink - fields = [] - - def create(self, validated_data): - user_id = self.context.get('user_id') - circle_id = self.context.get('circle_id') - no_of_entry = UserCircleLink.objects.filter(circle_id=circle_id, accepted=True).count() - ig_id = LearningCircle.objects.get(pk=circle_id).ig_id - if entry := UserCircleLink.objects.filter( - circle_id=circle_id, user_id=user_id - ).first(): - raise serializers.ValidationError("Cannot send another request at the moment") - if UserCircleLink.objects.filter(user_id=user_id, circle_id__ig_id=ig_id, accepted=True).exists(): - raise serializers.ValidationError("Already a member of learning circle with same interest group") - if no_of_entry >= 5: - raise serializers.ValidationError("Maximum member count reached") - - validated_data['id'] = uuid.uuid4() - validated_data['user_id'] = user_id - validated_data['circle_id'] = circle_id - validated_data['lead'] = False - validated_data['accepted'] = None - validated_data['accepted_at'] = None - validated_data['created_at'] = DateTimeUtils.get_current_utc_time() - return UserCircleLink.objects.create(**validated_data) - - class LearningCircleUpdateSerializer(serializers.ModelSerializer): is_accepted = serializers.BooleanField() diff --git a/api/dashboard/lc/dash_lc_view.py b/api/dashboard/lc/dash_lc_view.py index c71df9b5..6be0a8ab 100644 --- a/api/dashboard/lc/dash_lc_view.py +++ b/api/dashboard/lc/dash_lc_view.py @@ -107,6 +107,52 @@ def get(self, request): ).get_success_response() +class LearningCircleCreateApi(APIView): + def post(self, request): + user_id = JWTUtils.fetch_user_id(request) + + serializer = LearningCircleCreateSerializer( + data=request.data, + context={ + 'user_id': user_id + } + ) + if serializer.is_valid(): + circle = serializer.save() + + return CustomResponse( + general_message='LearningCircle created successfully', + response={ + 'circle_id': circle.id + } + ).get_success_response() + + return CustomResponse( + message=serializer.errors + ).get_failure_response() + + +class LearningCircleListMembersApi(APIView): + def get(self, request, circle_id): + learning_circle = LearningCircle.objects.filter( + id=circle_id + ) + + if learning_circle is None: + return CustomResponse( + general_message='Learning Circle Not Exists' + ).get_failure_response() + + serializer = LearningCircleMemberListSerializer( + learning_circle, + many=True + ) + + return CustomResponse( + response=serializer.data + ).get_success_response() + + class TotalLearningCircleListApi(APIView): def post(self, request, circle_code=None): user_id = JWTUtils.fetch_user_id(request) @@ -155,60 +201,14 @@ def post(self, request, circle_code=None): ).get_success_response() -class LearningCircleCreateApi(APIView): - def post(self, request): - user_id = JWTUtils.fetch_user_id(request) - - serializer = LearningCircleCreateSerializer( - data=request.data, - context={ - 'user_id': user_id - } - ) - if serializer.is_valid(): - circle = serializer.save() - - return CustomResponse( - general_message='LearningCircle created successfully', - response={ - 'circle_id': circle.id - } - ).get_success_response() - - return CustomResponse( - message=serializer.errors - ).get_failure_response() - - -class LearningCircleListMembersApi(APIView): - def get(self, request, circle_id): - learning_circle = LearningCircle.objects.filter( - id=circle_id - ) - - if learning_circle is None: - return CustomResponse( - general_message='Learning Circle Not Exists' - ).get_failure_response() - - serializer = LearningCircleMemberListSerializer( - learning_circle, - many=True - ) - - return CustomResponse( - response=serializer.data - ).get_success_response() - - class LearningCircleJoinApi(APIView): def post(self, request, circle_id): user_id = JWTUtils.fetch_user_id(request) user = User.objects.filter(id=user_id).first() - full_name = f'{user.first_name} {user.last_name}' if user.last_name else user.first_name + full_name = f'{user.fullname}' - lc = UserCircleLink.objects.filter( + user_learning_circle = UserCircleLink.objects.filter( circle_id=circle_id, lead=True ).first() @@ -222,10 +222,12 @@ def post(self, request, circle_id): ) if serializer.is_valid(): serializer.save() - lead_obj = User.objects.filter(id=lc.user.id).first() + user = User.objects.filter( + id=user_learning_circle.user.id + ).first() NotificationUtils.insert_notification( - user=lead_obj, + user=user, title="Member Request", description=f"{full_name} has requested to join your learning circle", button="LC", From d3ced798192db87a7636249c4a1f74e179ecd8f4 Mon Sep 17 00:00:00 2001 From: anirudh-mk Date: Sat, 4 Nov 2023 21:26:14 +0530 Subject: [PATCH 07/32] optim:LearningCircleHomeSerializer --- api/dashboard/lc/dash_lc_serializer.py | 92 ++++++------- api/dashboard/lc/dash_lc_view.py | 180 ++++++++++++------------- 2 files changed, 132 insertions(+), 140 deletions(-) diff --git a/api/dashboard/lc/dash_lc_serializer.py b/api/dashboard/lc/dash_lc_serializer.py index 46030ba9..bd43bb8c 100644 --- a/api/dashboard/lc/dash_lc_serializer.py +++ b/api/dashboard/lc/dash_lc_serializer.py @@ -256,34 +256,6 @@ def create(self, validated_data): return UserCircleLink.objects.create(**validated_data) -class LearningCircleDataSerializer(serializers.ModelSerializer): - interest_group = serializers.SerializerMethodField() - college = serializers.SerializerMethodField() - learning_circle = serializers.SerializerMethodField() - total_no_of_users = serializers.SerializerMethodField() - - class Meta: - model = LearningCircle - fields = [ - "interest_group", - "college", - "learning_circle", - "total_no_of_users" - ] - - def get_interest_group(self, obj): - return obj.values('ig_id').distinct().count() - - def get_total_no_of_users(self, obj): - return UserCircleLink.objects.all().count() - - def get_learning_circle(self, obj): - return obj.count() - - def get_college(self, obj): - return obj.values('org_id').distinct().count() - - class LearningCircleHomeSerializer(serializers.ModelSerializer): college = serializers.CharField(source='org.title', allow_null=True) total_karma = serializers.SerializerMethodField() @@ -317,27 +289,19 @@ class Meta: def get_is_member(self, obj): user = self.context.get('user_id') - try: - if link := UserCircleLink.objects.get( - user=user, - circle=obj, - accepted=True - ): - return True - except UserCircleLink.DoesNotExist: - return False + return obj.user_circle_link_circle.filter( + user=user, + circle=obj, + accepted=True + ).exists() def get_is_lead(self, obj): user = self.context.get('user_id') - try: - if link := UserCircleLink.objects.get( - user=user, - circle=obj, - lead=True - ): - return True - except UserCircleLink.DoesNotExist: - return False + return obj.user_circle_link_circle.filter( + user=user, + circle=obj, + lead=True + ).exists() def get_total_karma(self, obj): return ( @@ -359,10 +323,12 @@ def get_pending_members(self, obj): return self._get_member_info(obj, accepted=None) def _get_member_info(self, obj, accepted): - members = UserCircleLink.objects.filter( + + members = obj.user_circle_link_circle.filter( circle=obj, accepted=accepted ) + member_info = [] for member in members: @@ -377,9 +343,7 @@ def _get_member_info(self, obj, accepted): member_info.append({ 'id': member.user.id, - 'username': f'{member.user.first_name} {member.user.last_name}' - if member.user.last_name - else member.user.first_name, + 'username': f'{member.user.fullname}', 'profile_pic': member.user.profile_pic or None, 'karma': total_ig_karma, 'is_lead': member.lead, @@ -445,6 +409,34 @@ def get_previous_meetings(self, obj): return previous_meetings +class LearningCircleDataSerializer(serializers.ModelSerializer): + interest_group = serializers.SerializerMethodField() + college = serializers.SerializerMethodField() + learning_circle = serializers.SerializerMethodField() + total_no_of_users = serializers.SerializerMethodField() + + class Meta: + model = LearningCircle + fields = [ + "interest_group", + "college", + "learning_circle", + "total_no_of_users" + ] + + def get_interest_group(self, obj): + return obj.values('ig_id').distinct().count() + + def get_total_no_of_users(self, obj): + return UserCircleLink.objects.all().count() + + def get_learning_circle(self, obj): + return obj.count() + + def get_college(self, obj): + return obj.values('org_id').distinct().count() + + class LearningCircleUpdateSerializer(serializers.ModelSerializer): is_accepted = serializers.BooleanField() diff --git a/api/dashboard/lc/dash_lc_view.py b/api/dashboard/lc/dash_lc_view.py index 6be0a8ab..96558920 100644 --- a/api/dashboard/lc/dash_lc_view.py +++ b/api/dashboard/lc/dash_lc_view.py @@ -244,96 +244,6 @@ def post(self, request, circle_id): ).get_failure_response() -class MeetCreateEditDeleteAPI(APIView): - - def post(self, request, circle_id): - user_id = JWTUtils.fetch_user_id(request) - - serializer = MeetCreateEditDeleteSerializer( - data=request.data, - context={ - 'user_id': user_id, - 'circle_id': circle_id - } - ) - if serializer.is_valid(): - circle_meet_log = serializer.save() - - return CustomResponse( - general_message=f'Meet scheduled at {circle_meet_log.meet_time}' - ).get_success_response() - - return CustomResponse( - message=serializer.errors - ).get_failure_response() - - def patch(self, request, circle_id): - user_id = JWTUtils.fetch_user_id(request) - - learning_circle = LearningCircle.objects.filter( - id=circle_id - ).first() - - serializer = MeetCreateEditDeleteSerializer( - learning_circle, - data=request.data, - context={ - 'user_id': user_id - } - ) - if serializer.is_valid(): - serializer.save() - - return CustomResponse( - general_message='Meet updated successfully' - ).get_success_response() - - return CustomResponse( - message=serializer.errors - ).get_failure_response() - - -class LearningCircleLeadTransfer(APIView): - def patch(self, request, circle_id, lead_id): - user_id = JWTUtils.fetch_user_id(request) - - usr_circle_link = UserCircleLink.objects.filter( - circle__id=circle_id, - user__id=user_id - ).first() - - lead_circle_link = UserCircleLink.objects.filter( - circle__id=circle_id, - user__id=lead_id - ).first() - - if not LearningCircle.objects.filter( - id=circle_id - ).exists(): - - return CustomResponse( - general_message='Learning Circle not found' - ).get_failure_response() - - if usr_circle_link is None or usr_circle_link.lead != 1: - return CustomResponse( - general_message='User is not lead' - ).get_failure_response() - - if lead_circle_link is None: - return CustomResponse( - general_message='New lead not found in the circle' - ).get_failure_response() - - usr_circle_link.lead = None - lead_circle_link.lead = 1 - usr_circle_link.save() - lead_circle_link.save() - return CustomResponse( - general_message='Lead transferred successfully' - ).get_success_response() - - class LearningCircleHomeApi(APIView): def get(self, request, circle_id, member_id=None): user_id = JWTUtils.fetch_user_id(request) @@ -489,6 +399,96 @@ def delete(self, request, circle_id): return CustomResponse(general_message='Left').get_success_response() +class MeetCreateEditDeleteAPI(APIView): + + def post(self, request, circle_id): + user_id = JWTUtils.fetch_user_id(request) + + serializer = MeetCreateEditDeleteSerializer( + data=request.data, + context={ + 'user_id': user_id, + 'circle_id': circle_id + } + ) + if serializer.is_valid(): + circle_meet_log = serializer.save() + + return CustomResponse( + general_message=f'Meet scheduled at {circle_meet_log.meet_time}' + ).get_success_response() + + return CustomResponse( + message=serializer.errors + ).get_failure_response() + + def patch(self, request, circle_id): + user_id = JWTUtils.fetch_user_id(request) + + learning_circle = LearningCircle.objects.filter( + id=circle_id + ).first() + + serializer = MeetCreateEditDeleteSerializer( + learning_circle, + data=request.data, + context={ + 'user_id': user_id + } + ) + if serializer.is_valid(): + serializer.save() + + return CustomResponse( + general_message='Meet updated successfully' + ).get_success_response() + + return CustomResponse( + message=serializer.errors + ).get_failure_response() + + +class LearningCircleLeadTransfer(APIView): + def patch(self, request, circle_id, lead_id): + user_id = JWTUtils.fetch_user_id(request) + + usr_circle_link = UserCircleLink.objects.filter( + circle__id=circle_id, + user__id=user_id + ).first() + + lead_circle_link = UserCircleLink.objects.filter( + circle__id=circle_id, + user__id=lead_id + ).first() + + if not LearningCircle.objects.filter( + id=circle_id + ).exists(): + + return CustomResponse( + general_message='Learning Circle not found' + ).get_failure_response() + + if usr_circle_link is None or usr_circle_link.lead != 1: + return CustomResponse( + general_message='User is not lead' + ).get_failure_response() + + if lead_circle_link is None: + return CustomResponse( + general_message='New lead not found in the circle' + ).get_failure_response() + + usr_circle_link.lead = None + lead_circle_link.lead = 1 + usr_circle_link.save() + lead_circle_link.save() + return CustomResponse( + general_message='Lead transferred successfully' + ).get_success_response() + + class LearningCircleInviteLeadAPI(APIView): def post(self, request): From b56f3c613044791631851e302dd0890326acd36a Mon Sep 17 00:00:00 2001 From: anirudh-mk Date: Sat, 4 Nov 2023 21:52:18 +0530 Subject: [PATCH 08/32] optim:MeetGetPostPatchDeleteAPI --- api/dashboard/lc/dash_lc_view.py | 53 +++++++++++++------------------- api/dashboard/lc/urls.py | 6 ++-- 2 files changed, 25 insertions(+), 34 deletions(-) diff --git a/api/dashboard/lc/dash_lc_view.py b/api/dashboard/lc/dash_lc_view.py index 96558920..674dc68f 100644 --- a/api/dashboard/lc/dash_lc_view.py +++ b/api/dashboard/lc/dash_lc_view.py @@ -399,7 +399,28 @@ def delete(self, request, circle_id): return CustomResponse(general_message='Left').get_success_response() -class MeetCreateEditDeleteAPI(APIView): +class MeetGetPostPatchDeleteAPI(APIView): + + def get(self, request, meet_id): + + circle_meeting_log = CircleMeetingLog.objects.filter( + id=meet_id + ).values( + "id", + "meet_time", + "meet_place", + "day", + "attendees", + "agenda", + meet_created_by=F("created_by__first_name"), + meet_created_at=F("created_at"), + meet_updated_by=F("updated_by__first_name"), + meet_updated_at=F("updated_at"), + ) + + return CustomResponse( + response=circle_meeting_log + ).get_success_response() def post(self, request, circle_id): user_id = JWTUtils.fetch_user_id(request) @@ -635,33 +656,3 @@ def post(self, request, circle_id, muid, status): ).get_failure_response() -class PreviousMeetingsDetailsAPI(APIView): - """ - API for retrieving details of a previous meeting by ID. - - This API allows you to retrieve information about a previous meeting - based on its unique ID. - Methode: - - get: Retrieve details of a previous meeting. - """ - def get(self, request, meet_id): - - circle_meeting_log = CircleMeetingLog.objects.filter( - id=meet_id - ).values( - "id", - "meet_time", - "meet_place", - "day", - "attendees", - "agenda", - meet_created_by=F("created_by__first_name"), - meet_created_at=F("created_at"), - meet_updated_by=F("updated_by__first_name"), - meet_updated_at=F("updated_at"), - ) - - return CustomResponse( - response=circle_meeting_log - ).get_success_response() - diff --git a/api/dashboard/lc/urls.py b/api/dashboard/lc/urls.py index c1867326..c1b098db 100644 --- a/api/dashboard/lc/urls.py +++ b/api/dashboard/lc/urls.py @@ -14,9 +14,9 @@ path('join//', dash_lc_view.LearningCircleJoinApi.as_view()), path('//', dash_lc_view.LearningCircleHomeApi.as_view()), path('/', dash_lc_view.LearningCircleHomeApi.as_view()), - path('meeting-log//', dash_lc_view.PreviousMeetingsDetailsAPI.as_view()), - path('meet/edit//', dash_lc_view.MeetCreateEditDeleteAPI.as_view()), # optim - path('meet/create//', dash_lc_view.MeetCreateEditDeleteAPI.as_view()), # optim + path('meeting-log//', dash_lc_view.MeetGetPostPatchDeleteAPI.as_view()), + path('meet/edit//', dash_lc_view.MeetGetPostPatchDeleteAPI.as_view()), # optim + path('meet/create//', dash_lc_view.MeetGetPostPatchDeleteAPI.as_view()), # optim path('member/invite///', dash_lc_view.LearningCircleInviteMember.as_view()), path('member/invite/status////', dash_lc_view.LearningCircleInvitationStatus.as_view()), path('lead///', dash_lc_view.LearningCircleLeadTransfer.as_view()), From f6a35a84f4c1dd4b34997f2ca0376ca90abe4896 Mon Sep 17 00:00:00 2001 From: anirudh-mk Date: Sat, 4 Nov 2023 22:00:15 +0530 Subject: [PATCH 09/32] optim:LearningCircleInviteMemberAPI --- api/dashboard/lc/dash_lc_view.py | 15 +++++++-------- api/dashboard/lc/urls.py | 2 +- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/api/dashboard/lc/dash_lc_view.py b/api/dashboard/lc/dash_lc_view.py index 674dc68f..e968e3e2 100644 --- a/api/dashboard/lc/dash_lc_view.py +++ b/api/dashboard/lc/dash_lc_view.py @@ -538,7 +538,7 @@ def post(self, request): return CustomResponse(general_message='User Invited').get_success_response() -class LearningCircleInviteMember(APIView): +class LearningCircleInviteMemberAPI(APIView): """ Invite a member to a learning circle. """ @@ -556,19 +556,19 @@ def post(self, request, circle_id, muid): general_message='Muid is Invalid' ).get_failure_response() - usr_circle_link = UserCircleLink.objects.filter( + user_circle_link = UserCircleLink.objects.filter( circle__id=circle_id, user__id=user.id ).first() - if usr_circle_link: - if usr_circle_link.accepted: + if user_circle_link: + if user_circle_link.accepted: return CustomResponse( general_message='User already part of circle' ).get_failure_response() - elif usr_circle_link.is_invited: + elif user_circle_link.is_invited: return CustomResponse( general_message='User already invited' ).get_failure_response() @@ -576,7 +576,7 @@ def post(self, request, circle_id, muid): receiver_email = user.email html_address = ["lc_invitation.html"] inviter = User.objects.filter(id=JWTUtils.fetch_user_id(request)).first() - inviter_name = inviter.first_name + " " + inviter.last_name + inviter_name = inviter.full_name context = { "circle_name": LearningCircle.objects.filter( id=circle_id @@ -593,7 +593,7 @@ def post(self, request, circle_id, muid): ) if status == 1: - usr_circle_link_new = UserCircleLink( + UserCircleLink.objects.create( id=uuid.uuid4(), circle_id=circle_id, user=user, @@ -601,7 +601,6 @@ def post(self, request, circle_id, muid): accepted=False, created_at=DateTimeUtils.get_current_utc_time(), ) - usr_circle_link_new.save() return CustomResponse( general_message='User Invited' diff --git a/api/dashboard/lc/urls.py b/api/dashboard/lc/urls.py index c1b098db..1c4b2855 100644 --- a/api/dashboard/lc/urls.py +++ b/api/dashboard/lc/urls.py @@ -17,7 +17,7 @@ path('meeting-log//', dash_lc_view.MeetGetPostPatchDeleteAPI.as_view()), path('meet/edit//', dash_lc_view.MeetGetPostPatchDeleteAPI.as_view()), # optim path('meet/create//', dash_lc_view.MeetGetPostPatchDeleteAPI.as_view()), # optim - path('member/invite///', dash_lc_view.LearningCircleInviteMember.as_view()), + path('member/invite///', dash_lc_view.LearningCircleInviteMemberAPI.as_view()), path('member/invite/status////', dash_lc_view.LearningCircleInvitationStatus.as_view()), path('lead///', dash_lc_view.LearningCircleLeadTransfer.as_view()), ] From 3be9daaf20f8c8ab3a69f906d7cfb6f659febb4f Mon Sep 17 00:00:00 2001 From: anirudh-mk Date: Sat, 4 Nov 2023 22:05:27 +0530 Subject: [PATCH 10/32] optim:lc --- api/dashboard/lc/dash_lc_view.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/api/dashboard/lc/dash_lc_view.py b/api/dashboard/lc/dash_lc_view.py index e968e3e2..d1ce35a8 100644 --- a/api/dashboard/lc/dash_lc_view.py +++ b/api/dashboard/lc/dash_lc_view.py @@ -473,7 +473,7 @@ class LearningCircleLeadTransfer(APIView): def patch(self, request, circle_id, lead_id): user_id = JWTUtils.fetch_user_id(request) - usr_circle_link = UserCircleLink.objects.filter( + user_circle_link = UserCircleLink.objects.filter( circle__id=circle_id, user__id=user_id ).first() @@ -491,7 +491,7 @@ def patch(self, request, circle_id, lead_id): general_message='Learning Circle not found' ).get_failure_response() - if usr_circle_link is None or usr_circle_link.lead != 1: + if user_circle_link is None or user_circle_link.lead != 1: return CustomResponse( general_message='User is not lead' ).get_failure_response() @@ -501,10 +501,11 @@ def patch(self, request, circle_id, lead_id): general_message='New lead not found in the circle' ).get_failure_response() - usr_circle_link.lead = None + user_circle_link.lead = None lead_circle_link.lead = 1 - usr_circle_link.save() + user_circle_link.save() lead_circle_link.save() + return CustomResponse( general_message='Lead transferred successfully' ).get_success_response() @@ -630,25 +631,25 @@ def post(self, request, circle_id, muid, status): general_message='Muid is Invalid' ).get_failure_response() - usr_circle_link = UserCircleLink.objects.filter( + user_circle_link = UserCircleLink.objects.filter( circle__id=circle_id, user__id=user.id ).first() - if not usr_circle_link: + if not user_circle_link: return CustomResponse( general_message='User not invited' ).get_failure_response() if status == "accepted": - usr_circle_link.accepted = True - usr_circle_link.accepted_at = DateTimeUtils.get_current_utc_time() - usr_circle_link.save() + user_circle_link.accepted = True + user_circle_link.accepted_at = DateTimeUtils.get_current_utc_time() + user_circle_link.save() # return CustomResponse(general_message='User added to circle').get_success_response() return redirect(f'{domain}/dashboard/learning-circle/') elif status == "rejected": - usr_circle_link.delete() + user_circle_link.delete() return CustomResponse( general_message='User rejected invitation' From e69dac9754a5a20eece19c483d7bef4e57ba5a1b Mon Sep 17 00:00:00 2001 From: anirudh-mk Date: Sat, 4 Nov 2023 23:41:52 +0530 Subject: [PATCH 11/32] fix(lc create api) --- api/dashboard/lc/dash_lc_serializer.py | 7 +++++++ db/learning_circle.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/api/dashboard/lc/dash_lc_serializer.py b/api/dashboard/lc/dash_lc_serializer.py index bd43bb8c..4d92d418 100644 --- a/api/dashboard/lc/dash_lc_serializer.py +++ b/api/dashboard/lc/dash_lc_serializer.py @@ -90,6 +90,12 @@ def get_members(self, obj): class LearningCircleCreateSerializer(serializers.ModelSerializer): + ig = serializers.CharField(required=True, error_messages={ + 'required': 'ig field must not be left blank.' + }) + name = serializers.CharField(required=True, error_messages={ + 'required': 'name field must not be left blank.'} + ) class Meta: model = LearningCircle @@ -99,6 +105,7 @@ class Meta: ] def validate(self, data): + user_id = self.context.get('user_id') ig_id = data.get('ig') diff --git a/db/learning_circle.py b/db/learning_circle.py index 39a678b0..a1b2f8ad 100644 --- a/db/learning_circle.py +++ b/db/learning_circle.py @@ -13,7 +13,7 @@ class LearningCircle(models.Model): id = models.CharField(primary_key=True, max_length=36, default=uuid.uuid4()) name = models.CharField(max_length=255, unique=True) circle_code = models.CharField(unique=True, max_length=36) - ig = models.ForeignKey(InterestGroup, on_delete=models.CASCADE, blank=True, null=True, + ig = models.ForeignKey(InterestGroup, on_delete=models.CASCADE, blank=True, related_name="learning_circle_ig") org = models.ForeignKey(Organization, on_delete=models.CASCADE, blank=True, null=True, related_name="learning_circle_org") From 6ac68383f433c5f747c2f59cd9c7eeebf57ba93c Mon Sep 17 00:00:00 2001 From: jelanmathewjames Date: Sun, 5 Nov 2023 12:18:43 +0530 Subject: [PATCH 12/32] [FEAT] ws group send for landing-stats group send for reducing db hits for every creation and deletion --- api/common/common_consumer.py | 182 ++++++++++++++++++---------------- utils/baseconsumer.py | 9 -- 2 files changed, 96 insertions(+), 95 deletions(-) delete mode 100644 utils/baseconsumer.py diff --git a/api/common/common_consumer.py b/api/common/common_consumer.py index 996daf30..86a3e627 100644 --- a/api/common/common_consumer.py +++ b/api/common/common_consumer.py @@ -5,6 +5,9 @@ from django.db.models import Count from django.db.models.functions import Coalesce +from channels.generic.websocket import WebsocketConsumer +from asgiref.sync import async_to_sync + from db.learning_circle import LearningCircle from db.learning_circle import UserCircleLink from db.organization import Organization @@ -12,103 +15,110 @@ from db.user import User, UserRoleLink from utils.types import IntegrationType, OrganizationType -from utils.baseconsumer import BaseConsumer - -class GlobalCount(BaseConsumer): - def receive(self, text_data): - if json.loads(text_data)['type'] == 'global_count': - org_type_counts = Organization.objects.filter( +class GlobalCount(WebsocketConsumer): + data = {} + group_name = "landing_stats" + + def connect(self): + async_to_sync(self.channel_layer.group_add)( + self.group_name, + self.channel_name + ) + self.accept() + + self.data = { + 'members': self.members_count, + 'org_type_counts': self.org_type_counts, + 'enablers_mentors_count': self.enablers_mentors_count, + 'ig_count': self.interest_groups_count, + 'learning_circle_count': self.learning_circles_count + } + + self.send(text_data=json.dumps(self.data)) + + def disconnect(self, code): + self.channel_layer.group_discard(self.group_name, self.channel_name) + + @property + def members_count(self): + members_count = User.objects.all().count() + return members_count + + @property + def org_type_counts(self): + org_type_counts = Organization.objects.filter( org_type__in=[OrganizationType.COLLEGE.value, OrganizationType.COMPANY.value, OrganizationType.COMMUNITY.value] ).values('org_type').annotate(org_count=Coalesce(Count('org_type'), 0)) - org_type_counts = list(org_type_counts) - - enablers_mentors_count = UserRoleLink.objects.filter( - role__title__in=["Mentor", "Enabler"]).values( - 'role__title').annotate(role_count=Coalesce(Count('role__title'), 0)) - enablers_mentors_count = list(enablers_mentors_count) - - interest_groups_count = InterestGroup.objects.all().count() - learning_circles_count = LearningCircle.objects.all().count() - members_count = User.objects.all().count() - - data = { - 'members': members_count, - 'org_type_counts': org_type_counts, - 'enablers_mentors_count': enablers_mentors_count, - 'ig_count': interest_groups_count, - 'learning_circle_count': learning_circles_count - } - - self.send(text_data=json.dumps(data)) + org_type_counts = list(org_type_counts) + + return org_type_counts + + @property + def enablers_mentors_count(self): + enablers_mentors_count = UserRoleLink.objects.filter( + role__title__in=["Mentor", "Enabler"]).values( + 'role__title').annotate(role_count=Coalesce(Count('role__title'), 0)) + enablers_mentors_count = list(enablers_mentors_count) + + return enablers_mentors_count + + @property + def interest_groups_count(self): + interest_groups_count = InterestGroup.objects.all().count() + return interest_groups_count + + @property + def learning_circles_count(self): + learning_circles_count = LearningCircle.objects.all().count() + return learning_circles_count + + def get_based_on_sender(self, sender): + if sender == User: + self.data['members'] = self.members_count + + elif sender == Organization: + self.data['org_type_counts'] = self.org_type_counts + + elif sender == UserRoleLink: + self.data['enablers_mentors_count'] = self.enablers_mentors_count + + elif sender == InterestGroup: + self.data['ig_count'] = self.interest_groups_count + + elif sender == LearningCircle: + self.data['learning_circle_count'] = self.learning_circles_count + def receive(self, text_data): + @receiver(post_save, sender=User) @receiver(post_save, sender=LearningCircle) @receiver(post_save, sender=InterestGroup) @receiver(post_save, sender=UserRoleLink) @receiver(post_save, sender=Organization) - def user_post_save(sender, instance, created, **kwargs): - data = {} - - if created: - if sender == User: - count = User.objects.all().count() - data['members'] = count - - elif sender == LearningCircle: - count = LearningCircle.objects.all().count() - data['learning_circle_count'] = count - - elif sender == InterestGroup: - count = InterestGroup.objects.all().count() - data['ig_count'] = count - - elif sender == UserRoleLink: - count = UserRoleLink.objects.filter( - role__title__in=["Mentor", "Enabler"]).values( - 'role__title').annotate(role_count=Coalesce(Count('role__title'), 0)) - data['enablers_mentors_count'] = list(count) - - elif sender == Organization: - count = Organization.objects.filter( - org_type__in=[OrganizationType.COLLEGE.value, OrganizationType.COMPANY.value, - OrganizationType.COMMUNITY.value] - ).values('org_type').annotate(org_count=Coalesce(Count('org_type'), 0)) - data['org_type_counts'] = list(count) - - self.send(text_data=json.dumps(data)) - @receiver(post_delete, sender=User) @receiver(post_delete, sender=LearningCircle) @receiver(post_delete, sender=InterestGroup) - def user_post_delete(sender, instance, created, **kwargs): - data = {} - - if sender == User: - count = User.objects.all().count() - data['members'] = count - - elif sender == LearningCircle: - count = LearningCircle.objects.all().count() - data['learning_circle_count'] = count - - elif sender == InterestGroup: - count = InterestGroup.objects.all().count() - data['ig_count'] = count - - elif sender == UserRoleLink: - count = UserRoleLink.objects.filter( - role__title__in=["Mentor", "Enabler"]).values( - 'role__title').annotate(role_count=Coalesce(Count('role__title'), 0)) - data['enablers_mentors_count'] = list(count) - - elif sender == Organization: - count = Organization.objects.filter( - org_type__in=[OrganizationType.COLLEGE.value, OrganizationType.COMPANY.value, - OrganizationType.COMMUNITY.value] - ).values('org_type').annotate(org_count=Coalesce(Count('org_type'), 0)) - data['org_type_counts'] = list(count) - - self.send(text_data=json.dumps(data)) + @receiver(post_delete, sender=UserRoleLink) + @receiver(post_delete, sender=Organization) + def db_signals(sender, instance, created=None, *args, **kwargs): + if created: + self.get_based_on_sender(sender) + async_to_sync(self.channel_layer.group_send)( + self.group_name, + {"type": "send_data", "data": self.data} + ) + + if created == None: + self.get_based_on_sender(sender) + async_to_sync(self.channel_layer.group_send)( + self.group_name, + {"type": "send_data", "data": self.data} + ) + + def send_data(self, event): + self.send(text_data=json.dumps(event['data'])) + + diff --git a/utils/baseconsumer.py b/utils/baseconsumer.py deleted file mode 100644 index e4323d32..00000000 --- a/utils/baseconsumer.py +++ /dev/null @@ -1,9 +0,0 @@ -from channels.generic.websocket import WebsocketConsumer - -class BaseConsumer(WebsocketConsumer): - - def connect(self): - self.accept() - - def disconnect(self, close_code): - super().disconnect(close_code) \ No newline at end of file From ac27545f0251a2e18e8fbf143d8e7cc37070f6d5 Mon Sep 17 00:00:00 2001 From: aswanthabam Date: Sun, 5 Nov 2023 18:44:52 +0530 Subject: [PATCH 13/32] feat(profile) : profile picture upload --- api/dashboard/user/dash_user_serializer.py | 16 ++++++++ api/dashboard/user/dash_user_views.py | 46 ++++++++++++++++++++++ api/dashboard/user/urls.py | 1 + 3 files changed, 63 insertions(+) diff --git a/api/dashboard/user/dash_user_serializer.py b/api/dashboard/user/dash_user_serializer.py index e873275c..12db2f9f 100644 --- a/api/dashboard/user/dash_user_serializer.py +++ b/api/dashboard/user/dash_user_serializer.py @@ -355,3 +355,19 @@ def update(self, instance, validated_data): ) return super().update(instance, validated_data) + +class UserProfileUpdateSerializer(serializers.ModelSerializer): + profile_pic = serializers.CharField(required=True) + user_id = serializers.CharField(source='id',read_only=True) + + class Meta: + model = User + fields = [ + "user_id", + "profile_pic" + ] + + def update(self, instance, validated_data): + instance.profile_pic = validated_data.get('profile_pic') + instance.save() + return instance diff --git a/api/dashboard/user/dash_user_views.py b/api/dashboard/user/dash_user_views.py index 6081b780..0d1030ef 100644 --- a/api/dashboard/user/dash_user_views.py +++ b/api/dashboard/user/dash_user_views.py @@ -11,6 +11,7 @@ from utils.types import RoleType, WebHookActions, WebHookCategory from utils.utils import CommonUtils, DateTimeUtils, DiscordWebhooks, send_template_mail from . import dash_user_serializer +from django.core.files.storage import FileSystemStorage class UserInfoAPI(APIView): @@ -362,3 +363,48 @@ def save_password(self, request, forget_user): return CustomResponse( general_message="New Password Saved Successfully" ).get_success_response() + +class UserProfilePictureUpdateView(APIView): + + def post(self, request): + user_id = request.data.get('user_id') + user = User.objects.filter(id=user_id).first() + + if user is None: + return CustomResponse( + general_message="No user data available" + ).get_failure_response() + + pic = request.FILES.get('profile') + + if pic is None: + return CustomResponse( + general_message="No profile picture" + ).get_failure_response() + + if not pic.content_type.startswith("image/"): + return CustomResponse( + general_message="Expected an image" + ).get_failure_response() + + extention = '.png' # os.path.splitext(pic.name)[1] + fs = FileSystemStorage() + filename = f"user/profile/{user_id}{extention}" + if fs.exists(filename): + fs.delete(filename) + filename = fs.save(filename, pic) + uploaded_file_url = fs.url(filename) + + serializer = dash_user_serializer.UserProfileUpdateSerializer( + user,data={'profile_pic':uploaded_file_url} + ) + + if serializer.is_valid(): + serializer.save() + return CustomResponse( + response=serializer.data + ).get_success_response() + else: + return CustomResponse( + response=serializer.errors + ).get_failure_response() diff --git a/api/dashboard/user/urls.py b/api/dashboard/user/urls.py index ad2a8608..a700c91a 100644 --- a/api/dashboard/user/urls.py +++ b/api/dashboard/user/urls.py @@ -13,6 +13,7 @@ path('forgot-password/', dash_user_views.ForgotPasswordAPI.as_view(), name="forgot-password"), path('reset-password/verify-token//', dash_user_views.ResetPasswordVerifyTokenAPI.as_view()), path('reset-password//', dash_user_views.ResetPasswordConfirmAPI.as_view()), + path('profile/update/',dash_user_views.UserProfilePictureUpdateView.as_view()), path('csv/', dash_user_views.UserManagementCSV.as_view(), name="csv-user"), path('', dash_user_views.UserAPI.as_view(), name='list-user'), From bef75e14095e6f090d02b44e4beb049c93a41863 Mon Sep 17 00:00:00 2001 From: lordgrim Date: Sun, 5 Nov 2023 19:41:20 +0530 Subject: [PATCH 14/32] refactor(task): change base template name --- .../{base_template.xlsx => task_base_template.xlsx} | Bin api/dashboard/task/dash_task_view.py | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) rename api/dashboard/task/assets/{base_template.xlsx => task_base_template.xlsx} (100%) diff --git a/api/dashboard/task/assets/base_template.xlsx b/api/dashboard/task/assets/task_base_template.xlsx similarity index 100% rename from api/dashboard/task/assets/base_template.xlsx rename to api/dashboard/task/assets/task_base_template.xlsx diff --git a/api/dashboard/task/dash_task_view.py b/api/dashboard/task/dash_task_view.py index 113cb242..14dda5b8 100644 --- a/api/dashboard/task/dash_task_view.py +++ b/api/dashboard/task/dash_task_view.py @@ -508,7 +508,7 @@ class TaskBaseTemplateAPI(APIView): authentication_classes = [CustomizePermission] def get(self, request): - wb = load_workbook('./api/dashboard/task/assets/base_template.xlsx') + wb = load_workbook('./api/dashboard/task/assets/task_base_template.xlsx') ws = wb['Data Definitions'] levels = Level.objects.all().values_list('name', flat=True) channels = Channel.objects.all().values_list('name', flat=True) @@ -536,4 +536,4 @@ def get(self, request): 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='base_template.xlsx') \ No newline at end of file + return FileResponse(BytesIO(new_file_object), as_attachment=True, filename='task_base_template.xlsx') \ No newline at end of file From 4793a67b381e8105debbd08a2869792e9c2e096b Mon Sep 17 00:00:00 2001 From: lordgrim Date: Sun, 5 Nov 2023 19:42:35 +0530 Subject: [PATCH 15/32] refactor(karma_voucher): change base template name --- ...ase_template.xlsx => voucher_base_template.xlsx} | Bin api/dashboard/karma_voucher/karma_voucher_view.py | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) rename api/dashboard/karma_voucher/assets/{base_template.xlsx => voucher_base_template.xlsx} (100%) diff --git a/api/dashboard/karma_voucher/assets/base_template.xlsx b/api/dashboard/karma_voucher/assets/voucher_base_template.xlsx similarity index 100% rename from api/dashboard/karma_voucher/assets/base_template.xlsx rename to api/dashboard/karma_voucher/assets/voucher_base_template.xlsx diff --git a/api/dashboard/karma_voucher/karma_voucher_view.py b/api/dashboard/karma_voucher/karma_voucher_view.py index 33a3ff8d..e6fb7cef 100644 --- a/api/dashboard/karma_voucher/karma_voucher_view.py +++ b/api/dashboard/karma_voucher/karma_voucher_view.py @@ -332,7 +332,7 @@ class VoucherBaseTemplateAPI(APIView): authentication_classes = [CustomizePermission] def get(self, request): - wb = load_workbook('./api/dashboard/karma_voucher/assets/base_template.xlsx') + wb = load_workbook('./api/dashboard/karma_voucher/assets/voucher_base_template.xlsx') ws = wb['Data Definitions'] hashtags = TaskList.objects.all().values_list('hashtag', flat=True) data = { @@ -352,4 +352,4 @@ def get(self, request): 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='base_template.xlsx') \ No newline at end of file + return FileResponse(BytesIO(new_file_object), as_attachment=True, filename='voucher_base_template.xlsx') \ No newline at end of file From 9d9c4885c5c0e7ab3ac19217ab216de26e207a78 Mon Sep 17 00:00:00 2001 From: lordgrim Date: Sun, 5 Nov 2023 19:43:45 +0530 Subject: [PATCH 16/32] fix(task): channel endpoint --- api/dashboard/task/urls.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/dashboard/task/urls.py b/api/dashboard/task/urls.py index a7bab4b6..5072de8f 100644 --- a/api/dashboard/task/urls.py +++ b/api/dashboard/task/urls.py @@ -4,7 +4,7 @@ urlpatterns = [ - path('channels/', dash_task_view.ChannelDropdownAPI.as_view()), + path('channel/', dash_task_view.ChannelDropdownAPI.as_view()), path('ig/', dash_task_view.IGDropdownAPI.as_view()), path('organization/', dash_task_view.OrganizationDropdownAPI.as_view()), path('level/', dash_task_view.LevelDropdownAPI.as_view()), From 6e21e20e3a8db279b145c74926bde7d89f3a594f Mon Sep 17 00:00:00 2001 From: aswanthabam Date: Sun, 5 Nov 2023 20:16:27 +0530 Subject: [PATCH 17/32] feat : profile picture upload : image url --- api/dashboard/user/dash_user_views.py | 23 +++++++++++++++++++---- api/dashboard/user/urls.py | 3 ++- utils/response.py | 20 +++++++++++++++++++- utils/utils.py | 2 -- 4 files changed, 40 insertions(+), 8 deletions(-) diff --git a/api/dashboard/user/dash_user_views.py b/api/dashboard/user/dash_user_views.py index 0d1030ef..d36930f4 100644 --- a/api/dashboard/user/dash_user_views.py +++ b/api/dashboard/user/dash_user_views.py @@ -7,7 +7,7 @@ from db.user import ForgotPassword, User, UserRoleLink from utils.permission import CustomizePermission, JWTUtils, role_required -from utils.response import CustomResponse +from utils.response import CustomResponse, ImageResponse from utils.types import RoleType, WebHookActions, WebHookCategory from utils.utils import CommonUtils, DateTimeUtils, DiscordWebhooks, send_template_mail from . import dash_user_serializer @@ -364,8 +364,23 @@ def save_password(self, request, forget_user): general_message="New Password Saved Successfully" ).get_success_response() -class UserProfilePictureUpdateView(APIView): - +class UserProfilePictureView(APIView): + def get(self, request, user_id): + user = User.objects.filter(id=user_id).first() + + if user is None: + return CustomResponse( + general_message="No user data available" + ).get_failure_response() + image_path = f'user/profile/{user_id}.png' + response = ImageResponse(path=image_path) + if response.exists(): + return response.get_success_response() + else: + return CustomResponse( + general_message="No Profile picture available" + ).get_failure_response() + def post(self, request): user_id = request.data.get('user_id') user = User.objects.filter(id=user_id).first() @@ -393,7 +408,7 @@ def post(self, request): if fs.exists(filename): fs.delete(filename) filename = fs.save(filename, pic) - uploaded_file_url = fs.url(filename) + uploaded_file_url = f'/api/v1/dashboard/user/profile/{user_id}' serializer = dash_user_serializer.UserProfileUpdateSerializer( user,data={'profile_pic':uploaded_file_url} diff --git a/api/dashboard/user/urls.py b/api/dashboard/user/urls.py index a700c91a..e670433a 100644 --- a/api/dashboard/user/urls.py +++ b/api/dashboard/user/urls.py @@ -13,7 +13,8 @@ path('forgot-password/', dash_user_views.ForgotPasswordAPI.as_view(), name="forgot-password"), path('reset-password/verify-token//', dash_user_views.ResetPasswordVerifyTokenAPI.as_view()), path('reset-password//', dash_user_views.ResetPasswordConfirmAPI.as_view()), - path('profile/update/',dash_user_views.UserProfilePictureUpdateView.as_view()), + path('profile/update/',dash_user_views.UserProfilePictureView.as_view()), + path('profile//',dash_user_views.UserProfilePictureView.as_view()), path('csv/', dash_user_views.UserManagementCSV.as_view(), name="csv-user"), path('', dash_user_views.UserAPI.as_view(), name='list-user'), diff --git a/utils/response.py b/utils/response.py index 7bef98fb..0600eeea 100644 --- a/utils/response.py +++ b/utils/response.py @@ -3,6 +3,8 @@ from rest_framework import status from rest_framework.response import Response +from django.core.files.storage import FileSystemStorage +from django.http import HttpResponse class CustomResponse: """A custom response class for API views. @@ -101,4 +103,20 @@ def paginated_response(self, data: dict, pagination: dict) -> Response: "response": self.response, }, status=status.HTTP_200_OK, - ) \ No newline at end of file + ) + + +class ImageResponse: + def __init__(self,path:str): + fs = FileSystemStorage() + if fs.exists(path):self.file = fs.open(path) + else: self.file = None + + def exists(self) -> bool: + return False if self.file is None else True + + def get_success_response(self) -> Response: + return HttpResponse(self.file,status=status.HTTP_200_OK,content_type='image/png') + + def get_failure_response(self,http_status_code : int = status.HTTP_400_BAD_REQUEST) -> Response: + return HttpResponse(self.file,status=http_status_code,content_type='image/png') \ No newline at end of file diff --git a/utils/utils.py b/utils/utils.py index 49e2a209..7ce72127 100644 --- a/utils/utils.py +++ b/utils/utils.py @@ -17,7 +17,6 @@ from django.http import HttpResponse from django.template.loader import render_to_string - class CommonUtils: @staticmethod def get_paginated_queryset( @@ -172,7 +171,6 @@ def read_excel_file(self, file_obj): return rows - def send_template_mail( context: dict, subject: str, address: list[str], attachment: str = None): """ From fde55df140f884c7b47387acbda58098f39a5f92 Mon Sep 17 00:00:00 2001 From: aswanthabam Date: Sun, 5 Nov 2023 20:36:02 +0530 Subject: [PATCH 18/32] feat : profile picture upload (url updated) --- api/dashboard/user/dash_user_views.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/api/dashboard/user/dash_user_views.py b/api/dashboard/user/dash_user_views.py index d36930f4..99d32bdd 100644 --- a/api/dashboard/user/dash_user_views.py +++ b/api/dashboard/user/dash_user_views.py @@ -12,7 +12,7 @@ from utils.utils import CommonUtils, DateTimeUtils, DiscordWebhooks, send_template_mail from . import dash_user_serializer from django.core.files.storage import FileSystemStorage - +from decouple import config as decouple_config class UserInfoAPI(APIView): authentication_classes = [CustomizePermission] @@ -408,7 +408,8 @@ def post(self, request): if fs.exists(filename): fs.delete(filename) filename = fs.save(filename, pic) - uploaded_file_url = f'/api/v1/dashboard/user/profile/{user_id}' + file_url = fs.url(filename) + uploaded_file_url = f"{decouple_config('FR_DOMAIN_NAME')}{file_url}" # /api/v1/dashboard/user/profile/{user_id}" serializer = dash_user_serializer.UserProfileUpdateSerializer( user,data={'profile_pic':uploaded_file_url} From a6ffc2876efd62c60d84470846478fb362e8b0e3 Mon Sep 17 00:00:00 2001 From: aswanthabam Date: Sun, 5 Nov 2023 21:52:17 +0530 Subject: [PATCH 19/32] fix : profile pic upload --- api/dashboard/profile/profile_serializer.py | 12 +++- api/dashboard/user/dash_user_serializer.py | 16 ------ api/dashboard/user/dash_user_views.py | 61 +++++++++++---------- api/dashboard/user/urls.py | 1 - utils/types.py | 1 + 5 files changed, 45 insertions(+), 46 deletions(-) diff --git a/api/dashboard/profile/profile_serializer.py b/api/dashboard/profile/profile_serializer.py index 8218ebf7..4731a2b1 100644 --- a/api/dashboard/profile/profile_serializer.py +++ b/api/dashboard/profile/profile_serializer.py @@ -4,6 +4,7 @@ from django.db.models import F, Sum, Q from rest_framework import serializers from rest_framework.serializers import ModelSerializer +from decouple import config as decouple_config from db.organization import UserOrganizationLink from db.task import InterestGroup, KarmaActivityLog, Level, TaskList, Wallet, UserIgLink, UserLvlLink @@ -12,6 +13,7 @@ from utils.permission import JWTUtils from utils.types import OrganizationType, RoleType, MainRoles from utils.utils import DateTimeUtils +from django.core.files.storage import FileSystemStorage class UserLogSerializer(ModelSerializer): @@ -35,6 +37,7 @@ class UserProfileSerializer(serializers.ModelSerializer): karma_distribution = serializers.SerializerMethodField() interest_groups = serializers.SerializerMethodField() org_district_id = serializers.SerializerMethodField() + profile_pic = serializers.SerializerMethodField() class Meta: model = User @@ -57,7 +60,14 @@ class Meta: "interest_groups", "is_public", ) - + def get_profile_pic(self,obj): + fs = FileSystemStorage() + path = f'user/profile/{obj.id}.png' + if fs.exists(path): + profile_pic = f"{decouple_config('FR_DOMAIN_NAME')}{fs.url(path)}" + 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.all()}) diff --git a/api/dashboard/user/dash_user_serializer.py b/api/dashboard/user/dash_user_serializer.py index 12db2f9f..e873275c 100644 --- a/api/dashboard/user/dash_user_serializer.py +++ b/api/dashboard/user/dash_user_serializer.py @@ -355,19 +355,3 @@ def update(self, instance, validated_data): ) return super().update(instance, validated_data) - -class UserProfileUpdateSerializer(serializers.ModelSerializer): - profile_pic = serializers.CharField(required=True) - user_id = serializers.CharField(source='id',read_only=True) - - class Meta: - model = User - fields = [ - "user_id", - "profile_pic" - ] - - def update(self, instance, validated_data): - instance.profile_pic = validated_data.get('profile_pic') - instance.save() - return instance diff --git a/api/dashboard/user/dash_user_views.py b/api/dashboard/user/dash_user_views.py index 99d32bdd..2fa094e7 100644 --- a/api/dashboard/user/dash_user_views.py +++ b/api/dashboard/user/dash_user_views.py @@ -365,21 +365,32 @@ def save_password(self, request, forget_user): ).get_success_response() class UserProfilePictureView(APIView): - def get(self, request, user_id): - user = User.objects.filter(id=user_id).first() + + # def get(self, request, user_id): + # user = User.objects.filter(id=user_id).first() - if user is None: - return CustomResponse( - general_message="No user data available" - ).get_failure_response() - image_path = f'user/profile/{user_id}.png' - response = ImageResponse(path=image_path) - if response.exists(): - return response.get_success_response() - else: - return CustomResponse( - general_message="No Profile picture available" - ).get_failure_response() + # if user is None: + # return CustomResponse( + # general_message="No user data available" + # ).get_failure_response() + # image_path = f'user/profile/{user_id}.png' + # response = ImageResponse(path=image_path) + # if response.exists(): + # return response.get_success_response() + # else: + # return CustomResponse( + # general_message="No Profile picture available" + # ).get_failure_response() + + def patch(self,request): + DiscordWebhooks.general_updates( + WebHookCategory.USER_PROFILE.value, + WebHookActions.UPDATE.value, + JWTUtils.fetch_user_id(request) + ) + return CustomResponse( + general_message="Successfully updated" + ).get_success_response() def post(self, request): user_id = request.data.get('user_id') @@ -409,18 +420,12 @@ def post(self, request): fs.delete(filename) filename = fs.save(filename, pic) file_url = fs.url(filename) - uploaded_file_url = f"{decouple_config('FR_DOMAIN_NAME')}{file_url}" # /api/v1/dashboard/user/profile/{user_id}" + uploaded_file_url = f"{decouple_config('FR_DOMAIN_NAME')}{file_url}" + + return CustomResponse( + response={ + 'user_id':user.id, + 'profile_pic':uploaded_file_url + } + ).get_success_response() - serializer = dash_user_serializer.UserProfileUpdateSerializer( - user,data={'profile_pic':uploaded_file_url} - ) - - if serializer.is_valid(): - serializer.save() - return CustomResponse( - response=serializer.data - ).get_success_response() - else: - return CustomResponse( - response=serializer.errors - ).get_failure_response() diff --git a/api/dashboard/user/urls.py b/api/dashboard/user/urls.py index e670433a..f3f11f05 100644 --- a/api/dashboard/user/urls.py +++ b/api/dashboard/user/urls.py @@ -14,7 +14,6 @@ path('reset-password/verify-token//', dash_user_views.ResetPasswordVerifyTokenAPI.as_view()), path('reset-password//', dash_user_views.ResetPasswordConfirmAPI.as_view()), path('profile/update/',dash_user_views.UserProfilePictureView.as_view()), - path('profile//',dash_user_views.UserProfilePictureView.as_view()), path('csv/', dash_user_views.UserManagementCSV.as_view(), name="csv-user"), path('', dash_user_views.UserAPI.as_view(), name='list-user'), diff --git a/utils/types.py b/utils/types.py index ca84a8d6..d300dc49 100644 --- a/utils/types.py +++ b/utils/types.py @@ -73,6 +73,7 @@ class WebHookCategory(Enum): USER_ROLE = 'user-role' USER = 'user' USER_NAME = 'user-name' + USER_PROFILE = 'user-profile' class RefferalType(Enum): From 6f001dcb14541541b31f858d5767fc4be6cea4d3 Mon Sep 17 00:00:00 2001 From: Muhammed Zafar Date: Mon, 6 Nov 2023 14:43:42 +0530 Subject: [PATCH 20/32] [FEAT] user deletion start --- db/user.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/db/user.py b/db/user.py index 8a512b4a..44582f0c 100644 --- a/db/user.py +++ b/db/user.py @@ -20,8 +20,12 @@ class User(models.Model): active = models.BooleanField(default=True) exist_in_guild = models.BooleanField(default=False) profile_pic = models.CharField(max_length=200, blank=True, null=True) - district = models.ForeignKey("District",on_delete=models.CASCADE, blank=True, null=True) + district = models.ForeignKey("District", on_delete=models.CASCADE, blank=True, null=True) created_at = models.DateTimeField(auto_now_add=True) + suspended_at = models.DateTimeField(blank=True, null=True) + suspended_by = models.ForeignKey("self", on_delete=models.CASCADE, blank=True, null=True, related_name="suspended_by_user", db_column="suspended_by") + deleted_at = models.DateTimeField(blank=True, null=True) + deleted_by = models.ForeignKey("self", on_delete=models.CASCADE, blank=True, null=True, related_name="deleted_by_user", db_column="deleted_by") class Meta: managed = False From f673040a225fd84485e8de165c81c073f5f8feaa Mon Sep 17 00:00:00 2001 From: Muhammed Zafar Date: Mon, 6 Nov 2023 14:54:28 +0530 Subject: [PATCH 21/32] [FEAT] Remove active column --- db/user.py | 1 - 1 file changed, 1 deletion(-) diff --git a/db/user.py b/db/user.py index 44582f0c..1eb57f36 100644 --- a/db/user.py +++ b/db/user.py @@ -17,7 +17,6 @@ class User(models.Model): gender = models.CharField(max_length=10, blank=True, null=True, choices=[("Male", "Male"),("Female", "Female")]) dob = models.DateField(blank=True, null=True) admin = models.BooleanField(default=False) - active = models.BooleanField(default=True) exist_in_guild = models.BooleanField(default=False) profile_pic = models.CharField(max_length=200, blank=True, null=True) district = models.ForeignKey("District", on_delete=models.CASCADE, blank=True, null=True) From ba652b505dc3e72d01c5df79711fcdd9ce9f22e5 Mon Sep 17 00:00:00 2001 From: Muhammed Zafar Date: Mon, 6 Nov 2023 14:58:03 +0530 Subject: [PATCH 22/32] [FEAT] remove reference to active column --- api/dashboard/campus/serializers.py | 1 - api/leaderboard/leaderboard_view.py | 3 --- api/leaderboard/serializers.py | 1 - 3 files changed, 5 deletions(-) diff --git a/api/dashboard/campus/serializers.py b/api/dashboard/campus/serializers.py index f3a774ae..b3e62450 100644 --- a/api/dashboard/campus/serializers.py +++ b/api/dashboard/campus/serializers.py @@ -39,7 +39,6 @@ def get_active_members(self, obj): last_month = DateTimeUtils.get_current_utc_time() - timedelta(days=30) return obj.org.user_organization_link_org.filter( verified=True, - user__active=True, user__wallet_user__isnull=False, user__wallet_user__created_at__gte=last_month, ).count() diff --git a/api/leaderboard/leaderboard_view.py b/api/leaderboard/leaderboard_view.py index 81aec664..d57e53b2 100644 --- a/api/leaderboard/leaderboard_view.py +++ b/api/leaderboard/leaderboard_view.py @@ -17,7 +17,6 @@ def get(self, request): user_organization_link_user__org__org_type=OrganizationType.COLLEGE.value, user_role_link_user__role__title=RoleType.STUDENT.value, exist_in_guild=True, - active=True, ) .distinct() .select_related("wallet_user") @@ -49,7 +48,6 @@ def get(self, request): user_role_link_user__role__title=RoleType.STUDENT.value, user_organization_link_user__org__org_type=OrganizationType.COLLEGE.value, exist_in_guild=True, - active=True, ) .annotate( full_name=Concat(F("first_name"), Value(" "), F("last_name")), @@ -86,7 +84,6 @@ def get(self, request): Organization.objects.filter( org_type=OrganizationType.COLLEGE.value, user_organization_link_org__user__user_role_link_user__role__title=RoleType.STUDENT.value, - user_organization_link_org__user__active=True, user_organization_link_org__user__exist_in_guild=True, ) .distinct() diff --git a/api/leaderboard/serializers.py b/api/leaderboard/serializers.py index e35a4dc3..d404d67f 100644 --- a/api/leaderboard/serializers.py +++ b/api/leaderboard/serializers.py @@ -40,7 +40,6 @@ def get_active_members(self, obj): last_month = DateTimeUtils.get_current_utc_time() - timedelta(days=30) return obj.org.user_organization_link_org.filter( verified=True, - user__active=True, user__wallet_user__isnull=False, user__wallet_user__created_at__gte=last_month, ).count() From 9d2abe8544a86f4068316b8b18594b6a3bc96fb8 Mon Sep 17 00:00:00 2001 From: Muhammed Zafar Date: Mon, 6 Nov 2023 15:46:47 +0530 Subject: [PATCH 23/32] [FEAT] Add user manager --- db/managers/user_manager.py | 16 ++++++++++++++++ db/user.py | 3 +++ 2 files changed, 19 insertions(+) create mode 100644 db/managers/user_manager.py diff --git a/db/managers/user_manager.py b/db/managers/user_manager.py new file mode 100644 index 00000000..9368ff21 --- /dev/null +++ b/db/managers/user_manager.py @@ -0,0 +1,16 @@ +from django.db import models + + +class ActiveUserManager(models.Manager): + def get_queryset(self): + # This will return only the users where deleted_at, deleted_by, suspended_at, and suspended_by are NULL + return ( + super() + .get_queryset() + .filter( + deleted_at__isnull=True, + deleted_by__isnull=True, + suspended_at__isnull=True, + suspended_by__isnull=True, + ) + ) diff --git a/db/user.py b/db/user.py index 1eb57f36..2dd211ad 100644 --- a/db/user.py +++ b/db/user.py @@ -1,6 +1,7 @@ import uuid from django.db import models +from .managers import user_manager # fmt: off # noinspection PyPep8 @@ -25,6 +26,8 @@ class User(models.Model): suspended_by = models.ForeignKey("self", on_delete=models.CASCADE, blank=True, null=True, related_name="suspended_by_user", db_column="suspended_by") deleted_at = models.DateTimeField(blank=True, null=True) deleted_by = models.ForeignKey("self", on_delete=models.CASCADE, blank=True, null=True, related_name="deleted_by_user", db_column="deleted_by") + objects = user_manager.ActiveUserManager() + every = models.Manager() class Meta: managed = False From d20efb57279a29df331b5f20d696d5aca09e05b1 Mon Sep 17 00:00:00 2001 From: SurajSuresh123 Date: Mon, 6 Nov 2023 21:16:55 +0530 Subject: [PATCH 24/32] first commit --- api/dashboard/location/location_serializer.py | 128 +++------- api/dashboard/location/location_views.py | 233 ++++++------------ hello.py | Bin 0 -> 63336 bytes 3 files changed, 110 insertions(+), 251 deletions(-) create mode 100644 hello.py diff --git a/api/dashboard/location/location_serializer.py b/api/dashboard/location/location_serializer.py index a6f78191..e5f6076c 100644 --- a/api/dashboard/location/location_serializer.py +++ b/api/dashboard/location/location_serializer.py @@ -12,81 +12,62 @@ class LocationSerializer(serializers.ModelSerializer): class Meta: model = Country - fields = ["label", "value"] + fields = [ + "label", + "value" , + "created_at", + "updated_at", + ] class CountryCreateEditSerializer(serializers.ModelSerializer): label = serializers.CharField(source="name") - # value = serializers.CharField(source="id") + # value = serializers.CharField(source="id") class Meta: model = Country - fields = ["label"] - - def create(self, validated_data): - validated_data['id'] = str(uuid.uuid4()) - validated_data["updated_at"] = validated_data["created_at"] = DateTimeUtils.get_current_utc_time() - validated_data["updated_by_id"] = validated_data["created_by_id"] = self.context.get("user_id") - - return super().create(validated_data) - - def update(self, instance, validated_data): - validated_data["updated_at"] = DateTimeUtils.get_current_utc_time() - validated_data["updated_by_id"] = self.context.get("user_id") - - return super().update(instance, validated_data) - - def validate_label(self, country): - country_obj = Country.objects.filter(name=country).first() - if country_obj: - raise serializers.ValidationError('Country with this name is already exists') - return country + fields = ["label","updated_by", "created_by"] class StateRetrievalSerializer(serializers.ModelSerializer): + country = serializers.CharField(source="country.name", required=False, default=None) label = serializers.CharField(source="name") value = serializers.CharField(source="id") class Meta: - model = Country - fields = ["label", "value"] + model = State + fields = [ + "label", + "value", + "country", + "created_at", + "updated_at", + ] class StateCreateEditSerializer(serializers.ModelSerializer): label = serializers.CharField(source="name") - # value = serializers.CharField(source="id") + # value = serializers.CharField(source="id") class Meta: model = State - fields = ["label", "country"] - - def create(self, validated_data): - validated_data['id'] = str(uuid.uuid4()) - validated_data["updated_at"] = validated_data["created_at"] = DateTimeUtils.get_current_utc_time() - validated_data["updated_by_id"] = validated_data["created_by_id"] = self.context.get("user_id") - - return super().create(validated_data) - - def update(self, instance, validated_data): - validated_data["updated_at"] = DateTimeUtils.get_current_utc_time() - validated_data["updated_by_id"] = self.context.get("user_id") - - return super().update(instance, validated_data) - - def validate_label(self, state): - state_obj = State.objects.filter(name=state).first() - if state_obj: - raise serializers.ValidationError("State with this name is already exists") - return state + fields = ["label", "created_by", "updated_by"] class ZoneRetrievalSerializer(serializers.ModelSerializer): + state = serializers.CharField(source="state.name", required=False, default=None) label = serializers.CharField(source="name") value = serializers.CharField(source="id") class Meta: - model = Country - fields = ["label", "value"] + model = Zone + fields = [ + "label", + "value", + "state", + "created_at", + "updated_at", + ] class ZoneCreateEditSerializer(serializers.ModelSerializer): @@ -95,35 +76,23 @@ class ZoneCreateEditSerializer(serializers.ModelSerializer): class Meta: model = Zone - fields = ["label", "state"] - - def create(self, validated_data): - validated_data['id'] = str(uuid.uuid4()) - validated_data["updated_at"] = validated_data["created_at"] = DateTimeUtils.get_current_utc_time() - validated_data["updated_by_id"] = validated_data["created_by_id"] = self.context.get("user_id") - - return super().create(validated_data) - - def update(self, instance, validated_data): - validated_data["updated_at"] = DateTimeUtils.get_current_utc_time() - validated_data["updated_by_id"] = self.context.get("user_id") - - return super().update(instance, validated_data) - - def validate_label(self, zone): - zone_obj = Zone.objects.filter(name=zone).first() - if zone_obj: - raise serializers.ValidationError("Zone with this name is already exists") - return zone + fields = ["label", "created_by", "updated_by"] class DistrictRetrievalSerializer(serializers.ModelSerializer): + zone = serializers.CharField(source="zone.name", required=False, default=None) label = serializers.CharField(source="name") value = serializers.CharField(source="id") class Meta: - model = Country - fields = ["label", "value"] + model = District + fields = [ + "label", + "value", + "zone", + "created_at", + "updated_at", + ] class DistrictCreateEditSerializer(serializers.ModelSerializer): @@ -132,23 +101,4 @@ class DistrictCreateEditSerializer(serializers.ModelSerializer): class Meta: model = District - fields = ["label", "zone"] - - def create(self, validated_data): - validated_data['id'] = str(uuid.uuid4()) - validated_data["updated_at"] = validated_data["created_at"] = DateTimeUtils.get_current_utc_time() - validated_data["updated_by_id"] = validated_data["created_by_id"] = self.context.get("user_id") - - return super().create(validated_data) - - def update(self, instance, validated_data): - validated_data["updated_at"] = DateTimeUtils.get_current_utc_time() - validated_data["updated_by_id"] = self.context.get("user_id") - - return super().update(instance, validated_data) - - def validate_label(self, district): - district_obj = District.objects.filter(name=district).first() - if district_obj: - raise serializers.ValidationError("District with this name is already exists") - return district + fields = ["label","created_by", "updated_by"] diff --git a/api/dashboard/location/location_views.py b/api/dashboard/location/location_views.py index 64137738..e2afff28 100644 --- a/api/dashboard/location/location_views.py +++ b/api/dashboard/location/location_views.py @@ -15,76 +15,53 @@ class CountryDataAPI(APIView): @role_required([RoleType.ADMIN.value]) def get(self, request, country_id=None): - if country_id: countries = Country.objects.filter(id=country_id) else: countries = Country.objects.all() paginated_queryset = CommonUtils.get_paginated_queryset( - countries, - request, - [ - "name" - ], - { - "label": "name" - } + countries, request, ["name"], {"label": "name"} ) serializer = location_serializer.LocationSerializer( - paginated_queryset.get("queryset"), - many=True + paginated_queryset.get("queryset"), many=True ) return CustomResponse().paginated_response( - data=serializer.data, - pagination=paginated_queryset.get("pagination") + data=serializer.data, pagination=paginated_queryset.get("pagination") ) @role_required([RoleType.ADMIN.value]) def post(self, request): - user_id = JWTUtils.fetch_user_id(request) - + request_data = request.data + request_data["created_by"] = request_data[ + "updated_by" + ] = JWTUtils.fetch_user_id(request) serializer = location_serializer.CountryCreateEditSerializer( - data=request.data, - context={ - "user_id": user_id - } + data=request_data, ) if serializer.is_valid(): serializer.save() - return CustomResponse( - general_message="Country created Successfully" - ).get_success_response() + return CustomResponse(response=serializer.data).get_success_response() - return CustomResponse( - general_message=serializer.errors - ).get_failure_response() + return CustomResponse(general_message=serializer.errors).get_failure_response() @role_required([RoleType.ADMIN.value]) def patch(self, request, country_id): - user_id = JWTUtils.fetch_user_id(request) country = Country.objects.get(id=country_id) - + request_data = request.data + request_data["updated_by"] = JWTUtils.fetch_user_id(request) serializer = location_serializer.CountryCreateEditSerializer( - country, - data=request.data, - context={ - "user_id": user_id - } + country, data=request_data, partial=True ) if serializer.is_valid(): serializer.save() - return CustomResponse( - general_message="Country edited successfully" - ).get_success_response() + return CustomResponse(response=serializer.data).get_success_response() - return CustomResponse( - general_message=serializer.errors - ).get_failure_response() + return CustomResponse(general_message=serializer.errors).get_failure_response() @role_required([RoleType.ADMIN.value]) def delete(self, request, country_id): @@ -101,77 +78,60 @@ class StateDataAPI(APIView): @role_required([RoleType.ADMIN.value]) def get(self, request, state_id=None): - if state_id: states = State.objects.filter( - Q(pk=state_id) | - Q(country__pk=state_id) + Q(pk=state_id) | Q(country__pk=state_id) ).all() else: states = State.objects.all() paginated_queryset = CommonUtils.get_paginated_queryset( - states, - request, - [ - "name" - ], - { - "name": "name" - } + states, request, ["name"], {"name": "name"} ) serializer = location_serializer.StateRetrievalSerializer( - paginated_queryset.get("queryset"), - many=True + paginated_queryset.get("queryset"), many=True ) return CustomResponse().paginated_response( - data=serializer.data, - pagination=paginated_queryset.get("pagination") + data=serializer.data, pagination=paginated_queryset.get("pagination") ) @role_required([RoleType.ADMIN.value]) def post(self, request): - user_id = JWTUtils.fetch_user_id(request) + request_data = request.data + request_data["created_by"] = request_data[ + "updated_by" + ] = JWTUtils.fetch_user_id(request) serializer = location_serializer.StateCreateEditSerializer( - data=request.data, - context={ - "user_id": user_id - } + data=request_data, ) if serializer.is_valid(): serializer.save() return CustomResponse( - general_message="State created successfully" + response=serializer.data ).get_success_response() - return CustomResponse( - general_message=serializer.errors - ).get_failure_response() + return CustomResponse(general_message=serializer.errors).get_failure_response() @role_required([RoleType.ADMIN.value]) def patch(self, request, state_id): - user_id = JWTUtils.fetch_user_id(request) state = State.objects.get(id=state_id) - + request_data = request.data + request_data["updated_by"] = JWTUtils.fetch_user_id(request) serializer = location_serializer.StateCreateEditSerializer( - state, - data=request.data, - context={ - "user_id": user_id - } + state, data=request_data, partial=True ) if serializer.is_valid(): serializer.save() return CustomResponse( - general_message=serializer.data + response=serializer.data ).get_success_response() return CustomResponse( @@ -193,83 +153,63 @@ class ZoneDataAPI(APIView): @role_required([RoleType.ADMIN.value]) def get(self, request, zone_id=None): - if zone_id: zones = Zone.objects.filter( - Q(pk=zone_id) | - Q(state__pk=zone_id) | - Q(state__country__pk=zone_id) + Q(pk=zone_id) | Q(state__pk=zone_id) | Q(state__country__pk=zone_id) ).all() else: zones = Zone.objects.all() paginated_queryset = CommonUtils.get_paginated_queryset( - zones, - request, - [ - "name" - ], - { - "name": "name" - } + zones, request, ["name"], {"name": "name"} ) serializer = location_serializer.ZoneRetrievalSerializer( - paginated_queryset.get("queryset"), - many=True + paginated_queryset.get("queryset"), many=True ) return CustomResponse().paginated_response( - data=serializer.data, - pagination=paginated_queryset.get("pagination") + data=serializer.data, pagination=paginated_queryset.get("pagination") ) @role_required([RoleType.ADMIN.value]) def post(self, request): - user_id = JWTUtils.fetch_user_id(request) - + request_data = request.data + request_data["created_by"] = request_data[ + "updated_by" + ] = JWTUtils.fetch_user_id(request) serializer = location_serializer.ZoneCreateEditSerializer( - data=request.data, - context={ - "user_id": user_id - } + data=request.data, ) if serializer.is_valid(): serializer.save() return CustomResponse( - general_message="Zone created successfully" + response=serializer.data ).get_success_response() - return CustomResponse( - general_message=serializer.errors - ).get_failure_response() + return CustomResponse(general_message=serializer.errors).get_failure_response() @role_required([RoleType.ADMIN.value]) def patch(self, request, zone_id): - user_id = JWTUtils.fetch_user_id(request) + zone = Zone.objects.get(id=zone_id) - + request_data = request.data + request_data["updated_by"] = JWTUtils.fetch_user_id(request) serializer = location_serializer.ZoneCreateEditSerializer( - zone, - data=request.data, - context={ - "user_id": user_id - } + zone, data=request.data,partial=True ) if serializer.is_valid(): serializer.save() return CustomResponse( - general_message="zone edited successfully" + response=serializer.data ).get_success_response() - return CustomResponse( - general_message=serializer.errors - ).get_failure_response() + return CustomResponse(general_message=serializer.errors).get_failure_response() @role_required([RoleType.ADMIN.value]) def delete(self, request, zone_id): @@ -286,54 +226,44 @@ class DistrictDataAPI(APIView): @role_required([RoleType.ADMIN.value]) def get(self, request, district_id=None): - if district_id: districts = District.objects.filter( - Q(pk=district_id) | - Q(zone__pk=district_id) | - Q(zone__state__pk=district_id) | - Q(zone__state__country__pk=district_id) + Q(pk=district_id) + | Q(zone__pk=district_id) + | Q(zone__state__pk=district_id) + | Q(zone__state__country__pk=district_id) ).all() else: districts = District.objects.all() paginated_queryset = CommonUtils.get_paginated_queryset( - districts, - request, - [ - "name" - ], - { - "name": "name" - } + districts, request, ["name"], {"name": "name"} ) serializer = location_serializer.DistrictRetrievalSerializer( - paginated_queryset.get("queryset"), - many=True + paginated_queryset.get("queryset"), many=True ) return CustomResponse().paginated_response( - data=serializer.data, - pagination=paginated_queryset.get("pagination") + data=serializer.data, pagination=paginated_queryset.get("pagination") ) @role_required([RoleType.ADMIN.value]) def post(self, request): - user_id = JWTUtils.fetch_user_id(request) + request_data = request.data + request_data["created_by"] = request_data[ + "updated_by" + ] = JWTUtils.fetch_user_id(request) serializer = location_serializer.DistrictCreateEditSerializer( - data=request.data, - context={ - "user_id": user_id - } + data=request.data, ) if serializer.is_valid(): serializer.save() return CustomResponse( - general_message=serializer.data + response=serializer.data ).get_success_response() return CustomResponse( @@ -342,27 +272,21 @@ def post(self, request): @role_required([RoleType.ADMIN.value]) def patch(self, request, district_id): - user_id = JWTUtils.fetch_user_id(request) district = District.objects.get(id=district_id) - + request_data = request.data + request_data["updated_by"] = JWTUtils.fetch_user_id(request) serializer = location_serializer.DistrictCreateEditSerializer( - district, - data=request.data, - context={ - "user_id": user_id - } + district, data=request.data, partial=True ) if serializer.is_valid(): serializer.save() return CustomResponse( - general_message="Zone edited successfully" + response=serializer.data ).get_success_response() - return CustomResponse( - general_message=serializer.errors - ).get_failure_response() + return CustomResponse(general_message=serializer.errors).get_failure_response() @role_required([RoleType.ADMIN.value]) def delete(self, request, district_id): @@ -376,35 +300,20 @@ def delete(self, request, district_id): class CountryListApi(APIView): def get(self, request): - country = Country.objects.all().values( - 'id', - 'name' - ).order_by('name') + country = Country.objects.all().values("id", "name").order_by("name") - return CustomResponse( - response=country - ).get_success_response() + return CustomResponse(response=country).get_success_response() class StateListApi(APIView): def get(self, request): - state = State.objects.all().values( - 'id', - 'name' - ).order_by('name') + state = State.objects.all().values("id", "name").order_by("name") - return CustomResponse( - response=state - ).get_success_response() + return CustomResponse(response=state).get_success_response() class ZoneListApi(APIView): def get(self, request): - zone = Zone.objects.all().values( - 'id', - 'name' - ).order_by('name') + zone = Zone.objects.all().values("id", "name").order_by("name") - return CustomResponse( - response=zone - ).get_success_response() + return CustomResponse(response=zone).get_success_response() diff --git a/hello.py b/hello.py new file mode 100644 index 0000000000000000000000000000000000000000..d18651c757f6389e0bde675370583a1af6eb8e63 GIT binary patch literal 63336 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 Date: Mon, 6 Nov 2023 21:31:35 +0530 Subject: [PATCH 25/32] second commit --- api/dashboard/location/location_serializer.py | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/api/dashboard/location/location_serializer.py b/api/dashboard/location/location_serializer.py index e5f6076c..22bf624a 100644 --- a/api/dashboard/location/location_serializer.py +++ b/api/dashboard/location/location_serializer.py @@ -9,7 +9,8 @@ class LocationSerializer(serializers.ModelSerializer): label = serializers.CharField(source="name") value = serializers.CharField(source="id") - + created_by = serializers.CharField(source="created_by.fullname") + updated_by = serializers.CharField(source="updated_by.fullname") class Meta: model = Country fields = [ @@ -17,6 +18,8 @@ class Meta: "value" , "created_at", "updated_at", + "created_by", + "updated_by", ] @@ -33,7 +36,8 @@ class StateRetrievalSerializer(serializers.ModelSerializer): country = serializers.CharField(source="country.name", required=False, default=None) label = serializers.CharField(source="name") value = serializers.CharField(source="id") - + created_by = serializers.CharField(source="created_by.fullname") + updated_by = serializers.CharField(source="updated_by.fullname") class Meta: model = State fields = [ @@ -42,6 +46,8 @@ class Meta: "country", "created_at", "updated_at", + "created_by", + "updated_by", ] @@ -58,7 +64,8 @@ class ZoneRetrievalSerializer(serializers.ModelSerializer): state = serializers.CharField(source="state.name", required=False, default=None) label = serializers.CharField(source="name") value = serializers.CharField(source="id") - + created_by = serializers.CharField(source="created_by.fullname") + updated_by = serializers.CharField(source="updated_by.fullname") class Meta: model = Zone fields = [ @@ -67,6 +74,8 @@ class Meta: "state", "created_at", "updated_at", + "created_by", + "updated_by", ] @@ -83,7 +92,8 @@ class DistrictRetrievalSerializer(serializers.ModelSerializer): zone = serializers.CharField(source="zone.name", required=False, default=None) label = serializers.CharField(source="name") value = serializers.CharField(source="id") - + created_by = serializers.CharField(source="created_by.fullname") + updated_by = serializers.CharField(source="updated_by.fullname") class Meta: model = District fields = [ @@ -92,6 +102,8 @@ class Meta: "zone", "created_at", "updated_at", + "created_by", + "updated_by", ] From d1f871e014cfbe23f39e7f5a6eff006338d75fbe Mon Sep 17 00:00:00 2001 From: anirudh-mk Date: Mon, 6 Nov 2023 22:02:09 +0530 Subject: [PATCH 26/32] feat(organization models):OrgKarmaType and OrgKarmLog added --- db/organization.py | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/db/organization.py b/db/organization.py index f78433d7..ccaa560b 100644 --- a/db/organization.py +++ b/db/organization.py @@ -143,7 +143,6 @@ class Meta: db_table = 'org_discord_link' - class UserOrganizationLink(models.Model): id = models.CharField(primary_key=True, max_length=36, default=uuid.uuid4) user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='user_organization_link_user') @@ -159,6 +158,38 @@ class Meta: db_table = 'user_organization_link' +class OrgKarmaType(models.Model): + id = models.CharField(primary_key=True, max_length=36, default=uuid.uuid4()) + title = models.CharField(max_length=75) + karma = models.IntegerField() + description = models.CharField(max_length=200, blank=True, null=True) + updated_by = models.ForeignKey(User, models.DO_NOTHING, db_column='updated_by', related_name='org_karma_type_updated_by') + updated_at = models.DateTimeField(auto_now=True) + created_by = models.ForeignKey(User, models.DO_NOTHING, db_column='created_by', + related_name='org_karma_type_created_by') + created_at = models.DateTimeField(auto_now=True) + + class Meta: + managed = False + db_table = 'org_karma_type' + + +class OrgKarmaLog(models.Model): + id = models.CharField(primary_key=True, max_length=36, default=uuid.uuid4()) + org = models.ForeignKey(Organization, models.DO_NOTHING, related_name='org_karma_log_org') + karma = models.IntegerField() + type = models.ForeignKey(OrgKarmaType, models.DO_NOTHING, db_column='type', related_name='org_karma_log_type') + updated_by = models.ForeignKey(User, models.DO_NOTHING, db_column='updated_by', related_name='org_karma_log_updated_by') + updated_at = models.DateTimeField(auto_now=True) + created_by = models.ForeignKey(User, models.DO_NOTHING, db_column='created_by', + related_name='org_karma_log_created_by') + created_at = models.DateTimeField(auto_now=True) + + class Meta: + managed = False + db_table = 'org_karma_log' + + @property def total_karma(self): try: From 08743f3f5fcd937a1de01c94d4b9f5ac53fe276b Mon Sep 17 00:00:00 2001 From: aswanthabam Date: Mon, 6 Nov 2023 23:23:36 +0530 Subject: [PATCH 27/32] fix : profile picture upload (url) --- api/dashboard/profile/profile_serializer.py | 5 +++-- api/dashboard/profile/profile_view.py | 3 ++- api/dashboard/user/dash_user_views.py | 3 +-- mulearnbackend/urls.py | 9 +++++---- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/api/dashboard/profile/profile_serializer.py b/api/dashboard/profile/profile_serializer.py index 4731a2b1..8ee11149 100644 --- a/api/dashboard/profile/profile_serializer.py +++ b/api/dashboard/profile/profile_serializer.py @@ -4,7 +4,6 @@ from django.db.models import F, Sum, Q from rest_framework import serializers from rest_framework.serializers import ModelSerializer -from decouple import config as decouple_config from db.organization import UserOrganizationLink from db.task import InterestGroup, KarmaActivityLog, Level, TaskList, Wallet, UserIgLink, UserLvlLink @@ -60,14 +59,16 @@ class Meta: "interest_groups", "is_public", ) + def get_profile_pic(self,obj): fs = FileSystemStorage() path = f'user/profile/{obj.id}.png' if fs.exists(path): - profile_pic = f"{decouple_config('FR_DOMAIN_NAME')}{fs.url(path)}" + profile_pic = f"{self.context.get('request').build_absolute_uri('/')}{fs.url(path)[1:]}" 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.all()}) diff --git a/api/dashboard/profile/profile_view.py b/api/dashboard/profile/profile_view.py index 9f231cf2..d49702ba 100644 --- a/api/dashboard/profile/profile_view.py +++ b/api/dashboard/profile/profile_view.py @@ -139,7 +139,8 @@ def get(self, request, muid=None): serializer = profile_serializer.UserProfileSerializer( user, - many=False + many=False, + context={'request':request} ) return CustomResponse( diff --git a/api/dashboard/user/dash_user_views.py b/api/dashboard/user/dash_user_views.py index 2fa094e7..1be34a08 100644 --- a/api/dashboard/user/dash_user_views.py +++ b/api/dashboard/user/dash_user_views.py @@ -12,7 +12,6 @@ from utils.utils import CommonUtils, DateTimeUtils, DiscordWebhooks, send_template_mail from . import dash_user_serializer from django.core.files.storage import FileSystemStorage -from decouple import config as decouple_config class UserInfoAPI(APIView): authentication_classes = [CustomizePermission] @@ -420,7 +419,7 @@ def post(self, request): fs.delete(filename) filename = fs.save(filename, pic) file_url = fs.url(filename) - uploaded_file_url = f"{decouple_config('FR_DOMAIN_NAME')}{file_url}" + uploaded_file_url = f"{request.build_absolute_uri('/')}{file_url[1:]}" return CustomResponse( response={ diff --git a/mulearnbackend/urls.py b/mulearnbackend/urls.py index 7da20c5a..1cebec42 100644 --- a/mulearnbackend/urls.py +++ b/mulearnbackend/urls.py @@ -15,14 +15,15 @@ """ from django.conf import settings -from django.conf.urls.static import static +# from django.conf.urls.static import static # from django.contrib import admin -from django.urls import path, include +from django.urls import path, include, re_path +from django.views.static import serve urlpatterns = [ # path('admin/', admin.site.urls), path('api/v1/', include('api.urls')), - + re_path(r'^muback-media/(?P.*)$',serve,{'document_root':settings.MEDIA_ROOT}) ] -urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) +# urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) From c636ed898c42a11a35dcf382d41de1a304af14f6 Mon Sep 17 00:00:00 2001 From: Muhammed Zafar Date: Tue, 7 Nov 2023 00:44:09 +0530 Subject: [PATCH 28/32] [DELETE] Unecessary files --- hello.py | Bin 63336 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 hello.py diff --git a/hello.py b/hello.py deleted file mode 100644 index d18651c757f6389e0bde675370583a1af6eb8e63..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63336 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 Date: Tue, 7 Nov 2023 10:32:52 +0530 Subject: [PATCH 29/32] [PATCH] Remove more instances of user active --- api/dashboard/user/dash_user_serializer.py | 1 - api/dashboard/user/dash_user_views.py | 152 +++++++-------------- 2 files changed, 50 insertions(+), 103 deletions(-) diff --git a/api/dashboard/user/dash_user_serializer.py b/api/dashboard/user/dash_user_serializer.py index e873275c..d20d6808 100644 --- a/api/dashboard/user/dash_user_serializer.py +++ b/api/dashboard/user/dash_user_serializer.py @@ -45,7 +45,6 @@ class Meta: "mobile", "gender", "dob", - "active", "exist_in_guild", "joined", "roles", diff --git a/api/dashboard/user/dash_user_views.py b/api/dashboard/user/dash_user_views.py index 1be34a08..3dccb574 100644 --- a/api/dashboard/user/dash_user_views.py +++ b/api/dashboard/user/dash_user_views.py @@ -13,6 +13,7 @@ from . import dash_user_serializer from django.core.files.storage import FileSystemStorage + class UserInfoAPI(APIView): authentication_classes = [CustomizePermission] @@ -25,14 +26,9 @@ def get(self, request): general_message="No user data available" ).get_failure_response() - response = dash_user_serializer.UserSerializer( - user, - many=False - ).data + response = dash_user_serializer.UserSerializer(user, many=False).data - return CustomResponse( - response=response - ).get_success_response() + return CustomResponse(response=response).get_success_response() class UserGetPatchDeleteAPI(APIView): @@ -49,9 +45,7 @@ def get(self, request, user_id): serializer = dash_user_serializer.UserDetailsSerializer(user) - return CustomResponse( - response=serializer.data - ).get_success_response() + return CustomResponse(response=serializer.data).get_success_response() @role_required([RoleType.ADMIN.value]) def delete(self, request, user_id): @@ -62,7 +56,8 @@ def delete(self, request, user_id): general_message="User Not Available" ).get_failure_response() - user.active = False + user.deleted_by = User.objects.get(pk=JWTUtils.fetch_user_id(request)) + user.deleted_at = DateTimeUtils.get_current_utc_time() user.save() return CustomResponse( @@ -76,24 +71,19 @@ def patch(self, request, user_id): request.data["admin"] = JWTUtils.fetch_user_id(request) serializer = dash_user_serializer.UserDetailsEditSerializer( - user, data=request.data, - partial=True + user, data=request.data, partial=True ) if serializer.is_valid(): serializer.save() DiscordWebhooks.general_updates( - WebHookCategory.USER.value, - WebHookActions.UPDATE.value, - user_id + WebHookCategory.USER.value, WebHookActions.UPDATE.value, user_id ) return CustomResponse( general_message="User Edited Successfully" ).get_success_response() - return CustomResponse( - general_message=serializer.errors - ).get_failure_response() + return CustomResponse(general_message=serializer.errors).get_failure_response() class UserAPI(APIView): @@ -102,9 +92,7 @@ class UserAPI(APIView): @role_required([RoleType.ADMIN.value]) def get(self, request): user_queryset = User.objects.select_related( - "wallet_user", - "user_lvl_link_user", - "user_lvl_link_user__level" + "wallet_user", "user_lvl_link_user", "user_lvl_link_user__level" ).all() queryset = CommonUtils.get_paginated_queryset( @@ -126,13 +114,11 @@ def get(self, request): }, ) serializer = dash_user_serializer.UserDashboardSerializer( - queryset.get("queryset"), - many=True + queryset.get("queryset"), many=True ) return CustomResponse().paginated_response( - data=serializer.data, - pagination=queryset.get("pagination") + data=serializer.data, pagination=queryset.get("pagination") ) @@ -142,20 +128,14 @@ class UserManagementCSV(APIView): @role_required([RoleType.ADMIN.value]) def get(self, request): user_queryset = User.objects.select_related( - "wallet_user", - "user_lvl_link_user", - "user_lvl_link_user__level" + "wallet_user", "user_lvl_link_user", "user_lvl_link_user__level" ).all() serializer = dash_user_serializer.UserDashboardSerializer( - user_queryset, - many=True + user_queryset, many=True ) - return CommonUtils.generate_csv( - serializer.data, - "User" - ) + return CommonUtils.generate_csv(serializer.data, "User") class UserVerificationAPI(APIView): @@ -163,13 +143,10 @@ class UserVerificationAPI(APIView): @role_required([RoleType.ADMIN.value]) def get(self, request): - user_queryset = UserRoleLink.objects.select_related( - "user", - "role" - ).filter( + user_queryset = UserRoleLink.objects.select_related("user", "role").filter( verified=False ) - + queryset = CommonUtils.get_paginated_queryset( user_queryset, request, @@ -190,15 +167,11 @@ def get(self, request): }, ) serializer = dash_user_serializer.UserVerificationSerializer( - queryset.get( - "queryset" - ), - many=True + queryset.get("queryset"), many=True ) return CustomResponse().paginated_response( - data=serializer.data, - pagination=queryset.get("pagination") + data=serializer.data, pagination=queryset.get("pagination") ) @role_required([RoleType.ADMIN.value]) @@ -206,9 +179,7 @@ def patch(self, request, link_id): user = UserRoleLink.objects.get(id=link_id) user_serializer = dash_user_serializer.UserVerificationSerializer( - user, - data=request.data, - partial=True + user, data=request.data, partial=True ) if not user_serializer.is_valid(): @@ -250,19 +221,14 @@ class UserVerificationCSV(APIView): @role_required([RoleType.ADMIN.value]) def get(self, request): - user_queryset = UserRoleLink.objects.select_related( - "user", - "role" - ).filter(verified=False) - - serializer = dash_user_serializer.UserVerificationSerializer( - user_queryset, - many=True + user_queryset = UserRoleLink.objects.select_related("user", "role").filter( + verified=False ) - return CommonUtils.generate_csv( - serializer.data, - "User" + + serializer = dash_user_serializer.UserVerificationSerializer( + user_queryset, many=True ) + return CommonUtils.generate_csv(serializer.data, "User") class ForgotPasswordAPI(APIView): @@ -271,8 +237,7 @@ def post(self, request): if not ( user := User.objects.filter( - Q(muid=email_muid) | - Q(email=email_muid) + Q(muid=email_muid) | Q(email=email_muid) ).first() ): return CustomResponse( @@ -283,10 +248,7 @@ def post(self, request): expiry = created_at + timedelta(seconds=900) # 15 minutes forget_user = ForgotPassword.objects.create( - id=uuid.uuid4(), - user=user, - expiry=expiry, - created_at=created_at + id=uuid.uuid4(), user=user, expiry=expiry, created_at=created_at ) receiver_mail = user.email @@ -310,7 +272,6 @@ def post(self, request): class ResetPasswordVerifyTokenAPI(APIView): def post(self, request, token): if not (forget_user := ForgotPassword.objects.filter(id=token).first()): - return CustomResponse( general_message="Invalid Token" ).get_failure_response() @@ -319,9 +280,7 @@ def post(self, request, token): if forget_user.expiry > current_time: muid = forget_user.user.muid - return CustomResponse( - response={"muid": muid} - ).get_success_response() + return CustomResponse(response={"muid": muid}).get_success_response() else: forget_user.delete() return CustomResponse( @@ -332,24 +291,17 @@ def post(self, request, token): class ResetPasswordConfirmAPI(APIView): def post(self, request, token): if not (forget_user := ForgotPassword.objects.filter(id=token).first()): - return CustomResponse( general_message="Invalid Token" ).get_failure_response() current_time = DateTimeUtils.get_current_utc_time() if forget_user.expiry > current_time: - - return self.save_password( - request, - forget_user - ) + return self.save_password(request, forget_user) forget_user.delete() - return CustomResponse( - general_message="Link is expired" - ).get_failure_response() + return CustomResponse(general_message="Link is expired").get_failure_response() def save_password(self, request, forget_user): new_password = request.data.get("password") @@ -363,11 +315,11 @@ def save_password(self, request, forget_user): general_message="New Password Saved Successfully" ).get_success_response() -class UserProfilePictureView(APIView): +class UserProfilePictureView(APIView): # def get(self, request, user_id): # user = User.objects.filter(id=user_id).first() - + # if user is None: # return CustomResponse( # general_message="No user data available" @@ -381,38 +333,38 @@ class UserProfilePictureView(APIView): # general_message="No Profile picture available" # ).get_failure_response() - def patch(self,request): + def patch(self, request): DiscordWebhooks.general_updates( - WebHookCategory.USER_PROFILE.value, - WebHookActions.UPDATE.value, - JWTUtils.fetch_user_id(request) - ) + WebHookCategory.USER_PROFILE.value, + WebHookActions.UPDATE.value, + JWTUtils.fetch_user_id(request), + ) return CustomResponse( - general_message="Successfully updated" - ).get_success_response() - + general_message="Successfully updated" + ).get_success_response() + def post(self, request): - user_id = request.data.get('user_id') + user_id = request.data.get("user_id") user = User.objects.filter(id=user_id).first() if user is None: return CustomResponse( general_message="No user data available" ).get_failure_response() - - pic = request.FILES.get('profile') - + + pic = request.FILES.get("profile") + if pic is None: return CustomResponse( general_message="No profile picture" ).get_failure_response() - + if not pic.content_type.startswith("image/"): return CustomResponse( general_message="Expected an image" ).get_failure_response() - - extention = '.png' # os.path.splitext(pic.name)[1] + + extention = ".png" # os.path.splitext(pic.name)[1] fs = FileSystemStorage() filename = f"user/profile/{user_id}{extention}" if fs.exists(filename): @@ -420,11 +372,7 @@ def post(self, request): filename = fs.save(filename, pic) file_url = fs.url(filename) uploaded_file_url = f"{request.build_absolute_uri('/')}{file_url[1:]}" - + return CustomResponse( - response={ - 'user_id':user.id, - 'profile_pic':uploaded_file_url - } + response={"user_id": user.id, "profile_pic": uploaded_file_url} ).get_success_response() - From 255c7e2c4210685d5ce65a2aa3286ad62da4c899 Mon Sep 17 00:00:00 2001 From: anirudh-mk Date: Tue, 7 Nov 2023 20:39:54 +0530 Subject: [PATCH 30/32] feat(organization models):OrgKarmaType and OrgKarmLog added --- .../organisation/organisation_views.py | 48 ++++++++++++++++++- api/dashboard/organisation/serializers.py | 38 +++++++++++++++ api/dashboard/organisation/urls.py | 4 +- 3 files changed, 88 insertions(+), 2 deletions(-) diff --git a/api/dashboard/organisation/organisation_views.py b/api/dashboard/organisation/organisation_views.py index a9b059e0..23c45fb7 100644 --- a/api/dashboard/organisation/organisation_views.py +++ b/api/dashboard/organisation/organisation_views.py @@ -19,7 +19,8 @@ InstitutionCreateUpdateSerializer, InstitutionSerializer, InstitutionPrefillSerializer, - OrganizationMergerSerializer, + OrganizationMergerSerializer, OrganizationKarmaTypeGetPostPatchDeleteSerializer, + OrganizationKarmaLogGetPostPatchDeleteSerializer, ) @@ -470,3 +471,48 @@ def patch(self, request, organisation_id): return CustomResponse( general_message="An organization with the given id doesn't exist" ).get_failure_response() + + +class OrganizationKarmaTypeGetPostPatchDeleteAPI(APIView): + def post(self, request): + user_id = JWTUtils.fetch_user_id(request) + + serializer = OrganizationKarmaTypeGetPostPatchDeleteSerializer( + data=request.data, + context={ + 'user_id': user_id + } + ) + if serializer.is_valid(): + serializer.save() + + return CustomResponse( + "Organization karma type created successfully" + ).get_success_response() + + return CustomResponse( + serializer.errors + ).get_failure_response() + + +class OrganizationKarmaLogGetPostPatchDeleteAPI(APIView): + def post(self, request): + user_id = JWTUtils.fetch_user_id(request) + + serializer = OrganizationKarmaLogGetPostPatchDeleteSerializer( + data=request.data, + context={ + 'user_id': user_id + } + ) + + if serializer.is_valid(): + serializer.save() + + return CustomResponse( + "Organization karma Log created successfully" + ).get_success_response() + + return CustomResponse( + serializer.errors + ).get_failure_response() diff --git a/api/dashboard/organisation/serializers.py b/api/dashboard/organisation/serializers.py index bbe869e2..d4d760d2 100644 --- a/api/dashboard/organisation/serializers.py +++ b/api/dashboard/organisation/serializers.py @@ -11,6 +11,8 @@ State, OrgAffiliation, Department, + OrgKarmaType, + OrgKarmaLog, ) from utils.permission import JWTUtils from utils.types import OrganizationType @@ -361,3 +363,39 @@ def update(self, instance, validated_data): source_org.delete() return instance + + +class OrganizationKarmaTypeGetPostPatchDeleteSerializer(serializers.ModelSerializer): + + class Meta: + model = OrgKarmaType + fields = [ + "title", + "karma", + "description", + ] + + def create(self, validated_data): + user_id = self.context.get("user_id") + validated_data["updated_by_id"] = user_id + validated_data["created_by_id"] = user_id + + return OrgKarmaType.objects.create(**validated_data) + + +class OrganizationKarmaLogGetPostPatchDeleteSerializer(serializers.ModelSerializer): + + class Meta: + model = OrgKarmaLog + fields = [ + "org", + "karma", + "type", + ] + + def create(self, validated_data): + user_id = self.context.get("user_id") + validated_data["updated_by_id"] = user_id + validated_data["created_by_id"] = user_id + + return OrgKarmaLog.objects.create(**validated_data) diff --git a/api/dashboard/organisation/urls.py b/api/dashboard/organisation/urls.py index 5c9f9694..fc588ee9 100644 --- a/api/dashboard/organisation/urls.py +++ b/api/dashboard/organisation/urls.py @@ -21,5 +21,7 @@ path('departments/edit//', organisation_views.DepartmentAPI.as_view()), path('departments/delete//', organisation_views.DepartmentAPI.as_view()), path('affiliation/list/', organisation_views.AffiliationListAPI.as_view()), - path('merge_organizations//', organisation_views.OrganizationMergerView.as_view()) + path('merge_organizations//', organisation_views.OrganizationMergerView.as_view()), + path('karma-type/create/', organisation_views.OrganizationKarmaTypeGetPostPatchDeleteAPI.as_view()), + path('karma-log/create/', organisation_views.OrganizationKarmaLogGetPostPatchDeleteAPI.as_view()), ] From a75164d861429efa66140c3667cd8abb51fd3374 Mon Sep 17 00:00:00 2001 From: lordgrim Date: Wed, 8 Nov 2023 06:46:59 +0530 Subject: [PATCH 31/32] fix(task): column name in csv generator api --- api/dashboard/task/dash_task_serializer.py | 2 +- api/dashboard/task/dash_task_view.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/api/dashboard/task/dash_task_serializer.py b/api/dashboard/task/dash_task_serializer.py index 766f05dd..a64fc2d5 100644 --- a/api/dashboard/task/dash_task_serializer.py +++ b/api/dashboard/task/dash_task_serializer.py @@ -4,7 +4,7 @@ class TaskListSerializer(serializers.ModelSerializer): - channel = serializers.CharField(source="channels.name", required=False, default=None) + channel = serializers.CharField(source="channel.name", required=False, default=None) type = serializers.CharField(source="type.title") level = serializers.CharField(source="level.name", required=False, default=None) ig = serializers.CharField(source="ig.name", required=False, default=None) diff --git a/api/dashboard/task/dash_task_view.py b/api/dashboard/task/dash_task_view.py index 14dda5b8..c555355b 100644 --- a/api/dashboard/task/dash_task_view.py +++ b/api/dashboard/task/dash_task_view.py @@ -199,7 +199,7 @@ def get(self, request): task_queryset = TaskList.objects.select_related( "created_by", "updated_by", - "channels", + "channel", "type", "level", "ig", From 4097caac27cb8268e41639e31ca636fcb722bd19 Mon Sep 17 00:00:00 2001 From: SurajSuresh123 Date: Wed, 8 Nov 2023 20:37:40 +0530 Subject: [PATCH 32/32] third commit --- api/dashboard/location/location_serializer.py | 22 ++++- api/dashboard/location/location_views.py | 93 +++++++++++-------- 2 files changed, 73 insertions(+), 42 deletions(-) diff --git a/api/dashboard/location/location_serializer.py b/api/dashboard/location/location_serializer.py index 22bf624a..2b541223 100644 --- a/api/dashboard/location/location_serializer.py +++ b/api/dashboard/location/location_serializer.py @@ -11,11 +11,12 @@ class LocationSerializer(serializers.ModelSerializer): value = serializers.CharField(source="id") created_by = serializers.CharField(source="created_by.fullname") updated_by = serializers.CharField(source="updated_by.fullname") + class Meta: model = Country fields = [ "label", - "value" , + "value", "created_at", "updated_at", "created_by", @@ -29,7 +30,7 @@ class CountryCreateEditSerializer(serializers.ModelSerializer): # value = serializers.CharField(source="id") class Meta: model = Country - fields = ["label","updated_by", "created_by"] + fields = ["label", "updated_by", "created_by"] class StateRetrievalSerializer(serializers.ModelSerializer): @@ -38,6 +39,7 @@ class StateRetrievalSerializer(serializers.ModelSerializer): value = serializers.CharField(source="id") created_by = serializers.CharField(source="created_by.fullname") updated_by = serializers.CharField(source="updated_by.fullname") + class Meta: model = State fields = [ @@ -61,16 +63,21 @@ class Meta: class ZoneRetrievalSerializer(serializers.ModelSerializer): + country = serializers.CharField( + source="state.country.name", required=False, default=None + ) state = serializers.CharField(source="state.name", required=False, default=None) label = serializers.CharField(source="name") value = serializers.CharField(source="id") created_by = serializers.CharField(source="created_by.fullname") updated_by = serializers.CharField(source="updated_by.fullname") + class Meta: model = Zone fields = [ "label", "value", + "country", "state", "created_at", "updated_at", @@ -89,16 +96,25 @@ class Meta: class DistrictRetrievalSerializer(serializers.ModelSerializer): + country = serializers.CharField( + source="zone.state.country.name", required=False, default=None + ) + state = serializers.CharField( + source="zone.state.name", required=False, default=None + ) zone = serializers.CharField(source="zone.name", required=False, default=None) label = serializers.CharField(source="name") value = serializers.CharField(source="id") created_by = serializers.CharField(source="created_by.fullname") updated_by = serializers.CharField(source="updated_by.fullname") + class Meta: model = District fields = [ "label", "value", + "country", + "state", "zone", "created_at", "updated_at", @@ -113,4 +129,4 @@ class DistrictCreateEditSerializer(serializers.ModelSerializer): class Meta: model = District - fields = ["label","created_by", "updated_by"] + fields = ["label", "created_by", "updated_by"] diff --git a/api/dashboard/location/location_views.py b/api/dashboard/location/location_views.py index e2afff28..a4e7fc30 100644 --- a/api/dashboard/location/location_views.py +++ b/api/dashboard/location/location_views.py @@ -16,9 +16,11 @@ class CountryDataAPI(APIView): @role_required([RoleType.ADMIN.value]) def get(self, request, country_id=None): if country_id: - countries = Country.objects.filter(id=country_id) + countries = Country.objects.filter(id=country_id).select_related( + "created_by", "updated_by" + ) else: - countries = Country.objects.all() + countries = Country.objects.all().select_related("created_by", "updated_by") paginated_queryset = CommonUtils.get_paginated_queryset( countries, request, ["name"], {"label": "name"} @@ -79,12 +81,16 @@ class StateDataAPI(APIView): @role_required([RoleType.ADMIN.value]) def get(self, request, state_id=None): if state_id: - states = State.objects.filter( - Q(pk=state_id) | Q(country__pk=state_id) - ).all() + states = ( + State.objects.filter(Q(pk=state_id) | Q(country__pk=state_id)) + .all() + .select_related("country", "created_by", "updated_by") + ) else: - states = State.objects.all() + states = State.objects.all().select_related( + "country", "created_by", "updated_by" + ) paginated_queryset = CommonUtils.get_paginated_queryset( states, request, ["name"], {"name": "name"} @@ -112,9 +118,7 @@ def post(self, request): if serializer.is_valid(): serializer.save() - return CustomResponse( - response=serializer.data - ).get_success_response() + return CustomResponse(response=serializer.data).get_success_response() return CustomResponse(general_message=serializer.errors).get_failure_response() @@ -130,9 +134,7 @@ def patch(self, request, state_id): if serializer.is_valid(): serializer.save() - return CustomResponse( - response=serializer.data - ).get_success_response() + return CustomResponse(response=serializer.data).get_success_response() return CustomResponse( general_message="State edited successfully" @@ -154,12 +156,18 @@ class ZoneDataAPI(APIView): @role_required([RoleType.ADMIN.value]) def get(self, request, zone_id=None): if zone_id: - zones = Zone.objects.filter( - Q(pk=zone_id) | Q(state__pk=zone_id) | Q(state__country__pk=zone_id) - ).all() + zones = ( + Zone.objects.filter( + Q(pk=zone_id) | Q(state__pk=zone_id) | Q(state__country__pk=zone_id) + ) + .all() + .select_related("state", "state__country", "created_by", "updated_by") + ) else: - zones = Zone.objects.all() + zones = Zone.objects.all().select_related( + "state", "state__country", "created_by", "updated_by" + ) paginated_queryset = CommonUtils.get_paginated_queryset( zones, request, ["name"], {"name": "name"} @@ -180,34 +188,29 @@ def post(self, request): "updated_by" ] = JWTUtils.fetch_user_id(request) serializer = location_serializer.ZoneCreateEditSerializer( - data=request.data, + data=request.data, ) if serializer.is_valid(): serializer.save() - return CustomResponse( - response=serializer.data - ).get_success_response() + return CustomResponse(response=serializer.data).get_success_response() return CustomResponse(general_message=serializer.errors).get_failure_response() @role_required([RoleType.ADMIN.value]) def patch(self, request, zone_id): - zone = Zone.objects.get(id=zone_id) request_data = request.data request_data["updated_by"] = JWTUtils.fetch_user_id(request) serializer = location_serializer.ZoneCreateEditSerializer( - zone, data=request.data,partial=True + zone, data=request.data, partial=True ) if serializer.is_valid(): serializer.save() - return CustomResponse( - response=serializer.data - ).get_success_response() + return CustomResponse(response=serializer.data).get_success_response() return CustomResponse(general_message=serializer.errors).get_failure_response() @@ -227,15 +230,31 @@ class DistrictDataAPI(APIView): @role_required([RoleType.ADMIN.value]) def get(self, request, district_id=None): if district_id: - districts = District.objects.filter( - Q(pk=district_id) - | Q(zone__pk=district_id) - | Q(zone__state__pk=district_id) - | Q(zone__state__country__pk=district_id) - ).all() + districts = ( + District.objects.filter( + Q(pk=district_id) + | Q(zone__pk=district_id) + | Q(zone__state__pk=district_id) + | Q(zone__state__country__pk=district_id) + ) + .all() + .select_related( + "zone", + "zone__state", + "zone__state__country", + "created_by", + "updated_by", + ) + ) else: - districts = District.objects.all() + districts = District.objects.all().select_related( + "zone", + "zone__state", + "zone__state__country", + "created_by", + "updated_by", + ) paginated_queryset = CommonUtils.get_paginated_queryset( districts, request, ["name"], {"name": "name"} @@ -257,14 +276,12 @@ def post(self, request): ] = JWTUtils.fetch_user_id(request) serializer = location_serializer.DistrictCreateEditSerializer( - data=request.data, + data=request.data, ) if serializer.is_valid(): serializer.save() - return CustomResponse( - response=serializer.data - ).get_success_response() + return CustomResponse(response=serializer.data).get_success_response() return CustomResponse( general_message="Zone created successfully" @@ -282,9 +299,7 @@ def patch(self, request, district_id): if serializer.is_valid(): serializer.save() - return CustomResponse( - response=serializer.data - ).get_success_response() + return CustomResponse(response=serializer.data).get_success_response() return CustomResponse(general_message=serializer.errors).get_failure_response()