Merge pull request #19 from KiwiTechLLC/qa

Qa
This commit is contained in:
Ankitajain-kiwi
2023-06-29 21:25:52 +05:30
committed by GitHub
22 changed files with 303 additions and 57 deletions

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2.2 on 2023-06-29 12:10
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('account', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='useremailotp',
name='user_type',
field=models.CharField(blank=True, choices=[('1', 'junior'), ('2', 'guardian'), ('3', 'superuser')], default=None, max_length=15, null=True),
),
]

View File

@ -59,6 +59,7 @@ class UserEmailOtp(models.Model):
"""otp details"""
otp = models.CharField(max_length=10)
is_verified = models.BooleanField(default=False)
user_type = models.CharField(max_length=15, choices=USER_TYPE, null=True, blank=True, default=None)
# OTP validity
created_at = models.DateTimeField(auto_now_add=True)

View File

@ -12,6 +12,7 @@ from rest_framework import viewsets, status
from rest_framework.decorators import action
from django.contrib.auth import authenticate, login
from rest_framework_simplejwt.tokens import RefreshToken
from guardian.utils import upload_image_to_alibaba
class GoogleSignInSerializer(serializers.Serializer):
"""Google login Serializer"""
@ -20,7 +21,6 @@ class GoogleSignInSerializer(serializers.Serializer):
def create(self, validated_data):
"""Create or update user model"""
with transaction.atomic():
print("validated_data====>",validated_data)
if User.objects.filter(email__iexact=self.validated_data['email']).exists():
return User.objects.get(email__iexact=self.validated_data['email'])
@ -29,7 +29,34 @@ class GoogleSignInSerializer(serializers.Serializer):
email=self.validated_data['email'])
return instance
class UpdateGuardianImageSerializer(serializers.ModelSerializer):
"""Reset Password after verification"""
class Meta(object):
"""Meta info"""
model = Guardian
fields = '__all__'
def update(self, instance, validated_data):
"""update image """
instance.image = validated_data.get('image', instance.image)
instance.save()
return instance
class UpdateJuniorProfileImageSerializer(serializers.ModelSerializer):
"""Reset Password after verification"""
class Meta(object):
"""Meta info"""
model = Junior
fields = '__all__'
def update(self, instance, validated_data):
"""update image """
image = validated_data.get('image', instance.image)
filename = f"images/{image.name}"
image_url = upload_image_to_alibaba(image, filename)
instance.image = image_url
instance.save()
return instance
class ResetPasswordSerializer(serializers.Serializer):
"""Reset Password after verification"""
verification_code = serializers.CharField(max_length=10)
@ -41,15 +68,10 @@ class ResetPasswordSerializer(serializers.Serializer):
def create(self, validated_data):
verification_code = validated_data.pop('verification_code')
password = validated_data.pop('password')
print("verification_code===>",verification_code)
print("password===>", password)
user_opt_details = UserEmailOtp.objects.filter(otp=verification_code, is_verified=True).last()
print("user_opt_details===>",user_opt_details)
if user_opt_details:
print("qqqqqqqqqq")
user_details = User.objects.filter(email=user_opt_details.email).last()
if user_details:
print("333333333==>",user_details.password)
user_details.set_password(password)
user_details.save()
return {'password':password}
@ -69,13 +91,14 @@ class ChangePasswordSerializer(serializers.Serializer):
if self.context.password not in ('', None):
if user.check_password(value):
return value
raise serializers.ValidationError({"error":"Invalid Current password"})
raise serializers.ValidationError({"details":ERROR_CODE['2015']})
def create(self, validated_data):
new_password = validated_data.pop('new_password')
current_password = validated_data.pop('current_password')
if new_password == current_password:
raise serializers.ValidationError({"details": ERROR_CODE['2026']})
user_details = User.objects.filter(email=self.context).last()
print("user_details==>", user_details)
if user_details:
print("333333333==>",user_details.password)
user_details.set_password(new_password)
user_details.save()
return {'password':new_password}

View File

@ -5,7 +5,7 @@ from rest_framework.decorators import api_view
"""Third party import"""
from rest_framework import routers
from .views import (UserLogin, SendPhoneOtp, UserPhoneVerification, UserEmailVerification, ReSendEmailOtp,
ForgotPasswordAPIView, ResetPasswordAPIView, ChangePasswordAPIView)
ForgotPasswordAPIView, ResetPasswordAPIView, ChangePasswordAPIView, UpdateProfileImage)
"""Router"""
router = routers.SimpleRouter()
@ -17,10 +17,10 @@ router.register('send-phone-otp', SendPhoneOtp, basename='send-phone-otp')
router.register('user-phone-verification', UserPhoneVerification, basename='user-phone-verification')
router.register('user-email-verification', UserEmailVerification, basename='user-email-verification')
router.register('resend-email-otp', ReSendEmailOtp, basename='resend-email-otp')
urlpatterns = [
path('api/v1/', include(router.urls)),
path('api/v1/forgot-password/', ForgotPasswordAPIView.as_view()),
path('api/v1/reset-password/', ResetPasswordAPIView.as_view()),
path('api/v1/change-password/', ChangePasswordAPIView.as_view())
path('api/v1/change-password/', ChangePasswordAPIView.as_view()),
path('api/v1/update-profile-image/', UpdateProfileImage.as_view())
]

View File

@ -6,7 +6,7 @@ from rest_framework.response import Response
from templated_email import send_templated_mail
def send_otp_email(recipient_email, otp):
from_email = settings.EMAIL_HOST_USER
from_email = settings.EMAIL_FROM_ADDRESS
recipient_list = [recipient_email]
send_templated_mail(
template_name='email_otp_verification.email',

View File

@ -9,7 +9,7 @@ from account.models import UserProfile, UserPhoneOtp, UserEmailOtp
from django.contrib.auth.models import User
from .serializers import (SuperUserSerializer, GuardianSerializer, JuniorSerializer, EmailVerificationSerializer,
ForgotPasswordSerializer, ResetPasswordSerializer, ChangePasswordSerializer,
GoogleSignInSerializer)
GoogleSignInSerializer, UpdateGuardianImageSerializer, UpdateJuniorProfileImageSerializer)
from rest_framework_simplejwt.tokens import RefreshToken
from base.messages import ERROR_CODE, SUCCESS_CODE
from guardian.tasks import generate_otp
@ -44,7 +44,19 @@ from templated_email import send_templated_mail
# return custom_response(SUCCESS_CODE["3003"], response_status=status.HTTP_200_OK)
# return custom_response(ERROR_CODE["2002"], response_status=status.HTTP_400_BAD_REQUEST)
class UpdateProfileImage(views.APIView):
permission_classes = [IsAuthenticated]
def put(self, request, format=None):
if request.data['user_type'] == '1':
junior_query = Junior.objects.filter(auth=request.user).last()
serializer = UpdateJuniorProfileImageSerializer(junior_query, data=request.data, partial=True)
else:
guardian_query = Guardian.objects.filter(user=request.user).last()
serializer = UpdateGuardianImageSerializer(guardian_query, data=request.data, partial=True)
if serializer.is_valid():
serializer.save()
return custom_response(SUCCESS_CODE['3017'], serializer.data, response_status=status.HTTP_200_OK)
return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST)
class ChangePasswordAPIView(views.APIView):
permission_classes = [IsAuthenticated]
@ -130,26 +142,26 @@ class UserLogin(viewsets.ViewSet):
username = request.data.get('username')
password = request.data.get('password')
user = authenticate(request, username=username, password=password)
try:
if user is not None:
login(request, user)
guardian_data = Guardian.objects.filter(user__username=username, is_complete_profile=True).last()
guardian_data = Guardian.objects.filter(user__username=username, is_verified=True).last()
if guardian_data:
serializer = GuardianSerializer(guardian_data)
junior_data = Junior.objects.filter(auth__username=username, is_complete_profile=True).last()
serializer = GuardianSerializer(guardian_data).data
junior_data = Junior.objects.filter(auth__username=username, is_verified=True).last()
if junior_data:
serializer = JuniorSerializer(junior_data)
return custom_response(SUCCESS_CODE['3003'], serializer.data, response_status=status.HTTP_200_OK)
serializer = JuniorSerializer(junior_data).data
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)
except Exception as e:
logging.error(e)
user_profile_data = UserProfile.objects.filter(user__username=username).last()
email_verified = UserEmailOtp.objects.filter(email=username).last()
refresh = RefreshToken.for_user(user)
access_token = str(refresh.access_token)
data = {"auth_token":access_token, "is_profile_complete": False,
"user_role": user_profile_data.user_type,
"user_type": email_verified.user_type,
}
is_verified = False
if email_verified:
@ -196,6 +208,16 @@ class UserEmailVerification(viewsets.ModelViewSet):
if email_data:
email_data.is_verified = True
email_data.save()
if email_data.user_type == '1':
junior_data = Junior.objects.filter(auth__email=self.request.GET.get('email')).last()
if junior_data:
junior_data.is_verified = True
junior_data.save()
else:
guardian_data = Guardian.objects.filter(user__email=self.request.GET.get('email')).last()
if guardian_data:
guardian_data.is_verified = True
guardian_data.save()
refresh = RefreshToken.for_user(user_obj)
access_token = str(refresh.access_token)
return custom_response(SUCCESS_CODE['3011'], {"auth_token":access_token}, response_status=status.HTTP_200_OK)

View File

@ -35,7 +35,7 @@ ERROR_CODE = {
"2009": "The user provided cannot be found or the reset password token has become invalid/timed out.",
"2010": "Invalid Link.",
"2011": "Your profile has not been completed yet.",
"2012": "Password and Confirm password should be same.",
"2012": "Phone number already used",
"2013": "Invalid token.",
"2014": "Your old password doesn't match.",
"2015": "Invalid old password.",
@ -47,7 +47,9 @@ ERROR_CODE = {
"2021": "Already register",
"2022":"Invalid Guardian code",
"2023":"Invalid user",
"2024":"Email not verified"
"2024":"Email not verified",
"2025":"Invalid input. Expected a list of strings.",
"2026" : "New password should not same as old password"
}
SUCCESS_CODE = {
# Success code for password
@ -75,7 +77,8 @@ SUCCESS_CODE = {
"3013": "Valid Guardian code",
"3014": "Password has been updated successfully.",
"3015": "Verification code sent on your email.",
"3016": "Send otp on your Email successfully"
"3016": "Send otp on your Email successfully",
"3017": "Profile image update successfully"
}
STATUS_CODE_ERROR = {

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2.2 on 2023-06-28 06:52
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('guardian', '0003_guardian_country_name'),
]
operations = [
migrations.AddField(
model_name='guardian',
name='image',
field=models.ImageField(blank=True, default=None, null=True, upload_to='images/'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2.2 on 2023-06-29 06:14
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('guardian', '0004_guardian_image'),
]
operations = [
migrations.AlterField(
model_name='guardian',
name='image',
field=models.ImageField(blank=True, default=None, null=True, upload_to=''),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2.2 on 2023-06-29 12:10
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('guardian', '0005_alter_guardian_image'),
]
operations = [
migrations.AddField(
model_name='guardian',
name='is_verified',
field=models.BooleanField(default=False),
),
]

View File

@ -14,18 +14,21 @@ class Guardian(models.Model):
country_code = models.IntegerField(blank=True, null=True)
phone = models.CharField(max_length=31, null=True, blank=True, default=None)
country_name = models.CharField(max_length=30, null=True, blank=True, default=None)
"""Image info"""
image = models.ImageField(null=True, blank=True, default=None)
"""Personal info"""
family_name = models.CharField(max_length=50, null=True, blank=True, default=None)
gender = models.CharField(choices=GENDERS, max_length=15, null=True, blank=True, default=None)
dob = models.DateField(max_length=15, null=True, blank=True, default=None)
"""Profile activity"""
is_active = models.BooleanField(default=True)
is_verified = models.BooleanField(default=False)
is_complete_profile = models.BooleanField(default=False)
passcode = models.IntegerField(null=True, blank=True, default=None)
"""Codes"""
guardian_code = models.CharField(max_length=10, null=True, blank=True, default=None)
referral_code = models.CharField(max_length=10, null=True, blank=True, default=None)
referral_code_used = models.CharField(max_length=10, null=True, blank=True, default=None)
"""Profile activity"""
is_active = models.BooleanField(default=True)
is_complete_profile = models.BooleanField(default=False)
passcode = models.IntegerField(null=True, blank=True, default=None)
"""Profile created and updated time"""
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)

View File

@ -8,8 +8,10 @@ from django.db import transaction
from django.contrib.auth.models import User
"""Import Django app"""
from .models import Guardian
from account.models import UserProfile
from account.models import UserProfile, UserEmailOtp
from base.messages import ERROR_CODE, SUCCESS_CODE
from .utils import upload_image_to_alibaba
from junior.models import Junior
class UserSerializer(serializers.ModelSerializer):
"""User serializer"""
auth_token = serializers.SerializerMethodField('get_auth_token')
@ -33,17 +35,20 @@ class UserSerializer(serializers.ModelSerializer):
"""Create user profile"""
user = User.objects.create_user(username=email, email=email, password=password)
UserProfile.objects.create(user=user, user_type=user_type)
if user_type == '1':
Junior.objects.create(auth=user)
if user_type == '2':
Guardian.objects.create(user=user)
return user
except Exception as e:
"""Error handling"""
logging.error(e)
raise serializers.ValidationError({"details":ERROR_CODE['2021']})
def save(self, **kwargs):
"""save the data"""
with transaction.atomic():
instance = super().save(**kwargs)
return instance
otp = UserEmailOtp.objects.filter(email=email).last()
otp_verified = False
if otp and otp.is_verified:
otp_verified = True
raise serializers.ValidationError({"details":ERROR_CODE['2021'], "otp_verified":otp_verified, "code": "400", "status":"failed",
})
class CreateGuardianSerializer(serializers.ModelSerializer):
"""Create guardian serializer"""
@ -57,13 +62,14 @@ class CreateGuardianSerializer(serializers.ModelSerializer):
family_name = serializers.CharField(max_length=100, required=False)
dob = serializers.DateField(required=False)
referral_code = serializers.CharField(max_length=100, required=False)
image = serializers.ImageField(required=False)
class Meta(object):
"""Meta info"""
model = Guardian
fields = ['first_name', 'last_name', 'email', 'phone', 'family_name', 'gender', 'country_code',
'dob', 'referral_code', 'passcode', 'is_complete_profile', 'referral_code_used',
'country_name']
'country_name', 'image']
def get_first_name(self,obj):
"""first name of guardian"""
@ -79,6 +85,11 @@ class CreateGuardianSerializer(serializers.ModelSerializer):
def create(self, validated_data):
"""Create guardian profile"""
phone_number = validated_data.get('phone', None)
guardian_data = Guardian.objects.filter(phone=phone_number)
junior_data = Junior.objects.filter(phone=phone_number)
if phone_number and (guardian_data or junior_data):
raise serializers.ValidationError({"details": ERROR_CODE['2012']})
user = User.objects.filter(username=self.context['user']).last()
if user:
"""Save first and last name of guardian"""
@ -109,6 +120,11 @@ class CreateGuardianSerializer(serializers.ModelSerializer):
guardian.is_complete_profile = False
if complete_profile_field:
guardian.is_complete_profile = True
image = validated_data.pop('image', None)
if image:
filename = f"images/{image.name}"
image_url = upload_image_to_alibaba(image, filename)
guardian.image = image_url
guardian.save()
return guardian

13
guardian/utils.py Normal file
View File

@ -0,0 +1,13 @@
import oss2
from django.conf import settings
import tempfile
def upload_image_to_alibaba(image, filename):
# Save the image object to a temporary file
with tempfile.NamedTemporaryFile(delete=False) as temp_file:
temp_file.write(image.read())
auth = oss2.Auth(settings.ALIYUN_OSS_ACCESS_KEY_ID, settings.ALIYUN_OSS_ACCESS_KEY_SECRET)
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)
return f"https://{settings.ALIYUN_OSS_BUCKET_NAME}.{settings.ALIYUN_OSS_ENDPOINT}/{filename}"

View File

@ -3,8 +3,9 @@
from rest_framework.permissions import IsAuthenticated
from rest_framework import viewsets, status
"""Import Django app"""
from .serializers import UserSerializer
from .serializers import CreateGuardianSerializer
from .serializers import UserSerializer, CreateGuardianSerializer
from .models import Guardian
from junior.models import Junior
from account.models import UserEmailOtp
from .tasks import generate_otp
from account.utils import send_otp_email
@ -22,7 +23,7 @@ class SignupViewset(viewsets.ModelViewSet):
serializer.save()
"""Generate otp"""
otp = generate_otp()
UserEmailOtp.objects.create(email=request.data['email'], otp=otp)
UserEmailOtp.objects.create(email=request.data['email'], otp=otp, user_type=str(request.data['user_type']))
"""Send email to the register user"""
send_otp_email(request.data['email'], otp)
return custom_response(SUCCESS_CODE['3001'], {"email_otp": otp},

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2.2 on 2023-06-28 10:16
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('junior', '0002_junior_country_name'),
]
operations = [
migrations.AddField(
model_name='junior',
name='image',
field=models.ImageField(blank=True, default=None, null=True, upload_to='images/'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2.2 on 2023-06-29 06:14
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('junior', '0003_junior_image'),
]
operations = [
migrations.AlterField(
model_name='junior',
name='image',
field=models.ImageField(blank=True, default=None, null=True, upload_to=''),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2.2 on 2023-06-29 12:10
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('junior', '0004_alter_junior_image'),
]
operations = [
migrations.AddField(
model_name='junior',
name='is_verified',
field=models.BooleanField(default=False),
),
]

View File

@ -18,7 +18,7 @@ class Junior(models.Model):
"""Personal info"""
gender = models.CharField(max_length=10, choices=GENDERS, null=True, blank=True, default=None)
dob = models.DateField(max_length=15, null=True, blank=True, default=None)
# image = models.ImageField(upload_to='images/')
image = models.ImageField(null=True, blank=True, default=None)
"""Codes"""
junior_code = models.CharField(max_length=10, null=True, blank=True, default=None)
guardian_code = ArrayField(models.CharField(max_length=10, null=True, blank=True, default=None),null=True)
@ -28,6 +28,7 @@ class Junior(models.Model):
is_active = models.BooleanField(default=True)
is_complete_profile = models.BooleanField(default=False)
passcode = models.IntegerField(null=True, blank=True, default=None)
is_verified = models.BooleanField(default=False)
"""Profile created and updated time"""
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)

View File

@ -6,6 +6,9 @@ from django.db import transaction
import random
"""Import django app"""
from junior.models import Junior
from guardian.utils import upload_image_to_alibaba
from base.messages import ERROR_CODE, SUCCESS_CODE
from guardian.models import Guardian
class ListCharField(serializers.ListField):
"""Serializer for Array field"""
@ -19,7 +22,7 @@ class ListCharField(serializers.ListField):
"""internal value"""
if isinstance(data, list):
return data
raise serializers.ValidationError({"details":"Invalid input. Expected a list of strings."})
raise serializers.ValidationError({"details":ERROR_CODE['2025']})
class CreateJuniorSerializer(serializers.ModelSerializer):
@ -32,13 +35,14 @@ class CreateJuniorSerializer(serializers.ModelSerializer):
dob = serializers.DateField(required=False)
referral_code = serializers.CharField(max_length=100, required=False)
guardian_code = ListCharField(required=False)
image = serializers.ImageField(required=False)
class Meta(object):
"""Meta info"""
model = Junior
fields = ['first_name', 'last_name', 'email', 'phone', 'gender', 'country_code', 'dob', 'referral_code',
'passcode', 'is_complete_profile', 'guardian_code', 'referral_code_used',
'country_name']
'country_name', 'image']
def get_first_name(self,obj):
"""first name of junior"""
@ -54,6 +58,12 @@ class CreateJuniorSerializer(serializers.ModelSerializer):
def create(self, validated_data):
"""Create junior profile"""
image = validated_data.get('image', None)
phone_number = validated_data.get('phone', None)
guardian_data = Guardian.objects.filter(phone=phone_number)
junior_data = Junior.objects.filter(phone=phone_number)
if phone_number and (junior_data or guardian_data):
raise serializers.ValidationError({"details":ERROR_CODE['2012']})
user = User.objects.filter(username=self.context['user']).last()
if user:
"""Save first and last name of junior"""
@ -85,6 +95,10 @@ class CreateJuniorSerializer(serializers.ModelSerializer):
junior.is_complete_profile = False
if complete_profile_field:
junior.is_complete_profile = True
if image:
filename = f"images/{image.name}"
image_url = upload_image_to_alibaba(image, filename)
junior.image = image_url
junior.save()
return junior

View File

@ -19,6 +19,6 @@ upstream web {
location /static {
autoindex on;
alias /usr/src/app/zod_bank/static/;
alias /usr/src/app/static/;
}
}

View File

@ -1,5 +1,7 @@
aliyun-python-sdk-core==2.13.36
aliyun-python-sdk-dysmsapi==2.1.2
aliyun-python-sdk-kms==2.16.1
aliyun-python-sdk-sts==3.1.1
amqp==5.1.1
asgiref==3.7.2
async-timeout==4.0.2
@ -7,13 +9,16 @@ billiard==4.1.0
boto3==1.26.157
botocore==1.29.157
celery==5.3.1
certifi==2023.5.7
cffi==1.15.1
channels==4.0.0
channels-redis==4.1.0
charset-normalizer==3.1.0
click==8.1.3
click-didyoumean==0.3.0
click-plugins==1.1.1
click-repl==0.3.0
crcmod==1.7
cron-descriptor==1.4.0
cryptography==41.0.1
decouple==0.0.7
@ -34,15 +39,19 @@ djangorestframework==3.14.0
djangorestframework-simplejwt==5.2.2
drf-yasg==1.21.6
gunicorn==20.1.0
idna==3.4
inflection==0.5.1
jmespath==0.10.0
kombu==5.3.1
msgpack==1.0.5
oss2==2.18.0
packaging==23.1
phonenumbers==8.13.15
Pillow==9.5.0
prompt-toolkit==3.0.38
psycopg==3.1.9
pycparser==2.21
pycryptodome==3.18.0
PyJWT==2.7.0
python-crontab==2.7.1
python-dateutil==2.8.2
@ -50,6 +59,7 @@ python-dotenv==1.0.0
pytz==2023.3
PyYAML==6.0
redis==4.5.5
requests==2.31.0
s3transfer==0.6.1
six==1.16.0
sqlparse==0.4.4

View File

@ -172,20 +172,33 @@ CORS_ALLOW_HEADERS = (
https://docs.djangoproject.com/en/3.0/howto/static-files/"""
# Email settings
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = 'infozodbank@gmail.com'
# Replace with your Gmail email password or App password
EMAIL_HOST_PASSWORD = 'ghwdmznwwslvchga'
# EMAIL_USE_TLS = os.getenv('EMAIL_USE_TLS')
# EMAIL_BACKEND = os.getenv('EMAIL_BACKEND')
# EMAIL_HOST = os.getenv('EMAIL_HOST')
# EMAIL_HOST_USER = os.getenv('EMAIL_HOST_USER')
# EMAIL_HOST_PASSWORD = os.getenv('EMAIL_HOST_PASSWORD')
# EMAIL_PORT = os.getenv('EMAIL_PORT')
# EMAIL_USE_TLS = os.getenv('EMAIL_USE_TLS')
# EMAIL_HOST_USER = os.getenv('EMAIL_HOST_USER') # Replace with your Gmail email address
# EMAIL_HOST_PASSWORD = os.getenv('EMAIL_HOST_PASSWORD') # Replace with your Gmail email password or App password
# EMAIL_FROM_ADDRESS = os.getenv('EMAIL_FROM_ADDRESS')
EMAIL_BACKEND="django.core.mail.backends.smtp.EmailBackend"
EMAIL_HOST="smtp.sendgrid.net"
EMAIL_PORT="587"
EMAIL_USE_TLS="True"
EMAIL_HOST_USER="apikey" # Replace with your Gmail email address
EMAIL_HOST_PASSWORD="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"
EMAIL_FROM_ADDRESS="zodbank@yopmail.com"
# ALIYUN_OSS_ACCESS_KEY_ID = os.getenv('ALIYUN_OSS_ACCESS_KEY_ID')
# ALIYUN_OSS_ACCESS_KEY_SECRET = os.getenv('ALIYUN_OSS_ACCESS_KEY_SECRET')
# ALIYUN_OSS_BUCKET_NAME = os.getenv('ALIYUN_OSS_BUCKET_NAME')
# ALIYUN_OSS_ENDPOINT = os.getenv('ALIYUN_OSS_ENDPOINT')
# ALIYUN_OSS_REGION = os.getenv('ALIYUN_OSS_REGION')
ALIYUN_OSS_ACCESS_KEY_ID="LTAI5t7w1gq1CswJtvxtEZTd"
ALIYUN_OSS_ACCESS_KEY_SECRET="6yknAFpP2gVMhCWAJwbAjCEw2eehpf"
ALIYUN_OSS_BUCKET_NAME="zod-dev"
ALIYUN_OSS_ENDPOINT="oss-me-central-1.aliyuncs.com"
ALIYUN_OSS_REGION="Global"
STATIC_URL = 'static/'
STATIC_ROOT = 'static'