From 9bb1f0e904320da3395dec71c5b874522f375a0e Mon Sep 17 00:00:00 2001 From: AlfrinP Date: Fri, 5 Jul 2024 21:06:00 +0530 Subject: [PATCH 1/3] feat: transfer user api implemented --- .../organisation/organisation_views.py | 135 ++++++++++-------- api/dashboard/organisation/urls.py | 1 + 2 files changed, 78 insertions(+), 58 deletions(-) diff --git a/api/dashboard/organisation/organisation_views.py b/api/dashboard/organisation/organisation_views.py index 36540844..eb9d906b 100644 --- a/api/dashboard/organisation/organisation_views.py +++ b/api/dashboard/organisation/organisation_views.py @@ -6,7 +6,6 @@ from django.http import FileResponse from openpyxl import load_workbook from rest_framework.views import APIView - from db.organization import ( Department, OrgAffiliation, @@ -14,6 +13,8 @@ UserOrganizationLink, District, ) +from db.user import User + from utils.permission import CustomizePermission, JWTUtils, role_required from utils.response import CustomResponse from utils.types import OrganizationType, RoleType, WebHookActions, WebHookCategory @@ -25,9 +26,10 @@ InstitutionCreateUpdateSerializer, InstitutionSerializer, InstitutionPrefillSerializer, - OrganizationMergerSerializer, OrganizationKarmaTypeGetPostPatchDeleteSerializer, + OrganizationMergerSerializer, + OrganizationKarmaTypeGetPostPatchDeleteSerializer, OrganizationKarmaLogGetPostPatchDeleteSerializer, - OrganizationImportSerializer + OrganizationImportSerializer, ) @@ -80,8 +82,8 @@ def put(self, request, org_code): serializer.save() if ( - request.data.get("title") != old_title - and old_type == OrganizationType.COMMUNITY.value + request.data.get("title") != old_title + and old_type == OrganizationType.COMMUNITY.value ): DiscordWebhooks.general_updates( WebHookCategory.COMMUNITY.value, @@ -91,8 +93,8 @@ def put(self, request, org_code): ) if ( - request.data.get("orgType") != OrganizationType.COMMUNITY.value - and old_type == OrganizationType.COMMUNITY.value + request.data.get("orgType") != OrganizationType.COMMUNITY.value + and old_type == OrganizationType.COMMUNITY.value ): DiscordWebhooks.general_updates( WebHookCategory.COMMUNITY.value, @@ -101,8 +103,8 @@ def put(self, request, org_code): ) if ( - old_type != OrganizationType.COMMUNITY.value - and request.data.get("orgType") == OrganizationType.COMMUNITY.value + old_type != OrganizationType.COMMUNITY.value + and request.data.get("orgType") == OrganizationType.COMMUNITY.value ): title = request.data.get("title") or old_title DiscordWebhooks.general_updates( @@ -485,10 +487,7 @@ def post(self, request): user_id = JWTUtils.fetch_user_id(request) serializer = OrganizationKarmaTypeGetPostPatchDeleteSerializer( - data=request.data, - context={ - 'user_id': user_id - } + data=request.data, context={"user_id": user_id} ) if serializer.is_valid(): serializer.save() @@ -497,9 +496,7 @@ def post(self, request): "Organization karma type created successfully" ).get_success_response() - return CustomResponse( - serializer.errors - ).get_failure_response() + return CustomResponse(serializer.errors).get_failure_response() class OrganizationKarmaLogGetPostPatchDeleteAPI(APIView): @@ -507,10 +504,7 @@ def post(self, request): user_id = JWTUtils.fetch_user_id(request) serializer = OrganizationKarmaLogGetPostPatchDeleteSerializer( - data=request.data, - context={ - 'user_id': user_id - } + data=request.data, context={"user_id": user_id} ) if serializer.is_valid(): @@ -520,25 +514,23 @@ def post(self, request): "Organization karma Log created successfully" ).get_success_response() - return CustomResponse( - serializer.errors - ).get_failure_response() + return CustomResponse(serializer.errors).get_failure_response() class OrganisationBaseTemplateAPI(APIView): authentication_classes = [CustomizePermission] def get(self, request): - wb = load_workbook('./excel-templates/organisation_base_template.xlsx') - ws = wb['Data Definitions'] - affiliations = OrgAffiliation.objects.all().values_list('title', flat=True) - districts = District.objects.all().values_list('name', flat=True) + wb = load_workbook("./excel-templates/organisation_base_template.xlsx") + ws = wb["Data Definitions"] + affiliations = OrgAffiliation.objects.all().values_list("title", flat=True) + districts = District.objects.all().values_list("name", flat=True) org_types = OrganizationType.get_all_values() data = { - 'org_type': org_types, - 'affiliation': affiliations, - 'district': districts, + "org_type": org_types, + "affiliation": affiliations, + "district": districts, } # Write data column-wise for col_num, (col_name, col_values) in enumerate(data.items(), start=1): @@ -548,10 +540,14 @@ def get(self, request): with NamedTemporaryFile() as tmp: tmp.close() # with statement opened tmp, close it so wb.save can open it wb.save(tmp.name) - with open(tmp.name, 'rb') as f: + with open(tmp.name, "rb") as f: f.seek(0) new_file_object = f.read() - return FileResponse(BytesIO(new_file_object), as_attachment=True, filename='organisation_base_template.xlsx') + return FileResponse( + BytesIO(new_file_object), + as_attachment=True, + filename="organisation_base_template.xlsx", + ) class OrganisationImportAPI(APIView): @@ -574,13 +570,7 @@ def post(self, request): general_message="Empty csv file." ).get_failure_response() - temp_headers = [ - "title", - "code", - "org_type", - "affiliation", - "district" - ] + temp_headers = ["title", "code", "org_type", "affiliation", "district"] first_entry = excel_data[0] for key in temp_headers: if key not in first_entry: @@ -647,19 +637,15 @@ def post(self, request): affiliations = OrgAffiliation.objects.filter( title__in=affiliations_to_fetch - ).values( - "id", - "title" - ) + ).values("id", "title") - districts = District.objects.filter( - name__in=districts_to_fetch - ).values( - "id", - "name" + districts = District.objects.filter(name__in=districts_to_fetch).values( + "id", "name" ) - affiliations_dict = {affiliation["title"]: affiliation["id"] for affiliation in affiliations} + affiliations_dict = { + affiliation["title"]: affiliation["id"] for affiliation in affiliations + } districts_dict = {district["name"]: district["id"] for district in districts} org_types = OrganizationType.get_all_values() @@ -667,7 +653,9 @@ def post(self, request): affiliation = row.pop("affiliation") district = row.pop("district") - affiliation_id = affiliations_dict.get(affiliation) if affiliation is not None else None + affiliation_id = ( + affiliations_dict.get(affiliation) if affiliation is not None else None + ) district_id = districts_dict.get(district) org_type = row.get("org_type") @@ -689,21 +677,52 @@ def post(self, request): row["district_id"] = district_id valid_rows.append(row) - organization_list_serializer = OrganizationImportSerializer(data=valid_rows, many=True) + organization_list_serializer = OrganizationImportSerializer( + data=valid_rows, many=True + ) success_data = [] if organization_list_serializer.is_valid(): organization_list_serializer.save() for organization_data in organization_list_serializer.data: - success_data.append({ - 'title': organization_data.get('title', ''), - 'code': organization_data.get('code', ''), - 'org_type': organization_data.get('org_type', ''), - 'affiliation': organization_data.get('affiliation_id', ''), - 'district': organization_data.get('district_id', ''), - }) + success_data.append( + { + "title": organization_data.get("title", ""), + "code": organization_data.get("code", ""), + "org_type": organization_data.get("org_type", ""), + "affiliation": organization_data.get("affiliation_id", ""), + "district": organization_data.get("district_id", ""), + } + ) else: error_rows.append(organization_list_serializer.errors) return CustomResponse( response={"Success": success_data, "Failed": error_rows} ).get_success_response() + + +class TransferAPI(APIView): + def post(self, request): + fromcode = request.data.get("fromid") + tocode = request.data.get("toid") + if not (from_org := Organization.objects.filter(code=fromcode).first()): + return CustomResponse( + response={"No organisations present"} + ).get_failure_response() + user_org_links = UserOrganizationLink.objects.filter(org=from_org).update( + org=Organization.objects.filter(code=tocode) + ) + if user_org_links.none: + # if user_org_links.exists(): + # users_effected = [] + # for user_org_link in user_org_links: + # main_user = user_org_link.user + # main_user.org = get_object_or_404(Organization, code=tocode) + # main_user.save() + # users_effected.append(main_user) + return CustomResponse(response={"No Users present"}).get_failure_response() + else: + + return CustomResponse( + response={"Organisations transferred successfully"} + ).get_success_response() diff --git a/api/dashboard/organisation/urls.py b/api/dashboard/organisation/urls.py index e02e0998..9006b6b6 100644 --- a/api/dashboard/organisation/urls.py +++ b/api/dashboard/organisation/urls.py @@ -26,4 +26,5 @@ path('karma-log/create/', organisation_views.OrganizationKarmaLogGetPostPatchDeleteAPI.as_view()), path('base-template/', organisation_views.OrganisationBaseTemplateAPI.as_view()), path('import/', organisation_views.OrganisationImportAPI.as_view()), + path('transfer/', organisation_views.TransferAPI.as_view()), ] From 074cb93847c9bac0e2b0c94070a82001e555c5db Mon Sep 17 00:00:00 2001 From: SharonAliyas5573 Date: Sat, 6 Jul 2024 20:00:28 +0530 Subject: [PATCH 2/3] Refactor organisation transfer API --- .../organisation/organisation_views.py | 29 +++++++------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/api/dashboard/organisation/organisation_views.py b/api/dashboard/organisation/organisation_views.py index eb9d906b..1fdc33d0 100644 --- a/api/dashboard/organisation/organisation_views.py +++ b/api/dashboard/organisation/organisation_views.py @@ -703,26 +703,19 @@ def post(self, request): class TransferAPI(APIView): def post(self, request): - fromcode = request.data.get("fromid") - tocode = request.data.get("toid") - if not (from_org := Organization.objects.filter(code=fromcode).first()): + from_code = request.data.get("from_id") + to_code = request.data.get("to_id") + if not (from_org := Organization.objects.filter(code=from_code).first()): return CustomResponse( - response={"No organisations present"} + response={"From Organisations not present"} ).get_failure_response() - user_org_links = UserOrganizationLink.objects.filter(org=from_org).update( - org=Organization.objects.filter(code=tocode) - ) - if user_org_links.none: - # if user_org_links.exists(): - # users_effected = [] - # for user_org_link in user_org_links: - # main_user = user_org_link.user - # main_user.org = get_object_or_404(Organization, code=tocode) - # main_user.save() - # users_effected.append(main_user) - return CustomResponse(response={"No Users present"}).get_failure_response() - else: - + if not (to_org := Organization.objects.filter(code=to_code).first()): return CustomResponse( + response={"To Organisations not present"} + ).get_failure_response() + + UserOrganizationLink.objects.filter(org=from_org).update(org=to_org) + from_org.delete() + return CustomResponse( response={"Organisations transferred successfully"} ).get_success_response() From 48a7249c134bb6f898ad3a7fc8c1b8c14cc5798e Mon Sep 17 00:00:00 2001 From: jelanmathewjames Date: Sun, 7 Jul 2024 03:50:04 +0530 Subject: [PATCH 3/3] refactor: Update launchpad leaderboard to display latest organization, district, and state information for users --- api/launchpad/launchpad_views.py | 58 ++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/api/launchpad/launchpad_views.py b/api/launchpad/launchpad_views.py index 0de9a863..af988d3e 100644 --- a/api/launchpad/launchpad_views.py +++ b/api/launchpad/launchpad_views.py @@ -85,27 +85,34 @@ def get(self, request): task__hashtag='#lp24-introduction', ).values('user') + latest_org_link = UserOrganizationLink.objects.filter( + user=OuterRef('id'), + org__org_type__in=allowed_org_types + ).order_by('-created_at').values('org__title')[:1] + + latest_district = UserOrganizationLink.objects.filter( + user=OuterRef('id'), + org__org_type__in=allowed_org_types + ).order_by('-created_at').values('org__district__name')[:1] + + latest_state = UserOrganizationLink.objects.filter( + user=OuterRef('id'), + org__org_type__in=allowed_org_types + ).order_by('-created_at').values('org__district__zone__state__name')[:1] + users = User.objects.filter( karma_activity_log_user__task__event="launchpad", karma_activity_log_user__appraiser_approved=True, id__in=intro_task_completed_users ).prefetch_related( - Prefetch( - "user_organization_link_user", - queryset=UserOrganizationLink.objects.filter(org__org_type__in=allowed_org_types), - ), Prefetch( "user_role_link_user", queryset=UserRoleLink.objects.filter(verified=True, role__title__in=allowed_levels).select_related('role') ) - ).filter( - Q(user_organization_link_user__id__in=UserOrganizationLink.objects.filter( - org__org_type__in=allowed_org_types - ).values("id")) | Q(user_organization_link_user__id__isnull=True) ).annotate( - org=F("user_organization_link_user__org__title"), - district_name=F("user_organization_link_user__org__district__name"), - state=F("user_organization_link_user__org__district__zone__state__name"), + org=Subquery(latest_org_link), + district_name=Subquery(latest_district), + state=Subquery(latest_state), level=F("user_role_link_user__role__title"), time_=Max("karma_activity_log_user__created_at"), ).filter( @@ -147,28 +154,35 @@ def get(self, request): task__hashtag='#lp24-introduction', ).values('user') + latest_org_link = UserOrganizationLink.objects.filter( + user=OuterRef('id'), + org__org_type__in=allowed_org_types + ).order_by('-created_at').values('org__title')[:1] + + latest_district = UserOrganizationLink.objects.filter( + user=OuterRef('id'), + org__org_type__in=allowed_org_types + ).order_by('-created_at').values('org__district__name')[:1] + + latest_state = UserOrganizationLink.objects.filter( + user=OuterRef('id'), + org__org_type__in=allowed_org_types + ).order_by('-created_at').values('org__district__zone__state__name')[:1] + users = User.objects.filter( karma_activity_log_user__task__event="launchpad", karma_activity_log_user__appraiser_approved=True, id__in=intro_task_completed_users ).prefetch_related( - Prefetch( - "user_organization_link_user", - queryset=UserOrganizationLink.objects.filter(org__org_type__in=allowed_org_types), - ), Prefetch( "user_role_link_user", queryset=UserRoleLink.objects.filter(verified=True, role__title__in=allowed_levels).select_related('role') ) - ).filter( - Q(user_organization_link_user__id__in=UserOrganizationLink.objects.filter( - org__org_type__in=allowed_org_types - ).values("id")) | Q(user_organization_link_user__id__isnull=True) ).annotate( - org=F("user_organization_link_user__org__title"), - district_name=F("user_organization_link_user__org__district__name"), - state=F("user_organization_link_user__org__district__zone__state__name"), + org=Subquery(latest_org_link), + district_name=Subquery(latest_district), + state=Subquery(latest_state), level=F("user_role_link_user__role__title"), time_=Max("karma_activity_log_user__created_at"), ).distinct()