From b4026a4f118066fb36ab451687734dded8a750d1 Mon Sep 17 00:00:00 2001 From: jain Date: Fri, 18 Aug 2023 18:12:14 +0530 Subject: [PATCH 1/4] middleware --- account/custom_middleware.py | 5 +++-- account/utils.py | 4 +++- account/views.py | 6 +++++- guardian/views.py | 9 +++++++-- junior/views.py | 2 +- 5 files changed, 19 insertions(+), 7 deletions(-) diff --git a/account/custom_middleware.py b/account/custom_middleware.py index ec2e315..c2125cd 100644 --- a/account/custom_middleware.py +++ b/account/custom_middleware.py @@ -39,8 +39,9 @@ class CustomMiddleware(object): # Code to be executed after the view is called device_id = request.META.get('HTTP_DEVICE_ID') user_type = request.META.get('HTTP_USER_TYPE') + api_endpoint = request.path if request.user.is_authenticated: - """device details""" + # device details device_details = UserDeviceDetails.objects.filter(user=request.user, device_id=device_id).last() if user_type and str(user_type) == str(NUMBER['one']): junior = Junior.objects.filter(auth=request.user, is_active=False).last() @@ -52,7 +53,7 @@ class CustomMiddleware(object): if guardian: custom_error = custom_error_response(ERROR_CODE['2075'], response_status=status.HTTP_404_NOT_FOUND) response = custom_response(custom_error) - if device_id and not device_details: + if device_id and not device_details and api_endpoint != '/api/v1/user/login/': custom_error = custom_error_response(ERROR_CODE['2037'], response_status=status.HTTP_404_NOT_FOUND) response = custom_response(custom_error) return response diff --git a/account/utils.py b/account/utils.py index e016940..ad910ba 100644 --- a/account/utils.py +++ b/account/utils.py @@ -137,10 +137,12 @@ def user_device_details(user, device_id): device_id: string return """ - device_details, created = UserDeviceDetails.objects.get_or_create(user=user) + device_details, created = UserDeviceDetails.objects.get_or_create(user__id=user) if device_details: device_details.device_id = device_id device_details.save() + return True + return False def send_support_email(name, sender, subject, message): diff --git a/account/views.py b/account/views.py index c6fbb12..bf3a7d5 100644 --- a/account/views.py +++ b/account/views.py @@ -322,7 +322,11 @@ class UserLogin(viewsets.ViewSet): response_status=status.HTTP_401_UNAUTHORIZED ) # storing device id in using celery task so the time would be reduced - user_device_details.delay(user, device_id) + # user_device_details.delay(user.id, device_id) + device_details, created = UserDeviceDetails.objects.get_or_create(user=user) + if device_details: + device_details.device_id = device_id + device_details.save() return custom_response(SUCCESS_CODE['3003'], serializer, response_status=status.HTTP_200_OK) else: return custom_error_response(ERROR_CODE["2002"], response_status=status.HTTP_401_UNAUTHORIZED) diff --git a/guardian/views.py b/guardian/views.py index d06f5b9..ad6a134 100644 --- a/guardian/views.py +++ b/guardian/views.py @@ -260,7 +260,7 @@ class ApproveJuniorAPIView(viewsets.ViewSet): guardian = Guardian.objects.filter(user__email=self.request.user).last() # fetch junior query junior_queryset = Junior.objects.filter(id=self.request.data.get('junior_id')).last() - if junior_queryset and junior_queryset.is_deleted: + if junior_queryset and (junior_queryset.is_deleted or not junior_queryset.is_active): return custom_error_response(ERROR_CODE['2073'], response_status=status.HTTP_400_BAD_REQUEST) # action 1 is use for approve and 2 for reject if request.data['action'] == '1': @@ -295,7 +295,12 @@ class ApproveTaskAPIView(viewsets.ViewSet): task_queryset = JuniorTask.objects.filter(id=self.request.data.get('task_id'), guardian=guardian, junior=self.request.data.get('junior_id')).last() - if task_queryset and task_queryset.junior.is_deleted: + print("task_queryset.junior.is_deleted===>",task_queryset.junior.is_deleted) + print("task_queryset.junior.is_active===>",task_queryset.junior.is_active) + print("task_queryset.junior.is_deleted===>", type(task_queryset.junior.is_deleted)) + print("task_queryset.junior.is_active===>", type(task_queryset.junior.is_active)) + print("99999===>",(task_queryset.junior.is_deleted or not task_queryset.junior.is_active)) + if task_queryset and (task_queryset.junior.is_deleted or not task_queryset.junior.is_active): return custom_error_response(ERROR_CODE['2072'], response_status=status.HTTP_400_BAD_REQUEST) # use ApproveJuniorSerializer serializer serializer = ApproveTaskSerializer(context={"guardian_code": guardian.guardian_code, diff --git a/junior/views.py b/junior/views.py index 7a83b0a..1fdf2be 100644 --- a/junior/views.py +++ b/junior/views.py @@ -339,7 +339,7 @@ class CompleteJuniorTaskAPIView(views.APIView): task_queryset = JuniorTask.objects.filter(id=task_id, junior__auth__email=self.request.user ).select_related('guardian', 'junior').last() if task_queryset: - if task_queryset.junior.is_deleted: + if task_queryset.junior.is_deleted or not task_queryset.junior.is_active: return custom_error_response(ERROR_CODE['2074'], response_status=status.HTTP_400_BAD_REQUEST) # use CompleteTaskSerializer serializer if task_queryset.task_status in [str(NUMBER['four']), str(NUMBER['five'])]: From cdf1a7b74ea51beb70bd7647e3402fcca01aa267 Mon Sep 17 00:00:00 2001 From: jain Date: Fri, 18 Aug 2023 18:29:46 +0530 Subject: [PATCH 2/4] add comma --- account/views.py | 4 ++-- guardian/serializers.py | 2 +- guardian/views.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/account/views.py b/account/views.py index bf3a7d5..f5cb15f 100644 --- a/account/views.py +++ b/account/views.py @@ -235,7 +235,7 @@ class ForgotPasswordAPIView(views.APIView): 'verification_code': verification_code } ) - expiry = OTP_EXPIRY + expiry = timezone.now() + timezone.timedelta(days=1) user_data, created = UserEmailOtp.objects.get_or_create(email=email) if created: user_data.expired_at = expiry @@ -454,7 +454,7 @@ class ReSendEmailOtp(viewsets.ModelViewSet): def create(self, request, *args, **kwargs): otp = generate_otp() if User.objects.filter(email=request.data['email']): - expiry = OTP_EXPIRY + expiry = timezone.now() + timezone.timedelta(days=1) email_data, created = UserEmailOtp.objects.get_or_create(email=request.data['email']) if created: email_data.expired_at = expiry diff --git a/guardian/serializers.py b/guardian/serializers.py index f36bd46..8db860b 100644 --- a/guardian/serializers.py +++ b/guardian/serializers.py @@ -251,7 +251,7 @@ class GuardianDetailSerializer(serializers.ModelSerializer): """Meta info""" model = Guardian fields = ['id', 'email', 'first_name', 'last_name', 'country_code', 'phone', 'gender', 'dob', - 'guardian_code','is_active', 'is_complete_profile', 'created_at', 'image', 'is_deleted' + 'guardian_code','is_active', 'is_complete_profile', 'created_at', 'image', 'is_deleted', 'updated_at'] class TaskDetailsSerializer(serializers.ModelSerializer): """Task detail serializer""" diff --git a/guardian/views.py b/guardian/views.py index ad6a134..e7a4b87 100644 --- a/guardian/views.py +++ b/guardian/views.py @@ -66,7 +66,7 @@ class SignupViewset(viewsets.ModelViewSet): """Generate otp""" otp = generate_otp() # expire otp after 1 day - expiry = OTP_EXPIRY + expiry = timezone.now() + timezone.timedelta(days=1) # create user email otp object UserEmailOtp.objects.create(email=request.data['email'], otp=otp, user_type=str(request.data['user_type']), expired_at=expiry) From 3921f76f22642911d2ec7fa86c9442a5daef7179 Mon Sep 17 00:00:00 2001 From: jain Date: Fri, 18 Aug 2023 18:31:27 +0530 Subject: [PATCH 3/4] remove print statement --- guardian/views.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/guardian/views.py b/guardian/views.py index e7a4b87..9b9a0aa 100644 --- a/guardian/views.py +++ b/guardian/views.py @@ -295,11 +295,6 @@ class ApproveTaskAPIView(viewsets.ViewSet): task_queryset = JuniorTask.objects.filter(id=self.request.data.get('task_id'), guardian=guardian, junior=self.request.data.get('junior_id')).last() - print("task_queryset.junior.is_deleted===>",task_queryset.junior.is_deleted) - print("task_queryset.junior.is_active===>",task_queryset.junior.is_active) - print("task_queryset.junior.is_deleted===>", type(task_queryset.junior.is_deleted)) - print("task_queryset.junior.is_active===>", type(task_queryset.junior.is_active)) - print("99999===>",(task_queryset.junior.is_deleted or not task_queryset.junior.is_active)) if task_queryset and (task_queryset.junior.is_deleted or not task_queryset.junior.is_active): return custom_error_response(ERROR_CODE['2072'], response_status=status.HTTP_400_BAD_REQUEST) # use ApproveJuniorSerializer serializer From 21e006ae2aff1bde295fc2beb5a12e667da3aa20 Mon Sep 17 00:00:00 2001 From: abutalib-kiwi Date: Fri, 18 Aug 2023 18:34:48 +0530 Subject: [PATCH 4/4] added description for api, changes in upload image and file to alibaba method --- guardian/utils.py | 47 ++++++++++++++++++++++++-------- notifications/views.py | 8 +++--- web_admin/utils.py | 4 +-- web_admin/views/analytics.py | 17 ++---------- web_admin/views/article.py | 53 ++++++++++++++++++++++++++---------- web_admin/views/auth.py | 3 ++ 6 files changed, 85 insertions(+), 47 deletions(-) diff --git a/guardian/utils.py b/guardian/utils.py index d5081ac..14bd36a 100644 --- a/guardian/utils.py +++ b/guardian/utils.py @@ -43,18 +43,41 @@ def upload_image_to_alibaba(image, filename): # Save the image object to a temporary file with tempfile.NamedTemporaryFile(delete=False) as temp_file: """write image in temporary file""" - if type(image) == bytes: - temp_file.write(image) - else: - temp_file.write(image.read()) - """auth of bucket""" - auth = oss2.Auth(settings.ALIYUN_OSS_ACCESS_KEY_ID, settings.ALIYUN_OSS_ACCESS_KEY_SECRET) - """fetch bucket details""" - bucket = oss2.Bucket(auth, settings.ALIYUN_OSS_ENDPOINT, settings.ALIYUN_OSS_BUCKET_NAME) - # Upload the temporary file to Alibaba OSS - bucket.put_object_from_file(filename, temp_file.name) - """create perfect url for image""" - new_filename = filename.replace(' ', '%20') + temp_file.write(image.read()) + return upload_file_to_alibaba(temp_file, filename) + + +def upload_base64_image_to_alibaba(image, filename): + """ + upload image on oss alibaba bucket + """ + # Save the image object to a temporary file + with tempfile.NamedTemporaryFile(delete=False) as temp_file: + # write image in temporary file + temp_file.write(image) + return upload_file_to_alibaba(temp_file, filename) + + +def upload_excel_file_to_alibaba(response, filename): + """ + upload excel file on oss alibaba bucket + """ + # Save the image object to a temporary file + with tempfile.NamedTemporaryFile(delete=False) as temp_file: + # write image in temporary file + temp_file.write(response.content) + return upload_file_to_alibaba(temp_file, filename) + + +def upload_file_to_alibaba(temp_file, filename): + """auth of bucket""" + auth = oss2.Auth(settings.ALIYUN_OSS_ACCESS_KEY_ID, settings.ALIYUN_OSS_ACCESS_KEY_SECRET) + """fetch bucket details""" + bucket = oss2.Bucket(auth, settings.ALIYUN_OSS_ENDPOINT, settings.ALIYUN_OSS_BUCKET_NAME) + # Upload the temporary file to Alibaba OSS + bucket.put_object_from_file(filename, temp_file.name) + """create perfect url for image""" + new_filename = filename.replace(' ', '%20') return f"https://{settings.ALIYUN_OSS_BUCKET_NAME}.{settings.ALIYUN_OSS_ENDPOINT}/{new_filename}" diff --git a/notifications/views.py b/notifications/views.py index dc6e891..5adb536 100644 --- a/notifications/views.py +++ b/notifications/views.py @@ -56,10 +56,10 @@ class NotificationViewSet(viewsets.GenericViewSet): to send test notification :return: """ - send_notification_to_guardian(TEST_NOTIFICATION, None, request.auth.payload['user_id'], - {'task_id': None}) - send_notification_to_junior(TEST_NOTIFICATION, request.auth.payload['user_id'], None, - {'task_id': None}) + send_notification_to_guardian.delay(TEST_NOTIFICATION, None, request.auth.payload['user_id'], + {'task_id': None}) + send_notification_to_junior.delay(TEST_NOTIFICATION, None, request.auth.payload['user_id'], + {'task_id': None}) return custom_response(SUCCESS_CODE["3000"]) @action(methods=['get'], detail=False, url_path='list', url_name='list', diff --git a/web_admin/utils.py b/web_admin/utils.py index a47bbff..4170cf9 100644 --- a/web_admin/utils.py +++ b/web_admin/utils.py @@ -4,7 +4,7 @@ web_utils file import base64 from base.constants import ARTICLE_CARD_IMAGE_FOLDER -from guardian.utils import upload_image_to_alibaba +from guardian.utils import upload_image_to_alibaba, upload_base64_image_to_alibaba def pop_id(data): @@ -32,7 +32,7 @@ def get_image_url(data): image_name = data.pop('image_name') if 'image_name' in data else f"{data['title']}.jpg" filename = f"{ARTICLE_CARD_IMAGE_FOLDER}/{image_name}" # upload image on ali baba - image_url = upload_image_to_alibaba(base64_image, filename) + image_url = upload_base64_image_to_alibaba(base64_image, filename) return image_url elif 'image' in data and data['image'] is not None: image = data.pop('image') diff --git a/web_admin/views/analytics.py b/web_admin/views/analytics.py index 2ff3773..ddc4e0d 100644 --- a/web_admin/views/analytics.py +++ b/web_admin/views/analytics.py @@ -28,6 +28,7 @@ from django.http import HttpResponse from account.utils import custom_response from base.constants import PENDING, IN_PROGRESS, REJECTED, REQUESTED, COMPLETED, EXPIRED, DATE_FORMAT, TASK_STATUS from guardian.models import JuniorTask +from guardian.utils import upload_excel_file_to_alibaba from junior.models import JuniorPoints from web_admin.pagination import CustomPageNumberPagination from web_admin.permission import AdminPermission @@ -251,18 +252,6 @@ class AnalyticsViewSet(GenericViewSet): buffer.close() filename = f"{'analytics'}/{'ZOD_Bank_Analytics.xlsx'}" - with tempfile.NamedTemporaryFile(delete=False) as temp_file: - """write image in temporary file""" - temp_file.write(response.content) - """auth of bucket""" - auth = oss2.Auth(settings.ALIYUN_OSS_ACCESS_KEY_ID, settings.ALIYUN_OSS_ACCESS_KEY_SECRET) - """fetch bucket details""" - bucket = oss2.Bucket(auth, settings.ALIYUN_OSS_ENDPOINT, settings.ALIYUN_OSS_BUCKET_NAME) - # Upload the temporary file to Alibaba OSS - bucket.put_object_from_file(filename, temp_file.name) - """create perfect url for image""" - new_filename = filename.replace(' ', '%20') - link = f"https://{settings.ALIYUN_OSS_BUCKET_NAME}.{settings.ALIYUN_OSS_ENDPOINT}/{new_filename}" - print(link) - return custom_response(None, link) + file_link = upload_excel_file_to_alibaba(response, filename) + return custom_response(None, file_link) diff --git a/web_admin/views/article.py b/web_admin/views/article.py index 13c41c2..49f76fa 100644 --- a/web_admin/views/article.py +++ b/web_admin/views/article.py @@ -44,9 +44,20 @@ class ArticleViewSet(GenericViewSet, mixins.CreateModelMixin, mixins.UpdateModel def create(self, request, *args, **kwargs): """ article create api method - :param request: - :param args: - :param kwargs: + :param request: { "title": "string", "description": "string", + "article_cards": [ + { "title": "string", + "description": "string", + "image_name": "string", + "image_url": "string" + } ], + "article_survey": [ + { "question": "string", + "options": [ + { "option": "string", + "is_answer": true } + ] } + ] } :return: success message """ serializer = self.serializer_class(data=request.data) @@ -57,9 +68,24 @@ class ArticleViewSet(GenericViewSet, mixins.CreateModelMixin, mixins.UpdateModel def update(self, request, *args, **kwargs): """ article update api method - :param request: - :param args: - :param kwargs: + :param request: article_id, + { "title": "string", "description": "string", + "article_cards": [ + { "id": 0, + "title": "string", + "description": "string", + "image_name": "string", + "image_url": "string" + } ], + "article_survey": [ + { "id": 0, + "question": "string", + "options": [ + { "id": 0, + "option": "string", + "is_answer": true + } ] + } ] } :return: success message """ article = self.get_object() @@ -72,8 +98,6 @@ class ArticleViewSet(GenericViewSet, mixins.CreateModelMixin, mixins.UpdateModel """ article list api method :param request: - :param args: - :param kwargs: :return: list of article """ queryset = self.get_queryset() @@ -86,9 +110,7 @@ class ArticleViewSet(GenericViewSet, mixins.CreateModelMixin, mixins.UpdateModel def retrieve(self, request, *args, **kwargs): """ article detail api method - :param request: - :param args: - :param kwargs: + :param request: article_id :return: article detail data """ queryset = self.get_object() @@ -98,9 +120,7 @@ class ArticleViewSet(GenericViewSet, mixins.CreateModelMixin, mixins.UpdateModel def destroy(self, request, *args, **kwargs): """ article delete (soft delete) api method - :param request: - :param args: - :param kwargs: + :param request: article_id :return: success message """ article = self.get_object() @@ -177,7 +197,10 @@ class DefaultArticleCardImagesViewSet(GenericViewSet, mixins.CreateModelMixin, m def create(self, request, *args, **kwargs): """ api method to upload default article card images - :param request: + :param request: { + "image_name": "string", + "image": "image_file" + } :return: success message """ serializer = self.serializer_class(data=request.data) diff --git a/web_admin/views/auth.py b/web_admin/views/auth.py index fae973e..73f19e5 100644 --- a/web_admin/views/auth.py +++ b/web_admin/views/auth.py @@ -27,6 +27,7 @@ class ForgotAndResetPasswordViewSet(GenericViewSet): def admin_otp(self, request): """ api method to send otp + :param request: {"email": "string"} :return: success message """ serializer = self.serializer_class(data=request.data) @@ -40,6 +41,7 @@ class ForgotAndResetPasswordViewSet(GenericViewSet): def admin_verify_otp(self, request): """ api method to verify otp + :param request: {"email": "string", "otp": "otp"} :return: success message """ serializer = self.serializer_class(data=request.data) @@ -52,6 +54,7 @@ class ForgotAndResetPasswordViewSet(GenericViewSet): def admin_create_password(self, request): """ api method to create new password + :param request: {"email": "string", "new_password": "string", "confirm_password": "string"} :return: success message """ serializer = self.serializer_class(data=request.data)