mirror of
https://github.com/HamzaSha1/zod-backend.git
synced 2025-11-27 17:14:55 +00:00
Merge branch 'dev' into sprint5
This commit is contained in:
@ -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 = self.context
|
||||||
user_details.set_password(new_password)
|
user_details.set_password(new_password)
|
||||||
user_details.save()
|
user_details.save()
|
||||||
return {'password':new_password}
|
return {'password':new_password}
|
||||||
return ''
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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"""
|
||||||
|
|||||||
@ -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):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -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,30 +228,29 @@ 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():
|
"""
|
||||||
|
Post method to validate serializer
|
||||||
|
"""
|
||||||
|
serializer = self.serializer_class(data=request.data)
|
||||||
|
serializer.is_valid(raise_exception=True)
|
||||||
email = serializer.validated_data['email']
|
email = serializer.validated_data['email']
|
||||||
try:
|
# generate otp
|
||||||
User.objects.get(email=email)
|
|
||||||
except User.DoesNotExist:
|
|
||||||
return custom_error_response(ERROR_CODE['2004'], response_status=status.HTTP_404_NOT_FOUND)
|
|
||||||
verification_code = generate_otp()
|
verification_code = generate_otp()
|
||||||
# Send the verification code to the user's email
|
# Send the verification code to the user's email
|
||||||
from_email = settings.EMAIL_FROM_ADDRESS
|
send_all_email.delay(
|
||||||
recipient_list = [email]
|
'email_reset_verification.email', email, verification_code
|
||||||
send_templated_mail(
|
)
|
||||||
template_name='email_reset_verification.email',
|
expiry = OTP_EXPIRY
|
||||||
from_email=from_email,
|
user_data, created = UserEmailOtp.objects.get_or_create(
|
||||||
recipient_list=recipient_list,
|
email=email
|
||||||
context={
|
|
||||||
'verification_code': verification_code
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
expiry = timezone.now() + timezone.timedelta(days=1)
|
|
||||||
user_data, created = UserEmailOtp.objects.get_or_create(email=email)
|
|
||||||
if created:
|
if created:
|
||||||
user_data.expired_at = expiry
|
user_data.expired_at = expiry
|
||||||
user_data.save()
|
user_data.save()
|
||||||
@ -244,9 +258,10 @@ class ForgotPasswordAPIView(views.APIView):
|
|||||||
user_data.otp = verification_code
|
user_data.otp = verification_code
|
||||||
user_data.expired_at = expiry
|
user_data.expired_at = expiry
|
||||||
user_data.save()
|
user_data.save()
|
||||||
return custom_response(SUCCESS_CODE['3015'],
|
return custom_response(
|
||||||
response_status=status.HTTP_200_OK)
|
SUCCESS_CODE['3015'],
|
||||||
return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST)
|
response_status=status.HTTP_200_OK
|
||||||
|
)
|
||||||
|
|
||||||
class SendPhoneOtp(viewsets.ModelViewSet):
|
class SendPhoneOtp(viewsets.ModelViewSet):
|
||||||
"""Send otp on phone"""
|
"""Send otp on phone"""
|
||||||
|
|||||||
@ -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))
|
||||||
|
|||||||
@ -43,10 +43,33 @@ 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)
|
|
||||||
else:
|
|
||||||
temp_file.write(image.read())
|
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 of bucket"""
|
||||||
auth = oss2.Auth(settings.ALIYUN_OSS_ACCESS_KEY_ID, settings.ALIYUN_OSS_ACCESS_KEY_SECRET)
|
auth = oss2.Auth(settings.ALIYUN_OSS_ACCESS_KEY_ID, settings.ALIYUN_OSS_ACCESS_KEY_SECRET)
|
||||||
"""fetch bucket details"""
|
"""fetch bucket details"""
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -56,9 +56,9 @@ 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"])
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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:
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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'):
|
|
||||||
queryset = queryset.filter(id=kwargs['pk'])
|
serializer = UserManagementDetailSerializer(
|
||||||
serializer = UserManagementDetailSerializer(queryset, many=True)
|
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)
|
||||||
|
|||||||
@ -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'),
|
||||||
|
|||||||
Reference in New Issue
Block a user