Merge branch 'dev' into sprint5

This commit is contained in:
Ankitajain-kiwi
2023-08-21 15:13:35 +05:30
committed by GitHub
15 changed files with 275 additions and 166 deletions

View File

@ -104,10 +104,12 @@ class ResetPasswordSerializer(serializers.Serializer):
return user_opt_details return user_opt_details
return '' return ''
class ChangePasswordSerializer(serializers.Serializer): class ChangePasswordSerializer(serializers.Serializer):
"""Update Password after verification""" """Update Password after verification"""
current_password = serializers.CharField(max_length=100) current_password = serializers.CharField(max_length=100, required=True)
new_password = serializers.CharField(required=True) new_password = serializers.CharField(required=True)
class Meta(object): class Meta(object):
"""Meta info""" """Meta info"""
model = User model = User
@ -118,25 +120,36 @@ class ChangePasswordSerializer(serializers.Serializer):
if self.context.password not in ('', None) and user.check_password(value): if self.context.password not in ('', None) and user.check_password(value):
return value return value
raise serializers.ValidationError(ERROR_CODE['2015']) raise serializers.ValidationError(ERROR_CODE['2015'])
def create(self, validated_data): def create(self, validated_data):
"""
"""
new_password = validated_data.pop('new_password') new_password = validated_data.pop('new_password')
current_password = validated_data.pop('current_password') current_password = validated_data.pop('current_password')
"""Check new password is different from current password""" # Check new password is different from current password
if new_password == current_password: if new_password == current_password:
raise serializers.ValidationError({"details": ERROR_CODE['2026']}) raise serializers.ValidationError({"details": ERROR_CODE['2026']})
user_details = User.objects.filter(email=self.context).last()
if user_details:
user_details.set_password(new_password)
user_details.save()
return {'password':new_password}
return ''
user_details = self.context
user_details.set_password(new_password)
user_details.save()
return {'password':new_password}
class ForgotPasswordSerializer(serializers.Serializer): class ForgotPasswordSerializer(serializers.Serializer):
"""Forget password serializer""" """Forget password serializer"""
email = serializers.EmailField() email = serializers.EmailField(required=True)
def validate_email(self, value):
"""
validate email exist ot not
value: string
return none
"""
if not User.objects.get(email=value):
raise serializers.ValidationError({'details': ERROR_CODE['2004']})
return value
class AdminLoginSerializer(serializers.ModelSerializer): class AdminLoginSerializer(serializers.ModelSerializer):
"""admin login serializer""" """admin login serializer"""

View File

@ -129,6 +129,28 @@ def send_otp_email(recipient_email, otp):
) )
return otp return otp
@shared_task()
def send_all_email(template_name, email, otp):
"""
Send all type of email by passing template name
template_name: string
email: string
otp: string
"""
from_email = settings.EMAIL_FROM_ADDRESS
recipient_list = [email]
send_templated_mail(
template_name=template_name,
from_email=from_email,
recipient_list=recipient_list,
context={
'verification_code': otp
}
)
return otp
@shared_task @shared_task
def user_device_details(user, device_id): def user_device_details(user, device_id):
""" """

View File

@ -39,7 +39,7 @@ from base.messages import ERROR_CODE, SUCCESS_CODE
from base.constants import NUMBER, ZOD, JUN, GRD, USER_TYPE_FLAG from base.constants import NUMBER, ZOD, JUN, GRD, USER_TYPE_FLAG
from guardian.tasks import generate_otp from guardian.tasks import generate_otp
from account.utils import (send_otp_email, send_support_email, custom_response, custom_error_response, from account.utils import (send_otp_email, send_support_email, custom_response, custom_error_response,
generate_code, OTP_EXPIRY, user_device_details) generate_code, OTP_EXPIRY, user_device_details, send_all_email)
from junior.serializers import JuniorProfileSerializer from junior.serializers import JuniorProfileSerializer
from guardian.serializers import GuardianProfileSerializer from guardian.serializers import GuardianProfileSerializer
@ -193,15 +193,30 @@ class UpdateProfileImage(views.APIView):
return custom_error_response(ERROR_CODE['2036'],response_status=status.HTTP_400_BAD_REQUEST) return custom_error_response(ERROR_CODE['2036'],response_status=status.HTTP_400_BAD_REQUEST)
class ChangePasswordAPIView(views.APIView): class ChangePasswordAPIView(views.APIView):
"""change password""" """
change password"
"""
serializer_class = ChangePasswordSerializer serializer_class = ChangePasswordSerializer
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]
def post(self, request): def post(self, request):
serializer = ChangePasswordSerializer(context=request.user, data=request.data) """
POST request to change current login user password
"""
serializer = ChangePasswordSerializer(
context=request.user,
data=request.data
)
if serializer.is_valid(): if serializer.is_valid():
serializer.save() serializer.save()
return custom_response(SUCCESS_CODE['3007'], response_status=status.HTTP_200_OK) return custom_response(
return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST) SUCCESS_CODE['3007'],
response_status=status.HTTP_200_OK
)
return custom_error_response(
serializer.errors,
response_status=status.HTTP_400_BAD_REQUEST
)
class ResetPasswordAPIView(views.APIView): class ResetPasswordAPIView(views.APIView):
"""Reset password""" """Reset password"""
@ -213,40 +228,40 @@ class ResetPasswordAPIView(views.APIView):
return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST) return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST)
class ForgotPasswordAPIView(views.APIView): class ForgotPasswordAPIView(views.APIView):
"""Forgot password""" """
Forgot password
"""
serializer_class = ForgotPasswordSerializer
def post(self, request): def post(self, request):
serializer = ForgotPasswordSerializer(data=request.data)
if serializer.is_valid(): """
email = serializer.validated_data['email'] Post method to validate serializer
try: """
User.objects.get(email=email) serializer = self.serializer_class(data=request.data)
except User.DoesNotExist: serializer.is_valid(raise_exception=True)
return custom_error_response(ERROR_CODE['2004'], response_status=status.HTTP_404_NOT_FOUND) email = serializer.validated_data['email']
verification_code = generate_otp() # generate otp
# Send the verification code to the user's email verification_code = generate_otp()
from_email = settings.EMAIL_FROM_ADDRESS # Send the verification code to the user's email
recipient_list = [email] send_all_email.delay(
send_templated_mail( 'email_reset_verification.email', email, verification_code
template_name='email_reset_verification.email', )
from_email=from_email, expiry = OTP_EXPIRY
recipient_list=recipient_list, user_data, created = UserEmailOtp.objects.get_or_create(
context={ email=email
'verification_code': verification_code )
} if created:
) user_data.expired_at = expiry
expiry = timezone.now() + timezone.timedelta(days=1) user_data.save()
user_data, created = UserEmailOtp.objects.get_or_create(email=email) if user_data:
if created: user_data.otp = verification_code
user_data.expired_at = expiry user_data.expired_at = expiry
user_data.save() user_data.save()
if user_data: return custom_response(
user_data.otp = verification_code SUCCESS_CODE['3015'],
user_data.expired_at = expiry response_status=status.HTTP_200_OK
user_data.save() )
return custom_response(SUCCESS_CODE['3015'],
response_status=status.HTTP_200_OK)
return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST)
class SendPhoneOtp(viewsets.ModelViewSet): class SendPhoneOtp(viewsets.ModelViewSet):
"""Send otp on phone""" """Send otp on phone"""

View File

@ -1,7 +1,12 @@
"""task files""" """task files"""
"""Django import"""
# Django import
import secrets import secrets
def generate_otp(): def generate_otp():
"""generate random otp""" """
generate random otp
"""
digits = "0123456789" digits = "0123456789"
return "".join(secrets.choice(digits) for _ in range(6)) return "".join(secrets.choice(digits) for _ in range(6))

View File

@ -43,18 +43,41 @@ def upload_image_to_alibaba(image, filename):
# Save the image object to a temporary file # Save the image object to a temporary file
with tempfile.NamedTemporaryFile(delete=False) as temp_file: with tempfile.NamedTemporaryFile(delete=False) as temp_file:
"""write image in temporary file""" """write image in temporary file"""
if type(image) == bytes: temp_file.write(image.read())
temp_file.write(image) return upload_file_to_alibaba(temp_file, filename)
else:
temp_file.write(image.read())
"""auth of bucket""" def upload_base64_image_to_alibaba(image, filename):
auth = oss2.Auth(settings.ALIYUN_OSS_ACCESS_KEY_ID, settings.ALIYUN_OSS_ACCESS_KEY_SECRET) """
"""fetch bucket details""" upload image on oss alibaba bucket
bucket = oss2.Bucket(auth, settings.ALIYUN_OSS_ENDPOINT, settings.ALIYUN_OSS_BUCKET_NAME) """
# Upload the temporary file to Alibaba OSS # Save the image object to a temporary file
bucket.put_object_from_file(filename, temp_file.name) with tempfile.NamedTemporaryFile(delete=False) as temp_file:
"""create perfect url for image""" # write image in temporary file
new_filename = filename.replace(' ', '%20') 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}" return f"https://{settings.ALIYUN_OSS_BUCKET_NAME}.{settings.ALIYUN_OSS_ENDPOINT}/{new_filename}"

View File

@ -63,7 +63,7 @@ class SignupViewset(viewsets.ModelViewSet):
if request.data['user_type'] in [str(NUMBER['one']), str(NUMBER['two'])]: if request.data['user_type'] in [str(NUMBER['one']), str(NUMBER['two'])]:
serializer = UserSerializer(context=request.data['user_type'], data=request.data) serializer = UserSerializer(context=request.data['user_type'], data=request.data)
if serializer.is_valid(): if serializer.is_valid():
user = serializer.save() serializer.save()
"""Generate otp""" """Generate otp"""
otp = generate_otp() otp = generate_otp()
# expire otp after 1 day # expire otp after 1 day
@ -83,6 +83,7 @@ class SignupViewset(viewsets.ModelViewSet):
else: else:
return custom_error_response(ERROR_CODE['2028'], response_status=status.HTTP_400_BAD_REQUEST) return custom_error_response(ERROR_CODE['2028'], response_status=status.HTTP_400_BAD_REQUEST)
class UpdateGuardianProfile(viewsets.ModelViewSet): class UpdateGuardianProfile(viewsets.ModelViewSet):
"""Update guardian profile""" """Update guardian profile"""
serializer_class = CreateGuardianSerializer serializer_class = CreateGuardianSerializer

View File

@ -56,10 +56,10 @@ class NotificationViewSet(viewsets.GenericViewSet):
to send test notification to send test notification
:return: :return:
""" """
send_notification_to_guardian(TEST_NOTIFICATION, None, request.auth.payload['user_id'], send_notification_to_guardian.delay(TEST_NOTIFICATION, None, request.auth.payload['user_id'],
{'task_id': None}) {'task_id': None})
send_notification_to_junior(TEST_NOTIFICATION, request.auth.payload['user_id'], None, send_notification_to_junior.delay(TEST_NOTIFICATION, None, request.auth.payload['user_id'],
{'task_id': None}) {'task_id': None})
return custom_response(SUCCESS_CODE["3000"]) return custom_response(SUCCESS_CODE["3000"])
@action(methods=['get'], detail=False, url_path='list', url_name='list', @action(methods=['get'], detail=False, url_path='list', url_name='list',

View File

@ -92,10 +92,7 @@ class UserCSVReportSerializer(serializers.ModelSerializer):
:param obj: user object :param obj: user object
:return: user phone number :return: user phone number
""" """
if profile := obj.guardian_profile.all().first(): if profile := (obj.guardian_profile.all().first() or obj.junior_profile.all().first()):
return f"+{profile.country_code}{profile.phone}" \
if profile.country_code and profile.phone else profile.phone
elif profile := obj.junior_profile.all().first():
return f"+{profile.country_code}{profile.phone}" \ return f"+{profile.country_code}{profile.phone}" \
if profile.country_code and profile.phone else profile.phone if profile.country_code and profile.phone else profile.phone
else: else:
@ -120,9 +117,7 @@ class UserCSVReportSerializer(serializers.ModelSerializer):
:param obj: user object :param obj: user object
:return: user type :return: user type
""" """
if profile := obj.guardian_profile.all().first(): if profile := (obj.guardian_profile.all().first() or obj.junior_profile.all().first()):
return "Active" if profile.is_active else "Inactive"
elif profile := obj.junior_profile.all().first():
return "Active" if profile.is_active else "Inactive" return "Active" if profile.is_active else "Inactive"
@staticmethod @staticmethod

View File

@ -5,7 +5,7 @@ web_admin user_management serializers file
from rest_framework import serializers from rest_framework import serializers
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from base.constants import USER_TYPE from base.constants import USER_TYPE, GUARDIAN, JUNIOR
# local imports # local imports
from base.messages import ERROR_CODE, SUCCESS_CODE from base.messages import ERROR_CODE, SUCCESS_CODE
from guardian.models import Guardian from guardian.models import Guardian
@ -210,10 +210,10 @@ class JuniorSerializer(serializers.ModelSerializer):
""" """
instance.auth.email = self.validated_data.get('email', instance.auth.email) instance.auth.email = self.validated_data.get('email', instance.auth.email)
instance.auth.username = self.validated_data.get('email', instance.auth.username) instance.auth.username = self.validated_data.get('email', instance.auth.username)
instance.auth.save() instance.auth.save(update_fields=['email', 'username'])
instance.country_code = validated_data.get('country_code', instance.country_code) instance.country_code = validated_data.get('country_code', instance.country_code)
instance.phone = validated_data.get('phone', instance.phone) instance.phone = validated_data.get('phone', instance.phone)
instance.save() instance.save(update_fields=['country_code', 'phone'])
return instance return instance
@staticmethod @staticmethod
@ -265,33 +265,30 @@ class UserManagementDetailSerializer(serializers.ModelSerializer):
model = USER model = USER
fields = ('id', 'user_type', 'email', 'guardian_profile', 'junior_profile', 'associated_users') fields = ('id', 'user_type', 'email', 'guardian_profile', 'junior_profile', 'associated_users')
@staticmethod def get_user_type(self, obj):
def get_user_type(obj):
""" """
:param obj: user object :param obj: user object
:return: user type :return: user type
""" """
if obj.guardian_profile.all().first(): return GUARDIAN if self.context['user_type'] == GUARDIAN else JUNIOR
return dict(USER_TYPE).get('2')
elif obj.junior_profile.all().first():
return dict(USER_TYPE).get('1')
else:
return None
@staticmethod def get_associated_users(self, obj):
def get_associated_users(obj):
""" """
:param obj: user object :param obj: user object
:return: associated user :return: associated user
""" """
if profile := obj.guardian_profile.all().first(): if self.context['user_type'] == GUARDIAN:
profile = obj.guardian_profile.all().only('user_id', 'guardian_code').first()
if profile.guardian_code: if profile.guardian_code:
junior = Junior.objects.filter(guardian_code__contains=[profile.guardian_code], is_verified=True) junior = Junior.objects.filter(guardian_code__contains=[profile.guardian_code],
is_verified=True).select_related('auth')
serializer = JuniorSerializer(junior, many=True) serializer = JuniorSerializer(junior, many=True)
return serializer.data return serializer.data
elif profile := obj.junior_profile.all().first(): elif self.context['user_type'] == JUNIOR:
profile = obj.junior_profile.all().only('auth_id', 'guardian_code').first()
if profile.guardian_code: if profile.guardian_code:
guardian = Guardian.objects.filter(guardian_code__in=profile.guardian_code, is_verified=True) guardian = Guardian.objects.filter(guardian_code__in=profile.guardian_code,
is_verified=True).select_related('user')
serializer = GuardianSerializer(guardian, many=True) serializer = GuardianSerializer(guardian, many=True)
return serializer.data return serializer.data
else: else:

View File

@ -2,9 +2,10 @@
web_utils file web_utils file
""" """
import base64 import base64
import datetime
from base.constants import ARTICLE_CARD_IMAGE_FOLDER from base.constants import ARTICLE_CARD_IMAGE_FOLDER, DATE_FORMAT
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): def pop_id(data):
@ -29,10 +30,10 @@ def get_image_url(data):
return data['image_url'] return data['image_url']
elif 'image_url' in data and type(data['image_url']) == str and data['image_url'].startswith('data:image'): elif 'image_url' in data and type(data['image_url']) == str and data['image_url'].startswith('data:image'):
base64_image = base64.b64decode(data.get('image_url').split(',')[1]) base64_image = base64.b64decode(data.get('image_url').split(',')[1])
image_name = f"{data['title']} {data.pop('image_name')}" if 'image_name' in data else data['title'] image_name = data.pop('image_name') if 'image_name' in data else f"{data['title']}.jpg"
filename = f"{ARTICLE_CARD_IMAGE_FOLDER}/{image_name}" filename = f"{ARTICLE_CARD_IMAGE_FOLDER}/{image_name}"
# upload image on ali baba # 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 return image_url
elif 'image' in data and data['image'] is not None: elif 'image' in data and data['image'] is not None:
image = data.pop('image') image = data.pop('image')
@ -40,3 +41,21 @@ def get_image_url(data):
# upload image on ali baba # upload image on ali baba
image_url = upload_image_to_alibaba(image, filename) image_url = upload_image_to_alibaba(image, filename)
return image_url return image_url
def get_dates(start_date, end_date):
"""
to get start and end date
:param start_date: format (yyyy-mm-dd)
:param end_date: format (yyyy-mm-dd)
:return: start and end date
"""
if start_date and end_date:
start_date = datetime.datetime.strptime(start_date, DATE_FORMAT).date()
end_date = datetime.datetime.strptime(end_date, DATE_FORMAT).date()
else:
end_date = datetime.date.today()
start_date = end_date - datetime.timedelta(days=6)
return start_date, end_date

View File

@ -25,11 +25,12 @@ from django.http import HttpResponse
from account.utils import custom_response from account.utils import custom_response
from base.constants import PENDING, IN_PROGRESS, REJECTED, REQUESTED, COMPLETED, EXPIRED, DATE_FORMAT, TASK_STATUS from base.constants import PENDING, IN_PROGRESS, REJECTED, REQUESTED, COMPLETED, EXPIRED, DATE_FORMAT, TASK_STATUS
from guardian.models import JuniorTask from guardian.models import JuniorTask
from guardian.utils import upload_excel_file_to_alibaba
from junior.models import JuniorPoints from junior.models import JuniorPoints
from web_admin.pagination import CustomPageNumberPagination from web_admin.pagination import CustomPageNumberPagination
from web_admin.permission import AdminPermission from web_admin.permission import AdminPermission
from web_admin.serializers.analytics_serializer import LeaderboardSerializer, UserCSVReportSerializer from web_admin.serializers.analytics_serializer import LeaderboardSerializer, UserCSVReportSerializer
from web_admin.serializers.user_management_serializer import UserManagementListSerializer from web_admin.utils import get_dates
USER = get_user_model() USER = get_user_model()
@ -52,7 +53,7 @@ class AnalyticsViewSet(GenericViewSet):
).prefetch_related('guardian_profile', ).prefetch_related('guardian_profile',
'junior_profile' 'junior_profile'
).exclude(junior_profile__isnull=True, ).exclude(junior_profile__isnull=True,
guardian_profile__isnull=True).order_by('date_joined') guardian_profile__isnull=True).order_by('-date_joined')
return user_qs return user_qs
@action(methods=['get'], url_name='users-count', url_path='users-count', detail=False) @action(methods=['get'], url_name='users-count', url_path='users-count', detail=False)
@ -63,13 +64,8 @@ class AnalyticsViewSet(GenericViewSet):
:param request: end_date: date format (yyyy-mm-dd) :param request: end_date: date format (yyyy-mm-dd)
:return: :return:
""" """
start_date, end_date = get_dates(request.query_params.get('start_date'),
end_date = datetime.date.today() request.query_params.get('end_date'))
start_date = end_date - datetime.timedelta(days=6)
if request.query_params.get('start_date') and request.query_params.get('end_date'):
start_date = datetime.datetime.strptime(request.query_params.get('start_date'), DATE_FORMAT)
end_date = datetime.datetime.strptime(request.query_params.get('end_date'), DATE_FORMAT)
user_qs = self.get_queryset() user_qs = self.get_queryset()
queryset = user_qs.filter(date_joined__range=(start_date, (end_date + datetime.timedelta(days=1)))) queryset = user_qs.filter(date_joined__range=(start_date, (end_date + datetime.timedelta(days=1))))
@ -88,12 +84,8 @@ class AnalyticsViewSet(GenericViewSet):
:param request: end_date: date format (yyyy-mm-dd) :param request: end_date: date format (yyyy-mm-dd)
:return: :return:
""" """
end_date = datetime.date.today() start_date, end_date = get_dates(request.query_params.get('start_date'),
start_date = end_date - datetime.timedelta(days=6) request.query_params.get('end_date'))
if request.query_params.get('start_date') and request.query_params.get('end_date'):
start_date = datetime.datetime.strptime(request.query_params.get('start_date'), DATE_FORMAT)
end_date = datetime.datetime.strptime(request.query_params.get('end_date'), DATE_FORMAT)
user_qs = self.get_queryset() user_qs = self.get_queryset()
signup_data = user_qs.filter(date_joined__range=[start_date, (end_date + datetime.timedelta(days=1))] signup_data = user_qs.filter(date_joined__range=[start_date, (end_date + datetime.timedelta(days=1))]
@ -110,12 +102,8 @@ class AnalyticsViewSet(GenericViewSet):
:param request: end_date: date format (yyyy-mm-dd) :param request: end_date: date format (yyyy-mm-dd)
:return: :return:
""" """
end_date = datetime.date.today() start_date, end_date = get_dates(request.query_params.get('start_date'),
start_date = end_date - datetime.timedelta(days=6) request.query_params.get('end_date'))
if request.query_params.get('start_date') and request.query_params.get('end_date'):
start_date = datetime.datetime.strptime(request.query_params.get('start_date'), DATE_FORMAT)
end_date = datetime.datetime.strptime(request.query_params.get('end_date'), DATE_FORMAT)
assign_tasks = JuniorTask.objects.filter( assign_tasks = JuniorTask.objects.filter(
created_at__range=[start_date, (end_date + datetime.timedelta(days=1))] created_at__range=[start_date, (end_date + datetime.timedelta(days=1))]
@ -159,20 +147,17 @@ class AnalyticsViewSet(GenericViewSet):
response = HttpResponse(content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') response = HttpResponse(content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
response['Content-Disposition'] = 'attachment; filename="ZOD_Bank_Analytics.xlsx"' response['Content-Disposition'] = 'attachment; filename="ZOD_Bank_Analytics.xlsx"'
end_date = datetime.date.today() start_date, end_date = get_dates(request.query_params.get('start_date'),
start_date = end_date - datetime.timedelta(days=6) request.query_params.get('end_date'))
if request.query_params.get('start_date') and request.query_params.get('end_date'): # Use BytesIO for binary data
start_date = datetime.datetime.strptime(request.query_params.get('start_date'), DATE_FORMAT) buffer = io.BytesIO()
end_date = datetime.datetime.strptime(request.query_params.get('end_date'), DATE_FORMAT)
buffer = io.BytesIO() # Use BytesIO for binary data
# Create an XlsxWriter Workbook object # Create an XlsxWriter Workbook object
workbook = xlsxwriter.Workbook(buffer) workbook = xlsxwriter.Workbook(buffer)
# Add sheets # Add sheets
sheets = ['Users', 'Assign Tasks', 'Juniors leaderboard'] sheets = ['Users', 'Assign Tasks', 'Juniors Leaderboard']
for sheet_name in sheets: for sheet_name in sheets:
worksheet = workbook.add_worksheet(name=sheet_name) worksheet = workbook.add_worksheet(name=sheet_name)
@ -190,11 +175,7 @@ class AnalyticsViewSet(GenericViewSet):
'Date Joined': user['date_joined']} 'Date Joined': user['date_joined']}
for user in serializer.data for user in serializer.data
]) ])
for idx, col in enumerate(df_users.columns): write_excel_worksheet(worksheet, df_users)
worksheet.write(0, idx, col) # Write header
for row_num, row in enumerate(df_users.values, start=1):
for col_num, value in enumerate(row):
worksheet.write(row_num, col_num, value)
# sheet 2 for Assign Task # sheet 2 for Assign Task
elif sheet_name == 'Assign Tasks': elif sheet_name == 'Assign Tasks':
@ -207,19 +188,14 @@ class AnalyticsViewSet(GenericViewSet):
for task in assign_tasks for task in assign_tasks
]) ])
for idx, col in enumerate(df_tasks.columns): write_excel_worksheet(worksheet, df_tasks)
worksheet.write(0, idx, col) # Write header
for row_num, row in enumerate(df_tasks.values, start=1):
for col_num, value in enumerate(row):
worksheet.write(row_num, col_num, value)
# sheet 3 for Juniors Leaderboard and rank # sheet 3 for Juniors Leaderboard and rank
elif sheet_name == 'Juniors leaderboard': elif sheet_name == 'Juniors Leaderboard':
queryset = JuniorPoints.objects.prefetch_related('junior', 'junior__auth').annotate(rank=Window( queryset = JuniorPoints.objects.prefetch_related('junior', 'junior__auth').annotate(rank=Window(
expression=Rank(), expression=Rank(),
order_by=[F('total_points').desc(), 'junior__created_at'] order_by=[F('total_points').desc(), 'junior__created_at']
)).order_by('-total_points', 'junior__created_at') )).order_by('-total_points', 'junior__created_at')[:15]
df_leaderboard = pd.DataFrame([ df_leaderboard = pd.DataFrame([
{ {
'Junior Name': f"{junior.junior.auth.first_name} {junior.junior.auth.last_name}" 'Junior Name': f"{junior.junior.auth.first_name} {junior.junior.auth.last_name}"
@ -230,11 +206,7 @@ class AnalyticsViewSet(GenericViewSet):
for junior in queryset for junior in queryset
]) ])
for idx, col in enumerate(df_leaderboard.columns): write_excel_worksheet(worksheet, df_leaderboard)
worksheet.write(0, idx, col) # Write header
for row_num, row in enumerate(df_leaderboard.values, start=1):
for col_num, value in enumerate(row):
worksheet.write(row_num, col_num, value)
# Close the workbook to save the content # Close the workbook to save the content
workbook.close() workbook.close()
@ -244,5 +216,22 @@ class AnalyticsViewSet(GenericViewSet):
response.write(buffer.getvalue()) response.write(buffer.getvalue())
buffer.close() buffer.close()
return response filename = f"{'analytics'}/{'ZOD_Bank_Analytics.xlsx'}"
file_link = upload_excel_file_to_alibaba(response, filename)
return custom_response(None, file_link)
def write_excel_worksheet(worksheet, dataframe):
"""
to perform write action on worksheets
:param worksheet:
:param dataframe:
:return: worksheet
"""
for idx, col in enumerate(dataframe.columns):
# Write header
worksheet.write(0, idx, col)
for row_num, row in enumerate(dataframe.values, start=1):
for col_num, value in enumerate(row):
worksheet.write(row_num, col_num, value)
return worksheet

View File

@ -44,9 +44,20 @@ class ArticleViewSet(GenericViewSet, mixins.CreateModelMixin, mixins.UpdateModel
def create(self, request, *args, **kwargs): def create(self, request, *args, **kwargs):
""" """
article create api method article create api method
:param request: :param request: { "title": "string", "description": "string",
:param args: "article_cards": [
:param kwargs: { "title": "string",
"description": "string",
"image_name": "string",
"image_url": "string"
} ],
"article_survey": [
{ "question": "string",
"options": [
{ "option": "string",
"is_answer": true }
] }
] }
:return: success message :return: success message
""" """
serializer = self.serializer_class(data=request.data) serializer = self.serializer_class(data=request.data)
@ -57,9 +68,24 @@ class ArticleViewSet(GenericViewSet, mixins.CreateModelMixin, mixins.UpdateModel
def update(self, request, *args, **kwargs): def update(self, request, *args, **kwargs):
""" """
article update api method article update api method
:param request: :param request: article_id,
:param args: { "title": "string", "description": "string",
:param kwargs: "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 :return: success message
""" """
article = self.get_object() article = self.get_object()
@ -72,8 +98,6 @@ class ArticleViewSet(GenericViewSet, mixins.CreateModelMixin, mixins.UpdateModel
""" """
article list api method article list api method
:param request: :param request:
:param args:
:param kwargs:
:return: list of article :return: list of article
""" """
queryset = self.get_queryset() queryset = self.get_queryset()
@ -86,9 +110,7 @@ class ArticleViewSet(GenericViewSet, mixins.CreateModelMixin, mixins.UpdateModel
def retrieve(self, request, *args, **kwargs): def retrieve(self, request, *args, **kwargs):
""" """
article detail api method article detail api method
:param request: :param request: article_id
:param args:
:param kwargs:
:return: article detail data :return: article detail data
""" """
queryset = self.get_object() queryset = self.get_object()
@ -98,9 +120,7 @@ class ArticleViewSet(GenericViewSet, mixins.CreateModelMixin, mixins.UpdateModel
def destroy(self, request, *args, **kwargs): def destroy(self, request, *args, **kwargs):
""" """
article delete (soft delete) api method article delete (soft delete) api method
:param request: :param request: article_id
:param args:
:param kwargs:
:return: success message :return: success message
""" """
article = self.get_object() article = self.get_object()
@ -177,7 +197,10 @@ class DefaultArticleCardImagesViewSet(GenericViewSet, mixins.CreateModelMixin, m
def create(self, request, *args, **kwargs): def create(self, request, *args, **kwargs):
""" """
api method to upload default article card images api method to upload default article card images
:param request: :param request: {
"image_name": "string",
"image": "image_file"
}
:return: success message :return: success message
""" """
serializer = self.serializer_class(data=request.data) serializer = self.serializer_class(data=request.data)

View File

@ -27,6 +27,7 @@ class ForgotAndResetPasswordViewSet(GenericViewSet):
def admin_otp(self, request): def admin_otp(self, request):
""" """
api method to send otp api method to send otp
:param request: {"email": "string"}
:return: success message :return: success message
""" """
serializer = self.serializer_class(data=request.data) serializer = self.serializer_class(data=request.data)
@ -40,6 +41,7 @@ class ForgotAndResetPasswordViewSet(GenericViewSet):
def admin_verify_otp(self, request): def admin_verify_otp(self, request):
""" """
api method to verify otp api method to verify otp
:param request: {"email": "string", "otp": "otp"}
:return: success message :return: success message
""" """
serializer = self.serializer_class(data=request.data) serializer = self.serializer_class(data=request.data)
@ -52,6 +54,7 @@ class ForgotAndResetPasswordViewSet(GenericViewSet):
def admin_create_password(self, request): def admin_create_password(self, request):
""" """
api method to create new password api method to create new password
:param request: {"email": "string", "new_password": "string", "confirm_password": "string"}
:return: success message :return: success message
""" """
serializer = self.serializer_class(data=request.data) serializer = self.serializer_class(data=request.data)

View File

@ -14,6 +14,8 @@ from django.db.models import Q
from account.utils import custom_response, custom_error_response from account.utils import custom_response, custom_error_response
from base.constants import USER_TYPE from base.constants import USER_TYPE
from base.messages import SUCCESS_CODE, ERROR_CODE from base.messages import SUCCESS_CODE, ERROR_CODE
from guardian.models import Guardian
from junior.models import Junior
from web_admin.permission import AdminPermission from web_admin.permission import AdminPermission
from web_admin.serializers.user_management_serializer import (UserManagementListSerializer, from web_admin.serializers.user_management_serializer import (UserManagementListSerializer,
UserManagementDetailSerializer, GuardianSerializer, UserManagementDetailSerializer, GuardianSerializer,
@ -70,12 +72,14 @@ class UserManagementViewSet(GenericViewSet, mixins.ListModelMixin,
""" """
if self.request.query_params.get('user_type') not in [dict(USER_TYPE).get('1'), dict(USER_TYPE).get('2')]: if self.request.query_params.get('user_type') not in [dict(USER_TYPE).get('1'), dict(USER_TYPE).get('2')]:
return custom_error_response(ERROR_CODE['2067'], status.HTTP_400_BAD_REQUEST) return custom_error_response(ERROR_CODE['2067'], status.HTTP_400_BAD_REQUEST)
queryset = self.queryset queryset = self.queryset
if self.request.query_params.get('user_type') == dict(USER_TYPE).get('2'): queryset = queryset.filter(id=kwargs['pk'])
queryset = queryset.filter(id=kwargs['pk'])
elif self.request.query_params.get('user_type') == dict(USER_TYPE).get('1'): serializer = UserManagementDetailSerializer(
queryset = queryset.filter(id=kwargs['pk']) queryset, many=True,
serializer = UserManagementDetailSerializer(queryset, many=True) context={'user_type': self.request.query_params.get('user_type')}
)
return custom_response(None, data=serializer.data) return custom_response(None, data=serializer.data)
def partial_update(self, request, *args, **kwargs): def partial_update(self, request, *args, **kwargs):
@ -87,15 +91,14 @@ class UserManagementViewSet(GenericViewSet, mixins.ListModelMixin,
""" """
if self.request.query_params.get('user_type') not in [dict(USER_TYPE).get('1'), dict(USER_TYPE).get('2')]: if self.request.query_params.get('user_type') not in [dict(USER_TYPE).get('1'), dict(USER_TYPE).get('2')]:
return custom_error_response(ERROR_CODE['2067'], status.HTTP_400_BAD_REQUEST) return custom_error_response(ERROR_CODE['2067'], status.HTTP_400_BAD_REQUEST)
queryset = self.queryset
if self.request.query_params.get('user_type') == dict(USER_TYPE).get('2'): if self.request.query_params.get('user_type') == dict(USER_TYPE).get('2'):
user_obj = queryset.filter(id=kwargs['pk']).first() guardian = Guardian.objects.filter(user_id=kwargs['pk'], is_verified=True).first()
serializer = GuardianSerializer(user_obj.guardian_profile.all().first(), serializer = GuardianSerializer(guardian,
request.data, context={'user_id': kwargs['pk']}) request.data, context={'user_id': kwargs['pk']})
elif self.request.query_params.get('user_type') == dict(USER_TYPE).get('1'): elif self.request.query_params.get('user_type') == dict(USER_TYPE).get('1'):
user_obj = queryset.filter(id=kwargs['pk']).first() junior = Junior.objects.filter(auth_id=kwargs['pk'], is_verified=True).select_related('auth').first()
serializer = JuniorSerializer(user_obj.junior_profile.all().first(), serializer = JuniorSerializer(junior,
request.data, context={'user_id': kwargs['pk']}) request.data, context={'user_id': kwargs['pk']})
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)

View File

@ -125,6 +125,7 @@ SIMPLE_JWT = {
# Database # Database
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases # https://docs.djangoproject.com/en/3.0/ref/settings/#databases
DATABASES = { DATABASES = {
# default db setting
'default': { 'default': {
'ENGINE': 'django.contrib.gis.db.backends.postgis', 'ENGINE': 'django.contrib.gis.db.backends.postgis',
'NAME':os.getenv('DB_NAME'), 'NAME':os.getenv('DB_NAME'),