Compare commits

..

63 Commits

Author SHA1 Message Date
69c19cf097 sonar issues 2023-08-11 14:40:49 +05:30
18cb885410 Merge pull request #193 from KiwiTechLLC/ZBKADM-71
leaderboard ranking
2023-08-11 14:13:05 +05:30
4d7209df19 Merge pull request #194 from KiwiTechLLC/sprint4
remove deleted user from leaderboard
2023-08-11 13:40:48 +05:30
94c76b7f2e remove deleted user from leaderboard 2023-08-11 13:39:25 +05:30
af8ea39200 leaderboard ranking 2023-08-11 13:37:44 +05:30
6e9304b2cc Merge pull request #192 from KiwiTechLLC/sprint4
is complete article key
2023-08-11 13:04:54 +05:30
5eab8f4907 is complete article key 2023-08-11 13:04:05 +05:30
f750487b88 Merge pull request #190 from KiwiTechLLC/sprint4
add correct and attempt answer
2023-08-11 12:21:47 +05:30
8b0032f6d2 junior point table 2023-08-11 12:18:35 +05:30
bb65f81200 add correct and attempt answer 2023-08-11 11:48:02 +05:30
04db40e100 Merge pull request #189 from KiwiTechLLC/sprint4
create article
2023-08-10 21:24:15 +05:30
1e162255d7 create article 2023-08-10 20:17:24 +05:30
a479f3cb62 Merge pull request #187 from KiwiTechLLC/sprint4
task points
2023-08-10 19:06:32 +05:30
fbd6f9ece5 task points 2023-08-10 19:05:33 +05:30
11c84208b7 task points 2023-08-10 19:00:37 +05:30
80dffb7942 Merge pull request #184 from KiwiTechLLC/ZBKADM-71
image name fix, remove '|' character
2023-08-10 18:21:10 +05:30
0a8c2cf56d image name fix, remove '|' character 2023-08-10 18:17:49 +05:30
03fb4f4176 Merge pull request #182 from KiwiTechLLC/sprint4
current page update in article api
2023-08-10 15:51:09 +05:30
22afe7e555 current page update in article api 2023-08-10 15:43:31 +05:30
69723b362f current page update in article api 2023-08-10 15:30:46 +05:30
9e612c7171 Merge pull request #181 from KiwiTechLLC/sprint4
junior points
2023-08-10 12:20:34 +05:30
7a9be0326a junior points 2023-08-10 12:19:08 +05:30
aaa1c55227 Merge pull request #180 from KiwiTechLLC/sprint4
guardian code
2023-08-10 12:07:49 +05:30
656f0da89a guardian code 2023-08-10 12:06:52 +05:30
28e71e132c Merge pull request #178 from KiwiTechLLC/sprint4
Sprint4
2023-08-10 11:56:53 +05:30
b30643299f junior points 2023-08-10 11:56:19 +05:30
b6b70af13f remove guardian code request 2023-08-10 11:02:32 +05:30
22dd7fc10b remove guardian code request 2023-08-10 10:55:33 +05:30
924bc20193 Merge pull request #176 from KiwiTechLLC/sprint4
points
2023-08-09 19:21:50 +05:30
af7582b9e2 points 2023-08-09 19:20:56 +05:30
856d27d803 Merge pull request #175 from KiwiTechLLC/sprint4
points remove from serializer
2023-08-09 18:54:12 +05:30
19f56280e4 points remove from serializer 2023-08-09 18:53:18 +05:30
d3800dbc85 Merge pull request #173 from KiwiTechLLC/sprint4
guardian code update
2023-08-09 18:10:18 +05:30
9373dc4697 Merge pull request #172 from KiwiTechLLC/ZBKADM-71
analytics section api, users counts, new signup count, task report
2023-08-09 17:20:53 +05:30
32eaa6c3f2 guardian code update 2023-08-09 17:18:07 +05:30
11ff8fc700 conflict resolved 2023-08-09 17:03:42 +05:30
9c75cb1615 analytics section api, users counts, new signup count, task report 2023-08-09 16:57:19 +05:30
3f8b0e2eb7 Merge pull request #171 from KiwiTechLLC/sprint4
financial learning section api
2023-08-09 16:44:27 +05:30
69ce6857e8 financial learning section api 2023-08-09 16:36:33 +05:30
3efa31efe4 Merge pull request #169 from KiwiTechLLC/sprint4
Sprint4
2023-08-09 14:39:01 +05:30
275b09d2ea Merge branch 'sprint4' of github.com:KiwiTechLLC/ZODBank-Backend into sprint4 2023-08-09 14:38:09 +05:30
3cb0e3ed8b guardian code add in junior list api 2023-08-09 14:37:38 +05:30
823c5ea4c4 Merge pull request #168 from KiwiTechLLC/ZBKADM-69
otp, verify otp and login bug resolved
2023-08-09 14:21:58 +05:30
08750813ce Merge pull request #167 from KiwiTechLLC/sprint4
Sprint4
2023-08-09 13:54:08 +05:30
75f4f66285 Merge branch 'dev' into sprint4 2023-08-09 13:49:39 +05:30
881bda739b article card api, check answer api 2023-08-09 13:48:02 +05:30
d86f082e58 article card api, check answer api 2023-08-09 13:37:06 +05:30
b12c5071fe Merge pull request #164 from KiwiTechLLC/sprint4
changes in add junior api
2023-08-08 16:37:08 +05:30
f75201b3dd changes in add junior api 2023-08-08 16:36:03 +05:30
45ea7013f8 Merge pull request #162 from KiwiTechLLC/sprint4
junior list api
2023-08-08 16:06:52 +05:30
7d428f5eb5 junior list api 2023-08-08 16:05:56 +05:30
9ff64e64ef Merge pull request #160 from KiwiTechLLC/sprint4
top junior api
2023-08-08 15:04:03 +05:30
4b23394569 top junior api 2023-08-08 15:03:24 +05:30
81893c8841 Merge pull request #159 from KiwiTechLLC/ZBKADM-69
change in admin login
2023-08-08 14:38:43 +05:30
7fca493d0d Merge pull request #157 from KiwiTechLLC/sprint4
junior position changes and decrease api response time
2023-08-08 14:02:27 +05:30
85e4ae8761 junior position changes and decrease api response time 2023-08-08 13:54:04 +05:30
6ebd5ae410 Merge pull request #156 from KiwiTechLLC/sprint4
guardian list api changes
2023-08-08 12:35:43 +05:30
f57b111555 guardian list api changes 2023-08-08 11:48:53 +05:30
6596414675 guardian list api changes 2023-08-08 11:46:27 +05:30
ed7fd3c15d Merge pull request #155 from KiwiTechLLC/ZBKADM-69
notification list modified and mark as read method changed
2023-08-07 20:48:37 +05:30
8cf7148114 Merge pull request #154 from KiwiTechLLC/ZBKADM-69
change method to get real time
2023-08-07 19:19:00 +05:30
b98443479f Merge pull request #153 from KiwiTechLLC/sprint4
junior article points table
2023-08-07 19:12:55 +05:30
f917244265 junior article points table 2023-08-07 19:12:14 +05:30
32 changed files with 988 additions and 156 deletions

View File

@ -152,12 +152,12 @@ class AdminLoginSerializer(serializers.ModelSerializer):
def validate(self, attrs): def validate(self, attrs):
user = User.objects.filter(email__iexact=attrs['email'], is_superuser=True user = User.objects.filter(email__iexact=attrs['email'], is_superuser=True
).only('id', 'first_name', 'last_name', 'email', 'is_superuser').first() ).only('id', 'first_name', 'last_name', 'email',
'username', 'is_active', 'is_superuser').first()
if not user: if not user or not user.check_password(attrs['password']):
raise serializers.ValidationError({'details': ERROR_CODE['2002']})
elif not user.check_password(attrs['password']):
raise serializers.ValidationError({'details': ERROR_CODE['2002']}) raise serializers.ValidationError({'details': ERROR_CODE['2002']})
self.context.update({'user': user}) self.context.update({'user': user})
return attrs return attrs

View File

@ -23,7 +23,8 @@ from guardian.models import Guardian
from account.models import UserDelete from account.models import UserDelete
from base.messages import ERROR_CODE from base.messages import ERROR_CODE
from django.utils import timezone from django.utils import timezone
from base.constants import NUMBER
from junior.models import JuniorPoints
# Define delete # Define delete
# user account condition, # user account condition,
# Define delete # Define delete
@ -91,7 +92,9 @@ def junior_account_update(user_tb):
junior_data.is_active = False junior_data.is_active = False
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.save() junior_data.save()
JuniorPoints.objects.filter(junior=junior_data).delete()
def guardian_account_update(user_tb): def guardian_account_update(user_tb):
"""update guardian account after delete the user account""" """update guardian account after delete the user account"""

View File

@ -23,7 +23,7 @@ from django.conf import settings
# local imports # local imports
from guardian.models import Guardian from guardian.models import Guardian
from junior.models import Junior from junior.models import Junior, JuniorPoints
from guardian.utils import upload_image_to_alibaba from guardian.utils import upload_image_to_alibaba
from account.models import UserDeviceDetails, UserPhoneOtp, UserEmailOtp, DefaultTaskImages, UserNotification from account.models import UserDeviceDetails, UserPhoneOtp, UserEmailOtp, DefaultTaskImages, UserNotification
from django.contrib.auth.models import User from django.contrib.auth.models import User
@ -97,6 +97,8 @@ class GoogleLoginMixin(object):
referral_code=generate_code(ZOD, user_obj.id) referral_code=generate_code(ZOD, user_obj.id)
) )
serializer = JuniorSerializer(junior_query) serializer = JuniorSerializer(junior_query)
position = Junior.objects.all().count()
JuniorPoints.objects.create(junior=junior_query, position=position)
if str(user_type) == '2': if str(user_type) == '2':
guardian_query = Guardian.objects.create(user=user_obj, is_verified=True, is_active=True, guardian_query = Guardian.objects.create(user=user_obj, is_verified=True, is_active=True,
image=profile_picture,signup_method='2', image=profile_picture,signup_method='2',
@ -147,6 +149,8 @@ class SigninWithApple(views.APIView):
junior_code=generate_code(JUN, user.id), junior_code=generate_code(JUN, user.id),
referral_code=generate_code(ZOD, user.id)) referral_code=generate_code(ZOD, user.id))
serializer = JuniorSerializer(junior_query) serializer = JuniorSerializer(junior_query)
position = Junior.objects.all().count()
JuniorPoints.objects.create(junior=junior_query, position=position)
if str(user_type) == '2': if str(user_type) == '2':
guardian_query = Guardian.objects.create(user=user, is_verified=True, is_active=True, guardian_query = Guardian.objects.create(user=user, is_verified=True, is_active=True,
signup_method='3', signup_method='3',
@ -245,7 +249,6 @@ class ForgotPasswordAPIView(views.APIView):
class SendPhoneOtp(viewsets.ModelViewSet): class SendPhoneOtp(viewsets.ModelViewSet):
"""Send otp on phone""" """Send otp on phone"""
queryset = UserPhoneOtp.objects.all()
serializer_class = UserPhoneOtpSerializer serializer_class = UserPhoneOtpSerializer
def create(self, request, *args, **kwargs): def create(self, request, *args, **kwargs):
otp = generate_otp() otp = generate_otp()
@ -262,7 +265,6 @@ class SendPhoneOtp(viewsets.ModelViewSet):
class UserPhoneVerification(viewsets.ModelViewSet): class UserPhoneVerification(viewsets.ModelViewSet):
"""Send otp on phone""" """Send otp on phone"""
queryset = UserPhoneOtp.objects.all()
serializer_class = UserPhoneOtpSerializer serializer_class = UserPhoneOtpSerializer
def list(self, request, *args, **kwargs): def list(self, request, *args, **kwargs):
try: try:
@ -332,12 +334,12 @@ class UserLogin(viewsets.ViewSet):
email = request.data.get('email') email = request.data.get('email')
password = request.data.get('password') password = request.data.get('password')
user = User.objects.filter(email__iexact=email, is_superuser=True user = User.objects.filter(email__iexact=email, is_superuser=True
).only('id', 'first_name', 'last_name', 'email', 'is_superuser').first() ).only('id', 'first_name', 'last_name', 'email',
'username', 'is_active', 'is_superuser').first()
if not user: if not user or not user.check_password(password):
return custom_error_response(ERROR_CODE["2002"], response_status=status.HTTP_400_BAD_REQUEST)
elif not user.check_password(password):
return custom_error_response(ERROR_CODE["2002"], response_status=status.HTTP_400_BAD_REQUEST) return custom_error_response(ERROR_CODE["2002"], response_status=status.HTTP_400_BAD_REQUEST)
serializer = SuperUserSerializer(user) serializer = SuperUserSerializer(user)
return custom_response(SUCCESS_CODE['3003'], serializer.data, response_status=status.HTTP_200_OK) return custom_response(SUCCESS_CODE['3003'], serializer.data, response_status=status.HTTP_200_OK)
@ -369,7 +371,6 @@ class AdminLoginViewSet(viewsets.GenericViewSet):
class UserEmailVerification(viewsets.ModelViewSet): class UserEmailVerification(viewsets.ModelViewSet):
"""User Email verification""" """User Email verification"""
serializer_class = EmailVerificationSerializer serializer_class = EmailVerificationSerializer
queryset = UserEmailOtp.objects.all()
def list(self, request, *args, **kwargs): def list(self, request, *args, **kwargs):
try: try:
@ -412,7 +413,6 @@ class UserEmailVerification(viewsets.ModelViewSet):
class ReSendEmailOtp(viewsets.ModelViewSet): class ReSendEmailOtp(viewsets.ModelViewSet):
"""Send otp on phone""" """Send otp on phone"""
queryset = UserEmailOtp.objects.all()
serializer_class = EmailVerificationSerializer serializer_class = EmailVerificationSerializer
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]
@ -435,7 +435,6 @@ class ReSendEmailOtp(viewsets.ModelViewSet):
class ProfileAPIViewSet(viewsets.ModelViewSet): class ProfileAPIViewSet(viewsets.ModelViewSet):
"""Profile viewset""" """Profile viewset"""
queryset = User.objects.all()
serializer_class = JuniorProfileSerializer serializer_class = JuniorProfileSerializer
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]
@ -454,7 +453,6 @@ class ProfileAPIViewSet(viewsets.ModelViewSet):
class UploadImageAPIViewSet(viewsets.ModelViewSet): class UploadImageAPIViewSet(viewsets.ModelViewSet):
"""upload task image""" """upload task image"""
queryset = DefaultTaskImages.objects.all()
serializer_class = DefaultTaskImagesSerializer serializer_class = DefaultTaskImagesSerializer
def create(self, request, *args, **kwargs): def create(self, request, *args, **kwargs):
"""upload images""" """upload images"""
@ -473,7 +471,6 @@ class UploadImageAPIViewSet(viewsets.ModelViewSet):
class DefaultImageAPIViewSet(viewsets.ModelViewSet): class DefaultImageAPIViewSet(viewsets.ModelViewSet):
"""Profile viewset""" """Profile viewset"""
queryset = DefaultTaskImages.objects.all()
serializer_class = DefaultTaskImagesDetailsSerializer serializer_class = DefaultTaskImagesDetailsSerializer
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]
def list(self, request, *args, **kwargs): def list(self, request, *args, **kwargs):
@ -504,7 +501,6 @@ class DeleteUserProfileAPIViewSet(viewsets.GenericViewSet):
class UserNotificationAPIViewSet(viewsets.ModelViewSet): class UserNotificationAPIViewSet(viewsets.ModelViewSet):
"""notification viewset""" """notification viewset"""
queryset = UserNotification.objects.all()
serializer_class = UserNotificationSerializer serializer_class = UserNotificationSerializer
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]
def list(self, request, *args, **kwargs): def list(self, request, *args, **kwargs):
@ -516,7 +512,6 @@ class UserNotificationAPIViewSet(viewsets.ModelViewSet):
class UpdateUserNotificationAPIViewSet(viewsets.ModelViewSet): class UpdateUserNotificationAPIViewSet(viewsets.ModelViewSet):
"""Update notification viewset""" """Update notification viewset"""
queryset = UserNotification.objects.all()
serializer_class = UpdateUserNotificationSerializer serializer_class = UpdateUserNotificationSerializer
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]

View File

@ -70,6 +70,18 @@ SIGNUP_METHODS = (
('2', 'google'), ('2', 'google'),
('3', 'apple') ('3', 'apple')
) )
# guardian code status
GUARDIAN_CODE_STATUS = (
('1', 'no guardian code'),
('2', 'exist guardian code'),
('3', 'request for guardian code')
)
# article status
ARTICLE_STATUS = (
('1', 'read'),
('2', 'in_progress'),
('3', 'completed')
)
# relationship # relationship
RELATIONSHIP = ( RELATIONSHIP = (
('1', 'parent'), ('1', 'parent'),
@ -106,7 +118,9 @@ MAX_ARTICLE_CARD = 6
MIN_ARTICLE_SURVEY = 5 MIN_ARTICLE_SURVEY = 5
MAX_ARTICLE_SURVEY = 10 MAX_ARTICLE_SURVEY = 10
# real time url # already register
time_url = "http://worldtimeapi.org/api/timezone/Asia/Riyadh" Already_register_user = "duplicate key value violates unique constraint"
ARTICLE_CARD_IMAGE_FOLDER = 'article-card-images' ARTICLE_CARD_IMAGE_FOLDER = 'article-card-images'
DATE_FORMAT = '%Y-%m-%d'

View File

@ -149,7 +149,18 @@ SUCCESS_CODE = {
"3037": "Profile has been updated successfully.", "3037": "Profile has been updated successfully.",
"3038": "Status has been changed successfully.", "3038": "Status has been changed successfully.",
# notification read # notification read
"3039": "Notification read successfully" "3039": "Notification read successfully",
# start article
"3040": "Start article successfully",
# complete article
"3041": "Article completed successfully",
# submit assessment successfully
"3042": "Assessment completed successfully",
# read article
"3043": "Read article card successfully",
# remove guardian code request
"3044": "Remove guardian code request successfully",
} }
"""status code error""" """status code error"""
STATUS_CODE_ERROR = { STATUS_CODE_ERROR = {

Binary file not shown.

View File

@ -23,7 +23,7 @@ from account.models import UserProfile, UserEmailOtp, UserNotification
from account.utils import generate_code from account.utils import generate_code
from junior.serializers import JuniorDetailSerializer from junior.serializers import JuniorDetailSerializer
from base.messages import ERROR_CODE, SUCCESS_CODE from base.messages import ERROR_CODE, SUCCESS_CODE
from base.constants import NUMBER, JUN, ZOD, GRD from base.constants import NUMBER, JUN, ZOD, GRD, Already_register_user
from junior.models import Junior, JuniorPoints, JuniorGuardianRelationship from junior.models import Junior, JuniorPoints, JuniorGuardianRelationship
from .utils import real_time, convert_timedelta_into_datetime, update_referral_points from .utils import real_time, convert_timedelta_into_datetime, update_referral_points
# notification's constant # notification's constant
@ -68,8 +68,10 @@ class UserSerializer(serializers.ModelSerializer):
UserNotification.objects.get_or_create(user=user) UserNotification.objects.get_or_create(user=user)
if user_type == str(NUMBER['one']): if user_type == str(NUMBER['one']):
# create junior profile # create junior profile
Junior.objects.create(auth=user, junior_code=generate_code(JUN, user.id), junior = Junior.objects.create(auth=user, junior_code=generate_code(JUN, user.id),
referral_code=generate_code(ZOD, user.id)) referral_code=generate_code(ZOD, user.id))
position = Junior.objects.all().count()
JuniorPoints.objects.create(junior=junior, position=position)
if user_type == str(NUMBER['two']): if user_type == str(NUMBER['two']):
# create guardian profile # create guardian profile
Guardian.objects.create(user=user, guardian_code=generate_code(GRD, user.id), Guardian.objects.create(user=user, guardian_code=generate_code(GRD, user.id),
@ -82,7 +84,7 @@ class UserSerializer(serializers.ModelSerializer):
otp_verified = False otp_verified = False
if otp and otp.is_verified: if otp and otp.is_verified:
otp_verified = True otp_verified = True
raise serializers.ValidationError({"details":ERROR_CODE['2021'], "otp_verified":bool(otp_verified), raise serializers.ValidationError({"details": ERROR_CODE['2021'], "otp_verified":bool(otp_verified),
"code": 400, "status":"failed", "code": 400, "status":"failed",
}) })
@ -353,6 +355,7 @@ class ApproveJuniorSerializer(serializers.ModelSerializer):
instance = self.context['junior'] instance = self.context['junior']
instance.guardian_code = [self.context['guardian_code']] instance.guardian_code = [self.context['guardian_code']]
instance.guardian_code_approved = True instance.guardian_code_approved = True
instance.guardian_code_status = str(NUMBER['two'])
instance.save() instance.save()
return instance return instance
@ -385,8 +388,6 @@ class ApproveTaskSerializer(serializers.ModelSerializer):
# reject the task # reject the task
instance.task_status = str(NUMBER['three']) instance.task_status = str(NUMBER['three'])
instance.is_approved = False instance.is_approved = False
# update total task point
junior_data.total_points = junior_data.total_points - instance.points
# update reject time of task # update reject time of task
# instance.rejected_on = real_time() # instance.rejected_on = real_time()
instance.rejected_on = timezone.now().astimezone(pytz.utc) instance.rejected_on = timezone.now().astimezone(pytz.utc)
@ -403,11 +404,20 @@ class GuardianDetailListSerializer(serializers.ModelSerializer):
email = serializers.SerializerMethodField('get_email') email = serializers.SerializerMethodField('get_email')
image = serializers.SerializerMethodField('get_image') image = serializers.SerializerMethodField('get_image')
guardian_id = serializers.SerializerMethodField('get_guardian_id') guardian_id = serializers.SerializerMethodField('get_guardian_id')
guardian_code = serializers.SerializerMethodField('get_guardian_code')
gender = serializers.SerializerMethodField('get_gender')
phone = serializers.SerializerMethodField('get_phone')
country_name = serializers.SerializerMethodField('get_country_name')
dob = serializers.SerializerMethodField('get_dob')
guardian_code_status = serializers.SerializerMethodField('get_guardian_code_status')
# code info
class Meta(object): class Meta(object):
"""Meta info""" """Meta info"""
model = JuniorGuardianRelationship model = JuniorGuardianRelationship
fields = ['guardian_id', 'first_name', 'last_name', 'email', 'relationship', 'image', 'created_at', fields = ['guardian_id', 'first_name', 'last_name', 'email', 'relationship', 'image', 'dob',
'guardian_code', 'gender', 'phone', 'country_name', 'created_at', 'guardian_code_status',
'updated_at'] 'updated_at']
def get_guardian_id(self,obj): def get_guardian_id(self,obj):
@ -422,9 +432,33 @@ class GuardianDetailListSerializer(serializers.ModelSerializer):
return obj.guardian.user.last_name return obj.guardian.user.last_name
def get_email(self,obj): def get_email(self,obj):
"""emailof guardian""" """email of guardian"""
return obj.guardian.user.email return obj.guardian.user.email
def get_image(self,obj): def get_image(self,obj):
"""first name of guardian""" """guardian image"""
return obj.guardian.image return obj.guardian.image
def get_guardian_code(self,obj):
""" guardian code"""
return obj.guardian.guardian_code
def get_gender(self,obj):
""" guardian gender"""
return obj.guardian.gender
def get_phone(self,obj):
"""guardian phone"""
return obj.guardian.phone
def get_country_name(self,obj):
""" guardian country name """
return obj.guardian.country_name
def get_dob(self,obj):
"""guardian dob """
return obj.guardian.dob
def get_guardian_code_status(self,obj):
"""guardian code status"""
return obj.junior.guardian_code_status

View File

@ -11,7 +11,7 @@ import tempfile
# Import date time module's function # Import date time module's function
from datetime import datetime, time from datetime import datetime, time
# import Number constant # import Number constant
from base.constants import NUMBER, time_url from base.constants import NUMBER
# Import Junior's model # Import Junior's model
from junior.models import Junior, JuniorPoints from junior.models import Junior, JuniorPoints
# Import guardian's model # Import guardian's model

View File

@ -10,8 +10,8 @@ from rest_framework.permissions import IsAuthenticated
from rest_framework import viewsets, status from rest_framework import viewsets, status
from rest_framework.pagination import PageNumberPagination from rest_framework.pagination import PageNumberPagination
from django.contrib.auth.models import User from django.contrib.auth.models import User
from rest_framework.filters import SearchFilter
from rest_framework.filters import SearchFilter
from django.utils import timezone from django.utils import timezone
# Import guardian's model, # Import guardian's model,
@ -36,7 +36,7 @@ from account.models import UserEmailOtp, UserNotification
from .tasks import generate_otp from .tasks import generate_otp
from account.utils import custom_response, custom_error_response, OTP_EXPIRY, send_otp_email from account.utils import custom_response, custom_error_response, OTP_EXPIRY, send_otp_email
from base.messages import ERROR_CODE, SUCCESS_CODE from base.messages import ERROR_CODE, SUCCESS_CODE
from base.constants import NUMBER from base.constants import NUMBER, GUARDIAN_CODE_STATUS
from .utils import upload_image_to_alibaba from .utils import upload_image_to_alibaba
from notifications.constants import REGISTRATION, TASK_CREATED, LEADERBOARD_RANKING from notifications.constants import REGISTRATION, TASK_CREATED, LEADERBOARD_RANKING
from notifications.utils import send_notification from notifications.utils import send_notification
@ -59,7 +59,6 @@ class SignupViewset(viewsets.ModelViewSet):
serializer_class = UserSerializer serializer_class = UserSerializer
def create(self, request, *args, **kwargs): def create(self, request, *args, **kwargs):
"""Create user profile""" """Create user profile"""
try:
if request.data['user_type'] in [str(NUMBER['one']), str(NUMBER['two'])]: if request.data['user_type'] in [str(NUMBER['one']), str(NUMBER['two'])]:
serializer = UserSerializer(context=request.data['user_type'], data=request.data) serializer = UserSerializer(context=request.data['user_type'], data=request.data)
if serializer.is_valid(): if serializer.is_valid():
@ -80,12 +79,9 @@ class SignupViewset(viewsets.ModelViewSet):
return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST) return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST)
else: else:
return custom_error_response(ERROR_CODE['2028'], response_status=status.HTTP_400_BAD_REQUEST) return custom_error_response(ERROR_CODE['2028'], response_status=status.HTTP_400_BAD_REQUEST)
except Exception as e:
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
class UpdateGuardianProfile(viewsets.ViewSet): class UpdateGuardianProfile(viewsets.ViewSet):
"""Update guardian profile""" """Update guardian profile"""
queryset = Guardian.objects.all()
serializer_class = CreateGuardianSerializer serializer_class = CreateGuardianSerializer
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]
@ -119,7 +115,6 @@ class UpdateGuardianProfile(viewsets.ViewSet):
class AllTaskListAPIView(viewsets.ModelViewSet): class AllTaskListAPIView(viewsets.ModelViewSet):
"""Update guardian profile""" """Update guardian profile"""
serializer_class = TaskDetailsSerializer serializer_class = TaskDetailsSerializer
queryset = JuniorTask.objects.all()
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]
def list(self, request, *args, **kwargs): def list(self, request, *args, **kwargs):
@ -129,38 +124,6 @@ class AllTaskListAPIView(viewsets.ModelViewSet):
serializer = TaskDetailsSerializer(queryset, many=True) serializer = TaskDetailsSerializer(queryset, many=True)
return custom_response(None, serializer.data, response_status=status.HTTP_200_OK) return custom_response(None, serializer.data, response_status=status.HTTP_200_OK)
# class TaskListAPIView(viewsets.ModelViewSet):
# """Update guardian profile"""
# serializer_class = TaskDetailsSerializer
# permission_classes = [IsAuthenticated]
# pagination_class = PageNumberPagination
# http_method_names = ('get',)
#
# def list(self, request, *args, **kwargs):
# """Create guardian profile"""
# try:
# status_value = self.request.GET.get('status')
# 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')
# 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()
# # 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)
# except Exception as e:
# return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
class TaskListAPIView(viewsets.ModelViewSet): class TaskListAPIView(viewsets.ModelViewSet):
"""Update guardian profile""" """Update guardian profile"""
@ -261,9 +224,9 @@ class SearchTaskListAPIView(viewsets.ModelViewSet):
class TopJuniorListAPIView(viewsets.ModelViewSet): class TopJuniorListAPIView(viewsets.ModelViewSet):
"""Top juniors list""" """Top juniors list"""
queryset = JuniorPoints.objects.all()
serializer_class = TopJuniorSerializer serializer_class = TopJuniorSerializer
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]
queryset = JuniorPoints.objects.all()
def get_serializer_context(self): def get_serializer_context(self):
# context list # context list
@ -275,14 +238,12 @@ class TopJuniorListAPIView(viewsets.ModelViewSet):
"""Fetch junior list of those who complete their tasks""" """Fetch junior list of those who complete their tasks"""
try: try:
junior_total_points = self.get_queryset().order_by('-total_points') junior_total_points = self.get_queryset().order_by('-total_points')
# Update the position field for each JuniorPoints object # Update the position field for each JuniorPoints object
for index, junior in enumerate(junior_total_points): for index, junior in enumerate(junior_total_points):
junior.position = index + 1 junior.position = index + 1
send_notification.delay(LEADERBOARD_RANKING, None, junior.junior.auth.id, {}) send_notification.delay(LEADERBOARD_RANKING, None, junior.junior.auth.id, {})
junior.save() junior.save()
serializer = self.get_serializer(junior_total_points[:NUMBER['fifteen']], many=True)
serializer = self.get_serializer(junior_total_points, many=True)
return custom_response(None, serializer.data, response_status=status.HTTP_200_OK) return custom_response(None, serializer.data, 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)
@ -316,6 +277,7 @@ class ApproveJuniorAPIView(viewsets.ViewSet):
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 queryset[1].guardian_code = None
queryset[1].guardian_code_status = str(NUMBER['one'])
queryset[1].save() queryset[1].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:
@ -379,6 +341,6 @@ class GuardianListAPIView(viewsets.ModelViewSet):
# use GuardianDetailListSerializer serializer # use GuardianDetailListSerializer serializer
serializer = GuardianDetailListSerializer(guardian_data, many=True) serializer = GuardianDetailListSerializer(guardian_data, many=True)
return custom_response(None, serializer.data, response_status=status.HTTP_200_OK) return custom_response(None, serializer.data, response_status=status.HTTP_200_OK)
return custom_error_response(ERROR_CODE['2068'], response_status=status.HTTP_200_OK) return custom_response({"status": GUARDIAN_CODE_STATUS[1][0]}, 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)

View File

@ -2,8 +2,26 @@
"""Third party Django app""" """Third party Django app"""
from django.contrib import admin from django.contrib import admin
"""Import Django app""" """Import Django app"""
from .models import Junior, JuniorPoints, JuniorGuardianRelationship from .models import (Junior, JuniorPoints, JuniorGuardianRelationship, JuniorArticlePoints, JuniorArticle,
JuniorArticleCard)
# Register your models here. # Register your models here.
@admin.register(JuniorArticle)
class JuniorArticleAdmin(admin.ModelAdmin):
"""Junior Admin"""
list_display = ['junior', 'article', 'status', 'is_completed']
def __str__(self):
"""Return email id"""
return self.junior__auth__email
@admin.register(JuniorArticleCard)
class JuniorArticleCardAdmin(admin.ModelAdmin):
"""Junior Admin"""
list_display = ['junior', 'article', 'article_card', 'is_read']
def __str__(self):
"""Return email id"""
return self.junior__auth__email
@admin.register(Junior) @admin.register(Junior)
class JuniorAdmin(admin.ModelAdmin): class JuniorAdmin(admin.ModelAdmin):
"""Junior Admin""" """Junior Admin"""
@ -27,3 +45,7 @@ class JuniorGuardianRelationshipAdmin(admin.ModelAdmin):
"""Junior Admin""" """Junior Admin"""
list_display = ['guardian', 'junior', 'relationship'] list_display = ['guardian', 'junior', 'relationship']
@admin.register(JuniorArticlePoints)
class JuniorArticlePointsAdmin(admin.ModelAdmin):
"""Junior Admin"""
list_display = ['junior', 'article', 'question', 'submitted_answer', 'is_answer_correct']

View File

@ -0,0 +1,30 @@
# Generated by Django 4.2.2 on 2023-08-07 13:29
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('web_admin', '0004_alter_surveyoption_survey'),
('junior', '0018_remove_junior_relationship_and_more'),
]
operations = [
migrations.CreateModel(
name='JuniorArticlePoints',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('earn_points', models.IntegerField(blank=True, default=5, null=True)),
('is_attempt', models.BooleanField(default=False)),
('is_answer_correct', models.BooleanField(default=False)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('article', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='junior_articles', to='web_admin.article')),
('junior', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='juniors_details', to='junior.junior', verbose_name='Junior')),
('question', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='questions', to='web_admin.articlesurvey')),
('submitted_answer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='submitted_answer', to='web_admin.surveyoption')),
],
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2.2 on 2023-08-08 05:43
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('junior', '0019_juniorarticlepoints'),
]
operations = [
migrations.AddField(
model_name='junior',
name='guardian_code_status',
field=models.CharField(blank=True, choices=[('1', 'no guardian code'), ('2', 'exist guardian code'), ('3', 'request for guardian code')], default='1', max_length=31, null=True),
),
]

View File

@ -0,0 +1,20 @@
# Generated by Django 4.2.2 on 2023-08-08 09:45
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('web_admin', '0004_alter_surveyoption_survey'),
('junior', '0020_junior_guardian_code_status'),
]
operations = [
migrations.AlterField(
model_name='juniorarticlepoints',
name='submitted_answer',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='submitted_answer', to='web_admin.surveyoption'),
),
]

View File

@ -0,0 +1,27 @@
# Generated by Django 4.2.2 on 2023-08-09 09:34
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('web_admin', '0004_alter_surveyoption_survey'),
('junior', '0021_alter_juniorarticlepoints_submitted_answer'),
]
operations = [
migrations.CreateModel(
name='JuniorArticle',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('is_completed', models.BooleanField(default=False)),
('status', models.CharField(blank=True, choices=[('1', 'read'), ('2', 'in_progress'), ('3', 'completed')], default='1', max_length=10, null=True)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('article', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='junior_articles_details', to='web_admin.article')),
('junior', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='juniors_article', to='junior.junior', verbose_name='Junior')),
],
),
]

View File

@ -0,0 +1,27 @@
# Generated by Django 4.2.2 on 2023-08-09 10:47
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('web_admin', '0004_alter_surveyoption_survey'),
('junior', '0022_juniorarticle'),
]
operations = [
migrations.CreateModel(
name='JuniorArticleCard',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('is_read', models.BooleanField(default=False)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('article', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='junior_articles_detail', to='web_admin.article')),
('article_card', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='junior_article_card', to='web_admin.articlecard')),
('junior', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='juniors_article_card', to='junior.junior', verbose_name='Junior')),
],
),
]

View File

@ -0,0 +1,23 @@
# Generated by Django 4.2.2 on 2023-08-10 08:53
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('junior', '0023_juniorarticlecard'),
]
operations = [
migrations.AddField(
model_name='juniorarticle',
name='current_card_page',
field=models.IntegerField(blank=True, default=0, null=True),
),
migrations.AddField(
model_name='juniorarticle',
name='current_que_page',
field=models.IntegerField(blank=True, default=0, null=True),
),
]

View File

@ -0,0 +1,19 @@
# Generated by Django 4.2.2 on 2023-08-10 14:46
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('junior', '0024_juniorarticle_current_card_page_and_more'),
]
operations = [
migrations.AlterField(
model_name='juniorarticle',
name='junior',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='juniors_article', to='junior.junior', verbose_name='Junior'),
),
]

View File

@ -6,10 +6,11 @@ from django.contrib.auth import get_user_model
"""Import ArrayField""" """Import ArrayField"""
from django.contrib.postgres.fields import ArrayField from django.contrib.postgres.fields import ArrayField
"""Import django app""" """Import django app"""
from base.constants import GENDERS, SIGNUP_METHODS, RELATIONSHIP from base.constants import GENDERS, SIGNUP_METHODS, RELATIONSHIP, GUARDIAN_CODE_STATUS, ARTICLE_STATUS
# Import guardian's model # Import guardian's model
from guardian.models import Guardian from guardian.models import Guardian
# Import web admin's model
from web_admin.models import SurveyOption, ArticleSurvey, Article, ArticleCard
"""Define User model""" """Define User model"""
User = get_user_model() User = get_user_model()
# Create your models here. # Create your models here.
@ -73,6 +74,9 @@ class Junior(models.Model):
is_verified = models.BooleanField(default=False) is_verified = models.BooleanField(default=False)
"""guardian code is approved or not""" """guardian code is approved or not"""
guardian_code_approved = models.BooleanField(default=False) guardian_code_approved = models.BooleanField(default=False)
# guardian code status"""
guardian_code_status = models.CharField(max_length=31, choices=GUARDIAN_CODE_STATUS, default='1',
null=True, blank=True)
# Profile created and updated time""" # Profile created and updated time"""
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)
@ -137,3 +141,62 @@ class JuniorGuardianRelationship(models.Model):
return f'{self.guardian.user}' return f'{self.guardian.user}'
class JuniorArticlePoints(models.Model):
"""
Survey Options model
"""
# associated junior with the task
junior = models.ForeignKey(Junior, on_delete=models.CASCADE, related_name='juniors_details', verbose_name='Junior')
article = models.ForeignKey(Article, on_delete=models.CASCADE, related_name='junior_articles')
question = models.ForeignKey(ArticleSurvey, on_delete=models.CASCADE, related_name='questions')
submitted_answer = models.ForeignKey(SurveyOption, on_delete=models.SET_NULL, null=True,
related_name='submitted_answer')
# earn points"""
earn_points = models.IntegerField(blank=True, null=True, default=5)
is_attempt = models.BooleanField(default=False)
is_answer_correct = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
"""Return title"""
return f'{self.id} | {self.question}'
class JuniorArticle(models.Model):
"""
Survey Options model
"""
# associated junior with the task
junior = models.ForeignKey(Junior, on_delete=models.CASCADE, related_name='juniors_article',
verbose_name='Junior')
article = models.ForeignKey(Article, on_delete=models.CASCADE, related_name='junior_articles_details')
# article completed"""
is_completed = models.BooleanField(default=False)
status = models.CharField(max_length=10, choices=ARTICLE_STATUS, null=True, blank=True, default='1')
current_card_page = models.IntegerField(blank=True, null=True, default=0)
current_que_page = models.IntegerField(blank=True, null=True, default=0)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
"""Return title"""
return f'{self.id} | {self.article}'
class JuniorArticleCard(models.Model):
"""
Survey Options model
"""
# associated junior with the task
junior = models.ForeignKey(Junior, on_delete=models.CASCADE, related_name='juniors_article_card',
verbose_name='Junior')
article = models.ForeignKey(Article, on_delete=models.CASCADE, related_name='junior_articles_detail')
article_card = models.ForeignKey(ArticleCard, on_delete=models.CASCADE, related_name='junior_article_card')
# article card read"""
is_read = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
"""Return title"""
return f'{self.id} | {self.article}'

View File

@ -12,10 +12,11 @@ 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 from junior.models import Junior, JuniorPoints, JuniorGuardianRelationship, JuniorArticlePoints
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,
GUARDIAN_CODE_STATUS)
from guardian.models import Guardian, JuniorTask from guardian.models import Guardian, JuniorTask
from account.models import UserEmailOtp, UserNotification from account.models import UserEmailOtp, UserNotification
from junior.utils import junior_notification_email, junior_approval_mail from junior.utils import junior_notification_email, junior_approval_mail
@ -95,6 +96,9 @@ class CreateJuniorSerializer(serializers.ModelSerializer):
guardian_data = Guardian.objects.filter(guardian_code=guardian_code[0]).last() guardian_data = Guardian.objects.filter(guardian_code=guardian_code[0]).last()
if guardian_data: if guardian_data:
JuniorGuardianRelationship.objects.get_or_create(guardian=guardian_data, junior=junior) JuniorGuardianRelationship.objects.get_or_create(guardian=guardian_data, junior=junior)
junior.guardian_code_status = str(NUMBER['three'])
junior_approval_mail(user.email, user.first_name)
send_notification.delay(APPROVED_JUNIOR, None, guardian_data.user.id, {})
junior.dob = validated_data.get('dob', junior.dob) junior.dob = validated_data.get('dob', junior.dob)
junior.passcode = validated_data.get('passcode', junior.passcode) junior.passcode = validated_data.get('passcode', junior.passcode)
junior.country_name = validated_data.get('country_name', junior.country_name) junior.country_name = validated_data.get('country_name', junior.country_name)
@ -142,7 +146,7 @@ class JuniorDetailSerializer(serializers.ModelSerializer):
"""Meta info""" """Meta info"""
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', 'is_invited', 'referral_code','is_active', 'is_complete_profile', 'created_at', 'guardian_code', 'image', 'is_invited', 'referral_code','is_active', 'is_complete_profile', 'created_at',
'image', 'updated_at'] 'image', 'updated_at']
class JuniorDetailListSerializer(serializers.ModelSerializer): class JuniorDetailListSerializer(serializers.ModelSerializer):
@ -178,10 +182,11 @@ class JuniorDetailListSerializer(serializers.ModelSerializer):
data = JuniorPoints.objects.filter(junior=obj).last() data = JuniorPoints.objects.filter(junior=obj).last()
if data: if data:
return data.position return data.position
return 99999
def get_points(self, obj): def get_points(self, obj):
data = sum(JuniorTask.objects.filter(junior=obj, task_status=COMPLETED).values_list('points', flat=True)) data = JuniorPoints.objects.filter(junior=obj).last()
return data if data:
return data.total_points
return NUMBER['zero']
def get_in_progress_task(self, obj): def get_in_progress_task(self, obj):
data = JuniorTask.objects.filter(junior=obj, task_status=IN_PROGRESS).count() data = JuniorTask.objects.filter(junior=obj, task_status=IN_PROGRESS).count()
@ -206,10 +211,10 @@ class JuniorDetailListSerializer(serializers.ModelSerializer):
class Meta(object): class Meta(object):
"""Meta info""" """Meta info"""
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', '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'] 'requested_task', 'rejected_task', 'position', 'is_invited', 'guardian_code_status']
class JuniorProfileSerializer(serializers.ModelSerializer): class JuniorProfileSerializer(serializers.ModelSerializer):
"""junior serializer""" """junior serializer"""
@ -256,11 +261,10 @@ class JuniorProfileSerializer(serializers.ModelSerializer):
class AddJuniorSerializer(serializers.ModelSerializer): class AddJuniorSerializer(serializers.ModelSerializer):
"""Add junior serializer""" """Add junior serializer"""
class Meta(object): class Meta(object):
"""Meta info""" """Meta info"""
model = Junior model = Junior
fields = ['id', 'gender','dob', 'is_invited'] fields = ['id', 'gender', 'dob', 'is_invited']
def create(self, validated_data): def create(self, validated_data):
@ -269,6 +273,7 @@ class AddJuniorSerializer(serializers.ModelSerializer):
email = self.context['email'] email = self.context['email']
guardian = self.context['user'] guardian = self.context['user']
relationship = self.context['relationship'] relationship = self.context['relationship']
profile_image = self.context['image']
full_name = self.context['first_name'] + ' ' + self.context['last_name'] full_name = self.context['first_name'] + ' ' + self.context['last_name']
guardian_data = Guardian.objects.filter(user__username=guardian).last() guardian_data = Guardian.objects.filter(user__username=guardian).last()
user_data = User.objects.create(username=email, email=email, user_data = User.objects.create(username=email, email=email,
@ -278,14 +283,18 @@ class AddJuniorSerializer(serializers.ModelSerializer):
user_data.set_password(password) user_data.set_password(password)
user_data.save() user_data.save()
junior_data = Junior.objects.create(auth=user_data, gender=validated_data.get('gender'), junior_data = Junior.objects.create(auth=user_data, gender=validated_data.get('gender'),
image=profile_image,
dob=validated_data.get('dob'), is_invited=True, dob=validated_data.get('dob'), is_invited=True,
guardian_code=[guardian_data.guardian_code], guardian_code=[guardian_data.guardian_code],
junior_code=generate_code(JUN, user_data.id), junior_code=generate_code(JUN, user_data.id),
referral_code=generate_code(ZOD, 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) is_password_set=False, is_verified=True,
guardian_code_status=GUARDIAN_CODE_STATUS[1][0])
JuniorGuardianRelationship.objects.create(guardian=guardian_data, junior=junior_data, JuniorGuardianRelationship.objects.create(guardian=guardian_data, junior=junior_data,
relationship=relationship) relationship=relationship)
total_junior = Junior.objects.all().count()
JuniorPoints.objects.create(junior=junior_data, position=total_junior)
"""Generate otp""" """Generate otp"""
otp_value = generate_otp() otp_value = generate_otp()
expiry_time = timezone.now() + timezone.timedelta(days=1) expiry_time = timezone.now() + timezone.timedelta(days=1)
@ -311,6 +320,7 @@ class RemoveJuniorSerializer(serializers.ModelSerializer):
if instance: if instance:
instance.is_invited = False instance.is_invited = False
instance.guardian_code = '{}' instance.guardian_code = '{}'
instance.guardian_code_status = str(NUMBER['1'])
instance.save() instance.save()
return instance return instance
@ -323,7 +333,6 @@ class CompleteTaskSerializer(serializers.ModelSerializer):
fields = ('id', 'image') fields = ('id', 'image')
def update(self, instance, validated_data): def update(self, instance, validated_data):
instance.image = validated_data.get('image', instance.image) instance.image = validated_data.get('image', instance.image)
# instance.requested_on = real_time()
instance.requested_on = timezone.now().astimezone(pytz.utc) instance.requested_on = timezone.now().astimezone(pytz.utc)
instance.task_status = str(NUMBER['four']) instance.task_status = str(NUMBER['four'])
instance.is_approved = False instance.is_approved = False
@ -403,6 +412,8 @@ class AddGuardianSerializer(serializers.ModelSerializer):
relationship = self.context['relationship'] relationship = self.context['relationship']
full_name = self.context['first_name'] + ' ' + self.context['last_name'] full_name = self.context['first_name'] + ' ' + self.context['last_name']
junior_data = Junior.objects.filter(auth__username=junior).last() junior_data = Junior.objects.filter(auth__username=junior).last()
junior_data.guardian_code_status = GUARDIAN_CODE_STATUS[2][0]
junior_data.save()
instance = User.objects.filter(username=email).last() instance = User.objects.filter(username=email).last()
if instance: if instance:
guardian_data = Guardian.objects.filter(user=instance).update(is_invited=True, guardian_data = Guardian.objects.filter(user=instance).update(is_invited=True,
@ -481,3 +492,16 @@ class ReAssignTaskSerializer(serializers.ModelSerializer):
instance.requested_on = None instance.requested_on = None
instance.save() instance.save()
return instance return instance
class RemoveGuardianCodeSerializer(serializers.ModelSerializer):
"""User task Serializer"""
class Meta(object):
"""Meta class"""
model = Junior
fields = ('id', )
def update(self, instance, validated_data):
instance.guardian_code_status = str(NUMBER['one'])
instance.save()
return instance

View File

@ -4,7 +4,9 @@ from django.urls import path, include
from .views import (UpdateJuniorProfile, ValidateGuardianCode, JuniorListAPIView, AddJuniorAPIView, from .views import (UpdateJuniorProfile, ValidateGuardianCode, JuniorListAPIView, AddJuniorAPIView,
InvitedJuniorAPIView, FilterJuniorAPIView, RemoveJuniorAPIView, JuniorTaskListAPIView, InvitedJuniorAPIView, FilterJuniorAPIView, RemoveJuniorAPIView, JuniorTaskListAPIView,
CompleteJuniorTaskAPIView, JuniorPointsListAPIView, ValidateReferralCode, CompleteJuniorTaskAPIView, JuniorPointsListAPIView, ValidateReferralCode,
InviteGuardianAPIView, StartTaskAPIView, ReAssignJuniorTaskAPIView) InviteGuardianAPIView, StartTaskAPIView, ReAssignJuniorTaskAPIView, StartArticleAPIView,
StartAssessmentAPIView, CheckAnswerAPIView, CompleteArticleAPIView, ReadArticleCardAPIView,
CreateArticleCardAPIView, RemoveGuardianCodeAPIView)
"""Third party import""" """Third party import"""
from rest_framework import routers from rest_framework import routers
@ -41,6 +43,14 @@ router.register('junior-points', JuniorPointsListAPIView, basename='junior-point
router.register('validate-referral-code', ValidateReferralCode, basename='validate-referral-code') router.register('validate-referral-code', ValidateReferralCode, basename='validate-referral-code')
# invite guardian API""" # invite guardian API"""
router.register('invite-guardian', InviteGuardianAPIView, basename='invite-guardian') router.register('invite-guardian', InviteGuardianAPIView, basename='invite-guardian')
# start article"""
router.register('start-article', StartArticleAPIView, basename='start-article')
# start assessment api"""
router.register('start-assessment', StartAssessmentAPIView, basename='start-assessment')
# check answer api"""
router.register('check-answer', CheckAnswerAPIView, basename='check-answer')
# start article"""
router.register('create-article-card', CreateArticleCardAPIView, basename='create-article-card')
# Define url pattern""" # Define url pattern"""
urlpatterns = [ urlpatterns = [
path('api/v1/', include(router.urls)), path('api/v1/', include(router.urls)),
@ -48,4 +58,7 @@ urlpatterns = [
path('api/v1/complete-task/', CompleteJuniorTaskAPIView.as_view()), path('api/v1/complete-task/', CompleteJuniorTaskAPIView.as_view()),
path('api/v1/start-task/', StartTaskAPIView.as_view()), path('api/v1/start-task/', StartTaskAPIView.as_view()),
path('api/v1/reassign-task/', ReAssignJuniorTaskAPIView.as_view()), path('api/v1/reassign-task/', ReAssignJuniorTaskAPIView.as_view()),
path('api/v1/complete-article/', CompleteArticleAPIView.as_view()),
path('api/v1/read-article-card/', ReadArticleCardAPIView.as_view()),
path('api/v1/remove-guardian-code-request/', RemoveGuardianCodeAPIView.as_view()),
] ]

View File

@ -4,6 +4,7 @@ from django.conf import settings
"""Third party Django app""" """Third party Django app"""
from templated_email import send_templated_mail from templated_email import send_templated_mail
from .models import JuniorPoints from .models import JuniorPoints
from base.constants import NUMBER
from django.db.models import F from django.db.models import F
# junior notification # junior notification
# email for sending email # email for sending email
@ -50,11 +51,11 @@ def junior_approval_mail(guardian, full_name):
def update_positions_based_on_points(): def update_positions_based_on_points():
"""Update position of the junior""" """Update position of the junior"""
# First, retrieve all the JuniorPoints instances ordered by total_points in descending order. # First, retrieve all the JuniorPoints instances ordered by total_points in descending order.
juniors_points = JuniorPoints.objects.order_by('-total_points') juniors_points = JuniorPoints.objects.order_by('-total_points', 'created_at')
# Now, iterate through the queryset and update the position field based on the order. # Now, iterate through the queryset and update the position field based on the order.
position = 1 position = NUMBER['one']
for junior_point in juniors_points: for junior_point in juniors_points:
junior_point.position = position junior_point.position = position
junior_point.save() junior_point.save()
position += 1 position += NUMBER['one']

View File

@ -6,6 +6,7 @@ from rest_framework.permissions import IsAuthenticated
from rest_framework.pagination import PageNumberPagination from rest_framework.pagination import PageNumberPagination
from django.contrib.auth.models import User from django.contrib.auth.models import User
from rest_framework.filters import SearchFilter from rest_framework.filters import SearchFilter
from django.db.models import F
import datetime import datetime
import requests import requests
@ -27,20 +28,25 @@ import requests
# Import upload_image_to_alibaba # Import upload_image_to_alibaba
# Import custom_response, custom_error_response # Import custom_response, custom_error_response
# Import constants # Import constants
from junior.models import Junior, JuniorPoints, JuniorGuardianRelationship from django.db.models import Sum
from .serializers import (CreateJuniorSerializer, JuniorDetailListSerializer, AddJuniorSerializer,\ from junior.models import (Junior, JuniorPoints, JuniorGuardianRelationship, JuniorArticlePoints, JuniorArticle,
JuniorArticleCard)
from .serializers import (CreateJuniorSerializer, JuniorDetailListSerializer, AddJuniorSerializer,
RemoveJuniorSerializer, CompleteTaskSerializer, JuniorPointsSerializer, RemoveJuniorSerializer, CompleteTaskSerializer, JuniorPointsSerializer,
AddGuardianSerializer, StartTaskSerializer, ReAssignTaskSerializer) AddGuardianSerializer, StartTaskSerializer, ReAssignTaskSerializer,
RemoveGuardianCodeSerializer)
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
from base.constants import NUMBER from base.constants import NUMBER, ARTICLE_STATUS
from account.utils import custom_response, custom_error_response from account.utils import custom_response, custom_error_response
from guardian.utils import upload_image_to_alibaba from guardian.utils import upload_image_to_alibaba
from .utils import update_positions_based_on_points from .utils import update_positions_based_on_points
from notifications.utils import send_notification from notifications.utils import send_notification
from notifications.constants import REMOVE_JUNIOR from notifications.constants import REMOVE_JUNIOR
from web_admin.models import Article, ArticleSurvey, SurveyOption, ArticleCard
from web_admin.serializers.article_serializer import (ArticleSerializer, ArticleListSerializer,
StartAssessmentSerializer)
""" Define APIs """ """ Define APIs """
# Define validate guardian code API, # Define validate guardian code API,
# update junior profile, # update junior profile,
@ -59,7 +65,6 @@ from notifications.constants import REMOVE_JUNIOR
# Create your views here. # Create your views here.
class UpdateJuniorProfile(viewsets.ViewSet): class UpdateJuniorProfile(viewsets.ViewSet):
"""Update junior profile""" """Update junior profile"""
queryset = Junior.objects.all()
serializer_class = CreateJuniorSerializer serializer_class = CreateJuniorSerializer
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]
@ -93,7 +98,6 @@ class UpdateJuniorProfile(viewsets.ViewSet):
class ValidateGuardianCode(viewsets.ViewSet): class ValidateGuardianCode(viewsets.ViewSet):
"""Check guardian code exist or not""" """Check guardian code exist or not"""
queryset = Guardian.objects.all()
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]
def list(self, request, *args, **kwargs): def list(self, request, *args, **kwargs):
@ -151,8 +155,19 @@ class AddJuniorAPIView(viewsets.ModelViewSet):
def create(self, request, *args, **kwargs): def create(self, request, *args, **kwargs):
""" junior list""" """ junior list"""
try: try:
info_data = {'user': request.user, 'relationship': str(request.data['relationship']), 'email': request.data['email'], 'first_name': request.data['first_name'], info_data = {'user': request.user, 'relationship': str(request.data['relationship']),
'last_name': request.data['last_name']} 'email': request.data['email'], 'first_name': request.data['first_name'],
'last_name': request.data['last_name'], 'image':None}
profile_image = request.data.get('image')
if profile_image:
# check image size
if profile_image.size == NUMBER['zero']:
return custom_error_response(ERROR_CODE['2035'], response_status=status.HTTP_400_BAD_REQUEST)
# convert into file
filename = f"images/{profile_image.name}"
# upload image on ali baba
image_url = upload_image_to_alibaba(profile_image, filename)
info_data.update({"image": image_url})
if user := User.objects.filter(username=request.data['email']).first(): if user := User.objects.filter(username=request.data['email']).first():
self.associate_guardian(user) self.associate_guardian(user)
return custom_response(SUCCESS_CODE['3021'], response_status=status.HTTP_200_OK) return custom_response(SUCCESS_CODE['3021'], response_status=status.HTTP_200_OK)
@ -162,7 +177,7 @@ class AddJuniorAPIView(viewsets.ModelViewSet):
# save serializer # save serializer
serializer.save() serializer.save()
return custom_response(SUCCESS_CODE['3021'], serializer.data, response_status=status.HTTP_200_OK) return custom_response(SUCCESS_CODE['3021'], serializer.data, response_status=status.HTTP_200_OK)
return custom_error_response(serializer.error, response_status=status.HTTP_400_BAD_REQUEST) return custom_error_response(serializer.errors, 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)
@ -170,6 +185,7 @@ class AddJuniorAPIView(viewsets.ModelViewSet):
junior = Junior.objects.filter(auth=user).first() junior = Junior.objects.filter(auth=user).first()
guardian = Guardian.objects.filter(user=self.request.user).first() guardian = Guardian.objects.filter(user=self.request.user).first()
junior.guardian_code = [guardian.guardian_code] junior.guardian_code = [guardian.guardian_code]
junior.guardian_code_status = str(NUMBER['two'])
junior.save() junior.save()
JuniorGuardianRelationship.objects.get_or_create(guardian=guardian, junior=junior, JuniorGuardianRelationship.objects.get_or_create(guardian=guardian, junior=junior,
relationship=str(self.request.data['relationship'])) relationship=str(self.request.data['relationship']))
@ -180,7 +196,6 @@ class InvitedJuniorAPIView(viewsets.ModelViewSet):
"""Junior list of assosicated guardian""" """Junior list of assosicated guardian"""
serializer_class = JuniorDetailListSerializer serializer_class = JuniorDetailListSerializer
queryset = Junior.objects.all()
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]
pagination_class = PageNumberPagination pagination_class = PageNumberPagination
http_method_names = ('get',) http_method_names = ('get',)
@ -210,7 +225,6 @@ class FilterJuniorAPIView(viewsets.ModelViewSet):
serializer_class = JuniorDetailListSerializer serializer_class = JuniorDetailListSerializer
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]
pagination_class = PageNumberPagination pagination_class = PageNumberPagination
queryset = Junior.objects.all()
http_method_names = ('get',) http_method_names = ('get',)
def get_queryset(self): def get_queryset(self):
@ -247,7 +261,8 @@ class RemoveJuniorAPIView(views.APIView):
junior_id = self.request.GET.get('id') junior_id = self.request.GET.get('id')
guardian = Guardian.objects.filter(user__email=self.request.user).last() guardian = Guardian.objects.filter(user__email=self.request.user).last()
# fetch junior query # fetch junior query
junior_queryset = Junior.objects.filter(id=junior_id, guardian_code__icontains=str(guardian.guardian_code)).last() junior_queryset = Junior.objects.filter(id=junior_id,
guardian_code__icontains=str(guardian.guardian_code)).last()
if junior_queryset: if junior_queryset:
# use RemoveJuniorSerializer serializer # use RemoveJuniorSerializer serializer
serializer = RemoveJuniorSerializer(junior_queryset, data=request.data, partial=True) serializer = RemoveJuniorSerializer(junior_queryset, data=request.data, partial=True)
@ -268,7 +283,6 @@ class JuniorTaskListAPIView(viewsets.ModelViewSet):
serializer_class = TaskDetailsjuniorSerializer serializer_class = TaskDetailsjuniorSerializer
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]
pagination_class = PageNumberPagination pagination_class = PageNumberPagination
queryset = JuniorTask.objects.all()
http_method_names = ('get',) http_method_names = ('get',)
def list(self, request, *args, **kwargs): def list(self, request, *args, **kwargs):
@ -343,16 +357,12 @@ class JuniorPointsListAPIView(viewsets.ModelViewSet):
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]
http_method_names = ('get',) http_method_names = ('get',)
def get_queryset(self):
"""get queryset"""
return JuniorTask.objects.filter(junior__auth__email=self.request.user).last()
def list(self, request, *args, **kwargs): def list(self, request, *args, **kwargs):
"""profile view""" """profile view"""
try: try:
queryset = self.get_queryset()
# update position of junior
update_positions_based_on_points() update_positions_based_on_points()
queryset = JuniorPoints.objects.filter(junior__auth__email=self.request.user).last()
# update position of junior
serializer = JuniorPointsSerializer(queryset) serializer = JuniorPointsSerializer(queryset)
return custom_response(None, serializer.data, response_status=status.HTTP_200_OK) return custom_response(None, serializer.data, response_status=status.HTTP_200_OK)
except Exception as e: except Exception as e:
@ -458,3 +468,184 @@ class ReAssignJuniorTaskAPIView(views.APIView):
return custom_error_response(ERROR_CODE['2066'], response_status=status.HTTP_400_BAD_REQUEST) return custom_error_response(ERROR_CODE['2066'], 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 StartArticleAPIView(viewsets.ModelViewSet):
"""Start article"""
permission_classes = [IsAuthenticated]
http_method_names = ('post',)
def create(self, request, *args, **kwargs):
""" junior list"""
try:
junior_instance = Junior.objects.filter(auth=self.request.user).last()
article_id = request.data.get('article_id')
article_data = Article.objects.filter(id=article_id).last()
if not JuniorArticle.objects.filter(junior=junior_instance, article=article_data).last():
JuniorArticle.objects.create(junior=junior_instance, article=article_data, status=str(NUMBER['two']),
current_card_page=NUMBER['zero'], current_que_page=NUMBER['zero'])
if article_data:
question_query = ArticleSurvey.objects.filter(article=article_id)
for question in question_query:
if not JuniorArticlePoints.objects.filter(junior=junior_instance,
article=article_data,
question=question):
JuniorArticlePoints.objects.create(junior=junior_instance,
article=article_data,
question=question)
return custom_response(SUCCESS_CODE['3040'], response_status=status.HTTP_200_OK)
except Exception as e:
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
class StartAssessmentAPIView(viewsets.ModelViewSet):
"""Junior Points viewset"""
serializer_class = StartAssessmentSerializer
permission_classes = [IsAuthenticated]
http_method_names = ('get',)
def get_queryset(self):
article_id = self.request.GET.get('article_id')
# if referral_code:
article = Article.objects.filter(id=article_id, is_deleted=False).prefetch_related(
'article_cards', 'article_survey', 'article_survey__options'
).order_by('-created_at')
return article
def list(self, request, *args, **kwargs):
"""profile view"""
try:
queryset = self.get_queryset()
paginator = self.pagination_class()
paginated_queryset = paginator.paginate_queryset(queryset, request)
serializer = self.serializer_class(paginated_queryset, context={"user":request.user}, many=True)
return custom_response(None, serializer.data, response_status=status.HTTP_200_OK)
except Exception as e:
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
class CheckAnswerAPIView(viewsets.ModelViewSet):
"""Junior Points viewset"""
permission_classes = [IsAuthenticated]
http_method_names = ('get',)
def get_queryset(self):
question_id = self.request.GET.get('question_id')
article = ArticleSurvey.objects.filter(id=question_id).last()
return article
def list(self, request, *args, **kwargs):
"""profile view"""
try:
answer_id = self.request.GET.get('answer_id')
current_page = self.request.GET.get('current_page')
queryset = self.get_queryset()
submit_ans = SurveyOption.objects.filter(id=answer_id, is_answer=True).last()
junior_article_points = JuniorArticlePoints.objects.filter(junior__auth=self.request.user,
question=queryset)
if submit_ans:
junior_article_points.update(submitted_answer=submit_ans, is_attempt=True, is_answer_correct=True)
JuniorPoints.objects.filter(junior__auth=self.request.user).update(total_points=
F('total_points') + queryset.points)
else:
junior_article_points.update(submitted_answer=submit_ans, is_attempt=True, earn_points=0,
is_answer_correct=False)
JuniorArticle.objects.filter(junior__auth=self.request.user,
article=queryset.article).update(
current_que_page=int(current_page) + NUMBER['one'])
return custom_response(None, response_status=status.HTTP_200_OK)
except Exception as e:
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
class CompleteArticleAPIView(views.APIView):
"""Remove junior API"""
permission_classes = [IsAuthenticated]
http_method_names = ('put', 'get',)
def put(self, request, format=None):
try:
article_id = self.request.data.get('article_id')
JuniorArticle.objects.filter(junior__auth=request.user, article__id=article_id).update(
is_completed=True, status=str(NUMBER['three'])
)
return custom_response(SUCCESS_CODE['3041'], response_status=status.HTTP_200_OK)
except Exception as e:
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
def get(self, request, *args, **kwargs):
""" junior list"""
try:
article_id = self.request.GET.get('article_id')
total_earn_points = JuniorArticlePoints.objects.filter(junior__auth=request.user,
article__id=article_id,
is_answer_correct=True).aggregate(
total_earn_points=Sum('earn_points'))['total_earn_points']
data = {"total_earn_points":total_earn_points}
return custom_response(SUCCESS_CODE['3042'], data, response_status=status.HTTP_200_OK)
except Exception as e:
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
class ReadArticleCardAPIView(views.APIView):
"""Remove junior API"""
permission_classes = [IsAuthenticated]
http_method_names = ('put',)
def put(self, request, *args, **kwargs):
""" junior list"""
try:
junior_instance = Junior.objects.filter(auth=self.request.user).last()
article = self.request.data.get('article_id')
article_card = self.request.data.get('article_card')
current_page = self.request.data.get('current_page')
JuniorArticleCard.objects.filter(junior=junior_instance,
article__id=article,
article_card__id=article_card).update(is_read=True)
JuniorArticle.objects.filter(junior=junior_instance,
article__id=article).update(current_card_page=int(current_page)+NUMBER['one'])
return custom_response(SUCCESS_CODE['3043'], response_status=status.HTTP_200_OK)
except Exception as e:
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
class CreateArticleCardAPIView(viewsets.ModelViewSet):
"""Start article"""
permission_classes = [IsAuthenticated]
http_method_names = ('post',)
def create(self, request, *args, **kwargs):
""" junior list"""
try:
junior_instance = Junior.objects.filter(auth=self.request.user).last()
article_id = request.data.get('article_id')
article_data = Article.objects.filter(id=article_id).last()
if article_data:
article_cards = ArticleCard.objects.filter(article=article_id)
for article_card in article_cards:
if not JuniorArticleCard.objects.filter(junior=junior_instance,
article=article_data,
article_card=article_card):
JuniorArticleCard.objects.create(junior=junior_instance,
article=article_data,
article_card=article_card)
return custom_response(None, response_status=status.HTTP_200_OK)
except Exception as e:
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
class RemoveGuardianCodeAPIView(views.APIView):
"""Update junior task API"""
serializer_class = RemoveGuardianCodeSerializer
permission_classes = [IsAuthenticated]
def put(self, request, format=None):
try:
junior_queryset = Junior.objects.filter(auth=self.request.user).last()
if junior_queryset:
# use RemoveGuardianCodeSerializer serializer
serializer = RemoveGuardianCodeSerializer(junior_queryset, data=request.data, partial=True)
if serializer.is_valid():
# save serializer
serializer.save()
return custom_response(SUCCESS_CODE['3044'], response_status=status.HTTP_200_OK)
return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST)
else:
# task in another state
return custom_error_response(ERROR_CODE['2047'], response_status=status.HTTP_400_BAD_REQUEST)
except Exception as e:
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)

View File

@ -49,7 +49,7 @@ class ArticleSurvey(models.Model):
def __str__(self): def __str__(self):
"""Return title""" """Return title"""
return f'{self.id} | {self.article}' return f'{self.id} | {self.question}'
class SurveyOption(models.Model): class SurveyOption(models.Model):
@ -64,7 +64,7 @@ class SurveyOption(models.Model):
def __str__(self): def __str__(self):
"""Return title""" """Return title"""
return f'{self.id} | {self.survey}' return f'{self.id} | {self.option}'
class DefaultArticleCardImage(models.Model): class DefaultArticleCardImage(models.Model):

View File

@ -0,0 +1,52 @@
"""
web_admin analytics serializer file
"""
from rest_framework import serializers
from junior.models import JuniorPoints, Junior
class JuniorLeaderboardSerializer(serializers.ModelSerializer):
name = serializers.SerializerMethodField()
first_name = serializers.SerializerMethodField()
last_name = serializers.SerializerMethodField()
class Meta:
"""
meta class
"""
model = Junior
fields = ('id', 'name', 'first_name', 'last_name', 'is_active', 'image')
@staticmethod
def get_name(obj):
"""
:param obj: junior object
:return: full name
"""
return f"{obj.auth.first_name} {obj.auth.last_name}" if obj.auth.last_name else obj.auth.first_name
@staticmethod
def get_first_name(obj):
"""
:param obj: junior object
:return: first name
"""
return obj.auth.first_name
@staticmethod
def get_last_name(obj):
"""
:param obj: junior object
:return: last name
"""
return obj.auth.last_name
class LeaderboardSerializer(serializers.ModelSerializer):
junior = JuniorLeaderboardSerializer()
rank = serializers.IntegerField()
class Meta:
model = JuniorPoints
fields = ('total_points', 'rank', 'junior')

View File

@ -12,7 +12,7 @@ from base.messages import ERROR_CODE
from guardian.utils import upload_image_to_alibaba from guardian.utils import upload_image_to_alibaba
from web_admin.models import Article, ArticleCard, SurveyOption, ArticleSurvey, DefaultArticleCardImage from web_admin.models import Article, ArticleCard, SurveyOption, ArticleSurvey, DefaultArticleCardImage
from web_admin.utils import pop_id, get_image_url from web_admin.utils import pop_id, get_image_url
from junior.models import JuniorArticlePoints, JuniorArticle
USER = get_user_model() USER = get_user_model()
@ -220,16 +220,114 @@ class ArticleListSerializer(serializers.ModelSerializer):
serializer for article API serializer for article API
""" """
article_cards = ArticleCardSerializer(many=True) article_cards = ArticleCardSerializer(many=True)
article_survey = ArticleSurveySerializer(many=True)
total_points = serializers.SerializerMethodField('get_total_points') total_points = serializers.SerializerMethodField('get_total_points')
is_completed = serializers.SerializerMethodField('get_is_completed')
class Meta: class Meta:
""" """
meta class meta class
""" """
model = Article model = Article
fields = ('id', 'title', 'description', 'article_cards', 'total_points') fields = ('id', 'title', 'description', 'article_cards', 'article_survey', 'total_points', 'is_completed')
def get_total_points(self, obj): def get_total_points(self, obj):
"""total points of article""" """total points of article"""
total_question = ArticleSurvey.objects.filter(article=obj).count() total_question = ArticleSurvey.objects.filter(article=obj).count()
return total_question * 5 return total_question * NUMBER['five']
def get_is_completed(self, obj):
"""complete all question"""
junior_article = JuniorArticle.objects.filter(article=obj).last()
if junior_article:
junior_article.is_completed
return False
class ArticleQuestionSerializer(serializers.ModelSerializer):
"""
article survey serializer
"""
id = serializers.IntegerField(required=False)
options = SurveyOptionSerializer(many=True)
is_attempt = serializers.SerializerMethodField('get_is_attempt')
correct_answer = serializers.SerializerMethodField('get_correct_answer')
attempted_answer = serializers.SerializerMethodField('get_attempted_answer')
def get_is_attempt(self, obj):
"""attempt question or not"""
context_data = self.context.get('user')
junior_article_obj = JuniorArticlePoints.objects.filter(junior__auth=context_data, question=obj).last()
if junior_article_obj:
return junior_article_obj.is_attempt
return False
def get_correct_answer(self, obj):
"""attempt question or not"""
ans_obj = SurveyOption.objects.filter(survey=obj, is_answer=True).last()
if ans_obj:
return ans_obj.id
return str("None")
def get_attempted_answer(self, obj):
"""attempt question or not"""
context_data = self.context.get('user')
junior_article_obj = JuniorArticlePoints.objects.filter(junior__auth=context_data,
question=obj, is_answer_correct=True).last()
if junior_article_obj:
return junior_article_obj.submitted_answer.id
return None
class Meta:
"""
meta class
"""
model = ArticleSurvey
fields = ('id', 'question', 'options', 'points', 'is_attempt', 'correct_answer', 'attempted_answer')
class StartAssessmentSerializer(serializers.ModelSerializer):
"""
serializer for article API
"""
article_survey = ArticleQuestionSerializer(many=True)
current_page = serializers.SerializerMethodField('get_current_page')
def get_current_page(self, obj):
"""current page"""
context_data = self.context.get('user')
data = JuniorArticle.objects.filter(junior__auth=context_data, article=obj).last()
if data:
return data.current_que_page
return NUMBER['zero']
class Meta:
"""
meta class
"""
model = Article
fields = ('article_survey', 'current_page')
class ArticleCardlistSerializer(serializers.ModelSerializer):
"""
Article Card serializer
"""
id = serializers.IntegerField(required=False)
image_name = serializers.CharField(required=False)
image_url = serializers.CharField(required=False)
current_page = serializers.SerializerMethodField('get_current_page')
def get_current_page(self, obj):
"""current page"""
context_data = self.context.get('user')
data = JuniorArticle.objects.filter(junior__auth=context_data, article=obj.article).last()
if data:
return data.current_card_page
return NUMBER['zero']
class Meta:
"""
meta class
"""
model = ArticleCard
fields = ('id', 'title', 'description', 'image_name', 'image_url', 'current_page')

View File

@ -87,9 +87,9 @@ class AdminVerifyOTPSerializer(serializers.Serializer):
# fetch email otp object of the user # fetch email otp object of the user
user_otp_details = UserEmailOtp.objects.filter(email=email, otp=otp).last() user_otp_details = UserEmailOtp.objects.filter(email=email, otp=otp).last()
if not user_otp_details: if not user_otp_details:
raise serializers.ValidationError({'details': ERROR_CODE['2064']}) raise serializers.ValidationError({'details': ERROR_CODE['2008']})
if user_otp_details.user_type != dict(USER_TYPE).get('3'): if user_otp_details.user_type != dict(USER_TYPE).get('3'):
raise serializers.ValidationError({'details': ERROR_CODE['2063']}) raise serializers.ValidationError({'details': ERROR_CODE['2008']})
if user_otp_details.expired_at.replace(tzinfo=None) < datetime.utcnow(): if user_otp_details.expired_at.replace(tzinfo=None) < datetime.utcnow():
raise serializers.ValidationError({'details': ERROR_CODE['2029']}) raise serializers.ValidationError({'details': ERROR_CODE['2029']})
user_otp_details.is_verified = True user_otp_details.is_verified = True

View File

@ -6,7 +6,9 @@ from django.urls import path, include
from rest_framework import routers from rest_framework import routers
# local imports # local imports
from web_admin.views.article import ArticleViewSet, DefaultArticleCardImagesViewSet, ArticleListViewSet from web_admin.views.analytics import AnalyticsViewSet
from web_admin.views.article import (ArticleViewSet, DefaultArticleCardImagesViewSet, ArticleListViewSet,
ArticleCardListViewSet)
from web_admin.views.auth import ForgotAndResetPasswordViewSet from web_admin.views.auth import ForgotAndResetPasswordViewSet
from web_admin.views.user_management import UserManagementViewSet from web_admin.views.user_management import UserManagementViewSet
@ -16,7 +18,11 @@ router = routers.SimpleRouter()
router.register('article', ArticleViewSet, basename='article') router.register('article', ArticleViewSet, basename='article')
router.register('default-card-images', DefaultArticleCardImagesViewSet, basename='default-card-images') router.register('default-card-images', DefaultArticleCardImagesViewSet, basename='default-card-images')
router.register('user-management', UserManagementViewSet, basename='user') router.register('user-management', UserManagementViewSet, basename='user')
router.register('analytics', AnalyticsViewSet, basename='user-analytics')
router.register('article-list', ArticleListViewSet, basename='article-list') router.register('article-list', ArticleListViewSet, basename='article-list')
router.register('article-card-list', ArticleCardListViewSet, basename='article-card-list')
# forgot and reset password api for admin # forgot and reset password api for admin
router.register('admin', ForgotAndResetPasswordViewSet, basename='admin') router.register('admin', ForgotAndResetPasswordViewSet, basename='admin')

View File

@ -29,7 +29,7 @@ def get_image_url(data):
return data['image_url'] return data['image_url']
elif 'image_url' in data and type(data['image_url']) == str and data['image_url'].startswith('data:image'): elif 'image_url' in data and type(data['image_url']) == str and data['image_url'].startswith('data:image'):
base64_image = base64.b64decode(data.get('image_url').split(',')[1]) base64_image = base64.b64decode(data.get('image_url').split(',')[1])
image_name = f"{data['title']} | {data.pop('image_name')}" if 'image_name' in data else data['title'] image_name = f"{data['title']} {data.pop('image_name')}" if 'image_name' in data else data['title']
filename = f"{ARTICLE_CARD_IMAGE_FOLDER}/{image_name}" filename = f"{ARTICLE_CARD_IMAGE_FOLDER}/{image_name}"
# upload image on ali baba # upload image on ali baba
image_url = upload_image_to_alibaba(base64_image, filename) image_url = upload_image_to_alibaba(base64_image, filename)

View File

@ -0,0 +1,134 @@
"""
web_admin analytics view file
"""
import datetime
from rest_framework.viewsets import GenericViewSet
from rest_framework.decorators import action
from django.contrib.auth import get_user_model
from django.db.models import Q
from django.db.models import Count
from django.db.models.functions import TruncDate
from django.db.models import F, Window
from django.db.models.functions.window import Rank
from account.utils import custom_response
from base.constants import PENDING, IN_PROGRESS, REJECTED, REQUESTED, COMPLETED, EXPIRED, DATE_FORMAT
from guardian.models import JuniorTask
from junior.models import JuniorPoints
from web_admin.serializers.analytics_serializer import LeaderboardSerializer
USER = get_user_model()
class AnalyticsViewSet(GenericViewSet):
"""
analytics api view
to get user report (active users, guardians and juniors counts)
to get new user sign up report
to get task report (completed, in-progress, requested and rejected tasks count)
to get junior leaderboard and ranking
"""
serializer_class = None
def get_queryset(self):
user_qs = USER.objects.filter(
(Q(junior_profile__is_verified=True) | Q(guardian_profile__is_verified=True)),
is_superuser=False
).prefetch_related('guardian_profile',
'junior_profile'
).exclude(junior_profile__isnull=True,
guardian_profile__isnull=True).order_by('date_joined')
return user_qs
@action(methods=['get'], url_name='users-count', url_path='users-count', detail=False)
def total_users_count(self, request, *args, **kwargs):
"""
api method to get total users, guardians and juniors
:param request: start_date: date format (yyyy-mm-dd)
:param request: end_date: date format (yyyy-mm-dd)
:return:
"""
end_date = datetime.date.today()
start_date = end_date - datetime.timedelta(days=6)
if request.query_params.get('start_date') and request.query_params.get('end_date'):
start_date = datetime.datetime.strptime(request.query_params.get('start_date'), DATE_FORMAT)
end_date = datetime.datetime.strptime(request.query_params.get('end_date'), DATE_FORMAT)
user_qs = self.get_queryset()
queryset = user_qs.filter(date_joined__range=(start_date, (end_date + datetime.timedelta(days=1))))
data = {'total_users': queryset.count(),
'total_guardians': queryset.filter(junior_profile__isnull=True).count(),
'total_juniors': queryset.filter(guardian_profile__isnull=True).count()}
return custom_response(None, data)
@action(methods=['get'], url_name='new-signups', url_path='new-signups', detail=False)
def new_signups(self, request, *args, **kwargs):
"""
api method to get new signups
:param request: start_date: date format (yyyy-mm-dd)
:param request: end_date: date format (yyyy-mm-dd)
:return:
"""
end_date = datetime.date.today()
start_date = end_date - datetime.timedelta(days=6)
if request.query_params.get('start_date') and request.query_params.get('end_date'):
start_date = datetime.datetime.strptime(request.query_params.get('start_date'), DATE_FORMAT)
end_date = datetime.datetime.strptime(request.query_params.get('end_date'), DATE_FORMAT)
user_qs = self.get_queryset()
signup_data = user_qs.filter(date_joined__range=[start_date, (end_date + datetime.timedelta(days=1))]
).annotate(date=TruncDate('date_joined')
).values('date').annotate(signups=Count('id')).order_by('date')
return custom_response(None, signup_data)
@action(methods=['get'], url_name='assign-tasks', url_path='assign-tasks', detail=False)
def assign_tasks_report(self, request, *args, **kwargs):
"""
api method to get assign tasks count for (completed, in-progress, requested and rejected) task
:param request: start_date: date format (yyyy-mm-dd)
:param request: end_date: date format (yyyy-mm-dd)
:return:
"""
end_date = datetime.date.today()
start_date = end_date - datetime.timedelta(days=6)
if request.query_params.get('start_date') and request.query_params.get('end_date'):
start_date = datetime.datetime.strptime(request.query_params.get('start_date'), DATE_FORMAT)
end_date = datetime.datetime.strptime(request.query_params.get('end_date'), DATE_FORMAT)
assign_tasks = JuniorTask.objects.filter(
created_at__range=[start_date, (end_date + datetime.timedelta(days=1))]
).exclude(task_status__in=[PENDING, EXPIRED])
data = {
'task_completed': assign_tasks.filter(task_status=COMPLETED).count(),
'task_in_progress': assign_tasks.filter(task_status=IN_PROGRESS).count(),
'task_requested': assign_tasks.filter(task_status=REQUESTED).count(),
'task_rejected': assign_tasks.filter(task_status=REJECTED).count(),
}
return custom_response(None, data)
@action(methods=['get'], url_name='junior-leaderboard', url_path='junior-leaderboard', detail=False,
serializer_class=LeaderboardSerializer)
def junior_leaderboard(self, request):
"""
to get junior leaderboard and rank
:param request:
:return:
"""
queryset = JuniorPoints.objects.prefetch_related('junior', 'junior__auth').annotate(rank=Window(
expression=Rank(),
order_by=[F('total_points').desc(), 'junior__created_at']
)).order_by('-total_points', 'junior__created_at')
paginator = self.pagination_class()
paginated_queryset = paginator.paginate_queryset(queryset, request)
serializer = self.serializer_class(paginated_queryset, many=True)
return custom_response(None, serializer.data)

View File

@ -4,7 +4,7 @@ web_admin views file
# django imports # django imports
from rest_framework.viewsets import GenericViewSet, mixins from rest_framework.viewsets import GenericViewSet, mixins
from rest_framework.filters import OrderingFilter, SearchFilter from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework import status from rest_framework import status, viewsets
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated, AllowAny from rest_framework.permissions import IsAuthenticated, AllowAny
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
@ -16,7 +16,8 @@ from base.messages import SUCCESS_CODE, ERROR_CODE
from web_admin.models import Article, ArticleCard, ArticleSurvey, DefaultArticleCardImage from web_admin.models import Article, ArticleCard, ArticleSurvey, DefaultArticleCardImage
from web_admin.permission import AdminPermission from web_admin.permission import AdminPermission
from web_admin.serializers.article_serializer import (ArticleSerializer, ArticleCardSerializer, from web_admin.serializers.article_serializer import (ArticleSerializer, ArticleCardSerializer,
DefaultArticleCardImageSerializer, ArticleListSerializer) DefaultArticleCardImageSerializer, ArticleListSerializer,
ArticleCardlistSerializer)
USER = get_user_model() USER = get_user_model()
@ -224,4 +225,24 @@ class ArticleListViewSet(GenericViewSet, mixins.ListModelMixin):
paginator = self.pagination_class() paginator = self.pagination_class()
paginated_queryset = paginator.paginate_queryset(queryset, request) paginated_queryset = paginator.paginate_queryset(queryset, request)
serializer = self.serializer_class(paginated_queryset, many=True) serializer = self.serializer_class(paginated_queryset, many=True)
return custom_response(None, data=serializer.data, count=count) return custom_response(None, data=serializer.data)
class ArticleCardListViewSet(viewsets.ModelViewSet):
"""Junior Points viewset"""
serializer_class = ArticleCardlistSerializer
permission_classes = [IsAuthenticated]
http_method_names = ('get',)
def get_queryset(self):
"""get queryset"""
return ArticleCard.objects.filter(article=self.request.GET.get('article_id'))
def list(self, request, *args, **kwargs):
"""profile view"""
try:
queryset = self.get_queryset()
# article card list
serializer = ArticleCardlistSerializer(queryset, context={"user": self.request.user}, many=True)
return custom_response(None, serializer.data, response_status=status.HTTP_200_OK)
except Exception as e:
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)

View File

@ -29,11 +29,12 @@ class UserManagementViewSet(GenericViewSet, mixins.ListModelMixin,
""" """
serializer_class = UserManagementListSerializer serializer_class = UserManagementListSerializer
permission_classes = [IsAuthenticated, AdminPermission] permission_classes = [IsAuthenticated, AdminPermission]
queryset = USER.objects.filter(is_superuser=False queryset = USER.objects.filter(
).prefetch_related('guardian_profile', (Q(junior_profile__is_verified=True) | Q(guardian_profile__is_verified=True)),
is_superuser=False).prefetch_related('guardian_profile',
'junior_profile' 'junior_profile'
).exclude(junior_profile__isnull=True, ).exclude(junior_profile__isnull=True,
guardian_profile__isnull=True).order_by('date_joined') guardian_profile__isnull=True).order_by('-date_joined')
filter_backends = (SearchFilter,) filter_backends = (SearchFilter,)
search_fields = ['first_name', 'last_name'] search_fields = ['first_name', 'last_name']
http_method_names = ['get', 'post', 'patch'] http_method_names = ['get', 'post', 'patch']
@ -55,8 +56,6 @@ class UserManagementViewSet(GenericViewSet, mixins.ListModelMixin,
:return: :return:
""" """
queryset = self.get_queryset() queryset = self.get_queryset()
queryset = queryset.filter(
(Q(junior_profile__is_verified=True) | Q(guardian_profile__is_verified=True)))
paginator = self.pagination_class() paginator = self.pagination_class()
paginated_queryset = paginator.paginate_queryset(queryset, request) paginated_queryset = paginator.paginate_queryset(queryset, request)
serializer = self.serializer_class(paginated_queryset, many=True) serializer = self.serializer_class(paginated_queryset, many=True)

View File

@ -177,6 +177,31 @@ AUTH_PASSWORD_VALIDATORS = [
}, },
] ]
LOGGING = {
"version": 1,
"filters": {
"require_debug_true": {
"()": "django.utils.log.RequireDebugTrue"
}
},
"handlers": {
"console": {
"level": "DEBUG",
"filters": [
"require_debug_true"
],
"class": "logging.StreamHandler"
}
},
"loggers": {
"django.db.backends": {
"level": "DEBUG",
"handlers": [
"console"
]
}
}
}
# Internationalization # Internationalization
# https://docs.djangoproject.com/en/3.0/topics/i18n/ # https://docs.djangoproject.com/en/3.0/topics/i18n/