mirror of
https://github.com/HamzaSha1/zod-backend.git
synced 2026-03-10 20:31:45 +00:00
Compare commits
54 Commits
ZBKADM-72-
...
sprint5
| Author | SHA1 | Date | |
|---|---|---|---|
| c46b2ef52c | |||
| c47f6222d9 | |||
| e9315beab9 | |||
| a65eb2f77d | |||
| f5a03e2fdf | |||
| 1028822908 | |||
| e9aa2dfda9 | |||
| ab1a2be679 | |||
| 11605540d7 | |||
| 8cd4864748 | |||
| b1b7c42438 | |||
| 8f9450b743 | |||
| bb3441e4ed | |||
| 5b9f7b1828 | |||
| 89dda61bff | |||
| 31f071a463 | |||
| 20644a6293 | |||
| a8b01d4c3a | |||
| 56e1484b87 | |||
| 557a7d7a5c | |||
| 4e0c6a91f4 | |||
| f931e20334 | |||
| 8d159ac3a4 | |||
| 95ce57ec7d | |||
| 7068551050 | |||
| c23d65f67c | |||
| 73f05dc843 | |||
| 290089b9ef | |||
| 5f3a9c35fa | |||
| b92115168d | |||
| 19acef10ef | |||
| 05fd76a50b | |||
| 60e6d96379 | |||
| fad39d399f | |||
| d573d56a35 | |||
| 08a08960ee | |||
| f8e529600b | |||
| 9765c90b9b | |||
| 930c10b578 | |||
| 8ca74e4b03 | |||
| 95dad86b12 | |||
| dfff643c71 | |||
| 214566ec8f | |||
| 210e1a39e9 | |||
| e380f3f6ab | |||
| 99a59162a2 | |||
| 67a5f670f8 | |||
| 82189d3953 | |||
| 65ecd9a125 | |||
| a7bce32993 | |||
| 4495d8999c | |||
| 61e94c9469 | |||
| 1c3d4731c1 | |||
| 46853011be |
@ -2,7 +2,7 @@
|
||||
from django.contrib import admin
|
||||
|
||||
"""Import django app"""
|
||||
from .models import UserEmailOtp, DefaultTaskImages, UserNotification, UserDelete, UserDeviceDetails
|
||||
from .models import UserEmailOtp, DefaultTaskImages, UserNotification, UserDelete, UserDeviceDetails, ForceUpdate
|
||||
# Register your models here.
|
||||
|
||||
@admin.register(UserDelete)
|
||||
@ -39,6 +39,19 @@ 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"""
|
||||
|
||||
@ -5,7 +5,7 @@ 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
|
||||
from account.models import UserDeviceDetails, ForceUpdate
|
||||
from base.messages import ERROR_CODE, SUCCESS_CODE
|
||||
from base.constants import NUMBER
|
||||
from junior.models import Junior
|
||||
@ -17,10 +17,12 @@ 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):
|
||||
def custom_response(custom_error, response_status = status.HTTP_404_NOT_FOUND):
|
||||
"""custom response"""
|
||||
response = Response(custom_error.data, status=status.HTTP_404_NOT_FOUND)
|
||||
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
|
||||
@ -39,10 +41,17 @@ class CustomMiddleware(object):
|
||||
# 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
|
||||
device_details = UserDeviceDetails.objects.filter(user=request.user, device_id=device_id).last()
|
||||
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:
|
||||
@ -53,7 +62,11 @@ class CustomMiddleware(object):
|
||||
if guardian:
|
||||
custom_error = custom_error_response(ERROR_CODE['2075'], response_status=status.HTTP_404_NOT_FOUND)
|
||||
response = custom_response(custom_error)
|
||||
if device_id and not device_details 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 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)
|
||||
return response
|
||||
|
||||
28
account/migrations/0010_forceupdate.py
Normal file
28
account/migrations/0010_forceupdate.py
Normal file
@ -0,0 +1,28 @@
|
||||
# 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',
|
||||
},
|
||||
),
|
||||
]
|
||||
@ -2,8 +2,9 @@
|
||||
"""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
|
||||
from base.constants import USER_TYPE, DEVICE_TYPE
|
||||
# Create your models here.
|
||||
|
||||
class UserProfile(models.Model):
|
||||
@ -165,3 +166,25 @@ 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
|
||||
|
||||
@ -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
|
||||
from account.models import UserEmailOtp, DefaultTaskImages, UserDelete, UserNotification, UserPhoneOtp, ForceUpdate
|
||||
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
|
||||
@ -123,7 +123,7 @@ class ChangePasswordSerializer(serializers.Serializer):
|
||||
|
||||
def create(self, validated_data):
|
||||
"""
|
||||
|
||||
change password
|
||||
"""
|
||||
new_password = validated_data.pop('new_password')
|
||||
current_password = validated_data.pop('current_password')
|
||||
@ -308,7 +308,7 @@ class EmailVerificationSerializer(serializers.ModelSerializer):
|
||||
class Meta(object):
|
||||
"""Meta info"""
|
||||
model = UserEmailOtp
|
||||
fields = '__all__'
|
||||
fields = ('email',)
|
||||
|
||||
|
||||
|
||||
@ -390,3 +390,12 @@ 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')
|
||||
|
||||
@ -29,7 +29,7 @@ from .views import (UserLogin, SendPhoneOtp, UserPhoneVerification, UserEmailVer
|
||||
GoogleLoginViewSet, SigninWithApple, ProfileAPIViewSet, UploadImageAPIViewSet,
|
||||
DefaultImageAPIViewSet, DeleteUserProfileAPIViewSet, UserNotificationAPIViewSet,
|
||||
UpdateUserNotificationAPIViewSet, SendSupportEmail, LogoutAPIView, AccessTokenAPIView,
|
||||
AdminLoginViewSet)
|
||||
AdminLoginViewSet, ForceUpdateViewSet)
|
||||
"""Router"""
|
||||
router = routers.SimpleRouter()
|
||||
|
||||
@ -39,8 +39,6 @@ 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"""
|
||||
@ -57,6 +55,8 @@ 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)),
|
||||
|
||||
@ -93,7 +93,7 @@ def junior_account_update(user_tb):
|
||||
# Update junior account
|
||||
junior_data.is_active = False
|
||||
junior_data.is_verified = False
|
||||
junior_data.guardian_code = '{}'
|
||||
junior_data.guardian_code = None
|
||||
junior_data.guardian_code_status = str(NUMBER['one'])
|
||||
junior_data.is_deleted = True
|
||||
junior_data.save()
|
||||
@ -204,8 +204,12 @@ def custom_error_response(detail, response_status):
|
||||
if not detail:
|
||||
"""when details is empty"""
|
||||
detail = {}
|
||||
return Response({"error": detail, "status": "failed", "code": response_status})
|
||||
|
||||
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)
|
||||
|
||||
def get_user_data(attrs):
|
||||
"""
|
||||
|
||||
186
account/views.py
186
account/views.py
@ -4,6 +4,7 @@ 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
|
||||
@ -26,14 +27,15 @@ 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
|
||||
from account.models import (UserDeviceDetails, UserPhoneOtp, UserEmailOtp, DefaultTaskImages, UserNotification,
|
||||
ForceUpdate)
|
||||
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)
|
||||
AdminLoginSerializer, ForceUpdateSerializer)
|
||||
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
|
||||
@ -49,7 +51,8 @@ class GoogleLoginMixin(object):
|
||||
def google_login(request):
|
||||
"""google login function"""
|
||||
access_token = request.data.get('access_token')
|
||||
user_type = request.data.get('user_type')
|
||||
user_type = request.META.get('HTTP_USER_TYPE')
|
||||
device_id = request.META.get('HTTP_DEVICE_ID')
|
||||
if not access_token:
|
||||
return Response({'error': 'Access token is required.'}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
@ -82,14 +85,29 @@ 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)
|
||||
if str(user_type) == '2':
|
||||
elif 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)
|
||||
|
||||
if not User.objects.filter(email__iexact=email).exists():
|
||||
else:
|
||||
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,
|
||||
@ -100,13 +118,23 @@ class GoogleLoginMixin(object):
|
||||
serializer = JuniorSerializer(junior_query)
|
||||
position = Junior.objects.all().count()
|
||||
JuniorPoints.objects.create(junior=junior_query, position=position)
|
||||
if str(user_type) == '2':
|
||||
elif 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)
|
||||
@ -117,16 +145,26 @@ class GoogleLoginViewSet(GoogleLoginMixin, viewsets.GenericViewSet):
|
||||
serializer_class = GoogleLoginSerializer
|
||||
|
||||
def create(self, request):
|
||||
"""create method"""
|
||||
"""Payload
|
||||
{
|
||||
"access_token",
|
||||
"user_type": "1"
|
||||
}"""
|
||||
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."""
|
||||
"""This API is for sign in with Apple for app.
|
||||
Payload
|
||||
{
|
||||
"access_token",
|
||||
"user_type": "1"
|
||||
}"""
|
||||
def post(self, request):
|
||||
token = request.data.get("access_token")
|
||||
user_type = request.data.get("user_type")
|
||||
user_type = request.META.get('HTTP_USER_TYPE')
|
||||
device_id = request.META.get('HTTP_DEVICE_ID')
|
||||
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}
|
||||
@ -134,11 +172,26 @@ class SigninWithApple(views.APIView):
|
||||
try:
|
||||
user = User.objects.get(email=decoded_data.get("email"))
|
||||
if str(user_type) == '1':
|
||||
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)
|
||||
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
|
||||
)
|
||||
return custom_response(SUCCESS_CODE['3003'], serializer.data,
|
||||
response_status=status.HTTP_200_OK)
|
||||
|
||||
@ -152,12 +205,22 @@ class SigninWithApple(views.APIView):
|
||||
serializer = JuniorSerializer(junior_query)
|
||||
position = Junior.objects.all().count()
|
||||
JuniorPoints.objects.create(junior=junior_query, position=position)
|
||||
if str(user_type) == '2':
|
||||
elif 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:
|
||||
@ -202,6 +265,10 @@ class ChangePasswordAPIView(views.APIView):
|
||||
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,
|
||||
@ -219,7 +286,12 @@ class ChangePasswordAPIView(views.APIView):
|
||||
)
|
||||
|
||||
class ResetPasswordAPIView(views.APIView):
|
||||
"""Reset password"""
|
||||
"""Reset password
|
||||
Payload
|
||||
{
|
||||
"verification_code":"373770",
|
||||
"password":"Demo@1323"
|
||||
}"""
|
||||
def post(self, request):
|
||||
serializer = ResetPasswordSerializer(data=request.data)
|
||||
if serializer.is_valid():
|
||||
@ -236,7 +308,10 @@ class ForgotPasswordAPIView(views.APIView):
|
||||
def post(self, request):
|
||||
|
||||
"""
|
||||
Post method to validate serializer
|
||||
Payload
|
||||
{
|
||||
"email": "abc@yopmail.com"
|
||||
}
|
||||
"""
|
||||
serializer = self.serializer_class(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
@ -420,7 +495,12 @@ class AdminLoginViewSet(viewsets.GenericViewSet):
|
||||
|
||||
|
||||
class UserEmailVerification(viewsets.ModelViewSet):
|
||||
"""User Email verification"""
|
||||
"""User Email verification
|
||||
Payload
|
||||
{
|
||||
"email":"ramu@yopmail.com",
|
||||
"otp":"361123"
|
||||
}"""
|
||||
serializer_class = EmailVerificationSerializer
|
||||
http_method_names = ('post',)
|
||||
|
||||
@ -467,8 +547,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)
|
||||
@ -480,7 +563,7 @@ class ReSendEmailOtp(viewsets.ModelViewSet):
|
||||
email_data.otp = otp
|
||||
email_data.expired_at = expiry
|
||||
email_data.save()
|
||||
send_otp_email(request.data['email'], otp)
|
||||
send_otp_email.delay(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)
|
||||
@ -489,23 +572,28 @@ class ProfileAPIViewSet(viewsets.ModelViewSet):
|
||||
"""Profile viewset"""
|
||||
serializer_class = JuniorProfileSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
http_method_names = ('get',)
|
||||
|
||||
def list(self, request, *args, **kwargs):
|
||||
"""profile view"""
|
||||
if str(self.request.GET.get('user_type')) == '1':
|
||||
"""profile view
|
||||
Params
|
||||
user_type"""
|
||||
user_type = request.META.get('HTTP_USER_TYPE')
|
||||
if str(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(self.request.GET.get('user_type')) == '2':
|
||||
elif str(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']
|
||||
@ -525,6 +613,7 @@ 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()
|
||||
@ -533,7 +622,13 @@ class DefaultImageAPIViewSet(viewsets.ModelViewSet):
|
||||
|
||||
|
||||
class DeleteUserProfileAPIViewSet(viewsets.GenericViewSet):
|
||||
""" Delete user API view set """
|
||||
""" 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"""
|
||||
|
||||
@action(detail=False, methods=['POST'], url_path='user-account',serializer_class=UserDeleteSerializer,
|
||||
permission_classes=[IsAuthenticated])
|
||||
@ -555,8 +650,9 @@ class UserNotificationAPIViewSet(viewsets.ModelViewSet):
|
||||
"""notification viewset"""
|
||||
serializer_class = UserNotificationSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
http_method_names = ('get',)
|
||||
def list(self, request, *args, **kwargs):
|
||||
"""profile view"""
|
||||
"""notification 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)
|
||||
@ -566,9 +662,14 @@ class UpdateUserNotificationAPIViewSet(viewsets.ModelViewSet):
|
||||
"""Update notification viewset"""
|
||||
serializer_class = UpdateUserNotificationSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
http_method_names = ('post',)
|
||||
|
||||
def create(self, request, *args, **kwargs):
|
||||
"""profile view"""
|
||||
"""Payload
|
||||
{"email_notification": false,
|
||||
"sms_notification": false,
|
||||
"push_notification": false}
|
||||
"""
|
||||
serializer = UpdateUserNotificationSerializer(data=request.data,
|
||||
context=request.user)
|
||||
if serializer.is_valid():
|
||||
@ -578,7 +679,12 @@ class UpdateUserNotificationAPIViewSet(viewsets.ModelViewSet):
|
||||
|
||||
|
||||
class SendSupportEmail(views.APIView):
|
||||
"""support email api"""
|
||||
"""support email api
|
||||
payload
|
||||
name
|
||||
email
|
||||
message
|
||||
"""
|
||||
permission_classes = (IsAuthenticated,)
|
||||
|
||||
def post(self, request):
|
||||
@ -622,3 +728,27 @@ 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)
|
||||
|
||||
@ -43,14 +43,18 @@ 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",
|
||||
|
||||
@ -101,10 +101,17 @@ ERROR_CODE = {
|
||||
"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"
|
||||
|
||||
}
|
||||
"""Success message code"""
|
||||
@ -171,7 +178,8 @@ SUCCESS_CODE = {
|
||||
# remove guardian code request
|
||||
"3044": "Remove guardian code request successfully",
|
||||
# create faq
|
||||
"3045": "Create FAQ data"
|
||||
"3045": "Create FAQ data",
|
||||
"3046": "Add App version successfully"
|
||||
|
||||
}
|
||||
"""status code error"""
|
||||
|
||||
Binary file not shown.
@ -28,7 +28,7 @@ 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_POINTS, TASK_REJECTED
|
||||
from notifications.constants import TASK_APPROVED, TASK_REJECTED
|
||||
# send notification function
|
||||
from notifications.utils import send_notification, send_notification_to_junior
|
||||
from django.core.exceptions import ValidationError
|
||||
@ -36,6 +36,7 @@ from django.utils.translation import gettext as _
|
||||
|
||||
# In this serializer file
|
||||
# define user serializer,
|
||||
# define password validation
|
||||
# create guardian serializer,
|
||||
# task serializer,
|
||||
# guardian serializer,
|
||||
@ -47,6 +48,7 @@ from django.utils.translation import gettext as _
|
||||
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
|
||||
@ -57,6 +59,7 @@ class PasswordValidator:
|
||||
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(
|
||||
@ -64,16 +67,20 @@ class PasswordValidator:
|
||||
)
|
||||
|
||||
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."))
|
||||
|
||||
|
||||
@ -420,7 +427,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_POINTS, None, junior_details.auth.id,
|
||||
send_notification_to_junior.delay(TASK_APPROVED, instance.guardian.user.id, junior_details.auth.id,
|
||||
{'task_id': instance.id})
|
||||
else:
|
||||
# reject the task
|
||||
@ -429,7 +436,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, None, junior_details.auth.id,
|
||||
send_notification_to_junior.delay(TASK_REJECTED, instance.guardian.user.id, junior_details.auth.id,
|
||||
{'task_id': instance.id})
|
||||
instance.save()
|
||||
junior_data.save()
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
""" Urls files"""
|
||||
"""Django import"""
|
||||
from django.urls import path, include
|
||||
from .views import (SignupViewset, UpdateGuardianProfile, AllTaskListAPIView, CreateTaskAPIView, TaskListAPIView,
|
||||
from .views import (SignupViewset, UpdateGuardianProfile, CreateTaskAPIView, TaskListAPIView,
|
||||
SearchTaskListAPIView, TopJuniorListAPIView, ApproveJuniorAPIView, ApproveTaskAPIView,
|
||||
GuardianListAPIView)
|
||||
"""Third party import"""
|
||||
@ -25,8 +25,6 @@ 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"""
|
||||
|
||||
@ -127,7 +127,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']), str(NUMBER['four'])]
|
||||
task_status = [str(NUMBER['one']), str(NUMBER['two'])]
|
||||
JuniorTask.objects.filter(due_date__lt=datetime.today().date(),
|
||||
task_status__in=task_status).update(task_status=str(NUMBER['six']))
|
||||
except ObjectDoesNotExist as e:
|
||||
|
||||
@ -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,13 +32,13 @@ 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
|
||||
from account.models import UserEmailOtp, UserNotification, UserDeviceDetails
|
||||
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, LEADERBOARD_RANKING
|
||||
from notifications.constants import REGISTRATION, TASK_ASSIGNED, ASSOCIATE_APPROVED, ASSOCIATE_REJECTED
|
||||
from notifications.utils import send_notification_to_junior
|
||||
|
||||
""" Define APIs """
|
||||
@ -57,12 +57,14 @@ 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():
|
||||
serializer.save()
|
||||
user = serializer.save()
|
||||
"""Generate otp"""
|
||||
otp = generate_otp()
|
||||
# expire otp after 1 day
|
||||
@ -71,19 +73,20 @@ class SignupViewset(viewsets.ModelViewSet):
|
||||
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(request.data['email'], otp)
|
||||
send_otp_email.delay(request.data['email'], otp)
|
||||
UserDeviceDetails.objects.create(user=user, device_id=device_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.ViewSet):
|
||||
"""
|
||||
Update guardian profile
|
||||
"""
|
||||
|
||||
class UpdateGuardianProfile(viewsets.ModelViewSet):
|
||||
"""Update guardian profile"""
|
||||
serializer_class = CreateGuardianSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
http_method_names = ('post',)
|
||||
|
||||
def create(self, request, *args, **kwargs):
|
||||
"""Create guardian profile"""
|
||||
@ -126,7 +129,11 @@ class AllTaskListAPIView(viewsets.ModelViewSet):
|
||||
|
||||
|
||||
class TaskListAPIView(viewsets.ModelViewSet):
|
||||
"""Update guardian profile"""
|
||||
"""Task list
|
||||
Params
|
||||
status
|
||||
search
|
||||
page"""
|
||||
serializer_class = TaskDetailsSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
filter_backends = (SearchFilter,)
|
||||
@ -163,12 +170,16 @@ 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 in junior_id.guardian_code:
|
||||
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):
|
||||
@ -200,10 +211,11 @@ class CreateTaskAPIView(viewsets.ModelViewSet):
|
||||
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
class SearchTaskListAPIView(viewsets.ModelViewSet):
|
||||
"""Update guardian profile"""
|
||||
"""Filter task"""
|
||||
serializer_class = TaskDetailsSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
pagination_class = PageNumberPagination
|
||||
http_method_names = ('get',)
|
||||
|
||||
def get_queryset(self):
|
||||
"""Get the queryset for the view"""
|
||||
@ -214,7 +226,7 @@ class SearchTaskListAPIView(viewsets.ModelViewSet):
|
||||
return junior_queryset
|
||||
|
||||
def list(self, request, *args, **kwargs):
|
||||
"""Create guardian profile"""
|
||||
"""Filter task"""
|
||||
try:
|
||||
queryset = self.get_queryset()
|
||||
paginator = self.pagination_class()
|
||||
@ -228,10 +240,12 @@ class SearchTaskListAPIView(viewsets.ModelViewSet):
|
||||
|
||||
|
||||
class TopJuniorListAPIView(viewsets.ModelViewSet):
|
||||
"""Top juniors list"""
|
||||
"""Top juniors list
|
||||
No Params"""
|
||||
queryset = JuniorPoints.objects.all()
|
||||
serializer_class = TopJuniorSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
http_method_names = ('get',)
|
||||
|
||||
def get_serializer_context(self):
|
||||
# context list
|
||||
@ -246,7 +260,6 @@ 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_to_junior.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)
|
||||
@ -254,14 +267,17 @@ class TopJuniorListAPIView(viewsets.ModelViewSet):
|
||||
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
|
||||
class ApproveJuniorAPIView(viewsets.ViewSet):
|
||||
class ApproveJuniorAPIView(viewsets.ModelViewSet):
|
||||
"""approve junior by guardian"""
|
||||
serializer_class = ApproveJuniorSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
http_method_names = ('post',)
|
||||
|
||||
def create(self, request, *args, **kwargs):
|
||||
""" junior list"""
|
||||
""" Use below param
|
||||
{"junior_id":"75",
|
||||
"action":"1"}
|
||||
"""
|
||||
try:
|
||||
guardian = Guardian.objects.filter(user__email=self.request.user).last()
|
||||
# fetch junior query
|
||||
@ -272,28 +288,37 @@ class ApproveJuniorAPIView(viewsets.ViewSet):
|
||||
if request.data['action'] == '1':
|
||||
# use ApproveJuniorSerializer serializer
|
||||
serializer = ApproveJuniorSerializer(context={"guardian_code": guardian.guardian_code,
|
||||
"junior": junior_queryset, "action": request.data['action']},
|
||||
"junior": junior_queryset,
|
||||
"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)
|
||||
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.ViewSet):
|
||||
class ApproveTaskAPIView(viewsets.ModelViewSet):
|
||||
"""approve junior by guardian"""
|
||||
serializer_class = ApproveTaskSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
http_method_names = ('post',)
|
||||
def create(self, request, *args, **kwargs):
|
||||
""" junior list"""
|
||||
""" Params
|
||||
{"junior_id":"82",
|
||||
"task_id":"43",
|
||||
"action":"1"}
|
||||
action 1 for approve
|
||||
2 for reject
|
||||
"""
|
||||
# action 1 is use for approve and 2 for reject
|
||||
try:
|
||||
guardian = Guardian.objects.filter(user__email=self.request.user).last()
|
||||
@ -321,7 +346,7 @@ class ApproveTaskAPIView(viewsets.ViewSet):
|
||||
serializer.save()
|
||||
return custom_response(SUCCESS_CODE['3026'], response_status=status.HTTP_200_OK)
|
||||
else:
|
||||
return custom_response(ERROR_CODE['2038'], response_status=status.HTTP_400_BAD_REQUEST)
|
||||
return custom_error_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)
|
||||
|
||||
@ -333,7 +358,8 @@ class GuardianListAPIView(viewsets.ModelViewSet):
|
||||
http_method_names = ('get',)
|
||||
|
||||
def list(self, request, *args, **kwargs):
|
||||
""" junior list"""
|
||||
""" Guardian list of assosicated junior
|
||||
No Params"""
|
||||
try:
|
||||
guardian_data = JuniorGuardianRelationship.objects.filter(junior__auth__email=self.request.user)
|
||||
# fetch junior object
|
||||
|
||||
@ -22,9 +22,9 @@ 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 (INVITED_GUARDIAN, APPROVED_JUNIOR, SKIPPED_PROFILE_SETUP, TASK_ACTION,
|
||||
TASK_SUBMITTED)
|
||||
|
||||
from notifications.constants import (ASSOCIATE_REQUEST, JUNIOR_ADDED, TASK_ACTION,
|
||||
)
|
||||
from web_admin.models import ArticleCard
|
||||
|
||||
class ListCharField(serializers.ListField):
|
||||
"""Serializer for Array field"""
|
||||
@ -88,17 +88,23 @@ 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"""
|
||||
junior.guardian_code = validated_data.get('guardian_code', junior.guardian_code)
|
||||
"""condition for guardian code"""
|
||||
# Update guardian code"""
|
||||
# condition for guardian code
|
||||
if guardian_code:
|
||||
junior.guardian_code = 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"})
|
||||
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(user.email, user.first_name)
|
||||
send_notification_to_guardian.delay(APPROVED_JUNIOR, junior.auth.id, guardian_data.user.id, {})
|
||||
junior_approval_mail.delay(user.email, user.first_name)
|
||||
send_notification_to_guardian.delay(ASSOCIATE_REQUEST, junior.auth.id, 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)
|
||||
@ -292,7 +298,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.create(guardian=guardian_data, junior=junior_data,
|
||||
JuniorGuardianRelationship.objects.get_or_create(guardian=guardian_data, junior=junior_data,
|
||||
relationship=relationship)
|
||||
total_junior = Junior.objects.all().count()
|
||||
JuniorPoints.objects.create(junior=junior_data, position=total_junior)
|
||||
@ -304,9 +310,9 @@ class AddJuniorSerializer(serializers.ModelSerializer):
|
||||
# add push notification
|
||||
UserNotification.objects.get_or_create(user=user_data)
|
||||
"""Notification email"""
|
||||
junior_notification_email(email, full_name, email, password)
|
||||
junior_notification_email.delay(email, full_name, email, password)
|
||||
# push notification
|
||||
send_notification_to_junior.delay(SKIPPED_PROFILE_SETUP, None, junior_data.auth.id, {})
|
||||
send_notification_to_junior.delay(JUNIOR_ADDED, None, junior_data.auth.id, {})
|
||||
return junior_data
|
||||
|
||||
|
||||
@ -319,9 +325,11 @@ 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 = '{}'
|
||||
instance.guardian_code_status = str(NUMBER['one'])
|
||||
instance.guardian_code.remove(guardian_code)
|
||||
if not instance.guardian_code:
|
||||
instance.guardian_code_status = str(NUMBER['one'])
|
||||
instance.save()
|
||||
return instance
|
||||
|
||||
@ -338,8 +346,6 @@ class CompleteTaskSerializer(serializers.ModelSerializer):
|
||||
instance.task_status = str(NUMBER['four'])
|
||||
instance.is_approved = False
|
||||
instance.save()
|
||||
send_notification_to_junior.delay(TASK_SUBMITTED, instance.guardian.user.id,
|
||||
instance.junior.auth.id, {'task_id': instance.id})
|
||||
send_notification_to_guardian.delay(TASK_ACTION, instance.junior.auth.id,
|
||||
instance.guardian.user.id, {'task_id': instance.id})
|
||||
return instance
|
||||
@ -445,14 +451,13 @@ 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.create(guardian=guardian_data, junior=junior_data,
|
||||
JuniorGuardianRelationship.objects.get_or_create(guardian=guardian_data, junior=junior_data,
|
||||
relationship=relationship)
|
||||
|
||||
"""Notification email"""
|
||||
junior_notification_email(email, full_name, email, password)
|
||||
junior_approval_mail(email, full_name)
|
||||
send_notification_to_junior.delay(INVITED_GUARDIAN, guardian_data.user.id, junior_data.auth.id, {})
|
||||
send_notification_to_guardian.delay(APPROVED_JUNIOR, junior_data.auth.id, guardian_data.user.id, {})
|
||||
junior_approval_mail.delay(email, full_name)
|
||||
send_notification_to_guardian.delay(ASSOCIATE_REQUEST, junior_data.auth.id, guardian_data.user.id, {})
|
||||
return guardian_data
|
||||
|
||||
class StartTaskSerializer(serializers.ModelSerializer):
|
||||
@ -496,8 +501,6 @@ class ReAssignTaskSerializer(serializers.ModelSerializer):
|
||||
instance.save()
|
||||
return instance
|
||||
|
||||
|
||||
|
||||
class RemoveGuardianCodeSerializer(serializers.ModelSerializer):
|
||||
"""User task Serializer"""
|
||||
class Meta(object):
|
||||
@ -505,16 +508,33 @@ class RemoveGuardianCodeSerializer(serializers.ModelSerializer):
|
||||
model = Junior
|
||||
fields = ('id', )
|
||||
def update(self, instance, validated_data):
|
||||
instance.guardian_code = None
|
||||
instance.guardian_code_status = str(NUMBER['one'])
|
||||
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.save()
|
||||
return instance
|
||||
|
||||
class FAQSerializer(serializers.ModelSerializer):
|
||||
# FAQ Serializer
|
||||
"""FAQ Serializer"""
|
||||
|
||||
class Meta(object):
|
||||
# meta info
|
||||
"""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')
|
||||
|
||||
|
||||
@ -62,5 +62,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())
|
||||
]
|
||||
|
||||
@ -14,6 +14,8 @@ 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
|
||||
@ -32,7 +34,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
|
||||
|
||||
170
junior/views.py
170
junior/views.py
@ -13,7 +13,9 @@ 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,
|
||||
@ -36,7 +38,7 @@ from junior.models import (Junior, JuniorPoints, JuniorGuardianRelationship, Jun
|
||||
from .serializers import (CreateJuniorSerializer, JuniorDetailListSerializer, AddJuniorSerializer,
|
||||
RemoveJuniorSerializer, CompleteTaskSerializer, JuniorPointsSerializer,
|
||||
AddGuardianSerializer, StartTaskSerializer, ReAssignTaskSerializer,
|
||||
RemoveGuardianCodeSerializer, FAQSerializer)
|
||||
RemoveGuardianCodeSerializer, FAQSerializer, CreateArticleCardSerializer)
|
||||
from guardian.models import Guardian, JuniorTask
|
||||
from guardian.serializers import TaskDetailsSerializer, TaskDetailsjuniorSerializer
|
||||
from base.messages import ERROR_CODE, SUCCESS_CODE
|
||||
@ -65,13 +67,14 @@ from web_admin.serializers.article_serializer import (ArticleSerializer, Article
|
||||
# Start task
|
||||
# by junior API
|
||||
# Create your views here.
|
||||
class UpdateJuniorProfile(viewsets.ViewSet):
|
||||
class UpdateJuniorProfile(viewsets.ModelViewSet):
|
||||
"""Update junior profile"""
|
||||
serializer_class = CreateJuniorSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
http_method_names = ('post',)
|
||||
|
||||
def create(self, request, *args, **kwargs):
|
||||
"""Use CreateJuniorSerializer"""
|
||||
"""Create Junior Profile"""
|
||||
try:
|
||||
request_data = request.data
|
||||
image = request.data.get('image')
|
||||
@ -96,14 +99,19 @@ class UpdateJuniorProfile(viewsets.ViewSet):
|
||||
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:
|
||||
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
|
||||
error_detail = e.detail.get('error', None)
|
||||
return custom_error_response(error_detail, response_status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
class ValidateGuardianCode(viewsets.ViewSet):
|
||||
class ValidateGuardianCode(viewsets.ModelViewSet):
|
||||
"""Check guardian code exist or not"""
|
||||
permission_classes = [IsAuthenticated]
|
||||
http_method_names = ('get',)
|
||||
|
||||
def list(self, request, *args, **kwargs):
|
||||
"""check guardian code"""
|
||||
"""check guardian code
|
||||
Params
|
||||
"guardian_code"
|
||||
"""
|
||||
try:
|
||||
guardian_code = self.request.GET.get('guardian_code').split(',')
|
||||
for code in guardian_code:
|
||||
@ -155,7 +163,14 @@ class AddJuniorAPIView(viewsets.ModelViewSet):
|
||||
http_method_names = ('post',)
|
||||
|
||||
def create(self, request, *args, **kwargs):
|
||||
""" junior list"""
|
||||
""" add junior
|
||||
{ "gender":"1",
|
||||
"first_name":"abc",
|
||||
"last_name":"xyz",
|
||||
"dob":"2023-12-12",
|
||||
"relationship":"2",
|
||||
"email":"abc@yopmail.com"
|
||||
}"""
|
||||
try:
|
||||
info_data = {'user': request.user, 'relationship': str(request.data['relationship']),
|
||||
'email': request.data['email'], 'first_name': request.data['first_name'],
|
||||
@ -176,6 +191,8 @@ class AddJuniorAPIView(viewsets.ModelViewSet):
|
||||
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)
|
||||
return custom_response(SUCCESS_CODE['3021'], response_status=status.HTTP_200_OK)
|
||||
# use AddJuniorSerializer serializer
|
||||
serializer = AddJuniorSerializer(data=request.data, context=info_data)
|
||||
@ -190,14 +207,18 @@ class AddJuniorAPIView(viewsets.ModelViewSet):
|
||||
def associate_guardian(self, user):
|
||||
junior = Junior.objects.filter(auth__email=self.request.data['email']).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 guardian.guardian_code in junior.guardian_code:
|
||||
if junior.guardian_code and (guardian.guardian_code in junior.guardian_code):
|
||||
return False
|
||||
if type(junior.guardian_code) is list:
|
||||
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:
|
||||
junior.guardian_code = [guardian.guardian_code]
|
||||
return "Max"
|
||||
junior.guardian_code_status = str(NUMBER['two'])
|
||||
junior.save()
|
||||
JuniorGuardianRelationship.objects.get_or_create(guardian=guardian, junior=junior,
|
||||
@ -206,7 +227,7 @@ class AddJuniorAPIView(viewsets.ModelViewSet):
|
||||
|
||||
|
||||
class InvitedJuniorAPIView(viewsets.ModelViewSet):
|
||||
"""Junior list of assosicated guardian"""
|
||||
"""Invited Junior list of assosicated guardian"""
|
||||
|
||||
serializer_class = JuniorDetailListSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
@ -220,7 +241,8 @@ class InvitedJuniorAPIView(viewsets.ModelViewSet):
|
||||
is_invited=True)
|
||||
return junior_queryset
|
||||
def list(self, request, *args, **kwargs):
|
||||
""" junior list"""
|
||||
""" Invited Junior list of assosicated guardian
|
||||
No Params"""
|
||||
try:
|
||||
queryset = self.get_queryset()
|
||||
paginator = self.pagination_class()
|
||||
@ -234,12 +256,25 @@ class InvitedJuniorAPIView(viewsets.ModelViewSet):
|
||||
|
||||
|
||||
class FilterJuniorAPIView(viewsets.ModelViewSet):
|
||||
"""Update guardian profile"""
|
||||
"""filter junior 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')
|
||||
@ -250,7 +285,7 @@ class FilterJuniorAPIView(viewsets.ModelViewSet):
|
||||
return queryset
|
||||
|
||||
def list(self, request, *args, **kwargs):
|
||||
"""Create guardian profile"""
|
||||
"""Filter junior"""
|
||||
try:
|
||||
queryset = self.get_queryset()
|
||||
paginator = self.pagination_class()
|
||||
@ -264,7 +299,9 @@ class FilterJuniorAPIView(viewsets.ModelViewSet):
|
||||
|
||||
|
||||
class RemoveJuniorAPIView(views.APIView):
|
||||
"""Remove junior API"""
|
||||
"""Remove junior API
|
||||
Params
|
||||
id=37"""
|
||||
serializer_class = RemoveJuniorSerializer
|
||||
model = Junior
|
||||
permission_classes = [IsAuthenticated]
|
||||
@ -278,7 +315,8 @@ class RemoveJuniorAPIView(views.APIView):
|
||||
guardian_code__icontains=str(guardian.guardian_code)).last()
|
||||
if junior_queryset:
|
||||
# use RemoveJuniorSerializer serializer
|
||||
serializer = RemoveJuniorSerializer(junior_queryset, data=request.data, partial=True)
|
||||
serializer = RemoveJuniorSerializer(junior_queryset, context={"guardian_code":guardian.guardian_code},
|
||||
data=request.data, partial=True)
|
||||
if serializer.is_valid():
|
||||
# save serializer
|
||||
serializer.save()
|
||||
@ -292,14 +330,17 @@ class RemoveJuniorAPIView(views.APIView):
|
||||
|
||||
|
||||
class JuniorTaskListAPIView(viewsets.ModelViewSet):
|
||||
"""Update guardian profile"""
|
||||
"""Junior task list"""
|
||||
serializer_class = TaskDetailsjuniorSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
pagination_class = PageNumberPagination
|
||||
http_method_names = ('get',)
|
||||
|
||||
def list(self, request, *args, **kwargs):
|
||||
"""Create guardian profile"""
|
||||
"""Junior task list
|
||||
status=0
|
||||
search='title'
|
||||
page=1"""
|
||||
try:
|
||||
status_value = self.request.GET.get('status')
|
||||
search = self.request.GET.get('search')
|
||||
@ -329,7 +370,9 @@ class JuniorTaskListAPIView(viewsets.ModelViewSet):
|
||||
|
||||
|
||||
class CompleteJuniorTaskAPIView(views.APIView):
|
||||
"""Update junior task API"""
|
||||
"""Payload
|
||||
task_id
|
||||
image"""
|
||||
serializer_class = CompleteTaskSerializer
|
||||
model = JuniorTask
|
||||
permission_classes = [IsAuthenticated]
|
||||
@ -374,7 +417,8 @@ class JuniorPointsListAPIView(viewsets.ModelViewSet):
|
||||
http_method_names = ('get',)
|
||||
|
||||
def list(self, request, *args, **kwargs):
|
||||
"""profile view"""
|
||||
"""Junior Points
|
||||
No Params"""
|
||||
try:
|
||||
update_positions_based_on_points()
|
||||
queryset = JuniorPoints.objects.filter(junior__auth__email=self.request.user).last()
|
||||
@ -385,7 +429,7 @@ class JuniorPointsListAPIView(viewsets.ModelViewSet):
|
||||
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
|
||||
class ValidateReferralCode(viewsets.ViewSet):
|
||||
class ValidateReferralCode(viewsets.ModelViewSet):
|
||||
"""Check guardian code exist or not"""
|
||||
permission_classes = [IsAuthenticated]
|
||||
http_method_names = ('get',)
|
||||
@ -420,7 +464,13 @@ class InviteGuardianAPIView(viewsets.ModelViewSet):
|
||||
permission_classes = [IsAuthenticated]
|
||||
http_method_names = ('post',)
|
||||
def create(self, request, *args, **kwargs):
|
||||
""" junior list"""
|
||||
""" add guardian
|
||||
{
|
||||
"first_name":"abc",
|
||||
"last_name":"xyz",
|
||||
"email":"abc@yopmail.com",
|
||||
"relationship":2
|
||||
}"""
|
||||
try:
|
||||
if request.data['email'] == '':
|
||||
return custom_error_response(ERROR_CODE['2062'], response_status=status.HTTP_400_BAD_REQUEST)
|
||||
@ -438,7 +488,11 @@ class InviteGuardianAPIView(viewsets.ModelViewSet):
|
||||
|
||||
|
||||
class StartTaskAPIView(views.APIView):
|
||||
"""Update junior task API"""
|
||||
"""Update junior task API
|
||||
Paylod
|
||||
{
|
||||
"task_id":28
|
||||
}"""
|
||||
serializer_class = StartTaskSerializer
|
||||
model = JuniorTask
|
||||
permission_classes = [IsAuthenticated]
|
||||
@ -462,7 +516,13 @@ 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"""
|
||||
"""Update junior task API
|
||||
Payload
|
||||
{
|
||||
"task_id":34,
|
||||
"due_date":"2023-08-22"
|
||||
}
|
||||
"""
|
||||
serializer_class = ReAssignTaskSerializer
|
||||
model = JuniorTask
|
||||
permission_classes = [IsAuthenticated]
|
||||
@ -491,7 +551,10 @@ class StartArticleAPIView(viewsets.ModelViewSet):
|
||||
http_method_names = ('post',)
|
||||
|
||||
def create(self, request, *args, **kwargs):
|
||||
""" junior list"""
|
||||
""" Payload
|
||||
{
|
||||
"article_id":"2"
|
||||
}"""
|
||||
try:
|
||||
junior_instance = Junior.objects.filter(auth=self.request.user).last()
|
||||
article_id = request.data.get('article_id')
|
||||
@ -513,7 +576,7 @@ class StartArticleAPIView(viewsets.ModelViewSet):
|
||||
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
class StartAssessmentAPIView(viewsets.ModelViewSet):
|
||||
"""Junior Points viewset"""
|
||||
"""Question answer viewset"""
|
||||
serializer_class = StartAssessmentSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
http_method_names = ('get',)
|
||||
@ -526,7 +589,9 @@ class StartAssessmentAPIView(viewsets.ModelViewSet):
|
||||
).order_by('-created_at')
|
||||
return article
|
||||
def list(self, request, *args, **kwargs):
|
||||
"""profile view"""
|
||||
"""Params
|
||||
article_id
|
||||
"""
|
||||
|
||||
try:
|
||||
queryset = self.get_queryset()
|
||||
@ -538,7 +603,9 @@ class StartAssessmentAPIView(viewsets.ModelViewSet):
|
||||
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
class CheckAnswerAPIView(viewsets.ModelViewSet):
|
||||
"""Junior Points viewset"""
|
||||
"""Params
|
||||
question_id=1
|
||||
answer_id=1"""
|
||||
permission_classes = [IsAuthenticated]
|
||||
http_method_names = ('get',)
|
||||
|
||||
@ -547,13 +614,16 @@ class CheckAnswerAPIView(viewsets.ModelViewSet):
|
||||
article = ArticleSurvey.objects.filter(id=question_id).last()
|
||||
return article
|
||||
def list(self, request, *args, **kwargs):
|
||||
"""profile view"""
|
||||
""" Params
|
||||
question_id=1
|
||||
answer_id=1
|
||||
"""
|
||||
|
||||
try:
|
||||
answer_id = self.request.GET.get('answer_id')
|
||||
current_page = self.request.GET.get('current_page')
|
||||
queryset = self.get_queryset()
|
||||
submit_ans = SurveyOption.objects.filter(id=answer_id, is_answer=True).last()
|
||||
submit_ans = SurveyOption.objects.filter(id=answer_id).last()
|
||||
junior_article_points = JuniorArticlePoints.objects.filter(junior__auth=self.request.user,
|
||||
question=queryset)
|
||||
if submit_ans:
|
||||
@ -571,7 +641,9 @@ class CheckAnswerAPIView(viewsets.ModelViewSet):
|
||||
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
class CompleteArticleAPIView(views.APIView):
|
||||
"""Remove junior API"""
|
||||
"""Params
|
||||
article_id
|
||||
"""
|
||||
permission_classes = [IsAuthenticated]
|
||||
http_method_names = ('put', 'get',)
|
||||
def put(self, request, format=None):
|
||||
@ -585,7 +657,8 @@ class CompleteArticleAPIView(views.APIView):
|
||||
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
""" junior list"""
|
||||
""" Params
|
||||
article_id=1"""
|
||||
try:
|
||||
article_id = self.request.GET.get('article_id')
|
||||
total_earn_points = JuniorArticlePoints.objects.filter(junior__auth=request.user,
|
||||
@ -599,12 +672,16 @@ class CompleteArticleAPIView(views.APIView):
|
||||
|
||||
|
||||
class ReadArticleCardAPIView(views.APIView):
|
||||
"""Remove junior API"""
|
||||
"""Read article card API"""
|
||||
permission_classes = [IsAuthenticated]
|
||||
http_method_names = ('put',)
|
||||
|
||||
def put(self, request, *args, **kwargs):
|
||||
""" junior list"""
|
||||
""" Read article card
|
||||
Payload
|
||||
{"article_id":"1",
|
||||
"article_card":"2",
|
||||
"current_page":"2"}"""
|
||||
try:
|
||||
junior_instance = Junior.objects.filter(auth=self.request.user).last()
|
||||
article = self.request.data.get('article_id')
|
||||
@ -622,11 +699,14 @@ 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):
|
||||
""" junior list"""
|
||||
""" create article card
|
||||
Params
|
||||
{"article_id":1}"""
|
||||
try:
|
||||
junior_instance = Junior.objects.filter(auth=self.request.user).last()
|
||||
article_id = request.data.get('article_id')
|
||||
@ -645,16 +725,22 @@ class CreateArticleCardAPIView(viewsets.ModelViewSet):
|
||||
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
class RemoveGuardianCodeAPIView(views.APIView):
|
||||
"""Update junior task API"""
|
||||
"""Remove guardian code request API
|
||||
Payload
|
||||
{"guardian_code"
|
||||
:"GRD037"
|
||||
}"""
|
||||
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, data=request.data, partial=True)
|
||||
serializer = RemoveGuardianCodeSerializer(junior_queryset, context = {"guardian_code":guardian_code},
|
||||
data=request.data, partial=True)
|
||||
if serializer.is_valid():
|
||||
# save serializer
|
||||
serializer.save()
|
||||
@ -664,7 +750,8 @@ class RemoveGuardianCodeAPIView(views.APIView):
|
||||
# task in another state
|
||||
return custom_error_response(ERROR_CODE['2047'], response_status=status.HTTP_400_BAD_REQUEST)
|
||||
except Exception as e:
|
||||
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
|
||||
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,
|
||||
@ -682,7 +769,7 @@ class FAQViewSet(GenericViewSet, mixins.CreateModelMixin,
|
||||
"""
|
||||
faq create api method
|
||||
:param request:
|
||||
:param args:
|
||||
:param args: question, description
|
||||
:param kwargs:
|
||||
:return: success message
|
||||
"""
|
||||
@ -708,6 +795,3 @@ class FAQViewSet(GenericViewSet, mixins.CreateModelMixin,
|
||||
serializer = self.serializer_class(paginated_queryset, many=True)
|
||||
return custom_response(None, data=serializer.data, response_status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -10,3 +10,4 @@ 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']
|
||||
|
||||
@ -1,19 +1,20 @@
|
||||
"""
|
||||
notification constants file
|
||||
"""
|
||||
from base.constants import NUMBER
|
||||
REGISTRATION = NUMBER['one']
|
||||
TASK_ASSIGNED = 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']
|
||||
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
|
||||
|
||||
TEST_NOTIFICATION = 99
|
||||
|
||||
NOTIFICATION_DICT = {
|
||||
@ -21,49 +22,56 @@ NOTIFICATION_DICT = {
|
||||
"title": "Successfully registered!",
|
||||
"body": "You have registered successfully. Now login and complete your profile."
|
||||
},
|
||||
TASK_ASSIGNED: {
|
||||
"title": "New task assigned !!",
|
||||
"body": "{from_user} has assigned you a new task."
|
||||
},
|
||||
INVITED_GUARDIAN: {
|
||||
"title": "Invite guardian",
|
||||
"body": "Invite guardian successfully"
|
||||
},
|
||||
APPROVED_JUNIOR: {
|
||||
"title": "Approve junior !",
|
||||
ASSOCIATE_REQUEST: {
|
||||
"title": "Associate request!",
|
||||
"body": "You have request from {from_user} to associate with you."
|
||||
},
|
||||
|
||||
ASSOCIATE_REJECTED: {
|
||||
"title": "Associate request rejected!",
|
||||
"body": "Your request to associate has been rejected by {from_user}."
|
||||
},
|
||||
|
||||
ASSOCIATE_APPROVED: {
|
||||
"title": "Associate request approved!",
|
||||
"body": "Your request to associate has been approved by {from_user}."
|
||||
},
|
||||
# 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."
|
||||
},
|
||||
TASK_POINTS: {
|
||||
"title": "Earn Task points!",
|
||||
"body": "You earn 5 points for task."
|
||||
# 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_REJECTED: {
|
||||
"title": "Task rejected!",
|
||||
"body": "Your task has been rejected."
|
||||
},
|
||||
SKIPPED_PROFILE_SETUP: {
|
||||
"title": "Skipped profile setup!",
|
||||
"body": "Your guardian {from_user} has setup your profile."
|
||||
},
|
||||
TASK_SUBMITTED: {
|
||||
"title": "Task submitted!",
|
||||
"body": "Your task has been submitted successfully."
|
||||
# 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 approval."
|
||||
"body": "You have request from {from_user} for task completion."
|
||||
},
|
||||
LEADERBOARD_RANKING: {
|
||||
"title": "Leader board rank!",
|
||||
"body": "Your rank is ."
|
||||
# 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}."
|
||||
},
|
||||
# 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."
|
||||
},
|
||||
# Juniors will receive notification as soon as their custodians remove them from account
|
||||
REMOVE_JUNIOR: {
|
||||
"title": "Disassociate by guardian!",
|
||||
"body": "Your guardian disassociate you ."
|
||||
"body": "Your guardian has disassociated you."
|
||||
},
|
||||
TEST_NOTIFICATION: {
|
||||
"title": "Test Notification",
|
||||
|
||||
@ -40,6 +40,8 @@ class NotificationListSerializer(serializers.ModelSerializer):
|
||||
|
||||
class ReadNotificationSerializer(serializers.ModelSerializer):
|
||||
"""User task Serializer"""
|
||||
id = serializers.ListSerializer(child=serializers.IntegerField())
|
||||
|
||||
class Meta(object):
|
||||
"""Meta class"""
|
||||
model = Notification
|
||||
|
||||
@ -6,7 +6,7 @@ from django.urls import path, include
|
||||
from rest_framework import routers
|
||||
|
||||
# local imports
|
||||
from notifications.views import NotificationViewSet, ReadNotification
|
||||
from notifications.views import NotificationViewSet
|
||||
|
||||
# initiate router
|
||||
router = routers.SimpleRouter()
|
||||
@ -15,5 +15,4 @@ router.register('notifications', NotificationViewSet, basename='notifications')
|
||||
|
||||
urlpatterns = [
|
||||
path('api/v1/', include(router.urls)),
|
||||
path('api/v1/read-notification/', ReadNotification.as_view()),
|
||||
]
|
||||
|
||||
@ -97,6 +97,13 @@ def send_push(user, 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()
|
||||
@ -109,6 +116,13 @@ def send_notification_to_guardian(notification_type, from_user_id, to_user_id, e
|
||||
|
||||
@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()
|
||||
|
||||
@ -30,15 +30,8 @@ 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):
|
||||
"""
|
||||
@ -62,32 +55,11 @@ class NotificationViewSet(viewsets.GenericViewSet):
|
||||
{'task_id': None})
|
||||
return custom_response(SUCCESS_CODE["3000"])
|
||||
|
||||
@action(methods=['get'], detail=False, url_path='list', url_name='list',
|
||||
serializer_class=NotificationListSerializer)
|
||||
def notification_list(self, request):
|
||||
@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):
|
||||
"""
|
||||
notification list
|
||||
"""
|
||||
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)
|
||||
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)
|
||||
|
||||
@ -219,8 +219,7 @@ class ArticleListSerializer(serializers.ModelSerializer):
|
||||
"""
|
||||
serializer for article API
|
||||
"""
|
||||
article_cards = ArticleCardSerializer(many=True)
|
||||
article_survey = ArticleSurveySerializer(many=True)
|
||||
image = serializers.SerializerMethodField('get_image')
|
||||
total_points = serializers.SerializerMethodField('get_total_points')
|
||||
is_completed = serializers.SerializerMethodField('get_is_completed')
|
||||
|
||||
@ -229,12 +228,16 @@ class ArticleListSerializer(serializers.ModelSerializer):
|
||||
meta class
|
||||
"""
|
||||
model = Article
|
||||
fields = ('id', 'title', 'description', 'article_cards', 'article_survey', 'total_points', 'is_completed')
|
||||
fields = ('id', 'title', 'description','image', '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"""
|
||||
total_question = ArticleSurvey.objects.filter(article=obj).count()
|
||||
return total_question * NUMBER['five']
|
||||
return obj.article_survey.all().count() * NUMBER['five']
|
||||
|
||||
def get_is_completed(self, obj):
|
||||
"""complete all question"""
|
||||
@ -268,14 +271,14 @@ class ArticleQuestionSerializer(serializers.ModelSerializer):
|
||||
ans_obj = SurveyOption.objects.filter(survey=obj, is_answer=True).last()
|
||||
if ans_obj:
|
||||
return ans_obj.id
|
||||
return str("None")
|
||||
return None
|
||||
|
||||
def get_attempted_answer(self, obj):
|
||||
"""attempt question or not"""
|
||||
context_data = self.context.get('user')
|
||||
junior_article_obj = JuniorArticlePoints.objects.filter(junior__auth=context_data,
|
||||
question=obj, is_answer_correct=True).last()
|
||||
if junior_article_obj:
|
||||
question=obj).last()
|
||||
if junior_article_obj and junior_article_obj.submitted_answer:
|
||||
return junior_article_obj.submitted_answer.id
|
||||
return None
|
||||
|
||||
|
||||
@ -229,10 +229,7 @@ class ArticleListViewSet(GenericViewSet, mixins.ListModelMixin):
|
||||
http_method_names = ['get',]
|
||||
|
||||
def get_queryset(self):
|
||||
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)
|
||||
queryset = self.queryset.objects.filter(is_deleted=False, is_published=True).order_by('-created_at')
|
||||
return queryset
|
||||
|
||||
def list(self, request, *args, **kwargs):
|
||||
@ -248,7 +245,9 @@ class ArticleListViewSet(GenericViewSet, mixins.ListModelMixin):
|
||||
return custom_response(None, data=serializer.data)
|
||||
|
||||
class ArticleCardListViewSet(viewsets.ModelViewSet):
|
||||
"""Junior Points viewset"""
|
||||
"""Article card list
|
||||
use below query param
|
||||
article_id"""
|
||||
serializer_class = ArticleCardlistSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
http_method_names = ('get',)
|
||||
@ -257,7 +256,9 @@ class ArticleCardListViewSet(viewsets.ModelViewSet):
|
||||
"""get queryset"""
|
||||
return ArticleCard.objects.filter(article=self.request.GET.get('article_id'))
|
||||
def list(self, request, *args, **kwargs):
|
||||
"""profile view"""
|
||||
"""Article card list
|
||||
use below query param
|
||||
article_id"""
|
||||
|
||||
try:
|
||||
queryset = self.get_queryset()
|
||||
|
||||
Reference in New Issue
Block a user