Merge pull request #222 from KiwiTechLLC/sprint5

Sprint5
This commit is contained in:
dilipshrivastwa-kiwi
2023-08-18 16:31:35 +05:30
committed by GitHub
22 changed files with 332 additions and 56 deletions

View File

@ -7,7 +7,9 @@ from rest_framework.renderers import JSONRenderer
from account.utils import custom_error_response from account.utils import custom_error_response
from account.models import UserDeviceDetails from account.models import UserDeviceDetails
from base.messages import ERROR_CODE, SUCCESS_CODE from base.messages import ERROR_CODE, SUCCESS_CODE
from base.constants import NUMBER
from junior.models import Junior
from guardian.models import Guardian
# Custom middleware # Custom middleware
# when user login with # when user login with
# multiple device simultaneously # multiple device simultaneously
@ -15,6 +17,16 @@ from base.messages import ERROR_CODE, SUCCESS_CODE
# multiple devices only # multiple devices only
# user can login in single # user can login in single
# device at a time""" # device at a time"""
def custom_response(custom_error):
"""custom response"""
response = Response(custom_error.data, status=status.HTTP_404_NOT_FOUND)
# Set content type header to "application/json"
response['Content-Type'] = 'application/json'
# Render the response as JSON
renderer = JSONRenderer()
response.content = renderer.render(response.data)
return response
class CustomMiddleware(object): class CustomMiddleware(object):
"""Custom middleware""" """Custom middleware"""
def __init__(self, get_response): def __init__(self, get_response):
@ -26,15 +38,21 @@ class CustomMiddleware(object):
response = self.get_response(request) response = self.get_response(request)
# Code to be executed after the view is called # Code to be executed after the view is called
device_id = request.META.get('HTTP_DEVICE_ID') device_id = request.META.get('HTTP_DEVICE_ID')
user_type = request.META.get('HTTP_USER_TYPE')
if request.user.is_authenticated: if request.user.is_authenticated:
"""device details""" """device details"""
device_details = UserDeviceDetails.objects.filter(user=request.user, device_id=device_id).last() device_details = UserDeviceDetails.objects.filter(user=request.user, device_id=device_id).last()
if user_type and str(user_type) == str(NUMBER['one']):
junior = Junior.objects.filter(auth=request.user, is_active=False).last()
if junior:
custom_error = custom_error_response(ERROR_CODE['2075'], response_status=status.HTTP_404_NOT_FOUND)
response = custom_response(custom_error)
elif user_type and str(user_type) == str(NUMBER['two']):
guardian = Guardian.objects.filter(user=request.user, is_active=False).last()
if guardian:
custom_error = custom_error_response(ERROR_CODE['2075'], response_status=status.HTTP_404_NOT_FOUND)
response = custom_response(custom_error)
if device_id and not device_details: if device_id and not device_details:
custom_error = custom_error_response(ERROR_CODE['2037'], response_status=status.HTTP_404_NOT_FOUND) custom_error = custom_error_response(ERROR_CODE['2037'], response_status=status.HTTP_404_NOT_FOUND)
response = Response(custom_error.data, status=status.HTTP_404_NOT_FOUND) response = custom_response(custom_error)
# Set content type header to "application/json"
response['Content-Type'] = 'application/json'
# Render the response as JSON
renderer = JSONRenderer()
response.content = renderer.render(response.data)
return response return response

View File

@ -244,7 +244,7 @@ class GuardianSerializer(serializers.ModelSerializer):
"""Meta info""" """Meta info"""
model = Guardian model = Guardian
fields = ['id', 'auth_token', 'refresh_token', 'email', 'first_name', 'last_name', 'country_code', fields = ['id', 'auth_token', 'refresh_token', 'email', 'first_name', 'last_name', 'country_code',
'phone', 'family_name', 'gender', 'dob', 'referral_code', 'is_active', 'phone', 'family_name', 'gender', 'dob', 'referral_code', 'is_active', 'is_deleted',
'is_complete_profile', 'passcode', 'image', 'created_at', 'updated_at', 'user_type', 'country_name'] 'is_complete_profile', 'passcode', 'image', 'created_at', 'updated_at', 'user_type', 'country_name']
@ -287,7 +287,8 @@ class JuniorSerializer(serializers.ModelSerializer):
model = Junior model = Junior
fields = ['id', 'auth_token', 'refresh_token', 'email', 'first_name', 'last_name', 'country_code', fields = ['id', 'auth_token', 'refresh_token', 'email', 'first_name', 'last_name', 'country_code',
'phone', 'gender', 'dob', 'guardian_code', 'referral_code','is_active', 'is_password_set', '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'] 'is_complete_profile', 'created_at', 'image', 'updated_at', 'user_type', 'country_name','is_invited',
'is_deleted']
class EmailVerificationSerializer(serializers.ModelSerializer): class EmailVerificationSerializer(serializers.ModelSerializer):
"""Email verification serializer""" """Email verification serializer"""

View File

@ -8,14 +8,14 @@
<tr> <tr>
<td style="padding: 0 27px 15px;"> <td style="padding: 0 27px 15px;">
<p style="margin: 0; font-size: 16px; line-height: 20px; padding: 36px 0 0; font-weight: 500; color: #1f2532;"> <p style="margin: 0; font-size: 16px; line-height: 20px; padding: 36px 0 0; font-weight: 500; color: #1f2532;">
Hi {{name}}, Hi Support Team,
</p> </p>
</td> </td>
</tr> </tr>
<tr> <tr>
<td style="padding: 0 27px 22px;"> <td style="padding: 0 27px 22px;">
<p style="margin: 0;font-size: 14px; font-weight: 400; line-height: 21px; color: #1f2532;"> <p style="margin: 0;font-size: 14px; font-weight: 400; line-height: 21px; color: #1f2532;">
<b>{{name}}</b> have some queries and need some support. Please support them by using their email address <b> {{sender}}</b>. <br> <br> <b>Queries are:- </b> <br> {{ message }} <b>{{name}}</b> have some queries and need some support. Please support them by using their email address <b> {{sender}}</b>. <br> <br> <b>Queries are:- </b> <br><li> {{ message }}</li>
</p> </p>
</td> </td>
</tr> </tr>

View File

@ -95,6 +95,7 @@ def junior_account_update(user_tb):
junior_data.is_verified = False junior_data.is_verified = False
junior_data.guardian_code = '{}' junior_data.guardian_code = '{}'
junior_data.guardian_code_status = str(NUMBER['one']) junior_data.guardian_code_status = str(NUMBER['one'])
junior_data.is_deleted = True
junior_data.save() junior_data.save()
JuniorPoints.objects.filter(junior=junior_data).delete() JuniorPoints.objects.filter(junior=junior_data).delete()
@ -105,6 +106,7 @@ def guardian_account_update(user_tb):
# Update guardian account # Update guardian account
guardian_data.is_active = False guardian_data.is_active = False
guardian_data.is_verified = False guardian_data.is_verified = False
guardian_data.is_deleted = True
guardian_data.save() guardian_data.save()
jun_data = Junior.objects.filter(guardian_code__icontains=str(guardian_data.guardian_code)) jun_data = Junior.objects.filter(guardian_code__icontains=str(guardian_data.guardian_code))
"""Disassociate relation between guardian and junior""" """Disassociate relation between guardian and junior"""

View File

@ -287,7 +287,7 @@ class UserLogin(viewsets.ViewSet):
def login(self, request): def login(self, request):
username = request.data.get('username') username = request.data.get('username')
password = request.data.get('password') password = request.data.get('password')
user_type = request.data.get('user_type') user_type = request.META.get('HTTP_USER_TYPE')
device_id = request.META.get('HTTP_DEVICE_ID') device_id = request.META.get('HTTP_DEVICE_ID')
user = authenticate(request, username=username, password=password) user = authenticate(request, username=username, password=password)

View File

@ -96,9 +96,12 @@ ERROR_CODE = {
"2067": "Action not allowed. User type missing.", "2067": "Action not allowed. User type missing.",
"2068": "No guardian associated with this junior", "2068": "No guardian associated with this junior",
"2069": "Invalid user type", "2069": "Invalid user type",
"2070": "You did not find as a guardian", "2070": "You do not find as a guardian",
"2071": "You did not find as a junior" "2071": "You do not find as a junior",
"2072": "You can not approve or reject this task because junior does not exist in the system",
"2073": "You can not approve or reject this junior because junior does not exist in the system",
"2074": "You can not complete this task because you does not exist in the system",
"2075": "Your account is deactivated. Please contact with admin"
} }
"""Success message code""" """Success message code"""
SUCCESS_CODE = { SUCCESS_CODE = {
@ -163,6 +166,8 @@ SUCCESS_CODE = {
"3043": "Read article card successfully", "3043": "Read article card successfully",
# remove guardian code request # remove guardian code request
"3044": "Remove guardian code request successfully", "3044": "Remove guardian code request successfully",
# create faq
"3045": "Create FAQ data"
} }
"""status code error""" """status code error"""

Binary file not shown.

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2.2 on 2023-08-17 12:45
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('guardian', '0020_alter_juniortask_task_status'),
]
operations = [
migrations.AddField(
model_name='guardian',
name='is_deleted',
field=models.BooleanField(default=False),
),
]

View File

@ -57,6 +57,8 @@ class Guardian(models.Model):
is_invited = models.BooleanField(default=False) is_invited = models.BooleanField(default=False)
# Profile activity""" # Profile activity"""
is_password_set = models.BooleanField(default=True) is_password_set = models.BooleanField(default=True)
# guardian profile deleted or not"""
is_deleted = models.BooleanField(default=False)
"""Profile activity""" """Profile activity"""
is_active = models.BooleanField(default=True) is_active = models.BooleanField(default=True)
"""guardian is verified or not""" """guardian is verified or not"""

View File

@ -1,6 +1,7 @@
"""Serializer of Guardian""" """Serializer of Guardian"""
# third party imports # third party imports
import logging import logging
from django.contrib.auth import password_validation
from rest_framework import serializers from rest_framework import serializers
# Import Refresh token of jwt # Import Refresh token of jwt
from rest_framework_simplejwt.tokens import RefreshToken from rest_framework_simplejwt.tokens import RefreshToken
@ -30,7 +31,8 @@ from .utils import real_time, convert_timedelta_into_datetime, update_referral_p
from notifications.constants import TASK_POINTS, TASK_REJECTED from notifications.constants import TASK_POINTS, TASK_REJECTED
# send notification function # send notification function
from notifications.utils import send_notification, send_notification_to_junior from notifications.utils import send_notification, send_notification_to_junior
from django.core.exceptions import ValidationError
from django.utils.translation import gettext as _
# In this serializer file # In this serializer file
# define user serializer, # define user serializer,
@ -42,10 +44,45 @@ from notifications.utils import send_notification, send_notification_to_junior
# guardian profile serializer, # guardian profile serializer,
# approve junior serializer, # approve junior serializer,
# approve task serializer, # approve task serializer,
from rest_framework import serializers
class PasswordValidator:
def __init__(self, min_length=8, max_length=None, require_uppercase=True, require_numbers=True):
self.min_length = min_length
self.max_length = max_length
self.require_uppercase = require_uppercase
self.require_numbers = require_numbers
def __call__(self, value):
self.enforce_password_policy(value)
def enforce_password_policy(self, password):
special_characters = "!@#$%^&*()_-+=<>?/[]{}|"
if len(password) < self.min_length:
raise serializers.ValidationError(
_("Password must be at least %(min_length)d characters long.") % {'min_length': self.min_length}
)
if self.max_length is not None and len(password) > self.max_length:
raise serializers.ValidationError(
_("Password must be at most %(max_length)d characters long.") % {'max_length': self.max_length}
)
if self.require_uppercase and not any(char.isupper() for char in password):
raise serializers.ValidationError(_("Password must contain at least one uppercase letter."))
if self.require_numbers and not any(char.isdigit() for char in password):
raise serializers.ValidationError(_("Password must contain at least one digit."))
if self.require_numbers and not any(char in special_characters for char in password):
raise serializers.ValidationError(_("Password must contain at least one special character."))
class UserSerializer(serializers.ModelSerializer): class UserSerializer(serializers.ModelSerializer):
"""User serializer""" """User serializer"""
auth_token = serializers.SerializerMethodField('get_auth_token') auth_token = serializers.SerializerMethodField('get_auth_token')
password = serializers.CharField(write_only=True, validators=[PasswordValidator()])
class Meta(object): class Meta(object):
"""Meta info""" """Meta info"""
@ -214,7 +251,7 @@ class GuardianDetailSerializer(serializers.ModelSerializer):
"""Meta info""" """Meta info"""
model = Guardian model = Guardian
fields = ['id', 'email', 'first_name', 'last_name', 'country_code', 'phone', 'gender', 'dob', fields = ['id', 'email', 'first_name', 'last_name', 'country_code', 'phone', 'gender', 'dob',
'guardian_code','is_active', 'is_complete_profile', 'created_at', 'image', 'guardian_code','is_active', 'is_complete_profile', 'created_at', 'image', 'is_deleted'
'updated_at'] 'updated_at']
class TaskDetailsSerializer(serializers.ModelSerializer): class TaskDetailsSerializer(serializers.ModelSerializer):
"""Task detail serializer""" """Task detail serializer"""
@ -340,7 +377,7 @@ class GuardianProfileSerializer(serializers.ModelSerializer):
fields = ['id', 'email', 'first_name', 'last_name', 'country_name','country_code', 'phone', 'gender', 'dob', fields = ['id', 'email', 'first_name', 'last_name', 'country_name','country_code', 'phone', 'gender', 'dob',
'guardian_code', 'notification_count', 'total_count', 'complete_field_count', 'referral_code', 'guardian_code', 'notification_count', 'total_count', 'complete_field_count', 'referral_code',
'is_active', 'is_complete_profile', 'created_at', 'image', 'signup_method', 'is_active', 'is_complete_profile', 'created_at', 'image', 'signup_method',
'updated_at', 'passcode'] 'updated_at', 'passcode','is_deleted']
class ApproveJuniorSerializer(serializers.ModelSerializer): class ApproveJuniorSerializer(serializers.ModelSerializer):

View File

@ -255,31 +255,29 @@ class ApproveJuniorAPIView(viewsets.ViewSet):
serializer_class = ApproveJuniorSerializer serializer_class = ApproveJuniorSerializer
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]
def get_queryset(self):
"""Get the queryset for the view"""
guardian = Guardian.objects.filter(user__email=self.request.user).last()
# fetch junior query
junior_queryset = Junior.objects.filter(id=self.request.data.get('junior_id')).last()
return guardian, junior_queryset
def create(self, request, *args, **kwargs): def create(self, request, *args, **kwargs):
""" junior list""" """ junior list"""
try: try:
queryset = self.get_queryset() guardian = Guardian.objects.filter(user__email=self.request.user).last()
# fetch junior query
junior_queryset = Junior.objects.filter(id=self.request.data.get('junior_id')).last()
if junior_queryset and junior_queryset.is_deleted:
return custom_error_response(ERROR_CODE['2073'], response_status=status.HTTP_400_BAD_REQUEST)
# action 1 is use for approve and 2 for reject # action 1 is use for approve and 2 for reject
if request.data['action'] == '1': if request.data['action'] == '1':
# use ApproveJuniorSerializer serializer # use ApproveJuniorSerializer serializer
serializer = ApproveJuniorSerializer(context={"guardian_code": queryset[0].guardian_code, serializer = ApproveJuniorSerializer(context={"guardian_code": guardian.guardian_code,
"junior": queryset[1], "action": request.data['action']}, "junior": junior_queryset, "action": request.data['action']},
data=request.data) data=request.data)
if serializer.is_valid(): if serializer.is_valid():
# save serializer # save serializer
serializer.save() serializer.save()
return custom_response(SUCCESS_CODE['3023'], serializer.data, response_status=status.HTTP_200_OK) return custom_response(SUCCESS_CODE['3023'], serializer.data, response_status=status.HTTP_200_OK)
else: else:
queryset[1].guardian_code = None junior_queryset.guardian_code = None
queryset[1].guardian_code_status = str(NUMBER['one']) junior_queryset.guardian_code_status = str(NUMBER['one'])
queryset[1].save() junior_queryset.save()
return custom_response(SUCCESS_CODE['3024'], response_status=status.HTTP_200_OK) return custom_response(SUCCESS_CODE['3024'], response_status=status.HTTP_200_OK)
except Exception as e: except Exception as e:
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST) return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
@ -290,34 +288,31 @@ class ApproveTaskAPIView(viewsets.ViewSet):
serializer_class = ApproveTaskSerializer serializer_class = ApproveTaskSerializer
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]
def get_queryset(self):
"""Get the queryset for the view"""
guardian = Guardian.objects.filter(user__email=self.request.user).last()
# task query
task_queryset = JuniorTask.objects.filter(id=self.request.data.get('task_id'),
guardian=guardian,
junior=self.request.data.get('junior_id')).last()
return guardian, task_queryset
def create(self, request, *args, **kwargs): def create(self, request, *args, **kwargs):
""" junior list""" """ junior list"""
# action 1 is use for approve and 2 for reject # action 1 is use for approve and 2 for reject
try: try:
queryset = self.get_queryset() guardian = Guardian.objects.filter(user__email=self.request.user).last()
# task query
task_queryset = JuniorTask.objects.filter(id=self.request.data.get('task_id'),
guardian=guardian,
junior=self.request.data.get('junior_id')).last()
if task_queryset and task_queryset.junior.is_deleted:
return custom_error_response(ERROR_CODE['2072'], response_status=status.HTTP_400_BAD_REQUEST)
# use ApproveJuniorSerializer serializer # use ApproveJuniorSerializer serializer
serializer = ApproveTaskSerializer(context={"guardian_code": queryset[0].guardian_code, serializer = ApproveTaskSerializer(context={"guardian_code": guardian.guardian_code,
"task_instance": queryset[1], "task_instance": task_queryset,
"action": str(request.data['action']), "action": str(request.data['action']),
"junior": self.request.data['junior_id']}, "junior": self.request.data['junior_id']},
data=request.data) data=request.data)
unexpected_task_status = [str(NUMBER['five']), str(NUMBER['six'])] unexpected_task_status = [str(NUMBER['five']), str(NUMBER['six'])]
if (str(request.data['action']) == str(NUMBER['one']) and serializer.is_valid() if (str(request.data['action']) == str(NUMBER['one']) and serializer.is_valid()
and queryset[1] and queryset[1].task_status not in unexpected_task_status): and task_queryset and task_queryset.task_status not in unexpected_task_status):
# save serializer # save serializer
serializer.save() serializer.save()
return custom_response(SUCCESS_CODE['3025'], response_status=status.HTTP_200_OK) return custom_response(SUCCESS_CODE['3025'], response_status=status.HTTP_200_OK)
elif (str(request.data['action']) == str(NUMBER['two']) and serializer.is_valid() elif (str(request.data['action']) == str(NUMBER['two']) and serializer.is_valid()
and queryset[1] and queryset[1].task_status not in unexpected_task_status): and task_queryset and task_queryset.task_status not in unexpected_task_status):
# save serializer # save serializer
serializer.save() serializer.save()
return custom_response(SUCCESS_CODE['3026'], response_status=status.HTTP_200_OK) return custom_response(SUCCESS_CODE['3026'], response_status=status.HTTP_200_OK)

View File

@ -3,8 +3,9 @@
from django.contrib import admin from django.contrib import admin
"""Import Django app""" """Import Django app"""
from .models import (Junior, JuniorPoints, JuniorGuardianRelationship, JuniorArticlePoints, JuniorArticle, from .models import (Junior, JuniorPoints, JuniorGuardianRelationship, JuniorArticlePoints, JuniorArticle,
JuniorArticleCard) JuniorArticleCard, FAQ)
# Register your models here. # Register your models here.
admin.site.register(FAQ)
@admin.register(JuniorArticle) @admin.register(JuniorArticle)
class JuniorArticleAdmin(admin.ModelAdmin): class JuniorArticleAdmin(admin.ModelAdmin):
"""Junior Admin""" """Junior Admin"""

View File

@ -0,0 +1,39 @@
# Generated by Django 4.2.2 on 2023-08-17 09:04
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('junior', '0025_alter_juniorarticle_junior'),
]
operations = [
migrations.CreateModel(
name='FAQ',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('question', models.IntegerField(max_length=100)),
('description', models.CharField(max_length=500)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
],
options={
'verbose_name': 'FAQ',
'verbose_name_plural': 'FAQ',
},
),
migrations.AlterModelOptions(
name='juniorarticle',
options={'verbose_name': 'Junior Article', 'verbose_name_plural': 'Junior Article'},
),
migrations.AlterModelOptions(
name='juniorarticlecard',
options={'verbose_name': 'Junior Article Card', 'verbose_name_plural': 'Junior Article Card'},
),
migrations.AlterModelOptions(
name='juniorarticlepoints',
options={'verbose_name': 'Junior Article Points', 'verbose_name_plural': 'Junior Article Points'},
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2.2 on 2023-08-17 09:37
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('junior', '0026_faq_alter_juniorarticle_options_and_more'),
]
operations = [
migrations.AlterField(
model_name='faq',
name='question',
field=models.CharField(max_length=100),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2.2 on 2023-08-17 10:28
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('junior', '0027_alter_faq_question'),
]
operations = [
migrations.AddField(
model_name='faq',
name='status',
field=models.IntegerField(blank=True, default=1, null=True),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2.2 on 2023-08-17 12:45
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('junior', '0028_faq_status'),
]
operations = [
migrations.AddField(
model_name='junior',
name='is_deleted',
field=models.BooleanField(default=False),
),
]

View File

@ -68,6 +68,8 @@ class Junior(models.Model):
is_password_set = models.BooleanField(default=True) is_password_set = models.BooleanField(default=True)
# junior profile is complete or not""" # junior profile is complete or not"""
is_complete_profile = models.BooleanField(default=False) is_complete_profile = models.BooleanField(default=False)
# junior profile deleted or not"""
is_deleted = models.BooleanField(default=False)
# passcode of the junior profile""" # passcode of the junior profile"""
passcode = models.IntegerField(null=True, blank=True, default=None) passcode = models.IntegerField(null=True, blank=True, default=None)
# junior is verified or not""" # junior is verified or not"""
@ -158,6 +160,12 @@ class JuniorArticlePoints(models.Model):
created_at = models.DateTimeField(auto_now_add=True) created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True) updated_at = models.DateTimeField(auto_now=True)
class Meta(object):
""" Meta class """
verbose_name = 'Junior Article Points'
# another name of the model"""
verbose_name_plural = 'Junior Article Points'
def __str__(self): def __str__(self):
"""Return title""" """Return title"""
return f'{self.id} | {self.question}' return f'{self.id} | {self.question}'
@ -178,6 +186,12 @@ class JuniorArticle(models.Model):
created_at = models.DateTimeField(auto_now_add=True) created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True) updated_at = models.DateTimeField(auto_now=True)
class Meta(object):
""" Meta class """
verbose_name = 'Junior Article'
# another name of the model"""
verbose_name_plural = 'Junior Article'
def __str__(self): def __str__(self):
"""Return title""" """Return title"""
return f'{self.id} | {self.article}' return f'{self.id} | {self.article}'
@ -197,6 +211,34 @@ class JuniorArticleCard(models.Model):
created_at = models.DateTimeField(auto_now_add=True) created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True) updated_at = models.DateTimeField(auto_now=True)
class Meta(object):
""" Meta class """
verbose_name = 'Junior Article Card'
# another name of the model"""
verbose_name_plural = 'Junior Article Card'
def __str__(self): def __str__(self):
"""Return title""" """Return title"""
return f'{self.id} | {self.article}' return f'{self.id} | {self.article}'
class FAQ(models.Model):
"""FAQ model"""
# questions"""
question = models.CharField(max_length=100)
# answer"""
description = models.CharField(max_length=500)
# status
status = models.IntegerField(default=1, null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta(object):
""" Meta class """
verbose_name = 'FAQ'
# another name of the model"""
verbose_name_plural = 'FAQ'
def __str__(self):
"""Return email id"""
return f'{self.question}'

View File

@ -12,7 +12,7 @@ from rest_framework_simplejwt.tokens import RefreshToken
# local imports # local imports
from account.utils import send_otp_email, generate_code from account.utils import send_otp_email, generate_code
from junior.models import Junior, JuniorPoints, JuniorGuardianRelationship, JuniorArticlePoints from junior.models import Junior, JuniorPoints, JuniorGuardianRelationship, JuniorArticlePoints, FAQ
from guardian.tasks import generate_otp from guardian.tasks import generate_otp
from base.messages import ERROR_CODE, SUCCESS_CODE from base.messages import ERROR_CODE, SUCCESS_CODE
from base.constants import (PENDING, IN_PROGRESS, REJECTED, REQUESTED, COMPLETED, NUMBER, JUN, ZOD, EXPIRED, from base.constants import (PENDING, IN_PROGRESS, REJECTED, REQUESTED, COMPLETED, NUMBER, JUN, ZOD, EXPIRED,
@ -147,7 +147,7 @@ class JuniorDetailSerializer(serializers.ModelSerializer):
model = Junior model = Junior
fields = ['id', 'email', 'first_name', 'last_name', 'country_code', 'phone', 'gender', 'dob', fields = ['id', 'email', 'first_name', 'last_name', 'country_code', 'phone', 'gender', 'dob',
'guardian_code', 'image', 'is_invited', 'referral_code','is_active', 'is_complete_profile', 'guardian_code', 'image', 'is_invited', 'referral_code','is_active', 'is_complete_profile',
'created_at', 'image', 'updated_at'] 'created_at', 'image', 'is_deleted', 'updated_at']
class JuniorDetailListSerializer(serializers.ModelSerializer): class JuniorDetailListSerializer(serializers.ModelSerializer):
"""junior serializer""" """junior serializer"""
@ -214,7 +214,8 @@ class JuniorDetailListSerializer(serializers.ModelSerializer):
fields = ['id', 'email', 'first_name', 'last_name', 'country_code', 'country_name', 'phone', 'gender', 'dob', fields = ['id', 'email', 'first_name', 'last_name', 'country_code', 'country_name', 'phone', 'gender', 'dob',
'guardian_code', 'referral_code','is_active', 'is_complete_profile', 'created_at', 'image', 'guardian_code', 'referral_code','is_active', 'is_complete_profile', 'created_at', 'image',
'updated_at', 'assigned_task','points', 'pending_task', 'in_progress_task', 'completed_task', 'updated_at', 'assigned_task','points', 'pending_task', 'in_progress_task', 'completed_task',
'requested_task', 'rejected_task', 'position', 'is_invited', 'guardian_code_status'] 'requested_task', 'rejected_task', 'position', 'is_invited', 'guardian_code_status',
'is_deleted']
class JuniorProfileSerializer(serializers.ModelSerializer): class JuniorProfileSerializer(serializers.ModelSerializer):
"""junior serializer""" """junior serializer"""
@ -257,7 +258,7 @@ class JuniorProfileSerializer(serializers.ModelSerializer):
fields = ['id', 'email', 'first_name', 'last_name', 'country_name', 'country_code', 'phone', 'gender', 'dob', fields = ['id', 'email', 'first_name', 'last_name', 'country_name', 'country_code', 'phone', 'gender', 'dob',
'guardian_code', 'referral_code','is_active', 'is_complete_profile', 'created_at', 'image', 'guardian_code', 'referral_code','is_active', 'is_complete_profile', 'created_at', 'image',
'updated_at', 'notification_count', 'total_count', 'complete_field_count', 'signup_method', 'updated_at', 'notification_count', 'total_count', 'complete_field_count', 'signup_method',
'is_invited', 'passcode', 'guardian_code_approved'] 'is_invited', 'passcode', 'guardian_code_approved', 'is_deleted']
class AddJuniorSerializer(serializers.ModelSerializer): class AddJuniorSerializer(serializers.ModelSerializer):
"""Add junior serializer""" """Add junior serializer"""
@ -395,7 +396,7 @@ class JuniorPointsSerializer(serializers.ModelSerializer):
"""Meta info""" """Meta info"""
model = Junior model = Junior
fields = ['junior_id', 'total_points', 'position', 'pending_task', 'in_progress_task', 'completed_task', fields = ['junior_id', 'total_points', 'position', 'pending_task', 'in_progress_task', 'completed_task',
'requested_task', 'rejected_task', 'expired_task'] 'requested_task', 'rejected_task', 'expired_task', 'is_deleted']
class AddGuardianSerializer(serializers.ModelSerializer): class AddGuardianSerializer(serializers.ModelSerializer):
"""Add guardian serializer""" """Add guardian serializer"""
@ -508,3 +509,12 @@ class RemoveGuardianCodeSerializer(serializers.ModelSerializer):
instance.guardian_code_status = str(NUMBER['one']) instance.guardian_code_status = str(NUMBER['one'])
instance.save() instance.save()
return instance return instance
class FAQSerializer(serializers.ModelSerializer):
# FAQ Serializer
class Meta(object):
# meta info
model = FAQ
fields = ('id', 'question', 'description')

View File

@ -6,7 +6,7 @@ from .views import (UpdateJuniorProfile, ValidateGuardianCode, JuniorListAPIView
CompleteJuniorTaskAPIView, JuniorPointsListAPIView, ValidateReferralCode, CompleteJuniorTaskAPIView, JuniorPointsListAPIView, ValidateReferralCode,
InviteGuardianAPIView, StartTaskAPIView, ReAssignJuniorTaskAPIView, StartArticleAPIView, InviteGuardianAPIView, StartTaskAPIView, ReAssignJuniorTaskAPIView, StartArticleAPIView,
StartAssessmentAPIView, CheckAnswerAPIView, CompleteArticleAPIView, ReadArticleCardAPIView, StartAssessmentAPIView, CheckAnswerAPIView, CompleteArticleAPIView, ReadArticleCardAPIView,
CreateArticleCardAPIView, RemoveGuardianCodeAPIView) CreateArticleCardAPIView, RemoveGuardianCodeAPIView, FAQViewSet)
"""Third party import""" """Third party import"""
from rest_framework import routers from rest_framework import routers
@ -51,6 +51,8 @@ router.register('start-assessment', StartAssessmentAPIView, basename='start-asse
router.register('check-answer', CheckAnswerAPIView, basename='check-answer') router.register('check-answer', CheckAnswerAPIView, basename='check-answer')
# start article""" # start article"""
router.register('create-article-card', CreateArticleCardAPIView, basename='create-article-card') router.register('create-article-card', CreateArticleCardAPIView, basename='create-article-card')
# FAQ API
router.register('faq', FAQViewSet, basename='faq')
# Define url pattern""" # Define url pattern"""
urlpatterns = [ urlpatterns = [
path('api/v1/', include(router.urls)), path('api/v1/', include(router.urls)),

View File

@ -10,6 +10,8 @@ from django.db.models import F
import datetime import datetime
import requests import requests
from rest_framework.viewsets import GenericViewSet, mixins
"""Django app import""" """Django app import"""
# Import guardian's model, # Import guardian's model,
@ -30,11 +32,11 @@ import requests
# Import constants # Import constants
from django.db.models import Sum from django.db.models import Sum
from junior.models import (Junior, JuniorPoints, JuniorGuardianRelationship, JuniorArticlePoints, JuniorArticle, from junior.models import (Junior, JuniorPoints, JuniorGuardianRelationship, JuniorArticlePoints, JuniorArticle,
JuniorArticleCard) JuniorArticleCard, FAQ)
from .serializers import (CreateJuniorSerializer, JuniorDetailListSerializer, AddJuniorSerializer, from .serializers import (CreateJuniorSerializer, JuniorDetailListSerializer, AddJuniorSerializer,
RemoveJuniorSerializer, CompleteTaskSerializer, JuniorPointsSerializer, RemoveJuniorSerializer, CompleteTaskSerializer, JuniorPointsSerializer,
AddGuardianSerializer, StartTaskSerializer, ReAssignTaskSerializer, AddGuardianSerializer, StartTaskSerializer, ReAssignTaskSerializer,
RemoveGuardianCodeSerializer) RemoveGuardianCodeSerializer, FAQSerializer)
from guardian.models import Guardian, JuniorTask from guardian.models import Guardian, JuniorTask
from guardian.serializers import TaskDetailsSerializer, TaskDetailsjuniorSerializer from guardian.serializers import TaskDetailsSerializer, TaskDetailsjuniorSerializer
from base.messages import ERROR_CODE, SUCCESS_CODE from base.messages import ERROR_CODE, SUCCESS_CODE
@ -337,6 +339,8 @@ class CompleteJuniorTaskAPIView(views.APIView):
task_queryset = JuniorTask.objects.filter(id=task_id, junior__auth__email=self.request.user task_queryset = JuniorTask.objects.filter(id=task_id, junior__auth__email=self.request.user
).select_related('guardian', 'junior').last() ).select_related('guardian', 'junior').last()
if task_queryset: if task_queryset:
if task_queryset.junior.is_deleted:
return custom_error_response(ERROR_CODE['2074'], response_status=status.HTTP_400_BAD_REQUEST)
# use CompleteTaskSerializer serializer # use CompleteTaskSerializer serializer
if task_queryset.task_status in [str(NUMBER['four']), str(NUMBER['five'])]: if task_queryset.task_status in [str(NUMBER['four']), str(NUMBER['five'])]:
"""Already request send """ """Already request send """
@ -650,3 +654,49 @@ class RemoveGuardianCodeAPIView(views.APIView):
return custom_error_response(ERROR_CODE['2047'], response_status=status.HTTP_400_BAD_REQUEST) return custom_error_response(ERROR_CODE['2047'], response_status=status.HTTP_400_BAD_REQUEST)
except Exception as e: except Exception as e:
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST) return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
class FAQViewSet(GenericViewSet, mixins.CreateModelMixin,
mixins.ListModelMixin):
"""FAQ view set"""
serializer_class = FAQSerializer
permission_classes = [IsAuthenticated]
http_method_names = ['get', 'post']
def get_queryset(self):
return FAQ.objects.all()
def create(self, request, *args, **kwargs):
"""
faq create api method
:param request:
:param args:
:param kwargs:
:return: success message
"""
obj_data = [FAQ(**item) for item in request.data]
try:
FAQ.objects.bulk_create(obj_data)
return custom_response(SUCCESS_CODE["3045"], response_status=status.HTTP_200_OK)
except Exception as e:
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
def list(self, request, *args, **kwargs):
"""
article list api method
:param request:
:param args:
:param kwargs:
:return: list of article
"""
queryset = self.get_queryset()
paginator = self.pagination_class()
paginated_queryset = paginator.paginate_queryset(queryset, request)
serializer = self.serializer_class(paginated_queryset, many=True)
return custom_response(None, data=serializer.data, response_status=status.HTTP_200_OK)

View File

@ -28,7 +28,7 @@ class JuniorLeaderboardSerializer(serializers.ModelSerializer):
meta class meta class
""" """
model = Junior model = Junior
fields = ('id', 'name', 'first_name', 'last_name', 'is_active', 'image') fields = ('id', 'name', 'first_name', 'last_name', 'is_active', 'image', 'is_deleted')
@staticmethod @staticmethod
def get_name(obj): def get_name(obj):

View File

@ -108,7 +108,7 @@ class GuardianSerializer(serializers.ModelSerializer):
""" """
model = Guardian model = Guardian
fields = ('id', 'name', 'first_name', 'last_name', 'username', 'dob', 'gender', 'country_code', 'phone', fields = ('id', 'name', 'first_name', 'last_name', 'username', 'dob', 'gender', 'country_code', 'phone',
'is_active', 'country_name', 'image', 'email') 'is_active', 'country_name', 'image', 'email', 'is_deleted')
def validate(self, attrs): def validate(self, attrs):
""" """
@ -187,7 +187,7 @@ class JuniorSerializer(serializers.ModelSerializer):
""" """
model = Junior model = Junior
fields = ('id', 'name', 'first_name', 'last_name', 'username', 'dob', 'gender', 'country_code', 'phone', fields = ('id', 'name', 'first_name', 'last_name', 'username', 'dob', 'gender', 'country_code', 'phone',
'is_active', 'country_name', 'image', 'email') 'is_active', 'country_name', 'image', 'email', 'is_deleted')
def validate(self, attrs): def validate(self, attrs):
""" """