Merge pull request #77 from KiwiTechLLC/sprint3

Sprint3
This commit is contained in:
dilipshrivastwa-kiwi
2023-07-18 16:31:20 +05:30
committed by GitHub
14 changed files with 206 additions and 18 deletions

View File

@ -225,7 +225,7 @@ class JuniorSerializer(serializers.ModelSerializer):
return access_token
def get_refresh_token(self, obj):
refresh = RefreshToken.for_user(obj.user)
refresh = RefreshToken.for_user(obj.auth)
refresh_token = str(refresh)
return refresh_token
@ -248,7 +248,7 @@ class JuniorSerializer(serializers.ModelSerializer):
"""Meta info"""
model = Junior
fields = ['id', 'auth_token', 'refresh_token', 'email', 'first_name', 'last_name', 'country_code',
'phone', 'gender', 'dob', 'guardian_code', 'referral_code','is_active',
'phone', 'gender', 'dob', 'guardian_code', 'referral_code','is_active', 'is_password_set',
'is_complete_profile', 'created_at', 'image', 'updated_at', 'user_type', 'country_name','is_invited']
class EmailVerificationSerializer(serializers.ModelSerializer):

View File

@ -15,7 +15,7 @@
<tr>
<td style="padding: 0 27px 22px;">
<p style="margin: 0;font-size: 14px; font-weight: 400; line-height: 21px; color: #1f2532;">
You are receiving this email for join the ZOD bank platform. Please use <b>{{ url }} </b> link to join the platform.
You are receiving this email for joining the ZOD bank platform. Please use <b>{{ url }} </b> link to join the platform.
<br> Your credentials are:- username = <b>{{email}}</b> and password <b>{{password}}</b><br> <br>Below are the steps to complete the account and how to use this platform.
</p>

View File

@ -24,7 +24,7 @@ NUMBER = {
'sixteen': 16, 'seventeen': 17, 'eighteen': 18, 'nineteen': 19, 'twenty': 20,
'twenty_one': 21, 'twenty_two': 22,'twenty_three': 23, 'twenty_four': 24, 'twenty_five': 25,
'thirty': 30, 'forty': 40, 'fifty': 50, 'sixty': 60, 'seventy': 70, 'eighty': 80, 'ninty': 90,
'ninety_nine': 99, 'hundred': 100,
'ninety_nine': 99, 'hundred': 100, 'thirty_six_hundred': 3600
}

View File

@ -0,0 +1,28 @@
# Generated by Django 4.2.2 on 2023-07-18 07:17
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('guardian', '0015_alter_guardian_options_alter_juniortask_options'),
]
operations = [
migrations.AddField(
model_name='juniortask',
name='completed_on',
field=models.DateTimeField(blank=True, null=True),
),
migrations.AddField(
model_name='juniortask',
name='rejected_on',
field=models.DateTimeField(blank=True, null=True),
),
migrations.AddField(
model_name='juniortask',
name='requested_on',
field=models.DateTimeField(blank=True, null=True),
),
]

View File

@ -108,6 +108,12 @@ class JuniorTask(models.Model):
is_active = models.BooleanField(default=True)
"""Task is approved or not"""
is_approved = models.BooleanField(default=False)
"""request task on particular date"""
requested_on = models.DateTimeField(auto_now_add=False, null=True, blank=True)
"""reject task on particular date"""
rejected_on = models.DateTimeField(auto_now_add=False, null=True, blank=True)
"""complete task on particular date"""
completed_on = models.DateTimeField(auto_now_add=False, null=True, blank=True)
"""Profile created and updated time"""
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)

View File

@ -6,6 +6,7 @@ from rest_framework import serializers
from rest_framework_simplejwt.tokens import RefreshToken
from django.db import transaction
from django.contrib.auth.models import User
from datetime import datetime, time
"""Import Django app"""
# Import guardian's model,
# Import junior's model,
@ -23,6 +24,8 @@ from junior.serializers import JuniorDetailSerializer
from base.messages import ERROR_CODE, SUCCESS_CODE
from base.constants import NUMBER, JUN, ZOD, GRD
from junior.models import Junior, JuniorPoints
from .utils import real_time, convert_timedelta_into_datetime
# In this serializer file
@ -201,11 +204,27 @@ class TaskDetailsSerializer(serializers.ModelSerializer):
"""Task detail serializer"""
junior = JuniorDetailSerializer()
remaining_time = serializers.SerializerMethodField('get_remaining_time')
def get_remaining_time(self, obj):
""" remaining time to complete task"""
due_date_datetime = datetime.combine(obj.due_date, datetime.max.time())
# fetch real time
current_datetime = real_time()
# Perform the subtraction
if due_date_datetime > current_datetime:
time_difference = due_date_datetime - current_datetime
time_only = convert_timedelta_into_datetime(time_difference)
return str(time_difference.days) + ' days ' + str(time_only)
return str(NUMBER['zero']) + ' days ' + '00:00:00:00000'
class Meta(object):
"""Meta info"""
model = JuniorTask
fields = ['id', 'guardian', 'task_name', 'task_description', 'points', 'due_date','default_image', 'image',
'junior', 'task_status', 'is_active', 'created_at','updated_at']
'requested_on', 'rejected_on', 'completed_on',
'junior', 'task_status', 'is_active', 'remaining_time', 'created_at','updated_at']
class TopJuniorSerializer(serializers.ModelSerializer):
@ -303,12 +322,14 @@ class ApproveTaskSerializer(serializers.ModelSerializer):
instance.task_status = str(NUMBER['five'])
instance.is_approved = True
junior_data.total_task_points = junior_data.total_task_points + instance.points
instance.completed_on = datetime.today()
junior_data.save()
else:
# reject the task
instance.task_status = str(NUMBER['three'])
instance.is_approved = False
junior_data.total_task_points = junior_data.total_task_points - instance.points
instance.rejected_on = datetime.today()
junior_data.save()
instance.save()
return instance

View File

@ -5,6 +5,12 @@ import oss2
from django.conf import settings
"""Import tempfile"""
import tempfile
# Import date time module's function
from datetime import datetime, time
# Import real time client module
import ntplib
# import Number constant
from base.constants import NUMBER
# Define upload image on
# ali baba cloud
@ -13,6 +19,8 @@ import tempfile
# then check bucket name
# then upload on ali baba
# bucket and reform the image url"""
# fetch real time data without depend on system time
# convert time delta into date time object
def upload_image_to_alibaba(image, filename):
"""upload image on oss alibaba bucket"""
@ -30,3 +38,22 @@ def upload_image_to_alibaba(image, filename):
new_filename = filename.replace(' ', '%20')
return f"https://{settings.ALIYUN_OSS_BUCKET_NAME}.{settings.ALIYUN_OSS_ENDPOINT}/{new_filename}"
def real_time():
# Fetch real time.
# time is not depend on system time
# Get the current datetime
ntp_client = ntplib.NTPClient()
ntp_server = 'pool.ntp.org'
response = ntp_client.request(ntp_server)
current_datetime = datetime.fromtimestamp(response.tx_time)
return current_datetime
def convert_timedelta_into_datetime(time_difference):
# convert timedelta into datetime format
hours = time_difference.seconds // NUMBER['thirty_six_hundred']
minutes = (time_difference.seconds // NUMBER['sixty']) % NUMBER['sixty']
seconds = time_difference.seconds % NUMBER['sixty']
microseconds = time_difference.microseconds
# Create a new time object with the extracted time components
time_only = time(hours, minutes, seconds, microseconds)
return time_only

View File

@ -119,9 +119,16 @@ class TaskListAPIView(viewsets.ModelViewSet):
def list(self, request, *args, **kwargs):
"""Create guardian profile"""
status_value = self.request.GET.get('status')
if str(status_value) == '0':
search = self.request.GET.get('search')
if search and str(status_value) == '0':
queryset = JuniorTask.objects.filter(guardian__user=request.user,
task_name__icontains=search).order_by('due_date', 'created_at')
elif search and str(status_value) != '0':
queryset = JuniorTask.objects.filter(guardian__user=request.user,task_name__icontains=search,
task_status=status_value).order_by('due_date', 'created_at')
if search is None and str(status_value) == '0':
queryset = JuniorTask.objects.filter(guardian__user=request.user).order_by('due_date', 'created_at')
else:
elif search is None and str(status_value) != '0':
queryset = JuniorTask.objects.filter(guardian__user=request.user,
task_status=status_value).order_by('due_date','created_at')
paginator = self.pagination_class()

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2.2 on 2023-07-18 09:28
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('junior', '0013_alter_junior_options_alter_juniorpoints_options'),
]
operations = [
migrations.AddField(
model_name='junior',
name='is_password_set',
field=models.BooleanField(default=True),
),
]

View File

@ -63,6 +63,8 @@ class Junior(models.Model):
is_invited = models.BooleanField(default=False)
# Profile activity"""
is_active = models.BooleanField(default=True)
# check password is set or not
is_password_set = models.BooleanField(default=True)
# junior profile is complete or not"""
is_complete_profile = models.BooleanField(default=False)
# passcode of the junior profile"""

View File

@ -3,7 +3,7 @@
from rest_framework import serializers
from django.contrib.auth.models import User
from django.db import transaction
import random
from datetime import datetime
from django.utils import timezone
from rest_framework_simplejwt.tokens import RefreshToken
@ -277,12 +277,13 @@ class AddJuniorSerializer(serializers.ModelSerializer):
relationship=validated_data.get('relationship'),
junior_code=generate_code(JUN, user_data.id),
referral_code=generate_code(ZOD, user_data.id),
referral_code_used=guardian_data.referral_code)
referral_code_used=guardian_data.referral_code,
is_password_set=False, is_verified=True)
"""Generate otp"""
otp_value = generate_otp()
expiry_time = timezone.now() + timezone.timedelta(days=1)
UserEmailOtp.objects.create(email=email, otp=otp_value,
user_type='1', expired_at=expiry_time)
user_type='1', expired_at=expiry_time, is_verified=True)
"""Send email to the register user"""
send_otp_email(email, otp_value)
"""Notification email"""
@ -305,3 +306,17 @@ class RemoveJuniorSerializer(serializers.ModelSerializer):
instance.save()
return instance
class CompleteTaskSerializer(serializers.ModelSerializer):
"""User task Serializer"""
class Meta(object):
"""Meta class"""
model = JuniorTask
fields = ('id', 'image')
def update(self, instance, validated_data):
instance.image = validated_data.get('image', instance.image)
instance.requested_on = datetime.today()
instance.task_status = str(NUMBER['four'])
instance.is_approved = False
instance.save()
return instance

View File

@ -2,7 +2,8 @@
"""Django import"""
from django.urls import path, include
from .views import (UpdateJuniorProfile, ValidateGuardianCode, JuniorListAPIView, AddJuniorAPIView,
InvitedJuniorAPIView, FilterJuniorAPIView, RemoveJuniorAPIView)
InvitedJuniorAPIView, FilterJuniorAPIView, RemoveJuniorAPIView, JuniorTaskListAPIView,
CompleteJuniorTaskAPIView)
"""Third party import"""
from rest_framework import routers
@ -17,7 +18,8 @@ router = routers.SimpleRouter()
# junior list,
# add junior list, invited junior,
# filter-junior,
# remove junior"""
# remove junior,
# junior task list
"""API End points with router"""
router.register('create-junior-profile', UpdateJuniorProfile, basename='profile-update')
# validate guardian code API"""
@ -30,8 +32,11 @@ router.register('add-junior', AddJuniorAPIView, basename='add-junior')
router.register('invited-junior', InvitedJuniorAPIView, basename='invited-junior')
# Filter junior list API"""
router.register('filter-junior', FilterJuniorAPIView, basename='filter-junior')
# junior's task list API"""
router.register('junior-task-list', JuniorTaskListAPIView, basename='junior-task-list')
# Define url pattern"""
urlpatterns = [
path('api/v1/', include(router.urls)),
path('api/v1/remove-junior/', RemoveJuniorAPIView.as_view())
path('api/v1/remove-junior/', RemoveJuniorAPIView.as_view()),
path('api/v1/complete-task/', CompleteJuniorTaskAPIView.as_view())
]

View File

@ -17,8 +17,9 @@ from rest_framework.pagination import PageNumberPagination
# Import account's task
from junior.models import Junior
from .serializers import (CreateJuniorSerializer, JuniorDetailListSerializer, AddJuniorSerializer,\
RemoveJuniorSerializer)
from guardian.models import Guardian
RemoveJuniorSerializer, CompleteTaskSerializer)
from guardian.models import Guardian, JuniorTask
from guardian.serializers import TaskDetailsSerializer
from base.messages import ERROR_CODE, SUCCESS_CODE
from base.constants import NUMBER
from account.utils import custom_response, custom_error_response
@ -163,7 +164,7 @@ class FilterJuniorAPIView(viewsets.ModelViewSet):
class RemoveJuniorAPIView(views.APIView):
"""Eater Update API"""
"""Remove junior API"""
serializer_class = RemoveJuniorSerializer
model = Junior
permission_classes = [IsAuthenticated]
@ -184,3 +185,60 @@ class RemoveJuniorAPIView(views.APIView):
return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST)
else:
return custom_error_response(ERROR_CODE['2034'], response_status=status.HTTP_400_BAD_REQUEST)
class JuniorTaskListAPIView(viewsets.ModelViewSet):
"""Update guardian profile"""
serializer_class = TaskDetailsSerializer
permission_classes = [IsAuthenticated]
pagination_class = PageNumberPagination
queryset = JuniorTask.objects.all()
def list(self, request, *args, **kwargs):
"""Create guardian profile"""
status_value = self.request.GET.get('status')
search = self.request.GET.get('search')
if search and str(status_value) == '0':
queryset = JuniorTask.objects.filter(junior__auth=request.user,
task_name__icontains=search).order_by('due_date', 'created_at')
elif search and str(status_value) != '0':
queryset = JuniorTask.objects.filter(junior__auth=request.user, task_name__icontains=search,
task_status=status_value).order_by('due_date', 'created_at')
if search is None and str(status_value) == '0':
queryset = JuniorTask.objects.filter(junior__auth=request.user).order_by('due_date', 'created_at')
elif search is None and str(status_value) != '0':
queryset = JuniorTask.objects.filter(junior__auth=request.user,
task_status=status_value).order_by('due_date','created_at')
paginator = self.pagination_class()
# use Pagination
paginated_queryset = paginator.paginate_queryset(queryset, request)
# use TaskDetailsSerializer serializer
serializer = TaskDetailsSerializer(paginated_queryset, many=True)
return custom_response(None, serializer.data, response_status=status.HTTP_200_OK)
class CompleteJuniorTaskAPIView(views.APIView):
"""Update junior task API"""
serializer_class = CompleteTaskSerializer
model = JuniorTask
permission_classes = [IsAuthenticated]
def put(self, request, format=None):
task_id = self.request.data.get('task_id')
image = request.data['image']
if image and image.size == NUMBER['zero']:
return custom_error_response(ERROR_CODE['2035'], response_status=status.HTTP_400_BAD_REQUEST)
filename = f"images/{image.name}"
image_url = upload_image_to_alibaba(image, filename)
# fetch junior query
task_queryset = JuniorTask.objects.filter(id=task_id, junior__auth__email=self.request.user).last()
if task_queryset:
# use RemoveJuniorSerializer serializer
serializer = CompleteTaskSerializer(task_queryset, data={'image': image_url}, partial=True)
if serializer.is_valid():
# save serializer
serializer.save()
return custom_response(SUCCESS_CODE['3022'], serializer.data, response_status=status.HTTP_200_OK)
return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST)
else:
return custom_error_response(ERROR_CODE['2034'], response_status=status.HTTP_400_BAD_REQUEST)

View File

@ -105,11 +105,12 @@ REST_FRAMEWORK = {
'rest_framework.authentication.BasicAuthentication',
'rest_framework_simplejwt.authentication.JWTAuthentication',],
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 5,
'PAGE_SIZE': 10,
}
# define jwt token
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(hours=2, minutes=59, seconds=59, microseconds=999999),
# 'ACCESS_TOKEN_LIFETIME': timedelta(hours=2, minutes=59, seconds=59, microseconds=999999),
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5),
'REFRESH_TOKEN_LIFETIME': timedelta(hours=71, minutes=59, seconds=59, microseconds=999999),
}
# Database