From 5d386322e44cec026d48060fcdac73ce19bf0077 Mon Sep 17 00:00:00 2001 From: dilipshrivastwa-kiwi Date: Thu, 15 Jun 2023 15:11:18 +0530 Subject: [PATCH 01/19] add git ignore file --- .gitignore | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..063a8af --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +/static +/media +.idea/ +*.pyc +media/ +*.name +*.iml +*.log +*.xml +*.pyo +.DS_Store +.idea +venv/* +static/* +*.pem +*.sqlite3 +/migrations/__pycache__/ +/__pycache__/ +/*.pyc +*/__pycache__/*.pyc +__pycache__/ +*.env +ve/* + From 8bc3a307c03b879c26acfad66bd1bcc8e61df615 Mon Sep 17 00:00:00 2001 From: jain Date: Fri, 23 Jun 2023 19:13:49 +0530 Subject: [PATCH 02/19] Initial Commit --- zod_bank/account/__init__.py | 0 zod_bank/account/admin.py | 25 +++ zod_bank/account/apps.py | 6 + zod_bank/account/migrations/0001_initial.py | 65 +++++++ zod_bank/account/migrations/__init__.py | 0 zod_bank/account/models.py | 75 ++++++++ zod_bank/account/serializers.py | 104 +++++++++++ zod_bank/account/tests.py | 3 + zod_bank/account/urls.py | 20 +++ zod_bank/account/utils.py | 31 ++++ zod_bank/account/views.py | 111 ++++++++++++ zod_bank/base/__init__.py | 3 + zod_bank/base/common_email.py | 30 ++++ zod_bank/base/constants.py | 99 +++++++++++ zod_bank/base/custom_exceptions.py | 16 ++ zod_bank/base/image_constants.py | 16 ++ zod_bank/base/messages.py | 92 ++++++++++ zod_bank/base/routers.py | 17 ++ zod_bank/base/search_and_filters.py | 49 +++++ zod_bank/base/upload_file.py | 177 +++++++++++++++++++ zod_bank/guardian/__init__.py | 0 zod_bank/guardian/admin.py | 9 + zod_bank/guardian/apps.py | 6 + zod_bank/guardian/migrations/0001_initial.py | 43 +++++ zod_bank/guardian/migrations/__init__.py | 0 zod_bank/guardian/models.py | 31 ++++ zod_bank/guardian/serializers.py | 91 ++++++++++ zod_bank/guardian/tasks.py | 6 + zod_bank/guardian/tests.py | 3 + zod_bank/guardian/urls.py | 17 ++ zod_bank/guardian/views.py | 44 +++++ zod_bank/junior/__init__.py | 0 zod_bank/junior/admin.py | 9 + zod_bank/junior/apps.py | 6 + zod_bank/junior/migrations/0001_initial.py | 42 +++++ zod_bank/junior/migrations/__init__.py | 0 zod_bank/junior/models.py | 32 ++++ zod_bank/junior/serializers.py | 73 ++++++++ zod_bank/junior/tests.py | 3 + zod_bank/junior/urls.py | 17 ++ zod_bank/junior/views.py | 40 +++++ zod_bank/manage.py | 21 +++ zod_bank/nginx/django.conf | 24 +++ zod_bank/requirements.txt | 55 ++++++ zod_bank/zod_bank/__init__.py | 0 zod_bank/zod_bank/asgi.py | 16 ++ zod_bank/zod_bank/settings.py | 176 ++++++++++++++++++ zod_bank/zod_bank/urls.py | 33 ++++ zod_bank/zod_bank/wsgi.py | 16 ++ 49 files changed, 1752 insertions(+) create mode 100644 zod_bank/account/__init__.py create mode 100644 zod_bank/account/admin.py create mode 100644 zod_bank/account/apps.py create mode 100644 zod_bank/account/migrations/0001_initial.py create mode 100644 zod_bank/account/migrations/__init__.py create mode 100644 zod_bank/account/models.py create mode 100644 zod_bank/account/serializers.py create mode 100644 zod_bank/account/tests.py create mode 100644 zod_bank/account/urls.py create mode 100644 zod_bank/account/utils.py create mode 100644 zod_bank/account/views.py create mode 100644 zod_bank/base/__init__.py create mode 100644 zod_bank/base/common_email.py create mode 100644 zod_bank/base/constants.py create mode 100644 zod_bank/base/custom_exceptions.py create mode 100644 zod_bank/base/image_constants.py create mode 100644 zod_bank/base/messages.py create mode 100644 zod_bank/base/routers.py create mode 100644 zod_bank/base/search_and_filters.py create mode 100644 zod_bank/base/upload_file.py create mode 100644 zod_bank/guardian/__init__.py create mode 100644 zod_bank/guardian/admin.py create mode 100644 zod_bank/guardian/apps.py create mode 100644 zod_bank/guardian/migrations/0001_initial.py create mode 100644 zod_bank/guardian/migrations/__init__.py create mode 100644 zod_bank/guardian/models.py create mode 100644 zod_bank/guardian/serializers.py create mode 100644 zod_bank/guardian/tasks.py create mode 100644 zod_bank/guardian/tests.py create mode 100644 zod_bank/guardian/urls.py create mode 100644 zod_bank/guardian/views.py create mode 100644 zod_bank/junior/__init__.py create mode 100644 zod_bank/junior/admin.py create mode 100644 zod_bank/junior/apps.py create mode 100644 zod_bank/junior/migrations/0001_initial.py create mode 100644 zod_bank/junior/migrations/__init__.py create mode 100644 zod_bank/junior/models.py create mode 100644 zod_bank/junior/serializers.py create mode 100644 zod_bank/junior/tests.py create mode 100644 zod_bank/junior/urls.py create mode 100644 zod_bank/junior/views.py create mode 100755 zod_bank/manage.py create mode 100644 zod_bank/nginx/django.conf create mode 100644 zod_bank/requirements.txt create mode 100644 zod_bank/zod_bank/__init__.py create mode 100644 zod_bank/zod_bank/asgi.py create mode 100644 zod_bank/zod_bank/settings.py create mode 100644 zod_bank/zod_bank/urls.py create mode 100644 zod_bank/zod_bank/wsgi.py diff --git a/zod_bank/account/__init__.py b/zod_bank/account/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/zod_bank/account/admin.py b/zod_bank/account/admin.py new file mode 100644 index 0000000..fce7bde --- /dev/null +++ b/zod_bank/account/admin.py @@ -0,0 +1,25 @@ +from django.contrib import admin + +# Register your models here. +from .models import UserProfile, UserEmailOtp, UserPhoneOtp +# Register your models here. +@admin.register(UserProfile) +class UserProfileAdmin(admin.ModelAdmin): + list_display = ['user'] + + def __str__(self): + return self.user__email + +@admin.register(UserEmailOtp) +class UserEmailOtpAdmin(admin.ModelAdmin): + list_display = ['email'] + + def __str__(self): + return self.email + '-' + self.otp + +@admin.register(UserPhoneOtp) +class UserPhoneOtpAdmin(admin.ModelAdmin): + list_display = ['phone'] + + def __str__(self): + return self.phone + '-' + self.otp diff --git a/zod_bank/account/apps.py b/zod_bank/account/apps.py new file mode 100644 index 0000000..2b08f1a --- /dev/null +++ b/zod_bank/account/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class AccountConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'account' diff --git a/zod_bank/account/migrations/0001_initial.py b/zod_bank/account/migrations/0001_initial.py new file mode 100644 index 0000000..3a50122 --- /dev/null +++ b/zod_bank/account/migrations/0001_initial.py @@ -0,0 +1,65 @@ +# Generated by Django 4.2.2 on 2023-06-23 12:05 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='UserEmailOtp', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('email', models.EmailField(max_length=254)), + ('otp', models.CharField(max_length=10)), + ('is_verified', models.BooleanField(default=False)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('expired_at', models.DateTimeField(blank=True, null=True)), + ('is_active', models.BooleanField(default=True)), + ], + options={ + 'db_table': 'user_email_otp', + }, + ), + migrations.CreateModel( + name='UserPhoneOtp', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('country_code', models.IntegerField()), + ('phone', models.CharField(max_length=17)), + ('otp', models.CharField(max_length=10)), + ('is_verified', models.BooleanField(default=False)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('expired_at', models.DateTimeField(blank=True, null=True)), + ('is_active', models.BooleanField(default=True)), + ], + options={ + 'db_table': 'user_phone_otp', + }, + ), + migrations.CreateModel( + name='UserProfile', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('user_type', models.CharField(blank=True, choices=[('1', 'junior'), ('2', 'guardian'), ('3', 'superuser')], default=None, max_length=15, null=True)), + ('is_verified', models.BooleanField(default=False)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('is_active', models.BooleanField(default=False)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='user_profile', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'db_table': 'user_profile', + }, + ), + ] diff --git a/zod_bank/account/migrations/__init__.py b/zod_bank/account/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/zod_bank/account/models.py b/zod_bank/account/models.py new file mode 100644 index 0000000..ff8bb5d --- /dev/null +++ b/zod_bank/account/models.py @@ -0,0 +1,75 @@ +from django.db import models +import random +from django.contrib.auth.models import User +from base.constants import USER_TYPE +# Create your models here. + +class UserProfile(models.Model): + """ + User details + """ + user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='user_profile') + user_type = models.CharField(max_length=15, choices=USER_TYPE, null=True, blank=True, default=None) + is_verified = models.BooleanField(default=False) + + # OTP validity + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + is_active = models.BooleanField(default=False) + + class Meta(object): + """ Meta information """ + db_table = 'user_profile' + + def __str__(self): + """return phone as an object""" + return f'{self.user}' + +class UserPhoneOtp(models.Model): + """ + This class is used to verify user email and their contact no. + """ + """user details""" + country_code = models.IntegerField() + phone = models.CharField(max_length=17) + """otp details""" + otp = models.CharField(max_length=10) + is_verified = models.BooleanField(default=False) + + # OTP validity + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + expired_at = models.DateTimeField(blank=True, null=True) + is_active = models.BooleanField(default=True) + + class Meta(object): + """ Meta information """ + db_table = 'user_phone_otp' + + def __str__(self): + """return phone as an object""" + return self.phone + +class UserEmailOtp(models.Model): + """ + This class is used to verify user email and their contact no. + """ + """user details""" + email = models.EmailField() + """otp details""" + otp = models.CharField(max_length=10) + is_verified = models.BooleanField(default=False) + + # OTP validity + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + expired_at = models.DateTimeField(blank=True, null=True) + is_active = models.BooleanField(default=True) + + class Meta(object): + """ Meta information """ + db_table = 'user_email_otp' + + def __str__(self): + """return phone as an object""" + return self.email diff --git a/zod_bank/account/serializers.py b/zod_bank/account/serializers.py new file mode 100644 index 0000000..03b1012 --- /dev/null +++ b/zod_bank/account/serializers.py @@ -0,0 +1,104 @@ +from rest_framework import serializers +from django.contrib.auth.models import User +from guardian.models import Guardian +from junior.models import Junior +from account.models import UserProfile, UserEmailOtp, UserPhoneOtp +from base.constants import GUARDIAN, JUNIOR, SUPERUSER +from django.db import transaction +from base.messages import ERROR_CODE_REQUIRED, ERROR_CODE, SUCCESS_CODE, STATUS_CODE_ERROR +from django.core.exceptions import ObjectDoesNotExist +from django.contrib.auth import authenticate +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 + +class SuperUserSerializer(serializers.ModelSerializer): + user_type = serializers.SerializerMethodField('get_user_type') + + def get_user_type(self, obj): + """user type""" + return SUPERUSER + + class Meta(object): + """Meta info""" + model = User + fields = ['id', 'username', 'email', 'first_name', 'last_name', 'is_active', 'user_type'] + + +class GuardianSerializer(serializers.ModelSerializer): + """guardian serializer""" + user_type = serializers.SerializerMethodField('get_user_type') + email = serializers.SerializerMethodField('get_auth') + first_name = serializers.SerializerMethodField('get_first_name') + last_name = serializers.SerializerMethodField('get_last_name') + auth_token = serializers.SerializerMethodField('get_auth_token') + + def get_auth_token(self, obj): + refresh = RefreshToken.for_user(obj.user) + access_token = str(refresh.access_token) + return access_token + + def get_user_type(self, obj): + """user type""" + return GUARDIAN + + def get_auth(self, obj): + """user email address""" + return obj.user.username + + def get_first_name(self, obj): + """user first name""" + return obj.user.first_name + + def get_last_name(self, obj): + """user last name""" + return obj.user.last_name + + class Meta(object): + """Meta info""" + model = Guardian + fields = ['auth_token', 'email', 'first_name', 'last_name', 'country_code', 'phone', 'family_name', 'gender', 'dob', + 'referral_code', 'is_active', 'is_complete_profile', 'passcode', + 'created_at', 'updated_at', 'user_type'] + + +class JuniorSerializer(serializers.ModelSerializer): + """junior serializer""" + user_type = serializers.SerializerMethodField('get_user_type') + email = serializers.SerializerMethodField('get_auth') + first_name = serializers.SerializerMethodField('get_first_name') + last_name = serializers.SerializerMethodField('get_last_name') + auth_token = serializers.SerializerMethodField('get_auth_token') + + def get_auth_token(self, obj): + refresh = RefreshToken.for_user(obj.auth) + access_token = str(refresh.access_token) + return access_token + + def get_user_type(self, obj): + return JUNIOR + + def get_auth(self, obj): + return obj.auth.username + + def get_first_name(self, obj): + return obj.auth.first_name + + def get_last_name(self, obj): + return obj.auth.last_name + + class Meta(object): + """Meta info""" + model = Junior + fields = ['auth_token', 'email', 'first_name', 'last_name', 'country_code', 'phone', 'gender', 'dob', + 'guardian_code', 'referral_code','is_active', 'is_complete_profile', 'created_at', + 'updated_at', 'user_type'] + +class EmailVerificationSerializer(serializers.ModelSerializer): + """Email verification serializer""" + class Meta(object): + """Meta info""" + model = UserEmailOtp + fields = '__all__' + diff --git a/zod_bank/account/tests.py b/zod_bank/account/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/zod_bank/account/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/zod_bank/account/urls.py b/zod_bank/account/urls.py new file mode 100644 index 0000000..1350cea --- /dev/null +++ b/zod_bank/account/urls.py @@ -0,0 +1,20 @@ +""" Urls files""" +"""Django import""" +from django.urls import path, include +from rest_framework.decorators import api_view +"""Third party import""" +from rest_framework import routers +from .views import UserLogin, SendPhoneOtp, UserPhoneVerification, UserEmailVerification, ReSendEmailOtp +"""Router""" +router = routers.SimpleRouter() + +"""API End points with router""" +router.register('user', UserLogin, basename='user') +router.register('superuser', UserLogin, basename='superuser') +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)), +] diff --git a/zod_bank/account/utils.py b/zod_bank/account/utils.py new file mode 100644 index 0000000..c6ffe7f --- /dev/null +++ b/zod_bank/account/utils.py @@ -0,0 +1,31 @@ +from django.core.mail import send_mail +from django.conf import settings +import random +from rest_framework import viewsets, status +from rest_framework.response import Response +def send_otp_email(recipient_email, otp): + subject = 'One-Time Password' + message = f'Your OTP is: {otp}' + from_email = settings.DEFAULT_FROM_EMAIL + recipient_list = [recipient_email] + send_mail(subject, message, from_email, recipient_list) + return otp + +def custom_response(detail, data=None, response_status=status.HTTP_200_OK): + """Custom response code""" + if not data: + data = None + + return Response({"data": data, "message": detail, "status": "success", "code": response_status}) + + +def custom_error_response(detail, response_status): + """ + function is used for getting same global error response for all + :param detail: error message . + :param response_status: http status. + :return: Json response + """ + if not detail: + detail = {} + return Response({"error": detail, "status": "failed", "code": response_status}) diff --git a/zod_bank/account/views.py b/zod_bank/account/views.py new file mode 100644 index 0000000..352b834 --- /dev/null +++ b/zod_bank/account/views.py @@ -0,0 +1,111 @@ +from rest_framework import viewsets, status +from rest_framework.decorators import action +from rest_framework.response import Response +from django.contrib.auth import authenticate, login +from guardian.models import Guardian +from junior.models import Junior +from account.models import UserProfile, UserPhoneOtp, UserEmailOtp +from django.contrib.auth.models import User +from .serializers import SuperUserSerializer, GuardianSerializer, JuniorSerializer, EmailVerificationSerializer +from django.views.decorators.csrf import csrf_exempt +from rest_framework_simplejwt.serializers import TokenObtainPairSerializer +from rest_framework_simplejwt.views import TokenObtainPairView +from rest_framework_simplejwt.tokens import RefreshToken +from base.messages import ERROR_CODE, SUCCESS_CODE +from guardian.tasks import generate_otp + +from account.utils import custom_response, custom_error_response +class SendPhoneOtp(viewsets.ModelViewSet): + """Send otp on phone""" + def create(self, request, *args, **kwargs): + otp = generate_otp() + UserPhoneOtp.objects.create(country_code=self.request.data['country_code'], + phone=self.request.data['phone'], otp=otp) + return custom_response(None, {'phone_otp':otp}, response_status=status.HTTP_200_OK) + + +class UserPhoneVerification(viewsets.ModelViewSet): + """Send otp on phone""" + def list(self, request, *args, **kwargs): + try: + phone_data = UserPhoneOtp.objects.filter(phone=request.data['phone'], + otp=request.data['otp']).last() + if phone_data: + phone_data.is_verified = True + phone_data.save() + return custom_response(SUCCESS_CODE['3027'], response_status=status.HTTP_200_OK) + else: + return custom_error_response(ERROR_CODE["2008"], response_status=status.HTTP_400_BAD_REQUEST) + except Exception as e: + return custom_error_response(ERROR_CODE["2008"], response_status=status.HTTP_400_BAD_REQUEST) + + + +class UserLogin(viewsets.ViewSet): + @action(methods=['post'], detail=False) + def login(self, request): + 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() + if guardian_data: + serializer = GuardianSerializer(guardian_data) + junior_data = Junior.objects.filter(auth__username=username, is_complete_profile=True).last() + if junior_data: + serializer = JuniorSerializer(junior_data) + if user.is_superuser: + serializer = SuperUserSerializer(user) + return custom_response(None, serializer.data, response_status=status.HTTP_200_OK) + else: + return custom_error_response(ERROR_CODE["2002"], response_status=status.HTTP_401_UNAUTHORIZED) + except Exception as 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, + } + is_verified = False + if email_verified: + is_verified = email_verified.is_verified + if not is_verified: + otp = generate_otp() + email_verified.otp = otp + email_verified.save() + data.update({"email_otp":otp}) + return custom_response(ERROR_CODE['2024'], {"email_otp":otp, "is_email_verified": is_verified}, + response_status=status.HTTP_400_BAD_REQUEST) + data.update({"is_email_verified": is_verified}) + return custom_response(None, data, response_status=status.HTTP_200_OK) + +class UserEmailVerification(viewsets.ModelViewSet): + """User Email verification""" + serializer_class = EmailVerificationSerializer + + def list(self, request, *args, **kwargs): + try: + email_data = UserEmailOtp.objects.filter(email=request.data['email'], + otp=request.data['otp']).last() + if email_data: + email_data.is_verified = True + email_data.save() + return custom_response(SUCCESS_CODE['3011'], response_status=status.HTTP_200_OK) + else: + return custom_error_response(ERROR_CODE["2008"], response_status=status.HTTP_400_BAD_REQUEST) + except Exception as e: + return custom_error_response(ERROR_CODE["2008"], response_status=status.HTTP_400_BAD_REQUEST) + +class ReSendEmailOtp(viewsets.ModelViewSet): + """Send otp on phone""" + def create(self, request, *args, **kwargs): + otp = generate_otp() + if User.objects.filter(email=request.data['email']): + UserEmailOtp.objects.create(email=request.data['email'], otp=otp) + return custom_response(None, {'email_otp': otp}, response_status=status.HTTP_200_OK) + else: + return custom_error_response(ERROR_CODE["2023"], response_status=status.HTTP_400_BAD_REQUEST) + diff --git a/zod_bank/base/__init__.py b/zod_bank/base/__init__.py new file mode 100644 index 0000000..860fa73 --- /dev/null +++ b/zod_bank/base/__init__.py @@ -0,0 +1,3 @@ +""" +This is init module of the Project Zod Bank +""" diff --git a/zod_bank/base/common_email.py b/zod_bank/base/common_email.py new file mode 100644 index 0000000..4eb2a36 --- /dev/null +++ b/zod_bank/base/common_email.py @@ -0,0 +1,30 @@ +""" +Common send_mail function +""" +import logging + +from django.core.mail import EmailMultiAlternatives + + +def send_mail(subject, message, from_email, recipient_list, html_message=None, cc=None, + fail_silently=False): + """ + Send Email + :param subject: + :param message: + :param from_email: + :param recipient_list: + :param html_message: + :param cc: + :param fail_silently: + :return: + """ + try: + mail = EmailMultiAlternatives(subject, message, from_email, recipient_list, cc) + if html_message: + mail.attach_alternative(html_message, 'text/html') + + return mail.send(fail_silently) + except Exception as e: + logging.error(e) + return False diff --git a/zod_bank/base/constants.py b/zod_bank/base/constants.py new file mode 100644 index 0000000..72f2b0c --- /dev/null +++ b/zod_bank/base/constants.py @@ -0,0 +1,99 @@ +""" +This module contains constants used throughout the project +""" +import os + +# GOOGLE_URL used for interact with google server to verify user existence. +#GOOGLE_URL = "https://www.googleapis.com/plus/v1/" + + +# Super Admin string constant for 'role' +SUPER_ADMIN = "Super Admin" + +# Define jwt_token_expiration time in minutes for now token will expire after 3 days +JWT_TOKEN_EXPIRATION = 3 * 24 * 60 + +# Define common file extention +FILE_EXTENSION = ("gif", "jpeg", "jpg", "png", "svg", "csv", "doc", "docx", "odt", "pdf", "rtf", "txt", "wks", "wp", + "wpd") + +# Define file size in bytes(5MB = 5 * 1024 * 1024) +FILE_SIZE = 5 * 1024 * 1024 + +# String constant for configurable date for allocation lock period +ALLOCATION_LOCK_DATE = 1 + +sort_dict = { + '1': 'name', + '2': '-name' +} +USER_TYPE = ( + ('1', 'junior'), + ('2', 'guardian'), + ('3', 'superuser') +) +GENDERS = ( + ('1', 'Male'), + ('2', 'Female') +) +# duplicate name used defined in constant PROJECT_NAME +PROJECT_NAME = 'Zod Bank' +GUARDIAN = 'guardian' +JUNIOR = 'junior' +SUPERUSER = 'superuser' +# numbers used as a constant +NUMBER = { + 'point_zero': 0.0, + 'zero': 0, + 'one': 1, + 'two': 2, + 'three': 3, + 'four': 4, + 'five': 5, + 'six': 6, + 'seven': 7, + 'eight': 8, + 'nine': 9, + 'ten': 10, + 'eleven': 11, + 'twelve': 12, + 'thirteen': 13, + 'fourteen': 14, + 'fifteen': 15, + 'sixteen': 16, + 'seventeen': 17, + 'eighteen': 18, + 'nineteen': 19, + 'twenty_four': 24, + 'twenty_one': 21, + 'twenty_two': 22, + 'twenty_five': 25, + 'thirty': 30, + 'thirty_five': 35, + 'thirty_six': 36, + 'forty': 40, + 'fifty': 50, + 'fifty_nine': 59, + 'sixty': 60, + 'seventy_five': 75, + 'eighty': 80, + 'ninty_five': 95, + 'ninty_six': 96, + 'ninety_nine': 99, + 'hundred': 100, + 'one_one_nine': 119, + 'one_twenty': 120, + 'four_zero_four': 404, + 'five_hundred': 500, + 'minus_one': -1, + 'point_three': 0.3, + 'point_seven': 0.7 +} + +# Define the byte into kb +BYTE_IMAGE_SIZE = 1024 + +# validate file size +MAX_FILE_SIZE = 1024 * 1024 * 5 + + diff --git a/zod_bank/base/custom_exceptions.py b/zod_bank/base/custom_exceptions.py new file mode 100644 index 0000000..5815504 --- /dev/null +++ b/zod_bank/base/custom_exceptions.py @@ -0,0 +1,16 @@ +""" +module containing override conflict error class +""" +# third party imports +from django.utils.translation import ugettext_lazy as _ +from rest_framework import status +from rest_framework.exceptions import APIException + + +class ConflictError(APIException): + """ + Override conflict error + """ + status_code = status.HTTP_409_CONFLICT + default_detail = _('Not allowed request.') + default_code = 'conflict_error' diff --git a/zod_bank/base/image_constants.py b/zod_bank/base/image_constants.py new file mode 100644 index 0000000..0737698 --- /dev/null +++ b/zod_bank/base/image_constants.py @@ -0,0 +1,16 @@ +""" +This module contains constants used throughout the project +""" +from zod_bank.settings import BUCKET_NAME + +# Define S3 folder url +S3_FOLDER_DIR = { + 'user_image': 'user_image/', +} + +# S3 bucket url +S3_URL = "https://"+BUCKET_NAME+".s3.amazonaws.com/" + +S3_FOLDER_URL = { + 'user_image_file': S3_URL+S3_FOLDER_DIR['user_image'], +} diff --git a/zod_bank/base/messages.py b/zod_bank/base/messages.py new file mode 100644 index 0000000..718d6be --- /dev/null +++ b/zod_bank/base/messages.py @@ -0,0 +1,92 @@ +""" +This module contains all the messages used all across the project +""" + +ERROR_CODE_REQUIRED = { + # Error code for email address + "1000": ["Required email address not found."], + # Error code for password + "1001": ["Required password not found."], + # Error code for Required Post parameters + "1002": ["Required POST parameters not found."], + # Error code for Required Get parameters + "1003": ["Required GET parameters not found."], + # Error code for Required Headers + "1004": ["Required headers were not found."], + # Error code for Required Put parameters + "1005": ["Required PUT parameters not found."], + # Error code for Required query parameters + "1006": ["Required query parameters is not valid."], + # Error code for Required Head parameters + "1008": ["Required HEAD parameters not found."] +} + +# Error code +ERROR_CODE = { + "2000": "Email not found.", + "2001": "Your account has not been verified. Please check your email and verify it.", + "2002": "Invalid login credentials.", + "2003": "An account already exists with this email address.", + "2004": "User doesn't exist.", + "2005": "Your account has been activated.", + "2006": "Your account is not activated.", + "2007": "Your account already activated.", + "2008": "Invalid OTP.", + "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.", + "2013": "Invalid token.", + "2014": "Your old password doesn't match.", + "2015": "Invalid old password.", + "2016": "Invalid search.", + "2017": "{model} object with {pk} does not exist", + "2018": "Attached File not found", + "2019": "Either File extension or File size doesn't meet the requirements", + "2020": "Enter valid mobile number", + "2021": "Already register", + "2022":"Invalid Guardian code", + "2023":"Invalid user", + "2024":"Email not verified" +} +SUCCESS_CODE = { + # Success code for password + "3001": "Sign up successfully", + # Success code for Thank you + "3002": "Thank you for contacting us! Our Consumer Experience Team will reach out to you shortly.", + # Success code for account activation + "3003": "Your account has been activated.", + # Success code for password reset + "3004": "Password reset link has been sent to your email address", + # Success code for link verified + "3005": "Your link has been verified, it's valid", + # Success code for password reset + "3006": "Your password has been reset successfully.", + # Success code for password update + "3007": "Your password has been updated successfully.", + # Success code for valid link + "3008": "You have a valid link.", + # Success code for logged out + "3009": "You have successfully logged out!", + # Success code for check all fields + "3010": "All fields are valid", + "3011": "Email OTP Verified successfully", + "3012": "Phone OTP Verified successfully", + "3013": "Valid Guardian code", + "3014": "Password has been updated successfully." +} + +STATUS_CODE_ERROR = { + # Status code for Invalid Input + "4001": ["Invalid input."], + # Status code for Authentication credentials + "4002": ["Authentication credentials were not provided."], + # Status code for Permission + "4003": ["You do not have permission to perform this action."], + # Status code for not found + "4004": ["Not found."], + # Status code for method not allowed + "4005": ["Method not allowed."] +} + + diff --git a/zod_bank/base/routers.py b/zod_bank/base/routers.py new file mode 100644 index 0000000..e2df0e1 --- /dev/null +++ b/zod_bank/base/routers.py @@ -0,0 +1,17 @@ +""" +Custom routers for job sourcing . +""" +# third party imports +from rest_framework.routers import DefaultRouter + + +class OptionalSlashRouter(DefaultRouter): + """ + optional slash router class + """ + def __init__(self): + """ + explicitly appending '/' in urls if '/' doesn't exists for making common url patterns . + """ + super(OptionalSlashRouter, self).__init__() + self.trailing_slash = '/?' diff --git a/zod_bank/base/search_and_filters.py b/zod_bank/base/search_and_filters.py new file mode 100644 index 0000000..52330ef --- /dev/null +++ b/zod_bank/base/search_and_filters.py @@ -0,0 +1,49 @@ +""" +This module contains search methods that can be used to search over a particular field in a specific model. +Update SEARCH_MAP dict for searching with model name and fields name +""" +# python imports +import operator +from functools import reduce + +# third party imports +from django.contrib.auth import get_user_model +from django.db.models import Q + +SEARCH_MAP = { + get_user_model(): {'search_fields': ['first_name__icontains', 'last_name__icontains', 'username__icontains']} +} + + +def search_query(search_by, search_term): + """ + :param search_by: search fields + :param search_term: search value + :return: return query + """ + query = [] + if search_by: + for key in search_by: + query.append({key: search_term}) + return query + + +def get_search_fields(model): + """ + :param model: model name + :return: dict of searching field name + """ + return SEARCH_MAP[model]['search_fields'] + + +def global_search(search_data, model_name): + """ + :param search_data: search value + :param model_name: model name + :return: query + """ + # get search fields for the above model + search_fields = get_search_fields(model_name) + # build query + query = search_query(search_fields, search_data) + return model_name.objects.filter(reduce(operator.or_, [Q(**x) for x in query])) diff --git a/zod_bank/base/upload_file.py b/zod_bank/base/upload_file.py new file mode 100644 index 0000000..14f9e02 --- /dev/null +++ b/zod_bank/base/upload_file.py @@ -0,0 +1,177 @@ +""" +This file used for file uploaded +""" +import datetime +# python imports +import logging +import mimetypes +import os + +import boto3 +from django.core.files.storage import FileSystemStorage +# django imports +from django.utils.crypto import get_random_string +from rest_framework.status import HTTP_400_BAD_REQUEST, HTTP_200_OK + +from base import constants +from base.constants import NUMBER +# local import +from resourcekit.settings import base_settings as settings +from resourcekit.settings.base_settings import BASE_DIR + + +def image_upload(folder, file_name, data): + """ + Function to upload files + :param folder:folder location string + :param file_name:file_name without ext string + :param data:data file obj + :return:Dictionary + """ + status = HTTP_400_BAD_REQUEST + img_name = None + error = None + try: + s3_client = boto3.client('s3', + aws_access_key_id=settings.AWS_ACCESS_KEY, + aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY, + region_name=settings.AWS_DEFAULT_REGION + ) + + bucket_name = settings.BUCKET_NAME + MEDIA_ROOT = os.path.join(BASE_DIR, 'media/tmp') + fss = FileSystemStorage() + file = fss.save('tmp/' + str(file_name), data) + fss.url(file) + tmp_file = os.path.join(MEDIA_ROOT, str(file_name)) + s3_client.upload_file( + tmp_file, bucket_name, folder + str(file_name), + ExtraArgs={'ACL': 'public-read', 'ContentType': data.content_type} + ) + os.unlink(tmp_file) + img_name = file_name + status = HTTP_200_OK + except Exception as e: + error = e + logging.error(e) + return status, error, img_name + + +def file_delete(folder, file_name): + """ + To delete common file + :param folder: folder name str + :param file_name: file_name string type + """ + status = HTTP_400_BAD_REQUEST + error = None + try: + s3_client = boto3.client('s3', + aws_access_key_id=settings.AWS_ACCESS_KEY, + aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY, + region_name=settings.AWS_DEFAULT_REGION + ) + + s3_client.delete_object(Bucket=settings.BUCKET_NAME, Key=str(folder) + str(file_name)) + status = HTTP_200_OK + except Exception as e: + error = e + return status, error + + +def get_aws_obj(folder, file_name): + """ + To get aws file obj + :param folder: folder string type + :param file_name: file_name string type + """ + status = HTTP_400_BAD_REQUEST + obj = None + try: + s3_client = boto3.client('s3', + aws_access_key_id=settings.AWS_ACCESS_KEY, + aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY, + region_name=settings.AWS_DEFAULT_REGION + ) + file_name = folder + file_name + obj = s3_client.get_object(Bucket=settings.BUCKET_NAME, Key=file_name) + status = HTTP_200_OK + except Exception as e: + logging.error(e) + return status, obj + + +def upload_image(post_data, folder): + """ + :param post_data: + :param folder: string type + :return: + """ + upload_obj = None + # Check Post data + if post_data: + date_now = datetime.datetime.now() + file_extension = os.path.splitext(str(post_data.name)) + file_extension = file_extension[constants.NUMBER['one']].split(".")[constants.NUMBER['one']].lower() + rand = get_random_string(NUMBER['twelve']) + image_name = str(rand) + date_now.strftime("%s") + "." + file_extension + upload_obj = image_upload(folder, image_name, post_data) + return upload_obj + + +def upload_voice_kit_image(post_data, folder, image_dir): + """ + :param post_data: + :param folder: string type + :param image_dir: image_dir + :return: + """ + upload_obj = None + # Check Post data + if post_data: + date_now = datetime.datetime.now() + file_extension = os.path.splitext(str(post_data)) + file_extension = file_extension[constants.NUMBER['one']].split(".")[constants.NUMBER['one']].lower() + rand = get_random_string(NUMBER['twelve']) + image_name = str(rand) + date_now.strftime("%s") + "." + file_extension + upload_obj = voice_kit_image_upload(folder, image_name, post_data, image_dir) + return upload_obj + + +def voice_kit_image_upload(folder, file_name, data, image_dir): + """ + Function to upload files + :param folder:folder location string + :param file_name:file_name without ext string + :param data:data file obj + :return:Dictionary + """ + status = HTTP_400_BAD_REQUEST + img_name = None + error = None + try: + s3_client = boto3.client('s3', + aws_access_key_id=settings.AWS_ACCESS_KEY, + aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY, + region_name=settings.AWS_DEFAULT_REGION + ) + + bucket_name = settings.BUCKET_NAME + MEDIA_ROOT = os.path.join(BASE_DIR, 'media/tmp') + fss = FileSystemStorage() + with open(image_dir+data, 'rb') as f: + file = fss.save('tmp/' + str(file_name), f) + fss.url(file) + tmp_file = os.path.join(MEDIA_ROOT, str(file_name)) + s3_client.upload_file( + tmp_file, bucket_name, folder + str(file_name), + ExtraArgs={'ACL': 'public-read', 'ContentType': mimetypes.guess_type(file_name)[0]} + ) + os.unlink(tmp_file) + img_name = file_name + status = HTTP_200_OK + except Exception as e: + error = e + logging.error(e) + return status, error, img_name + diff --git a/zod_bank/guardian/__init__.py b/zod_bank/guardian/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/zod_bank/guardian/admin.py b/zod_bank/guardian/admin.py new file mode 100644 index 0000000..f2c8fbc --- /dev/null +++ b/zod_bank/guardian/admin.py @@ -0,0 +1,9 @@ +from django.contrib import admin +from .models import Guardian +# Register your models here. +@admin.register(Guardian) +class GuardianAdmin(admin.ModelAdmin): + list_display = ['user', 'family_name'] + + def __str__(self): + return self.user__email \ No newline at end of file diff --git a/zod_bank/guardian/apps.py b/zod_bank/guardian/apps.py new file mode 100644 index 0000000..b69ed5d --- /dev/null +++ b/zod_bank/guardian/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class CustodianConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'guardian' diff --git a/zod_bank/guardian/migrations/0001_initial.py b/zod_bank/guardian/migrations/0001_initial.py new file mode 100644 index 0000000..0038a3b --- /dev/null +++ b/zod_bank/guardian/migrations/0001_initial.py @@ -0,0 +1,43 @@ +# Generated by Django 4.2.2 on 2023-06-23 12:05 + +from django.conf import settings +import django.contrib.postgres.fields +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Guardian', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('country_code', models.IntegerField(blank=True, null=True)), + ('phone', models.CharField(blank=True, default=None, max_length=31, null=True)), + ('family_name', models.CharField(blank=True, default=None, max_length=50, null=True)), + ('gender', models.CharField(blank=True, choices=[('1', 'Male'), ('2', 'Female')], default=None, max_length=15, null=True)), + ('dob', models.DateField(blank=True, default=None, max_length=15, null=True)), + ('guardian_code', models.CharField(blank=True, default=None, max_length=10, null=True)), + ('junior_code', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(blank=True, default=None, max_length=10, null=True), null=True, size=None)), + ('referral_code', models.CharField(blank=True, default=None, max_length=10, null=True)), + ('referral_code_used', models.CharField(blank=True, default=None, max_length=10, null=True)), + ('is_active', models.BooleanField(default=True)), + ('is_complete_profile', models.BooleanField(default=False)), + ('passcode', models.IntegerField(blank=True, default=None, null=True)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='guardian_profile', to=settings.AUTH_USER_MODEL, verbose_name='Email')), + ], + options={ + 'verbose_name': 'Guardian', + 'db_table': 'guardians', + }, + ), + ] diff --git a/zod_bank/guardian/migrations/__init__.py b/zod_bank/guardian/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/zod_bank/guardian/models.py b/zod_bank/guardian/models.py new file mode 100644 index 0000000..2819bf3 --- /dev/null +++ b/zod_bank/guardian/models.py @@ -0,0 +1,31 @@ +from django.db import models +from django.contrib.auth import get_user_model +from base.constants import GENDERS +from django.contrib.postgres.fields import ArrayField +User = get_user_model() +# Create your models here. + +class Guardian(models.Model): + user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='guardian_profile', verbose_name='Email') + country_code = models.IntegerField(blank=True, null=True) + phone = models.CharField(max_length=31, null=True, blank=True, default=None) + 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) + guardian_code = models.CharField(max_length=10, null=True, blank=True, default=None) + junior_code = ArrayField(models.CharField(max_length=10, null=True, blank=True, default=None),null=True) + 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) + is_active = models.BooleanField(default=True) + is_complete_profile = models.BooleanField(default=False) + passcode = models.IntegerField(null=True, blank=True, default=None) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + class Meta(object): + """ Meta class """ + db_table = 'guardians' + verbose_name = 'Guardian' + + def __str__(self): + return f'{self.user}' diff --git a/zod_bank/guardian/serializers.py b/zod_bank/guardian/serializers.py new file mode 100644 index 0000000..e55c766 --- /dev/null +++ b/zod_bank/guardian/serializers.py @@ -0,0 +1,91 @@ +from rest_framework import serializers +from django.contrib.auth.models import User +from .models import Guardian +from django.db import transaction +import random +from account.models import UserProfile +from junior.models import Junior +from base.constants import GENDERS, GUARDIAN, JUNIOR, SUPERUSER +from rest_framework_simplejwt.tokens import RefreshToken +from base.messages import ERROR_CODE, SUCCESS_CODE +class UserSerializer(serializers.ModelSerializer): + auth_token = serializers.SerializerMethodField('get_auth_token') + + + class Meta(object): + model = User + fields = ['email', 'password', 'auth_token'] + + def get_auth_token(self, obj): + refresh = RefreshToken.for_user(obj) + access_token = str(refresh.access_token) + return access_token + def create(self, validated_data): + email = validated_data.get('email') + user_type = self.context + password = validated_data.get('password') + try: + user = User.objects.create_user(username=email, email=email, password=password) + UserProfile.objects.create(user=user, user_type=user_type) + return user + except: + raise serializers.ValidationError({"details":ERROR_CODE['2021']}) + + def save(self, **kwargs): + with transaction.atomic(): + instance = super().save(**kwargs) + return instance + +class CreateGuardianSerializer(serializers.ModelSerializer): + first_name = serializers.SerializerMethodField('get_first_name') + last_name = serializers.SerializerMethodField('get_last_name') + email = serializers.SerializerMethodField('get_email') + phone = serializers.CharField(max_length=20, required=False) + family_name = serializers.CharField(max_length=100, required=False) + country_code = serializers.IntegerField(required=False) + dob = serializers.DateField(required=False) + referral_code = serializers.CharField(max_length=100, required=False) + + class Meta(object): + model = Guardian + fields = ['first_name', 'last_name', 'email', 'phone', 'family_name', 'gender', 'country_code', 'dob', 'referral_code', 'passcode', + 'is_complete_profile'] + + def get_first_name(self,obj): + return obj.user.first_name + + def get_last_name(self,obj): + return obj.user.last_name + + def get_email(self,obj): + return obj.user.email + + def create(self, validated_data): + user = User.objects.filter(username=self.context['user']).last() + if user: + user.first_name = self.context.get('first_name', user.first_name) + user.last_name = self.context.get('last_name', user.last_name) + user.save() + guardian, created = Guardian.objects.get_or_create(user=self.context['user']) + if created: + guardian.referral_code = ''.join([str(random.randrange(9)) for _ in range(4)]) + guardian.guardian_code = ''.join([str(random.randrange(9)) for _ in range(4)]) + if guardian: + guardian.phone = validated_data.get('phone', guardian.phone) + guardian.gender = validated_data.get('gender',guardian.gender) + guardian.family_name = validated_data.get('family_name', guardian.family_name) + guardian.dob = validated_data.get('dob',guardian.dob) + guardian.passcode = validated_data.get('passcode', guardian.passcode) + complete_profile_field = all([guardian.phone, guardian.gender, guardian.family_name, + guardian.dob, guardian.country_code, user.first_name, user.last_name]) + guardian.is_complete_profile = False + if complete_profile_field: + guardian.is_complete_profile = True + guardian.country_code = validated_data.get('country_code', guardian.country_code) + guardian.save() + return guardian + + def save(self, **kwargs): + with transaction.atomic(): + instance = super().save(**kwargs) + return instance diff --git a/zod_bank/guardian/tasks.py b/zod_bank/guardian/tasks.py new file mode 100644 index 0000000..7a5dd90 --- /dev/null +++ b/zod_bank/guardian/tasks.py @@ -0,0 +1,6 @@ +"""task files""" +"""Django import""" +import random +def generate_otp(): + """generate random otp""" + return ''.join([str(random.randrange(9)) for _ in range(6)]) diff --git a/zod_bank/guardian/tests.py b/zod_bank/guardian/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/zod_bank/guardian/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/zod_bank/guardian/urls.py b/zod_bank/guardian/urls.py new file mode 100644 index 0000000..64aa80f --- /dev/null +++ b/zod_bank/guardian/urls.py @@ -0,0 +1,17 @@ +""" Urls files""" +"""Django import""" +from django.urls import path, include +from rest_framework.decorators import api_view +from .views import SignupViewset, UpdateGuardianProfile +"""Third party import""" +from rest_framework import routers + +"""Router""" +router = routers.SimpleRouter() + +"""API End points with router""" +router.register('sign-up', SignupViewset, basename='sign-up') +router.register('update-guardian-profile', UpdateGuardianProfile, basename='update-guardian-profile') +urlpatterns = [ + path('api/v1/', include(router.urls)), +] diff --git a/zod_bank/guardian/views.py b/zod_bank/guardian/views.py new file mode 100644 index 0000000..f43e4c8 --- /dev/null +++ b/zod_bank/guardian/views.py @@ -0,0 +1,44 @@ +from django.shortcuts import render +from rest_framework import (pagination, viewsets, status, generics, mixins) +from .serializers import CreateGuardianSerializer +from rest_framework.decorators import action +from rest_framework.response import Response +from django.views.decorators.csrf import csrf_exempt +# Create your views here. +from rest_framework import viewsets, status +from rest_framework.response import Response +from .serializers import UserSerializer +from django.contrib.auth.models import User +from rest_framework.permissions import IsAuthenticated +from base.constants import GUARDIAN, JUNIOR, SUPERUSER +from junior.models import Junior +from account.models import UserEmailOtp +from .tasks import generate_otp +from account.utils import send_otp_email +from account.utils import custom_response, custom_error_response +from base.messages import ERROR_CODE, SUCCESS_CODE +class SignupViewset(viewsets.ModelViewSet): + serializer_class = UserSerializer + + def create(self, request, *args, **kwargs): + serializer = UserSerializer(context=request.data['user_type'], data=request.data) + if serializer.is_valid(): + serializer.save() + otp = generate_otp() + UserEmailOtp.objects.create(email=request.data['email'], otp=otp) + # send_otp_email(request.data['email'], otp) + return custom_response(SUCCESS_CODE['3001'], {"email_otp": otp}, + response_status=status.HTTP_200_OK) + return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST) + +class UpdateGuardianProfile(viewsets.ViewSet): + serializer_class = CreateGuardianSerializer + permission_classes = [IsAuthenticated] + + def create(self, request, *args, **kwargs): + serializer = CreateGuardianSerializer(context={"user":request.user,"first_name":request.data.get('first_name', ''), + "last_name": request.data.get('last_name',' ')}, data=request.data) + if serializer.is_valid(): + serializer.save() + return custom_response(None, serializer.data,response_status=status.HTTP_200_OK) + return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST) diff --git a/zod_bank/junior/__init__.py b/zod_bank/junior/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/zod_bank/junior/admin.py b/zod_bank/junior/admin.py new file mode 100644 index 0000000..07d6053 --- /dev/null +++ b/zod_bank/junior/admin.py @@ -0,0 +1,9 @@ +from django.contrib import admin +from .models import Junior +# Register your models here. +@admin.register(Junior) +class JuniorAdmin(admin.ModelAdmin): + list_display = ['auth'] + + def __str__(self): + return self.auth__email diff --git a/zod_bank/junior/apps.py b/zod_bank/junior/apps.py new file mode 100644 index 0000000..0232709 --- /dev/null +++ b/zod_bank/junior/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class JuniorConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'junior' diff --git a/zod_bank/junior/migrations/0001_initial.py b/zod_bank/junior/migrations/0001_initial.py new file mode 100644 index 0000000..e451c2e --- /dev/null +++ b/zod_bank/junior/migrations/0001_initial.py @@ -0,0 +1,42 @@ +# Generated by Django 4.2.2 on 2023-06-23 12:05 + +from django.conf import settings +import django.contrib.postgres.fields +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Junior', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('phone', models.CharField(blank=True, default=None, max_length=31, null=True)), + ('country_code', models.IntegerField(blank=True, null=True)), + ('gender', models.CharField(blank=True, choices=[('1', 'Male'), ('2', 'Female')], default=None, max_length=10, null=True)), + ('dob', models.DateField(blank=True, default=None, max_length=15, null=True)), + ('junior_code', models.CharField(blank=True, default=None, max_length=10, null=True)), + ('guardian_code', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(blank=True, default=None, max_length=10, null=True), null=True, size=None)), + ('referral_code', models.CharField(blank=True, default=None, max_length=10, null=True)), + ('referral_code_used', models.CharField(blank=True, default=None, max_length=10, null=True)), + ('is_active', models.BooleanField(default=True)), + ('is_complete_profile', models.BooleanField(default=False)), + ('passcode', models.IntegerField(blank=True, default=None, null=True)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('auth', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='junior_profile', to=settings.AUTH_USER_MODEL, verbose_name='Email')), + ], + options={ + 'verbose_name': 'Junior', + 'db_table': 'junior', + }, + ), + ] diff --git a/zod_bank/junior/migrations/__init__.py b/zod_bank/junior/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/zod_bank/junior/models.py b/zod_bank/junior/models.py new file mode 100644 index 0000000..43c9d74 --- /dev/null +++ b/zod_bank/junior/models.py @@ -0,0 +1,32 @@ +from django.db import models +from django.contrib.auth import get_user_model +from base.constants import GENDERS +from guardian.models import Guardian +from django.contrib.postgres.fields import ArrayField +User = get_user_model() +# Create your models here. + +class Junior(models.Model): + auth = models.ForeignKey(User, on_delete=models.CASCADE, related_name='junior_profile', verbose_name='Email') + phone = models.CharField(max_length=31, null=True, blank=True, default=None) + country_code = models.IntegerField(blank=True, null=True) + 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/') + 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) + 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) + is_active = models.BooleanField(default=True) + is_complete_profile = models.BooleanField(default=False) + passcode = models.IntegerField(null=True, blank=True, default=None) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + class Meta(object): + """ Meta class """ + db_table = 'junior' + verbose_name = 'Junior' + + def __str__(self): + return f'{self.auth}' diff --git a/zod_bank/junior/serializers.py b/zod_bank/junior/serializers.py new file mode 100644 index 0000000..3e493e7 --- /dev/null +++ b/zod_bank/junior/serializers.py @@ -0,0 +1,73 @@ +from rest_framework import serializers +from django.contrib.auth.models import User +from .models import Guardian +from django.db import transaction +import random +from account.models import UserProfile +from junior.models import Junior +from base.constants import GENDERS, GUARDIAN, JUNIOR, SUPERUSER +from rest_framework_simplejwt.tokens import RefreshToken +from base.messages import ERROR_CODE, SUCCESS_CODE +from django.contrib.postgres.fields import ArrayField + +class ListCharField(serializers.ListField): + child = serializers.CharField() + + def to_representation(self, data): + return data + + def to_internal_value(self, data): + if isinstance(data, list): + return data + raise serializers.ValidationError({"details":"Invalid input. Expected a list of strings."}) + + +class CreateJuniorSerializer(serializers.ModelSerializer): + first_name = serializers.SerializerMethodField('get_first_name') + last_name = serializers.SerializerMethodField('get_last_name') + email = serializers.SerializerMethodField('get_email') + phone = serializers.CharField(max_length=20, required=False) + country_code = serializers.IntegerField(required=False) + dob = serializers.DateField(required=False) + referral_code = serializers.CharField(max_length=100, required=False) + guardian_code = ListCharField(required=False) + + class Meta(object): + model = Junior + fields = ['first_name', 'last_name', 'email', 'phone', 'gender', 'country_code', 'dob', 'referral_code', + 'passcode', 'is_complete_profile', 'guardian_code'] + + def get_first_name(self,obj): + return obj.auth.first_name + + def get_last_name(self,obj): + return obj.auth.last_name + + def get_email(self,obj): + return obj.auth.email + + def create(self, validated_data): + user = User.objects.filter(username=self.context['user']).last() + if user: + user.first_name = self.context.get('first_name', user.first_name) + user.last_name = self.context.get('last_name', user.last_name) + user.save() + junior, created = Junior.objects.get_or_create(auth=self.context['user']) + if created: + junior.referral_code = ''.join([str(random.randrange(9)) for _ in range(4)]) + junior.junior_code = ''.join([str(random.randrange(9)) for _ in range(4)]) + if junior: + junior.phone = validated_data.get('phone', junior.phone) + junior.gender = validated_data.get('gender',junior.gender) + junior.guardian_code = validated_data.get('guardian_code', junior.guardian_code) + junior.dob = validated_data.get('dob',junior.dob) + junior.passcode = validated_data.get('passcode', junior.passcode) + junior.is_complete_profile = validated_data.get('is_complete_profile', junior.is_complete_profile) + junior.country_code = validated_data.get('country_code', junior.country_code) + junior.save() + return junior + + def save(self, **kwargs): + with transaction.atomic(): + instance = super().save(**kwargs) + return instance diff --git a/zod_bank/junior/tests.py b/zod_bank/junior/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/zod_bank/junior/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/zod_bank/junior/urls.py b/zod_bank/junior/urls.py new file mode 100644 index 0000000..cce385d --- /dev/null +++ b/zod_bank/junior/urls.py @@ -0,0 +1,17 @@ +""" Urls files""" +"""Django import""" +from django.urls import path, include +from rest_framework.decorators import api_view +from .views import UpdateJuniorProfile, ValidateGuardianCode +"""Third party import""" +from rest_framework import routers + +"""Router""" +router = routers.SimpleRouter() + +"""API End points with router""" +router.register('profile-update', UpdateJuniorProfile, basename='profile-update') +router.register('validate-guardian-code', ValidateGuardianCode, basename='validate-guardian-code') +urlpatterns = [ + path('api/v1/', include(router.urls)), +] diff --git a/zod_bank/junior/views.py b/zod_bank/junior/views.py new file mode 100644 index 0000000..4eb3a35 --- /dev/null +++ b/zod_bank/junior/views.py @@ -0,0 +1,40 @@ +from django.shortcuts import render +from rest_framework import (pagination, viewsets, status, generics, mixins) +from rest_framework.decorators import action +from rest_framework.response import Response +from django.views.decorators.csrf import csrf_exempt +# Create your views here. +from rest_framework import viewsets, status +from rest_framework.response import Response +from .serializers import CreateJuniorSerializer +from django.contrib.auth.models import User +from rest_framework.permissions import IsAuthenticated +from base.constants import GUARDIAN, JUNIOR, SUPERUSER +from junior.models import Junior +from guardian.models import Guardian +from base.messages import ERROR_CODE, SUCCESS_CODE +from account.utils import custom_response, custom_error_response + +class UpdateJuniorProfile(viewsets.ViewSet): + serializer_class = CreateJuniorSerializer + permission_classes = [IsAuthenticated] + + def create(self, request, *args, **kwargs): + serializer = CreateJuniorSerializer(context={"user":request.user,"first_name":request.data.get('first_name', ''), + "last_name": request.data.get('last_name',' ')}, data=request.data) + if serializer.is_valid(): + serializer.save() + return custom_response(None, serializer.data, response_status=status.HTTP_200_OK) + return custom_error_response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + +class ValidateGuardianCode(viewsets.ViewSet): + permission_classes = [IsAuthenticated] + + def list(self, request, *args, **kwargs): + guardian_code = request.data.get('guardian_code') + for code in guardian_code: + guardian_data = Guardian.objects.filter(guardian_code=code).exists() + if guardian_data: + return custom_response(SUCCESS_CODE['3028'], response_status=status.HTTP_200_OK) + else: + return custom_error_response(ERROR_CODE["2022"], response_status=status.HTTP_400_BAD_REQUEST) diff --git a/zod_bank/manage.py b/zod_bank/manage.py new file mode 100755 index 0000000..169c7c2 --- /dev/null +++ b/zod_bank/manage.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'zod_bank.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/zod_bank/nginx/django.conf b/zod_bank/nginx/django.conf new file mode 100644 index 0000000..488e2c0 --- /dev/null +++ b/zod_bank/nginx/django.conf @@ -0,0 +1,24 @@ +upstream web { + ip_hash; + server web:8000; + } + + # portal + server { + location / { + proxy_pass http://web/; + proxy_set_header Host $http_host; + } + listen 8000; + client_max_body_size 512M; + server_name localhost; + proxy_read_timeout 900; + proxy_connect_timeout 900; + proxy_send_timeout 900; + #proxy_set_header Host $http_host; + + location /static { + autoindex on; + alias /usr/src/app/zod_bank/static/; + } + } diff --git a/zod_bank/requirements.txt b/zod_bank/requirements.txt new file mode 100644 index 0000000..e78af44 --- /dev/null +++ b/zod_bank/requirements.txt @@ -0,0 +1,55 @@ +aliyun-python-sdk-core==2.13.36 +aliyun-python-sdk-dysmsapi==2.1.2 +amqp==5.1.1 +asgiref==3.7.2 +async-timeout==4.0.2 +billiard==4.1.0 +boto3==1.26.157 +botocore==1.29.157 +celery==5.3.1 +cffi==1.15.1 +channels==4.0.0 +channels-redis==4.1.0 +click==8.1.3 +click-didyoumean==0.3.0 +click-plugins==1.1.1 +click-repl==0.3.0 +cron-descriptor==1.4.0 +cryptography==41.0.1 +decouple==0.0.7 +Django==4.2.2 +django-celery-beat==2.5.0 +django-celery-results==2.5.1 +django-cors-headers==4.1.0 +django-dotenv==1.4.2 +django-extensions==3.2.3 +django-ses==3.5.0 +django-storages==1.13.2 +django-timezone-field==5.1 +djangorestframework==3.14.0 +djangorestframework-simplejwt==5.2.2 +drf-yasg==1.21.6 +inflection==0.5.1 +jmespath==0.10.0 +kombu==5.3.1 +msgpack==1.0.5 +packaging==23.1 +prompt-toolkit==3.0.38 +psycopg==3.1.9 +pycparser==2.21 +PyJWT==2.7.0 +python-crontab==2.7.1 +python-dateutil==2.8.2 +python-dotenv==1.0.0 +pytz==2023.3 +PyYAML==6.0 +redis==4.5.5 +s3transfer==0.6.1 +six==1.16.0 +sqlparse==0.4.4 +typing_extensions==4.6.3 +tzdata==2023.3 +uritemplate==4.1.1 +urllib3==1.26.16 +vine==5.0.0 +wcwidth==0.2.6 diff --git a/zod_bank/zod_bank/__init__.py b/zod_bank/zod_bank/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/zod_bank/zod_bank/asgi.py b/zod_bank/zod_bank/asgi.py new file mode 100644 index 0000000..967882b --- /dev/null +++ b/zod_bank/zod_bank/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for ZOD_Bank project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/3.0/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'zod_bank.settings') + +application = get_asgi_application() diff --git a/zod_bank/zod_bank/settings.py b/zod_bank/zod_bank/settings.py new file mode 100644 index 0000000..0c8da76 --- /dev/null +++ b/zod_bank/zod_bank/settings.py @@ -0,0 +1,176 @@ +""" +Django settings for ZOD_Bank project. + +Generated by 'django-admin startproject' using Django 3.0.14. + +For more information on this file, see +https://docs.djangoproject.com/en/3.0/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/3.0/ref/settings/ +""" + +import os +from dotenv import load_dotenv +from datetime import timedelta +load_dotenv() +# OR, the same with increased verbosity: +load_dotenv(verbose=True) +env_path = os.path.join(os.path.abspath(os.path.join('.env', os.pardir)), '.env') +load_dotenv(dotenv_path=env_path) + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +# OR, the same with increased verbosity: +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = '-pb+8w#)6qsh+w&tr+q$tholf7=54v%05e^9!lneiqqgtddg6q' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = ['*'] + + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'django_extensions', + 'storages', + 'drf_yasg', + 'corsheaders', + 'django.contrib.postgres', + 'rest_framework', + 'django_ses', + 'account', + 'junior', + 'guardian', +] +# CSRF_COOKIE_SECURE = False +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'zod_bank.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'zod_bank.wsgi.application' +REST_FRAMEWORK = { + 'DEFAULT_AUTHENTICATION_CLASSES': [ + # 'rest_framework.authentication.SessionAuthentication', + 'rest_framework.authentication.BasicAuthentication', + 'rest_framework_simplejwt.authentication.JWTAuthentication', +] +} +SIMPLE_JWT = { + 'ACCESS_TOKEN_LIFETIME': timedelta(minutes=15), + 'REFRESH_TOKEN_LIFETIME': timedelta(days=7), +} +# Database +# https://docs.djangoproject.com/en/3.0/ref/settings/#databases +DATABASES = { + 'default': { + 'ENGINE': 'django.contrib.gis.db.backends.postgis', + 'NAME':os.getenv('DB_NAME'), + 'USER':os.getenv('DB_USERNAME'), + 'PASSWORD':os.getenv('DB_PASSWORD'), + 'HOST':os.getenv('DB_HOST'), + 'PORT':os.getenv('DB_PORT'), + } +} +# Password validation +# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/3.0/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + +# cors header settings +SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') + +CORS_ORIGIN_ALLOW_ALL = True + +CORS_ALLOW_METHODS = ( + 'DELETE', + 'GET', + 'OPTIONS', + 'PATCH', + 'POST', + 'PUT', +) + +CORS_ALLOW_HEADERS = ( + 'accept', + 'accept-encoding', + 'authorization', + 'content-type', + 'dnt', + 'origin', + 'account-agent', + 'x-csrftoken', + 'x-requested-with', +) + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/3.0/howto/static-files/ + + + +STATIC_URL = '/static/' diff --git a/zod_bank/zod_bank/urls.py b/zod_bank/zod_bank/urls.py new file mode 100644 index 0000000..274451e --- /dev/null +++ b/zod_bank/zod_bank/urls.py @@ -0,0 +1,33 @@ +"""ZOD_Bank URL Configuration + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/3.0/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +# third-party import +from django.conf.urls.static import static +from django.contrib import admin +from django.urls import path, include +from drf_yasg import openapi +from drf_yasg.views import get_schema_view +from django.urls import path + + +schema_view = get_schema_view(openapi.Info(title="Zod Bank API", default_version='v1'), public=True, ) + +urlpatterns = [ + path('apidoc/', schema_view.with_ui('swagger', cache_timeout=None), name='schema-swagger-ui'), + path('admin/', admin.site.urls), + path('', include(('account.urls', 'account'), namespace='account')), + path('', include('guardian.urls')), + path('', include(('junior.urls', 'junior'), namespace='junior')), +] diff --git a/zod_bank/zod_bank/wsgi.py b/zod_bank/zod_bank/wsgi.py new file mode 100644 index 0000000..e6b5c4f --- /dev/null +++ b/zod_bank/zod_bank/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for ZOD_Bank project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/3.0/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'zod_bank.settings') + +application = get_wsgi_application() From 89982f851f2932c4c95b000e8d7ed93e8f2d4f34 Mon Sep 17 00:00:00 2001 From: jain Date: Sat, 24 Jun 2023 18:17:32 +0530 Subject: [PATCH 03/19] forgot password and email verification --- zod_bank/account/serializers.py | 32 +++++++++++ .../templated_email/email_base.email | 54 +++++++++++++++++++ .../email_otp_verification.email | 23 ++++++++ .../email_reset_verification.email | 23 ++++++++ zod_bank/account/urls.py | 6 ++- zod_bank/account/utils.py | 15 ++++-- zod_bank/account/views.py | 50 +++++++++++++++-- zod_bank/base/messages.py | 5 +- zod_bank/guardian/views.py | 3 +- zod_bank/zod_bank/settings.py | 26 +++++++++ 10 files changed, 226 insertions(+), 11 deletions(-) create mode 100644 zod_bank/account/templates/templated_email/email_base.email create mode 100644 zod_bank/account/templates/templated_email/email_otp_verification.email create mode 100644 zod_bank/account/templates/templated_email/email_reset_verification.email diff --git a/zod_bank/account/serializers.py b/zod_bank/account/serializers.py index 03b1012..f70f084 100644 --- a/zod_bank/account/serializers.py +++ b/zod_bank/account/serializers.py @@ -13,6 +13,38 @@ from rest_framework.decorators import action from django.contrib.auth import authenticate, login from rest_framework_simplejwt.tokens import RefreshToken +class ResetPasswordSerializer(serializers.Serializer): + """Reset Password after verification""" + verification_code = serializers.CharField(max_length=10) + password = serializers.CharField(required=True) + class Meta(object): + """Meta info""" + model = User + + 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} + return user_opt_details + + + + +class ForgotPasswordSerializer(serializers.Serializer): + """Forget password serializer""" + email = serializers.EmailField() + class SuperUserSerializer(serializers.ModelSerializer): user_type = serializers.SerializerMethodField('get_user_type') diff --git a/zod_bank/account/templates/templated_email/email_base.email b/zod_bank/account/templates/templated_email/email_base.email new file mode 100644 index 0000000..5721e28 --- /dev/null +++ b/zod_bank/account/templates/templated_email/email_base.email @@ -0,0 +1,54 @@ + +{% block subject %}DinDin{% endblock %} +{% load static %} + +{% block html %} + + + + + Zod Bank | OTP + + + + + + + + + + +
+ + + + + {% block plain %} + {% endblock %} + + + +
+
+

-

+

Cheers!

+

Zod Bank Team

+
+
+ + + +{% endblock %} diff --git a/zod_bank/account/templates/templated_email/email_otp_verification.email b/zod_bank/account/templates/templated_email/email_otp_verification.email new file mode 100644 index 0000000..8b3c693 --- /dev/null +++ b/zod_bank/account/templates/templated_email/email_otp_verification.email @@ -0,0 +1,23 @@ +{% extends "templated_email/email_base.email" %} + +{% block subject %} + OTP Verification +{% endblock %} + +{% block plain %} + + +

+ Hi User, +

+ + + + +

+ You are receiving this email for email verification. Please use {{ otp }} as the verification code for your email address & username. + +

+ + +{% endblock %} diff --git a/zod_bank/account/templates/templated_email/email_reset_verification.email b/zod_bank/account/templates/templated_email/email_reset_verification.email new file mode 100644 index 0000000..0138d99 --- /dev/null +++ b/zod_bank/account/templates/templated_email/email_reset_verification.email @@ -0,0 +1,23 @@ +{% extends "templated_email/email_base.email" %} + +{% block subject %} + Reset Password Verification +{% endblock %} + +{% block plain %} + + +

+ Hi User, +

+ + + + +

+ You are receiving this email for reset password verification. Please use {{ verification_code }} as the verification code. + +

+ + +{% endblock %} diff --git a/zod_bank/account/urls.py b/zod_bank/account/urls.py index 1350cea..0b3ddb5 100644 --- a/zod_bank/account/urls.py +++ b/zod_bank/account/urls.py @@ -4,7 +4,8 @@ from django.urls import path, include from rest_framework.decorators import api_view """Third party import""" from rest_framework import routers -from .views import UserLogin, SendPhoneOtp, UserPhoneVerification, UserEmailVerification, ReSendEmailOtp +from .views import (UserLogin, SendPhoneOtp, UserPhoneVerification, UserEmailVerification, ReSendEmailOtp, + ForgotPasswordAPIView, ResetPasswordAPIView) """Router""" router = routers.SimpleRouter() @@ -15,6 +16,9 @@ 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()) ] diff --git a/zod_bank/account/utils.py b/zod_bank/account/utils.py index c6ffe7f..2d86106 100644 --- a/zod_bank/account/utils.py +++ b/zod_bank/account/utils.py @@ -3,12 +3,19 @@ from django.conf import settings import random from rest_framework import viewsets, status from rest_framework.response import Response + +from templated_email import send_templated_mail def send_otp_email(recipient_email, otp): - subject = 'One-Time Password' - message = f'Your OTP is: {otp}' - from_email = settings.DEFAULT_FROM_EMAIL + from_email = settings.EMAIL_HOST_USER recipient_list = [recipient_email] - send_mail(subject, message, from_email, recipient_list) + send_templated_mail( + template_name='email_otp_verification.email', + from_email=from_email, + recipient_list=recipient_list, + context={ + 'otp': otp + } + ) return otp def custom_response(detail, data=None, response_status=status.HTTP_200_OK): diff --git a/zod_bank/account/views.py b/zod_bank/account/views.py index 352b834..321b200 100644 --- a/zod_bank/account/views.py +++ b/zod_bank/account/views.py @@ -1,12 +1,13 @@ -from rest_framework import viewsets, status +from rest_framework import viewsets, status, views from rest_framework.decorators import action -from rest_framework.response import Response +import random from django.contrib.auth import authenticate, login from guardian.models import Guardian from junior.models import Junior from account.models import UserProfile, UserPhoneOtp, UserEmailOtp from django.contrib.auth.models import User -from .serializers import SuperUserSerializer, GuardianSerializer, JuniorSerializer, EmailVerificationSerializer +from .serializers import (SuperUserSerializer, GuardianSerializer, JuniorSerializer, EmailVerificationSerializer, + ForgotPasswordSerializer, ResetPasswordSerializer) from django.views.decorators.csrf import csrf_exempt from rest_framework_simplejwt.serializers import TokenObtainPairSerializer from rest_framework_simplejwt.views import TokenObtainPairView @@ -15,6 +16,49 @@ from base.messages import ERROR_CODE, SUCCESS_CODE from guardian.tasks import generate_otp from account.utils import custom_response, custom_error_response +from django.core.mail import EmailMessage +from django.core.mail import send_mail +from rest_framework.response import Response +from templated_email import send_templated_mail +import secrets + +class ResetPasswordAPIView(views.APIView): + def post(self, request): + print("request.data====>",request.data) + serializer = ResetPasswordSerializer(data=request.data) + if serializer.is_valid(): + serializer.save() + return custom_response(SUCCESS_CODE['3006'], response_status=status.HTTP_200_OK) + return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST) + +class ForgotPasswordAPIView(views.APIView): + def post(self, request): + serializer = ForgotPasswordSerializer(data=request.data) + if serializer.is_valid(): + email = serializer.validated_data['email'] + try: + User.objects.get(email=email) + except User.DoesNotExist: + return custom_error_response(ERROR_CODE['2004'], response_status=status.HTTP_404_NOT_FOUND) + verification_code = ''.join([str(random.randrange(9)) for _ in range(6)]) + # Send the verification code to the user's email + subject = 'Password Reset Verification Code' + message = f'Your verification code is: {verification_code}' + from_email = 'infozodbank@gmail.com' + recipient_list = [email] + send_templated_mail( + template_name='email_reset_verification.email', + from_email=from_email, + recipient_list=recipient_list, + context={ + 'verification_code': verification_code + } + ) + UserEmailOtp.objects.create(email=email, otp=verification_code) + return custom_response(SUCCESS_CODE['3015'], {'verification_code': verification_code}, + response_status=status.HTTP_200_OK) + return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST) + class SendPhoneOtp(viewsets.ModelViewSet): """Send otp on phone""" def create(self, request, *args, **kwargs): diff --git a/zod_bank/base/messages.py b/zod_bank/base/messages.py index 718d6be..953d761 100644 --- a/zod_bank/base/messages.py +++ b/zod_bank/base/messages.py @@ -27,7 +27,7 @@ ERROR_CODE = { "2001": "Your account has not been verified. Please check your email and verify it.", "2002": "Invalid login credentials.", "2003": "An account already exists with this email address.", - "2004": "User doesn't exist.", + "2004": "User not found.", "2005": "Your account has been activated.", "2006": "Your account is not activated.", "2007": "Your account already activated.", @@ -73,7 +73,8 @@ SUCCESS_CODE = { "3011": "Email OTP Verified successfully", "3012": "Phone OTP Verified successfully", "3013": "Valid Guardian code", - "3014": "Password has been updated successfully." + "3014": "Password has been updated successfully.", + "3015": "Verification code sent on your email." } STATUS_CODE_ERROR = { diff --git a/zod_bank/guardian/views.py b/zod_bank/guardian/views.py index f43e4c8..2b40702 100644 --- a/zod_bank/guardian/views.py +++ b/zod_bank/guardian/views.py @@ -17,6 +17,7 @@ from .tasks import generate_otp from account.utils import send_otp_email from account.utils import custom_response, custom_error_response from base.messages import ERROR_CODE, SUCCESS_CODE + class SignupViewset(viewsets.ModelViewSet): serializer_class = UserSerializer @@ -26,7 +27,7 @@ class SignupViewset(viewsets.ModelViewSet): serializer.save() otp = generate_otp() UserEmailOtp.objects.create(email=request.data['email'], otp=otp) - # send_otp_email(request.data['email'], otp) + send_otp_email(request.data['email'], otp) return custom_response(SUCCESS_CODE['3001'], {"email_otp": otp}, response_status=status.HTTP_200_OK) return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST) diff --git a/zod_bank/zod_bank/settings.py b/zod_bank/zod_bank/settings.py index 0c8da76..9e47b30 100644 --- a/zod_bank/zod_bank/settings.py +++ b/zod_bank/zod_bank/settings.py @@ -171,6 +171,32 @@ CORS_ALLOW_HEADERS = ( # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/3.0/howto/static-files/ +# +# MAIL_MAILER='smtp' +# MAIL_HOST='smtp.gmail.com' +# MAIL_PORT=587 +# mail_username='infozodbank@gmail.com' +# MAIL_PASSWORD='ghwdmznwwslvchga' +# MAIL_ENCRYPTION='tls' +# mail_from_address='infozodbank@gmail.com' +# MAIL_FROM_NAME="${APP_NAME}" + +# MAIL_MAILER='smtp' +# MAIL_HOST='smtp.gmail.com' +# MAIL_PORT=587 +# mail_username='ankita.jain@kiwitech.com' +# MAIL_PASSWORD='jaijain0912@' +# MAIL_ENCRYPTION='tls' +# mail_from_address='infozodbank@gmail.com' +# MAIL_FROM_NAME="${APP_NAME}" + +# 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' +EMAIL_HOST_PASSWORD = 'ghwdmznwwslvchga' # Replace with your Gmail email password or App password STATIC_URL = '/static/' From 9db620d8186985344cfeda40bac4a6ffaa681d22 Mon Sep 17 00:00:00 2001 From: jain Date: Mon, 26 Jun 2023 10:38:49 +0530 Subject: [PATCH 04/19] forgot, reset and change password --- zod_bank/account/serializers.py | 28 ++++++++++++++++++- .../email_reset_verification.email | 2 +- zod_bank/account/urls.py | 5 ++-- zod_bank/account/views.py | 23 +++++++++++---- zod_bank/base/messages.py | 2 +- zod_bank/guardian/urls.py | 2 +- zod_bank/junior/urls.py | 2 +- 7 files changed, 51 insertions(+), 13 deletions(-) diff --git a/zod_bank/account/serializers.py b/zod_bank/account/serializers.py index f70f084..94c774f 100644 --- a/zod_bank/account/serializers.py +++ b/zod_bank/account/serializers.py @@ -36,8 +36,34 @@ class ResetPasswordSerializer(serializers.Serializer): user_details.set_password(password) user_details.save() return {'password':password} - return user_opt_details + return user_opt_details + return '' +class ChangePasswordSerializer(serializers.Serializer): + """Update Password after verification""" + current_password = serializers.CharField(max_length=100) + new_password = serializers.CharField(required=True) + class Meta(object): + """Meta info""" + model = User + + def validate_current_password(self, value): + user = self.context + if self.context.password not in ('', None): + if user.check_password(value): + return value + raise serializers.ValidationError({"error":"Invalid Current password"}) + def create(self, validated_data): + new_password = validated_data.pop('new_password') + 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} + return user_details + return '' diff --git a/zod_bank/account/templates/templated_email/email_reset_verification.email b/zod_bank/account/templates/templated_email/email_reset_verification.email index 0138d99..e2f8ebf 100644 --- a/zod_bank/account/templates/templated_email/email_reset_verification.email +++ b/zod_bank/account/templates/templated_email/email_reset_verification.email @@ -1,7 +1,7 @@ {% extends "templated_email/email_base.email" %} {% block subject %} - Reset Password Verification + Password Reset Verification Code {% endblock %} {% block plain %} diff --git a/zod_bank/account/urls.py b/zod_bank/account/urls.py index 0b3ddb5..3c1fc2c 100644 --- a/zod_bank/account/urls.py +++ b/zod_bank/account/urls.py @@ -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) + ForgotPasswordAPIView, ResetPasswordAPIView, ChangePasswordAPIView) """Router""" router = routers.SimpleRouter() @@ -20,5 +20,6 @@ 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/reset-password/', ResetPasswordAPIView.as_view()), + path('api/v1/change-password/', ChangePasswordAPIView.as_view()) ] diff --git a/zod_bank/account/views.py b/zod_bank/account/views.py index 321b200..82039b9 100644 --- a/zod_bank/account/views.py +++ b/zod_bank/account/views.py @@ -7,21 +7,34 @@ from junior.models import Junior from account.models import UserProfile, UserPhoneOtp, UserEmailOtp from django.contrib.auth.models import User from .serializers import (SuperUserSerializer, GuardianSerializer, JuniorSerializer, EmailVerificationSerializer, - ForgotPasswordSerializer, ResetPasswordSerializer) + ForgotPasswordSerializer, ResetPasswordSerializer, ChangePasswordSerializer) from django.views.decorators.csrf import csrf_exempt from rest_framework_simplejwt.serializers import TokenObtainPairSerializer from rest_framework_simplejwt.views import TokenObtainPairView from rest_framework_simplejwt.tokens import RefreshToken from base.messages import ERROR_CODE, SUCCESS_CODE from guardian.tasks import generate_otp - +from django.conf import settings from account.utils import custom_response, custom_error_response from django.core.mail import EmailMessage from django.core.mail import send_mail from rest_framework.response import Response +from rest_framework.permissions import IsAuthenticated from templated_email import send_templated_mail import secrets + +class ChangePasswordAPIView(views.APIView): + permission_classes = [IsAuthenticated] + def post(self, request): + print("request.data====>",request.data) + print("request.user====>", request.user) + serializer = ChangePasswordSerializer(context=request.user, data=request.data) + if serializer.is_valid(): + serializer.save() + return custom_response(SUCCESS_CODE['3006'], response_status=status.HTTP_200_OK) + return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST) + class ResetPasswordAPIView(views.APIView): def post(self, request): print("request.data====>",request.data) @@ -42,9 +55,7 @@ class ForgotPasswordAPIView(views.APIView): return custom_error_response(ERROR_CODE['2004'], response_status=status.HTTP_404_NOT_FOUND) verification_code = ''.join([str(random.randrange(9)) for _ in range(6)]) # Send the verification code to the user's email - subject = 'Password Reset Verification Code' - message = f'Your verification code is: {verification_code}' - from_email = 'infozodbank@gmail.com' + from_email = settings.EMAIL_HOST_USER recipient_list = [email] send_templated_mail( template_name='email_reset_verification.email', @@ -102,7 +113,7 @@ class UserLogin(viewsets.ViewSet): serializer = JuniorSerializer(junior_data) if user.is_superuser: serializer = SuperUserSerializer(user) - return custom_response(None, serializer.data, response_status=status.HTTP_200_OK) + return custom_response(SUCCESS_CODE['3003'], serializer.data, response_status=status.HTTP_200_OK) else: return custom_error_response(ERROR_CODE["2002"], response_status=status.HTTP_401_UNAUTHORIZED) except Exception as e: diff --git a/zod_bank/base/messages.py b/zod_bank/base/messages.py index 953d761..39f0282 100644 --- a/zod_bank/base/messages.py +++ b/zod_bank/base/messages.py @@ -55,7 +55,7 @@ SUCCESS_CODE = { # Success code for Thank you "3002": "Thank you for contacting us! Our Consumer Experience Team will reach out to you shortly.", # Success code for account activation - "3003": "Your account has been activated.", + "3003": "Log in successfully", # Success code for password reset "3004": "Password reset link has been sent to your email address", # Success code for link verified diff --git a/zod_bank/guardian/urls.py b/zod_bank/guardian/urls.py index 64aa80f..0e3f898 100644 --- a/zod_bank/guardian/urls.py +++ b/zod_bank/guardian/urls.py @@ -11,7 +11,7 @@ router = routers.SimpleRouter() """API End points with router""" router.register('sign-up', SignupViewset, basename='sign-up') -router.register('update-guardian-profile', UpdateGuardianProfile, basename='update-guardian-profile') +router.register('complete-guardian-profile', UpdateGuardianProfile, basename='update-guardian-profile') urlpatterns = [ path('api/v1/', include(router.urls)), ] diff --git a/zod_bank/junior/urls.py b/zod_bank/junior/urls.py index cce385d..27a312e 100644 --- a/zod_bank/junior/urls.py +++ b/zod_bank/junior/urls.py @@ -10,7 +10,7 @@ from rest_framework import routers router = routers.SimpleRouter() """API End points with router""" -router.register('profile-update', UpdateJuniorProfile, basename='profile-update') +router.register('complete-junior-profile', UpdateJuniorProfile, basename='profile-update') router.register('validate-guardian-code', ValidateGuardianCode, basename='validate-guardian-code') urlpatterns = [ path('api/v1/', include(router.urls)), From 9bd31f9e864fdeffb917ae678027cf629c1d01a8 Mon Sep 17 00:00:00 2001 From: jain Date: Mon, 26 Jun 2023 16:44:32 +0530 Subject: [PATCH 05/19] jira-9 changes in phone verification --- zod_bank/account/serializers.py | 2 +- zod_bank/account/urls.py | 2 +- zod_bank/account/views.py | 34 ++++++++++++-------- zod_bank/base/constants.py | 50 +---------------------------- zod_bank/base/custom_exceptions.py | 16 --------- zod_bank/base/search_and_filters.py | 49 ---------------------------- zod_bank/base/upload_file.py | 4 +-- zod_bank/guardian/models.py | 1 - zod_bank/guardian/urls.py | 2 +- zod_bank/junior/urls.py | 2 +- zod_bank/junior/views.py | 2 +- zod_bank/requirements.txt | 5 +++ 12 files changed, 33 insertions(+), 136 deletions(-) delete mode 100644 zod_bank/base/custom_exceptions.py delete mode 100644 zod_bank/base/search_and_filters.py diff --git a/zod_bank/account/serializers.py b/zod_bank/account/serializers.py index 94c774f..2f18213 100644 --- a/zod_bank/account/serializers.py +++ b/zod_bank/account/serializers.py @@ -13,6 +13,7 @@ from rest_framework.decorators import action from django.contrib.auth import authenticate, login from rest_framework_simplejwt.tokens import RefreshToken + class ResetPasswordSerializer(serializers.Serializer): """Reset Password after verification""" verification_code = serializers.CharField(max_length=10) @@ -62,7 +63,6 @@ class ChangePasswordSerializer(serializers.Serializer): user_details.set_password(new_password) user_details.save() return {'password':new_password} - return user_details return '' diff --git a/zod_bank/account/urls.py b/zod_bank/account/urls.py index 3c1fc2c..0df4826 100644 --- a/zod_bank/account/urls.py +++ b/zod_bank/account/urls.py @@ -11,7 +11,7 @@ router = routers.SimpleRouter() """API End points with router""" router.register('user', UserLogin, basename='user') -router.register('superuser', UserLogin, basename='superuser') +router.register('admin', UserLogin, basename='admin') 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') diff --git a/zod_bank/account/views.py b/zod_bank/account/views.py index 82039b9..e3a9550 100644 --- a/zod_bank/account/views.py +++ b/zod_bank/account/views.py @@ -9,8 +9,6 @@ from django.contrib.auth.models import User from .serializers import (SuperUserSerializer, GuardianSerializer, JuniorSerializer, EmailVerificationSerializer, ForgotPasswordSerializer, ResetPasswordSerializer, ChangePasswordSerializer) from django.views.decorators.csrf import csrf_exempt -from rest_framework_simplejwt.serializers import TokenObtainPairSerializer -from rest_framework_simplejwt.views import TokenObtainPairView from rest_framework_simplejwt.tokens import RefreshToken from base.messages import ERROR_CODE, SUCCESS_CODE from guardian.tasks import generate_otp @@ -21,14 +19,11 @@ from django.core.mail import send_mail from rest_framework.response import Response from rest_framework.permissions import IsAuthenticated from templated_email import send_templated_mail -import secrets class ChangePasswordAPIView(views.APIView): permission_classes = [IsAuthenticated] def post(self, request): - print("request.data====>",request.data) - print("request.user====>", request.user) serializer = ChangePasswordSerializer(context=request.user, data=request.data) if serializer.is_valid(): serializer.save() @@ -37,7 +32,6 @@ class ChangePasswordAPIView(views.APIView): class ResetPasswordAPIView(views.APIView): def post(self, request): - print("request.data====>",request.data) serializer = ResetPasswordSerializer(data=request.data) if serializer.is_valid(): serializer.save() @@ -65,7 +59,10 @@ class ForgotPasswordAPIView(views.APIView): 'verification_code': verification_code } ) - UserEmailOtp.objects.create(email=email, otp=verification_code) + user_data = UserEmailOtp.objects.get_or_create(email=email) + if user_data: + user_data.otp = verification_code + user_data.save() return custom_response(SUCCESS_CODE['3015'], {'verification_code': verification_code}, response_status=status.HTTP_200_OK) return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST) @@ -74,9 +71,15 @@ class SendPhoneOtp(viewsets.ModelViewSet): """Send otp on phone""" def create(self, request, *args, **kwargs): otp = generate_otp() - UserPhoneOtp.objects.create(country_code=self.request.data['country_code'], - phone=self.request.data['phone'], otp=otp) - return custom_response(None, {'phone_otp':otp}, response_status=status.HTTP_200_OK) + phone_number = self.request.data['phone'] + if phone_number.isdigit() and len(phone_number) == 10: + phone_otp, created = UserPhoneOtp.objects.get_or_create(country_code=self.request.data['country_code'], + phone=self.request.data['phone']) + if phone_otp: + phone_otp.otp = otp + phone_otp.save() + return custom_response(None, {'phone_otp':otp}, response_status=status.HTTP_200_OK) + return custom_error_response(ERROR_CODE['2020'], response_status=status.HTTP_400_BAD_REQUEST) class UserPhoneVerification(viewsets.ModelViewSet): @@ -88,7 +91,7 @@ class UserPhoneVerification(viewsets.ModelViewSet): if phone_data: phone_data.is_verified = True phone_data.save() - return custom_response(SUCCESS_CODE['3027'], response_status=status.HTTP_200_OK) + return custom_response(SUCCESS_CODE['3012'], response_status=status.HTTP_200_OK) else: return custom_error_response(ERROR_CODE["2008"], response_status=status.HTTP_400_BAD_REQUEST) except Exception as e: @@ -132,8 +135,8 @@ class UserLogin(viewsets.ViewSet): email_verified.otp = otp email_verified.save() data.update({"email_otp":otp}) - return custom_response(ERROR_CODE['2024'], {"email_otp":otp, "is_email_verified": is_verified}, - response_status=status.HTTP_400_BAD_REQUEST) + return custom_response(ERROR_CODE['2024'], {"email_otp": otp, "is_email_verified": is_verified}, + response_status=status.HTTP_200_OK) data.update({"is_email_verified": is_verified}) return custom_response(None, data, response_status=status.HTTP_200_OK) @@ -159,7 +162,10 @@ class ReSendEmailOtp(viewsets.ModelViewSet): def create(self, request, *args, **kwargs): otp = generate_otp() if User.objects.filter(email=request.data['email']): - UserEmailOtp.objects.create(email=request.data['email'], otp=otp) + email_data = UserEmailOtp.objects.get_or_create(email=request.data['email']) + if email_data: + email_data.otp = otp + email_data.save() return custom_response(None, {'email_otp': otp}, response_status=status.HTTP_200_OK) else: return custom_error_response(ERROR_CODE["2023"], response_status=status.HTTP_400_BAD_REQUEST) diff --git a/zod_bank/base/constants.py b/zod_bank/base/constants.py index 72f2b0c..b66ed5f 100644 --- a/zod_bank/base/constants.py +++ b/zod_bank/base/constants.py @@ -14,8 +14,7 @@ SUPER_ADMIN = "Super Admin" JWT_TOKEN_EXPIRATION = 3 * 24 * 60 # Define common file extention -FILE_EXTENSION = ("gif", "jpeg", "jpg", "png", "svg", "csv", "doc", "docx", "odt", "pdf", "rtf", "txt", "wks", "wp", - "wpd") +FILE_EXTENSION = ("gif", "jpeg", "jpg", "png", "svg") # Define file size in bytes(5MB = 5 * 1024 * 1024) FILE_SIZE = 5 * 1024 * 1024 @@ -42,53 +41,6 @@ GUARDIAN = 'guardian' JUNIOR = 'junior' SUPERUSER = 'superuser' # numbers used as a constant -NUMBER = { - 'point_zero': 0.0, - 'zero': 0, - 'one': 1, - 'two': 2, - 'three': 3, - 'four': 4, - 'five': 5, - 'six': 6, - 'seven': 7, - 'eight': 8, - 'nine': 9, - 'ten': 10, - 'eleven': 11, - 'twelve': 12, - 'thirteen': 13, - 'fourteen': 14, - 'fifteen': 15, - 'sixteen': 16, - 'seventeen': 17, - 'eighteen': 18, - 'nineteen': 19, - 'twenty_four': 24, - 'twenty_one': 21, - 'twenty_two': 22, - 'twenty_five': 25, - 'thirty': 30, - 'thirty_five': 35, - 'thirty_six': 36, - 'forty': 40, - 'fifty': 50, - 'fifty_nine': 59, - 'sixty': 60, - 'seventy_five': 75, - 'eighty': 80, - 'ninty_five': 95, - 'ninty_six': 96, - 'ninety_nine': 99, - 'hundred': 100, - 'one_one_nine': 119, - 'one_twenty': 120, - 'four_zero_four': 404, - 'five_hundred': 500, - 'minus_one': -1, - 'point_three': 0.3, - 'point_seven': 0.7 -} # Define the byte into kb BYTE_IMAGE_SIZE = 1024 diff --git a/zod_bank/base/custom_exceptions.py b/zod_bank/base/custom_exceptions.py deleted file mode 100644 index 5815504..0000000 --- a/zod_bank/base/custom_exceptions.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -module containing override conflict error class -""" -# third party imports -from django.utils.translation import ugettext_lazy as _ -from rest_framework import status -from rest_framework.exceptions import APIException - - -class ConflictError(APIException): - """ - Override conflict error - """ - status_code = status.HTTP_409_CONFLICT - default_detail = _('Not allowed request.') - default_code = 'conflict_error' diff --git a/zod_bank/base/search_and_filters.py b/zod_bank/base/search_and_filters.py deleted file mode 100644 index 52330ef..0000000 --- a/zod_bank/base/search_and_filters.py +++ /dev/null @@ -1,49 +0,0 @@ -""" -This module contains search methods that can be used to search over a particular field in a specific model. -Update SEARCH_MAP dict for searching with model name and fields name -""" -# python imports -import operator -from functools import reduce - -# third party imports -from django.contrib.auth import get_user_model -from django.db.models import Q - -SEARCH_MAP = { - get_user_model(): {'search_fields': ['first_name__icontains', 'last_name__icontains', 'username__icontains']} -} - - -def search_query(search_by, search_term): - """ - :param search_by: search fields - :param search_term: search value - :return: return query - """ - query = [] - if search_by: - for key in search_by: - query.append({key: search_term}) - return query - - -def get_search_fields(model): - """ - :param model: model name - :return: dict of searching field name - """ - return SEARCH_MAP[model]['search_fields'] - - -def global_search(search_data, model_name): - """ - :param search_data: search value - :param model_name: model name - :return: query - """ - # get search fields for the above model - search_fields = get_search_fields(model_name) - # build query - query = search_query(search_fields, search_data) - return model_name.objects.filter(reduce(operator.or_, [Q(**x) for x in query])) diff --git a/zod_bank/base/upload_file.py b/zod_bank/base/upload_file.py index 14f9e02..2d47ad2 100644 --- a/zod_bank/base/upload_file.py +++ b/zod_bank/base/upload_file.py @@ -16,8 +16,8 @@ from rest_framework.status import HTTP_400_BAD_REQUEST, HTTP_200_OK from base import constants from base.constants import NUMBER # local import -from resourcekit.settings import base_settings as settings -from resourcekit.settings.base_settings import BASE_DIR +from zod_bank.settings import base_settings as settings +from zod_bank.settings.base_settings import BASE_DIR def image_upload(folder, file_name, data): diff --git a/zod_bank/guardian/models.py b/zod_bank/guardian/models.py index 2819bf3..03ce62a 100644 --- a/zod_bank/guardian/models.py +++ b/zod_bank/guardian/models.py @@ -13,7 +13,6 @@ class Guardian(models.Model): 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) guardian_code = models.CharField(max_length=10, null=True, blank=True, default=None) - junior_code = ArrayField(models.CharField(max_length=10, null=True, blank=True, default=None),null=True) 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) is_active = models.BooleanField(default=True) diff --git a/zod_bank/guardian/urls.py b/zod_bank/guardian/urls.py index 0e3f898..5adfc55 100644 --- a/zod_bank/guardian/urls.py +++ b/zod_bank/guardian/urls.py @@ -11,7 +11,7 @@ router = routers.SimpleRouter() """API End points with router""" router.register('sign-up', SignupViewset, basename='sign-up') -router.register('complete-guardian-profile', UpdateGuardianProfile, basename='update-guardian-profile') +router.register('create-guardian-profile', UpdateGuardianProfile, basename='update-guardian-profile') urlpatterns = [ path('api/v1/', include(router.urls)), ] diff --git a/zod_bank/junior/urls.py b/zod_bank/junior/urls.py index 27a312e..1dc2e23 100644 --- a/zod_bank/junior/urls.py +++ b/zod_bank/junior/urls.py @@ -10,7 +10,7 @@ from rest_framework import routers router = routers.SimpleRouter() """API End points with router""" -router.register('complete-junior-profile', UpdateJuniorProfile, basename='profile-update') +router.register('create-junior-profile', UpdateJuniorProfile, basename='profile-update') router.register('validate-guardian-code', ValidateGuardianCode, basename='validate-guardian-code') urlpatterns = [ path('api/v1/', include(router.urls)), diff --git a/zod_bank/junior/views.py b/zod_bank/junior/views.py index 4eb3a35..7eb1063 100644 --- a/zod_bank/junior/views.py +++ b/zod_bank/junior/views.py @@ -25,7 +25,7 @@ class UpdateJuniorProfile(viewsets.ViewSet): if serializer.is_valid(): serializer.save() return custom_response(None, serializer.data, response_status=status.HTTP_200_OK) - return custom_error_response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST) class ValidateGuardianCode(viewsets.ViewSet): permission_classes = [IsAuthenticated] diff --git a/zod_bank/requirements.txt b/zod_bank/requirements.txt index e78af44..da73f65 100644 --- a/zod_bank/requirements.txt +++ b/zod_bank/requirements.txt @@ -23,8 +23,12 @@ django-celery-results==2.5.1 django-cors-headers==4.1.0 django-dotenv==1.4.2 django-extensions==3.2.3 +django-phonenumber-field==7.1.0 +django-render-block==0.9.2 django-ses==3.5.0 +django-smtp-ssl==1.0 django-storages==1.13.2 +django-templated-email==3.0.1 django-timezone-field==5.1 djangorestframework==3.14.0 djangorestframework-simplejwt==5.2.2 @@ -34,6 +38,7 @@ jmespath==0.10.0 kombu==5.3.1 msgpack==1.0.5 packaging==23.1 +phonenumbers==8.13.15 prompt-toolkit==3.0.38 psycopg==3.1.9 pycparser==2.21 From 44b25dde3ea542e860898654ce0d4aad116b4ebd Mon Sep 17 00:00:00 2001 From: jain Date: Tue, 27 Jun 2023 11:44:00 +0530 Subject: [PATCH 06/19] Jira-13 sonar fixes --- zod_bank/account/admin.py | 8 ++++- zod_bank/account/utils.py | 4 +-- zod_bank/account/views.py | 28 ++++++++++++++--- zod_bank/guardian/admin.py | 7 ++++- zod_bank/guardian/apps.py | 3 ++ zod_bank/guardian/models.py | 11 ++++++- zod_bank/guardian/serializers.py | 53 +++++++++++++++++++++++--------- zod_bank/guardian/tests.py | 2 ++ zod_bank/guardian/urls.py | 6 ++-- zod_bank/guardian/views.py | 34 ++++++++++---------- zod_bank/junior/admin.py | 5 +++ zod_bank/junior/apps.py | 4 ++- zod_bank/junior/models.py | 13 ++++++-- zod_bank/junior/serializers.py | 35 ++++++++++++++++----- zod_bank/junior/tests.py | 2 ++ zod_bank/junior/urls.py | 4 ++- zod_bank/junior/views.py | 26 ++++++++-------- zod_bank/manage.py | 4 +++ zod_bank/zod_bank/settings.py | 28 +++-------------- 19 files changed, 188 insertions(+), 89 deletions(-) diff --git a/zod_bank/account/admin.py b/zod_bank/account/admin.py index fce7bde..7dbf869 100644 --- a/zod_bank/account/admin.py +++ b/zod_bank/account/admin.py @@ -1,10 +1,12 @@ +"""Account admin""" from django.contrib import admin -# Register your models here. +"""Import django app""" from .models import UserProfile, UserEmailOtp, UserPhoneOtp # Register your models here. @admin.register(UserProfile) class UserProfileAdmin(admin.ModelAdmin): + """User profile admin""" list_display = ['user'] def __str__(self): @@ -12,14 +14,18 @@ class UserProfileAdmin(admin.ModelAdmin): @admin.register(UserEmailOtp) class UserEmailOtpAdmin(admin.ModelAdmin): + """User Email otp admin""" list_display = ['email'] def __str__(self): + """Return object in email and otp format""" return self.email + '-' + self.otp @admin.register(UserPhoneOtp) class UserPhoneOtpAdmin(admin.ModelAdmin): + """User Phone otp admin""" list_display = ['phone'] def __str__(self): + """Return object in phone number and otp format""" return self.phone + '-' + self.otp diff --git a/zod_bank/account/utils.py b/zod_bank/account/utils.py index 2d86106..f20ef19 100644 --- a/zod_bank/account/utils.py +++ b/zod_bank/account/utils.py @@ -1,6 +1,6 @@ -from django.core.mail import send_mail +"""Account utils""" +"""Third party Django app""" from django.conf import settings -import random from rest_framework import viewsets, status from rest_framework.response import Response diff --git a/zod_bank/account/views.py b/zod_bank/account/views.py index e3a9550..3a6d6f6 100644 --- a/zod_bank/account/views.py +++ b/zod_bank/account/views.py @@ -1,6 +1,7 @@ from rest_framework import viewsets, status, views from rest_framework.decorators import action import random +import logging from django.contrib.auth import authenticate, login from guardian.models import Guardian from junior.models import Junior @@ -8,7 +9,6 @@ from account.models import UserProfile, UserPhoneOtp, UserEmailOtp from django.contrib.auth.models import User from .serializers import (SuperUserSerializer, GuardianSerializer, JuniorSerializer, EmailVerificationSerializer, ForgotPasswordSerializer, ResetPasswordSerializer, ChangePasswordSerializer) -from django.views.decorators.csrf import csrf_exempt from rest_framework_simplejwt.tokens import RefreshToken from base.messages import ERROR_CODE, SUCCESS_CODE from guardian.tasks import generate_otp @@ -94,7 +94,7 @@ class UserPhoneVerification(viewsets.ModelViewSet): return custom_response(SUCCESS_CODE['3012'], response_status=status.HTTP_200_OK) else: return custom_error_response(ERROR_CODE["2008"], response_status=status.HTTP_400_BAD_REQUEST) - except Exception as e: + except Exception: return custom_error_response(ERROR_CODE["2008"], response_status=status.HTTP_400_BAD_REQUEST) @@ -114,12 +114,11 @@ class UserLogin(viewsets.ViewSet): junior_data = Junior.objects.filter(auth__username=username, is_complete_profile=True).last() if junior_data: serializer = JuniorSerializer(junior_data) - if user.is_superuser: - serializer = SuperUserSerializer(user) return custom_response(SUCCESS_CODE['3003'], serializer.data, 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) @@ -140,6 +139,26 @@ class UserLogin(viewsets.ViewSet): data.update({"is_email_verified": is_verified}) return custom_response(None, data, response_status=status.HTTP_200_OK) + @action(methods=['post'], detail=False) + def admin_login(self, request): + 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) + if user.is_superuser: + serializer = SuperUserSerializer(user) + return custom_response(SUCCESS_CODE['3003'], serializer.data, 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) + refresh = RefreshToken.for_user(user) + access_token = str(refresh.access_token) + data = {"auth_token": access_token, "user_role": '3'} + return custom_response(None, data, response_status=status.HTTP_200_OK) + class UserEmailVerification(viewsets.ModelViewSet): """User Email verification""" serializer_class = EmailVerificationSerializer @@ -155,6 +174,7 @@ class UserEmailVerification(viewsets.ModelViewSet): else: return custom_error_response(ERROR_CODE["2008"], response_status=status.HTTP_400_BAD_REQUEST) except Exception as e: + logging.error(e) return custom_error_response(ERROR_CODE["2008"], response_status=status.HTTP_400_BAD_REQUEST) class ReSendEmailOtp(viewsets.ModelViewSet): diff --git a/zod_bank/guardian/admin.py b/zod_bank/guardian/admin.py index f2c8fbc..a3bd40c 100644 --- a/zod_bank/guardian/admin.py +++ b/zod_bank/guardian/admin.py @@ -1,9 +1,14 @@ +"""Guardian admin""" +"""Third party Django app""" from django.contrib import admin +"""Import Django app""" from .models import Guardian # Register your models here. @admin.register(Guardian) class GuardianAdmin(admin.ModelAdmin): + """Junior Admin""" list_display = ['user', 'family_name'] def __str__(self): - return self.user__email \ No newline at end of file + """Return email id""" + return self.user__email diff --git a/zod_bank/guardian/apps.py b/zod_bank/guardian/apps.py index b69ed5d..fcaf209 100644 --- a/zod_bank/guardian/apps.py +++ b/zod_bank/guardian/apps.py @@ -1,6 +1,9 @@ +"""Guardian app file""" +"""Third party Django app""" from django.apps import AppConfig class CustodianConfig(AppConfig): + """Guardian config""" default_auto_field = 'django.db.models.BigAutoField' name = 'guardian' diff --git a/zod_bank/guardian/models.py b/zod_bank/guardian/models.py index 03ce62a..f135bae 100644 --- a/zod_bank/guardian/models.py +++ b/zod_bank/guardian/models.py @@ -1,23 +1,31 @@ +"""Guardian model file""" +"""Third party Django app""" from django.db import models from django.contrib.auth import get_user_model +"""Import Django app""" from base.constants import GENDERS -from django.contrib.postgres.fields import ArrayField User = get_user_model() # Create your models here. class Guardian(models.Model): + """Guardian model""" user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='guardian_profile', verbose_name='Email') + """Contact details""" country_code = models.IntegerField(blank=True, null=True) phone = models.CharField(max_length=31, 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) + """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) @@ -27,4 +35,5 @@ class Guardian(models.Model): verbose_name = 'Guardian' def __str__(self): + """Return email id""" return f'{self.user}' diff --git a/zod_bank/guardian/serializers.py b/zod_bank/guardian/serializers.py index e55c766..e2bd807 100644 --- a/zod_bank/guardian/serializers.py +++ b/zod_bank/guardian/serializers.py @@ -1,91 +1,116 @@ -from rest_framework import serializers -from django.contrib.auth.models import User -from .models import Guardian -from django.db import transaction +"""Serializer of Guardian""" +"""Third party Django app""" +import logging import random -from account.models import UserProfile -from junior.models import Junior -from base.constants import GENDERS, GUARDIAN, JUNIOR, SUPERUSER +from rest_framework import serializers from rest_framework_simplejwt.tokens import RefreshToken +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 base.messages import ERROR_CODE, SUCCESS_CODE class UserSerializer(serializers.ModelSerializer): + """User serializer""" auth_token = serializers.SerializerMethodField('get_auth_token') - class Meta(object): + """Meta info""" model = User fields = ['email', 'password', 'auth_token'] def get_auth_token(self, obj): + """generate auth token""" refresh = RefreshToken.for_user(obj) access_token = str(refresh.access_token) return access_token def create(self, validated_data): + """fetch data""" email = validated_data.get('email') user_type = self.context password = validated_data.get('password') try: + """Create user profile""" user = User.objects.create_user(username=email, email=email, password=password) UserProfile.objects.create(user=user, user_type=user_type) return user - except: + 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 class CreateGuardianSerializer(serializers.ModelSerializer): + """Create guardian serializer""" + """Basic info""" first_name = serializers.SerializerMethodField('get_first_name') last_name = serializers.SerializerMethodField('get_last_name') email = serializers.SerializerMethodField('get_email') + """Contact details""" phone = serializers.CharField(max_length=20, required=False) - family_name = serializers.CharField(max_length=100, required=False) country_code = serializers.IntegerField(required=False) + family_name = serializers.CharField(max_length=100, required=False) dob = serializers.DateField(required=False) referral_code = serializers.CharField(max_length=100, 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'] + fields = ['first_name', 'last_name', 'email', 'phone', 'family_name', 'gender', 'country_code', + 'dob', 'referral_code', 'passcode', 'is_complete_profile'] def get_first_name(self,obj): + """first name of guardian""" return obj.user.first_name def get_last_name(self,obj): + """last name of guardian""" return obj.user.last_name def get_email(self,obj): + """emailof guardian""" return obj.user.email def create(self, validated_data): + """Create guardian profile""" user = User.objects.filter(username=self.context['user']).last() if user: + """Save first and last name of guardian""" user.first_name = self.context.get('first_name', user.first_name) user.last_name = self.context.get('last_name', user.last_name) user.save() + """Create guardian data""" guardian, created = Guardian.objects.get_or_create(user=self.context['user']) if created: + """Create referral code and guardian code""" guardian.referral_code = ''.join([str(random.randrange(9)) for _ in range(4)]) guardian.guardian_code = ''.join([str(random.randrange(9)) for _ in range(4)]) if guardian: - guardian.phone = validated_data.get('phone', guardian.phone) + """update details according to the data get from request""" guardian.gender = validated_data.get('gender',guardian.gender) guardian.family_name = validated_data.get('family_name', guardian.family_name) guardian.dob = validated_data.get('dob',guardian.dob) + """Update country code and phone number""" + guardian.phone = validated_data.get('phone', guardian.phone) + guardian.country_code = validated_data.get('country_code', guardian.country_code) guardian.passcode = validated_data.get('passcode', guardian.passcode) + guardian.referral_code_used = validated_data.get('referral_code_used', guardian.referral_code_used) + """Complete profile of the junior if below all data are filled""" complete_profile_field = all([guardian.phone, guardian.gender, guardian.family_name, guardian.dob, guardian.country_code, user.first_name, user.last_name]) guardian.is_complete_profile = False if complete_profile_field: guardian.is_complete_profile = True - guardian.country_code = validated_data.get('country_code', guardian.country_code) guardian.save() return guardian def save(self, **kwargs): + """Save the data into junior table""" with transaction.atomic(): instance = super().save(**kwargs) return instance diff --git a/zod_bank/guardian/tests.py b/zod_bank/guardian/tests.py index 7ce503c..3036e8b 100644 --- a/zod_bank/guardian/tests.py +++ b/zod_bank/guardian/tests.py @@ -1,3 +1,5 @@ +"""Test file of Guardian""" +"""Third party Django app""" from django.test import TestCase # Create your tests here. diff --git a/zod_bank/guardian/urls.py b/zod_bank/guardian/urls.py index 5adfc55..5399f2b 100644 --- a/zod_bank/guardian/urls.py +++ b/zod_bank/guardian/urls.py @@ -1,17 +1,19 @@ """ Urls files""" """Django import""" from django.urls import path, include -from rest_framework.decorators import api_view from .views import SignupViewset, UpdateGuardianProfile """Third party import""" from rest_framework import routers -"""Router""" +"""Define Router""" router = routers.SimpleRouter() """API End points with router""" +"""Sign up API""" router.register('sign-up', SignupViewset, basename='sign-up') +"""Create guardian profile API""" router.register('create-guardian-profile', UpdateGuardianProfile, basename='update-guardian-profile') +"""Define Url pattern""" urlpatterns = [ path('api/v1/', include(router.urls)), ] diff --git a/zod_bank/guardian/views.py b/zod_bank/guardian/views.py index 2b40702..72e5b94 100644 --- a/zod_bank/guardian/views.py +++ b/zod_bank/guardian/views.py @@ -1,45 +1,47 @@ -from django.shortcuts import render -from rest_framework import (pagination, viewsets, status, generics, mixins) -from .serializers import CreateGuardianSerializer -from rest_framework.decorators import action -from rest_framework.response import Response -from django.views.decorators.csrf import csrf_exempt -# Create your views here. -from rest_framework import viewsets, status -from rest_framework.response import Response -from .serializers import UserSerializer -from django.contrib.auth.models import User +"""Views of Guardian""" +"""Third party Django app""" from rest_framework.permissions import IsAuthenticated -from base.constants import GUARDIAN, JUNIOR, SUPERUSER -from junior.models import Junior +from rest_framework import viewsets, status +"""Import Django app""" +from .serializers import UserSerializer +from .serializers import CreateGuardianSerializer from account.models import UserEmailOtp from .tasks import generate_otp from account.utils import send_otp_email from account.utils import custom_response, custom_error_response from base.messages import ERROR_CODE, SUCCESS_CODE - +# Create your views here. class SignupViewset(viewsets.ModelViewSet): + """Signup view set""" serializer_class = UserSerializer def create(self, request, *args, **kwargs): + """Create user profile""" serializer = UserSerializer(context=request.data['user_type'], data=request.data) if serializer.is_valid(): serializer.save() + """Generate otp""" otp = generate_otp() UserEmailOtp.objects.create(email=request.data['email'], otp=otp) + """Send email to the register user""" send_otp_email(request.data['email'], otp) return custom_response(SUCCESS_CODE['3001'], {"email_otp": otp}, response_status=status.HTTP_200_OK) return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST) class UpdateGuardianProfile(viewsets.ViewSet): + """Update guardian profile""" serializer_class = CreateGuardianSerializer permission_classes = [IsAuthenticated] def create(self, request, *args, **kwargs): - serializer = CreateGuardianSerializer(context={"user":request.user,"first_name":request.data.get('first_name', ''), - "last_name": request.data.get('last_name',' ')}, data=request.data) + """Create guardian profile""" + serializer = CreateGuardianSerializer(context={"user":request.user, + "first_name":request.data.get('first_name', ''), + "last_name": request.data.get('last_name',' ')}, + data=request.data) if serializer.is_valid(): + """save serializer""" serializer.save() return custom_response(None, serializer.data,response_status=status.HTTP_200_OK) return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST) diff --git a/zod_bank/junior/admin.py b/zod_bank/junior/admin.py index 07d6053..87cd7d8 100644 --- a/zod_bank/junior/admin.py +++ b/zod_bank/junior/admin.py @@ -1,9 +1,14 @@ +"""Junior admin""" +"""Third party Django app""" from django.contrib import admin +"""Import Django app""" from .models import Junior # Register your models here. @admin.register(Junior) class JuniorAdmin(admin.ModelAdmin): + """Junior Admin""" list_display = ['auth'] def __str__(self): + """Return email id""" return self.auth__email diff --git a/zod_bank/junior/apps.py b/zod_bank/junior/apps.py index 0232709..f3df25e 100644 --- a/zod_bank/junior/apps.py +++ b/zod_bank/junior/apps.py @@ -1,6 +1,8 @@ +"""App file""" +"""Import AppConfig""" from django.apps import AppConfig - class JuniorConfig(AppConfig): + """Junior config""" default_auto_field = 'django.db.models.BigAutoField' name = 'junior' diff --git a/zod_bank/junior/models.py b/zod_bank/junior/models.py index 43c9d74..732bb66 100644 --- a/zod_bank/junior/models.py +++ b/zod_bank/junior/models.py @@ -1,25 +1,33 @@ +"""Junior model """ +"""Import django""" from django.db import models from django.contrib.auth import get_user_model -from base.constants import GENDERS -from guardian.models import Guardian from django.contrib.postgres.fields import ArrayField +"""Import django app""" +from base.constants import GENDERS User = get_user_model() # Create your models here. class Junior(models.Model): + """Junior model""" auth = models.ForeignKey(User, on_delete=models.CASCADE, related_name='junior_profile', verbose_name='Email') + """Contact details""" phone = models.CharField(max_length=31, null=True, blank=True, default=None) country_code = models.IntegerField(blank=True, null=True) + """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/') + """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) 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) @@ -29,4 +37,5 @@ class Junior(models.Model): verbose_name = 'Junior' def __str__(self): + """Return email id""" return f'{self.auth}' diff --git a/zod_bank/junior/serializers.py b/zod_bank/junior/serializers.py index 3e493e7..5d6df77 100644 --- a/zod_bank/junior/serializers.py +++ b/zod_bank/junior/serializers.py @@ -1,28 +1,29 @@ +"""Serializer file for junior""" +"""Import Django 3rd party app""" from rest_framework import serializers from django.contrib.auth.models import User -from .models import Guardian from django.db import transaction import random -from account.models import UserProfile +"""Import django app""" from junior.models import Junior -from base.constants import GENDERS, GUARDIAN, JUNIOR, SUPERUSER -from rest_framework_simplejwt.tokens import RefreshToken -from base.messages import ERROR_CODE, SUCCESS_CODE -from django.contrib.postgres.fields import ArrayField class ListCharField(serializers.ListField): + """Serializer for Array field""" child = serializers.CharField() def to_representation(self, data): + """to represent the data""" return data def to_internal_value(self, data): + """internal value""" if isinstance(data, list): return data raise serializers.ValidationError({"details":"Invalid input. Expected a list of strings."}) class CreateJuniorSerializer(serializers.ModelSerializer): + """Create junior serializer""" first_name = serializers.SerializerMethodField('get_first_name') last_name = serializers.SerializerMethodField('get_last_name') email = serializers.SerializerMethodField('get_email') @@ -33,41 +34,59 @@ class CreateJuniorSerializer(serializers.ModelSerializer): guardian_code = ListCharField(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'] def get_first_name(self,obj): + """first name of junior""" return obj.auth.first_name def get_last_name(self,obj): + """last name of junior""" return obj.auth.last_name def get_email(self,obj): + """email of junior""" return obj.auth.email def create(self, validated_data): + """Create junior profile""" user = User.objects.filter(username=self.context['user']).last() if user: + """Save first and last name of junior""" user.first_name = self.context.get('first_name', user.first_name) user.last_name = self.context.get('last_name', user.last_name) user.save() + """Create junior data""" junior, created = Junior.objects.get_or_create(auth=self.context['user']) if created: + """Create referral code and junior code""" junior.referral_code = ''.join([str(random.randrange(9)) for _ in range(4)]) junior.junior_code = ''.join([str(random.randrange(9)) for _ in range(4)]) if junior: - junior.phone = validated_data.get('phone', junior.phone) + """update details according to the data get from request""" junior.gender = validated_data.get('gender',junior.gender) + """Update guardian code""" junior.guardian_code = validated_data.get('guardian_code', junior.guardian_code) junior.dob = validated_data.get('dob',junior.dob) junior.passcode = validated_data.get('passcode', junior.passcode) - junior.is_complete_profile = validated_data.get('is_complete_profile', junior.is_complete_profile) + """Update country code and phone number""" + junior.phone = validated_data.get('phone', junior.phone) junior.country_code = validated_data.get('country_code', junior.country_code) + junior.referral_code_used = validated_data.get('referral_code_used', junior.referral_code_used) + """Complete profile of the junior if below all data are filled""" + complete_profile_field = all([junior.phone, junior.gender, junior.family_name, + junior.dob, junior.country_code, user.first_name, user.last_name]) + junior.is_complete_profile = False + if complete_profile_field: + junior.is_complete_profile = True junior.save() return junior def save(self, **kwargs): + """Save the data into junior table""" with transaction.atomic(): instance = super().save(**kwargs) return instance diff --git a/zod_bank/junior/tests.py b/zod_bank/junior/tests.py index 7ce503c..1a75974 100644 --- a/zod_bank/junior/tests.py +++ b/zod_bank/junior/tests.py @@ -1,3 +1,5 @@ +"""Junior test file""" +"""Import TestCase""" from django.test import TestCase # Create your tests here. diff --git a/zod_bank/junior/urls.py b/zod_bank/junior/urls.py index 1dc2e23..2b64fe4 100644 --- a/zod_bank/junior/urls.py +++ b/zod_bank/junior/urls.py @@ -1,7 +1,6 @@ """ Urls files""" """Django import""" from django.urls import path, include -from rest_framework.decorators import api_view from .views import UpdateJuniorProfile, ValidateGuardianCode """Third party import""" from rest_framework import routers @@ -10,8 +9,11 @@ from rest_framework import routers router = routers.SimpleRouter() """API End points with router""" +"""Create junior profile API""" router.register('create-junior-profile', UpdateJuniorProfile, basename='profile-update') +"""validate guardian code API""" router.register('validate-guardian-code', ValidateGuardianCode, basename='validate-guardian-code') +"""Define url pattern""" urlpatterns = [ path('api/v1/', include(router.urls)), ] diff --git a/zod_bank/junior/views.py b/zod_bank/junior/views.py index 7eb1063..4022ba7 100644 --- a/zod_bank/junior/views.py +++ b/zod_bank/junior/views.py @@ -1,36 +1,36 @@ -from django.shortcuts import render -from rest_framework import (pagination, viewsets, status, generics, mixins) -from rest_framework.decorators import action -from rest_framework.response import Response -from django.views.decorators.csrf import csrf_exempt -# Create your views here. +"""Junior view file""" from rest_framework import viewsets, status -from rest_framework.response import Response -from .serializers import CreateJuniorSerializer -from django.contrib.auth.models import User from rest_framework.permissions import IsAuthenticated -from base.constants import GUARDIAN, JUNIOR, SUPERUSER +"""Django app import""" from junior.models import Junior +from .serializers import CreateJuniorSerializer from guardian.models import Guardian from base.messages import ERROR_CODE, SUCCESS_CODE from account.utils import custom_response, custom_error_response - +# Create your views here. class UpdateJuniorProfile(viewsets.ViewSet): + """Update junior profile""" serializer_class = CreateJuniorSerializer permission_classes = [IsAuthenticated] def create(self, request, *args, **kwargs): - serializer = CreateJuniorSerializer(context={"user":request.user,"first_name":request.data.get('first_name', ''), - "last_name": request.data.get('last_name',' ')}, data=request.data) + """Use CreateJuniorSerializer""" + serializer = CreateJuniorSerializer(context={"user":request.user, + "first_name":request.data.get('first_name', ''), + "last_name": request.data.get('last_name',' ')}, + data=request.data) if serializer.is_valid(): + """save serializer""" serializer.save() return custom_response(None, serializer.data, response_status=status.HTTP_200_OK) return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST) class ValidateGuardianCode(viewsets.ViewSet): + """Check guardian code exist or not""" permission_classes = [IsAuthenticated] def list(self, request, *args, **kwargs): + """check guardian code""" guardian_code = request.data.get('guardian_code') for code in guardian_code: guardian_data = Guardian.objects.filter(guardian_code=code).exists() diff --git a/zod_bank/manage.py b/zod_bank/manage.py index 169c7c2..fe9e065 100755 --- a/zod_bank/manage.py +++ b/zod_bank/manage.py @@ -1,14 +1,18 @@ #!/usr/bin/env python """Django's command-line utility for administrative tasks.""" +"""Django import""" import os import sys def main(): + """Main function""" os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'zod_bank.settings') try: + """Import execute from command line function""" from django.core.management import execute_from_command_line except ImportError as exc: + """Show Exception error""" raise ImportError( "Couldn't import Django. Are you sure it's installed and " "available on your PYTHONPATH environment variable? Did you " diff --git a/zod_bank/zod_bank/settings.py b/zod_bank/zod_bank/settings.py index 9e47b30..79eaeeb 100644 --- a/zod_bank/zod_bank/settings.py +++ b/zod_bank/zod_bank/settings.py @@ -57,7 +57,7 @@ INSTALLED_APPS = [ 'junior', 'guardian', ] -# CSRF_COOKIE_SECURE = False + MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', @@ -168,27 +168,9 @@ CORS_ALLOW_HEADERS = ( 'x-requested-with', ) -# Static files (CSS, JavaScript, Images) -# https://docs.djangoproject.com/en/3.0/howto/static-files/ +"""Static files (CSS, JavaScript, Images) +https://docs.djangoproject.com/en/3.0/howto/static-files/""" -# -# MAIL_MAILER='smtp' -# MAIL_HOST='smtp.gmail.com' -# MAIL_PORT=587 -# mail_username='infozodbank@gmail.com' -# MAIL_PASSWORD='ghwdmznwwslvchga' -# MAIL_ENCRYPTION='tls' -# mail_from_address='infozodbank@gmail.com' -# MAIL_FROM_NAME="${APP_NAME}" - -# MAIL_MAILER='smtp' -# MAIL_HOST='smtp.gmail.com' -# MAIL_PORT=587 -# mail_username='ankita.jain@kiwitech.com' -# MAIL_PASSWORD='jaijain0912@' -# MAIL_ENCRYPTION='tls' -# mail_from_address='infozodbank@gmail.com' -# MAIL_FROM_NAME="${APP_NAME}" # Email settings EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' @@ -196,7 +178,7 @@ EMAIL_HOST = 'smtp.gmail.com' EMAIL_PORT = 587 EMAIL_USE_TLS = True EMAIL_HOST_USER = 'infozodbank@gmail.com' -EMAIL_HOST_PASSWORD = 'ghwdmznwwslvchga' # Replace with your Gmail email password or App password - +# Replace with your Gmail email password or App password +EMAIL_HOST_PASSWORD = 'ghwdmznwwslvchga' STATIC_URL = '/static/' From aaa173063675cef229aeb826050fb54c80b672b8 Mon Sep 17 00:00:00 2001 From: jain Date: Tue, 27 Jun 2023 11:46:20 +0530 Subject: [PATCH 07/19] Jira-13 migrate file --- .../0002_remove_guardian_junior_code.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 zod_bank/guardian/migrations/0002_remove_guardian_junior_code.py diff --git a/zod_bank/guardian/migrations/0002_remove_guardian_junior_code.py b/zod_bank/guardian/migrations/0002_remove_guardian_junior_code.py new file mode 100644 index 0000000..6996d0a --- /dev/null +++ b/zod_bank/guardian/migrations/0002_remove_guardian_junior_code.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2.2 on 2023-06-27 06:15 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('guardian', '0001_initial'), + ] + + operations = [ + migrations.RemoveField( + model_name='guardian', + name='junior_code', + ), + ] From 232f082c77109f7314b0e0a7bd6aa23abaebf064 Mon Sep 17 00:00:00 2001 From: jain Date: Tue, 27 Jun 2023 14:59:00 +0530 Subject: [PATCH 08/19] jira-7 changes in requirment.txt file --- zod_bank/Dockerfile | 11 +++++++++++ zod_bank/account/views.py | 20 +++++++++++--------- zod_bank/base/messages.py | 5 +++-- zod_bank/docker-compose.yml | 18 ++++++++++++++++++ zod_bank/junior/views.py | 4 ++-- zod_bank/requirements.txt | 1 + 6 files changed, 46 insertions(+), 13 deletions(-) create mode 100644 zod_bank/Dockerfile create mode 100644 zod_bank/docker-compose.yml diff --git a/zod_bank/Dockerfile b/zod_bank/Dockerfile new file mode 100644 index 0000000..77c6fa8 --- /dev/null +++ b/zod_bank/Dockerfile @@ -0,0 +1,11 @@ +FROM python:3.9 +ENV PYTHONUNBUFFERED 1 +RUN mkdir /usr/src/app +WORKDIR /usr/src/app +COPY . . +RUN apt-get update +RUN apt-get install wkhtmltopdf -y +RUN apt install -y gdal-bin python3-gdal +RUN pip install -r requirements.txt +WORKDIR /usr/src/app + diff --git a/zod_bank/account/views.py b/zod_bank/account/views.py index 3a6d6f6..c6f65ff 100644 --- a/zod_bank/account/views.py +++ b/zod_bank/account/views.py @@ -13,6 +13,7 @@ from rest_framework_simplejwt.tokens import RefreshToken from base.messages import ERROR_CODE, SUCCESS_CODE from guardian.tasks import generate_otp from django.conf import settings +from account.utils import send_otp_email from account.utils import custom_response, custom_error_response from django.core.mail import EmailMessage from django.core.mail import send_mail @@ -27,7 +28,7 @@ class ChangePasswordAPIView(views.APIView): serializer = ChangePasswordSerializer(context=request.user, data=request.data) if serializer.is_valid(): serializer.save() - return custom_response(SUCCESS_CODE['3006'], response_status=status.HTTP_200_OK) + return custom_response(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): @@ -59,11 +60,11 @@ class ForgotPasswordAPIView(views.APIView): 'verification_code': verification_code } ) - user_data = UserEmailOtp.objects.get_or_create(email=email) + user_data, created = UserEmailOtp.objects.get_or_create(email=email) if user_data: user_data.otp = verification_code user_data.save() - return custom_response(SUCCESS_CODE['3015'], {'verification_code': verification_code}, + 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) @@ -86,8 +87,8 @@ class UserPhoneVerification(viewsets.ModelViewSet): """Send otp on phone""" def list(self, request, *args, **kwargs): try: - phone_data = UserPhoneOtp.objects.filter(phone=request.data['phone'], - otp=request.data['otp']).last() + phone_data = UserPhoneOtp.objects.filter(phone=self.request.GET.get('phone'), + otp=self.request.GET.get('otp')).last() if phone_data: phone_data.is_verified = True phone_data.save() @@ -165,8 +166,8 @@ class UserEmailVerification(viewsets.ModelViewSet): def list(self, request, *args, **kwargs): try: - email_data = UserEmailOtp.objects.filter(email=request.data['email'], - otp=request.data['otp']).last() + email_data = UserEmailOtp.objects.filter(email=self.request.GET.get('email'), + otp=self.request.GET.get('otp')).last() if email_data: email_data.is_verified = True email_data.save() @@ -182,11 +183,12 @@ class ReSendEmailOtp(viewsets.ModelViewSet): def create(self, request, *args, **kwargs): otp = generate_otp() if User.objects.filter(email=request.data['email']): - email_data = UserEmailOtp.objects.get_or_create(email=request.data['email']) + email_data, created = UserEmailOtp.objects.get_or_create(email=request.data['email']) if email_data: email_data.otp = otp email_data.save() - return custom_response(None, {'email_otp': otp}, response_status=status.HTTP_200_OK) + send_otp_email(request.data['email'], otp) + return custom_response(SUCCESS_CODE['3016'], response_status=status.HTTP_200_OK) else: return custom_error_response(ERROR_CODE["2023"], response_status=status.HTTP_400_BAD_REQUEST) diff --git a/zod_bank/base/messages.py b/zod_bank/base/messages.py index 39f0282..37507fd 100644 --- a/zod_bank/base/messages.py +++ b/zod_bank/base/messages.py @@ -63,7 +63,7 @@ SUCCESS_CODE = { # Success code for password reset "3006": "Your password has been reset successfully.", # Success code for password update - "3007": "Your password has been updated successfully.", + "3007": "Your password has been changed successfully.", # Success code for valid link "3008": "You have a valid link.", # Success code for logged out @@ -74,7 +74,8 @@ SUCCESS_CODE = { "3012": "Phone OTP Verified successfully", "3013": "Valid Guardian code", "3014": "Password has been updated successfully.", - "3015": "Verification code sent on your email." + "3015": "Verification code sent on your email.", + "3016": "Send otp on your Email successfully" } STATUS_CODE_ERROR = { diff --git a/zod_bank/docker-compose.yml b/zod_bank/docker-compose.yml new file mode 100644 index 0000000..700bf1b --- /dev/null +++ b/zod_bank/docker-compose.yml @@ -0,0 +1,18 @@ +version: '3' +services: + nginx: + image: nginx:latest + container_name: nginx + ports: + - "8000:8000" + volumes: + - ./nginx:/etc/nginx/conf.d + - .:/usr/src/app + depends_on: + - web + web: + build: . + container_name: django + command: bash -c "pip install -r requirements.txt && python manage.py collectstatic --noinput && python manage.py migrate && gunicorn zod_bank.wsgi -b 0.0.0.0:8000 -t 300 --log-level=info" + volumes: + - .:/usr/src/app diff --git a/zod_bank/junior/views.py b/zod_bank/junior/views.py index 4022ba7..153bb41 100644 --- a/zod_bank/junior/views.py +++ b/zod_bank/junior/views.py @@ -31,10 +31,10 @@ class ValidateGuardianCode(viewsets.ViewSet): def list(self, request, *args, **kwargs): """check guardian code""" - guardian_code = request.data.get('guardian_code') + guardian_code = self.request.GET.get('guardian_code').split(',') for code in guardian_code: guardian_data = Guardian.objects.filter(guardian_code=code).exists() if guardian_data: - return custom_response(SUCCESS_CODE['3028'], response_status=status.HTTP_200_OK) + return custom_response(SUCCESS_CODE['3013'], response_status=status.HTTP_200_OK) else: return custom_error_response(ERROR_CODE["2022"], response_status=status.HTTP_400_BAD_REQUEST) diff --git a/zod_bank/requirements.txt b/zod_bank/requirements.txt index da73f65..a875fbf 100644 --- a/zod_bank/requirements.txt +++ b/zod_bank/requirements.txt @@ -33,6 +33,7 @@ django-timezone-field==5.1 djangorestframework==3.14.0 djangorestframework-simplejwt==5.2.2 drf-yasg==1.21.6 +gunicorn==20.1.0 inflection==0.5.1 jmespath==0.10.0 kombu==5.3.1 From d4eaaada7429daba596b5983b96d11ea40d4d344 Mon Sep 17 00:00:00 2001 From: jain Date: Tue, 27 Jun 2023 15:17:46 +0530 Subject: [PATCH 09/19] auth token changes --- zod_bank/account/views.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/zod_bank/account/views.py b/zod_bank/account/views.py index c6f65ff..80a1e1a 100644 --- a/zod_bank/account/views.py +++ b/zod_bank/account/views.py @@ -166,12 +166,15 @@ class UserEmailVerification(viewsets.ModelViewSet): def list(self, request, *args, **kwargs): try: + user_obj = User.objects.filter(username=self.request.GET.get('email')).last() email_data = UserEmailOtp.objects.filter(email=self.request.GET.get('email'), otp=self.request.GET.get('otp')).last() if email_data: email_data.is_verified = True email_data.save() - return custom_response(SUCCESS_CODE['3011'], response_status=status.HTTP_200_OK) + 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) else: return custom_error_response(ERROR_CODE["2008"], response_status=status.HTTP_400_BAD_REQUEST) except Exception as e: From 4537f1f4facf7f115770267c080f84cdbdfa270e Mon Sep 17 00:00:00 2001 From: jain Date: Tue, 27 Jun 2023 16:45:42 +0530 Subject: [PATCH 10/19] changes --- zod_bank/Dockerfile => Dockerfile | 0 .../docker-compose.yml => docker-compose.yml | 0 zod_bank/requirements.txt => requirements.txt | 0 zod_bank/account/urls.py | 3 ++- zod_bank/account/views.py | 4 ++++ zod_bank/zod_bank/settings.py | 20 ++++++++++++------- 6 files changed, 19 insertions(+), 8 deletions(-) rename zod_bank/Dockerfile => Dockerfile (100%) rename zod_bank/docker-compose.yml => docker-compose.yml (100%) rename zod_bank/requirements.txt => requirements.txt (100%) diff --git a/zod_bank/Dockerfile b/Dockerfile similarity index 100% rename from zod_bank/Dockerfile rename to Dockerfile diff --git a/zod_bank/docker-compose.yml b/docker-compose.yml similarity index 100% rename from zod_bank/docker-compose.yml rename to docker-compose.yml diff --git a/zod_bank/requirements.txt b/requirements.txt similarity index 100% rename from zod_bank/requirements.txt rename to requirements.txt diff --git a/zod_bank/account/urls.py b/zod_bank/account/urls.py index 0df4826..8462378 100644 --- a/zod_bank/account/urls.py +++ b/zod_bank/account/urls.py @@ -5,13 +5,14 @@ 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, GoogleLoginAPIViewset) """Router""" router = routers.SimpleRouter() """API End points with router""" router.register('user', UserLogin, basename='user') router.register('admin', UserLogin, basename='admin') +router.register('google-login', GoogleLoginAPIViewset, basename='admin') 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') diff --git a/zod_bank/account/views.py b/zod_bank/account/views.py index 80a1e1a..5e73a14 100644 --- a/zod_bank/account/views.py +++ b/zod_bank/account/views.py @@ -21,6 +21,10 @@ from rest_framework.response import Response from rest_framework.permissions import IsAuthenticated from templated_email import send_templated_mail +class GoogleLoginAPIViewset(viewsets.ModelViewSet): + """Google Login""" + serializer_class = SocialSignInSerializer + class ChangePasswordAPIView(views.APIView): permission_classes = [IsAuthenticated] diff --git a/zod_bank/zod_bank/settings.py b/zod_bank/zod_bank/settings.py index 79eaeeb..e1527a4 100644 --- a/zod_bank/zod_bank/settings.py +++ b/zod_bank/zod_bank/settings.py @@ -173,12 +173,18 @@ 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_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_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') STATIC_URL = '/static/' From 8ff142ce2ffcf22e2a08a3ddf19f9f138c29254e Mon Sep 17 00:00:00 2001 From: jain Date: Tue, 27 Jun 2023 16:53:38 +0530 Subject: [PATCH 11/19] changes docker file position --- zod_bank/Dockerfile => Dockerfile | 0 zod_bank/docker-compose.yml => docker-compose.yml | 0 zod_bank/requirements.txt => requirements.txt | 0 zod_bank/account/views.py | 1 - 4 files changed, 1 deletion(-) rename zod_bank/Dockerfile => Dockerfile (100%) rename zod_bank/docker-compose.yml => docker-compose.yml (100%) rename zod_bank/requirements.txt => requirements.txt (100%) diff --git a/zod_bank/Dockerfile b/Dockerfile similarity index 100% rename from zod_bank/Dockerfile rename to Dockerfile diff --git a/zod_bank/docker-compose.yml b/docker-compose.yml similarity index 100% rename from zod_bank/docker-compose.yml rename to docker-compose.yml diff --git a/zod_bank/requirements.txt b/requirements.txt similarity index 100% rename from zod_bank/requirements.txt rename to requirements.txt diff --git a/zod_bank/account/views.py b/zod_bank/account/views.py index 80a1e1a..ccb52d5 100644 --- a/zod_bank/account/views.py +++ b/zod_bank/account/views.py @@ -194,4 +194,3 @@ class ReSendEmailOtp(viewsets.ModelViewSet): return custom_response(SUCCESS_CODE['3016'], response_status=status.HTTP_200_OK) else: return custom_error_response(ERROR_CODE["2023"], response_status=status.HTTP_400_BAD_REQUEST) - From 019d028cb64d582db7ff57554a838e7d6b1ae21e Mon Sep 17 00:00:00 2001 From: jain Date: Tue, 27 Jun 2023 17:22:59 +0530 Subject: [PATCH 12/19] jira-5 google login --- zod_bank/account/serializers.py | 15 +++++++++++++++ zod_bank/account/views.py | 21 +++++++++++++++++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/zod_bank/account/serializers.py b/zod_bank/account/serializers.py index 2f18213..4ee88c4 100644 --- a/zod_bank/account/serializers.py +++ b/zod_bank/account/serializers.py @@ -13,6 +13,21 @@ from rest_framework.decorators import action from django.contrib.auth import authenticate, login from rest_framework_simplejwt.tokens import RefreshToken +class GoogleSignInSerializer(serializers.Serializer): + """Google login Serializer""" + + def create(self, validated_data): + """Create or update user model""" + with transaction.atomic(): + print() + if User.objects.filter(email__iexact=self.validated_data['email']).exists(): + return User.objects.get(email__iexact=self.validated_data['email']) + + if not User.objects.filter(email__iexact=self.validated_data['email']).exists(): + instance = User.objects.create(username=self.validated_data['email'], + email=self.validated_data['email']) + return instance + class ResetPasswordSerializer(serializers.Serializer): """Reset Password after verification""" diff --git a/zod_bank/account/views.py b/zod_bank/account/views.py index 5e73a14..a8f25ab 100644 --- a/zod_bank/account/views.py +++ b/zod_bank/account/views.py @@ -8,7 +8,8 @@ from junior.models import Junior from account.models import UserProfile, UserPhoneOtp, UserEmailOtp from django.contrib.auth.models import User from .serializers import (SuperUserSerializer, GuardianSerializer, JuniorSerializer, EmailVerificationSerializer, - ForgotPasswordSerializer, ResetPasswordSerializer, ChangePasswordSerializer) + ForgotPasswordSerializer, ResetPasswordSerializer, ChangePasswordSerializer, + GoogleSignInSerializer) from rest_framework_simplejwt.tokens import RefreshToken from base.messages import ERROR_CODE, SUCCESS_CODE from guardian.tasks import generate_otp @@ -23,7 +24,23 @@ from templated_email import send_templated_mail class GoogleLoginAPIViewset(viewsets.ModelViewSet): """Google Login""" - serializer_class = SocialSignInSerializer + serializer_class = GoogleSignInSerializer + + def create(self, request, *args, **kwargs): + """ + Override default behaviour of create method + """ + provider_type = [] + serializer = self.get_serializer(data=request.data) + if serializer.is_valid(raise_exception=True): + provider = self.get_provider_view(request.data.get('provider')) + # if User is not authenticated then send error message + if not provider.is_authenticated(request): + return custom_error_response({}, status.HTTP_400_BAD_REQUEST) + + user = serializer.save() + if User.objects.filter(email__iexact=user.email).exists(): + class ChangePasswordAPIView(views.APIView): From ad582d77d7206c8be59ce1d31bd55d28e60f7db6 Mon Sep 17 00:00:00 2001 From: jain Date: Tue, 27 Jun 2023 17:27:19 +0530 Subject: [PATCH 13/19] changes --- {zod_bank/account => account}/__init__.py | 0 {zod_bank/account => account}/admin.py | 0 {zod_bank/account => account}/apps.py | 0 {zod_bank/account => account}/migrations/0001_initial.py | 0 {zod_bank/account => account}/migrations/__init__.py | 0 {zod_bank/account => account}/models.py | 0 {zod_bank/account => account}/serializers.py | 0 .../templates/templated_email/email_base.email | 0 .../templates/templated_email/email_otp_verification.email | 0 .../templates/templated_email/email_reset_verification.email | 0 {zod_bank/account => account}/tests.py | 0 {zod_bank/account => account}/urls.py | 0 {zod_bank/account => account}/utils.py | 0 {zod_bank/account => account}/views.py | 0 {zod_bank/base => base}/__init__.py | 0 {zod_bank/base => base}/common_email.py | 0 {zod_bank/base => base}/constants.py | 0 {zod_bank/base => base}/image_constants.py | 0 {zod_bank/base => base}/messages.py | 0 {zod_bank/base => base}/routers.py | 0 {zod_bank/base => base}/upload_file.py | 0 {zod_bank/guardian => guardian}/__init__.py | 0 {zod_bank/guardian => guardian}/admin.py | 0 {zod_bank/guardian => guardian}/apps.py | 0 {zod_bank/guardian => guardian}/migrations/0001_initial.py | 0 .../migrations/0002_remove_guardian_junior_code.py | 0 {zod_bank/guardian => guardian}/migrations/__init__.py | 0 {zod_bank/guardian => guardian}/models.py | 0 {zod_bank/guardian => guardian}/serializers.py | 0 {zod_bank/guardian => guardian}/tasks.py | 0 {zod_bank/guardian => guardian}/tests.py | 0 {zod_bank/guardian => guardian}/urls.py | 0 {zod_bank/guardian => guardian}/views.py | 0 {zod_bank/junior => junior}/__init__.py | 0 {zod_bank/junior => junior}/admin.py | 0 {zod_bank/junior => junior}/apps.py | 0 {zod_bank/junior => junior}/migrations/0001_initial.py | 0 {zod_bank/junior => junior}/migrations/__init__.py | 0 {zod_bank/junior => junior}/models.py | 0 {zod_bank/junior => junior}/serializers.py | 0 {zod_bank/junior => junior}/tests.py | 0 {zod_bank/junior => junior}/urls.py | 0 {zod_bank/junior => junior}/views.py | 0 zod_bank/manage.py => manage.py | 0 {zod_bank/nginx => nginx}/django.conf | 0 zod_bank/{zod_bank => }/__init__.py | 0 zod_bank/{zod_bank => }/asgi.py | 0 zod_bank/{zod_bank => }/settings.py | 0 zod_bank/{zod_bank => }/urls.py | 0 zod_bank/{zod_bank => }/wsgi.py | 0 50 files changed, 0 insertions(+), 0 deletions(-) rename {zod_bank/account => account}/__init__.py (100%) rename {zod_bank/account => account}/admin.py (100%) rename {zod_bank/account => account}/apps.py (100%) rename {zod_bank/account => account}/migrations/0001_initial.py (100%) rename {zod_bank/account => account}/migrations/__init__.py (100%) rename {zod_bank/account => account}/models.py (100%) rename {zod_bank/account => account}/serializers.py (100%) rename {zod_bank/account => account}/templates/templated_email/email_base.email (100%) rename {zod_bank/account => account}/templates/templated_email/email_otp_verification.email (100%) rename {zod_bank/account => account}/templates/templated_email/email_reset_verification.email (100%) rename {zod_bank/account => account}/tests.py (100%) rename {zod_bank/account => account}/urls.py (100%) rename {zod_bank/account => account}/utils.py (100%) rename {zod_bank/account => account}/views.py (100%) rename {zod_bank/base => base}/__init__.py (100%) rename {zod_bank/base => base}/common_email.py (100%) rename {zod_bank/base => base}/constants.py (100%) rename {zod_bank/base => base}/image_constants.py (100%) rename {zod_bank/base => base}/messages.py (100%) rename {zod_bank/base => base}/routers.py (100%) rename {zod_bank/base => base}/upload_file.py (100%) rename {zod_bank/guardian => guardian}/__init__.py (100%) rename {zod_bank/guardian => guardian}/admin.py (100%) rename {zod_bank/guardian => guardian}/apps.py (100%) rename {zod_bank/guardian => guardian}/migrations/0001_initial.py (100%) rename {zod_bank/guardian => guardian}/migrations/0002_remove_guardian_junior_code.py (100%) rename {zod_bank/guardian => guardian}/migrations/__init__.py (100%) rename {zod_bank/guardian => guardian}/models.py (100%) rename {zod_bank/guardian => guardian}/serializers.py (100%) rename {zod_bank/guardian => guardian}/tasks.py (100%) rename {zod_bank/guardian => guardian}/tests.py (100%) rename {zod_bank/guardian => guardian}/urls.py (100%) rename {zod_bank/guardian => guardian}/views.py (100%) rename {zod_bank/junior => junior}/__init__.py (100%) rename {zod_bank/junior => junior}/admin.py (100%) rename {zod_bank/junior => junior}/apps.py (100%) rename {zod_bank/junior => junior}/migrations/0001_initial.py (100%) rename {zod_bank/junior => junior}/migrations/__init__.py (100%) rename {zod_bank/junior => junior}/models.py (100%) rename {zod_bank/junior => junior}/serializers.py (100%) rename {zod_bank/junior => junior}/tests.py (100%) rename {zod_bank/junior => junior}/urls.py (100%) rename {zod_bank/junior => junior}/views.py (100%) rename zod_bank/manage.py => manage.py (100%) rename {zod_bank/nginx => nginx}/django.conf (100%) rename zod_bank/{zod_bank => }/__init__.py (100%) rename zod_bank/{zod_bank => }/asgi.py (100%) rename zod_bank/{zod_bank => }/settings.py (100%) rename zod_bank/{zod_bank => }/urls.py (100%) rename zod_bank/{zod_bank => }/wsgi.py (100%) diff --git a/zod_bank/account/__init__.py b/account/__init__.py similarity index 100% rename from zod_bank/account/__init__.py rename to account/__init__.py diff --git a/zod_bank/account/admin.py b/account/admin.py similarity index 100% rename from zod_bank/account/admin.py rename to account/admin.py diff --git a/zod_bank/account/apps.py b/account/apps.py similarity index 100% rename from zod_bank/account/apps.py rename to account/apps.py diff --git a/zod_bank/account/migrations/0001_initial.py b/account/migrations/0001_initial.py similarity index 100% rename from zod_bank/account/migrations/0001_initial.py rename to account/migrations/0001_initial.py diff --git a/zod_bank/account/migrations/__init__.py b/account/migrations/__init__.py similarity index 100% rename from zod_bank/account/migrations/__init__.py rename to account/migrations/__init__.py diff --git a/zod_bank/account/models.py b/account/models.py similarity index 100% rename from zod_bank/account/models.py rename to account/models.py diff --git a/zod_bank/account/serializers.py b/account/serializers.py similarity index 100% rename from zod_bank/account/serializers.py rename to account/serializers.py diff --git a/zod_bank/account/templates/templated_email/email_base.email b/account/templates/templated_email/email_base.email similarity index 100% rename from zod_bank/account/templates/templated_email/email_base.email rename to account/templates/templated_email/email_base.email diff --git a/zod_bank/account/templates/templated_email/email_otp_verification.email b/account/templates/templated_email/email_otp_verification.email similarity index 100% rename from zod_bank/account/templates/templated_email/email_otp_verification.email rename to account/templates/templated_email/email_otp_verification.email diff --git a/zod_bank/account/templates/templated_email/email_reset_verification.email b/account/templates/templated_email/email_reset_verification.email similarity index 100% rename from zod_bank/account/templates/templated_email/email_reset_verification.email rename to account/templates/templated_email/email_reset_verification.email diff --git a/zod_bank/account/tests.py b/account/tests.py similarity index 100% rename from zod_bank/account/tests.py rename to account/tests.py diff --git a/zod_bank/account/urls.py b/account/urls.py similarity index 100% rename from zod_bank/account/urls.py rename to account/urls.py diff --git a/zod_bank/account/utils.py b/account/utils.py similarity index 100% rename from zod_bank/account/utils.py rename to account/utils.py diff --git a/zod_bank/account/views.py b/account/views.py similarity index 100% rename from zod_bank/account/views.py rename to account/views.py diff --git a/zod_bank/base/__init__.py b/base/__init__.py similarity index 100% rename from zod_bank/base/__init__.py rename to base/__init__.py diff --git a/zod_bank/base/common_email.py b/base/common_email.py similarity index 100% rename from zod_bank/base/common_email.py rename to base/common_email.py diff --git a/zod_bank/base/constants.py b/base/constants.py similarity index 100% rename from zod_bank/base/constants.py rename to base/constants.py diff --git a/zod_bank/base/image_constants.py b/base/image_constants.py similarity index 100% rename from zod_bank/base/image_constants.py rename to base/image_constants.py diff --git a/zod_bank/base/messages.py b/base/messages.py similarity index 100% rename from zod_bank/base/messages.py rename to base/messages.py diff --git a/zod_bank/base/routers.py b/base/routers.py similarity index 100% rename from zod_bank/base/routers.py rename to base/routers.py diff --git a/zod_bank/base/upload_file.py b/base/upload_file.py similarity index 100% rename from zod_bank/base/upload_file.py rename to base/upload_file.py diff --git a/zod_bank/guardian/__init__.py b/guardian/__init__.py similarity index 100% rename from zod_bank/guardian/__init__.py rename to guardian/__init__.py diff --git a/zod_bank/guardian/admin.py b/guardian/admin.py similarity index 100% rename from zod_bank/guardian/admin.py rename to guardian/admin.py diff --git a/zod_bank/guardian/apps.py b/guardian/apps.py similarity index 100% rename from zod_bank/guardian/apps.py rename to guardian/apps.py diff --git a/zod_bank/guardian/migrations/0001_initial.py b/guardian/migrations/0001_initial.py similarity index 100% rename from zod_bank/guardian/migrations/0001_initial.py rename to guardian/migrations/0001_initial.py diff --git a/zod_bank/guardian/migrations/0002_remove_guardian_junior_code.py b/guardian/migrations/0002_remove_guardian_junior_code.py similarity index 100% rename from zod_bank/guardian/migrations/0002_remove_guardian_junior_code.py rename to guardian/migrations/0002_remove_guardian_junior_code.py diff --git a/zod_bank/guardian/migrations/__init__.py b/guardian/migrations/__init__.py similarity index 100% rename from zod_bank/guardian/migrations/__init__.py rename to guardian/migrations/__init__.py diff --git a/zod_bank/guardian/models.py b/guardian/models.py similarity index 100% rename from zod_bank/guardian/models.py rename to guardian/models.py diff --git a/zod_bank/guardian/serializers.py b/guardian/serializers.py similarity index 100% rename from zod_bank/guardian/serializers.py rename to guardian/serializers.py diff --git a/zod_bank/guardian/tasks.py b/guardian/tasks.py similarity index 100% rename from zod_bank/guardian/tasks.py rename to guardian/tasks.py diff --git a/zod_bank/guardian/tests.py b/guardian/tests.py similarity index 100% rename from zod_bank/guardian/tests.py rename to guardian/tests.py diff --git a/zod_bank/guardian/urls.py b/guardian/urls.py similarity index 100% rename from zod_bank/guardian/urls.py rename to guardian/urls.py diff --git a/zod_bank/guardian/views.py b/guardian/views.py similarity index 100% rename from zod_bank/guardian/views.py rename to guardian/views.py diff --git a/zod_bank/junior/__init__.py b/junior/__init__.py similarity index 100% rename from zod_bank/junior/__init__.py rename to junior/__init__.py diff --git a/zod_bank/junior/admin.py b/junior/admin.py similarity index 100% rename from zod_bank/junior/admin.py rename to junior/admin.py diff --git a/zod_bank/junior/apps.py b/junior/apps.py similarity index 100% rename from zod_bank/junior/apps.py rename to junior/apps.py diff --git a/zod_bank/junior/migrations/0001_initial.py b/junior/migrations/0001_initial.py similarity index 100% rename from zod_bank/junior/migrations/0001_initial.py rename to junior/migrations/0001_initial.py diff --git a/zod_bank/junior/migrations/__init__.py b/junior/migrations/__init__.py similarity index 100% rename from zod_bank/junior/migrations/__init__.py rename to junior/migrations/__init__.py diff --git a/zod_bank/junior/models.py b/junior/models.py similarity index 100% rename from zod_bank/junior/models.py rename to junior/models.py diff --git a/zod_bank/junior/serializers.py b/junior/serializers.py similarity index 100% rename from zod_bank/junior/serializers.py rename to junior/serializers.py diff --git a/zod_bank/junior/tests.py b/junior/tests.py similarity index 100% rename from zod_bank/junior/tests.py rename to junior/tests.py diff --git a/zod_bank/junior/urls.py b/junior/urls.py similarity index 100% rename from zod_bank/junior/urls.py rename to junior/urls.py diff --git a/zod_bank/junior/views.py b/junior/views.py similarity index 100% rename from zod_bank/junior/views.py rename to junior/views.py diff --git a/zod_bank/manage.py b/manage.py similarity index 100% rename from zod_bank/manage.py rename to manage.py diff --git a/zod_bank/nginx/django.conf b/nginx/django.conf similarity index 100% rename from zod_bank/nginx/django.conf rename to nginx/django.conf diff --git a/zod_bank/zod_bank/__init__.py b/zod_bank/__init__.py similarity index 100% rename from zod_bank/zod_bank/__init__.py rename to zod_bank/__init__.py diff --git a/zod_bank/zod_bank/asgi.py b/zod_bank/asgi.py similarity index 100% rename from zod_bank/zod_bank/asgi.py rename to zod_bank/asgi.py diff --git a/zod_bank/zod_bank/settings.py b/zod_bank/settings.py similarity index 100% rename from zod_bank/zod_bank/settings.py rename to zod_bank/settings.py diff --git a/zod_bank/zod_bank/urls.py b/zod_bank/urls.py similarity index 100% rename from zod_bank/zod_bank/urls.py rename to zod_bank/urls.py diff --git a/zod_bank/zod_bank/wsgi.py b/zod_bank/wsgi.py similarity index 100% rename from zod_bank/zod_bank/wsgi.py rename to zod_bank/wsgi.py From 7b6d34f3343fb4a14d83e2177ee4fa07d4630308 Mon Sep 17 00:00:00 2001 From: jain Date: Tue, 27 Jun 2023 17:37:12 +0530 Subject: [PATCH 14/19] setting changes --- zod_bank/settings.py | 1 + 1 file changed, 1 insertion(+) diff --git a/zod_bank/settings.py b/zod_bank/settings.py index 79eaeeb..c9afada 100644 --- a/zod_bank/settings.py +++ b/zod_bank/settings.py @@ -182,3 +182,4 @@ EMAIL_HOST_USER = 'infozodbank@gmail.com' EMAIL_HOST_PASSWORD = 'ghwdmznwwslvchga' STATIC_URL = '/static/' +STATIC_ROOT = os.path.join(os.path.dirname(BASE_DIR), 'static') From d208e5252c7961e7420cfe4563240b735e01afb0 Mon Sep 17 00:00:00 2001 From: jain Date: Tue, 27 Jun 2023 19:32:57 +0530 Subject: [PATCH 15/19] jira-13 update country name --- .../migrations/0003_guardian_country_name.py | 18 ++++++++++++++++++ guardian/models.py | 1 + guardian/serializers.py | 1 + junior/migrations/0002_junior_country_name.py | 18 ++++++++++++++++++ junior/models.py | 1 + junior/serializers.py | 1 + 6 files changed, 40 insertions(+) create mode 100644 guardian/migrations/0003_guardian_country_name.py create mode 100644 junior/migrations/0002_junior_country_name.py diff --git a/guardian/migrations/0003_guardian_country_name.py b/guardian/migrations/0003_guardian_country_name.py new file mode 100644 index 0000000..ea9858b --- /dev/null +++ b/guardian/migrations/0003_guardian_country_name.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.2 on 2023-06-27 13:59 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('guardian', '0002_remove_guardian_junior_code'), + ] + + operations = [ + migrations.AddField( + model_name='guardian', + name='country_name', + field=models.CharField(blank=True, default=None, max_length=30, null=True), + ), + ] diff --git a/guardian/models.py b/guardian/models.py index f135bae..d9228b7 100644 --- a/guardian/models.py +++ b/guardian/models.py @@ -13,6 +13,7 @@ class Guardian(models.Model): """Contact details""" 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) """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) diff --git a/guardian/serializers.py b/guardian/serializers.py index e2bd807..c4dcfca 100644 --- a/guardian/serializers.py +++ b/guardian/serializers.py @@ -99,6 +99,7 @@ class CreateGuardianSerializer(serializers.ModelSerializer): guardian.phone = validated_data.get('phone', guardian.phone) guardian.country_code = validated_data.get('country_code', guardian.country_code) guardian.passcode = validated_data.get('passcode', guardian.passcode) + guardian.country_name = validated_data.get('country_name', guardian.country_name) guardian.referral_code_used = validated_data.get('referral_code_used', guardian.referral_code_used) """Complete profile of the junior if below all data are filled""" complete_profile_field = all([guardian.phone, guardian.gender, guardian.family_name, diff --git a/junior/migrations/0002_junior_country_name.py b/junior/migrations/0002_junior_country_name.py new file mode 100644 index 0000000..0dd74bd --- /dev/null +++ b/junior/migrations/0002_junior_country_name.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.2 on 2023-06-27 13:59 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('junior', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='junior', + name='country_name', + field=models.CharField(blank=True, default=None, max_length=30, null=True), + ), + ] diff --git a/junior/models.py b/junior/models.py index 732bb66..b389e3a 100644 --- a/junior/models.py +++ b/junior/models.py @@ -14,6 +14,7 @@ class Junior(models.Model): """Contact details""" phone = models.CharField(max_length=31, null=True, blank=True, default=None) country_code = models.IntegerField(blank=True, null=True) + country_name = models.CharField(max_length=30, null=True, blank=True, default=None) """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) diff --git a/junior/serializers.py b/junior/serializers.py index 5d6df77..54d6fac 100644 --- a/junior/serializers.py +++ b/junior/serializers.py @@ -72,6 +72,7 @@ class CreateJuniorSerializer(serializers.ModelSerializer): junior.guardian_code = validated_data.get('guardian_code', junior.guardian_code) junior.dob = validated_data.get('dob',junior.dob) junior.passcode = validated_data.get('passcode', junior.passcode) + junior.country_name = validated_data.get('country_name', junior.country_name) """Update country code and phone number""" junior.phone = validated_data.get('phone', junior.phone) junior.country_code = validated_data.get('country_code', junior.country_code) From 7b02b7dfbc429016682aab95745e37cbc19cd0d0 Mon Sep 17 00:00:00 2001 From: jain Date: Tue, 27 Jun 2023 20:16:35 +0530 Subject: [PATCH 16/19] changes in setting.py file --- account/serializers.py | 3 ++- account/urls.py | 4 ++-- account/views.py | 39 +++++++++++++++++++++------------------ zod_bank/settings.py | 3 ++- 4 files changed, 27 insertions(+), 22 deletions(-) diff --git a/account/serializers.py b/account/serializers.py index 4ee88c4..afd923c 100644 --- a/account/serializers.py +++ b/account/serializers.py @@ -15,11 +15,12 @@ from rest_framework_simplejwt.tokens import RefreshToken class GoogleSignInSerializer(serializers.Serializer): """Google login Serializer""" + email = serializers.EmailField() def create(self, validated_data): """Create or update user model""" with transaction.atomic(): - print() + 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']) diff --git a/account/urls.py b/account/urls.py index 8462378..eab8be4 100644 --- a/account/urls.py +++ b/account/urls.py @@ -5,14 +5,14 @@ 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, GoogleLoginAPIViewset) + ForgotPasswordAPIView, ResetPasswordAPIView, ChangePasswordAPIView) """Router""" router = routers.SimpleRouter() """API End points with router""" router.register('user', UserLogin, basename='user') router.register('admin', UserLogin, basename='admin') -router.register('google-login', GoogleLoginAPIViewset, basename='admin') +# router.register('google-login', GoogleLoginAPIViewset, basename='admin') 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') diff --git a/account/views.py b/account/views.py index 4fe28a5..69e4e95 100644 --- a/account/views.py +++ b/account/views.py @@ -22,24 +22,27 @@ from rest_framework.response import Response from rest_framework.permissions import IsAuthenticated from templated_email import send_templated_mail -class GoogleLoginAPIViewset(viewsets.ModelViewSet): - """Google Login""" - serializer_class = GoogleSignInSerializer - - def create(self, request, *args, **kwargs): - """ - Override default behaviour of create method - """ - provider_type = [] - serializer = self.get_serializer(data=request.data) - if serializer.is_valid(raise_exception=True): - provider = self.get_provider_view(request.data.get('provider')) - # if User is not authenticated then send error message - if not provider.is_authenticated(request): - return custom_error_response({}, status.HTTP_400_BAD_REQUEST) - - user = serializer.save() - if User.objects.filter(email__iexact=user.email).exists(): +# class GoogleLoginAPIViewset(viewsets.ModelViewSet): +# """Google Login""" +# serializer_class = GoogleSignInSerializer +# +# def create(self, request, *args, **kwargs): +# """ +# Override default behaviour of create method +# """ +# provider_type = [] +# serializer = self.get_serializer(data=request.data) +# if serializer.is_valid(raise_exception=True): +# # provider = self.get_provider_view(request.data.get('provider')) +# # if User is not authenticated then send error message +# # if not provider.is_authenticated(request): +# # return custom_error_response({}, status.HTTP_400_BAD_REQUEST) +# +# user = serializer.save() +# if User.objects.filter(email__iexact=user.email).exists(): +# print("ppppppppppppp") +# 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) diff --git a/zod_bank/settings.py b/zod_bank/settings.py index e1527a4..5ef382e 100644 --- a/zod_bank/settings.py +++ b/zod_bank/settings.py @@ -187,4 +187,5 @@ EMAIL_HOST_USER = os.getenv('EMAIL_HOST_USER') EMAIL_HOST_PASSWORD = os.getenv('EMAIL_HOST_PASSWORD') EMAIL_PORT = os.getenv('EMAIL_PORT') -STATIC_URL = '/static/' +STATIC_URL = 'static/' +STATIC_ROOT = 'static' From d849153becd2708df25e404d4092af5fbf0b9c0b Mon Sep 17 00:00:00 2001 From: jain Date: Tue, 27 Jun 2023 20:43:22 +0530 Subject: [PATCH 17/19] changes in setting.py file --- zod_bank/settings.py | 1 - 1 file changed, 1 deletion(-) diff --git a/zod_bank/settings.py b/zod_bank/settings.py index bd7d3f3..5ef382e 100644 --- a/zod_bank/settings.py +++ b/zod_bank/settings.py @@ -189,4 +189,3 @@ EMAIL_PORT = os.getenv('EMAIL_PORT') STATIC_URL = 'static/' STATIC_ROOT = 'static' - From 4a982f1bafc04e0090508dfdb55fad5e7df99371 Mon Sep 17 00:00:00 2001 From: jain Date: Tue, 27 Jun 2023 20:44:42 +0530 Subject: [PATCH 18/19] changes in setting.py file --- zod_bank/settings.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/zod_bank/settings.py b/zod_bank/settings.py index 5ef382e..1c758b7 100644 --- a/zod_bank/settings.py +++ b/zod_bank/settings.py @@ -173,19 +173,19 @@ 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_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_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 = 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') STATIC_URL = 'static/' STATIC_ROOT = 'static' From f0a2a4bd4b1a9e94ac12eed23261ad31d795e6cc Mon Sep 17 00:00:00 2001 From: jain Date: Tue, 27 Jun 2023 21:34:40 +0530 Subject: [PATCH 19/19] jira-13 update profile --- guardian/serializers.py | 12 +++++++----- junior/serializers.py | 12 +++++++----- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/guardian/serializers.py b/guardian/serializers.py index c4dcfca..f2c0c46 100644 --- a/guardian/serializers.py +++ b/guardian/serializers.py @@ -62,7 +62,8 @@ class CreateGuardianSerializer(serializers.ModelSerializer): """Meta info""" model = Guardian fields = ['first_name', 'last_name', 'email', 'phone', 'family_name', 'gender', 'country_code', - 'dob', 'referral_code', 'passcode', 'is_complete_profile'] + 'dob', 'referral_code', 'passcode', 'is_complete_profile', 'referral_code_used', + 'country_name'] def get_first_name(self,obj): """first name of guardian""" @@ -81,9 +82,10 @@ class CreateGuardianSerializer(serializers.ModelSerializer): user = User.objects.filter(username=self.context['user']).last() if user: """Save first and last name of guardian""" - user.first_name = self.context.get('first_name', user.first_name) - user.last_name = self.context.get('last_name', user.last_name) - user.save() + if self.context.get('first_name') != '' and self.context.get('last_name') != '': + user.first_name = self.context.get('first_name', user.first_name) + user.last_name = self.context.get('last_name', user.last_name) + user.save() """Create guardian data""" guardian, created = Guardian.objects.get_or_create(user=self.context['user']) if created: @@ -102,7 +104,7 @@ class CreateGuardianSerializer(serializers.ModelSerializer): guardian.country_name = validated_data.get('country_name', guardian.country_name) guardian.referral_code_used = validated_data.get('referral_code_used', guardian.referral_code_used) """Complete profile of the junior if below all data are filled""" - complete_profile_field = all([guardian.phone, guardian.gender, guardian.family_name, + complete_profile_field = all([guardian.phone, guardian.gender, guardian.family_name, guardian.country_name, guardian.dob, guardian.country_code, user.first_name, user.last_name]) guardian.is_complete_profile = False if complete_profile_field: diff --git a/junior/serializers.py b/junior/serializers.py index 54d6fac..a741203 100644 --- a/junior/serializers.py +++ b/junior/serializers.py @@ -37,7 +37,8 @@ class CreateJuniorSerializer(serializers.ModelSerializer): """Meta info""" model = Junior fields = ['first_name', 'last_name', 'email', 'phone', 'gender', 'country_code', 'dob', 'referral_code', - 'passcode', 'is_complete_profile', 'guardian_code'] + 'passcode', 'is_complete_profile', 'guardian_code', 'referral_code_used', + 'country_name'] def get_first_name(self,obj): """first name of junior""" @@ -56,9 +57,10 @@ class CreateJuniorSerializer(serializers.ModelSerializer): user = User.objects.filter(username=self.context['user']).last() if user: """Save first and last name of junior""" - user.first_name = self.context.get('first_name', user.first_name) - user.last_name = self.context.get('last_name', user.last_name) - user.save() + if self.context.get('first_name') != '' and self.context.get('last_name') != '': + user.first_name = self.context.get('first_name', user.first_name) + user.last_name = self.context.get('last_name', user.last_name) + user.save() """Create junior data""" junior, created = Junior.objects.get_or_create(auth=self.context['user']) if created: @@ -78,7 +80,7 @@ class CreateJuniorSerializer(serializers.ModelSerializer): junior.country_code = validated_data.get('country_code', junior.country_code) junior.referral_code_used = validated_data.get('referral_code_used', junior.referral_code_used) """Complete profile of the junior if below all data are filled""" - complete_profile_field = all([junior.phone, junior.gender, junior.family_name, + complete_profile_field = all([junior.phone, junior.gender, junior.country_name, junior.dob, junior.country_code, user.first_name, user.last_name]) junior.is_complete_profile = False if complete_profile_field: