From f91724426530c10ecdb6322a47875069b6f1936d Mon Sep 17 00:00:00 2001 From: jain Date: Mon, 7 Aug 2023 19:12:14 +0530 Subject: [PATCH 01/11] junior article points table --- guardian/views.py | 2 +- junior/migrations/0019_juniorarticlepoints.py | 30 +++++++++++++++++++ junior/models.py | 22 +++++++++++++- 3 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 junior/migrations/0019_juniorarticlepoints.py diff --git a/guardian/views.py b/guardian/views.py index 1fa4e1b..ee86199 100644 --- a/guardian/views.py +++ b/guardian/views.py @@ -345,6 +345,6 @@ class GuardianListAPIView(viewsets.ModelViewSet): # use GuardianDetailListSerializer serializer serializer = GuardianDetailListSerializer(guardian_data, many=True) return custom_response(None, serializer.data, response_status=status.HTTP_200_OK) - return custom_error_response(ERROR_CODE['2068'], response_status=status.HTTP_200_OK) + return custom_response(ERROR_CODE['2068'], response_status=status.HTTP_200_OK) except Exception as e: return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST) diff --git a/junior/migrations/0019_juniorarticlepoints.py b/junior/migrations/0019_juniorarticlepoints.py new file mode 100644 index 0000000..1112702 --- /dev/null +++ b/junior/migrations/0019_juniorarticlepoints.py @@ -0,0 +1,30 @@ +# Generated by Django 4.2.2 on 2023-08-07 13:29 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('web_admin', '0004_alter_surveyoption_survey'), + ('junior', '0018_remove_junior_relationship_and_more'), + ] + + operations = [ + migrations.CreateModel( + name='JuniorArticlePoints', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('earn_points', models.IntegerField(blank=True, default=5, null=True)), + ('is_attempt', models.BooleanField(default=False)), + ('is_answer_correct', models.BooleanField(default=False)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('article', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='junior_articles', to='web_admin.article')), + ('junior', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='juniors_details', to='junior.junior', verbose_name='Junior')), + ('question', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='questions', to='web_admin.articlesurvey')), + ('submitted_answer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='submitted_answer', to='web_admin.surveyoption')), + ], + ), + ] diff --git a/junior/models.py b/junior/models.py index b18cbf5..908822c 100644 --- a/junior/models.py +++ b/junior/models.py @@ -9,7 +9,8 @@ from django.contrib.postgres.fields import ArrayField from base.constants import GENDERS, SIGNUP_METHODS, RELATIONSHIP # Import guardian's model from guardian.models import Guardian - +# Import web admin's model +from web_admin.models import SurveyOption, ArticleSurvey, Article """Define User model""" User = get_user_model() # Create your models here. @@ -137,3 +138,22 @@ class JuniorGuardianRelationship(models.Model): return f'{self.guardian.user}' +class JuniorArticlePoints(models.Model): + """ + Survey Options model + """ + # associated junior with the task + junior = models.ForeignKey(Junior, on_delete=models.CASCADE, related_name='juniors_details', verbose_name='Junior') + article = models.ForeignKey(Article, on_delete=models.CASCADE, related_name='junior_articles') + question = models.ForeignKey(ArticleSurvey, on_delete=models.CASCADE, related_name='questions') + submitted_answer = models.ForeignKey(SurveyOption, on_delete=models.CASCADE, related_name='submitted_answer') + # earn points""" + earn_points = models.IntegerField(blank=True, null=True, default=5) + is_attempt = models.BooleanField(default=False) + is_answer_correct = models.BooleanField(default=False) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + def __str__(self): + """Return title""" + return f'{self.id} | {self.question}' From 659641467525ee06c6e2104f9d96788394cd97a3 Mon Sep 17 00:00:00 2001 From: jain Date: Tue, 8 Aug 2023 11:46:27 +0530 Subject: [PATCH 02/11] guardian list api changes --- base/constants.py | 6 +++ guardian/serializers.py | 39 +++++++++++++++++-- guardian/views.py | 4 +- .../0020_junior_guardian_code_status.py | 18 +++++++++ junior/models.py | 5 ++- junior/serializers.py | 12 ++++-- web_admin/serializers/article_serializer.py | 7 +++- 7 files changed, 80 insertions(+), 11 deletions(-) create mode 100644 junior/migrations/0020_junior_guardian_code_status.py diff --git a/base/constants.py b/base/constants.py index 6022f62..e38cb29 100644 --- a/base/constants.py +++ b/base/constants.py @@ -70,6 +70,12 @@ SIGNUP_METHODS = ( ('2', 'google'), ('3', 'apple') ) +# guardian code status +GUARDIAN_CODE_STATUS = ( + ('1', 'no guardian code'), + ('2', 'exist guardian code'), + ('3', 'request for guardian code') +) # relationship RELATIONSHIP = ( ('1', 'parent'), diff --git a/guardian/serializers.py b/guardian/serializers.py index 04acb9d..1fa385b 100644 --- a/guardian/serializers.py +++ b/guardian/serializers.py @@ -394,11 +394,20 @@ class GuardianDetailListSerializer(serializers.ModelSerializer): email = serializers.SerializerMethodField('get_email') image = serializers.SerializerMethodField('get_image') guardian_id = serializers.SerializerMethodField('get_guardian_id') + guardian_code = serializers.SerializerMethodField('get_guardian_code') + gender = serializers.SerializerMethodField('get_gender') + phone = serializers.SerializerMethodField('get_phone') + country_name = serializers.SerializerMethodField('get_country_name') + dob = serializers.SerializerMethodField('get_dob') + guardian_code_status = serializers.SerializerMethodField('get_guardian_code_status') + # code info + class Meta(object): """Meta info""" model = JuniorGuardianRelationship - fields = ['guardian_id', 'first_name', 'last_name', 'email', 'relationship', 'image', 'created_at', + fields = ['guardian_id', 'first_name', 'last_name', 'email', 'relationship', 'image', 'dob', + 'guardian_code', 'gender', 'phone', 'country_name', 'created_at', 'guardian_code_status', 'updated_at'] def get_guardian_id(self,obj): @@ -413,9 +422,33 @@ class GuardianDetailListSerializer(serializers.ModelSerializer): return obj.guardian.user.last_name def get_email(self,obj): - """emailof guardian""" + """email of guardian""" return obj.guardian.user.email def get_image(self,obj): - """first name of guardian""" + """guardian image""" return obj.guardian.image + + def get_guardian_code(self,obj): + """ guardian code""" + return obj.guardian.guardian_code + + def get_gender(self,obj): + """ guardian gender""" + return obj.guardian.gender + + def get_phone(self,obj): + """guardian phone""" + return obj.guardian.phone + + def get_country_name(self,obj): + """ guardian country name """ + return obj.guardian.country_name + + def get_dob(self,obj): + """guardian dob """ + return obj.guardian.dob + + def get_guardian_code_status(self,obj): + """guardian code status""" + return obj.junior.guardian_code_status diff --git a/guardian/views.py b/guardian/views.py index ee86199..775932a 100644 --- a/guardian/views.py +++ b/guardian/views.py @@ -34,7 +34,7 @@ from account.models import UserEmailOtp, UserNotification from .tasks import generate_otp from account.utils import custom_response, custom_error_response, OTP_EXPIRY, send_otp_email from base.messages import ERROR_CODE, SUCCESS_CODE -from base.constants import NUMBER +from base.constants import NUMBER, GUARDIAN_CODE_STATUS from .utils import upload_image_to_alibaba from notifications.constants import REGISTRATION, TASK_CREATED, LEADERBOARD_RANKING from notifications.utils import send_notification @@ -345,6 +345,6 @@ class GuardianListAPIView(viewsets.ModelViewSet): # use GuardianDetailListSerializer serializer serializer = GuardianDetailListSerializer(guardian_data, many=True) return custom_response(None, serializer.data, response_status=status.HTTP_200_OK) - return custom_response(ERROR_CODE['2068'], response_status=status.HTTP_200_OK) + return custom_response({"status": GUARDIAN_CODE_STATUS['1']},response_status=status.HTTP_200_OK) except Exception as e: return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST) diff --git a/junior/migrations/0020_junior_guardian_code_status.py b/junior/migrations/0020_junior_guardian_code_status.py new file mode 100644 index 0000000..62e09d3 --- /dev/null +++ b/junior/migrations/0020_junior_guardian_code_status.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.2 on 2023-08-08 05:43 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('junior', '0019_juniorarticlepoints'), + ] + + operations = [ + migrations.AddField( + model_name='junior', + name='guardian_code_status', + field=models.CharField(blank=True, choices=[('1', 'no guardian code'), ('2', 'exist guardian code'), ('3', 'request for guardian code')], default='1', max_length=31, null=True), + ), + ] diff --git a/junior/models.py b/junior/models.py index 908822c..3adf459 100644 --- a/junior/models.py +++ b/junior/models.py @@ -6,7 +6,7 @@ from django.contrib.auth import get_user_model """Import ArrayField""" from django.contrib.postgres.fields import ArrayField """Import django app""" -from base.constants import GENDERS, SIGNUP_METHODS, RELATIONSHIP +from base.constants import GENDERS, SIGNUP_METHODS, RELATIONSHIP, GUARDIAN_CODE_STATUS # Import guardian's model from guardian.models import Guardian # Import web admin's model @@ -74,6 +74,9 @@ class Junior(models.Model): is_verified = models.BooleanField(default=False) """guardian code is approved or not""" guardian_code_approved = models.BooleanField(default=False) + # guardian code status""" + guardian_code_status = models.CharField(max_length=31, choices=GUARDIAN_CODE_STATUS, default='1', + null=True, blank=True) # Profile created and updated time""" created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) diff --git a/junior/serializers.py b/junior/serializers.py index 1dc04da..178ba14 100644 --- a/junior/serializers.py +++ b/junior/serializers.py @@ -12,7 +12,8 @@ from account.utils import send_otp_email, generate_code from junior.models import Junior, JuniorPoints, JuniorGuardianRelationship 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 +from base.constants import (PENDING, IN_PROGRESS, REJECTED, REQUESTED, COMPLETED, NUMBER, JUN, ZOD, EXPIRED, + GUARDIAN_CODE_STATUS) from guardian.models import Guardian, JuniorTask from account.models import UserEmailOtp, UserNotification from junior.utils import junior_notification_email, junior_approval_mail @@ -280,7 +281,8 @@ class AddJuniorSerializer(serializers.ModelSerializer): junior_code=generate_code(JUN, user_data.id), referral_code=generate_code(ZOD, user_data.id), referral_code_used=guardian_data.referral_code, - is_password_set=False, is_verified=True) + is_password_set=False, is_verified=True, + guardian_code_status=GUARDIAN_CODE_STATUS['2']) JuniorGuardianRelationship.objects.create(guardian=guardian_data, junior=junior_data, relationship=relationship) """Generate otp""" @@ -399,13 +401,15 @@ class AddGuardianSerializer(serializers.ModelSerializer): relationship = self.context['relationship'] full_name = self.context['first_name'] + ' ' + self.context['last_name'] junior_data = Junior.objects.filter(auth__username=junior).last() + junior_data.guardian_code_status = GUARDIAN_CODE_STATUS['3'] + junior_data.save() instance = User.objects.filter(username=email).last() if instance: guardian_data = Guardian.objects.filter(user=instance).update(is_invited=True, - referral_code=generate_code(ZOD, + referral_code=generate_code(ZOD, instance.id), referral_code_used=junior_data.referral_code, - is_verified=True) + is_verified=True) UserNotification.objects.get_or_create(user=instance) return guardian_data else: diff --git a/web_admin/serializers/article_serializer.py b/web_admin/serializers/article_serializer.py index 5b42686..c338d04 100644 --- a/web_admin/serializers/article_serializer.py +++ b/web_admin/serializers/article_serializer.py @@ -221,15 +221,20 @@ class ArticleListSerializer(serializers.ModelSerializer): """ article_cards = ArticleCardSerializer(many=True) total_points = serializers.SerializerMethodField('get_total_points') + is_completed = serializers.SerializerMethodField('get_is_completed') class Meta: """ meta class """ model = Article - fields = ('id', 'title', 'description', 'article_cards', 'total_points') + fields = ('id', 'title', 'description', 'article_cards', 'total_points', 'is_completed') def get_total_points(self, obj): """total points of article""" total_question = ArticleSurvey.objects.filter(article=obj).count() return total_question * 5 + + def get_is_completed(self, obj): + """complete all question""" + return False \ No newline at end of file From f57b111555aaca2e4c259c5bc53b45de2b534424 Mon Sep 17 00:00:00 2001 From: jain Date: Tue, 8 Aug 2023 11:48:53 +0530 Subject: [PATCH 03/11] guardian list api changes --- web_admin/serializers/article_serializer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_admin/serializers/article_serializer.py b/web_admin/serializers/article_serializer.py index c338d04..695401e 100644 --- a/web_admin/serializers/article_serializer.py +++ b/web_admin/serializers/article_serializer.py @@ -233,7 +233,7 @@ class ArticleListSerializer(serializers.ModelSerializer): def get_total_points(self, obj): """total points of article""" total_question = ArticleSurvey.objects.filter(article=obj).count() - return total_question * 5 + return total_question * NUMBER['five'] def get_is_completed(self, obj): """complete all question""" From 85e4ae876135775e1ac48424384cba335e40c0d0 Mon Sep 17 00:00:00 2001 From: jain Date: Tue, 8 Aug 2023 13:54:04 +0530 Subject: [PATCH 04/11] junior position changes and decrease api response time --- account/views.py | 9 ---- guardian/serializers.py | 6 ++- guardian/views.py | 3 -- junior/admin.py | 6 ++- junior/urls.py | 4 +- junior/views.py | 49 +++++++++++++++++---- web_admin/models.py | 4 +- web_admin/serializers/article_serializer.py | 2 +- 8 files changed, 55 insertions(+), 28 deletions(-) diff --git a/account/views.py b/account/views.py index 61c4e0e..b36d75d 100644 --- a/account/views.py +++ b/account/views.py @@ -245,7 +245,6 @@ class ForgotPasswordAPIView(views.APIView): class SendPhoneOtp(viewsets.ModelViewSet): """Send otp on phone""" - queryset = UserPhoneOtp.objects.all() serializer_class = UserPhoneOtpSerializer def create(self, request, *args, **kwargs): otp = generate_otp() @@ -262,7 +261,6 @@ class SendPhoneOtp(viewsets.ModelViewSet): class UserPhoneVerification(viewsets.ModelViewSet): """Send otp on phone""" - queryset = UserPhoneOtp.objects.all() serializer_class = UserPhoneOtpSerializer def list(self, request, *args, **kwargs): try: @@ -376,7 +374,6 @@ class AdminLoginViewSet(viewsets.GenericViewSet): class UserEmailVerification(viewsets.ModelViewSet): """User Email verification""" serializer_class = EmailVerificationSerializer - queryset = UserEmailOtp.objects.all() def list(self, request, *args, **kwargs): try: @@ -419,7 +416,6 @@ class UserEmailVerification(viewsets.ModelViewSet): class ReSendEmailOtp(viewsets.ModelViewSet): """Send otp on phone""" - queryset = UserEmailOtp.objects.all() serializer_class = EmailVerificationSerializer permission_classes = [IsAuthenticated] @@ -442,7 +438,6 @@ class ReSendEmailOtp(viewsets.ModelViewSet): class ProfileAPIViewSet(viewsets.ModelViewSet): """Profile viewset""" - queryset = User.objects.all() serializer_class = JuniorProfileSerializer permission_classes = [IsAuthenticated] @@ -461,7 +456,6 @@ class ProfileAPIViewSet(viewsets.ModelViewSet): class UploadImageAPIViewSet(viewsets.ModelViewSet): """upload task image""" - queryset = DefaultTaskImages.objects.all() serializer_class = DefaultTaskImagesSerializer def create(self, request, *args, **kwargs): """upload images""" @@ -480,7 +474,6 @@ class UploadImageAPIViewSet(viewsets.ModelViewSet): class DefaultImageAPIViewSet(viewsets.ModelViewSet): """Profile viewset""" - queryset = DefaultTaskImages.objects.all() serializer_class = DefaultTaskImagesDetailsSerializer permission_classes = [IsAuthenticated] def list(self, request, *args, **kwargs): @@ -511,7 +504,6 @@ class DeleteUserProfileAPIViewSet(viewsets.GenericViewSet): class UserNotificationAPIViewSet(viewsets.ModelViewSet): """notification viewset""" - queryset = UserNotification.objects.all() serializer_class = UserNotificationSerializer permission_classes = [IsAuthenticated] def list(self, request, *args, **kwargs): @@ -523,7 +515,6 @@ class UserNotificationAPIViewSet(viewsets.ModelViewSet): class UpdateUserNotificationAPIViewSet(viewsets.ModelViewSet): """Update notification viewset""" - queryset = UserNotification.objects.all() serializer_class = UpdateUserNotificationSerializer permission_classes = [IsAuthenticated] diff --git a/guardian/serializers.py b/guardian/serializers.py index 1fa385b..65dd1ea 100644 --- a/guardian/serializers.py +++ b/guardian/serializers.py @@ -67,8 +67,10 @@ class UserSerializer(serializers.ModelSerializer): UserNotification.objects.get_or_create(user=user) if user_type == str(NUMBER['one']): # create junior profile - Junior.objects.create(auth=user, junior_code=generate_code(JUN, user.id), - referral_code=generate_code(ZOD, user.id)) + junior = Junior.objects.create(auth=user, junior_code=generate_code(JUN, user.id), + referral_code=generate_code(ZOD, user.id)) + position = Junior.objects.all().count() + JuniorPoints.objects.create(junior=junior, position=position) if user_type == str(NUMBER['two']): # create guardian profile Guardian.objects.create(user=user, guardian_code=generate_code(GRD, user.id), diff --git a/guardian/views.py b/guardian/views.py index 775932a..9b55cf6 100644 --- a/guardian/views.py +++ b/guardian/views.py @@ -83,7 +83,6 @@ class SignupViewset(viewsets.ModelViewSet): class UpdateGuardianProfile(viewsets.ViewSet): """Update guardian profile""" - queryset = Guardian.objects.all() serializer_class = CreateGuardianSerializer permission_classes = [IsAuthenticated] @@ -117,7 +116,6 @@ class UpdateGuardianProfile(viewsets.ViewSet): class AllTaskListAPIView(viewsets.ModelViewSet): """Update guardian profile""" serializer_class = TaskDetailsSerializer - queryset = JuniorTask.objects.all() permission_classes = [IsAuthenticated] def list(self, request, *args, **kwargs): @@ -229,7 +227,6 @@ class TopJuniorListAPIView(viewsets.ModelViewSet): """Top juniors list""" serializer_class = TopJuniorSerializer permission_classes = [IsAuthenticated] - queryset = JuniorPoints.objects.all() def get_serializer_context(self): # context list diff --git a/junior/admin.py b/junior/admin.py index acd8734..5fdfcce 100644 --- a/junior/admin.py +++ b/junior/admin.py @@ -2,7 +2,7 @@ """Third party Django app""" from django.contrib import admin """Import Django app""" -from .models import Junior, JuniorPoints, JuniorGuardianRelationship +from .models import Junior, JuniorPoints, JuniorGuardianRelationship, JuniorArticlePoints # Register your models here. @admin.register(Junior) class JuniorAdmin(admin.ModelAdmin): @@ -27,3 +27,7 @@ class JuniorGuardianRelationshipAdmin(admin.ModelAdmin): """Junior Admin""" list_display = ['guardian', 'junior', 'relationship'] +@admin.register(JuniorArticlePoints) +class JuniorArticlePointsAdmin(admin.ModelAdmin): + """Junior Admin""" + list_display = ['junior', 'article', 'question', 'submitted_answer'] diff --git a/junior/urls.py b/junior/urls.py index f66fa30..267faef 100644 --- a/junior/urls.py +++ b/junior/urls.py @@ -4,7 +4,7 @@ from django.urls import path, include from .views import (UpdateJuniorProfile, ValidateGuardianCode, JuniorListAPIView, AddJuniorAPIView, InvitedJuniorAPIView, FilterJuniorAPIView, RemoveJuniorAPIView, JuniorTaskListAPIView, CompleteJuniorTaskAPIView, JuniorPointsListAPIView, ValidateReferralCode, - InviteGuardianAPIView, StartTaskAPIView, ReAssignJuniorTaskAPIView) + InviteGuardianAPIView, StartTaskAPIView, ReAssignJuniorTaskAPIView, StartArticleAPIView) """Third party import""" from rest_framework import routers @@ -41,6 +41,8 @@ router.register('junior-points', JuniorPointsListAPIView, basename='junior-point router.register('validate-referral-code', ValidateReferralCode, basename='validate-referral-code') # invite guardian API""" router.register('invite-guardian', InviteGuardianAPIView, basename='invite-guardian') +# start article""" +router.register('start-article', StartArticleAPIView, basename='start-article') # Define url pattern""" urlpatterns = [ path('api/v1/', include(router.urls)), diff --git a/junior/views.py b/junior/views.py index 15cd387..449ac5f 100644 --- a/junior/views.py +++ b/junior/views.py @@ -27,8 +27,8 @@ import requests # Import upload_image_to_alibaba # Import custom_response, custom_error_response # Import constants -from junior.models import Junior, JuniorPoints, JuniorGuardianRelationship -from .serializers import (CreateJuniorSerializer, JuniorDetailListSerializer, AddJuniorSerializer,\ +from junior.models import Junior, JuniorPoints, JuniorGuardianRelationship, JuniorArticlePoints +from .serializers import (CreateJuniorSerializer, JuniorDetailListSerializer, AddJuniorSerializer, RemoveJuniorSerializer, CompleteTaskSerializer, JuniorPointsSerializer, AddGuardianSerializer, StartTaskSerializer, ReAssignTaskSerializer) from guardian.models import Guardian, JuniorTask @@ -40,7 +40,7 @@ from guardian.utils import upload_image_to_alibaba from .utils import update_positions_based_on_points from notifications.utils import send_notification from notifications.constants import REMOVE_JUNIOR - +from web_admin.models import Article, ArticleSurvey, SurveyOption """ Define APIs """ # Define validate guardian code API, # update junior profile, @@ -59,7 +59,6 @@ from notifications.constants import REMOVE_JUNIOR # Create your views here. class UpdateJuniorProfile(viewsets.ViewSet): """Update junior profile""" - queryset = Junior.objects.all() serializer_class = CreateJuniorSerializer permission_classes = [IsAuthenticated] @@ -93,7 +92,6 @@ class UpdateJuniorProfile(viewsets.ViewSet): class ValidateGuardianCode(viewsets.ViewSet): """Check guardian code exist or not""" - queryset = Guardian.objects.all() permission_classes = [IsAuthenticated] def list(self, request, *args, **kwargs): @@ -115,7 +113,6 @@ class JuniorListAPIView(viewsets.ModelViewSet): """Junior list of assosicated guardian""" serializer_class = JuniorDetailListSerializer - queryset = Junior.objects.all() permission_classes = [IsAuthenticated] filter_backends = (SearchFilter,) search_fields = ['auth__first_name', 'auth__last_name'] @@ -180,7 +177,6 @@ class InvitedJuniorAPIView(viewsets.ModelViewSet): """Junior list of assosicated guardian""" serializer_class = JuniorDetailListSerializer - queryset = Junior.objects.all() permission_classes = [IsAuthenticated] pagination_class = PageNumberPagination http_method_names = ('get',) @@ -210,7 +206,6 @@ class FilterJuniorAPIView(viewsets.ModelViewSet): serializer_class = JuniorDetailListSerializer permission_classes = [IsAuthenticated] pagination_class = PageNumberPagination - queryset = Junior.objects.all() http_method_names = ('get',) def get_queryset(self): @@ -268,7 +263,6 @@ class JuniorTaskListAPIView(viewsets.ModelViewSet): serializer_class = TaskDetailsjuniorSerializer permission_classes = [IsAuthenticated] pagination_class = PageNumberPagination - queryset = JuniorTask.objects.all() http_method_names = ('get',) def list(self, request, *args, **kwargs): @@ -458,3 +452,40 @@ class ReAssignJuniorTaskAPIView(views.APIView): return custom_error_response(ERROR_CODE['2066'], 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 StartArticleAPIView(viewsets.ModelViewSet): + """Start article""" + serializer_class = AddGuardianSerializer + permission_classes = [IsAuthenticated] + http_method_names = ('post',) + + def create(self, request, *args, **kwargs): + """ junior list""" + try: + junior_instance = Junior.objects.filter(auth=self.request.user).last() + article_id = request.data.get('article_id') + article_data = Article.objects.filter(id=article_id).last() + if article_data: + print("article_data====>", article_data,'===>',type(article_data)) + question_query = ArticleSurvey.objects.filter(article=article_id) + print("question_query====>",question_query,'===>',type(question_query)) + for question in question_query: + print("question====>", question, '===>', type(question)) + answer = SurveyOption.objects.filter(survey=question) + print("answer===>",answer,'====>',type(answer)) + for ans in answer: + JuniorArticlePoints.objects.create(junior=junior_instance, + article=article_data, + question=question, + submitted_answer=ans) + print("CREATED CREATED") + return custom_response(SUCCESS_CODE['3034'], response_status=status.HTTP_200_OK) + # 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) + except Exception as e: + return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST) diff --git a/web_admin/models.py b/web_admin/models.py index 8a3bb16..5dbef97 100644 --- a/web_admin/models.py +++ b/web_admin/models.py @@ -49,7 +49,7 @@ class ArticleSurvey(models.Model): def __str__(self): """Return title""" - return f'{self.id} | {self.article}' + return f'{self.id} | {self.question}' class SurveyOption(models.Model): @@ -64,7 +64,7 @@ class SurveyOption(models.Model): def __str__(self): """Return title""" - return f'{self.id} | {self.survey}' + return f'{self.id} | {self.option}' class DefaultArticleCardImage(models.Model): diff --git a/web_admin/serializers/article_serializer.py b/web_admin/serializers/article_serializer.py index 695401e..b39d20d 100644 --- a/web_admin/serializers/article_serializer.py +++ b/web_admin/serializers/article_serializer.py @@ -237,4 +237,4 @@ class ArticleListSerializer(serializers.ModelSerializer): def get_is_completed(self, obj): """complete all question""" - return False \ No newline at end of file + return False From 4b23394569bc345d29de5e48d9758cf5bdedad46 Mon Sep 17 00:00:00 2001 From: jain Date: Tue, 8 Aug 2023 15:03:24 +0530 Subject: [PATCH 05/11] top junior api --- guardian/views.py | 1 + 1 file changed, 1 insertion(+) diff --git a/guardian/views.py b/guardian/views.py index 9b55cf6..076f563 100644 --- a/guardian/views.py +++ b/guardian/views.py @@ -225,6 +225,7 @@ class SearchTaskListAPIView(viewsets.ModelViewSet): class TopJuniorListAPIView(viewsets.ModelViewSet): """Top juniors list""" + queryset = JuniorPoints.objects.all() serializer_class = TopJuniorSerializer permission_classes = [IsAuthenticated] From 7d428f5eb5bc6b5776e955c4ac38043a8b3a1c8e Mon Sep 17 00:00:00 2001 From: jain Date: Tue, 8 Aug 2023 16:05:56 +0530 Subject: [PATCH 06/11] junior list api --- base/messages.py | 3 ++- ...er_juniorarticlepoints_submitted_answer.py | 20 ++++++++++++++++ junior/models.py | 3 ++- junior/serializers.py | 4 ++-- junior/views.py | 24 +++++-------------- 5 files changed, 32 insertions(+), 22 deletions(-) create mode 100644 junior/migrations/0021_alter_juniorarticlepoints_submitted_answer.py diff --git a/base/messages.py b/base/messages.py index cf85f2b..05b4ec3 100644 --- a/base/messages.py +++ b/base/messages.py @@ -149,7 +149,8 @@ SUCCESS_CODE = { "3037": "Profile has been updated successfully.", "3038": "Status has been changed successfully.", # notification read - "3039": "Notification read successfully" + "3039": "Notification read successfully", + "3040": "Start article successfully" } """status code error""" STATUS_CODE_ERROR = { diff --git a/junior/migrations/0021_alter_juniorarticlepoints_submitted_answer.py b/junior/migrations/0021_alter_juniorarticlepoints_submitted_answer.py new file mode 100644 index 0000000..45ce9a4 --- /dev/null +++ b/junior/migrations/0021_alter_juniorarticlepoints_submitted_answer.py @@ -0,0 +1,20 @@ +# Generated by Django 4.2.2 on 2023-08-08 09:45 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('web_admin', '0004_alter_surveyoption_survey'), + ('junior', '0020_junior_guardian_code_status'), + ] + + operations = [ + migrations.AlterField( + model_name='juniorarticlepoints', + name='submitted_answer', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='submitted_answer', to='web_admin.surveyoption'), + ), + ] diff --git a/junior/models.py b/junior/models.py index 3adf459..3d2aaa4 100644 --- a/junior/models.py +++ b/junior/models.py @@ -149,7 +149,8 @@ class JuniorArticlePoints(models.Model): junior = models.ForeignKey(Junior, on_delete=models.CASCADE, related_name='juniors_details', verbose_name='Junior') article = models.ForeignKey(Article, on_delete=models.CASCADE, related_name='junior_articles') question = models.ForeignKey(ArticleSurvey, on_delete=models.CASCADE, related_name='questions') - submitted_answer = models.ForeignKey(SurveyOption, on_delete=models.CASCADE, related_name='submitted_answer') + submitted_answer = models.ForeignKey(SurveyOption, on_delete=models.SET_NULL, null=True, + related_name='submitted_answer') # earn points""" earn_points = models.IntegerField(blank=True, null=True, default=5) is_attempt = models.BooleanField(default=False) diff --git a/junior/serializers.py b/junior/serializers.py index 178ba14..f8be6aa 100644 --- a/junior/serializers.py +++ b/junior/serializers.py @@ -282,7 +282,7 @@ class AddJuniorSerializer(serializers.ModelSerializer): referral_code=generate_code(ZOD, user_data.id), referral_code_used=guardian_data.referral_code, is_password_set=False, is_verified=True, - guardian_code_status=GUARDIAN_CODE_STATUS['2']) + guardian_code_status=GUARDIAN_CODE_STATUS[1][0]) JuniorGuardianRelationship.objects.create(guardian=guardian_data, junior=junior_data, relationship=relationship) """Generate otp""" @@ -401,7 +401,7 @@ class AddGuardianSerializer(serializers.ModelSerializer): relationship = self.context['relationship'] full_name = self.context['first_name'] + ' ' + self.context['last_name'] junior_data = Junior.objects.filter(auth__username=junior).last() - junior_data.guardian_code_status = GUARDIAN_CODE_STATUS['3'] + junior_data.guardian_code_status = GUARDIAN_CODE_STATUS[2][0] junior_data.save() instance = User.objects.filter(username=email).last() if instance: diff --git a/junior/views.py b/junior/views.py index 449ac5f..98428ce 100644 --- a/junior/views.py +++ b/junior/views.py @@ -113,6 +113,7 @@ class JuniorListAPIView(viewsets.ModelViewSet): """Junior list of assosicated guardian""" serializer_class = JuniorDetailListSerializer + queryset = Junior.objects.all() permission_classes = [IsAuthenticated] filter_backends = (SearchFilter,) search_fields = ['auth__first_name', 'auth__last_name'] @@ -455,7 +456,6 @@ class ReAssignJuniorTaskAPIView(views.APIView): class StartArticleAPIView(viewsets.ModelViewSet): """Start article""" - serializer_class = AddGuardianSerializer permission_classes = [IsAuthenticated] http_method_names = ('post',) @@ -466,26 +466,14 @@ class StartArticleAPIView(viewsets.ModelViewSet): article_id = request.data.get('article_id') article_data = Article.objects.filter(id=article_id).last() if article_data: - print("article_data====>", article_data,'===>',type(article_data)) question_query = ArticleSurvey.objects.filter(article=article_id) - print("question_query====>",question_query,'===>',type(question_query)) for question in question_query: - print("question====>", question, '===>', type(question)) - answer = SurveyOption.objects.filter(survey=question) - print("answer===>",answer,'====>',type(answer)) - for ans in answer: + if not JuniorArticlePoints.objects.filter(junior=junior_instance, + article=article_data, + question=question): JuniorArticlePoints.objects.create(junior=junior_instance, article=article_data, - question=question, - submitted_answer=ans) - print("CREATED CREATED") - return custom_response(SUCCESS_CODE['3034'], response_status=status.HTTP_200_OK) - # 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) + question=question) + return custom_response(SUCCESS_CODE['3040'], response_status=status.HTTP_200_OK) except Exception as e: return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST) From f75201b3dd0114078133a25c9da683dbf7e125ca Mon Sep 17 00:00:00 2001 From: jain Date: Tue, 8 Aug 2023 16:36:03 +0530 Subject: [PATCH 07/11] changes in add junior api --- guardian/views.py | 2 +- junior/serializers.py | 5 +++-- junior/views.py | 17 ++++++++++++++--- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/guardian/views.py b/guardian/views.py index 076f563..3e265b0 100644 --- a/guardian/views.py +++ b/guardian/views.py @@ -343,6 +343,6 @@ class GuardianListAPIView(viewsets.ModelViewSet): # use GuardianDetailListSerializer serializer serializer = GuardianDetailListSerializer(guardian_data, many=True) return custom_response(None, serializer.data, response_status=status.HTTP_200_OK) - return custom_response({"status": GUARDIAN_CODE_STATUS['1']},response_status=status.HTTP_200_OK) + return custom_response({"status": GUARDIAN_CODE_STATUS[1][0]}, response_status=status.HTTP_200_OK) except Exception as e: return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST) diff --git a/junior/serializers.py b/junior/serializers.py index f8be6aa..24e8b21 100644 --- a/junior/serializers.py +++ b/junior/serializers.py @@ -254,11 +254,10 @@ class JuniorProfileSerializer(serializers.ModelSerializer): class AddJuniorSerializer(serializers.ModelSerializer): """Add junior serializer""" - class Meta(object): """Meta info""" model = Junior - fields = ['id', 'gender','dob', 'is_invited'] + fields = ['id', 'gender', 'dob', 'is_invited'] def create(self, validated_data): @@ -267,6 +266,7 @@ class AddJuniorSerializer(serializers.ModelSerializer): email = self.context['email'] guardian = self.context['user'] relationship = self.context['relationship'] + profile_image = self.context['image'] full_name = self.context['first_name'] + ' ' + self.context['last_name'] guardian_data = Guardian.objects.filter(user__username=guardian).last() user_data = User.objects.create(username=email, email=email, @@ -276,6 +276,7 @@ class AddJuniorSerializer(serializers.ModelSerializer): user_data.set_password(password) user_data.save() junior_data = Junior.objects.create(auth=user_data, gender=validated_data.get('gender'), + image=profile_image, dob=validated_data.get('dob'), is_invited=True, guardian_code=[guardian_data.guardian_code], junior_code=generate_code(JUN, user_data.id), diff --git a/junior/views.py b/junior/views.py index 98428ce..e1cb8e0 100644 --- a/junior/views.py +++ b/junior/views.py @@ -149,8 +149,19 @@ class AddJuniorAPIView(viewsets.ModelViewSet): def create(self, request, *args, **kwargs): """ junior list""" try: - info_data = {'user': request.user, 'relationship': str(request.data['relationship']), 'email': request.data['email'], 'first_name': request.data['first_name'], - 'last_name': request.data['last_name']} + info_data = {'user': request.user, 'relationship': str(request.data['relationship']), + 'email': request.data['email'], 'first_name': request.data['first_name'], + 'last_name': request.data['last_name'], 'image':None} + profile_image = request.data.get('image') + if profile_image: + # check image size + if profile_image.size == NUMBER['zero']: + return custom_error_response(ERROR_CODE['2035'], response_status=status.HTTP_400_BAD_REQUEST) + # convert into file + filename = f"images/{profile_image.name}" + # upload image on ali baba + 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) return custom_response(SUCCESS_CODE['3021'], response_status=status.HTTP_200_OK) @@ -160,7 +171,7 @@ class AddJuniorAPIView(viewsets.ModelViewSet): # save serializer serializer.save() return custom_response(SUCCESS_CODE['3021'], serializer.data, response_status=status.HTTP_200_OK) - return custom_error_response(serializer.error, response_status=status.HTTP_400_BAD_REQUEST) + 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) From d86f082e587fc78971faa7cdae8a615bbc66bd17 Mon Sep 17 00:00:00 2001 From: jain Date: Wed, 9 Aug 2023 13:37:06 +0530 Subject: [PATCH 08/11] article card api, check answer api --- junior/serializers.py | 3 ++ junior/urls.py | 7 ++- junior/utils.py | 2 +- junior/views.py | 59 +++++++++++++++++++- web_admin/serializers/article_serializer.py | 60 +++++++++++++++++++-- web_admin/urls.py | 4 +- web_admin/views/article.py | 27 ++++++++-- 7 files changed, 152 insertions(+), 10 deletions(-) diff --git a/junior/serializers.py b/junior/serializers.py index 24e8b21..4014ee4 100644 --- a/junior/serializers.py +++ b/junior/serializers.py @@ -286,6 +286,8 @@ class AddJuniorSerializer(serializers.ModelSerializer): guardian_code_status=GUARDIAN_CODE_STATUS[1][0]) JuniorGuardianRelationship.objects.create(guardian=guardian_data, junior=junior_data, relationship=relationship) + total_junior = Junior.objects.all().count() + JuniorPoints.objects.create(junior=junior_data, position=total_junior) """Generate otp""" otp_value = generate_otp() expiry_time = timezone.now() + timezone.timedelta(days=1) @@ -479,3 +481,4 @@ class ReAssignTaskSerializer(serializers.ModelSerializer): instance.requested_on = None instance.save() return instance + diff --git a/junior/urls.py b/junior/urls.py index 267faef..76e5b47 100644 --- a/junior/urls.py +++ b/junior/urls.py @@ -4,7 +4,8 @@ from django.urls import path, include from .views import (UpdateJuniorProfile, ValidateGuardianCode, JuniorListAPIView, AddJuniorAPIView, InvitedJuniorAPIView, FilterJuniorAPIView, RemoveJuniorAPIView, JuniorTaskListAPIView, CompleteJuniorTaskAPIView, JuniorPointsListAPIView, ValidateReferralCode, - InviteGuardianAPIView, StartTaskAPIView, ReAssignJuniorTaskAPIView, StartArticleAPIView) + InviteGuardianAPIView, StartTaskAPIView, ReAssignJuniorTaskAPIView, StartArticleAPIView, + StartAssessmentAPIView, CheckAnswerAPIView) """Third party import""" from rest_framework import routers @@ -43,6 +44,10 @@ router.register('validate-referral-code', ValidateReferralCode, basename='valida router.register('invite-guardian', InviteGuardianAPIView, basename='invite-guardian') # start article""" router.register('start-article', StartArticleAPIView, basename='start-article') +# start assessment api""" +router.register('start-assessment', StartAssessmentAPIView, basename='start-assessment') +# check answer api""" +router.register('check-answer', CheckAnswerAPIView, basename='check-answer') # Define url pattern""" urlpatterns = [ path('api/v1/', include(router.urls)), diff --git a/junior/utils.py b/junior/utils.py index fefe950..621a6dd 100644 --- a/junior/utils.py +++ b/junior/utils.py @@ -50,7 +50,7 @@ def junior_approval_mail(guardian, full_name): def update_positions_based_on_points(): """Update position of the junior""" # First, retrieve all the JuniorPoints instances ordered by total_points in descending order. - juniors_points = JuniorPoints.objects.order_by('-total_points') + juniors_points = JuniorPoints.objects.order_by('-total_points', 'updated_at') # Now, iterate through the queryset and update the position field based on the order. position = 1 diff --git a/junior/views.py b/junior/views.py index e1cb8e0..9a7ce35 100644 --- a/junior/views.py +++ b/junior/views.py @@ -6,6 +6,7 @@ from rest_framework.permissions import IsAuthenticated from rest_framework.pagination import PageNumberPagination from django.contrib.auth.models import User from rest_framework.filters import SearchFilter +from django.db.models import F import datetime import requests @@ -41,6 +42,8 @@ from .utils import update_positions_based_on_points from notifications.utils import send_notification from notifications.constants import REMOVE_JUNIOR from web_admin.models import Article, ArticleSurvey, SurveyOption +from web_admin.serializers.article_serializer import (ArticleSerializer, ArticleListSerializer, + StartAssessmentSerializer) """ Define APIs """ # Define validate guardian code API, # update junior profile, @@ -351,6 +354,7 @@ class JuniorPointsListAPIView(viewsets.ModelViewSet): def get_queryset(self): """get queryset""" + update_positions_based_on_points() return JuniorTask.objects.filter(junior__auth__email=self.request.user).last() def list(self, request, *args, **kwargs): """profile view""" @@ -358,7 +362,6 @@ class JuniorPointsListAPIView(viewsets.ModelViewSet): try: queryset = self.get_queryset() # update position of junior - update_positions_based_on_points() serializer = JuniorPointsSerializer(queryset) return custom_response(None, serializer.data, response_status=status.HTTP_200_OK) except Exception as e: @@ -488,3 +491,57 @@ class StartArticleAPIView(viewsets.ModelViewSet): return custom_response(SUCCESS_CODE['3040'], response_status=status.HTTP_200_OK) except Exception as e: return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST) + +class StartAssessmentAPIView(viewsets.ModelViewSet): + """Junior Points viewset""" + serializer_class = StartAssessmentSerializer + permission_classes = [IsAuthenticated] + http_method_names = ('get',) + + def get_queryset(self): + article_id = self.request.GET.get('article_id') + # if referral_code: + article = Article.objects.filter(id=article_id, is_deleted=False).prefetch_related( + 'article_cards', 'article_survey', 'article_survey__options' + ).order_by('-created_at') + return article + def list(self, request, *args, **kwargs): + """profile view""" + + try: + queryset = self.get_queryset() + paginator = self.pagination_class() + paginated_queryset = paginator.paginate_queryset(queryset, request) + serializer = self.serializer_class(paginated_queryset, context={"user":request.user}, many=True) + return custom_response(None, serializer.data, response_status=status.HTTP_200_OK) + except Exception as e: + return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST) + +class CheckAnswerAPIView(viewsets.ModelViewSet): + """Junior Points viewset""" + permission_classes = [IsAuthenticated] + http_method_names = ('get',) + + def get_queryset(self): + question_id = self.request.GET.get('question_id') + article = ArticleSurvey.objects.filter(id=question_id).last() + return article + def list(self, request, *args, **kwargs): + """profile view""" + + try: + answer_id = self.request.GET.get('answer_id') + queryset = self.get_queryset() + submit_ans = SurveyOption.objects.filter(id=answer_id, is_answer=True).last() + junior_article_points = JuniorArticlePoints.objects.filter(junior__auth=self.request.user, + question=queryset) + if submit_ans: + junior_article_points.update(submitted_answer=submit_ans, is_attempt=True, is_answer_correct=True) + JuniorPoints.objects.filter(junior__auth=self.request.user).update(total_points= + F('total_points')+ queryset.points) + else: + junior_article_points.update(submitted_answer=submit_ans, is_attempt=True, earn_points=0, + is_answer_correct=False) + return custom_response(None, response_status=status.HTTP_200_OK) + except Exception as e: + return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST) diff --git a/web_admin/serializers/article_serializer.py b/web_admin/serializers/article_serializer.py index b39d20d..9458190 100644 --- a/web_admin/serializers/article_serializer.py +++ b/web_admin/serializers/article_serializer.py @@ -12,7 +12,7 @@ from base.messages import ERROR_CODE from guardian.utils import upload_image_to_alibaba from web_admin.models import Article, ArticleCard, SurveyOption, ArticleSurvey, DefaultArticleCardImage from web_admin.utils import pop_id, get_image_url - +from junior.models import JuniorArticlePoints USER = get_user_model() @@ -64,7 +64,7 @@ class ArticleSurveySerializer(serializers.ModelSerializer): meta class """ model = ArticleSurvey - fields = ('id', 'question', 'options') + fields = ('id', 'question', 'options', 'points') class ArticleSerializer(serializers.ModelSerializer): @@ -220,6 +220,7 @@ class ArticleListSerializer(serializers.ModelSerializer): serializer for article API """ article_cards = ArticleCardSerializer(many=True) + article_survey = ArticleSurveySerializer(many=True) total_points = serializers.SerializerMethodField('get_total_points') is_completed = serializers.SerializerMethodField('get_is_completed') @@ -228,7 +229,7 @@ class ArticleListSerializer(serializers.ModelSerializer): meta class """ model = Article - fields = ('id', 'title', 'description', 'article_cards', 'total_points', 'is_completed') + fields = ('id', 'title', 'description', 'article_cards', 'article_survey', 'total_points', 'is_completed') def get_total_points(self, obj): """total points of article""" @@ -238,3 +239,56 @@ class ArticleListSerializer(serializers.ModelSerializer): def get_is_completed(self, obj): """complete all question""" return False + +class ArticleQuestionSerializer(serializers.ModelSerializer): + """ + article survey serializer + """ + id = serializers.IntegerField(required=False) + options = SurveyOptionSerializer(many=True) + is_attempt = serializers.SerializerMethodField('get_is_attempt') + + def get_is_attempt(self, obj): + """attempt question or not""" + context_data = self.context.get('user') + junior_article_obj = JuniorArticlePoints.objects.filter(junior__auth=context_data, question=obj).last() + if junior_article_obj: + return junior_article_obj.is_attempt + return False + + class Meta: + """ + meta class + """ + model = ArticleSurvey + fields = ('id', 'question', 'options', 'points', 'is_attempt') + +class StartAssessmentSerializer(serializers.ModelSerializer): + """ + serializer for article API + """ + article_survey = ArticleQuestionSerializer(many=True) + + class Meta: + """ + meta class + """ + model = Article + fields = ('article_survey',) + + +class CheckAnswerSerializer(serializers.ModelSerializer): + """ + serializer for article API + """ + article_survey = ArticleSurveySerializer(many=True) + + class Meta: + """ + meta class + """ + model = ArticleSurvey + fields = ('id', 'article_survey') + + def create(self, validated_data): + """create function""" diff --git a/web_admin/urls.py b/web_admin/urls.py index 065d30d..6bf3b5e 100644 --- a/web_admin/urls.py +++ b/web_admin/urls.py @@ -6,7 +6,8 @@ from django.urls import path, include from rest_framework import routers # local imports -from web_admin.views.article import ArticleViewSet, DefaultArticleCardImagesViewSet, ArticleListViewSet +from web_admin.views.article import (ArticleViewSet, DefaultArticleCardImagesViewSet, ArticleListViewSet, + ArticleCardListViewSet) from web_admin.views.auth import ForgotAndResetPasswordViewSet from web_admin.views.user_management import UserManagementViewSet @@ -17,6 +18,7 @@ router.register('article', ArticleViewSet, basename='article') router.register('default-card-images', DefaultArticleCardImagesViewSet, basename='default-card-images') router.register('user-management', UserManagementViewSet, basename='user') router.register('article-list', ArticleListViewSet, basename='article-list') +router.register('article-card-list', ArticleCardListViewSet, basename='article-card-list') # forgot and reset password api for admin router.register('admin', ForgotAndResetPasswordViewSet, basename='admin') diff --git a/web_admin/views/article.py b/web_admin/views/article.py index f334650..d4cc843 100644 --- a/web_admin/views/article.py +++ b/web_admin/views/article.py @@ -4,7 +4,7 @@ web_admin views file # django imports from rest_framework.viewsets import GenericViewSet, mixins from rest_framework.filters import OrderingFilter, SearchFilter -from rest_framework import status +from rest_framework import status, viewsets from rest_framework.decorators import action from rest_framework.permissions import IsAuthenticated, AllowAny from django.contrib.auth import get_user_model @@ -16,7 +16,8 @@ from base.messages import SUCCESS_CODE, ERROR_CODE from web_admin.models import Article, ArticleCard, ArticleSurvey, DefaultArticleCardImage from web_admin.permission import AdminPermission from web_admin.serializers.article_serializer import (ArticleSerializer, ArticleCardSerializer, - DefaultArticleCardImageSerializer, ArticleListSerializer) + DefaultArticleCardImageSerializer, ArticleListSerializer + ) USER = get_user_model() @@ -224,4 +225,24 @@ class ArticleListViewSet(GenericViewSet, mixins.ListModelMixin): 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, count=count) + return custom_response(None, data=serializer.data) + +class ArticleCardListViewSet(viewsets.ModelViewSet): + """Junior Points viewset""" + serializer_class = ArticleCardSerializer + permission_classes = [IsAuthenticated] + http_method_names = ('get',) + + def get_queryset(self): + """get queryset""" + return ArticleCard.objects.filter(article=self.request.GET.get('article_id')) + def list(self, request, *args, **kwargs): + """profile view""" + + try: + queryset = self.get_queryset() + # article card list + serializer = ArticleCardSerializer(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) From 881bda739b4d3d40ea042329a649a46155dc669c Mon Sep 17 00:00:00 2001 From: jain Date: Wed, 9 Aug 2023 13:48:02 +0530 Subject: [PATCH 09/11] article card api, check answer api --- base/constants.py | 4 ++-- guardian/serializers.py | 4 ++-- guardian/utils.py | 2 +- guardian/views.py | 44 +++++++++++++++++++---------------------- 4 files changed, 25 insertions(+), 29 deletions(-) diff --git a/base/constants.py b/base/constants.py index e38cb29..7efdb8b 100644 --- a/base/constants.py +++ b/base/constants.py @@ -112,7 +112,7 @@ MAX_ARTICLE_CARD = 6 MIN_ARTICLE_SURVEY = 5 MAX_ARTICLE_SURVEY = 10 -# real time url -time_url = "http://worldtimeapi.org/api/timezone/Asia/Riyadh" +# already register +Already_register_user = "duplicate key value violates unique constraint" ARTICLE_CARD_IMAGE_FOLDER = 'article-card-images' diff --git a/guardian/serializers.py b/guardian/serializers.py index 65dd1ea..172ccc4 100644 --- a/guardian/serializers.py +++ b/guardian/serializers.py @@ -22,7 +22,7 @@ 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 +from base.constants import NUMBER, JUN, ZOD, GRD, Already_register_user from junior.models import Junior, JuniorPoints, JuniorGuardianRelationship from .utils import real_time, convert_timedelta_into_datetime, update_referral_points # notification's constant @@ -83,7 +83,7 @@ class UserSerializer(serializers.ModelSerializer): otp_verified = False if otp and otp.is_verified: otp_verified = True - raise serializers.ValidationError({"details":ERROR_CODE['2021'], "otp_verified":bool(otp_verified), + raise serializers.ValidationError({"details": ERROR_CODE['2021'], "otp_verified":bool(otp_verified), "code": 400, "status":"failed", }) diff --git a/guardian/utils.py b/guardian/utils.py index 9a6ae05..57e8080 100644 --- a/guardian/utils.py +++ b/guardian/utils.py @@ -11,7 +11,7 @@ import tempfile # Import date time module's function from datetime import datetime, time # import Number constant -from base.constants import NUMBER, time_url +from base.constants import NUMBER # Import Junior's model from junior.models import Junior, JuniorPoints # Import guardian's model diff --git a/guardian/views.py b/guardian/views.py index 3e265b0..75a16ff 100644 --- a/guardian/views.py +++ b/guardian/views.py @@ -10,7 +10,6 @@ from rest_framework.permissions import IsAuthenticated from rest_framework import viewsets, status from rest_framework.pagination import PageNumberPagination from django.contrib.auth.models import User -from django.utils import timezone # Import guardian's model, # Import junior's model, @@ -57,29 +56,26 @@ class SignupViewset(viewsets.ModelViewSet): serializer_class = UserSerializer def create(self, request, *args, **kwargs): """Create user profile""" - try: - 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(): - user = serializer.save() - """Generate otp""" - otp = generate_otp() - # expire otp after 1 day - expiry = OTP_EXPIRY - # create user email otp object - UserEmailOtp.objects.create(email=request.data['email'], otp=otp, - user_type=str(request.data['user_type']), expired_at=expiry) - """Send email to the register user""" - send_otp_email(request.data['email'], otp) - # send push notification for registration - send_notification.delay(REGISTRATION, None, user.id, {}) - return custom_response(SUCCESS_CODE['3001'], - response_status=status.HTTP_200_OK) - return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST) - else: - return custom_error_response(ERROR_CODE['2028'], response_status=status.HTTP_400_BAD_REQUEST) - except Exception as e: - return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST) + 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(): + user = serializer.save() + """Generate otp""" + otp = generate_otp() + # expire otp after 1 day + expiry = OTP_EXPIRY + # create user email otp object + UserEmailOtp.objects.create(email=request.data['email'], otp=otp, + user_type=str(request.data['user_type']), expired_at=expiry) + """Send email to the register user""" + send_otp_email(request.data['email'], otp) + # send push notification for registration + send_notification.delay(REGISTRATION, None, user.id, {}) + return custom_response(SUCCESS_CODE['3001'], + response_status=status.HTTP_200_OK) + return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST) + else: + return custom_error_response(ERROR_CODE['2028'], response_status=status.HTTP_400_BAD_REQUEST) class UpdateGuardianProfile(viewsets.ViewSet): """Update guardian profile""" From 3cb0e3ed8b86784c6781e01ea3022ef104f04ad9 Mon Sep 17 00:00:00 2001 From: jain Date: Wed, 9 Aug 2023 14:37:38 +0530 Subject: [PATCH 10/11] guardian code add in junior list api --- junior/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/junior/serializers.py b/junior/serializers.py index 4014ee4..3f374cc 100644 --- a/junior/serializers.py +++ b/junior/serializers.py @@ -207,7 +207,7 @@ class JuniorDetailListSerializer(serializers.ModelSerializer): fields = ['id', 'email', 'first_name', 'last_name', 'country_code', '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'] + 'requested_task', 'rejected_task', 'position', 'is_invited', 'guardian_code_status'] class JuniorProfileSerializer(serializers.ModelSerializer): """junior serializer""" From 69ce6857e8bd95ee83b3525d1ac27c5d5ab1779c Mon Sep 17 00:00:00 2001 From: jain Date: Wed, 9 Aug 2023 16:36:33 +0530 Subject: [PATCH 11/11] financial learning section api --- base/constants.py | 6 ++ base/messages.py | 8 +- guardian/serializers.py | 2 - junior/admin.py | 22 +++++- junior/migrations/0022_juniorarticle.py | 27 +++++++ junior/migrations/0023_juniorarticlecard.py | 27 +++++++ junior/models.py | 39 +++++++++- junior/serializers.py | 2 +- junior/urls.py | 7 +- junior/views.py | 84 ++++++++++++++++++++- 10 files changed, 211 insertions(+), 13 deletions(-) create mode 100644 junior/migrations/0022_juniorarticle.py create mode 100644 junior/migrations/0023_juniorarticlecard.py diff --git a/base/constants.py b/base/constants.py index 7efdb8b..36079b9 100644 --- a/base/constants.py +++ b/base/constants.py @@ -76,6 +76,12 @@ GUARDIAN_CODE_STATUS = ( ('2', 'exist guardian code'), ('3', 'request for guardian code') ) +# article status +ARTICLE_STATUS = ( + ('1', 'read'), + ('2', 'in_progress'), + ('3', 'completed') +) # relationship RELATIONSHIP = ( ('1', 'parent'), diff --git a/base/messages.py b/base/messages.py index 05b4ec3..1e3e146 100644 --- a/base/messages.py +++ b/base/messages.py @@ -150,7 +150,13 @@ SUCCESS_CODE = { "3038": "Status has been changed successfully.", # notification read "3039": "Notification read successfully", - "3040": "Start article successfully" + "3040": "Start article successfully", + # complete article + "3041": "Article completed successfully", + # submit assessment successfully + "3042": "Assessment completed successfully", + "3043": "Read article card successfully" + } """status code error""" STATUS_CODE_ERROR = { diff --git a/guardian/serializers.py b/guardian/serializers.py index 0a8b625..12d5383 100644 --- a/guardian/serializers.py +++ b/guardian/serializers.py @@ -387,8 +387,6 @@ class ApproveTaskSerializer(serializers.ModelSerializer): # reject the task instance.task_status = str(NUMBER['three']) instance.is_approved = False - # update total task point - junior_data.total_points = junior_data.total_points - instance.points # update reject time of task # instance.rejected_on = real_time() instance.rejected_on = timezone.now().astimezone(pytz.utc) diff --git a/junior/admin.py b/junior/admin.py index 5fdfcce..6c6cdf9 100644 --- a/junior/admin.py +++ b/junior/admin.py @@ -2,8 +2,26 @@ """Third party Django app""" from django.contrib import admin """Import Django app""" -from .models import Junior, JuniorPoints, JuniorGuardianRelationship, JuniorArticlePoints +from .models import (Junior, JuniorPoints, JuniorGuardianRelationship, JuniorArticlePoints, JuniorArticle, + JuniorArticleCard) # Register your models here. +@admin.register(JuniorArticle) +class JuniorArticleAdmin(admin.ModelAdmin): + """Junior Admin""" + list_display = ['junior', 'article', 'status', 'is_completed'] + + def __str__(self): + """Return email id""" + return self.junior__auth__email + +@admin.register(JuniorArticleCard) +class JuniorArticleCardAdmin(admin.ModelAdmin): + """Junior Admin""" + list_display = ['junior', 'article', 'article_card', 'is_read'] + + def __str__(self): + """Return email id""" + return self.junior__auth__email @admin.register(Junior) class JuniorAdmin(admin.ModelAdmin): """Junior Admin""" @@ -30,4 +48,4 @@ class JuniorGuardianRelationshipAdmin(admin.ModelAdmin): @admin.register(JuniorArticlePoints) class JuniorArticlePointsAdmin(admin.ModelAdmin): """Junior Admin""" - list_display = ['junior', 'article', 'question', 'submitted_answer'] + list_display = ['junior', 'article', 'question', 'submitted_answer', 'is_answer_correct'] diff --git a/junior/migrations/0022_juniorarticle.py b/junior/migrations/0022_juniorarticle.py new file mode 100644 index 0000000..9dd794e --- /dev/null +++ b/junior/migrations/0022_juniorarticle.py @@ -0,0 +1,27 @@ +# Generated by Django 4.2.2 on 2023-08-09 09:34 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('web_admin', '0004_alter_surveyoption_survey'), + ('junior', '0021_alter_juniorarticlepoints_submitted_answer'), + ] + + operations = [ + migrations.CreateModel( + name='JuniorArticle', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('is_completed', models.BooleanField(default=False)), + ('status', models.CharField(blank=True, choices=[('1', 'read'), ('2', 'in_progress'), ('3', 'completed')], default='1', max_length=10, null=True)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('article', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='junior_articles_details', to='web_admin.article')), + ('junior', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='juniors_article', to='junior.junior', verbose_name='Junior')), + ], + ), + ] diff --git a/junior/migrations/0023_juniorarticlecard.py b/junior/migrations/0023_juniorarticlecard.py new file mode 100644 index 0000000..9b8a1af --- /dev/null +++ b/junior/migrations/0023_juniorarticlecard.py @@ -0,0 +1,27 @@ +# Generated by Django 4.2.2 on 2023-08-09 10:47 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('web_admin', '0004_alter_surveyoption_survey'), + ('junior', '0022_juniorarticle'), + ] + + operations = [ + migrations.CreateModel( + name='JuniorArticleCard', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('is_read', models.BooleanField(default=False)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('article', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='junior_articles_detail', to='web_admin.article')), + ('article_card', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='junior_article_card', to='web_admin.articlecard')), + ('junior', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='juniors_article_card', to='junior.junior', verbose_name='Junior')), + ], + ), + ] diff --git a/junior/models.py b/junior/models.py index 3d2aaa4..180b425 100644 --- a/junior/models.py +++ b/junior/models.py @@ -6,11 +6,11 @@ from django.contrib.auth import get_user_model """Import ArrayField""" from django.contrib.postgres.fields import ArrayField """Import django app""" -from base.constants import GENDERS, SIGNUP_METHODS, RELATIONSHIP, GUARDIAN_CODE_STATUS +from base.constants import GENDERS, SIGNUP_METHODS, RELATIONSHIP, GUARDIAN_CODE_STATUS, ARTICLE_STATUS # Import guardian's model from guardian.models import Guardian # Import web admin's model -from web_admin.models import SurveyOption, ArticleSurvey, Article +from web_admin.models import SurveyOption, ArticleSurvey, Article, ArticleCard """Define User model""" User = get_user_model() # Create your models here. @@ -161,3 +161,38 @@ class JuniorArticlePoints(models.Model): def __str__(self): """Return title""" return f'{self.id} | {self.question}' + +class JuniorArticle(models.Model): + """ + Survey Options model + """ + # associated junior with the task + junior = models.OneToOneField(Junior, on_delete=models.CASCADE, related_name='juniors_article', verbose_name='Junior') + article = models.ForeignKey(Article, on_delete=models.CASCADE, related_name='junior_articles_details') + # article completed""" + is_completed = models.BooleanField(default=False) + status = models.CharField(max_length=10, choices=ARTICLE_STATUS, null=True, blank=True, default='1') + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + def __str__(self): + """Return title""" + return f'{self.id} | {self.article}' + +class JuniorArticleCard(models.Model): + """ + Survey Options model + """ + # associated junior with the task + junior = models.ForeignKey(Junior, on_delete=models.CASCADE, related_name='juniors_article_card', verbose_name='Junior') + article = models.ForeignKey(Article, on_delete=models.CASCADE, related_name='junior_articles_detail') + article_card = models.ForeignKey(ArticleCard, on_delete=models.CASCADE, related_name='junior_article_card') + + # article card read""" + is_read = models.BooleanField(default=False) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + def __str__(self): + """Return title""" + return f'{self.id} | {self.article}' diff --git a/junior/serializers.py b/junior/serializers.py index bfd79d1..079031a 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 +from junior.models import Junior, JuniorPoints, JuniorGuardianRelationship, JuniorArticlePoints from guardian.tasks import generate_otp from base.messages import ERROR_CODE, SUCCESS_CODE from base.constants import (PENDING, IN_PROGRESS, REJECTED, REQUESTED, COMPLETED, NUMBER, JUN, ZOD, EXPIRED, diff --git a/junior/urls.py b/junior/urls.py index 76e5b47..e494a3d 100644 --- a/junior/urls.py +++ b/junior/urls.py @@ -5,7 +5,8 @@ from .views import (UpdateJuniorProfile, ValidateGuardianCode, JuniorListAPIView InvitedJuniorAPIView, FilterJuniorAPIView, RemoveJuniorAPIView, JuniorTaskListAPIView, CompleteJuniorTaskAPIView, JuniorPointsListAPIView, ValidateReferralCode, InviteGuardianAPIView, StartTaskAPIView, ReAssignJuniorTaskAPIView, StartArticleAPIView, - StartAssessmentAPIView, CheckAnswerAPIView) + StartAssessmentAPIView, CheckAnswerAPIView, CompleteArticleAPIView, ReadArticleCardAPIView, + CreateArticleCardAPIView) """Third party import""" from rest_framework import routers @@ -48,6 +49,8 @@ router.register('start-article', StartArticleAPIView, basename='start-article') router.register('start-assessment', StartAssessmentAPIView, basename='start-assessment') # check answer api""" router.register('check-answer', CheckAnswerAPIView, basename='check-answer') +# start article""" +router.register('create-article-card', CreateArticleCardAPIView, basename='create-article-card') # Define url pattern""" urlpatterns = [ path('api/v1/', include(router.urls)), @@ -55,4 +58,6 @@ urlpatterns = [ path('api/v1/complete-task/', CompleteJuniorTaskAPIView.as_view()), path('api/v1/start-task/', StartTaskAPIView.as_view()), path('api/v1/reassign-task/', ReAssignJuniorTaskAPIView.as_view()), + path('api/v1/complete-article/', CompleteArticleAPIView.as_view()), + path('api/v1/read-article-card/', ReadArticleCardAPIView.as_view()), ] diff --git a/junior/views.py b/junior/views.py index 9a7ce35..5926c47 100644 --- a/junior/views.py +++ b/junior/views.py @@ -28,20 +28,23 @@ import requests # Import upload_image_to_alibaba # Import custom_response, custom_error_response # Import constants -from junior.models import Junior, JuniorPoints, JuniorGuardianRelationship, JuniorArticlePoints +from django.db.models import Sum +from junior.models import (Junior, JuniorPoints, JuniorGuardianRelationship, JuniorArticlePoints, JuniorArticle, + JuniorArticleCard) from .serializers import (CreateJuniorSerializer, JuniorDetailListSerializer, AddJuniorSerializer, RemoveJuniorSerializer, CompleteTaskSerializer, JuniorPointsSerializer, - AddGuardianSerializer, StartTaskSerializer, ReAssignTaskSerializer) + AddGuardianSerializer, StartTaskSerializer, ReAssignTaskSerializer + ) 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 +from base.constants import NUMBER, ARTICLE_STATUS from account.utils import custom_response, custom_error_response from guardian.utils import upload_image_to_alibaba from .utils import update_positions_based_on_points from notifications.utils import send_notification from notifications.constants import REMOVE_JUNIOR -from web_admin.models import Article, ArticleSurvey, SurveyOption +from web_admin.models import Article, ArticleSurvey, SurveyOption, ArticleCard from web_admin.serializers.article_serializer import (ArticleSerializer, ArticleListSerializer, StartAssessmentSerializer) """ Define APIs """ @@ -479,6 +482,8 @@ class StartArticleAPIView(viewsets.ModelViewSet): junior_instance = Junior.objects.filter(auth=self.request.user).last() article_id = request.data.get('article_id') article_data = Article.objects.filter(id=article_id).last() + if not JuniorArticle.objects.filter(junior=junior_instance, article=article_data).last(): + JuniorArticle.objects.create(junior=junior_instance, article=article_data, status=str(NUMBER['two'])) if article_data: question_query = ArticleSurvey.objects.filter(article=article_id) for question in question_query: @@ -545,3 +550,74 @@ class CheckAnswerAPIView(viewsets.ModelViewSet): return custom_response(None, response_status=status.HTTP_200_OK) except Exception as e: return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST) + +class CompleteArticleAPIView(views.APIView): + """Remove junior API""" + permission_classes = [IsAuthenticated] + http_method_names = ('put', 'get',) + def put(self, request, format=None): + try: + article_id = self.request.data.get('article_id') + JuniorArticle.objects.filter(junior__auth=request.user, article__id=article_id).update( + is_completed=True, status=str(NUMBER['three']) + ) + return custom_response(SUCCESS_CODE['3041'], response_status=status.HTTP_200_OK) + except Exception as e: + return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST) + + def get(self, request, *args, **kwargs): + """ junior list""" + try: + article_id = self.request.GET.get('article_id') + total_earn_points = JuniorArticlePoints.objects.filter(junior__auth=request.user, + article__id=article_id, + is_answer_correct=True).aggregate( + total_earn_points=Sum('earn_points'))['total_earn_points'] + data = {"total_earn_points":total_earn_points} + return custom_response(SUCCESS_CODE['3042'], data, response_status=status.HTTP_200_OK) + except Exception as e: + return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST) + + +class ReadArticleCardAPIView(views.APIView): + """Remove junior API""" + permission_classes = [IsAuthenticated] + http_method_names = ('put',) + + def put(self, request, *args, **kwargs): + """ junior list""" + try: + junior_instance = Junior.objects.filter(auth=self.request.user).last() + article = self.request.data.get('article_id') + article_card = self.request.data.get('article_card') + JuniorArticleCard.objects.filter(junior=junior_instance, + article__id=article, + article_card__id=article_card).update(is_read=True) + return custom_response(SUCCESS_CODE['3043'], response_status=status.HTTP_200_OK) + except Exception as e: + return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST) + + +class CreateArticleCardAPIView(viewsets.ModelViewSet): + """Start article""" + permission_classes = [IsAuthenticated] + http_method_names = ('post',) + + def create(self, request, *args, **kwargs): + """ junior list""" + try: + junior_instance = Junior.objects.filter(auth=self.request.user).last() + article_id = request.data.get('article_id') + article_data = Article.objects.filter(id=article_id).last() + if article_data: + article_cards = ArticleCard.objects.filter(article=article_id) + for article_card in article_cards: + if not JuniorArticleCard.objects.filter(junior=junior_instance, + article=article_data, + article_card=article_card): + JuniorArticleCard.objects.create(junior=junior_instance, + article=article_data, + article_card=article_card) + return custom_response(None, response_status=status.HTTP_200_OK) + except Exception as e: + return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)