Compare commits

..

89 Commits

Author SHA1 Message Date
3072bd5cdb added optional name as user 2023-08-24 14:54:46 +05:30
930b58cf05 added optional name as user 2023-08-24 14:51:24 +05:30
cd3b385756 added optional user as name 2023-08-24 13:33:34 +05:30
f541608656 changed notification method, added celery task to notify expiring task 2023-08-24 12:10:18 +05:30
5b9f7b1828 Merge pull request #254 from KiwiTechLLC/sprint5
google login with user type and is published article only display
2023-08-23 17:47:12 +05:30
89dda61bff google login with user type and is published article only display 2023-08-23 17:46:20 +05:30
31f071a463 Merge pull request #253 from KiwiTechLLC/sprint5
google login with user type and is published article only display
2023-08-23 17:26:17 +05:30
20644a6293 google login with user type and is published article only display 2023-08-23 17:15:54 +05:30
a8b01d4c3a Merge pull request #252 from KiwiTechLLC/ZBKBCK-47
mark ad read api modified
2023-08-23 13:01:58 +05:30
56e1484b87 mark ad read api modified 2023-08-23 12:56:57 +05:30
557a7d7a5c Merge pull request #250 from KiwiTechLLC/sprint5
response 308 in force update
2023-08-23 12:38:21 +05:30
4e0c6a91f4 response 308 in force update 2023-08-23 12:29:53 +05:30
f931e20334 Merge pull request #249 from KiwiTechLLC/sprint5
changes in profile API
2023-08-23 11:54:48 +05:30
8d159ac3a4 changes in profile API 2023-08-23 11:45:38 +05:30
95ce57ec7d Merge pull request #248 from KiwiTechLLC/sprint5
force update not affect admin's api
2023-08-23 11:20:22 +05:30
7068551050 force update not affect admin's api 2023-08-23 11:16:46 +05:30
c23d65f67c Merge pull request #245 from KiwiTechLLC/sprint5
force update
2023-08-22 19:35:26 +05:30
73f05dc843 Merge pull request #247 from KiwiTechLLC/ZBKBCK-47
added notitifcation for association rejected, approved, added mark as…
2023-08-22 19:28:44 +05:30
290089b9ef added notitifcation for association rejected, approved, added mark as read api 2023-08-22 19:26:30 +05:30
5f3a9c35fa junior guardiuan code 2023-08-22 19:14:57 +05:30
b92115168d Merge pull request #246 from KiwiTechLLC/ZBKBCK-47
added notitifcation for association rejected, approved, added mark as…
2023-08-22 19:13:30 +05:30
19acef10ef added notitifcation for association rejected, approved, added mark as read api 2023-08-22 19:03:39 +05:30
05fd76a50b force update 2023-08-22 18:29:22 +05:30
60e6d96379 Merge pull request #243 from KiwiTechLLC/ZBKBCK-47
minor changes
2023-08-22 16:11:16 +05:30
fad39d399f minor changes 2023-08-22 16:04:58 +05:30
d573d56a35 minor changes 2023-08-22 16:01:08 +05:30
08a08960ee Merge pull request #241 from KiwiTechLLC/sprint5
force update and mail by celery task
2023-08-22 13:49:21 +05:30
f8e529600b force update and mail by celery task 2023-08-22 13:46:37 +05:30
9765c90b9b Merge pull request #240 from KiwiTechLLC/sprint5
swagger update
2023-08-22 11:31:20 +05:30
930c10b578 swagger update 2023-08-22 11:28:52 +05:30
8ca74e4b03 Merge pull request #239 from KiwiTechLLC/ZBKBCK-47
notification changes
2023-08-22 10:57:57 +05:30
95dad86b12 notification changes 2023-08-21 20:10:39 +05:30
dfff643c71 Merge pull request #237 from KiwiTechLLC/sprint5
Error response
2023-08-21 19:11:10 +05:30
214566ec8f Error response 2023-08-21 19:09:44 +05:30
210e1a39e9 Merge pull request #236 from KiwiTechLLC/sprint5
swagger update
2023-08-21 18:45:48 +05:30
e380f3f6ab swagger update 2023-08-21 18:44:18 +05:30
99a59162a2 swagger update 2023-08-21 18:12:03 +05:30
67a5f670f8 Merge pull request #234 from KiwiTechLLC/sprint5
Sprint5
2023-08-21 16:03:09 +05:30
82189d3953 signup 2023-08-21 16:00:39 +05:30
65ecd9a125 Merge branch 'dev' of github.com:KiwiTechLLC/ZODBank-Backend into sprint5 2023-08-21 15:59:47 +05:30
a7bce32993 signup 2023-08-21 15:59:20 +05:30
4495d8999c Merge pull request #233 from KiwiTechLLC/sprint5
swagger fixes
2023-08-21 15:15:31 +05:30
61e94c9469 Merge branch 'dev' into sprint5 2023-08-21 15:13:35 +05:30
1c3d4731c1 swagger fixes 2023-08-21 15:11:43 +05:30
46853011be Merge pull request #232 from KiwiTechLLC/ZBKADM-72-minor-changes
minor changes
2023-08-21 15:04:44 +05:30
2216411fd2 Merge branch 'dev' into ZBKADM-72-minor-changes 2023-08-21 14:33:36 +05:30
606c1fa6e6 minor changes in excel import api method 2023-08-21 14:28:06 +05:30
092cbfad3e Merge branch 'qa' into dev 2023-08-21 12:57:57 +05:30
249a469d89 Merge pull request #230 from KiwiTechLLC/sprint5
resolve bugs
2023-08-21 12:54:46 +05:30
d202774df1 resolve bugs 2023-08-21 12:39:05 +05:30
1adf0c2f70 resolve bugs 2023-08-21 12:24:01 +05:30
b193166914 Merge pull request #229 from KiwiTechLLC/sprint5
login issue
2023-08-20 14:14:45 +05:30
48b455e38a login issue 2023-08-20 14:12:17 +05:30
6d54a718b9 Merge pull request #226 from KiwiTechLLC/ZBKBCK-346
[ZBKBCK-346] change password and forgot password api has been optimised
2023-08-18 20:26:02 +05:30
e84180a6c2 Merge branch 'dev' into ZBKADM-72-minor-changes 2023-08-18 18:46:47 +05:30
92e5104e3f expiry date of otp 2023-08-18 18:37:01 +05:30
ed1b5dd453 Merge pull request #215 from KiwiTechLLC/dev
Dev
2023-08-16 16:34:54 +05:30
74328f37b2 Merge pull request #212 from KiwiTechLLC/dev
Dev
2023-08-16 11:38:39 +05:30
d8f4467d98 Merge pull request #209 from KiwiTechLLC/dev
guardian code status
2023-08-14 18:23:41 +05:30
a9cc05c675 Merge pull request #207 from KiwiTechLLC/dev
Dev
2023-08-14 17:33:56 +05:30
83d7d119be Merge pull request #203 from KiwiTechLLC/dev
Dev
2023-08-14 11:46:04 +05:30
19a6475097 Merge pull request #200 from KiwiTechLLC/dev
Dev
2023-08-11 16:55:51 +05:30
4ca60af5da Merge pull request #195 from KiwiTechLLC/dev
Dev
2023-08-11 13:50:53 +05:30
807526acfa Merge pull request #191 from KiwiTechLLC/dev
Dev
2023-08-11 12:24:28 +05:30
f4149379c2 Merge pull request #188 from KiwiTechLLC/dev
Dev
2023-08-10 19:21:12 +05:30
b8f1acaed8 Merge pull request #185 from KiwiTechLLC/dev
Dev
2023-08-10 18:37:06 +05:30
9e5dd5e3d5 Merge pull request #183 from KiwiTechLLC/dev
Dev
2023-08-10 17:04:06 +05:30
b961044e4d Merge pull request #179 from KiwiTechLLC/dev
Dev
2023-08-10 11:57:29 +05:30
2498394127 Merge pull request #177 from KiwiTechLLC/dev
Dev
2023-08-09 19:22:42 +05:30
2fc65d462d Merge pull request #174 from KiwiTechLLC/dev
Dev
2023-08-09 18:11:40 +05:30
cdf656fdad Merge pull request #170 from KiwiTechLLC/dev
Dev
2023-08-09 14:51:13 +05:30
8eaf8751c2 Merge pull request #165 from KiwiTechLLC/dev
Dev
2023-08-08 17:14:36 +05:30
6867920754 Merge pull request #163 from KiwiTechLLC/dev
Dev
2023-08-08 16:07:14 +05:30
22ba4288d9 Merge pull request #161 from KiwiTechLLC/dev
Dev
2023-08-08 15:04:50 +05:30
7ab16cb3de Merge pull request #158 from KiwiTechLLC/dev
Dev
2023-08-08 14:24:44 +05:30
07d150309b Merge pull request #146 from KiwiTechLLC/dev
Dev
2023-08-04 15:04:55 +05:30
3801e6e027 Merge pull request #142 from KiwiTechLLC/dev
Dev
2023-08-03 14:59:49 +05:30
e89fc513cb Merge pull request #138 from KiwiTechLLC/dev
Dev
2023-08-02 14:25:06 +05:30
e1af1c200d Merge pull request #136 from KiwiTechLLC/dev
Dev
2023-08-02 11:33:29 +05:30
b238379a22 Merge pull request #130 from KiwiTechLLC/dev
Dev
2023-07-28 19:49:56 +05:30
c081bc621d Merge pull request #124 from KiwiTechLLC/dev
merging dev into qa
2023-07-27 22:04:51 +05:30
d2c8b18e3f Merge pull request #120 from KiwiTechLLC/dev
merging dev itno qa
2023-07-27 11:37:25 +05:30
bdc0ba4fd5 Merge pull request #117 from KiwiTechLLC/dev
Dev
2023-07-26 16:58:38 +05:30
3af2584d6a Merge pull request #115 from KiwiTechLLC/dev
Dev
2023-07-26 11:09:40 +05:30
62cf2b14bf Merge pull request #113 from KiwiTechLLC/dev
merging dev into qa
2023-07-26 11:01:45 +05:30
cbd3d139a5 Merge pull request #110 from KiwiTechLLC/dev
Dev
2023-07-25 17:36:49 +05:30
7cb792c6cf Merge pull request #104 from KiwiTechLLC/dev
Dev
2023-07-25 11:52:36 +05:30
5ea28bbd75 Merge pull request #102 from KiwiTechLLC/dev
Dev
2023-07-24 15:56:54 +05:30
180104ece8 Merge pull request #100 from KiwiTechLLC/dev
Dev
2023-07-24 11:04:08 +05:30
32 changed files with 806 additions and 346 deletions

View File

@ -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"""

View File

@ -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
@ -18,9 +18,9 @@ from guardian.models import Guardian
# user can login in single
# device at a time"""
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,6 +39,9 @@ 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
@ -56,4 +59,10 @@ class CustomMiddleware(object):
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)
force_update = ForceUpdate.objects.filter(version=version, device_type=device_type).last()
api_endpoint_checks = not any(endpoint in api_endpoint for endpoint in ['/admin/', '/api/v1/admin/'])
if not force_update and version and device_type:
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

View 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',
},
),
]

View File

@ -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

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
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
@ -308,7 +308,7 @@ class EmailVerificationSerializer(serializers.ModelSerializer):
class Meta(object):
"""Meta info"""
model = UserEmailOtp
fields = '__all__'
fields = ('email',)
@ -390,3 +390,11 @@ 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

@ -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)),

View File

@ -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):
"""
@ -278,8 +282,9 @@ 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
return f"{user_obj.first_name} {user_obj.last_name}" if user_obj.first_name or user_obj.last_name else "User"

View File

@ -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():
@ -234,8 +306,12 @@ class ForgotPasswordAPIView(views.APIView):
serializer_class = ForgotPasswordSerializer
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)
@ -262,7 +338,6 @@ class ForgotPasswordAPIView(views.APIView):
response_status=status.HTTP_200_OK
)
class SendPhoneOtp(viewsets.ModelViewSet):
"""Send otp on phone"""
serializer_class = UserPhoneOtpSerializer
@ -310,22 +385,24 @@ 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, is_verified=True).last()
guardian_data = Guardian.objects.filter(user__username=username).last()
if guardian_data:
serializer = GuardianSerializer(
guardian_data, context={'user_type': user_type}
).data
if guardian_data.is_verified:
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, is_verified=True).last()
junior_data = Junior.objects.filter(auth__username=username).last()
if junior_data:
serializer = JuniorSerializer(
junior_data, context={'user_type': user_type}
).data
if junior_data.is_verified:
serializer = JuniorSerializer(
junior_data, context={'user_type': user_type}
).data
else:
return custom_error_response(
ERROR_CODE["2071"],
@ -418,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',)
@ -465,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)
@ -478,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)
@ -487,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']
@ -523,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()
@ -531,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])
@ -553,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)
@ -564,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():
@ -576,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):
@ -620,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)

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"
@ -50,7 +50,10 @@ USER_TYPE = (
('2', 'guardian'),
('3', 'superuser')
)
DEVICE_TYPE = (
('1', 'android'),
('2', 'ios')
)
USER_TYPE_FLAG = {
"FIRST" : "1",
"TWO" : "2",

View File

@ -101,7 +101,13 @@ 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",
"2075": "Your account is deactivated. Please contact with admin"
"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",
"2079": "Please update your app version for enjoying uninterrupted services",
"2080": "Can not add App version"
}
"""Success message code"""
SUCCESS_CODE = {
@ -167,7 +173,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"""

View File

@ -1,6 +1,8 @@
"""
web_admin tasks file
"""
import datetime
# third party imports
from celery import shared_task
from templated_email import send_templated_mail
@ -8,6 +10,12 @@ from templated_email import send_templated_mail
# django imports
from django.conf import settings
# local imports
from base.constants import PENDING, IN_PROGRESS, JUNIOR
from guardian.models import JuniorTask
from notifications.constants import PENDING_TASK_EXPIRING, IN_PROGRESS_TASK_EXPIRING
from notifications.utils import send_notification
@shared_task
def send_email_otp(email, verification_code):
@ -27,3 +35,45 @@ def send_email_otp(email, verification_code):
}
)
return True
@shared_task
def send_mail(recipient_list, template, context: dict = None):
"""
used to send otp on email
:param context:
:param recipient_list: e-mail list
:param template: email template
"""
if context is None:
context = {}
from_email = settings.EMAIL_FROM_ADDRESS
recipient_list = recipient_list
send_templated_mail(
template_name=template,
from_email=from_email,
recipient_list=recipient_list,
context=context
)
return True
@shared_task()
def notify_task_expiry():
"""
task to send notification for those task which expiring soon
:return:
"""
all_pending_tasks = JuniorTask.objects.filter(
task_status__in=[PENDING, IN_PROGRESS],
due_date__range=[datetime.datetime.now().date(),
(datetime.datetime.now().date() + datetime.timedelta(days=1))])
if pending_tasks := all_pending_tasks.filter(task_status=PENDING):
for task in pending_tasks:
send_notification(PENDING_TASK_EXPIRING, None, None, task.junior.auth.id,
{'task_id': task.id})
if in_progress_tasks := all_pending_tasks.filter(task_status=IN_PROGRESS):
for task in in_progress_tasks:
send_notification(IN_PROGRESS_TASK_EXPIRING, task.junior.auth.id, JUNIOR, task.guardian.user.id,
{'task_id': task.id})
return True

Binary file not shown.

View File

@ -24,13 +24,13 @@ from account.models import UserProfile, UserEmailOtp, UserNotification
from account.utils import generate_code
from junior.serializers import JuniorDetailSerializer
from base.messages import ERROR_CODE, SUCCESS_CODE
from base.constants import NUMBER, JUN, ZOD, GRD, Already_register_user
from base.constants import NUMBER, JUN, ZOD, GRD, Already_register_user, GUARDIAN
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 notifications.utils import send_notification
from django.core.exceptions import ValidationError
from django.utils.translation import gettext as _
@ -420,8 +420,8 @@ 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,
{'task_id': instance.id})
send_notification.delay(TASK_APPROVED, instance.guardian.user.id, GUARDIAN,
junior_details.auth.id, {'task_id': instance.id})
else:
# reject the task
instance.task_status = str(NUMBER['three'])
@ -429,8 +429,8 @@ 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,
{'task_id': instance.id})
send_notification.delay(TASK_REJECTED, instance.guardian.user.id, GUARDIAN,
junior_details.auth.id, {'task_id': instance.id})
instance.save()
junior_data.save()
return junior_details

View File

@ -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"""

View File

@ -21,7 +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
@ -117,7 +117,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, None, junior_queryset.auth.id, {})

View File

@ -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
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 base.constants import NUMBER, GUARDIAN_CODE_STATUS, GUARDIAN
from .utils import upload_image_to_alibaba
from notifications.constants import REGISTRATION, TASK_ASSIGNED, LEADERBOARD_RANKING
from notifications.utils import send_notification_to_junior
from notifications.constants import REGISTRATION, TASK_ASSIGNED, ASSOCIATE_APPROVED, ASSOCIATE_REJECTED
from notifications.utils import send_notification
""" Define APIs """
# Define Signup API,
@ -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,9 +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 not in junior_id.guardian_code:
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)
@ -187,19 +201,20 @@ class CreateTaskAPIView(viewsets.ModelViewSet):
if serializer.is_valid():
# save serializer
task = serializer.save()
junior_id = Junior.objects.filter(id=junior).last()
send_notification_to_junior.delay(TASK_ASSIGNED, request.auth.payload['user_id'],
junior_id.auth.id, {'task_id': task.id})
send_notification.delay(TASK_ASSIGNED, request.auth.payload['user_id'], GUARDIAN,
junior_id.auth.id, {'task_id': task.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):
"""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"""
@ -210,7 +225,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()
@ -224,10 +239,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
@ -242,7 +259,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)
@ -250,14 +266,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
@ -273,23 +292,32 @@ class ApproveJuniorAPIView(viewsets.ViewSet):
if serializer.is_valid():
# save serializer
serializer.save()
send_notification.delay(ASSOCIATE_APPROVED, guardian.user.id, GUARDIAN,
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.delay(ASSOCIATE_REJECTED, guardian.user.id, GUARDIAN, 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()
@ -317,7 +345,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)
@ -329,7 +357,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

View File

@ -16,15 +16,15 @@ from junior.models import Junior, JuniorPoints, JuniorGuardianRelationship, Juni
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,
GUARDIAN_CODE_STATUS)
GUARDIAN_CODE_STATUS, JUNIOR)
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 (INVITED_GUARDIAN, APPROVED_JUNIOR, SKIPPED_PROFILE_SETUP, TASK_ACTION,
TASK_SUBMITTED)
from notifications.utils import send_notification
from notifications.constants import (ASSOCIATE_REQUEST, JUNIOR_ADDED, TASK_ACTION,
)
from web_admin.models import ArticleCard
class ListCharField(serializers.ListField):
"""Serializer for Array field"""
@ -97,8 +97,9 @@ class CreateJuniorSerializer(serializers.ModelSerializer):
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.delay(ASSOCIATE_REQUEST, junior.auth.id, JUNIOR, 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 +293,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 +305,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.delay(JUNIOR_ADDED, None, None, junior_data.auth.id, {})
return junior_data
@ -338,10 +339,8 @@ 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})
send_notification.delay(TASK_ACTION, instance.junior.auth.id, JUNIOR,
instance.guardian.user.id, {'task_id': instance.id})
return instance
class JuniorPointsSerializer(serializers.ModelSerializer):
@ -445,14 +444,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.delay(ASSOCIATE_REQUEST, junior_data.auth.id, JUNIOR, guardian_data.user.id, {})
return guardian_data
class StartTaskSerializer(serializers.ModelSerializer):
@ -518,3 +516,11 @@ class FAQSerializer(serializers.ModelSerializer):
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

@ -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

View File

@ -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,15 +38,15 @@ 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
from base.constants import NUMBER, ARTICLE_STATUS
from base.constants import NUMBER, ARTICLE_STATUS, none
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,
@ -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')
@ -98,12 +101,16 @@ class UpdateJuniorProfile(viewsets.ViewSet):
except Exception as e:
return custom_error_response(str(e), 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 +162,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'],
@ -171,7 +185,11 @@ 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():
self.associate_guardian(user)
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)
return custom_response(SUCCESS_CODE['3021'], response_status=status.HTTP_200_OK)
# use AddJuniorSerializer serializer
serializer = AddJuniorSerializer(data=request.data, context=info_data)
@ -184,9 +202,16 @@ 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=user).first()
junior = Junior.objects.filter(auth__email=self.request.data['email']).first()
guardian = Guardian.objects.filter(user=self.request.user).first()
junior.guardian_code = [guardian.guardian_code]
if not junior:
return none
if junior.guardian_code and (guardian.guardian_code in junior.guardian_code):
return False
if type(junior.guardian_code) is list:
junior.guardian_code.append(guardian.guardian_code)
else:
junior.guardian_code = [guardian.guardian_code]
junior.guardian_code_status = str(NUMBER['two'])
junior.save()
JuniorGuardianRelationship.objects.get_or_create(guardian=guardian, junior=junior,
@ -195,7 +220,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]
@ -209,7 +234,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()
@ -223,12 +249,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', # Query parameter name
openapi.IN_QUERY, # Parameter location
description='title of the name',
type=openapi.TYPE_STRING, # Parameter type
),
# Add more parameters as needed
]
)
def get_queryset(self):
"""Get the queryset for the view"""
title = self.request.GET.get('title')
@ -239,7 +278,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()
@ -253,7 +292,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]
@ -271,7 +312,7 @@ class RemoveJuniorAPIView(views.APIView):
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, 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:
@ -281,14 +322,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')
@ -318,7 +362,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]
@ -363,7 +409,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()
@ -374,7 +421,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',)
@ -409,7 +456,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)
@ -427,7 +480,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]
@ -451,7 +508,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]
@ -480,7 +543,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')
@ -502,7 +568,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',)
@ -515,7 +581,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()
@ -527,7 +595,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',)
@ -536,7 +606,10 @@ 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')
@ -560,7 +633,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):
@ -574,7 +649,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,
@ -588,12 +664,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')
@ -611,11 +691,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')
@ -634,7 +717,8 @@ 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
No Payload"""
serializer_class = RemoveGuardianCodeSerializer
permission_classes = [IsAuthenticated]
@ -671,7 +755,7 @@ class FAQViewSet(GenericViewSet, mixins.CreateModelMixin,
"""
faq create api method
:param request:
:param args:
:param args: question, description
:param kwargs:
:return: success message
"""
@ -697,6 +781,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)

View File

@ -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']

View File

@ -1,19 +1,21 @@
"""
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
PENDING_TASK_EXPIRING = 12
IN_PROGRESS_TASK_EXPIRING = 13
REMOVE_JUNIOR = 15
TEST_NOTIFICATION = 99
NOTIFICATION_DICT = {
@ -21,50 +23,72 @@ 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 !",
# user will receive notification as soon junior sign up application using their guardian code
# for association
ASSOCIATE_REQUEST: {
"title": "Associate request!",
"body": "You have request from {from_user} to associate with you."
},
# Juniors will receive notification when custodians reject their request for associate
ASSOCIATE_REJECTED: {
"title": "Associate request rejected!",
"body": "Your request to associate has been rejected by {from_user}."
},
# Juniors will receive notification when custodians approve their request for associate
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": "{from_user} completed her task {task_name}."
},
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 when their task end date about to end
PENDING_TASK_EXPIRING: {
"title": "Task expiring soon!",
"body": "Your task {task_name} is expiring soon. Please complete it."
},
# User will receive notification when their assigned task is about to end
# and juniors have not performed any action
IN_PROGRESS_TASK_EXPIRING: {
"title": "Task expiring soon!",
"body": "{from_user} didn't take any action on assigned task {task_name} and it's expiring soon. "
"Please assist to complete it."
},
# 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
TEST_NOTIFICATION: {
"title": "Test Notification",
"body": "This notification is for testing purpose from {from_user}."

View File

@ -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

View File

@ -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()),
]

View File

@ -9,15 +9,15 @@ from firebase_admin.messaging import Message, Notification as FirebaseNotificati
# django imports
from django.contrib.auth import get_user_model
# local imports
from account.models import UserNotification
from account.utils import get_user_full_name
from guardian.models import Guardian
from base.constants import GUARDIAN, JUNIOR
from guardian.models import Guardian, JuniorTask
from junior.models import Junior
from notifications.constants import NOTIFICATION_DICT
from notifications.models import Notification
# local imports
User = get_user_model()
@ -42,49 +42,69 @@ 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):
def get_from_user_details(from_user_id, from_user_type):
"""
used to get the basic details
used to get from user details
"""
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
from_user = None
from_user_name = None
from_user_image = None
if from_user_id:
if from_user_type == GUARDIAN:
guardian = Guardian.objects.filter(user_id=from_user_id).select_related('user').first()
from_user = guardian.user
from_user_name = get_user_full_name(from_user)
from_user_image = guardian.image
elif from_user_type == JUNIOR:
junior = Junior.objects.filter(auth_id=from_user_id).select_related('auth').first()
from_user = junior.auth
from_user_name = get_user_full_name(from_user)
from_user_image = junior.image
return from_user_name, from_user_image, from_user
def get_notification_data(notification_type, from_user, to_user, extra_data):
def get_notification_data(notification_type, from_user_id, from_user_type, to_user_id, extra_data):
"""
get notification and push data
:param from_user_type: GUARDIAN or JUNIOR
:param notification_type: notification_type
:param from_user: from_user obj
:param to_user: to_user obj
:param from_user_id: from_user obj
:param to_user_id: 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
task_name = None
if 'task_id' in extra_data:
task = JuniorTask.objects.filter(id=extra_data.get('task_id')).first()
task_name = task.task_name
extra_data['task_image'] = task.image if task.image else task.default_image
from_user_name, from_user_image, from_user = get_from_user_details(from_user_id, from_user_type)
push_data['body'] = push_data['body'].format(from_user=from_user_name, task_name=task_name)
notification_data['body'] = notification_data['body'].format(from_user=from_user_name, task_name=task_name)
notification_data['from_user'] = from_user_name
notification_data['from_user_image'] = from_user_image
notification_data.update(extra_data)
return notification_data, push_data
to_user = User.objects.get(id=to_user_id)
return notification_data, push_data, from_user, to_user
def send_notification(notification_type, from_user, to_user, extra_data):
@shared_task()
def send_notification(notification_type, from_user_id, from_user_type, to_user_id, 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)
notification_data, push_data, from_user, to_user = get_notification_data(notification_type, from_user_id,
from_user_type, to_user_id, extra_data)
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()})
Notification.objects.create(notification_type=notification_type, notification_from=from_user,
notification_to=to_user, data=notification_data)
if user_notification_type.push_notification:
if user_notification_type and user_notification_type.push_notification:
send_push(to_user, push_data)
@ -97,25 +117,31 @@ def send_push(user, data):
@shared_task()
def send_notification_to_guardian(notification_type, from_user_id, to_user_id, extra_data):
from_user = None
"""
:param notification_type:
:param from_user_id:
:param to_user_id:
:param extra_data:
:return:
"""
if from_user_id:
from_user = Junior.objects.filter(auth_id=from_user_id).select_related('auth').first()
from_user = Junior.objects.filter(auth_id=from_user_id).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)
send_notification(notification_type, from_user_id, to_user_id, extra_data)
@shared_task()
def send_notification_to_junior(notification_type, from_user_id, to_user_id, extra_data):
from_user = None
"""
:param notification_type:
:param from_user_id:
:param to_user_id:
:param extra_data:
:return:
"""
if from_user_id:
from_user = Guardian.objects.filter(user_id=from_user_id).select_related('user').first()
from_user = Guardian.objects.filter(user_id=from_user_id).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)
send_notification(notification_type, from_user_id, to_user_id, extra_data)

View File

@ -4,41 +4,40 @@ notifications views file
# django imports
from django.db.models import Q
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated
from rest_framework.permissions import IsAuthenticated, AllowAny
from rest_framework.response import Response
from rest_framework import viewsets, status, views
# local imports
from account.utils import custom_response, custom_error_response
from base.messages import SUCCESS_CODE, ERROR_CODE
from base.tasks import notify_task_expiry
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
# Import model
from notifications.utils import send_notification
from notifications.models import Notification
class NotificationViewSet(viewsets.GenericViewSet):
""" used to do the notification actions """
"""
used to do the notification actions
"""
serializer_class = NotificationListSerializer
permission_classes = [IsAuthenticated, ]
def list(self, request, *args, **kwargs) -> Response:
""" list the notifications """
"""
to list user's notifications
:param request:
:return:
"""
queryset = Notification.objects.filter(notification_to_id=request.auth.payload['user_id']
).select_related('notification_to').order_by('-id')
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):
"""
@ -56,38 +55,24 @@ 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(TEST_NOTIFICATION, None, None, request.auth.payload['user_id'],
{})
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)
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)
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)
@action(methods=['get'], url_path='task', url_name='task', detail=False,
permission_classes=[AllowAny])
def task(self, request, *args, **kwargs):
"""
notification list
"""
notify_task_expiry()
return custom_response(SUCCESS_CODE['3039'], response_status=status.HTTP_200_OK)

View File

@ -7,6 +7,7 @@ from rest_framework import serializers
# django imports
from django.contrib.auth import get_user_model
from account.utils import get_user_full_name
# local imports
from base.constants import USER_TYPE
@ -74,6 +75,7 @@ class UserCSVReportSerializer(serializers.ModelSerializer):
"""
user csv/xls report serializer
"""
name = serializers.SerializerMethodField()
phone_number = serializers.SerializerMethodField()
user_type = serializers.SerializerMethodField()
is_active = serializers.SerializerMethodField()
@ -84,7 +86,15 @@ class UserCSVReportSerializer(serializers.ModelSerializer):
meta class
"""
model = USER
fields = ('first_name', 'last_name', 'email', 'phone_number', 'user_type', 'is_active', 'date_joined')
fields = ('name', 'email', 'phone_number', 'user_type', 'is_active', 'date_joined')
@staticmethod
def get_name(obj):
"""
:param obj: user object
:return: full name
"""
return get_user_full_name(obj)
@staticmethod
def get_phone_number(obj):

View File

@ -14,7 +14,7 @@ from account.models import UserEmailOtp
from base.constants import USER_TYPE
from base.messages import ERROR_CODE
from guardian.tasks import generate_otp
from base.tasks import send_email_otp
from base.tasks import send_mail
USER = get_user_model()
@ -48,11 +48,13 @@ class AdminOTPSerializer(serializers.ModelSerializer):
:return: user_data
"""
email = validated_data['email']
verification_code = generate_otp()
template = 'email_reset_verification.email'
# Send the verification code to the user's email
send_email_otp.delay(email, verification_code)
data = {
"verification_code": verification_code
}
send_mail.delay([email], template, data)
expiry = timezone.now() + timezone.timedelta(days=1)
user_data, created = UserEmailOtp.objects.update_or_create(email=email,

View File

@ -5,6 +5,7 @@ web_admin user_management serializers file
from rest_framework import serializers
from django.contrib.auth import get_user_model
from account.utils import get_user_full_name
from base.constants import USER_TYPE, GUARDIAN, JUNIOR
# local imports
from base.messages import ERROR_CODE, SUCCESS_CODE
@ -37,7 +38,7 @@ class UserManagementListSerializer(serializers.ModelSerializer):
:param obj: user object
:return: full name
"""
return f"{obj.first_name} {obj.last_name}" if obj.last_name else obj.first_name
return get_user_full_name(obj)
@staticmethod
def get_country_code(obj):
@ -144,7 +145,7 @@ class GuardianSerializer(serializers.ModelSerializer):
:param obj: guardian object
:return: full name
"""
return f"{obj.user.first_name} {obj.user.last_name}" if obj.user.last_name else obj.user.first_name
return get_user_full_name(obj.user)
@staticmethod
def get_first_name(obj):
@ -222,7 +223,7 @@ class JuniorSerializer(serializers.ModelSerializer):
:param obj: junior object
:return: full name
"""
return f"{obj.auth.first_name} {obj.auth.last_name}" if obj.auth.last_name else obj.auth.first_name
return get_user_full_name(obj.auth)
@staticmethod
def get_first_name(obj):

View File

@ -2,8 +2,9 @@
web_utils file
"""
import base64
import datetime
from base.constants import ARTICLE_CARD_IMAGE_FOLDER
from base.constants import ARTICLE_CARD_IMAGE_FOLDER, DATE_FORMAT
from guardian.utils import upload_image_to_alibaba, upload_base64_image_to_alibaba
@ -40,3 +41,21 @@ 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

@ -6,9 +6,6 @@ import datetime
import io
import pandas as pd
import xlsxwriter
import tempfile
import oss2
from django.conf import settings
# third party imports
from rest_framework.viewsets import GenericViewSet
@ -25,7 +22,7 @@ from django.db.models.functions.window import Rank
from django.http import HttpResponse
# local imports
from account.utils import custom_response
from account.utils import custom_response, get_user_full_name
from base.constants import PENDING, IN_PROGRESS, REJECTED, REQUESTED, COMPLETED, EXPIRED, DATE_FORMAT, TASK_STATUS
from guardian.models import JuniorTask
from guardian.utils import upload_excel_file_to_alibaba
@ -33,7 +30,7 @@ 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.serializers.user_management_serializer import UserManagementListSerializer
from web_admin.utils import get_dates
USER = get_user_model()
@ -56,7 +53,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)
@ -67,13 +64,8 @@ class AnalyticsViewSet(GenericViewSet):
:param request: end_date: date format (yyyy-mm-dd)
:return:
"""
end_date = datetime.date.today()
start_date = end_date - datetime.timedelta(days=6)
if request.query_params.get('start_date') and request.query_params.get('end_date'):
start_date = datetime.datetime.strptime(request.query_params.get('start_date'), DATE_FORMAT)
end_date = datetime.datetime.strptime(request.query_params.get('end_date'), DATE_FORMAT)
start_date, end_date = get_dates(request.query_params.get('start_date'),
request.query_params.get('end_date'))
user_qs = self.get_queryset()
queryset = user_qs.filter(date_joined__range=(start_date, (end_date + datetime.timedelta(days=1))))
@ -92,12 +84,8 @@ class AnalyticsViewSet(GenericViewSet):
:param request: end_date: date format (yyyy-mm-dd)
:return:
"""
end_date = datetime.date.today()
start_date = end_date - datetime.timedelta(days=6)
if request.query_params.get('start_date') and request.query_params.get('end_date'):
start_date = datetime.datetime.strptime(request.query_params.get('start_date'), DATE_FORMAT)
end_date = datetime.datetime.strptime(request.query_params.get('end_date'), DATE_FORMAT)
start_date, end_date = get_dates(request.query_params.get('start_date'),
request.query_params.get('end_date'))
user_qs = self.get_queryset()
signup_data = user_qs.filter(date_joined__range=[start_date, (end_date + datetime.timedelta(days=1))]
@ -114,22 +102,20 @@ class AnalyticsViewSet(GenericViewSet):
:param request: end_date: date format (yyyy-mm-dd)
:return:
"""
end_date = datetime.date.today()
start_date = end_date - datetime.timedelta(days=6)
if request.query_params.get('start_date') and request.query_params.get('end_date'):
start_date = datetime.datetime.strptime(request.query_params.get('start_date'), DATE_FORMAT)
end_date = datetime.datetime.strptime(request.query_params.get('end_date'), DATE_FORMAT)
start_date, end_date = get_dates(request.query_params.get('start_date'),
request.query_params.get('end_date'))
assign_tasks = JuniorTask.objects.filter(
created_at__range=[start_date, (end_date + datetime.timedelta(days=1))]
).exclude(task_status__in=[PENDING, EXPIRED])
)
data = {
'task_completed': assign_tasks.filter(task_status=COMPLETED).count(),
'task_pending': assign_tasks.filter(task_status=PENDING).count(),
'task_in_progress': assign_tasks.filter(task_status=IN_PROGRESS).count(),
'task_requested': assign_tasks.filter(task_status=REQUESTED).count(),
'task_rejected': assign_tasks.filter(task_status=REJECTED).count(),
'task_expired': assign_tasks.filter(task_status=EXPIRED).count(),
}
return custom_response(None, data)
@ -163,12 +149,8 @@ class AnalyticsViewSet(GenericViewSet):
response = HttpResponse(content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
response['Content-Disposition'] = 'attachment; filename="ZOD_Bank_Analytics.xlsx"'
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)
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()
@ -177,7 +159,7 @@ class AnalyticsViewSet(GenericViewSet):
workbook = xlsxwriter.Workbook(buffer)
# Add sheets
sheets = ['Users', 'Assign Tasks', 'Juniors leaderboard']
sheets = ['Users', 'Assign Tasks', 'Juniors Leaderboard']
for sheet_name in sheets:
worksheet = workbook.add_worksheet(name=sheet_name)
@ -189,59 +171,48 @@ class AnalyticsViewSet(GenericViewSet):
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']}
{'Name': user['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
])
for idx, col in enumerate(df_users.columns):
# Write header
worksheet.write(0, idx, col)
for row_num, row in enumerate(df_users.values, start=1):
for col_num, value in enumerate(row):
worksheet.write(row_num, col_num, value)
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])
).select_related('junior__auth', 'guardian__user').only('task_name', 'task_status',
'junior__auth__first_name',
'junior__auth__last_name',
'guardian__user__first_name',
'guardian__user__last_name',)
df_tasks = pd.DataFrame([
{'Task Name': task.task_name, 'Task Status': dict(TASK_STATUS).get(task.task_status).capitalize()}
{'Task Name': task.task_name, 'Assign To': get_user_full_name(task.junior.auth),
'Assign By': get_user_full_name(task.guardian.user),
'Task Status': dict(TASK_STATUS).get(task.task_status).capitalize()}
for task in assign_tasks
])
for idx, col in enumerate(df_tasks.columns):
# Write header
worksheet.write(0, idx, col)
for row_num, row in enumerate(df_tasks.values, start=1):
for col_num, value in enumerate(row):
worksheet.write(row_num, col_num, value)
write_excel_worksheet(worksheet, df_tasks)
# sheet 3 for Juniors Leaderboard and rank
elif sheet_name == 'Juniors leaderboard':
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,
'Name': get_user_full_name(junior.junior.auth),
'Points': junior.total_points,
'Rank': junior.rank
}
for junior in queryset
])
for idx, col in enumerate(df_leaderboard.columns):
# Write header
worksheet.write(0, idx, col)
for row_num, row in enumerate(df_leaderboard.values, start=1):
for col_num, value in enumerate(row):
worksheet.write(row_num, col_num, value)
write_excel_worksheet(worksheet, df_leaderboard)
# Close the workbook to save the content
workbook.close()
@ -255,3 +226,18 @@ class AnalyticsViewSet(GenericViewSet):
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

@ -229,7 +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 = self.queryset.objects.filter(is_deleted=False, is_published=True).prefetch_related(
'article_cards', 'article_survey', 'article_survey__options'
).order_by('-created_at')
queryset = self.filter_queryset(article)
@ -248,7 +248,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 +259,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()

View File

@ -27,6 +27,13 @@ app.config_from_object('django.conf:settings')
# Load task modules from all registered Django apps.
app.autodiscover_tasks()
app.conf.beat_schedule = {
'notify_task_expiry': {
'task': 'base.tasks.notify_task_expiry',
'schedule': crontab(minute='0', hour='*/1'),
},
}
@app.task(bind=True)
def debug_task(self):