Compare commits

..

17 Commits

Author SHA1 Message Date
c7c55f2a04 user notification issue 2023-08-16 16:41:08 +05:30
bcf308b6eb Merge pull request #213 from KiwiTechLLC/qa
Qa
2023-08-16 11:39:02 +05:30
54748a6704 Merge pull request #210 from KiwiTechLLC/qa
Qa
2023-08-14 18:24:10 +05:30
74e704570a Merge pull request #208 from KiwiTechLLC/qa
Qa
2023-08-14 17:34:25 +05:30
136d0b732a Merge pull request #204 from KiwiTechLLC/qa
Qa
2023-08-14 11:46:35 +05:30
b974cc2010 Merge pull request #201 from KiwiTechLLC/qa
Qa
2023-08-11 17:08:10 +05:30
4fddc7b3e2 Merge pull request #131 from KiwiTechLLC/qa
Qa
2023-07-28 20:19:40 +05:30
ed18758cc5 Merge pull request #125 from KiwiTechLLC/qa
Qa
2023-07-28 11:13:10 +05:30
fb74c6c207 Merge pull request #67 from KiwiTechLLC/qa
change access token duration
2023-07-14 12:46:38 +05:30
87cb49d34d Merge pull request #66 from KiwiTechLLC/qa
Qa
2023-07-13 19:25:57 +05:30
4261b5ad29 Merge pull request #31 from KiwiTechLLC/qa
Qa
2023-06-30 17:22:54 +05:30
6c0c3e0aca Merge pull request #29 from KiwiTechLLC/qa
Qa
2023-06-30 16:26:16 +05:30
c6b220d6f2 Merge pull request #27 from KiwiTechLLC/qa
Qa
2023-06-30 15:54:15 +05:30
b5b793dc88 Merge pull request #25 from KiwiTechLLC/qa
Qa
2023-06-30 11:19:12 +05:30
1b5019e347 Merge pull request #22 from KiwiTechLLC/qa
Qa
2023-06-29 21:49:47 +05:30
8c1e96a3df Merge pull request #19 from KiwiTechLLC/qa
Qa
2023-06-29 21:25:52 +05:30
545fa8229b Merge pull request #12 from KiwiTechLLC/qa
Qa to stage First commit
2023-06-28 17:53:09 +05:30
46 changed files with 464 additions and 1520 deletions

View File

@ -2,7 +2,7 @@
from django.contrib import admin
"""Import django app"""
from .models import UserEmailOtp, DefaultTaskImages, UserNotification, UserDelete, UserDeviceDetails, ForceUpdate
from .models import UserEmailOtp, DefaultTaskImages, UserNotification, UserDelete, UserDeviceDetails
# Register your models here.
@admin.register(UserDelete)
@ -39,19 +39,6 @@ class UserEmailOtpAdmin(admin.ModelAdmin):
"""Return object in email and otp format"""
return self.email + '-' + self.otp
@admin.register(ForceUpdate)
class ForceUpdateAdmin(admin.ModelAdmin):
"""Force update"""
list_display = ['version', 'device_type']
readonly_fields = ('device_type',)
def has_add_permission(self, request):
count = ForceUpdate.objects.all().count()
if count < 2:
return True
return False
def has_delete_permission(self, request, obj=None):
return False
@admin.register(UserDeviceDetails)
class UserDeviceDetailsAdmin(admin.ModelAdmin):
"""User profile admin"""

View File

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

View File

@ -1,28 +0,0 @@
# Generated by Django 4.2.2 on 2023-08-22 07:39
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('account', '0009_alter_userdevicedetails_device_id'),
]
operations = [
migrations.CreateModel(
name='ForceUpdate',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('version', models.CharField(blank=True, max_length=50, null=True)),
('device_type', models.CharField(blank=True, choices=[('1', 'android'), ('2', 'ios')], default=None, max_length=15, null=True)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
],
options={
'verbose_name': 'Force Update Version',
'verbose_name_plural': 'Force Update Version',
'db_table': 'force_update',
},
),
]

View File

@ -2,9 +2,8 @@
"""Django import"""
from django.db import models
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError
"""App import"""
from base.constants import USER_TYPE, DEVICE_TYPE
from base.constants import USER_TYPE
# Create your models here.
class UserProfile(models.Model):
@ -166,25 +165,3 @@ class UserDeviceDetails(models.Model):
def __str__(self):
return self.user.email
class ForceUpdate(models.Model):
"""
Force update
"""
"""Version ID"""
version = models.CharField(max_length=50, null=True, blank=True)
device_type = models.CharField(max_length=15, choices=DEVICE_TYPE, null=True, blank=True, default=None)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta(object):
""" Meta information """
db_table = 'force_update'
verbose_name = 'Force Update Version'
verbose_name_plural = 'Force Update Version'
def __str__(self):
return self.version

View File

@ -18,7 +18,7 @@ import secrets
from guardian.models import Guardian
from junior.models import Junior
from account.models import UserEmailOtp, DefaultTaskImages, UserDelete, UserNotification, UserPhoneOtp, ForceUpdate
from account.models import UserEmailOtp, DefaultTaskImages, UserDelete, UserNotification, UserPhoneOtp
from base.constants import GUARDIAN, JUNIOR, SUPERUSER, NUMBER
from base.messages import ERROR_CODE, SUCCESS_CODE, STATUS_CODE_ERROR
from .utils import delete_user_account_condition_social, delete_user_account_condition
@ -104,12 +104,10 @@ class ResetPasswordSerializer(serializers.Serializer):
return user_opt_details
return ''
class ChangePasswordSerializer(serializers.Serializer):
"""Update Password after verification"""
current_password = serializers.CharField(max_length=100, required=True)
current_password = serializers.CharField(max_length=100)
new_password = serializers.CharField(required=True)
class Meta(object):
"""Meta info"""
model = User
@ -120,36 +118,25 @@ class ChangePasswordSerializer(serializers.Serializer):
if self.context.password not in ('', None) and user.check_password(value):
return value
raise serializers.ValidationError(ERROR_CODE['2015'])
def create(self, validated_data):
"""
change password
"""
new_password = validated_data.pop('new_password')
current_password = validated_data.pop('current_password')
# Check new password is different from current password
"""Check new password is different from current password"""
if new_password == current_password:
raise serializers.ValidationError({"details": ERROR_CODE['2026']})
user_details = User.objects.filter(email=self.context).last()
if user_details:
user_details.set_password(new_password)
user_details.save()
return {'password':new_password}
return ''
user_details = self.context
user_details.set_password(new_password)
user_details.save()
return {'password':new_password}
class ForgotPasswordSerializer(serializers.Serializer):
"""Forget password serializer"""
email = serializers.EmailField(required=True)
email = serializers.EmailField()
def validate_email(self, value):
"""
validate email exist ot not
value: string
return none
"""
if not User.objects.get(email=value):
raise serializers.ValidationError({'details': ERROR_CODE['2004']})
return value
class AdminLoginSerializer(serializers.ModelSerializer):
"""admin login serializer"""
@ -257,7 +244,7 @@ class GuardianSerializer(serializers.ModelSerializer):
"""Meta info"""
model = Guardian
fields = ['id', 'auth_token', 'refresh_token', 'email', 'first_name', 'last_name', 'country_code',
'phone', 'family_name', 'gender', 'dob', 'referral_code', 'is_active', 'is_deleted',
'phone', 'family_name', 'gender', 'dob', 'referral_code', 'is_active',
'is_complete_profile', 'passcode', 'image', 'created_at', 'updated_at', 'user_type', 'country_name']
@ -300,15 +287,14 @@ class JuniorSerializer(serializers.ModelSerializer):
model = Junior
fields = ['id', 'auth_token', 'refresh_token', 'email', 'first_name', 'last_name', 'country_code',
'phone', 'gender', 'dob', 'guardian_code', 'referral_code','is_active', 'is_password_set',
'is_complete_profile', 'created_at', 'image', 'updated_at', 'user_type', 'country_name','is_invited',
'is_deleted']
'is_complete_profile', 'created_at', 'image', 'updated_at', 'user_type', 'country_name','is_invited']
class EmailVerificationSerializer(serializers.ModelSerializer):
"""Email verification serializer"""
class Meta(object):
"""Meta info"""
model = UserEmailOtp
fields = ('email',)
fields = '__all__'
@ -390,12 +376,3 @@ class UserPhoneOtpSerializer(serializers.ModelSerializer):
"""Meta info"""
model = UserPhoneOtp
fields = '__all__'
class ForceUpdateSerializer(serializers.ModelSerializer):
""" ForceUpdate Serializer
"""
class Meta(object):
""" meta info """
model = ForceUpdate
fields = ('id', 'version', 'device_type')

View File

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

View File

@ -29,7 +29,7 @@ from .views import (UserLogin, SendPhoneOtp, UserPhoneVerification, UserEmailVer
GoogleLoginViewSet, SigninWithApple, ProfileAPIViewSet, UploadImageAPIViewSet,
DefaultImageAPIViewSet, DeleteUserProfileAPIViewSet, UserNotificationAPIViewSet,
UpdateUserNotificationAPIViewSet, SendSupportEmail, LogoutAPIView, AccessTokenAPIView,
AdminLoginViewSet, ForceUpdateViewSet)
AdminLoginViewSet)
"""Router"""
router = routers.SimpleRouter()
@ -39,6 +39,8 @@ router.register('user', UserLogin, basename='user')
router.register('admin', AdminLoginViewSet, basename='admin')
"""google login end point"""
router.register('google-login', GoogleLoginViewSet, basename='admin')
router.register('send-phone-otp', SendPhoneOtp, basename='send-phone-otp')
router.register('user-phone-verification', UserPhoneVerification, basename='user-phone-verification')
"""email verification end point"""
router.register('user-email-verification', UserEmailVerification, basename='user-email-verification')
"""Resend email otp end point"""
@ -55,8 +57,6 @@ router.register('delete', DeleteUserProfileAPIViewSet, basename='delete')
router.register('user-notification', UserNotificationAPIViewSet, basename='user-notification')
"""update user account notification"""
router.register('update-user-notification', UpdateUserNotificationAPIViewSet, basename='update-user-notification')
# Force update entry API
router.register('force-update', ForceUpdateViewSet, basename='force-update')
"""Define url pattern"""
urlpatterns = [
path('api/v1/', include(router.urls)),

View File

@ -93,9 +93,8 @@ def junior_account_update(user_tb):
# Update junior account
junior_data.is_active = False
junior_data.is_verified = False
junior_data.guardian_code = None
junior_data.guardian_code = '{}'
junior_data.guardian_code_status = str(NUMBER['one'])
junior_data.is_deleted = True
junior_data.save()
JuniorPoints.objects.filter(junior=junior_data).delete()
@ -106,7 +105,6 @@ def guardian_account_update(user_tb):
# Update guardian account
guardian_data.is_active = False
guardian_data.is_verified = False
guardian_data.is_deleted = True
guardian_data.save()
jun_data = Junior.objects.filter(guardian_code__icontains=str(guardian_data.guardian_code))
"""Disassociate relation between guardian and junior"""
@ -129,28 +127,6 @@ def send_otp_email(recipient_email, otp):
)
return otp
@shared_task()
def send_all_email(template_name, email, otp):
"""
Send all type of email by passing template name
template_name: string
email: string
otp: string
"""
from_email = settings.EMAIL_FROM_ADDRESS
recipient_list = [email]
send_templated_mail(
template_name=template_name,
from_email=from_email,
recipient_list=recipient_list,
context={
'verification_code': otp
}
)
return otp
@shared_task
def user_device_details(user, device_id):
"""
@ -159,12 +135,10 @@ def user_device_details(user, device_id):
device_id: string
return
"""
device_details, created = UserDeviceDetails.objects.get_or_create(user__id=user)
device_details, created = UserDeviceDetails.objects.get_or_create(user=user)
if device_details:
device_details.device_id = device_id
device_details.save()
return True
return False
def send_support_email(name, sender, subject, message):
@ -204,12 +178,8 @@ def custom_error_response(detail, response_status):
if not detail:
"""when details is empty"""
detail = {}
if response_status == 406:
return Response({"error": detail, "status": "failed", "code": response_status,},
status=status.HTTP_308_PERMANENT_REDIRECT)
else:
return Response({"error": detail, "status": "failed", "code": response_status},
status=status.HTTP_400_BAD_REQUEST)
return Response({"error": detail, "status": "failed", "code": response_status})
def get_user_data(attrs):
"""
@ -281,9 +251,3 @@ def generate_code(value, user_id):
OTP_EXPIRY = timezone.now() + timezone.timedelta(days=1)
def get_user_full_name(user_obj):
"""
to get user's full name
"""
return f"{user_obj.first_name} {user_obj.last_name}" if user_obj.last_name else user_obj.first_name

View File

@ -4,7 +4,6 @@ import threading
from notifications.utils import remove_fcm_token
# django imports
from rest_framework.viewsets import GenericViewSet, mixins
from datetime import datetime, timedelta
from rest_framework import viewsets, status, views
from rest_framework.decorators import action
@ -27,21 +26,20 @@ from django.conf import settings
from guardian.models import Guardian
from junior.models import Junior, JuniorPoints
from guardian.utils import upload_image_to_alibaba
from account.models import (UserDeviceDetails, UserPhoneOtp, UserEmailOtp, DefaultTaskImages, UserNotification,
ForceUpdate)
from account.models import UserDeviceDetails, UserPhoneOtp, UserEmailOtp, DefaultTaskImages, UserNotification
from django.contrib.auth.models import User
from .serializers import (SuperUserSerializer, GuardianSerializer, JuniorSerializer, EmailVerificationSerializer,
ForgotPasswordSerializer, ResetPasswordSerializer, ChangePasswordSerializer,
GoogleLoginSerializer, UpdateGuardianImageSerializer, UpdateJuniorProfileImageSerializer,
DefaultTaskImagesSerializer, DefaultTaskImagesDetailsSerializer, UserDeleteSerializer,
UserNotificationSerializer, UpdateUserNotificationSerializer, UserPhoneOtpSerializer,
AdminLoginSerializer, ForceUpdateSerializer)
AdminLoginSerializer)
from rest_framework_simplejwt.tokens import RefreshToken
from base.messages import ERROR_CODE, SUCCESS_CODE
from base.constants import NUMBER, ZOD, JUN, GRD, USER_TYPE_FLAG
from guardian.tasks import generate_otp
from account.utils import (send_otp_email, send_support_email, custom_response, custom_error_response,
generate_code, OTP_EXPIRY, user_device_details, send_all_email)
generate_code, OTP_EXPIRY, user_device_details)
from junior.serializers import JuniorProfileSerializer
from guardian.serializers import GuardianProfileSerializer
@ -51,8 +49,7 @@ class GoogleLoginMixin(object):
def google_login(request):
"""google login function"""
access_token = request.data.get('access_token')
user_type = request.META.get('HTTP_USER_TYPE')
device_id = request.META.get('HTTP_DEVICE_ID')
user_type = request.data.get('user_type')
if not access_token:
return Response({'error': 'Access token is required.'}, status=status.HTTP_400_BAD_REQUEST)
@ -85,29 +82,14 @@ class GoogleLoginMixin(object):
if user_data.exists():
if str(user_type) == '1':
junior_query = Junior.objects.filter(auth=user_data.last()).last()
if not junior_query:
return custom_error_response(
ERROR_CODE["2071"],
response_status=status.HTTP_400_BAD_REQUEST
)
serializer = JuniorSerializer(junior_query)
elif str(user_type) == '2':
if str(user_type) == '2':
guardian_query = Guardian.objects.filter(user=user_data.last()).last()
if not guardian_query:
return custom_error_response(
ERROR_CODE["2070"],
response_status=status.HTTP_400_BAD_REQUEST
)
serializer = GuardianSerializer(guardian_query)
else:
return custom_error_response(
ERROR_CODE["2069"],
response_status=status.HTTP_400_BAD_REQUEST
)
return custom_response(SUCCESS_CODE['3003'], serializer.data,
response_status=status.HTTP_200_OK)
else:
if not User.objects.filter(email__iexact=email).exists():
user_obj = User.objects.create(username=email, email=email, first_name=first_name, last_name=last_name)
if str(user_type) == '1':
junior_query = Junior.objects.create(auth=user_obj, is_verified=True, is_active=True,
@ -118,23 +100,13 @@ class GoogleLoginMixin(object):
serializer = JuniorSerializer(junior_query)
position = Junior.objects.all().count()
JuniorPoints.objects.create(junior=junior_query, position=position)
elif str(user_type) == '2':
if str(user_type) == '2':
guardian_query = Guardian.objects.create(user=user_obj, is_verified=True, is_active=True,
image=profile_picture,signup_method='2',
guardian_code=generate_code(GRD, user_obj.id),
referral_code=generate_code(ZOD, user_obj.id)
)
serializer = GuardianSerializer(guardian_query)
else:
user_obj.delete()
return custom_error_response(
ERROR_CODE["2069"],
response_status=status.HTTP_400_BAD_REQUEST
)
device_detail, created = UserDeviceDetails.objects.get_or_create(user=user_obj)
if device_detail:
device_detail.device_id = device_id
device_detail.save()
# Return a JSON response with the user's email and name
return custom_response(SUCCESS_CODE['3003'], serializer.data,
response_status=status.HTTP_200_OK)
@ -145,26 +117,16 @@ class GoogleLoginViewSet(GoogleLoginMixin, viewsets.GenericViewSet):
serializer_class = GoogleLoginSerializer
def create(self, request):
"""Payload
{
"access_token",
"user_type": "1"
}"""
"""create method"""
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
return self.google_login(request)
class SigninWithApple(views.APIView):
"""This API is for sign in with Apple for app.
Payload
{
"access_token",
"user_type": "1"
}"""
"""This API is for sign in with Apple for app."""
def post(self, request):
token = request.data.get("access_token")
user_type = request.META.get('HTTP_USER_TYPE')
device_id = request.META.get('HTTP_DEVICE_ID')
user_type = request.data.get("user_type")
try:
decoded_data = jwt.decode(token, options={"verify_signature": False})
user_data = {"email": decoded_data.get('email'), "username": decoded_data.get('email'), "is_active": True}
@ -172,26 +134,11 @@ class SigninWithApple(views.APIView):
try:
user = User.objects.get(email=decoded_data.get("email"))
if str(user_type) == '1':
junior_data = Junior.objects.filter(auth=user).last()
if not junior_data:
return custom_error_response(
ERROR_CODE["2071"],
response_status=status.HTTP_400_BAD_REQUEST
)
serializer = JuniorSerializer(junior_data)
elif str(user_type) == '2':
guardian_data = Guardian.objects.filter(user=user).last()
if not guardian_data:
return custom_error_response(
ERROR_CODE["2070"],
response_status=status.HTTP_400_BAD_REQUEST
)
serializer = GuardianSerializer(guardian_data)
else:
return custom_error_response(
ERROR_CODE["2069"],
response_status=status.HTTP_400_BAD_REQUEST
)
junior_query = Junior.objects.filter(auth=user).last()
serializer = JuniorSerializer(junior_query)
if str(user_type) == '2':
guardian_query = Guardian.objects.filter(user=user).last()
serializer = GuardianSerializer(guardian_query)
return custom_response(SUCCESS_CODE['3003'], serializer.data,
response_status=status.HTTP_200_OK)
@ -205,22 +152,12 @@ class SigninWithApple(views.APIView):
serializer = JuniorSerializer(junior_query)
position = Junior.objects.all().count()
JuniorPoints.objects.create(junior=junior_query, position=position)
elif str(user_type) == '2':
if str(user_type) == '2':
guardian_query = Guardian.objects.create(user=user, is_verified=True, is_active=True,
signup_method='3',
guardian_code=generate_code(GRD, user.id),
referral_code=generate_code(ZOD, user.id))
serializer = GuardianSerializer(guardian_query)
else:
user.delete()
return custom_error_response(
ERROR_CODE["2069"],
response_status=status.HTTP_400_BAD_REQUEST
)
device_detail, created = UserDeviceDetails.objects.get_or_create(user=user)
if device_detail:
device_detail.device_id = device_id
device_detail.save()
return custom_response(SUCCESS_CODE['3003'], serializer.data,
response_status=status.HTTP_200_OK)
except Exception as e:
@ -256,42 +193,18 @@ class UpdateProfileImage(views.APIView):
return custom_error_response(ERROR_CODE['2036'],response_status=status.HTTP_400_BAD_REQUEST)
class ChangePasswordAPIView(views.APIView):
"""
change password"
"""
"""change password"""
serializer_class = ChangePasswordSerializer
permission_classes = [IsAuthenticated]
def post(self, request):
"""
POST request to change current login user password
Payload
{ "current_password":"Demo@123",
"new_password":"Demo@123"
}
"""
serializer = ChangePasswordSerializer(
context=request.user,
data=request.data
)
serializer = ChangePasswordSerializer(context=request.user, data=request.data)
if serializer.is_valid():
serializer.save()
return custom_response(
SUCCESS_CODE['3007'],
response_status=status.HTTP_200_OK
)
return custom_error_response(
serializer.errors,
response_status=status.HTTP_400_BAD_REQUEST
)
return custom_response(SUCCESS_CODE['3007'], response_status=status.HTTP_200_OK)
return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST)
class ResetPasswordAPIView(views.APIView):
"""Reset password
Payload
{
"verification_code":"373770",
"password":"Demo@1323"
}"""
"""Reset password"""
def post(self, request):
serializer = ResetPasswordSerializer(data=request.data)
if serializer.is_valid():
@ -300,43 +213,40 @@ class ResetPasswordAPIView(views.APIView):
return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST)
class ForgotPasswordAPIView(views.APIView):
"""
Forgot password
"""
serializer_class = ForgotPasswordSerializer
"""Forgot password"""
def post(self, request):
"""
Payload
{
"email": "abc@yopmail.com"
}
"""
serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)
email = serializer.validated_data['email']
# generate otp
verification_code = generate_otp()
# Send the verification code to the user's email
send_all_email.delay(
'email_reset_verification.email', email, verification_code
)
expiry = OTP_EXPIRY
user_data, created = UserEmailOtp.objects.get_or_create(
email=email
)
if created:
user_data.expired_at = expiry
user_data.save()
if user_data:
user_data.otp = verification_code
user_data.expired_at = expiry
user_data.save()
return custom_response(
SUCCESS_CODE['3015'],
response_status=status.HTTP_200_OK
)
serializer = ForgotPasswordSerializer(data=request.data)
if serializer.is_valid():
email = serializer.validated_data['email']
try:
User.objects.get(email=email)
except User.DoesNotExist:
return custom_error_response(ERROR_CODE['2004'], response_status=status.HTTP_404_NOT_FOUND)
verification_code = generate_otp()
# Send the verification code to the user's email
from_email = settings.EMAIL_FROM_ADDRESS
recipient_list = [email]
send_templated_mail(
template_name='email_reset_verification.email',
from_email=from_email,
recipient_list=recipient_list,
context={
'verification_code': verification_code
}
)
expiry = OTP_EXPIRY
user_data, created = UserEmailOtp.objects.get_or_create(email=email)
if created:
user_data.expired_at = expiry
user_data.save()
if user_data:
user_data.otp = verification_code
user_data.expired_at = expiry
user_data.save()
return custom_response(SUCCESS_CODE['3015'],
response_status=status.HTTP_200_OK)
return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST)
class SendPhoneOtp(viewsets.ModelViewSet):
"""Send otp on phone"""
@ -377,7 +287,7 @@ class UserLogin(viewsets.ViewSet):
def login(self, request):
username = request.data.get('username')
password = request.data.get('password')
user_type = request.META.get('HTTP_USER_TYPE')
user_type = request.data.get('user_type')
device_id = request.META.get('HTTP_DEVICE_ID')
user = authenticate(request, username=username, password=password)
@ -385,24 +295,22 @@ class UserLogin(viewsets.ViewSet):
if user is not None:
login(request, user)
if str(user_type) == USER_TYPE_FLAG["TWO"]:
guardian_data = Guardian.objects.filter(user__username=username).last()
guardian_data = Guardian.objects.filter(user__username=username, is_verified=True).last()
if guardian_data:
if guardian_data.is_verified:
serializer = GuardianSerializer(
guardian_data, context={'user_type': user_type}
).data
serializer = GuardianSerializer(
guardian_data, context={'user_type': user_type}
).data
else:
return custom_error_response(
ERROR_CODE["2070"],
response_status=status.HTTP_401_UNAUTHORIZED
)
elif str(user_type) == USER_TYPE_FLAG["FIRST"]:
junior_data = Junior.objects.filter(auth__username=username).last()
junior_data = Junior.objects.filter(auth__username=username, is_verified=True).last()
if junior_data:
if junior_data.is_verified:
serializer = JuniorSerializer(
junior_data, context={'user_type': user_type}
).data
serializer = JuniorSerializer(
junior_data, context={'user_type': user_type}
).data
else:
return custom_error_response(
ERROR_CODE["2071"],
@ -413,12 +321,8 @@ class UserLogin(viewsets.ViewSet):
ERROR_CODE["2069"],
response_status=status.HTTP_401_UNAUTHORIZED
)
# storing device id in using celery task so the time would be reduced
# user_device_details.delay(user.id, device_id)
device_details, created = UserDeviceDetails.objects.get_or_create(user=user)
if device_details:
device_details.device_id = device_id
device_details.save()
# storing device id in using thread so the time would be reduced
threading.Thread(target=user_device_details, args=(user, device_id))
return custom_response(SUCCESS_CODE['3003'], serializer, response_status=status.HTTP_200_OK)
else:
return custom_error_response(ERROR_CODE["2002"], response_status=status.HTTP_401_UNAUTHORIZED)
@ -495,20 +399,14 @@ class AdminLoginViewSet(viewsets.GenericViewSet):
class UserEmailVerification(viewsets.ModelViewSet):
"""User Email verification
Payload
{
"email":"ramu@yopmail.com",
"otp":"361123"
}"""
"""User Email verification"""
serializer_class = EmailVerificationSerializer
http_method_names = ('post',)
def create(self, request, *args, **kwargs):
def list(self, request, *args, **kwargs):
try:
user_obj = User.objects.filter(username=self.request.data.get('email')).last()
email_data = UserEmailOtp.objects.filter(email=self.request.data.get('email'),
otp=self.request.data.get('otp')).last()
user_obj = User.objects.filter(username=self.request.GET.get('email')).last()
email_data = UserEmailOtp.objects.filter(email=self.request.GET.get('email'),
otp=self.request.GET.get('otp')).last()
if email_data:
input_datetime_str = str(email_data.expired_at)
input_format = "%Y-%m-%d %H:%M:%S.%f%z"
@ -522,12 +420,12 @@ class UserEmailVerification(viewsets.ModelViewSet):
email_data.is_verified = True
email_data.save()
if email_data.user_type == '1':
junior_data = Junior.objects.filter(auth__email=self.request.data.get('email')).last()
junior_data = Junior.objects.filter(auth__email=self.request.GET.get('email')).last()
if junior_data:
junior_data.is_verified = True
junior_data.save()
else:
guardian_data = Guardian.objects.filter(user__email=self.request.data.get('email')).last()
guardian_data = Guardian.objects.filter(user__email=self.request.GET.get('email')).last()
if guardian_data:
guardian_data.is_verified = True
guardian_data.save()
@ -547,14 +445,11 @@ class ReSendEmailOtp(viewsets.ModelViewSet):
"""Send otp on phone"""
serializer_class = EmailVerificationSerializer
permission_classes = [IsAuthenticated]
http_method_names = ('post',)
def create(self, request, *args, **kwargs):
"""Param
{"email":"ashok@yopmail.com"}
"""
otp = generate_otp()
if User.objects.filter(email=request.data['email']):
expiry = timezone.now() + timezone.timedelta(days=1)
expiry = OTP_EXPIRY
email_data, created = UserEmailOtp.objects.get_or_create(email=request.data['email'])
if created:
email_data.expired_at = expiry
@ -563,7 +458,7 @@ class ReSendEmailOtp(viewsets.ModelViewSet):
email_data.otp = otp
email_data.expired_at = expiry
email_data.save()
send_otp_email.delay(request.data['email'], otp)
send_otp_email(request.data['email'], otp)
return custom_response(SUCCESS_CODE['3016'], response_status=status.HTTP_200_OK)
else:
return custom_error_response(ERROR_CODE["2023"], response_status=status.HTTP_400_BAD_REQUEST)
@ -572,28 +467,23 @@ class ProfileAPIViewSet(viewsets.ModelViewSet):
"""Profile viewset"""
serializer_class = JuniorProfileSerializer
permission_classes = [IsAuthenticated]
http_method_names = ('get',)
def list(self, request, *args, **kwargs):
"""profile view
Params
user_type"""
user_type = request.META.get('HTTP_USER_TYPE')
if str(user_type) == '1':
"""profile view"""
if str(self.request.GET.get('user_type')) == '1':
junior_data = Junior.objects.filter(auth=self.request.user).last()
if junior_data:
serializer = JuniorProfileSerializer(junior_data)
return custom_response(None, serializer.data, response_status=status.HTTP_200_OK)
elif str(user_type) == '2':
elif str(self.request.GET.get('user_type')) == '2':
guardian_data = Guardian.objects.filter(user=self.request.user).last()
if guardian_data:
serializer = GuardianProfileSerializer(guardian_data)
return custom_response(None, serializer.data, response_status=status.HTTP_200_OK)
return custom_error_response(None, response_status=status.HTTP_400_BAD_REQUEST)
class UploadImageAPIViewSet(viewsets.ModelViewSet):
"""upload task image"""
serializer_class = DefaultTaskImagesSerializer
http_method_names = ('post',)
def create(self, request, *args, **kwargs):
"""upload images"""
image_data = request.data['image_url']
@ -613,7 +503,6 @@ class DefaultImageAPIViewSet(viewsets.ModelViewSet):
"""Profile viewset"""
serializer_class = DefaultTaskImagesDetailsSerializer
permission_classes = [IsAuthenticated]
http_method_names = ('get',)
def list(self, request, *args, **kwargs):
"""profile view"""
queryset = DefaultTaskImages.objects.all()
@ -622,13 +511,7 @@ class DefaultImageAPIViewSet(viewsets.ModelViewSet):
class DeleteUserProfileAPIViewSet(viewsets.GenericViewSet):
""" Delete user API view set
{"user_type":1,
"signup_method":"1",
"password":"Demo@123"}
signup_method 1 for manual
2 for google login
3 for apple login"""
""" Delete user API view set """
@action(detail=False, methods=['POST'], url_path='user-account',serializer_class=UserDeleteSerializer,
permission_classes=[IsAuthenticated])
@ -650,9 +533,8 @@ class UserNotificationAPIViewSet(viewsets.ModelViewSet):
"""notification viewset"""
serializer_class = UserNotificationSerializer
permission_classes = [IsAuthenticated]
http_method_names = ('get',)
def list(self, request, *args, **kwargs):
"""notification view"""
"""profile view"""
queryset = UserNotification.objects.filter(user=request.user)
serializer = UserNotificationSerializer(queryset, many=True)
return custom_response(None, serializer.data, response_status=status.HTTP_200_OK)
@ -662,14 +544,9 @@ class UpdateUserNotificationAPIViewSet(viewsets.ModelViewSet):
"""Update notification viewset"""
serializer_class = UpdateUserNotificationSerializer
permission_classes = [IsAuthenticated]
http_method_names = ('post',)
def create(self, request, *args, **kwargs):
"""Payload
{"email_notification": false,
"sms_notification": false,
"push_notification": false}
"""
"""profile view"""
serializer = UpdateUserNotificationSerializer(data=request.data,
context=request.user)
if serializer.is_valid():
@ -679,12 +556,7 @@ class UpdateUserNotificationAPIViewSet(viewsets.ModelViewSet):
class SendSupportEmail(views.APIView):
"""support email api
payload
name
email
message
"""
"""support email api"""
permission_classes = (IsAuthenticated,)
def post(self, request):
@ -728,27 +600,3 @@ class AccessTokenAPIView(views.APIView):
data = {"auth_token": access_token}
return custom_response(None, data, response_status=status.HTTP_200_OK)
class ForceUpdateViewSet(GenericViewSet, mixins.CreateModelMixin):
"""FAQ view set"""
serializer_class = ForceUpdateSerializer
http_method_names = ['post']
def create(self, request, *args, **kwargs):
"""
faq create api method
:param request:
:param args: version, device type
:param kwargs:
:return: success message
"""
if ForceUpdate.objects.all().count() >= 2:
return custom_error_response(ERROR_CODE['2080'], response_status=status.HTTP_400_BAD_REQUEST)
obj_data = [ForceUpdate(**item) for item in request.data]
try:
ForceUpdate.objects.bulk_create(obj_data)
return custom_response(SUCCESS_CODE["3046"], 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

@ -27,7 +27,7 @@ NUMBER = {
'ninety_nine': 99, 'hundred': 100, 'thirty_six_hundred': 3600
}
none = "none"
# Super Admin string constant for 'role'
SUPER_ADMIN = "Super Admin"
@ -43,18 +43,14 @@ FILE_SIZE = 5 * 1024 * 1024
# String constant for configurable date for allocation lock period
ALLOCATION_LOCK_DATE = 1
# guardian code status tuple
guardian_code_tuple = ('1','3')
"""user type"""
USER_TYPE = (
('1', 'junior'),
('2', 'guardian'),
('3', 'superuser')
)
DEVICE_TYPE = (
('1', 'android'),
('2', 'ios')
)
USER_TYPE_FLAG = {
"FIRST" : "1",
"TWO" : "2",

View File

@ -96,22 +96,8 @@ ERROR_CODE = {
"2067": "Action not allowed. User type missing.",
"2068": "No guardian associated with this junior",
"2069": "Invalid user type",
"2070": "You do not find as a guardian",
"2071": "You do not find as a junior",
"2072": "You can not approve or reject this task because junior does not exist in the system",
"2073": "You can not approve or reject this junior because junior does not exist in the system",
"2074": "You can not complete this task because you does not exist in the system",
# deactivate account
"2075": "Your account is deactivated. Please contact with admin",
"2076": "This junior already associate with you",
"2077": "You can not add guardian",
"2078": "This junior is not associate with you",
# force update
"2079": "Please update your app version for enjoying uninterrupted services",
"2080": "Can not add App version",
"2081": "You can not add more than 3 guardian",
# guardian code not exist
"2082": "Guardian code does not exist"
"2070": "You did not find as a guardian",
"2071": "You did not find as a junior"
}
"""Success message code"""
@ -177,9 +163,6 @@ SUCCESS_CODE = {
"3043": "Read article card successfully",
# remove guardian code request
"3044": "Remove guardian code request successfully",
# create faq
"3045": "Create FAQ data",
"3046": "Add App version successfully"
}
"""status code error"""

Binary file not shown.

View File

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

View File

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

View File

@ -1,7 +1,6 @@
"""Serializer of Guardian"""
# third party imports
import logging
from django.contrib.auth import password_validation
from rest_framework import serializers
# Import Refresh token of jwt
from rest_framework_simplejwt.tokens import RefreshToken
@ -28,15 +27,13 @@ from base.constants import NUMBER, JUN, ZOD, GRD, Already_register_user
from junior.models import Junior, JuniorPoints, JuniorGuardianRelationship
from .utils import real_time, convert_timedelta_into_datetime, update_referral_points
# notification's constant
from notifications.constants import TASK_APPROVED, TASK_REJECTED
from notifications.constants import TASK_POINTS, TASK_REJECTED
# send notification function
from notifications.utils import send_notification, send_notification_to_junior
from django.core.exceptions import ValidationError
from django.utils.translation import gettext as _
from notifications.utils import send_notification
# In this serializer file
# define user serializer,
# define password validation
# create guardian serializer,
# task serializer,
# guardian serializer,
@ -45,51 +42,10 @@ from django.utils.translation import gettext as _
# guardian profile serializer,
# approve junior serializer,
# approve task serializer,
from rest_framework import serializers
class PasswordValidator:
"""Password validation"""
def __init__(self, min_length=8, max_length=None, require_uppercase=True, require_numbers=True):
self.min_length = min_length
self.max_length = max_length
self.require_uppercase = require_uppercase
self.require_numbers = require_numbers
def __call__(self, value):
self.enforce_password_policy(value)
def enforce_password_policy(self, password):
# add validation for password
special_characters = "!@#$%^&*()_-+=<>?/[]{}|"
if len(password) < self.min_length:
raise serializers.ValidationError(
_("Password must be at least %(min_length)d characters long.") % {'min_length': self.min_length}
)
if self.max_length is not None and len(password) > self.max_length:
# must be 8 character
raise serializers.ValidationError(
_("Password must be at most %(max_length)d characters long.") % {'max_length': self.max_length}
)
if self.require_uppercase and not any(char.isupper() for char in password):
# must contain upper case letter
raise serializers.ValidationError(_("Password must contain at least one uppercase letter."))
if self.require_numbers and not any(char.isdigit() for char in password):
# must contain digit
raise serializers.ValidationError(_("Password must contain at least one digit."))
if self.require_numbers and not any(char in special_characters for char in password):
# must contain special character
raise serializers.ValidationError(_("Password must contain at least one special character."))
class UserSerializer(serializers.ModelSerializer):
"""User serializer"""
auth_token = serializers.SerializerMethodField('get_auth_token')
password = serializers.CharField(write_only=True, validators=[PasswordValidator()])
class Meta(object):
"""Meta info"""
@ -258,7 +214,7 @@ class GuardianDetailSerializer(serializers.ModelSerializer):
"""Meta info"""
model = Guardian
fields = ['id', 'email', 'first_name', 'last_name', 'country_code', 'phone', 'gender', 'dob',
'guardian_code','is_active', 'is_complete_profile', 'created_at', 'image', 'is_deleted',
'guardian_code','is_active', 'is_complete_profile', 'created_at', 'image',
'updated_at']
class TaskDetailsSerializer(serializers.ModelSerializer):
"""Task detail serializer"""
@ -384,7 +340,7 @@ class GuardianProfileSerializer(serializers.ModelSerializer):
fields = ['id', 'email', 'first_name', 'last_name', 'country_name','country_code', 'phone', 'gender', 'dob',
'guardian_code', 'notification_count', 'total_count', 'complete_field_count', 'referral_code',
'is_active', 'is_complete_profile', 'created_at', 'image', 'signup_method',
'updated_at', 'passcode','is_deleted']
'updated_at', 'passcode']
class ApproveJuniorSerializer(serializers.ModelSerializer):
@ -427,8 +383,7 @@ class ApproveTaskSerializer(serializers.ModelSerializer):
# update complete time of task
# instance.completed_on = real_time()
instance.completed_on = timezone.now().astimezone(pytz.utc)
send_notification_to_junior.delay(TASK_APPROVED, instance.guardian.user.id, junior_details.auth.id,
{'task_id': instance.id})
send_notification.delay(TASK_POINTS, None, junior_details.auth.id, {})
else:
# reject the task
instance.task_status = str(NUMBER['three'])
@ -436,8 +391,7 @@ class ApproveTaskSerializer(serializers.ModelSerializer):
# update reject time of task
# instance.rejected_on = real_time()
instance.rejected_on = timezone.now().astimezone(pytz.utc)
send_notification_to_junior.delay(TASK_REJECTED, instance.guardian.user.id, junior_details.auth.id,
{'task_id': instance.id})
send_notification.delay(TASK_REJECTED, None, junior_details.auth.id, {})
instance.save()
junior_data.save()
return junior_details

View File

@ -1,12 +1,7 @@
"""task files"""
# Django import
"""Django import"""
import secrets
def generate_otp():
"""
generate random otp
"""
"""generate random otp"""
digits = "0123456789"
return "".join(secrets.choice(digits) for _ in range(6))

View File

@ -1,7 +1,7 @@
""" Urls files"""
"""Django import"""
from django.urls import path, include
from .views import (SignupViewset, UpdateGuardianProfile, CreateTaskAPIView, TaskListAPIView,
from .views import (SignupViewset, UpdateGuardianProfile, AllTaskListAPIView, CreateTaskAPIView, TaskListAPIView,
SearchTaskListAPIView, TopJuniorListAPIView, ApproveJuniorAPIView, ApproveTaskAPIView,
GuardianListAPIView)
"""Third party import"""
@ -25,6 +25,8 @@ router.register('sign-up', SignupViewset, basename='sign-up')
router.register('create-guardian-profile', UpdateGuardianProfile, basename='update-guardian-profile')
# Create Task API"""
router.register('create-task', CreateTaskAPIView, basename='create-task')
# All Task list API"""
router.register('all-task-list', AllTaskListAPIView, basename='all-task-list')
# Task list bases on the status API"""
router.register('task-list', TaskListAPIView, basename='task-list')
# Leaderboard API"""

View File

@ -21,9 +21,7 @@ from zod_bank.celery import app
# notification's constant
from notifications.constants import REFERRAL_POINTS
# send notification function
from notifications.utils import send_notification, send_notification_to_junior
from notifications.utils import send_notification
# Define upload image on
# ali baba cloud
# firstly save image
@ -43,41 +41,18 @@ def upload_image_to_alibaba(image, filename):
# Save the image object to a temporary file
with tempfile.NamedTemporaryFile(delete=False) as temp_file:
"""write image in temporary file"""
temp_file.write(image.read())
return upload_file_to_alibaba(temp_file, filename)
def upload_base64_image_to_alibaba(image, filename):
"""
upload image on oss alibaba bucket
"""
# Save the image object to a temporary file
with tempfile.NamedTemporaryFile(delete=False) as temp_file:
# write image in temporary file
temp_file.write(image)
return upload_file_to_alibaba(temp_file, filename)
def upload_excel_file_to_alibaba(response, filename):
"""
upload excel file on oss alibaba bucket
"""
# Save the image object to a temporary file
with tempfile.NamedTemporaryFile(delete=False) as temp_file:
# write image in temporary file
temp_file.write(response.content)
return upload_file_to_alibaba(temp_file, filename)
def upload_file_to_alibaba(temp_file, filename):
"""auth of bucket"""
auth = oss2.Auth(settings.ALIYUN_OSS_ACCESS_KEY_ID, settings.ALIYUN_OSS_ACCESS_KEY_SECRET)
"""fetch bucket details"""
bucket = oss2.Bucket(auth, settings.ALIYUN_OSS_ENDPOINT, settings.ALIYUN_OSS_BUCKET_NAME)
# Upload the temporary file to Alibaba OSS
bucket.put_object_from_file(filename, temp_file.name)
"""create perfect url for image"""
new_filename = filename.replace(' ', '%20')
if type(image) == bytes:
temp_file.write(image)
else:
temp_file.write(image.read())
"""auth of bucket"""
auth = oss2.Auth(settings.ALIYUN_OSS_ACCESS_KEY_ID, settings.ALIYUN_OSS_ACCESS_KEY_SECRET)
"""fetch bucket details"""
bucket = oss2.Bucket(auth, settings.ALIYUN_OSS_ENDPOINT, settings.ALIYUN_OSS_BUCKET_NAME)
# Upload the temporary file to Alibaba OSS
bucket.put_object_from_file(filename, temp_file.name)
"""create perfect url for image"""
new_filename = filename.replace(' ', '%20')
return f"https://{settings.ALIYUN_OSS_BUCKET_NAME}.{settings.ALIYUN_OSS_ENDPOINT}/{new_filename}"
@ -117,7 +92,7 @@ def update_referral_points(referral_code, referral_code_used):
junior_query.total_points = junior_query.total_points + NUMBER['five']
junior_query.referral_points = junior_query.referral_points + NUMBER['five']
junior_query.save()
send_notification_to_junior.delay(REFERRAL_POINTS, None, junior_queryset.auth.id, {})
send_notification.delay(REFERRAL_POINTS, None, junior_queryset.auth.id, {})
@ -127,7 +102,7 @@ def update_expired_task_status(data=None):
Update task of the status if due date is in past
"""
try:
task_status = [str(NUMBER['one']), str(NUMBER['two'])]
task_status = [str(NUMBER['one']), str(NUMBER['two']), str(NUMBER['four'])]
JuniorTask.objects.filter(due_date__lt=datetime.today().date(),
task_status__in=task_status).update(task_status=str(NUMBER['six']))
except ObjectDoesNotExist as e:

View File

@ -10,7 +10,7 @@ from rest_framework.permissions import IsAuthenticated
from rest_framework import viewsets, status
from rest_framework.pagination import PageNumberPagination
from django.contrib.auth.models import User
from base.constants import guardian_code_tuple
from rest_framework.filters import SearchFilter
from django.utils import timezone
@ -32,14 +32,14 @@ from .serializers import (UserSerializer, CreateGuardianSerializer, TaskSerializ
GuardianDetailListSerializer)
from .models import Guardian, JuniorTask
from junior.models import Junior, JuniorPoints, JuniorGuardianRelationship
from account.models import UserEmailOtp, UserNotification, UserDeviceDetails
from account.models import UserEmailOtp, UserNotification
from .tasks import generate_otp
from account.utils import custom_response, custom_error_response, OTP_EXPIRY, send_otp_email
from base.messages import ERROR_CODE, SUCCESS_CODE
from base.constants import NUMBER, GUARDIAN_CODE_STATUS
from .utils import upload_image_to_alibaba
from notifications.constants import REGISTRATION, TASK_ASSIGNED, ASSOCIATE_APPROVED, ASSOCIATE_REJECTED
from notifications.utils import send_notification_to_junior
from notifications.constants import REGISTRATION, TASK_CREATED, LEADERBOARD_RANKING
from notifications.utils import send_notification
""" Define APIs """
# Define Signup API,
@ -57,10 +57,8 @@ class SignupViewset(viewsets.ModelViewSet):
"""Signup view set"""
queryset = User.objects.all()
serializer_class = UserSerializer
http_method_names = ('post',)
def create(self, request, *args, **kwargs):
"""Create user profile"""
device_id = request.META.get('HTTP_DEVICE_ID')
if request.data['user_type'] in [str(NUMBER['one']), str(NUMBER['two'])]:
serializer = UserSerializer(context=request.data['user_type'], data=request.data)
if serializer.is_valid():
@ -68,25 +66,24 @@ class SignupViewset(viewsets.ModelViewSet):
"""Generate otp"""
otp = generate_otp()
# expire otp after 1 day
expiry = timezone.now() + timezone.timedelta(days=1)
expiry = OTP_EXPIRY
# create user email otp object
UserEmailOtp.objects.create(email=request.data['email'], otp=otp,
user_type=str(request.data['user_type']), expired_at=expiry)
"""Send email to the register user"""
send_otp_email.delay(request.data['email'], otp)
UserDeviceDetails.objects.create(user=user, device_id=device_id)
send_otp_email(request.data['email'], otp)
# send push notification for registration
send_notification.delay(REGISTRATION, None, user.id, {})
return custom_response(SUCCESS_CODE['3001'],
response_status=status.HTTP_200_OK)
return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST)
else:
return custom_error_response(ERROR_CODE['2028'], response_status=status.HTTP_400_BAD_REQUEST)
class UpdateGuardianProfile(viewsets.ModelViewSet):
class UpdateGuardianProfile(viewsets.ViewSet):
"""Update guardian profile"""
serializer_class = CreateGuardianSerializer
permission_classes = [IsAuthenticated]
http_method_names = ('post',)
def create(self, request, *args, **kwargs):
"""Create guardian profile"""
@ -129,11 +126,7 @@ class AllTaskListAPIView(viewsets.ModelViewSet):
class TaskListAPIView(viewsets.ModelViewSet):
"""Task list
Params
status
search
page"""
"""Update guardian profile"""
serializer_class = TaskDetailsSerializer
permission_classes = [IsAuthenticated]
filter_backends = (SearchFilter,)
@ -170,17 +163,9 @@ class CreateTaskAPIView(viewsets.ModelViewSet):
http_method_names = ('post', )
def create(self, request, *args, **kwargs):
"""
image should be in form data
"""
try:
image = request.data['default_image']
junior = request.data['junior']
junior_id = Junior.objects.filter(id=junior).last()
guardian_data = Guardian.objects.filter(user=request.user).last()
if (guardian_data.guardian_code not in junior_id.guardian_code or
junior_id.guardian_code_status in guardian_code_tuple):
return custom_error_response(ERROR_CODE['2078'], response_status=status.HTTP_400_BAD_REQUEST)
allowed_extensions = ['.jpg', '.jpeg', '.png']
if not any(extension in str(image) for extension in allowed_extensions):
return custom_error_response(ERROR_CODE['2048'], response_status=status.HTTP_400_BAD_REQUEST)
@ -201,21 +186,19 @@ class CreateTaskAPIView(viewsets.ModelViewSet):
serializer = TaskSerializer(context={"user":request.user, "image":image_data}, data=data)
if serializer.is_valid():
# save serializer
task = serializer.save()
send_notification_to_junior.delay(TASK_ASSIGNED, request.auth.payload['user_id'],
junior_id.auth.id, {'task_id': task.id})
serializer.save()
junior_id = Junior.objects.filter(id=junior).last()
send_notification.delay(TASK_CREATED, None, junior_id.auth.id, {})
return custom_response(SUCCESS_CODE['3018'], serializer.data, response_status=status.HTTP_200_OK)
return custom_error_response(serializer.errors, 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 SearchTaskListAPIView(viewsets.ModelViewSet):
"""Filter task"""
"""Update guardian profile"""
serializer_class = TaskDetailsSerializer
permission_classes = [IsAuthenticated]
pagination_class = PageNumberPagination
http_method_names = ('get',)
def get_queryset(self):
"""Get the queryset for the view"""
@ -226,7 +209,7 @@ class SearchTaskListAPIView(viewsets.ModelViewSet):
return junior_queryset
def list(self, request, *args, **kwargs):
"""Filter task"""
"""Create guardian profile"""
try:
queryset = self.get_queryset()
paginator = self.pagination_class()
@ -240,12 +223,10 @@ class SearchTaskListAPIView(viewsets.ModelViewSet):
class TopJuniorListAPIView(viewsets.ModelViewSet):
"""Top juniors list
No Params"""
"""Top juniors list"""
queryset = JuniorPoints.objects.all()
serializer_class = TopJuniorSerializer
permission_classes = [IsAuthenticated]
http_method_names = ('get',)
def get_serializer_context(self):
# context list
@ -260,6 +241,7 @@ class TopJuniorListAPIView(viewsets.ModelViewSet):
# Update the position field for each JuniorPoints object
for index, junior in enumerate(junior_total_points):
junior.position = index + 1
send_notification.delay(LEADERBOARD_RANKING, None, junior.junior.auth.id, {})
junior.save()
serializer = self.get_serializer(junior_total_points[:NUMBER['fifteen']], many=True)
return custom_response(None, serializer.data, response_status=status.HTTP_200_OK)
@ -267,86 +249,79 @@ class TopJuniorListAPIView(viewsets.ModelViewSet):
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
class ApproveJuniorAPIView(viewsets.ModelViewSet):
class ApproveJuniorAPIView(viewsets.ViewSet):
"""approve junior by guardian"""
serializer_class = ApproveJuniorSerializer
permission_classes = [IsAuthenticated]
http_method_names = ('post',)
def get_queryset(self):
"""Get the queryset for the view"""
guardian = Guardian.objects.filter(user__email=self.request.user).last()
# fetch junior query
junior_queryset = Junior.objects.filter(id=self.request.data.get('junior_id')).last()
return guardian, junior_queryset
def create(self, request, *args, **kwargs):
""" Use below param
{"junior_id":"75",
"action":"1"}
"""
""" junior list"""
try:
guardian = Guardian.objects.filter(user__email=self.request.user).last()
# fetch junior query
junior_queryset = Junior.objects.filter(id=self.request.data.get('junior_id')).last()
if junior_queryset and (junior_queryset.is_deleted or not junior_queryset.is_active):
return custom_error_response(ERROR_CODE['2073'], response_status=status.HTTP_400_BAD_REQUEST)
queryset = self.get_queryset()
# action 1 is use for approve and 2 for reject
if request.data['action'] == '1':
# use ApproveJuniorSerializer serializer
serializer = ApproveJuniorSerializer(context={"guardian_code": guardian.guardian_code,
"junior": junior_queryset,
"action": request.data['action']},
serializer = ApproveJuniorSerializer(context={"guardian_code": queryset[0].guardian_code,
"junior": queryset[1], "action": request.data['action']},
data=request.data)
if serializer.is_valid():
# save serializer
serializer.save()
send_notification_to_junior.delay(ASSOCIATE_APPROVED, guardian.user.id, junior_queryset.auth.id)
return custom_response(SUCCESS_CODE['3023'], serializer.data, response_status=status.HTTP_200_OK)
else:
junior_queryset.guardian_code = None
junior_queryset.guardian_code_status = str(NUMBER['one'])
junior_queryset.save()
send_notification_to_junior.delay(ASSOCIATE_REJECTED, guardian.user.id, junior_queryset.auth.id)
queryset[1].guardian_code = None
queryset[1].guardian_code_status = str(NUMBER['one'])
queryset[1].save()
return custom_response(SUCCESS_CODE['3024'], response_status=status.HTTP_200_OK)
except Exception as e:
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
class ApproveTaskAPIView(viewsets.ModelViewSet):
class ApproveTaskAPIView(viewsets.ViewSet):
"""approve junior by guardian"""
serializer_class = ApproveTaskSerializer
permission_classes = [IsAuthenticated]
http_method_names = ('post',)
def get_queryset(self):
"""Get the queryset for the view"""
guardian = Guardian.objects.filter(user__email=self.request.user).last()
# task query
task_queryset = JuniorTask.objects.filter(id=self.request.data.get('task_id'),
guardian=guardian,
junior=self.request.data.get('junior_id')).last()
return guardian, task_queryset
def create(self, request, *args, **kwargs):
""" Params
{"junior_id":"82",
"task_id":"43",
"action":"1"}
action 1 for approve
2 for reject
"""
""" junior list"""
# action 1 is use for approve and 2 for reject
try:
guardian = Guardian.objects.filter(user__email=self.request.user).last()
# task query
task_queryset = JuniorTask.objects.filter(id=self.request.data.get('task_id'),
guardian=guardian,
junior=self.request.data.get('junior_id')).last()
if task_queryset and (task_queryset.junior.is_deleted or not task_queryset.junior.is_active):
return custom_error_response(ERROR_CODE['2072'], response_status=status.HTTP_400_BAD_REQUEST)
queryset = self.get_queryset()
# use ApproveJuniorSerializer serializer
serializer = ApproveTaskSerializer(context={"guardian_code": guardian.guardian_code,
"task_instance": task_queryset,
serializer = ApproveTaskSerializer(context={"guardian_code": queryset[0].guardian_code,
"task_instance": queryset[1],
"action": str(request.data['action']),
"junior": self.request.data['junior_id']},
data=request.data)
unexpected_task_status = [str(NUMBER['five']), str(NUMBER['six'])]
if (str(request.data['action']) == str(NUMBER['one']) and serializer.is_valid()
and task_queryset and task_queryset.task_status not in unexpected_task_status):
and queryset[1] and queryset[1].task_status not in unexpected_task_status):
# save serializer
serializer.save()
return custom_response(SUCCESS_CODE['3025'], response_status=status.HTTP_200_OK)
elif (str(request.data['action']) == str(NUMBER['two']) and serializer.is_valid()
and task_queryset and task_queryset.task_status not in unexpected_task_status):
and queryset[1] and queryset[1].task_status not in unexpected_task_status):
# save serializer
serializer.save()
return custom_response(SUCCESS_CODE['3026'], response_status=status.HTTP_200_OK)
else:
return custom_error_response(ERROR_CODE['2038'], response_status=status.HTTP_400_BAD_REQUEST)
return custom_response(ERROR_CODE['2038'], response_status=status.HTTP_400_BAD_REQUEST)
except Exception as e:
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
@ -358,8 +333,7 @@ class GuardianListAPIView(viewsets.ModelViewSet):
http_method_names = ('get',)
def list(self, request, *args, **kwargs):
""" Guardian list of assosicated junior
No Params"""
""" junior list"""
try:
guardian_data = JuniorGuardianRelationship.objects.filter(junior__auth__email=self.request.user)
# fetch junior object

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -12,7 +12,7 @@ from rest_framework_simplejwt.tokens import RefreshToken
# local imports
from account.utils import send_otp_email, generate_code
from junior.models import Junior, JuniorPoints, JuniorGuardianRelationship, JuniorArticlePoints, FAQ
from junior.models import Junior, JuniorPoints, JuniorGuardianRelationship, JuniorArticlePoints
from guardian.tasks import generate_otp
from base.messages import ERROR_CODE, SUCCESS_CODE
from base.constants import (PENDING, IN_PROGRESS, REJECTED, REQUESTED, COMPLETED, NUMBER, JUN, ZOD, EXPIRED,
@ -21,10 +21,10 @@ from guardian.models import Guardian, JuniorTask
from account.models import UserEmailOtp, UserNotification
from junior.utils import junior_notification_email, junior_approval_mail
from guardian.utils import real_time, update_referral_points, convert_timedelta_into_datetime
from notifications.utils import send_notification, send_notification_to_junior, send_notification_to_guardian
from notifications.constants import (ASSOCIATE_REQUEST, JUNIOR_ADDED, TASK_ACTION,
)
from web_admin.models import ArticleCard
from notifications.utils import send_notification
from notifications.constants import (INVITED_GUARDIAN, APPROVED_JUNIOR, SKIPPED_PROFILE_SETUP, TASK_ACTION,
TASK_SUBMITTED)
class ListCharField(serializers.ListField):
"""Serializer for Array field"""
@ -88,23 +88,17 @@ class CreateJuniorSerializer(serializers.ModelSerializer):
if junior:
"""update details according to the data get from request"""
junior.gender = validated_data.get('gender',junior.gender)
# Update guardian code"""
# condition for guardian code
"""Update guardian code"""
junior.guardian_code = validated_data.get('guardian_code', junior.guardian_code)
"""condition for guardian code"""
if guardian_code:
if not junior.guardian_code:
junior.guardian_code = []
junior.guardian_code.extend(guardian_code)
elif len(junior.guardian_code) < 3 and len(guardian_code) < 3:
junior.guardian_code.extend(guardian_code)
else:
raise serializers.ValidationError({"error":ERROR_CODE['2081'],"code":"400", "status":"failed"})
junior.guardian_code = guardian_code
guardian_data = Guardian.objects.filter(guardian_code=guardian_code[0]).last()
if guardian_data:
JuniorGuardianRelationship.objects.get_or_create(guardian=guardian_data, junior=junior)
junior.guardian_code_status = str(NUMBER['three'])
junior_approval_mail.delay(user.email, user.first_name)
send_notification_to_guardian.delay(ASSOCIATE_REQUEST, junior.auth.id, guardian_data.user.id, {})
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.passcode = validated_data.get('passcode', junior.passcode)
junior.country_name = validated_data.get('country_name', junior.country_name)
@ -153,7 +147,7 @@ class JuniorDetailSerializer(serializers.ModelSerializer):
model = Junior
fields = ['id', 'email', 'first_name', 'last_name', 'country_code', 'phone', 'gender', 'dob',
'guardian_code', 'image', 'is_invited', 'referral_code','is_active', 'is_complete_profile',
'created_at', 'image', 'is_deleted', 'updated_at']
'created_at', 'image', 'updated_at']
class JuniorDetailListSerializer(serializers.ModelSerializer):
"""junior serializer"""
@ -220,8 +214,7 @@ class JuniorDetailListSerializer(serializers.ModelSerializer):
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',
'updated_at', 'assigned_task','points', 'pending_task', 'in_progress_task', 'completed_task',
'requested_task', 'rejected_task', 'position', 'is_invited', 'guardian_code_status',
'is_deleted']
'requested_task', 'rejected_task', 'position', 'is_invited', 'guardian_code_status']
class JuniorProfileSerializer(serializers.ModelSerializer):
"""junior serializer"""
@ -264,7 +257,7 @@ class JuniorProfileSerializer(serializers.ModelSerializer):
fields = ['id', 'email', 'first_name', 'last_name', 'country_name', 'country_code', 'phone', 'gender', 'dob',
'guardian_code', 'referral_code','is_active', 'is_complete_profile', 'created_at', 'image',
'updated_at', 'notification_count', 'total_count', 'complete_field_count', 'signup_method',
'is_invited', 'passcode', 'guardian_code_approved', 'is_deleted']
'is_invited', 'passcode', 'guardian_code_approved']
class AddJuniorSerializer(serializers.ModelSerializer):
"""Add junior serializer"""
@ -298,7 +291,7 @@ class AddJuniorSerializer(serializers.ModelSerializer):
referral_code_used=guardian_data.referral_code,
is_password_set=False, is_verified=True,
guardian_code_status=GUARDIAN_CODE_STATUS[1][0])
JuniorGuardianRelationship.objects.get_or_create(guardian=guardian_data, junior=junior_data,
JuniorGuardianRelationship.objects.create(guardian=guardian_data, junior=junior_data,
relationship=relationship)
total_junior = Junior.objects.all().count()
JuniorPoints.objects.create(junior=junior_data, position=total_junior)
@ -310,9 +303,9 @@ class AddJuniorSerializer(serializers.ModelSerializer):
# add push notification
UserNotification.objects.get_or_create(user=user_data)
"""Notification email"""
junior_notification_email.delay(email, full_name, email, password)
junior_notification_email(email, full_name, email, password)
# push notification
send_notification_to_junior.delay(JUNIOR_ADDED, None, junior_data.auth.id, {})
send_notification.delay(SKIPPED_PROFILE_SETUP, None, junior_data.auth.id, {})
return junior_data
@ -325,11 +318,9 @@ class RemoveJuniorSerializer(serializers.ModelSerializer):
fields = ('id', 'is_invited')
def update(self, instance, validated_data):
if instance:
guardian_code = self.context['guardian_code']
instance.is_invited = False
instance.guardian_code.remove(guardian_code)
if not instance.guardian_code:
instance.guardian_code_status = str(NUMBER['one'])
instance.guardian_code = '{}'
instance.guardian_code_status = str(NUMBER['one'])
instance.save()
return instance
@ -346,8 +337,8 @@ class CompleteTaskSerializer(serializers.ModelSerializer):
instance.task_status = str(NUMBER['four'])
instance.is_approved = False
instance.save()
send_notification_to_guardian.delay(TASK_ACTION, instance.junior.auth.id,
instance.guardian.user.id, {'task_id': instance.id})
send_notification.delay(TASK_SUBMITTED, None, instance.junior.auth.id, {})
send_notification.delay(TASK_ACTION, None, instance.guardian.user.id, {})
return instance
class JuniorPointsSerializer(serializers.ModelSerializer):
@ -402,7 +393,7 @@ class JuniorPointsSerializer(serializers.ModelSerializer):
"""Meta info"""
model = Junior
fields = ['junior_id', 'total_points', 'position', 'pending_task', 'in_progress_task', 'completed_task',
'requested_task', 'rejected_task', 'expired_task', 'is_deleted']
'requested_task', 'rejected_task', 'expired_task']
class AddGuardianSerializer(serializers.ModelSerializer):
"""Add guardian serializer"""
@ -451,13 +442,14 @@ class AddGuardianSerializer(serializers.ModelSerializer):
user_type=str(NUMBER['two']), expired_at=expiry_time,
is_verified=True)
UserNotification.objects.get_or_create(user=user)
JuniorGuardianRelationship.objects.get_or_create(guardian=guardian_data, junior=junior_data,
JuniorGuardianRelationship.objects.create(guardian=guardian_data, junior=junior_data,
relationship=relationship)
"""Notification email"""
junior_notification_email(email, full_name, email, password)
junior_approval_mail.delay(email, full_name)
send_notification_to_guardian.delay(ASSOCIATE_REQUEST, junior_data.auth.id, guardian_data.user.id, {})
junior_approval_mail(email, full_name)
send_notification.delay(INVITED_GUARDIAN, None, junior_data.auth.id, {})
send_notification.delay(APPROVED_JUNIOR, None, guardian_data.user.id, {})
return guardian_data
class StartTaskSerializer(serializers.ModelSerializer):
@ -501,6 +493,8 @@ class ReAssignTaskSerializer(serializers.ModelSerializer):
instance.save()
return instance
class RemoveGuardianCodeSerializer(serializers.ModelSerializer):
"""User task Serializer"""
class Meta(object):
@ -508,33 +502,7 @@ class RemoveGuardianCodeSerializer(serializers.ModelSerializer):
model = Junior
fields = ('id', )
def update(self, instance, validated_data):
guardian_code = self.context['guardian_code']
if guardian_code in instance.guardian_code:
instance.guardian_code.remove(guardian_code)
else:
raise serializers.ValidationError({"error":ERROR_CODE['2082'],"code":"400", "status":"failed"})
if not instance.guardian_code:
instance.guardian_code_status = str(NUMBER['one'])
elif instance.guardian_code and (len(instance.guardian_code) == 1 and '-' in instance.guardian_code):
instance.guardian_code_status = str(NUMBER['one'])
else:
instance.guardian_code_status = str(NUMBER['two'])
instance.guardian_code = None
instance.guardian_code_status = str(NUMBER['one'])
instance.save()
return instance
class FAQSerializer(serializers.ModelSerializer):
"""FAQ Serializer"""
class Meta(object):
"""meta info"""
model = FAQ
fields = ('id', 'question', 'description')
class CreateArticleCardSerializer(serializers.ModelSerializer):
"""Article card Serializer"""
class Meta(object):
"""meta info"""
model = ArticleCard
fields = ('id', 'article')

View File

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

View File

@ -14,8 +14,6 @@ from django.db.models import F
# being part of the zod bank and access the platform
# define junior notification email
# junior approval email
from celery import shared_task
@shared_task()
def junior_notification_email(recipient_email, full_name, email, password):
"""Notification email"""
from_email = settings.EMAIL_FROM_ADDRESS
@ -34,7 +32,7 @@ def junior_notification_email(recipient_email, full_name, email, password):
}
)
return full_name
@shared_task()
def junior_approval_mail(guardian, full_name):
"""junior approval mail"""
from_email = settings.EMAIL_FROM_ADDRESS

View File

@ -10,12 +10,8 @@ from django.db.models import F
import datetime
import requests
from rest_framework.viewsets import GenericViewSet, mixins
"""Django app import"""
from drf_yasg.utils import swagger_auto_schema
from drf_yasg import openapi
from drf_yasg.views import get_schema_view
# Import guardian's model,
# Import junior's model,
# Import account's model,
@ -34,19 +30,19 @@ from drf_yasg.views import get_schema_view
# Import constants
from django.db.models import Sum
from junior.models import (Junior, JuniorPoints, JuniorGuardianRelationship, JuniorArticlePoints, JuniorArticle,
JuniorArticleCard, FAQ)
JuniorArticleCard)
from .serializers import (CreateJuniorSerializer, JuniorDetailListSerializer, AddJuniorSerializer,
RemoveJuniorSerializer, CompleteTaskSerializer, JuniorPointsSerializer,
AddGuardianSerializer, StartTaskSerializer, ReAssignTaskSerializer,
RemoveGuardianCodeSerializer, FAQSerializer, CreateArticleCardSerializer)
RemoveGuardianCodeSerializer)
from guardian.models import Guardian, JuniorTask
from guardian.serializers import TaskDetailsSerializer, TaskDetailsjuniorSerializer
from base.messages import ERROR_CODE, SUCCESS_CODE
from base.constants import NUMBER, ARTICLE_STATUS, none
from base.constants import NUMBER, ARTICLE_STATUS
from account.utils import custom_response, custom_error_response
from guardian.utils import upload_image_to_alibaba
from .utils import update_positions_based_on_points
from notifications.utils import send_notification, send_notification_to_junior
from notifications.utils import send_notification
from notifications.constants import REMOVE_JUNIOR
from web_admin.models import Article, ArticleSurvey, SurveyOption, ArticleCard
from web_admin.serializers.article_serializer import (ArticleSerializer, ArticleListSerializer,
@ -67,14 +63,13 @@ from web_admin.serializers.article_serializer import (ArticleSerializer, Article
# Start task
# by junior API
# Create your views here.
class UpdateJuniorProfile(viewsets.ModelViewSet):
class UpdateJuniorProfile(viewsets.ViewSet):
"""Update junior profile"""
serializer_class = CreateJuniorSerializer
permission_classes = [IsAuthenticated]
http_method_names = ('post',)
def create(self, request, *args, **kwargs):
"""Create Junior Profile"""
"""Use CreateJuniorSerializer"""
try:
request_data = request.data
image = request.data.get('image')
@ -99,19 +94,14 @@ class UpdateJuniorProfile(viewsets.ModelViewSet):
return custom_response(None, serializer.data, response_status=status.HTTP_200_OK)
return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST)
except Exception as e:
error_detail = e.detail.get('error', None)
return custom_error_response(error_detail, response_status=status.HTTP_400_BAD_REQUEST)
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
class ValidateGuardianCode(viewsets.ModelViewSet):
class ValidateGuardianCode(viewsets.ViewSet):
"""Check guardian code exist or not"""
permission_classes = [IsAuthenticated]
http_method_names = ('get',)
def list(self, request, *args, **kwargs):
"""check guardian code
Params
"guardian_code"
"""
"""check guardian code"""
try:
guardian_code = self.request.GET.get('guardian_code').split(',')
for code in guardian_code:
@ -163,14 +153,7 @@ class AddJuniorAPIView(viewsets.ModelViewSet):
http_method_names = ('post',)
def create(self, request, *args, **kwargs):
""" add junior
{ "gender":"1",
"first_name":"abc",
"last_name":"xyz",
"dob":"2023-12-12",
"relationship":"2",
"email":"abc@yopmail.com"
}"""
""" junior list"""
try:
info_data = {'user': request.user, 'relationship': str(request.data['relationship']),
'email': request.data['email'], 'first_name': request.data['first_name'],
@ -186,13 +169,7 @@ class AddJuniorAPIView(viewsets.ModelViewSet):
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():
data = self.associate_guardian(user)
if data == none:
return custom_error_response(ERROR_CODE['2077'], response_status=status.HTTP_400_BAD_REQUEST)
elif not data:
return custom_error_response(ERROR_CODE['2076'], response_status=status.HTTP_400_BAD_REQUEST)
if data == "Max":
return custom_error_response(ERROR_CODE['2081'], response_status=status.HTTP_400_BAD_REQUEST)
self.associate_guardian(user)
return custom_response(SUCCESS_CODE['3021'], response_status=status.HTTP_200_OK)
# use AddJuniorSerializer serializer
serializer = AddJuniorSerializer(data=request.data, context=info_data)
@ -205,20 +182,9 @@ class AddJuniorAPIView(viewsets.ModelViewSet):
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
def associate_guardian(self, user):
junior = Junior.objects.filter(auth__email=self.request.data['email']).first()
junior = Junior.objects.filter(auth=user).first()
guardian = Guardian.objects.filter(user=self.request.user).first()
if junior.guardian_code and ('-' in junior.guardian_code):
junior.guardian_code.remove('-')
if not junior:
return none
if junior.guardian_code and (guardian.guardian_code in junior.guardian_code):
return False
if not junior.guardian_code:
junior.guardian_code = [guardian.guardian_code]
if type(junior.guardian_code) is list and len(junior.guardian_code) < 3:
junior.guardian_code.append(guardian.guardian_code)
else:
return "Max"
junior.guardian_code = [guardian.guardian_code]
junior.guardian_code_status = str(NUMBER['two'])
junior.save()
JuniorGuardianRelationship.objects.get_or_create(guardian=guardian, junior=junior,
@ -227,7 +193,7 @@ class AddJuniorAPIView(viewsets.ModelViewSet):
class InvitedJuniorAPIView(viewsets.ModelViewSet):
"""Invited Junior list of assosicated guardian"""
"""Junior list of assosicated guardian"""
serializer_class = JuniorDetailListSerializer
permission_classes = [IsAuthenticated]
@ -241,8 +207,7 @@ class InvitedJuniorAPIView(viewsets.ModelViewSet):
is_invited=True)
return junior_queryset
def list(self, request, *args, **kwargs):
""" Invited Junior list of assosicated guardian
No Params"""
""" junior list"""
try:
queryset = self.get_queryset()
paginator = self.pagination_class()
@ -256,25 +221,12 @@ class InvitedJuniorAPIView(viewsets.ModelViewSet):
class FilterJuniorAPIView(viewsets.ModelViewSet):
"""filter junior profile"""
"""Update guardian profile"""
serializer_class = JuniorDetailListSerializer
permission_classes = [IsAuthenticated]
pagination_class = PageNumberPagination
http_method_names = ('get',)
@swagger_auto_schema(
manual_parameters=[
# Example of a query parameter
openapi.Parameter(
'title',
openapi.IN_QUERY,
description='title of the name',
type=openapi.TYPE_STRING,
),
# Add more parameters as needed
]
)
def get_queryset(self):
"""Get the queryset for the view"""
title = self.request.GET.get('title')
@ -285,7 +237,7 @@ class FilterJuniorAPIView(viewsets.ModelViewSet):
return queryset
def list(self, request, *args, **kwargs):
"""Filter junior"""
"""Create guardian profile"""
try:
queryset = self.get_queryset()
paginator = self.pagination_class()
@ -299,9 +251,7 @@ class FilterJuniorAPIView(viewsets.ModelViewSet):
class RemoveJuniorAPIView(views.APIView):
"""Remove junior API
Params
id=37"""
"""Remove junior API"""
serializer_class = RemoveJuniorSerializer
model = Junior
permission_classes = [IsAuthenticated]
@ -315,12 +265,11 @@ class RemoveJuniorAPIView(views.APIView):
guardian_code__icontains=str(guardian.guardian_code)).last()
if junior_queryset:
# use RemoveJuniorSerializer serializer
serializer = RemoveJuniorSerializer(junior_queryset, context={"guardian_code":guardian.guardian_code},
data=request.data, partial=True)
serializer = RemoveJuniorSerializer(junior_queryset, data=request.data, partial=True)
if serializer.is_valid():
# save serializer
serializer.save()
send_notification_to_junior.delay(REMOVE_JUNIOR, None, junior_queryset.auth.id, {})
send_notification.delay(REMOVE_JUNIOR, None, junior_queryset.auth.id, {})
return custom_response(SUCCESS_CODE['3022'], serializer.data, response_status=status.HTTP_200_OK)
return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST)
else:
@ -330,17 +279,14 @@ class RemoveJuniorAPIView(views.APIView):
class JuniorTaskListAPIView(viewsets.ModelViewSet):
"""Junior task list"""
"""Update guardian profile"""
serializer_class = TaskDetailsjuniorSerializer
permission_classes = [IsAuthenticated]
pagination_class = PageNumberPagination
http_method_names = ('get',)
def list(self, request, *args, **kwargs):
"""Junior task list
status=0
search='title'
page=1"""
"""Create guardian profile"""
try:
status_value = self.request.GET.get('status')
search = self.request.GET.get('search')
@ -370,9 +316,7 @@ class JuniorTaskListAPIView(viewsets.ModelViewSet):
class CompleteJuniorTaskAPIView(views.APIView):
"""Payload
task_id
image"""
"""Update junior task API"""
serializer_class = CompleteTaskSerializer
model = JuniorTask
permission_classes = [IsAuthenticated]
@ -390,11 +334,8 @@ class CompleteJuniorTaskAPIView(views.APIView):
image_url = upload_image_to_alibaba(image, filename)
# fetch junior query
task_queryset = JuniorTask.objects.filter(id=task_id, junior__auth__email=self.request.user
).select_related('guardian', 'junior').last()
task_queryset = JuniorTask.objects.filter(id=task_id, junior__auth__email=self.request.user).last()
if task_queryset:
if task_queryset.junior.is_deleted or not task_queryset.junior.is_active:
return custom_error_response(ERROR_CODE['2074'], response_status=status.HTTP_400_BAD_REQUEST)
# use CompleteTaskSerializer serializer
if task_queryset.task_status in [str(NUMBER['four']), str(NUMBER['five'])]:
"""Already request send """
@ -417,8 +358,7 @@ class JuniorPointsListAPIView(viewsets.ModelViewSet):
http_method_names = ('get',)
def list(self, request, *args, **kwargs):
"""Junior Points
No Params"""
"""profile view"""
try:
update_positions_based_on_points()
queryset = JuniorPoints.objects.filter(junior__auth__email=self.request.user).last()
@ -429,7 +369,7 @@ class JuniorPointsListAPIView(viewsets.ModelViewSet):
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
class ValidateReferralCode(viewsets.ModelViewSet):
class ValidateReferralCode(viewsets.ViewSet):
"""Check guardian code exist or not"""
permission_classes = [IsAuthenticated]
http_method_names = ('get',)
@ -464,13 +404,7 @@ class InviteGuardianAPIView(viewsets.ModelViewSet):
permission_classes = [IsAuthenticated]
http_method_names = ('post',)
def create(self, request, *args, **kwargs):
""" add guardian
{
"first_name":"abc",
"last_name":"xyz",
"email":"abc@yopmail.com",
"relationship":2
}"""
""" junior list"""
try:
if request.data['email'] == '':
return custom_error_response(ERROR_CODE['2062'], response_status=status.HTTP_400_BAD_REQUEST)
@ -488,11 +422,7 @@ class InviteGuardianAPIView(viewsets.ModelViewSet):
class StartTaskAPIView(views.APIView):
"""Update junior task API
Paylod
{
"task_id":28
}"""
"""Update junior task API"""
serializer_class = StartTaskSerializer
model = JuniorTask
permission_classes = [IsAuthenticated]
@ -516,13 +446,7 @@ class StartTaskAPIView(views.APIView):
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
class ReAssignJuniorTaskAPIView(views.APIView):
"""Update junior task API
Payload
{
"task_id":34,
"due_date":"2023-08-22"
}
"""
"""Update junior task API"""
serializer_class = ReAssignTaskSerializer
model = JuniorTask
permission_classes = [IsAuthenticated]
@ -551,10 +475,7 @@ class StartArticleAPIView(viewsets.ModelViewSet):
http_method_names = ('post',)
def create(self, request, *args, **kwargs):
""" Payload
{
"article_id":"2"
}"""
""" junior list"""
try:
junior_instance = Junior.objects.filter(auth=self.request.user).last()
article_id = request.data.get('article_id')
@ -576,7 +497,7 @@ class StartArticleAPIView(viewsets.ModelViewSet):
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
class StartAssessmentAPIView(viewsets.ModelViewSet):
"""Question answer viewset"""
"""Junior Points viewset"""
serializer_class = StartAssessmentSerializer
permission_classes = [IsAuthenticated]
http_method_names = ('get',)
@ -589,9 +510,7 @@ class StartAssessmentAPIView(viewsets.ModelViewSet):
).order_by('-created_at')
return article
def list(self, request, *args, **kwargs):
"""Params
article_id
"""
"""profile view"""
try:
queryset = self.get_queryset()
@ -603,9 +522,7 @@ class StartAssessmentAPIView(viewsets.ModelViewSet):
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
class CheckAnswerAPIView(viewsets.ModelViewSet):
"""Params
question_id=1
answer_id=1"""
"""Junior Points viewset"""
permission_classes = [IsAuthenticated]
http_method_names = ('get',)
@ -614,16 +531,13 @@ class CheckAnswerAPIView(viewsets.ModelViewSet):
article = ArticleSurvey.objects.filter(id=question_id).last()
return article
def list(self, request, *args, **kwargs):
""" Params
question_id=1
answer_id=1
"""
"""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).last()
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:
@ -641,9 +555,7 @@ class CheckAnswerAPIView(viewsets.ModelViewSet):
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
class CompleteArticleAPIView(views.APIView):
"""Params
article_id
"""
"""Remove junior API"""
permission_classes = [IsAuthenticated]
http_method_names = ('put', 'get',)
def put(self, request, format=None):
@ -657,8 +569,7 @@ class CompleteArticleAPIView(views.APIView):
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
def get(self, request, *args, **kwargs):
""" Params
article_id=1"""
""" junior list"""
try:
article_id = self.request.GET.get('article_id')
total_earn_points = JuniorArticlePoints.objects.filter(junior__auth=request.user,
@ -672,16 +583,12 @@ class CompleteArticleAPIView(views.APIView):
class ReadArticleCardAPIView(views.APIView):
"""Read article card API"""
"""Remove junior API"""
permission_classes = [IsAuthenticated]
http_method_names = ('put',)
def put(self, request, *args, **kwargs):
""" Read article card
Payload
{"article_id":"1",
"article_card":"2",
"current_page":"2"}"""
""" junior list"""
try:
junior_instance = Junior.objects.filter(auth=self.request.user).last()
article = self.request.data.get('article_id')
@ -699,14 +606,11 @@ class ReadArticleCardAPIView(views.APIView):
class CreateArticleCardAPIView(viewsets.ModelViewSet):
"""Start article"""
serializer_class = CreateArticleCardSerializer
permission_classes = [IsAuthenticated]
http_method_names = ('post',)
def create(self, request, *args, **kwargs):
""" create article card
Params
{"article_id":1}"""
""" junior list"""
try:
junior_instance = Junior.objects.filter(auth=self.request.user).last()
article_id = request.data.get('article_id')
@ -725,22 +629,16 @@ class CreateArticleCardAPIView(viewsets.ModelViewSet):
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
class RemoveGuardianCodeAPIView(views.APIView):
"""Remove guardian code request API
Payload
{"guardian_code"
:"GRD037"
}"""
"""Update junior task API"""
serializer_class = RemoveGuardianCodeSerializer
permission_classes = [IsAuthenticated]
def put(self, request, format=None):
try:
guardian_code = self.request.data.get("guardian_code")
junior_queryset = Junior.objects.filter(auth=self.request.user).last()
if junior_queryset:
# use RemoveGuardianCodeSerializer serializer
serializer = RemoveGuardianCodeSerializer(junior_queryset, context = {"guardian_code":guardian_code},
data=request.data, partial=True)
serializer = RemoveGuardianCodeSerializer(junior_queryset, data=request.data, partial=True)
if serializer.is_valid():
# save serializer
serializer.save()
@ -749,49 +647,5 @@ class RemoveGuardianCodeAPIView(views.APIView):
else:
# task in another state
return custom_error_response(ERROR_CODE['2047'], response_status=status.HTTP_400_BAD_REQUEST)
except Exception as e:
error_detail = e.detail.get('error', None)
return custom_error_response(error_detail, response_status=status.HTTP_400_BAD_REQUEST)
class FAQViewSet(GenericViewSet, mixins.CreateModelMixin,
mixins.ListModelMixin):
"""FAQ view set"""
serializer_class = FAQSerializer
permission_classes = [IsAuthenticated]
http_method_names = ['get', 'post']
def get_queryset(self):
return FAQ.objects.all()
def create(self, request, *args, **kwargs):
"""
faq create api method
:param request:
:param args: question, description
:param kwargs:
:return: success message
"""
obj_data = [FAQ(**item) for item in request.data]
try:
FAQ.objects.bulk_create(obj_data)
return custom_response(SUCCESS_CODE["3045"], response_status=status.HTTP_200_OK)
except Exception as e:
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
def list(self, request, *args, **kwargs):
"""
article list api method
:param request:
:param args:
:param kwargs:
:return: list of article
"""
queryset = self.get_queryset()
paginator = self.pagination_class()
paginated_queryset = paginator.paginate_queryset(queryset, request)
serializer = self.serializer_class(paginated_queryset, many=True)
return custom_response(None, data=serializer.data, response_status=status.HTTP_200_OK)

View File

@ -10,4 +10,3 @@ from notifications.models import Notification
class NotificationAdmin(admin.ModelAdmin):
"""Notification Admin"""
list_display = ['id', 'notification_type', 'notification_to', 'data', 'is_read']
list_filter = ['notification_type']

View File

@ -1,20 +1,19 @@
"""
notification constants file
"""
REGISTRATION = 1
ASSOCIATE_REQUEST = 3
ASSOCIATE_REJECTED = 4
ASSOCIATE_APPROVED = 5
REFERRAL_POINTS = 6
JUNIOR_ADDED = 7
TASK_ASSIGNED = 8
TASK_ACTION = 9
TASK_REJECTED = 10
TASK_APPROVED = 11
REMOVE_JUNIOR = 13
from base.constants import NUMBER
REGISTRATION = NUMBER['one']
TASK_CREATED = NUMBER['two']
INVITED_GUARDIAN = NUMBER['three']
APPROVED_JUNIOR = NUMBER['four']
REFERRAL_POINTS = NUMBER['five']
TASK_POINTS = NUMBER['six']
TASK_REJECTED = NUMBER['seven']
SKIPPED_PROFILE_SETUP = NUMBER['eight']
TASK_SUBMITTED = NUMBER['nine']
TASK_ACTION = NUMBER['ten']
LEADERBOARD_RANKING = NUMBER['eleven']
REMOVE_JUNIOR = NUMBER['twelve']
TEST_NOTIFICATION = 99
NOTIFICATION_DICT = {
@ -22,59 +21,52 @@ NOTIFICATION_DICT = {
"title": "Successfully registered!",
"body": "You have registered successfully. Now login and complete your profile."
},
ASSOCIATE_REQUEST: {
"title": "Associate request!",
"body": "You have request from {from_user} to associate with you."
TASK_CREATED: {
"title": "Task created!",
"body": "Task created successfully."
},
ASSOCIATE_REJECTED: {
"title": "Associate request rejected!",
"body": "Your request to associate has been rejected by {from_user}."
INVITED_GUARDIAN: {
"title": "Invite guardian",
"body": "Invite guardian successfully"
},
ASSOCIATE_APPROVED: {
"title": "Associate request approved!",
"body": "Your request to associate has been approved by {from_user}."
APPROVED_JUNIOR: {
"title": "Approve junior",
"body": "You have request from junior to associate with you"
},
# Juniors will receive Notifications for every Points earned by referrals
REFERRAL_POINTS: {
"title": "Earn Referral points!",
"title": "Earn Referral points",
"body": "You earn 5 points for referral."
},
# Juniors will receive notification once any custodians add them in their account
JUNIOR_ADDED: {
"title": "Profile already setup!",
"body": "Your guardian has already setup your profile."
TASK_POINTS: {
"title": "Earn Task points!",
"body": "You earn 5 points for task."
},
# Juniors will receive Notification for every Task Assign by Custodians
TASK_ASSIGNED: {
"title": "New task assigned!",
"body": "{from_user} has assigned you a new task."
},
# Guardian will receive notification as soon as junior send task for approval
TASK_ACTION: {
"title": "Task completion approval!",
"body": "You have request from {from_user} for task completion."
},
# Juniors will receive notification as soon as their task is rejected by custodians
TASK_REJECTED: {
"title": "Task completion rejected!",
"body": "Your task completion request has been rejected by {from_user}."
"title": "Task rejected!",
"body": "Your task has been rejected."
},
# Juniors will receive notification as soon as their task is approved by custodians
# and for every Points earned by Task completion
TASK_APPROVED: {
"title": "Task completion approved!",
"body": "Your task completion request has been approved by {from_user}. "
"Also you earned 5 points for successful completion."
SKIPPED_PROFILE_SETUP: {
"title": "Skipped profile setup!",
"body": "Your guardian has been setup your profile."
},
TASK_SUBMITTED: {
"title": "Task submitted!",
"body": "Your task has been submitted successfully."
},
TASK_ACTION: {
"title": "Task approval!",
"body": "You have request for task approval."
},
LEADERBOARD_RANKING: {
"title": "Leader board rank!",
"body": "Your rank is ."
},
# Juniors will receive notification as soon as their custodians remove them from account
REMOVE_JUNIOR: {
"title": "Disassociate by guardian!",
"body": "Your guardian has disassociated you."
"body": "Your guardian disassociate you ."
},
TEST_NOTIFICATION: {
"title": "Test Notification",
"body": "This notification is for testing purpose from {from_user}."
"body": "This notification is for testing purpose"
}
}

View File

@ -35,13 +35,10 @@ class NotificationListSerializer(serializers.ModelSerializer):
class Meta(object):
"""meta info"""
model = Notification
fields = ['id', 'data', 'is_read', 'created_at']
fields = ['id', 'data', 'is_read']
class ReadNotificationSerializer(serializers.ModelSerializer):
"""User task Serializer"""
id = serializers.ListSerializer(child=serializers.IntegerField())
class Meta(object):
"""Meta class"""
model = Notification

View File

@ -6,7 +6,7 @@ from django.urls import path, include
from rest_framework import routers
# local imports
from notifications.views import NotificationViewSet
from notifications.views import NotificationViewSet, ReadNotification
# initiate router
router = routers.SimpleRouter()
@ -15,4 +15,5 @@ router.register('notifications', NotificationViewSet, basename='notifications')
urlpatterns = [
path('api/v1/', include(router.urls)),
path('api/v1/read-notification/', ReadNotification.as_view()),
]

View File

@ -10,9 +10,6 @@ from firebase_admin.messaging import Message, Notification as FirebaseNotificati
from django.contrib.auth import get_user_model
from account.models import UserNotification
from account.utils import get_user_full_name
from guardian.models import Guardian
from junior.models import Junior
from notifications.constants import NOTIFICATION_DICT
from notifications.models import Notification
@ -42,94 +39,30 @@ def remove_fcm_token(user_id: int, access_token: str, registration_id) -> None:
print(e)
def get_basic_detail(from_user_id, to_user_id):
"""
used to get the basic details
"""
def get_basic_detail(notification_type, from_user_id, to_user_id):
""" used to get the basic details """
notification_data = NOTIFICATION_DICT[notification_type]
from_user = User.objects.get(id=from_user_id) if from_user_id else None
to_user = User.objects.get(id=to_user_id)
return from_user, to_user
return notification_data, from_user, to_user
def get_notification_data(notification_type, from_user, to_user, extra_data):
"""
get notification and push data
:param notification_type: notification_type
:param from_user: from_user obj
:param to_user: to_user obj
:param extra_data: any extra data provided
:return: notification and push data
"""
push_data = NOTIFICATION_DICT[notification_type].copy()
notification_data = push_data.copy()
notification_data['to_user'] = get_user_full_name(to_user)
if from_user:
from_user_name = get_user_full_name(from_user)
push_data['body'] = push_data['body'].format(from_user=from_user_name)
notification_data['body'] = notification_data['body'].format(from_user=from_user_name)
notification_data['from_user'] = from_user_name
notification_data.update(extra_data)
return notification_data, push_data
def send_notification(notification_type, from_user, to_user, extra_data):
"""
used to send the push for the given notification type
"""
# (from_user, to_user) = get_basic_detail(from_user_id, to_user_id)
notification_data, push_data = get_notification_data(notification_type, from_user, to_user, extra_data)
@shared_task()
def send_notification(notification_type, from_user_id, to_user_id, extra_data):
""" used to send the push for the given notification type """
(notification_data, from_user, to_user) = get_basic_detail(notification_type, from_user_id, to_user_id)
user_notification_type = UserNotification.objects.filter(user=to_user).first()
notification_data.update({'badge': Notification.objects.filter(notification_to=to_user, is_read=False).count()})
data = notification_data
Notification.objects.create(notification_type=notification_type, notification_from=from_user,
notification_to=to_user, data=notification_data)
notification_to=to_user, data=data)
if user_notification_type.push_notification:
send_push(to_user, push_data)
data.update({'badge': Notification.objects.filter(notification_to=to_user, is_read=False).count()})
send_push(to_user, data)
def send_push(user, data):
""" used to send push notification to specific user """
notification_data = data.pop('data', None)
user.fcmdevice_set.filter(active=True).send_message(
Message(notification=FirebaseNotification(data['title'], data['body']), data=data)
Message(notification=FirebaseNotification(data['title'], data['body']), data=notification_data)
)
@shared_task()
def send_notification_to_guardian(notification_type, from_user_id, to_user_id, extra_data):
"""
:param notification_type:
:param from_user_id:
:param to_user_id:
:param extra_data:
:return:
"""
from_user = None
if from_user_id:
from_user = Junior.objects.filter(auth_id=from_user_id).select_related('auth').first()
extra_data['from_user_image'] = from_user.image
from_user = from_user.auth
to_user = Guardian.objects.filter(user_id=to_user_id).select_related('user').first()
extra_data['to_user_image'] = to_user.image
send_notification(notification_type, from_user, to_user.user, extra_data)
@shared_task()
def send_notification_to_junior(notification_type, from_user_id, to_user_id, extra_data):
"""
:param notification_type:
:param from_user_id:
:param to_user_id:
:param extra_data:
:return:
"""
from_user = None
if from_user_id:
from_user = Guardian.objects.filter(user_id=from_user_id).select_related('user').first()
extra_data['from_user_image'] = from_user.image
from_user = from_user.user
to_user = Junior.objects.filter(auth_id=to_user_id).select_related('auth').first()
extra_data['to_user_image'] = to_user.image
send_notification(notification_type, from_user, to_user.auth, extra_data)

View File

@ -13,7 +13,7 @@ from base.messages import SUCCESS_CODE, ERROR_CODE
from notifications.constants import TEST_NOTIFICATION
# Import serializer
from notifications.serializers import RegisterDevice, NotificationListSerializer, ReadNotificationSerializer
from notifications.utils import send_notification, send_notification_to_guardian, send_notification_to_junior
from notifications.utils import send_notification
# Import model
from notifications.models import Notification
@ -30,8 +30,15 @@ class NotificationViewSet(viewsets.GenericViewSet):
paginator = self.pagination_class()
paginated_queryset = paginator.paginate_queryset(queryset, request)
serializer = self.serializer_class(paginated_queryset, many=True)
self.mark_notifications_as_read(serializer.data)
return custom_response(None, serializer.data)
@staticmethod
def mark_notifications_as_read(data):
""" used to mark notification queryset as read """
ids = [obj['id'] for obj in data]
Notification.objects.filter(id__in=ids).update(is_read=True)
@action(methods=['post'], detail=False, url_path='device', url_name='device', serializer_class=RegisterDevice)
def fcm_registration(self, request):
"""
@ -49,17 +56,35 @@ class NotificationViewSet(viewsets.GenericViewSet):
to send test notification
:return:
"""
send_notification_to_guardian.delay(TEST_NOTIFICATION, None, request.auth.payload['user_id'],
{'task_id': None})
send_notification_to_junior.delay(TEST_NOTIFICATION, None, request.auth.payload['user_id'],
{'task_id': None})
send_notification.delay(TEST_NOTIFICATION, None, request.auth.payload['user_id'], {})
return custom_response(SUCCESS_CODE["3000"])
@action(methods=['patch'], url_path='mark-as-read', url_name='mark-as-read', detail=False,
serializer_class=ReadNotificationSerializer)
def mark_as_read(self, request, *args, **kwargs):
@action(methods=['get'], detail=False, url_path='list', url_name='list',
serializer_class=NotificationListSerializer)
def notification_list(self, request):
"""
notification list
"""
Notification.objects.filter(id__in=request.data.get('id')).update(is_read=True)
return custom_response(SUCCESS_CODE['3039'], response_status=status.HTTP_200_OK)
try:
queryset = Notification.objects.filter(notification_to=request.user)
serializer = NotificationListSerializer(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 ReadNotification(views.APIView):
"""Update notification API"""
serializer_class = ReadNotificationSerializer
model = Notification
permission_classes = [IsAuthenticated]
def put(self, request, format=None):
try:
notification_id = self.request.data.get('notification_id')
notification_queryset = Notification.objects.filter(id__in=notification_id,
notification_to=self.request.user).update(is_read=True)
if notification_queryset:
return custom_response(SUCCESS_CODE['3039'], 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

@ -99,6 +99,3 @@ uritemplate==4.1.1
urllib3==1.26.16
vine==5.0.0
wcwidth==0.2.6
pandas==2.0.3
XlsxWriter==3.1.2

View File

@ -1,18 +1,13 @@
"""
web_admin pagination file
"""
# third party imports
from rest_framework.pagination import PageNumberPagination
from base.constants import NUMBER
class CustomPageNumberPagination(PageNumberPagination):
"""
custom paginator class
"""
# Set the desired page size
page_size = NUMBER['ten']
page_size = 10 # Set the desired page size
page_size_query_param = 'page_size'
# Set a maximum page size if needed
max_page_size = NUMBER['hundred']
max_page_size = 100 # Set a maximum page size if needed

View File

@ -1,24 +1,12 @@
"""
web_admin analytics serializer file
"""
# third party imports
from rest_framework import serializers
# django imports
from django.contrib.auth import get_user_model
# local imports
from base.constants import USER_TYPE
from junior.models import JuniorPoints, Junior
USER = get_user_model()
class JuniorLeaderboardSerializer(serializers.ModelSerializer):
"""
junior leaderboard serializer
"""
name = serializers.SerializerMethodField()
first_name = serializers.SerializerMethodField()
last_name = serializers.SerializerMethodField()
@ -28,7 +16,7 @@ class JuniorLeaderboardSerializer(serializers.ModelSerializer):
meta class
"""
model = Junior
fields = ('id', 'name', 'first_name', 'last_name', 'is_active', 'image', 'is_deleted')
fields = ('id', 'name', 'first_name', 'last_name', 'is_active', 'image')
@staticmethod
def get_name(obj):
@ -56,75 +44,9 @@ class JuniorLeaderboardSerializer(serializers.ModelSerializer):
class LeaderboardSerializer(serializers.ModelSerializer):
"""
leaderboard serializer
"""
junior = JuniorLeaderboardSerializer()
rank = serializers.IntegerField()
class Meta:
"""
meta class
"""
model = JuniorPoints
fields = ('total_points', 'rank', 'junior')
class UserCSVReportSerializer(serializers.ModelSerializer):
"""
user csv/xls report serializer
"""
phone_number = serializers.SerializerMethodField()
user_type = serializers.SerializerMethodField()
is_active = serializers.SerializerMethodField()
date_joined = serializers.SerializerMethodField()
class Meta:
"""
meta class
"""
model = USER
fields = ('first_name', 'last_name', 'email', 'phone_number', 'user_type', 'is_active', 'date_joined')
@staticmethod
def get_phone_number(obj):
"""
:param obj: user object
:return: user phone number
"""
if profile := (obj.guardian_profile.all().first() or obj.junior_profile.all().first()):
return f"+{profile.country_code}{profile.phone}" \
if profile.country_code and profile.phone else profile.phone
else:
return None
@staticmethod
def get_user_type(obj):
"""
:param obj: user object
:return: user type
"""
if obj.guardian_profile.all().first():
return dict(USER_TYPE).get('2').capitalize()
elif obj.junior_profile.all().first():
return dict(USER_TYPE).get('1').capitalize()
else:
return None
@staticmethod
def get_is_active(obj):
"""
:param obj: user object
:return: user type
"""
if profile := (obj.guardian_profile.all().first() or obj.junior_profile.all().first()):
return "Active" if profile.is_active else "Inactive"
@staticmethod
def get_date_joined(obj):
"""
:param obj: user obj
:return: formatted date
"""
date = obj.date_joined.strftime("%d %b %Y")
return date

View File

@ -219,7 +219,8 @@ class ArticleListSerializer(serializers.ModelSerializer):
"""
serializer for article API
"""
image = serializers.SerializerMethodField('get_image')
article_cards = ArticleCardSerializer(many=True)
article_survey = ArticleSurveySerializer(many=True)
total_points = serializers.SerializerMethodField('get_total_points')
is_completed = serializers.SerializerMethodField('get_is_completed')
@ -228,16 +229,12 @@ class ArticleListSerializer(serializers.ModelSerializer):
meta class
"""
model = Article
fields = ('id', 'title', 'description','image', 'total_points', 'is_completed')
fields = ('id', 'title', 'description', 'article_cards', 'article_survey', 'total_points', 'is_completed')
def get_image(self, obj):
"""article image"""
if obj.article_cards.first():
return obj.article_cards.first().image_url
return None
def get_total_points(self, obj):
"""total points of article"""
return obj.article_survey.all().count() * NUMBER['five']
total_question = ArticleSurvey.objects.filter(article=obj).count()
return total_question * NUMBER['five']
def get_is_completed(self, obj):
"""complete all question"""
@ -271,14 +268,14 @@ class ArticleQuestionSerializer(serializers.ModelSerializer):
ans_obj = SurveyOption.objects.filter(survey=obj, is_answer=True).last()
if ans_obj:
return ans_obj.id
return None
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).last()
if junior_article_obj and junior_article_obj.submitted_answer:
question=obj, is_answer_correct=True).last()
if junior_article_obj:
return junior_article_obj.submitted_answer.id
return None

View File

@ -5,7 +5,7 @@ web_admin user_management serializers file
from rest_framework import serializers
from django.contrib.auth import get_user_model
from base.constants import USER_TYPE, GUARDIAN, JUNIOR
from base.constants import USER_TYPE
# local imports
from base.messages import ERROR_CODE, SUCCESS_CODE
from guardian.models import Guardian
@ -108,7 +108,7 @@ class GuardianSerializer(serializers.ModelSerializer):
"""
model = Guardian
fields = ('id', 'name', 'first_name', 'last_name', 'username', 'dob', 'gender', 'country_code', 'phone',
'is_active', 'country_name', 'image', 'email', 'is_deleted')
'is_active', 'country_name', 'image', 'email')
def validate(self, attrs):
"""
@ -187,7 +187,7 @@ class JuniorSerializer(serializers.ModelSerializer):
"""
model = Junior
fields = ('id', 'name', 'first_name', 'last_name', 'username', 'dob', 'gender', 'country_code', 'phone',
'is_active', 'country_name', 'image', 'email', 'is_deleted')
'is_active', 'country_name', 'image', 'email')
def validate(self, attrs):
"""
@ -210,10 +210,10 @@ class JuniorSerializer(serializers.ModelSerializer):
"""
instance.auth.email = self.validated_data.get('email', instance.auth.email)
instance.auth.username = self.validated_data.get('email', instance.auth.username)
instance.auth.save(update_fields=['email', 'username'])
instance.auth.save()
instance.country_code = validated_data.get('country_code', instance.country_code)
instance.phone = validated_data.get('phone', instance.phone)
instance.save(update_fields=['country_code', 'phone'])
instance.save()
return instance
@staticmethod
@ -265,30 +265,33 @@ class UserManagementDetailSerializer(serializers.ModelSerializer):
model = USER
fields = ('id', 'user_type', 'email', 'guardian_profile', 'junior_profile', 'associated_users')
def get_user_type(self, obj):
@staticmethod
def get_user_type(obj):
"""
:param obj: user object
:return: user type
"""
return GUARDIAN if self.context['user_type'] == GUARDIAN else JUNIOR
if obj.guardian_profile.all().first():
return dict(USER_TYPE).get('2')
elif obj.junior_profile.all().first():
return dict(USER_TYPE).get('1')
else:
return None
def get_associated_users(self, obj):
@staticmethod
def get_associated_users(obj):
"""
:param obj: user object
:return: associated user
"""
if self.context['user_type'] == GUARDIAN:
profile = obj.guardian_profile.all().only('user_id', 'guardian_code').first()
if profile := obj.guardian_profile.all().first():
if profile.guardian_code:
junior = Junior.objects.filter(guardian_code__contains=[profile.guardian_code],
is_verified=True).select_related('auth')
junior = Junior.objects.filter(guardian_code__contains=[profile.guardian_code], is_verified=True)
serializer = JuniorSerializer(junior, many=True)
return serializer.data
elif self.context['user_type'] == JUNIOR:
profile = obj.junior_profile.all().only('auth_id', 'guardian_code').first()
elif profile := obj.junior_profile.all().first():
if profile.guardian_code:
guardian = Guardian.objects.filter(guardian_code__in=profile.guardian_code,
is_verified=True).select_related('user')
guardian = Guardian.objects.filter(guardian_code__in=profile.guardian_code, is_verified=True)
serializer = GuardianSerializer(guardian, many=True)
return serializer.data
else:

View File

@ -2,10 +2,9 @@
web_utils file
"""
import base64
import datetime
from base.constants import ARTICLE_CARD_IMAGE_FOLDER, DATE_FORMAT
from guardian.utils import upload_image_to_alibaba, upload_base64_image_to_alibaba
from base.constants import ARTICLE_CARD_IMAGE_FOLDER
from guardian.utils import upload_image_to_alibaba
def pop_id(data):
@ -30,10 +29,10 @@ def get_image_url(data):
return data['image_url']
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])
image_name = data.pop('image_name') if 'image_name' in data else f"{data['title']}.jpg"
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}"
# upload image on ali baba
image_url = upload_base64_image_to_alibaba(base64_image, filename)
image_url = upload_image_to_alibaba(base64_image, filename)
return image_url
elif 'image' in data and data['image'] is not None:
image = data.pop('image')
@ -41,21 +40,3 @@ def get_image_url(data):
# upload image on ali baba
image_url = upload_image_to_alibaba(image, filename)
return image_url
def get_dates(start_date, end_date):
"""
to get start and end date
:param start_date: format (yyyy-mm-dd)
:param end_date: format (yyyy-mm-dd)
:return: start and end date
"""
if start_date and end_date:
start_date = datetime.datetime.strptime(start_date, DATE_FORMAT).date()
end_date = datetime.datetime.strptime(end_date, DATE_FORMAT).date()
else:
end_date = datetime.date.today()
start_date = end_date - datetime.timedelta(days=6)
return start_date, end_date

View File

@ -3,9 +3,6 @@ web_admin analytics view file
"""
# python imports
import datetime
import io
import pandas as pd
import xlsxwriter
# third party imports
from rest_framework.viewsets import GenericViewSet
@ -19,18 +16,15 @@ 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 django.http import HttpResponse
# local imports
from account.utils import custom_response
from base.constants import PENDING, IN_PROGRESS, REJECTED, REQUESTED, COMPLETED, EXPIRED, DATE_FORMAT, TASK_STATUS
from base.constants import PENDING, IN_PROGRESS, REJECTED, REQUESTED, COMPLETED, EXPIRED, DATE_FORMAT
from guardian.models import JuniorTask
from guardian.utils import upload_excel_file_to_alibaba
from junior.models import JuniorPoints
from web_admin.pagination import CustomPageNumberPagination
from web_admin.permission import AdminPermission
from web_admin.serializers.analytics_serializer import LeaderboardSerializer, UserCSVReportSerializer
from web_admin.utils import get_dates
from web_admin.serializers.analytics_serializer import LeaderboardSerializer
USER = get_user_model()
@ -53,7 +47,7 @@ class AnalyticsViewSet(GenericViewSet):
).prefetch_related('guardian_profile',
'junior_profile'
).exclude(junior_profile__isnull=True,
guardian_profile__isnull=True).order_by('-date_joined')
guardian_profile__isnull=True).order_by('date_joined')
return user_qs
@action(methods=['get'], url_name='users-count', url_path='users-count', detail=False)
@ -64,8 +58,13 @@ class AnalyticsViewSet(GenericViewSet):
:param request: end_date: date format (yyyy-mm-dd)
:return:
"""
start_date, end_date = get_dates(request.query_params.get('start_date'),
request.query_params.get('end_date'))
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))))
@ -84,8 +83,12 @@ class AnalyticsViewSet(GenericViewSet):
:param request: end_date: date format (yyyy-mm-dd)
:return:
"""
start_date, end_date = get_dates(request.query_params.get('start_date'),
request.query_params.get('end_date'))
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))]
@ -102,8 +105,12 @@ class AnalyticsViewSet(GenericViewSet):
:param request: end_date: date format (yyyy-mm-dd)
:return:
"""
start_date, end_date = get_dates(request.query_params.get('start_date'),
request.query_params.get('end_date'))
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))]
@ -134,104 +141,3 @@ class AnalyticsViewSet(GenericViewSet):
paginated_queryset = paginator.paginate_queryset(queryset, request)
serializer = self.serializer_class(paginated_queryset, many=True)
return custom_response(None, serializer.data)
@action(methods=['get'], url_name='export-excel', url_path='export-excel', detail=False)
def export_excel(self, request):
"""
to export users count, task details and top juniors in csv/excel file
:param request: start_date: date format (yyyy-mm-dd)
:param request: end_date: date format (yyyy-mm-dd)
:return:
"""
response = HttpResponse(content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
response['Content-Disposition'] = 'attachment; filename="ZOD_Bank_Analytics.xlsx"'
start_date, end_date = get_dates(request.query_params.get('start_date'),
request.query_params.get('end_date'))
# Use BytesIO for binary data
buffer = io.BytesIO()
# Create an XlsxWriter Workbook object
workbook = xlsxwriter.Workbook(buffer)
# Add sheets
sheets = ['Users', 'Assign Tasks', 'Juniors Leaderboard']
for sheet_name in sheets:
worksheet = workbook.add_worksheet(name=sheet_name)
# sheet 1 for Total Users
if sheet_name == 'Users':
user_qs = self.get_queryset()
queryset = user_qs.filter(date_joined__range=(start_date, (end_date + datetime.timedelta(days=1))))
serializer = UserCSVReportSerializer(queryset, many=True)
df_users = pd.DataFrame([
{'Name': f"{user['first_name']} {user['last_name']}",
'Email': user['email'], 'Phone Number': user['phone_number'],
'User Type': user['user_type'], 'Status': user['is_active'],
'Date Joined': user['date_joined']}
for user in serializer.data
])
write_excel_worksheet(worksheet, df_users)
# sheet 2 for Assign Task
elif sheet_name == 'Assign Tasks':
assign_tasks = JuniorTask.objects.filter(
created_at__range=[start_date, (end_date + datetime.timedelta(days=1))]
).exclude(task_status__in=[PENDING, EXPIRED])
df_tasks = pd.DataFrame([
{'Task Name': task.task_name, 'Task Status': dict(TASK_STATUS).get(task.task_status).capitalize()}
for task in assign_tasks
])
write_excel_worksheet(worksheet, df_tasks)
# sheet 3 for Juniors Leaderboard and rank
elif sheet_name == 'Juniors Leaderboard':
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')[:15]
df_leaderboard = pd.DataFrame([
{
'Junior Name': f"{junior.junior.auth.first_name} {junior.junior.auth.last_name}"
if junior.junior.auth.last_name else junior.junior.auth.first_name,
'Points': junior.total_points,
'Rank': junior.rank
}
for junior in queryset
])
write_excel_worksheet(worksheet, df_leaderboard)
# Close the workbook to save the content
workbook.close()
# Reset the buffer position and write the content to the response
buffer.seek(0)
response.write(buffer.getvalue())
buffer.close()
filename = f"{'analytics'}/{'ZOD_Bank_Analytics.xlsx'}"
file_link = upload_excel_file_to_alibaba(response, filename)
return custom_response(None, file_link)
def write_excel_worksheet(worksheet, dataframe):
"""
to perform write action on worksheets
:param worksheet:
:param dataframe:
:return: worksheet
"""
for idx, col in enumerate(dataframe.columns):
# Write header
worksheet.write(0, idx, col)
for row_num, row in enumerate(dataframe.values, start=1):
for col_num, value in enumerate(row):
worksheet.write(row_num, col_num, value)
return worksheet

View File

@ -44,20 +44,9 @@ class ArticleViewSet(GenericViewSet, mixins.CreateModelMixin, mixins.UpdateModel
def create(self, request, *args, **kwargs):
"""
article create api method
:param request: { "title": "string", "description": "string",
"article_cards": [
{ "title": "string",
"description": "string",
"image_name": "string",
"image_url": "string"
} ],
"article_survey": [
{ "question": "string",
"options": [
{ "option": "string",
"is_answer": true }
] }
] }
:param request:
:param args:
:param kwargs:
:return: success message
"""
serializer = self.serializer_class(data=request.data)
@ -68,24 +57,9 @@ class ArticleViewSet(GenericViewSet, mixins.CreateModelMixin, mixins.UpdateModel
def update(self, request, *args, **kwargs):
"""
article update api method
:param request: article_id,
{ "title": "string", "description": "string",
"article_cards": [
{ "id": 0,
"title": "string",
"description": "string",
"image_name": "string",
"image_url": "string"
} ],
"article_survey": [
{ "id": 0,
"question": "string",
"options": [
{ "id": 0,
"option": "string",
"is_answer": true
} ]
} ] }
:param request:
:param args:
:param kwargs:
:return: success message
"""
article = self.get_object()
@ -98,6 +72,8 @@ class ArticleViewSet(GenericViewSet, mixins.CreateModelMixin, mixins.UpdateModel
"""
article list api method
:param request:
:param args:
:param kwargs:
:return: list of article
"""
queryset = self.get_queryset()
@ -110,7 +86,9 @@ class ArticleViewSet(GenericViewSet, mixins.CreateModelMixin, mixins.UpdateModel
def retrieve(self, request, *args, **kwargs):
"""
article detail api method
:param request: article_id
:param request:
:param args:
:param kwargs:
:return: article detail data
"""
queryset = self.get_object()
@ -120,7 +98,9 @@ class ArticleViewSet(GenericViewSet, mixins.CreateModelMixin, mixins.UpdateModel
def destroy(self, request, *args, **kwargs):
"""
article delete (soft delete) api method
:param request: article_id
:param request:
:param args:
:param kwargs:
:return: success message
"""
article = self.get_object()
@ -197,10 +177,7 @@ class DefaultArticleCardImagesViewSet(GenericViewSet, mixins.CreateModelMixin, m
def create(self, request, *args, **kwargs):
"""
api method to upload default article card images
:param request: {
"image_name": "string",
"image": "image_file"
}
:param request:
:return: success message
"""
serializer = self.serializer_class(data=request.data)
@ -229,7 +206,10 @@ class ArticleListViewSet(GenericViewSet, mixins.ListModelMixin):
http_method_names = ['get',]
def get_queryset(self):
queryset = self.queryset.objects.filter(is_deleted=False, is_published=True).order_by('-created_at')
article = self.queryset.objects.filter(is_deleted=False).prefetch_related(
'article_cards', 'article_survey', 'article_survey__options'
).order_by('-created_at')
queryset = self.filter_queryset(article)
return queryset
def list(self, request, *args, **kwargs):
@ -245,9 +225,7 @@ class ArticleListViewSet(GenericViewSet, mixins.ListModelMixin):
return custom_response(None, data=serializer.data)
class ArticleCardListViewSet(viewsets.ModelViewSet):
"""Article card list
use below query param
article_id"""
"""Junior Points viewset"""
serializer_class = ArticleCardlistSerializer
permission_classes = [IsAuthenticated]
http_method_names = ('get',)
@ -256,9 +234,7 @@ class ArticleCardListViewSet(viewsets.ModelViewSet):
"""get queryset"""
return ArticleCard.objects.filter(article=self.request.GET.get('article_id'))
def list(self, request, *args, **kwargs):
"""Article card list
use below query param
article_id"""
"""profile view"""
try:
queryset = self.get_queryset()

View File

@ -27,7 +27,6 @@ class ForgotAndResetPasswordViewSet(GenericViewSet):
def admin_otp(self, request):
"""
api method to send otp
:param request: {"email": "string"}
:return: success message
"""
serializer = self.serializer_class(data=request.data)
@ -41,7 +40,6 @@ class ForgotAndResetPasswordViewSet(GenericViewSet):
def admin_verify_otp(self, request):
"""
api method to verify otp
:param request: {"email": "string", "otp": "otp"}
:return: success message
"""
serializer = self.serializer_class(data=request.data)
@ -54,7 +52,6 @@ class ForgotAndResetPasswordViewSet(GenericViewSet):
def admin_create_password(self, request):
"""
api method to create new password
:param request: {"email": "string", "new_password": "string", "confirm_password": "string"}
:return: success message
"""
serializer = self.serializer_class(data=request.data)

View File

@ -14,8 +14,6 @@ from django.db.models import Q
from account.utils import custom_response, custom_error_response
from base.constants import USER_TYPE
from base.messages import SUCCESS_CODE, ERROR_CODE
from guardian.models import Guardian
from junior.models import Junior
from web_admin.permission import AdminPermission
from web_admin.serializers.user_management_serializer import (UserManagementListSerializer,
UserManagementDetailSerializer, GuardianSerializer,
@ -72,14 +70,12 @@ class UserManagementViewSet(GenericViewSet, mixins.ListModelMixin,
"""
if self.request.query_params.get('user_type') not in [dict(USER_TYPE).get('1'), dict(USER_TYPE).get('2')]:
return custom_error_response(ERROR_CODE['2067'], status.HTTP_400_BAD_REQUEST)
queryset = self.queryset
queryset = queryset.filter(id=kwargs['pk'])
serializer = UserManagementDetailSerializer(
queryset, many=True,
context={'user_type': self.request.query_params.get('user_type')}
)
if self.request.query_params.get('user_type') == dict(USER_TYPE).get('2'):
queryset = queryset.filter(guardian_profile__user__id=kwargs['pk'])
elif self.request.query_params.get('user_type') == dict(USER_TYPE).get('1'):
queryset = queryset.filter(junior_profile__auth__id=kwargs['pk'])
serializer = UserManagementDetailSerializer(queryset, many=True)
return custom_response(None, data=serializer.data)
def partial_update(self, request, *args, **kwargs):
@ -91,14 +87,15 @@ class UserManagementViewSet(GenericViewSet, mixins.ListModelMixin,
"""
if self.request.query_params.get('user_type') not in [dict(USER_TYPE).get('1'), dict(USER_TYPE).get('2')]:
return custom_error_response(ERROR_CODE['2067'], status.HTTP_400_BAD_REQUEST)
queryset = self.queryset
if self.request.query_params.get('user_type') == dict(USER_TYPE).get('2'):
guardian = Guardian.objects.filter(user_id=kwargs['pk'], is_verified=True).first()
serializer = GuardianSerializer(guardian,
user_obj = queryset.filter(guardian_profile__user__id=kwargs['pk']).first()
serializer = GuardianSerializer(user_obj.guardian_profile.all().first(),
request.data, context={'user_id': kwargs['pk']})
elif self.request.query_params.get('user_type') == dict(USER_TYPE).get('1'):
junior = Junior.objects.filter(auth_id=kwargs['pk'], is_verified=True).select_related('auth').first()
serializer = JuniorSerializer(junior,
user_obj = queryset.filter(junior_profile__auth__id=kwargs['pk']).first()
serializer = JuniorSerializer(user_obj.junior_profile.all().first(),
request.data, context={'user_id': kwargs['pk']})
serializer.is_valid(raise_exception=True)
@ -117,12 +114,12 @@ class UserManagementViewSet(GenericViewSet, mixins.ListModelMixin,
return custom_error_response(ERROR_CODE['2067'], status.HTTP_400_BAD_REQUEST)
queryset = self.queryset
if self.request.query_params.get('user_type') == dict(USER_TYPE).get('2'):
user_obj = queryset.filter(id=kwargs['pk']).first()
user_obj = queryset.filter(guardian_profile__user__id=kwargs['pk']).first()
obj = user_obj.guardian_profile.all().first()
obj.is_active = False if obj.is_active else True
obj.save()
elif self.request.query_params.get('user_type') == dict(USER_TYPE).get('1'):
user_obj = queryset.filter(id=kwargs['pk']).first()
user_obj = queryset.filter(junior_profile__auth__id=kwargs['pk']).first()
obj = user_obj.junior_profile.all().first()
obj.is_active = False if obj.is_active else True
obj.save()

View File

@ -125,7 +125,6 @@ SIMPLE_JWT = {
# Database
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases
DATABASES = {
# default db setting
'default': {
'ENGINE': 'django.contrib.gis.db.backends.postgis',
'NAME':os.getenv('DB_NAME'),
@ -178,9 +177,6 @@ AUTH_PASSWORD_VALIDATORS = [
},
]
# database query logs settings
# Allows us to check db hits
# useful to optimize db query and hit
LOGGING = {
"version": 1,
"filters": {
@ -197,7 +193,6 @@ LOGGING = {
"class": "logging.StreamHandler"
}
},
# database logger
"loggers": {
"django.db.backends": {
"level": "DEBUG",
@ -247,7 +242,6 @@ CORS_ALLOW_HEADERS = (
'x-requested-with',
)
# CORS header settings
CORS_EXPOSE_HEADERS = (
'Access-Control-Allow-Origin: *',
)
@ -303,7 +297,5 @@ STATIC_URL = 'static/'
# define static root
STATIC_ROOT = 'static'
# media url
MEDIA_URL = "/media/"
# media path
MEDIA_ROOT = os.path.join(os.path.dirname(BASE_DIR), 'media')