diff --git a/account/custom_middleware.py b/account/custom_middleware.py index 7a06e43..ec2e315 100644 --- a/account/custom_middleware.py +++ b/account/custom_middleware.py @@ -7,7 +7,9 @@ from rest_framework.renderers import JSONRenderer from account.utils import custom_error_response from account.models import UserDeviceDetails from base.messages import ERROR_CODE, SUCCESS_CODE - +from base.constants import NUMBER +from junior.models import Junior +from guardian.models import Guardian # Custom middleware # when user login with # multiple device simultaneously @@ -15,6 +17,16 @@ from base.messages import ERROR_CODE, SUCCESS_CODE # multiple devices only # user can login in single # device at a time""" + +def custom_response(custom_error): + """custom response""" + response = Response(custom_error.data, status=status.HTTP_404_NOT_FOUND) + # Set content type header to "application/json" + response['Content-Type'] = 'application/json' + # Render the response as JSON + renderer = JSONRenderer() + response.content = renderer.render(response.data) + return response class CustomMiddleware(object): """Custom middleware""" def __init__(self, get_response): @@ -26,15 +38,21 @@ class CustomMiddleware(object): response = self.get_response(request) # Code to be executed after the view is called device_id = request.META.get('HTTP_DEVICE_ID') + user_type = request.META.get('HTTP_USER_TYPE') if request.user.is_authenticated: """device details""" device_details = UserDeviceDetails.objects.filter(user=request.user, device_id=device_id).last() + if user_type and str(user_type) == str(NUMBER['one']): + junior = Junior.objects.filter(auth=request.user, is_active=False).last() + if junior: + custom_error = custom_error_response(ERROR_CODE['2075'], response_status=status.HTTP_404_NOT_FOUND) + response = custom_response(custom_error) + elif user_type and str(user_type) == str(NUMBER['two']): + guardian = Guardian.objects.filter(user=request.user, is_active=False).last() + if guardian: + custom_error = custom_error_response(ERROR_CODE['2075'], response_status=status.HTTP_404_NOT_FOUND) + response = custom_response(custom_error) if device_id and not device_details: custom_error = custom_error_response(ERROR_CODE['2037'], response_status=status.HTTP_404_NOT_FOUND) - response = Response(custom_error.data, status=status.HTTP_404_NOT_FOUND) - # Set content type header to "application/json" - response['Content-Type'] = 'application/json' - # Render the response as JSON - renderer = JSONRenderer() - response.content = renderer.render(response.data) + response = custom_response(custom_error) return response diff --git a/account/serializers.py b/account/serializers.py index ebdc263..0caeb8c 100644 --- a/account/serializers.py +++ b/account/serializers.py @@ -244,7 +244,7 @@ class GuardianSerializer(serializers.ModelSerializer): """Meta info""" model = Guardian fields = ['id', 'auth_token', 'refresh_token', 'email', 'first_name', 'last_name', 'country_code', - 'phone', 'family_name', 'gender', 'dob', 'referral_code', 'is_active', + 'phone', 'family_name', 'gender', 'dob', 'referral_code', 'is_active', 'is_deleted', 'is_complete_profile', 'passcode', 'image', 'created_at', 'updated_at', 'user_type', 'country_name'] @@ -287,7 +287,8 @@ class JuniorSerializer(serializers.ModelSerializer): model = Junior fields = ['id', 'auth_token', 'refresh_token', 'email', 'first_name', 'last_name', 'country_code', 'phone', 'gender', 'dob', 'guardian_code', 'referral_code','is_active', 'is_password_set', - 'is_complete_profile', 'created_at', 'image', 'updated_at', 'user_type', 'country_name','is_invited'] + 'is_complete_profile', 'created_at', 'image', 'updated_at', 'user_type', 'country_name','is_invited', + 'is_deleted'] class EmailVerificationSerializer(serializers.ModelSerializer): """Email verification serializer""" diff --git a/account/templates/templated_email/support_mail.email b/account/templates/templated_email/support_mail.email index 50467a9..34d6156 100644 --- a/account/templates/templated_email/support_mail.email +++ b/account/templates/templated_email/support_mail.email @@ -8,14 +8,14 @@

- Hi {{name}}, + Hi Support Team,

- {{name}} have some queries and need some support. Please support them by using their email address {{sender}}.

Queries are:-
{{ message }} + {{name}} have some queries and need some support. Please support them by using their email address {{sender}}.

Queries are:-

  • {{ message }}
  • diff --git a/account/utils.py b/account/utils.py index 8df5294..e016940 100644 --- a/account/utils.py +++ b/account/utils.py @@ -95,6 +95,7 @@ def junior_account_update(user_tb): junior_data.is_verified = False junior_data.guardian_code = '{}' junior_data.guardian_code_status = str(NUMBER['one']) + junior_data.is_deleted = True junior_data.save() JuniorPoints.objects.filter(junior=junior_data).delete() @@ -105,6 +106,7 @@ def guardian_account_update(user_tb): # Update guardian account guardian_data.is_active = False guardian_data.is_verified = False + guardian_data.is_deleted = True guardian_data.save() jun_data = Junior.objects.filter(guardian_code__icontains=str(guardian_data.guardian_code)) """Disassociate relation between guardian and junior""" diff --git a/account/views.py b/account/views.py index c17f853..f91f1fe 100644 --- a/account/views.py +++ b/account/views.py @@ -287,7 +287,7 @@ class UserLogin(viewsets.ViewSet): def login(self, request): username = request.data.get('username') password = request.data.get('password') - user_type = request.data.get('user_type') + user_type = request.META.get('HTTP_USER_TYPE') device_id = request.META.get('HTTP_DEVICE_ID') user = authenticate(request, username=username, password=password) diff --git a/base/messages.py b/base/messages.py index 10fbfaa..cbcd559 100644 --- a/base/messages.py +++ b/base/messages.py @@ -96,9 +96,12 @@ ERROR_CODE = { "2067": "Action not allowed. User type missing.", "2068": "No guardian associated with this junior", "2069": "Invalid user type", - "2070": "You did not find as a guardian", - "2071": "You did not find as a junior" - + "2070": "You do not find as a guardian", + "2071": "You do not find as a junior", + "2072": "You can not approve or reject this task because junior does not exist in the system", + "2073": "You can not approve or reject this junior because junior does not exist in the system", + "2074": "You can not complete this task because you does not exist in the system", + "2075": "Your account is deactivated. Please contact with admin" } """Success message code""" SUCCESS_CODE = { @@ -163,6 +166,8 @@ SUCCESS_CODE = { "3043": "Read article card successfully", # remove guardian code request "3044": "Remove guardian code request successfully", + # create faq + "3045": "Create FAQ data" } """status code error""" diff --git a/celerybeat-schedule b/celerybeat-schedule index ce5d8ac..4a3bd31 100644 Binary files a/celerybeat-schedule and b/celerybeat-schedule differ diff --git a/guardian/migrations/0021_guardian_is_deleted.py b/guardian/migrations/0021_guardian_is_deleted.py new file mode 100644 index 0000000..11833c6 --- /dev/null +++ b/guardian/migrations/0021_guardian_is_deleted.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.2 on 2023-08-17 12:45 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('guardian', '0020_alter_juniortask_task_status'), + ] + + operations = [ + migrations.AddField( + model_name='guardian', + name='is_deleted', + field=models.BooleanField(default=False), + ), + ] diff --git a/guardian/models.py b/guardian/models.py index 45afee7..5c6457a 100644 --- a/guardian/models.py +++ b/guardian/models.py @@ -57,6 +57,8 @@ class Guardian(models.Model): is_invited = models.BooleanField(default=False) # Profile activity""" is_password_set = models.BooleanField(default=True) + # guardian profile deleted or not""" + is_deleted = models.BooleanField(default=False) """Profile activity""" is_active = models.BooleanField(default=True) """guardian is verified or not""" diff --git a/guardian/serializers.py b/guardian/serializers.py index cbd1e4e..f36bd46 100644 --- a/guardian/serializers.py +++ b/guardian/serializers.py @@ -1,6 +1,7 @@ """Serializer of Guardian""" # third party imports import logging +from django.contrib.auth import password_validation from rest_framework import serializers # Import Refresh token of jwt from rest_framework_simplejwt.tokens import RefreshToken @@ -30,7 +31,8 @@ from .utils import real_time, convert_timedelta_into_datetime, update_referral_p from notifications.constants import TASK_POINTS, TASK_REJECTED # send notification function from notifications.utils import send_notification, send_notification_to_junior - +from django.core.exceptions import ValidationError +from django.utils.translation import gettext as _ # In this serializer file # define user serializer, @@ -42,10 +44,45 @@ from notifications.utils import send_notification, send_notification_to_junior # guardian profile serializer, # approve junior serializer, # approve task serializer, +from rest_framework import serializers + +class PasswordValidator: + def __init__(self, min_length=8, max_length=None, require_uppercase=True, require_numbers=True): + self.min_length = min_length + self.max_length = max_length + self.require_uppercase = require_uppercase + self.require_numbers = require_numbers + + def __call__(self, value): + self.enforce_password_policy(value) + + def enforce_password_policy(self, password): + special_characters = "!@#$%^&*()_-+=<>?/[]{}|" + if len(password) < self.min_length: + raise serializers.ValidationError( + _("Password must be at least %(min_length)d characters long.") % {'min_length': self.min_length} + ) + + if self.max_length is not None and len(password) > self.max_length: + raise serializers.ValidationError( + _("Password must be at most %(max_length)d characters long.") % {'max_length': self.max_length} + ) + + if self.require_uppercase and not any(char.isupper() for char in password): + raise serializers.ValidationError(_("Password must contain at least one uppercase letter.")) + + if self.require_numbers and not any(char.isdigit() for char in password): + raise serializers.ValidationError(_("Password must contain at least one digit.")) + if self.require_numbers and not any(char in special_characters for char in password): + raise serializers.ValidationError(_("Password must contain at least one special character.")) + + + class UserSerializer(serializers.ModelSerializer): """User serializer""" auth_token = serializers.SerializerMethodField('get_auth_token') + password = serializers.CharField(write_only=True, validators=[PasswordValidator()]) class Meta(object): """Meta info""" @@ -214,7 +251,7 @@ class GuardianDetailSerializer(serializers.ModelSerializer): """Meta info""" model = Guardian fields = ['id', 'email', 'first_name', 'last_name', 'country_code', 'phone', 'gender', 'dob', - 'guardian_code','is_active', 'is_complete_profile', 'created_at', 'image', + 'guardian_code','is_active', 'is_complete_profile', 'created_at', 'image', 'is_deleted' 'updated_at'] class TaskDetailsSerializer(serializers.ModelSerializer): """Task detail serializer""" @@ -340,7 +377,7 @@ class GuardianProfileSerializer(serializers.ModelSerializer): fields = ['id', 'email', 'first_name', 'last_name', 'country_name','country_code', 'phone', 'gender', 'dob', 'guardian_code', 'notification_count', 'total_count', 'complete_field_count', 'referral_code', 'is_active', 'is_complete_profile', 'created_at', 'image', 'signup_method', - 'updated_at', 'passcode'] + 'updated_at', 'passcode','is_deleted'] class ApproveJuniorSerializer(serializers.ModelSerializer): diff --git a/guardian/views.py b/guardian/views.py index 67fe6ef..fc52a8e 100644 --- a/guardian/views.py +++ b/guardian/views.py @@ -255,31 +255,29 @@ class ApproveJuniorAPIView(viewsets.ViewSet): serializer_class = ApproveJuniorSerializer permission_classes = [IsAuthenticated] - def get_queryset(self): - """Get the queryset for the view""" - guardian = Guardian.objects.filter(user__email=self.request.user).last() - # fetch junior query - junior_queryset = Junior.objects.filter(id=self.request.data.get('junior_id')).last() - return guardian, junior_queryset def create(self, request, *args, **kwargs): """ junior list""" try: - queryset = self.get_queryset() + guardian = Guardian.objects.filter(user__email=self.request.user).last() + # fetch junior query + junior_queryset = Junior.objects.filter(id=self.request.data.get('junior_id')).last() + if junior_queryset and junior_queryset.is_deleted: + return custom_error_response(ERROR_CODE['2073'], response_status=status.HTTP_400_BAD_REQUEST) # action 1 is use for approve and 2 for reject if request.data['action'] == '1': # use ApproveJuniorSerializer serializer - serializer = ApproveJuniorSerializer(context={"guardian_code": queryset[0].guardian_code, - "junior": queryset[1], "action": request.data['action']}, + serializer = ApproveJuniorSerializer(context={"guardian_code": guardian.guardian_code, + "junior": junior_queryset, "action": request.data['action']}, data=request.data) if serializer.is_valid(): # save serializer serializer.save() return custom_response(SUCCESS_CODE['3023'], serializer.data, response_status=status.HTTP_200_OK) else: - queryset[1].guardian_code = None - queryset[1].guardian_code_status = str(NUMBER['one']) - queryset[1].save() + junior_queryset.guardian_code = None + junior_queryset.guardian_code_status = str(NUMBER['one']) + junior_queryset.save() return custom_response(SUCCESS_CODE['3024'], response_status=status.HTTP_200_OK) except Exception as e: return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST) @@ -290,34 +288,31 @@ class ApproveTaskAPIView(viewsets.ViewSet): serializer_class = ApproveTaskSerializer permission_classes = [IsAuthenticated] - def get_queryset(self): - """Get the queryset for the view""" - guardian = Guardian.objects.filter(user__email=self.request.user).last() - # task query - task_queryset = JuniorTask.objects.filter(id=self.request.data.get('task_id'), - guardian=guardian, - junior=self.request.data.get('junior_id')).last() - return guardian, task_queryset - def create(self, request, *args, **kwargs): """ junior list""" # action 1 is use for approve and 2 for reject try: - queryset = self.get_queryset() + guardian = Guardian.objects.filter(user__email=self.request.user).last() + # task query + task_queryset = JuniorTask.objects.filter(id=self.request.data.get('task_id'), + guardian=guardian, + junior=self.request.data.get('junior_id')).last() + if task_queryset and task_queryset.junior.is_deleted: + return custom_error_response(ERROR_CODE['2072'], response_status=status.HTTP_400_BAD_REQUEST) # use ApproveJuniorSerializer serializer - serializer = ApproveTaskSerializer(context={"guardian_code": queryset[0].guardian_code, - "task_instance": queryset[1], + serializer = ApproveTaskSerializer(context={"guardian_code": guardian.guardian_code, + "task_instance": task_queryset, "action": str(request.data['action']), "junior": self.request.data['junior_id']}, data=request.data) unexpected_task_status = [str(NUMBER['five']), str(NUMBER['six'])] if (str(request.data['action']) == str(NUMBER['one']) and serializer.is_valid() - and queryset[1] and queryset[1].task_status not in unexpected_task_status): + and task_queryset and task_queryset.task_status not in unexpected_task_status): # save serializer serializer.save() return custom_response(SUCCESS_CODE['3025'], response_status=status.HTTP_200_OK) elif (str(request.data['action']) == str(NUMBER['two']) and serializer.is_valid() - and queryset[1] and queryset[1].task_status not in unexpected_task_status): + and task_queryset and task_queryset.task_status not in unexpected_task_status): # save serializer serializer.save() return custom_response(SUCCESS_CODE['3026'], response_status=status.HTTP_200_OK) diff --git a/junior/admin.py b/junior/admin.py index 6c6cdf9..2ffda51 100644 --- a/junior/admin.py +++ b/junior/admin.py @@ -3,8 +3,9 @@ from django.contrib import admin """Import Django app""" from .models import (Junior, JuniorPoints, JuniorGuardianRelationship, JuniorArticlePoints, JuniorArticle, - JuniorArticleCard) + JuniorArticleCard, FAQ) # Register your models here. +admin.site.register(FAQ) @admin.register(JuniorArticle) class JuniorArticleAdmin(admin.ModelAdmin): """Junior Admin""" diff --git a/junior/migrations/0026_faq_alter_juniorarticle_options_and_more.py b/junior/migrations/0026_faq_alter_juniorarticle_options_and_more.py new file mode 100644 index 0000000..12243a2 --- /dev/null +++ b/junior/migrations/0026_faq_alter_juniorarticle_options_and_more.py @@ -0,0 +1,39 @@ +# Generated by Django 4.2.2 on 2023-08-17 09:04 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('junior', '0025_alter_juniorarticle_junior'), + ] + + operations = [ + migrations.CreateModel( + name='FAQ', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('question', models.IntegerField(max_length=100)), + ('description', models.CharField(max_length=500)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ], + options={ + 'verbose_name': 'FAQ', + 'verbose_name_plural': 'FAQ', + }, + ), + migrations.AlterModelOptions( + name='juniorarticle', + options={'verbose_name': 'Junior Article', 'verbose_name_plural': 'Junior Article'}, + ), + migrations.AlterModelOptions( + name='juniorarticlecard', + options={'verbose_name': 'Junior Article Card', 'verbose_name_plural': 'Junior Article Card'}, + ), + migrations.AlterModelOptions( + name='juniorarticlepoints', + options={'verbose_name': 'Junior Article Points', 'verbose_name_plural': 'Junior Article Points'}, + ), + ] diff --git a/junior/migrations/0027_alter_faq_question.py b/junior/migrations/0027_alter_faq_question.py new file mode 100644 index 0000000..46fefd8 --- /dev/null +++ b/junior/migrations/0027_alter_faq_question.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.2 on 2023-08-17 09:37 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('junior', '0026_faq_alter_juniorarticle_options_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='faq', + name='question', + field=models.CharField(max_length=100), + ), + ] diff --git a/junior/migrations/0028_faq_status.py b/junior/migrations/0028_faq_status.py new file mode 100644 index 0000000..bdfbf67 --- /dev/null +++ b/junior/migrations/0028_faq_status.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.2 on 2023-08-17 10:28 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('junior', '0027_alter_faq_question'), + ] + + operations = [ + migrations.AddField( + model_name='faq', + name='status', + field=models.IntegerField(blank=True, default=1, null=True), + ), + ] diff --git a/junior/migrations/0029_junior_is_deleted.py b/junior/migrations/0029_junior_is_deleted.py new file mode 100644 index 0000000..a39f60f --- /dev/null +++ b/junior/migrations/0029_junior_is_deleted.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.2 on 2023-08-17 12:45 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('junior', '0028_faq_status'), + ] + + operations = [ + migrations.AddField( + model_name='junior', + name='is_deleted', + field=models.BooleanField(default=False), + ), + ] diff --git a/junior/models.py b/junior/models.py index 025843e..773557b 100644 --- a/junior/models.py +++ b/junior/models.py @@ -68,6 +68,8 @@ class Junior(models.Model): is_password_set = models.BooleanField(default=True) # junior profile is complete or not""" is_complete_profile = models.BooleanField(default=False) + # junior profile deleted or not""" + is_deleted = models.BooleanField(default=False) # passcode of the junior profile""" passcode = models.IntegerField(null=True, blank=True, default=None) # junior is verified or not""" @@ -158,6 +160,12 @@ class JuniorArticlePoints(models.Model): created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) + class Meta(object): + """ Meta class """ + verbose_name = 'Junior Article Points' + # another name of the model""" + verbose_name_plural = 'Junior Article Points' + def __str__(self): """Return title""" return f'{self.id} | {self.question}' @@ -178,6 +186,12 @@ class JuniorArticle(models.Model): created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) + class Meta(object): + """ Meta class """ + verbose_name = 'Junior Article' + # another name of the model""" + verbose_name_plural = 'Junior Article' + def __str__(self): """Return title""" return f'{self.id} | {self.article}' @@ -197,6 +211,34 @@ class JuniorArticleCard(models.Model): created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) + class Meta(object): + """ Meta class """ + verbose_name = 'Junior Article Card' + # another name of the model""" + verbose_name_plural = 'Junior Article Card' + def __str__(self): """Return title""" return f'{self.id} | {self.article}' + + +class FAQ(models.Model): + """FAQ model""" + # questions""" + question = models.CharField(max_length=100) + # answer""" + description = models.CharField(max_length=500) + # status + status = models.IntegerField(default=1, null=True, blank=True) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + class Meta(object): + """ Meta class """ + verbose_name = 'FAQ' + # another name of the model""" + verbose_name_plural = 'FAQ' + + def __str__(self): + """Return email id""" + return f'{self.question}' diff --git a/junior/serializers.py b/junior/serializers.py index f932a26..b4aa54f 100644 --- a/junior/serializers.py +++ b/junior/serializers.py @@ -12,7 +12,7 @@ from rest_framework_simplejwt.tokens import RefreshToken # local imports from account.utils import send_otp_email, generate_code -from junior.models import Junior, JuniorPoints, JuniorGuardianRelationship, JuniorArticlePoints +from junior.models import Junior, JuniorPoints, JuniorGuardianRelationship, JuniorArticlePoints, FAQ 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, @@ -147,7 +147,7 @@ class JuniorDetailSerializer(serializers.ModelSerializer): model = Junior fields = ['id', 'email', 'first_name', 'last_name', 'country_code', 'phone', 'gender', 'dob', 'guardian_code', 'image', 'is_invited', 'referral_code','is_active', 'is_complete_profile', - 'created_at', 'image', 'updated_at'] + 'created_at', 'image', 'is_deleted', 'updated_at'] class JuniorDetailListSerializer(serializers.ModelSerializer): """junior serializer""" @@ -214,7 +214,8 @@ class JuniorDetailListSerializer(serializers.ModelSerializer): fields = ['id', 'email', 'first_name', 'last_name', 'country_code', 'country_name', 'phone', 'gender', 'dob', 'guardian_code', 'referral_code','is_active', 'is_complete_profile', 'created_at', 'image', 'updated_at', 'assigned_task','points', 'pending_task', 'in_progress_task', 'completed_task', - 'requested_task', 'rejected_task', 'position', 'is_invited', 'guardian_code_status'] + 'requested_task', 'rejected_task', 'position', 'is_invited', 'guardian_code_status', + 'is_deleted'] class JuniorProfileSerializer(serializers.ModelSerializer): """junior serializer""" @@ -257,7 +258,7 @@ class JuniorProfileSerializer(serializers.ModelSerializer): fields = ['id', 'email', 'first_name', 'last_name', 'country_name', 'country_code', 'phone', 'gender', 'dob', 'guardian_code', 'referral_code','is_active', 'is_complete_profile', 'created_at', 'image', 'updated_at', 'notification_count', 'total_count', 'complete_field_count', 'signup_method', - 'is_invited', 'passcode', 'guardian_code_approved'] + 'is_invited', 'passcode', 'guardian_code_approved', 'is_deleted'] class AddJuniorSerializer(serializers.ModelSerializer): """Add junior serializer""" @@ -395,7 +396,7 @@ class JuniorPointsSerializer(serializers.ModelSerializer): """Meta info""" model = Junior fields = ['junior_id', 'total_points', 'position', 'pending_task', 'in_progress_task', 'completed_task', - 'requested_task', 'rejected_task', 'expired_task'] + 'requested_task', 'rejected_task', 'expired_task', 'is_deleted'] class AddGuardianSerializer(serializers.ModelSerializer): """Add guardian serializer""" @@ -508,3 +509,12 @@ class RemoveGuardianCodeSerializer(serializers.ModelSerializer): instance.guardian_code_status = str(NUMBER['one']) instance.save() return instance + +class FAQSerializer(serializers.ModelSerializer): + # FAQ Serializer + + class Meta(object): + # meta info + model = FAQ + fields = ('id', 'question', 'description') + diff --git a/junior/urls.py b/junior/urls.py index b145d4f..08fe33a 100644 --- a/junior/urls.py +++ b/junior/urls.py @@ -6,7 +6,7 @@ from .views import (UpdateJuniorProfile, ValidateGuardianCode, JuniorListAPIView CompleteJuniorTaskAPIView, JuniorPointsListAPIView, ValidateReferralCode, InviteGuardianAPIView, StartTaskAPIView, ReAssignJuniorTaskAPIView, StartArticleAPIView, StartAssessmentAPIView, CheckAnswerAPIView, CompleteArticleAPIView, ReadArticleCardAPIView, - CreateArticleCardAPIView, RemoveGuardianCodeAPIView) + CreateArticleCardAPIView, RemoveGuardianCodeAPIView, FAQViewSet) """Third party import""" from rest_framework import routers @@ -51,6 +51,8 @@ router.register('start-assessment', StartAssessmentAPIView, basename='start-asse router.register('check-answer', CheckAnswerAPIView, basename='check-answer') # start article""" router.register('create-article-card', CreateArticleCardAPIView, basename='create-article-card') +# FAQ API +router.register('faq', FAQViewSet, basename='faq') # Define url pattern""" urlpatterns = [ path('api/v1/', include(router.urls)), diff --git a/junior/views.py b/junior/views.py index 6b8bc2f..7a83b0a 100644 --- a/junior/views.py +++ b/junior/views.py @@ -10,6 +10,8 @@ from django.db.models import F import datetime import requests + +from rest_framework.viewsets import GenericViewSet, mixins """Django app import""" # Import guardian's model, @@ -30,11 +32,11 @@ import requests # Import constants from django.db.models import Sum from junior.models import (Junior, JuniorPoints, JuniorGuardianRelationship, JuniorArticlePoints, JuniorArticle, - JuniorArticleCard) + JuniorArticleCard, FAQ) from .serializers import (CreateJuniorSerializer, JuniorDetailListSerializer, AddJuniorSerializer, RemoveJuniorSerializer, CompleteTaskSerializer, JuniorPointsSerializer, AddGuardianSerializer, StartTaskSerializer, ReAssignTaskSerializer, - RemoveGuardianCodeSerializer) + RemoveGuardianCodeSerializer, FAQSerializer) from guardian.models import Guardian, JuniorTask from guardian.serializers import TaskDetailsSerializer, TaskDetailsjuniorSerializer from base.messages import ERROR_CODE, SUCCESS_CODE @@ -337,6 +339,8 @@ class CompleteJuniorTaskAPIView(views.APIView): task_queryset = JuniorTask.objects.filter(id=task_id, junior__auth__email=self.request.user ).select_related('guardian', 'junior').last() if task_queryset: + if task_queryset.junior.is_deleted: + return custom_error_response(ERROR_CODE['2074'], response_status=status.HTTP_400_BAD_REQUEST) # use CompleteTaskSerializer serializer if task_queryset.task_status in [str(NUMBER['four']), str(NUMBER['five'])]: """Already request send """ @@ -650,3 +654,49 @@ class RemoveGuardianCodeAPIView(views.APIView): return custom_error_response(ERROR_CODE['2047'], response_status=status.HTTP_400_BAD_REQUEST) except Exception as e: return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST) + + +class FAQViewSet(GenericViewSet, mixins.CreateModelMixin, + mixins.ListModelMixin): + """FAQ view set""" + + serializer_class = FAQSerializer + permission_classes = [IsAuthenticated] + http_method_names = ['get', 'post'] + + def get_queryset(self): + return FAQ.objects.all() + + def create(self, request, *args, **kwargs): + """ + faq create api method + :param request: + :param args: + :param kwargs: + :return: success message + """ + obj_data = [FAQ(**item) for item in request.data] + try: + FAQ.objects.bulk_create(obj_data) + return custom_response(SUCCESS_CODE["3045"], response_status=status.HTTP_200_OK) + except Exception as e: + return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST) + + + def list(self, request, *args, **kwargs): + """ + article list api method + :param request: + :param args: + :param kwargs: + :return: list of article + """ + queryset = self.get_queryset() + paginator = self.pagination_class() + paginated_queryset = paginator.paginate_queryset(queryset, request) + serializer = self.serializer_class(paginated_queryset, many=True) + return custom_response(None, data=serializer.data, response_status=status.HTTP_200_OK) + + + + diff --git a/web_admin/serializers/analytics_serializer.py b/web_admin/serializers/analytics_serializer.py index ce6c72e..0e3418a 100644 --- a/web_admin/serializers/analytics_serializer.py +++ b/web_admin/serializers/analytics_serializer.py @@ -28,7 +28,7 @@ class JuniorLeaderboardSerializer(serializers.ModelSerializer): meta class """ model = Junior - fields = ('id', 'name', 'first_name', 'last_name', 'is_active', 'image') + fields = ('id', 'name', 'first_name', 'last_name', 'is_active', 'image', 'is_deleted') @staticmethod def get_name(obj): diff --git a/web_admin/serializers/user_management_serializer.py b/web_admin/serializers/user_management_serializer.py index 3544c66..21a0a3b 100644 --- a/web_admin/serializers/user_management_serializer.py +++ b/web_admin/serializers/user_management_serializer.py @@ -108,7 +108,7 @@ class GuardianSerializer(serializers.ModelSerializer): """ model = Guardian fields = ('id', 'name', 'first_name', 'last_name', 'username', 'dob', 'gender', 'country_code', 'phone', - 'is_active', 'country_name', 'image', 'email') + 'is_active', 'country_name', 'image', 'email', 'is_deleted') def validate(self, attrs): """ @@ -187,7 +187,7 @@ class JuniorSerializer(serializers.ModelSerializer): """ model = Junior fields = ('id', 'name', 'first_name', 'last_name', 'username', 'dob', 'gender', 'country_code', 'phone', - 'is_active', 'country_name', 'image', 'email') + 'is_active', 'country_name', 'image', 'email', 'is_deleted') def validate(self, attrs): """