diff --git a/base/messages.py b/base/messages.py index 059d9e8..7bec3cc 100644 --- a/base/messages.py +++ b/base/messages.py @@ -80,7 +80,8 @@ ERROR_CODE = { # invalid junior id msg "2047": "Invalid Junior ID ", "2048": "Choose right file for image", - "2049": "This task is already requested " + "2049": "This task is already requested ", + "2059": "Already exist junior" } """Success message code""" SUCCESS_CODE = { @@ -128,6 +129,7 @@ SUCCESS_CODE = { "3031": "Article Survey has been removed successfully.", "3032": "Task request sent successfully", "3033": "Valid Referral code", + "3034": "Invite guardian successfully" } """status code error""" STATUS_CODE_ERROR = { diff --git a/celerybeat-schedule b/celerybeat-schedule index 2e805bd..cd2e03e 100644 Binary files a/celerybeat-schedule and b/celerybeat-schedule differ diff --git a/guardian/migrations/0017_juniortask_is_invited_juniortask_is_password_set.py b/guardian/migrations/0017_juniortask_is_invited_juniortask_is_password_set.py new file mode 100644 index 0000000..e340016 --- /dev/null +++ b/guardian/migrations/0017_juniortask_is_invited_juniortask_is_password_set.py @@ -0,0 +1,23 @@ +# Generated by Django 4.2.2 on 2023-07-24 13:21 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('guardian', '0016_juniortask_completed_on_juniortask_rejected_on_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='juniortask', + name='is_invited', + field=models.BooleanField(default=False), + ), + migrations.AddField( + model_name='juniortask', + name='is_password_set', + field=models.BooleanField(default=True), + ), + ] diff --git a/guardian/migrations/0018_remove_juniortask_is_invited_and_more.py b/guardian/migrations/0018_remove_juniortask_is_invited_and_more.py new file mode 100644 index 0000000..a9870e1 --- /dev/null +++ b/guardian/migrations/0018_remove_juniortask_is_invited_and_more.py @@ -0,0 +1,21 @@ +# Generated by Django 4.2.2 on 2023-07-24 13:23 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('guardian', '0017_juniortask_is_invited_juniortask_is_password_set'), + ] + + operations = [ + migrations.RemoveField( + model_name='juniortask', + name='is_invited', + ), + migrations.RemoveField( + model_name='juniortask', + name='is_password_set', + ), + ] diff --git a/guardian/migrations/0019_guardian_is_invited_guardian_is_password_set.py b/guardian/migrations/0019_guardian_is_invited_guardian_is_password_set.py new file mode 100644 index 0000000..6c188e4 --- /dev/null +++ b/guardian/migrations/0019_guardian_is_invited_guardian_is_password_set.py @@ -0,0 +1,23 @@ +# Generated by Django 4.2.2 on 2023-07-24 13:23 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('guardian', '0018_remove_juniortask_is_invited_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='guardian', + name='is_invited', + field=models.BooleanField(default=False), + ), + migrations.AddField( + model_name='guardian', + name='is_password_set', + field=models.BooleanField(default=True), + ), + ] diff --git a/guardian/models.py b/guardian/models.py index b4a31dd..6ecd27b 100644 --- a/guardian/models.py +++ b/guardian/models.py @@ -53,6 +53,10 @@ class Guardian(models.Model): gender = models.CharField(choices=GENDERS, max_length=15, null=True, blank=True, default=None) """date of birth of the guardian""" dob = models.DateField(max_length=15, null=True, blank=True, default=None) + # invited junior""" + is_invited = models.BooleanField(default=False) + # Profile activity""" + is_password_set = models.BooleanField(default=True) """Profile activity""" is_active = models.BooleanField(default=True) """guardian is verified or not""" diff --git a/junior/serializers.py b/junior/serializers.py index b1d1615..9b8a8fe 100644 --- a/junior/serializers.py +++ b/junior/serializers.py @@ -17,7 +17,8 @@ from guardian.models import Guardian, JuniorTask from account.models import UserEmailOtp from junior.utils import junior_notification_email, junior_approval_mail from guardian.utils import real_time, update_referral_points - +from notifications.utils import send_notification +from notifications.constants import INVITED_GUARDIAN, APPROVED_JUNIOR class ListCharField(serializers.ListField): @@ -272,7 +273,6 @@ class AddJuniorSerializer(serializers.ModelSerializer): user_data = User.objects.create(username=email, email=email, first_name=self.context['first_name'], last_name=self.context['last_name']) - password = User.objects.make_random_password() user_data.set_password(password) user_data.save() @@ -288,8 +288,6 @@ class AddJuniorSerializer(serializers.ModelSerializer): expiry_time = timezone.now() + timezone.timedelta(days=1) UserEmailOtp.objects.create(email=email, otp=otp_value, user_type='1', expired_at=expiry_time, is_verified=True) - """Send email to the register user""" - send_otp_email(email, otp_value) """Notification email""" junior_notification_email(email, full_name, email, password) junior_approval_mail(guardian, full_name) @@ -374,3 +372,59 @@ class JuniorPointsSerializer(serializers.ModelSerializer): model = Junior fields = ['junior_id', 'total_points', 'position', 'pending_task', 'in_progress_task', 'completed_task', 'requested_task', 'rejected_task'] + +class AddGuardianSerializer(serializers.ModelSerializer): + """Add guardian serializer""" + auth_token = serializers.SerializerMethodField('get_auth_token') + + def get_auth_token(self, obj): + """auth token""" + refresh = RefreshToken.for_user(obj) + access_token = str(refresh.access_token) + return access_token + + class Meta(object): + """Meta info""" + model = Guardian + fields = ['id', 'auth_token'] + + + def create(self, validated_data): + """ invite and create guardian""" + with transaction.atomic(): + email = self.context['email'] + junior = self.context['user'] + full_name = self.context['first_name'] + ' ' + self.context['last_name'] + junior_data = Junior.objects.filter(auth__username=junior).last() + instance = User.objects.filter(username=email).last() + if instance: + guardian_data = Guardian.objects.filter(user=user).update(is_invited=True, + referral_code=generate_code(ZOD, + instance.id), + referral_code_used=junior_data.referral_code, + is_verified=True) + return guardian_data + else: + user = User.objects.create(username=email, email=email, + first_name=self.context['first_name'], + last_name=self.context['last_name']) + + password = User.objects.make_random_password() + user.set_password(password) + user.save() + Guardian.objects.create(user=user, is_invited=True, + referral_code=generate_code(ZOD, user.id), + referral_code_used=junior_data.referral_code, + is_password_set=False, is_verified=True) + """Generate otp""" + otp_value = generate_otp() + expiry_time = timezone.now() + timezone.timedelta(days=1) + UserEmailOtp.objects.create(email=email, otp=otp_value, + user_type=str(NUMBER['two']), expired_at=expiry_time, + is_verified=True) + """Notification email""" + junior_notification_email(email, full_name, email, password) + junior_approval_mail(email, full_name) + send_notification(INVITED_GUARDIAN, None, junior_data.auth.id, {}) + send_notification(APPROVED_JUNIOR, None, email, {}) + return instance diff --git a/junior/urls.py b/junior/urls.py index e4a160d..bd3ed35 100644 --- a/junior/urls.py +++ b/junior/urls.py @@ -3,7 +3,8 @@ from django.urls import path, include from .views import (UpdateJuniorProfile, ValidateGuardianCode, JuniorListAPIView, AddJuniorAPIView, InvitedJuniorAPIView, FilterJuniorAPIView, RemoveJuniorAPIView, JuniorTaskListAPIView, - CompleteJuniorTaskAPIView, JuniorPointsListAPIView, ValidateReferralCode) + CompleteJuniorTaskAPIView, JuniorPointsListAPIView, ValidateReferralCode, + InviteGuardianAPIView) """Third party import""" from rest_framework import routers @@ -38,6 +39,8 @@ router.register('junior-task-list', JuniorTaskListAPIView, basename='junior-task router.register('junior-points', JuniorPointsListAPIView, basename='junior-points') # validate referral code API""" router.register('validate-referral-code', ValidateReferralCode, basename='validate-referral-code') +# invite guardian API""" +router.register('invite-guardian', InviteGuardianAPIView, basename='invite-guardian') # Define url pattern""" urlpatterns = [ path('api/v1/', include(router.urls)), diff --git a/junior/views.py b/junior/views.py index 67f24e9..aecbf80 100644 --- a/junior/views.py +++ b/junior/views.py @@ -4,6 +4,7 @@ import os from rest_framework import viewsets, status, generics,views from rest_framework.permissions import IsAuthenticated from rest_framework.pagination import PageNumberPagination +from django.contrib.auth.models import User import requests """Django app import""" @@ -21,7 +22,8 @@ import requests # import junior serializer from junior.models import Junior, JuniorPoints from .serializers import (CreateJuniorSerializer, JuniorDetailListSerializer, AddJuniorSerializer,\ - RemoveJuniorSerializer, CompleteTaskSerializer, JuniorPointsSerializer) + RemoveJuniorSerializer, CompleteTaskSerializer, JuniorPointsSerializer, + AddGuardianSerializer) from guardian.models import Guardian, JuniorTask from guardian.serializers import TaskDetailsSerializer from base.messages import ERROR_CODE, SUCCESS_CODE @@ -117,6 +119,9 @@ class AddJuniorAPIView(viewsets.ModelViewSet): """ junior list""" info = {'user': request.user, 'email': request.data['email'], 'first_name': request.data['first_name'], 'last_name': request.data['last_name']} + if User.objects.filter(username=request.data['email']): + return custom_error_response(ERROR_CODE['2059'], response_status=status.HTTP_400_BAD_REQUEST) + # use AddJuniorSerializer serializer serializer = AddJuniorSerializer(data=request.data, context=info) if serializer.is_valid(): @@ -257,7 +262,7 @@ class CompleteJuniorTaskAPIView(views.APIView): task_queryset = JuniorTask.objects.filter(id=task_id, junior__auth__email=self.request.user).last() if task_queryset: # use CompleteTaskSerializer serializer - if task_queryset.task_status in ['4', '5']: + if task_queryset.task_status in [str(NUMBER['four']), str(NUMBER['five'])]: """Already request send """ return custom_error_response(ERROR_CODE['2049'], response_status=status.HTTP_400_BAD_REQUEST) serializer = CompleteTaskSerializer(task_queryset, data={'image': image_url}, partial=True) @@ -311,3 +316,20 @@ class ValidateReferralCode(viewsets.ViewSet): if self.get_queryset(): return custom_response(SUCCESS_CODE['3033'], response_status=status.HTTP_200_OK) return custom_error_response(ERROR_CODE["2019"], response_status=status.HTTP_400_BAD_REQUEST) + +class InviteGuardianAPIView(viewsets.ModelViewSet): + """Invite guardian by junior""" + serializer_class = AddGuardianSerializer + permission_classes = [IsAuthenticated] + + def create(self, request, *args, **kwargs): + """ junior list""" + info = {'user': request.user, 'email': request.data['email'], 'first_name': request.data['first_name'], + 'last_name': request.data['last_name']} + # use AddJuniorSerializer serializer + serializer = AddGuardianSerializer(data=request.data, context=info) + if serializer.is_valid(): + # save serializer + serializer.save() + return custom_response(SUCCESS_CODE['3034'], serializer.data, response_status=status.HTTP_200_OK) + return custom_error_response(serializer.error, response_status=status.HTTP_400_BAD_REQUEST) diff --git a/notifications/constants.py b/notifications/constants.py index 25602a8..c6f0a9f 100644 --- a/notifications/constants.py +++ b/notifications/constants.py @@ -3,6 +3,8 @@ notification constants file """ REGISTRATION = 1 TASK_CREATED = 2 +INVITED_GUARDIAN = 3 +APPROVED_JUNIOR = 4 TEST_NOTIFICATION = 99 NOTIFICATION_DICT = { @@ -14,6 +16,14 @@ NOTIFICATION_DICT = { "title": "Task created!", "body": "Task created successfully." }, + INVITED_GUARDIAN: { + "title": "Invite guardian", + "body": "Invite guardian successfully" + }, + APPROVED_JUNIOR: { + "title": "Approve junior", + "body": "You have request for associate the junior" + }, TEST_NOTIFICATION: { "title": "Test Notification", "body": "This notification is for testing purpose"