diff --git a/account/views.py b/account/views.py index c814100..7979215 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: @@ -368,7 +366,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: @@ -411,7 +408,6 @@ class UserEmailVerification(viewsets.ModelViewSet): class ReSendEmailOtp(viewsets.ModelViewSet): """Send otp on phone""" - queryset = UserEmailOtp.objects.all() serializer_class = EmailVerificationSerializer permission_classes = [IsAuthenticated] @@ -434,7 +430,6 @@ class ReSendEmailOtp(viewsets.ModelViewSet): class ProfileAPIViewSet(viewsets.ModelViewSet): """Profile viewset""" - queryset = User.objects.all() serializer_class = JuniorProfileSerializer permission_classes = [IsAuthenticated] @@ -453,7 +448,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""" @@ -472,7 +466,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): @@ -503,7 +496,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): @@ -515,7 +507,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/base/constants.py b/base/constants.py index 6022f62..36079b9 100644 --- a/base/constants.py +++ b/base/constants.py @@ -70,6 +70,18 @@ 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') +) +# article status +ARTICLE_STATUS = ( + ('1', 'read'), + ('2', 'in_progress'), + ('3', 'completed') +) # relationship RELATIONSHIP = ( ('1', 'parent'), @@ -106,7 +118,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/base/messages.py b/base/messages.py index f7d36dc..f1d5daa 100644 --- a/base/messages.py +++ b/base/messages.py @@ -149,7 +149,14 @@ 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", + # 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 4d0ea65..12d5383 100644 --- a/guardian/serializers.py +++ b/guardian/serializers.py @@ -23,7 +23,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 @@ -68,8 +68,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), @@ -82,7 +84,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", }) @@ -385,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) @@ -403,11 +403,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): @@ -422,9 +431,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/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 227c052..8d38395 100644 --- a/guardian/views.py +++ b/guardian/views.py @@ -10,8 +10,8 @@ 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 rest_framework.filters import SearchFilter +from rest_framework.filters import SearchFilter from django.utils import timezone # Import guardian's model, @@ -36,7 +36,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 @@ -59,33 +59,29 @@ 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""" - queryset = Guardian.objects.all() serializer_class = CreateGuardianSerializer permission_classes = [IsAuthenticated] @@ -119,7 +115,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): @@ -261,9 +256,9 @@ class SearchTaskListAPIView(viewsets.ModelViewSet): class TopJuniorListAPIView(viewsets.ModelViewSet): """Top juniors list""" + queryset = JuniorPoints.objects.all() serializer_class = TopJuniorSerializer permission_classes = [IsAuthenticated] - queryset = JuniorPoints.objects.all() def get_serializer_context(self): # context list @@ -379,6 +374,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({"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/admin.py b/junior/admin.py index acd8734..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 +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""" @@ -27,3 +45,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', 'is_answer_correct'] 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/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/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/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 b18cbf5..180b425 100644 --- a/junior/models.py +++ b/junior/models.py @@ -6,10 +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 +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, ArticleCard """Define User model""" User = get_user_model() # Create your models here. @@ -73,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) @@ -137,3 +141,58 @@ 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.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) + 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}' + +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 bdedbb5..079031a 100644 --- a/junior/serializers.py +++ b/junior/serializers.py @@ -12,10 +12,11 @@ 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 +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 @@ -209,7 +210,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""" @@ -256,11 +257,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): @@ -269,6 +269,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, @@ -278,14 +279,18 @@ 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), 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[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) @@ -403,13 +408,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[2][0] + 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: @@ -481,3 +488,4 @@ class ReAssignTaskSerializer(serializers.ModelSerializer): instance.requested_on = None instance.save() return instance + diff --git a/junior/urls.py b/junior/urls.py index f66fa30..e494a3d 100644 --- a/junior/urls.py +++ b/junior/urls.py @@ -4,7 +4,9 @@ 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, + StartAssessmentAPIView, CheckAnswerAPIView, CompleteArticleAPIView, ReadArticleCardAPIView, + CreateArticleCardAPIView) """Third party import""" from rest_framework import routers @@ -41,6 +43,14 @@ 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') +# start assessment api""" +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)), @@ -48,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/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 15cd387..5926c47 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 @@ -27,20 +28,25 @@ 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 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, ArticleCard +from web_admin.serializers.article_serializer import (ArticleSerializer, ArticleListSerializer, + StartAssessmentSerializer) """ Define APIs """ # Define validate guardian code API, # update junior profile, @@ -59,7 +65,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 +98,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): @@ -151,8 +155,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) @@ -162,7 +177,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) @@ -180,7 +195,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 +224,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 +281,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): @@ -345,6 +357,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""" @@ -352,7 +365,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: @@ -458,3 +470,154 @@ 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""" + 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 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: + if not JuniorArticlePoints.objects.filter(junior=junior_instance, + article=article_data, + question=question): + JuniorArticlePoints.objects.create(junior=junior_instance, + article=article_data, + 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) + +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) + +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) 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 5b42686..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,16 +220,75 @@ 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') class Meta: """ meta class """ model = Article - fields = ('id', 'title', 'description', 'article_cards', 'total_points') + fields = ('id', 'title', 'description', 'article_cards', 'article_survey', '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 + return total_question * NUMBER['five'] + + 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 d586e50..7f65fc8 100644 --- a/web_admin/urls.py +++ b/web_admin/urls.py @@ -7,7 +7,8 @@ from rest_framework import routers # local imports from web_admin.views.analytics import AnalyticsViewSet -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,9 +18,10 @@ router = routers.SimpleRouter() 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('analytics', AnalyticsViewSet, basename='user-analytics') -# router.register('task-analytics', TaskAnalyticsViewSet, basename='task-analytics') + +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)