mirror of
https://github.com/HamzaSha1/zod-backend.git
synced 2026-10-23 09:27:57 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
af121f5a53 | ||
|
|
d3564efbb9 | ||
|
|
ee92c98f34 | ||
|
|
fbce04b97e | ||
|
|
afaed69eec | ||
|
|
3c0eaf676e | ||
|
|
6ffaa66a4d | ||
|
|
4b8e7189c1 | ||
|
|
d68f24543d | ||
|
|
3534561697 | ||
|
|
de774111c0 | ||
|
|
bab50e4492 | ||
|
|
151a177e76 | ||
|
|
73a62186a7 | ||
|
|
83c66ab3b6 | ||
|
|
94e53e1dcd | ||
|
|
68b77ef766 | ||
|
|
a2000459d3 | ||
|
|
c079f3ceca | ||
|
|
671cdfc27b | ||
|
|
a83e27b12a | ||
|
|
87aa1af02b | ||
|
|
5f3026f08f |
+1
-1
@@ -21,4 +21,4 @@ static/*
|
|||||||
__pycache__/
|
__pycache__/
|
||||||
*.env
|
*.env
|
||||||
ve/*
|
ve/*
|
||||||
|
celerybeat-schedule
|
||||||
|
|||||||
+4
-1
@@ -88,7 +88,10 @@ ERROR_CODE = {
|
|||||||
"2060": "Task does not exist or not in pending state",
|
"2060": "Task does not exist or not in pending state",
|
||||||
"2061": "Please insert image or check the image is valid or not.",
|
"2061": "Please insert image or check the image is valid or not.",
|
||||||
# email not null
|
# email not null
|
||||||
"2062": "Please enter email address"
|
"2062": "Please enter email address",
|
||||||
|
"2063": "Unauthorized access.",
|
||||||
|
"2064": "To change your password first request an OTP and get it verify then change your password.",
|
||||||
|
"2065": "Passwords do not match. Please try again."
|
||||||
}
|
}
|
||||||
"""Success message code"""
|
"""Success message code"""
|
||||||
SUCCESS_CODE = {
|
SUCCESS_CODE = {
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
"""
|
||||||
|
web_admin tasks file
|
||||||
|
"""
|
||||||
|
# third party imports
|
||||||
|
from celery import shared_task
|
||||||
|
from templated_email import send_templated_mail
|
||||||
|
|
||||||
|
# django imports
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
|
||||||
|
@shared_task
|
||||||
|
def send_email_otp(email, verification_code):
|
||||||
|
"""
|
||||||
|
used to send otp on email
|
||||||
|
:param email: e-mail
|
||||||
|
:param verification_code: otp
|
||||||
|
"""
|
||||||
|
from_email = settings.EMAIL_FROM_ADDRESS
|
||||||
|
recipient_list = [email]
|
||||||
|
send_templated_mail(
|
||||||
|
template_name='email_reset_verification.email',
|
||||||
|
from_email=from_email,
|
||||||
|
recipient_list=recipient_list,
|
||||||
|
context={
|
||||||
|
'verification_code': verification_code
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return True
|
||||||
Binary file not shown.
@@ -308,6 +308,7 @@ class GuardianProfileSerializer(serializers.ModelSerializer):
|
|||||||
'is_active', 'is_complete_profile', 'created_at', 'image', 'signup_method',
|
'is_active', 'is_complete_profile', 'created_at', 'image', 'signup_method',
|
||||||
'updated_at', 'passcode']
|
'updated_at', 'passcode']
|
||||||
|
|
||||||
|
|
||||||
class ApproveJuniorSerializer(serializers.ModelSerializer):
|
class ApproveJuniorSerializer(serializers.ModelSerializer):
|
||||||
"""approve junior serializer"""
|
"""approve junior serializer"""
|
||||||
class Meta(object):
|
class Meta(object):
|
||||||
@@ -319,9 +320,11 @@ class ApproveJuniorSerializer(serializers.ModelSerializer):
|
|||||||
"""update guardian code"""
|
"""update guardian code"""
|
||||||
instance = self.context['junior']
|
instance = self.context['junior']
|
||||||
instance.guardian_code = [self.context['guardian_code']]
|
instance.guardian_code = [self.context['guardian_code']]
|
||||||
|
instance.is_invited = True
|
||||||
instance.save()
|
instance.save()
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
|
|
||||||
class ApproveTaskSerializer(serializers.ModelSerializer):
|
class ApproveTaskSerializer(serializers.ModelSerializer):
|
||||||
"""approve task serializer"""
|
"""approve task serializer"""
|
||||||
class Meta(object):
|
class Meta(object):
|
||||||
|
|||||||
+1
-1
@@ -99,7 +99,7 @@ def update_expired_task_status(data=None):
|
|||||||
Update task of the status if due date is in past
|
Update task of the status if due date is in past
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
task_status = [str(NUMBER['one']), str(NUMBER['two'])]
|
task_status = [str(NUMBER['one']), str(NUMBER['two']), str(NUMBER['four'])]
|
||||||
JuniorTask.objects.filter(due_date__lt=datetime.today().date(),
|
JuniorTask.objects.filter(due_date__lt=datetime.today().date(),
|
||||||
task_status__in=task_status).update(task_status=str(NUMBER['six']))
|
task_status__in=task_status).update(task_status=str(NUMBER['six']))
|
||||||
except ObjectDoesNotExist as e:
|
except ObjectDoesNotExist as e:
|
||||||
|
|||||||
@@ -281,10 +281,13 @@ class ApproveJuniorAPIView(viewsets.ViewSet):
|
|||||||
serializer.save()
|
serializer.save()
|
||||||
return custom_response(SUCCESS_CODE['3023'], serializer.data, response_status=status.HTTP_200_OK)
|
return custom_response(SUCCESS_CODE['3023'], serializer.data, response_status=status.HTTP_200_OK)
|
||||||
else:
|
else:
|
||||||
|
queryset[1].guardian_code = None
|
||||||
|
queryset[1].save()
|
||||||
return custom_response(SUCCESS_CODE['3024'], response_status=status.HTTP_200_OK)
|
return custom_response(SUCCESS_CODE['3024'], response_status=status.HTTP_200_OK)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
|
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
|
|
||||||
class ApproveTaskAPIView(viewsets.ViewSet):
|
class ApproveTaskAPIView(viewsets.ViewSet):
|
||||||
"""approve junior by guardian"""
|
"""approve junior by guardian"""
|
||||||
serializer_class = ApproveTaskSerializer
|
serializer_class = ApproveTaskSerializer
|
||||||
|
|||||||
+23
-4
@@ -5,6 +5,8 @@ from rest_framework import viewsets, status, generics,views
|
|||||||
from rest_framework.permissions import IsAuthenticated
|
from rest_framework.permissions import IsAuthenticated
|
||||||
from rest_framework.pagination import PageNumberPagination
|
from rest_framework.pagination import PageNumberPagination
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
from rest_framework.filters import SearchFilter
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
import requests
|
import requests
|
||||||
"""Django app import"""
|
"""Django app import"""
|
||||||
@@ -115,8 +117,14 @@ class JuniorListAPIView(viewsets.ModelViewSet):
|
|||||||
serializer_class = JuniorDetailListSerializer
|
serializer_class = JuniorDetailListSerializer
|
||||||
queryset = Junior.objects.all()
|
queryset = Junior.objects.all()
|
||||||
permission_classes = [IsAuthenticated]
|
permission_classes = [IsAuthenticated]
|
||||||
|
filter_backends = (SearchFilter,)
|
||||||
|
search_fields = ['auth__first_name', 'auth__last_name']
|
||||||
http_method_names = ('get',)
|
http_method_names = ('get',)
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
queryset = self.filter_queryset(self.queryset)
|
||||||
|
return queryset
|
||||||
|
|
||||||
def list(self, request, *args, **kwargs):
|
def list(self, request, *args, **kwargs):
|
||||||
""" junior list"""
|
""" junior list"""
|
||||||
try:
|
try:
|
||||||
@@ -124,7 +132,8 @@ class JuniorListAPIView(viewsets.ModelViewSet):
|
|||||||
guardian_data = Guardian.objects.filter(user__email=request.user).last()
|
guardian_data = Guardian.objects.filter(user__email=request.user).last()
|
||||||
# fetch junior object
|
# fetch junior object
|
||||||
if guardian_data:
|
if guardian_data:
|
||||||
queryset = Junior.objects.filter(guardian_code__icontains=str(guardian_data.guardian_code))
|
queryset = self.get_queryset()
|
||||||
|
queryset = queryset.filter(guardian_code__icontains=str(guardian_data.guardian_code))
|
||||||
# use JuniorDetailListSerializer serializer
|
# use JuniorDetailListSerializer serializer
|
||||||
serializer = JuniorDetailListSerializer(queryset, many=True)
|
serializer = JuniorDetailListSerializer(queryset, many=True)
|
||||||
return custom_response(None, serializer.data, response_status=status.HTTP_200_OK)
|
return custom_response(None, serializer.data, response_status=status.HTTP_200_OK)
|
||||||
@@ -132,20 +141,22 @@ class JuniorListAPIView(viewsets.ModelViewSet):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
|
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
|
|
||||||
class AddJuniorAPIView(viewsets.ModelViewSet):
|
class AddJuniorAPIView(viewsets.ModelViewSet):
|
||||||
"""Add Junior by guardian"""
|
"""Add Junior by guardian"""
|
||||||
queryset = Junior.objects.all()
|
queryset = Junior.objects.all()
|
||||||
serializer_class = AddJuniorSerializer
|
serializer_class = AddJuniorSerializer
|
||||||
permission_classes = [IsAuthenticated]
|
permission_classes = [IsAuthenticated]
|
||||||
http_method_names = ('post',)
|
http_method_names = ('post',)
|
||||||
|
|
||||||
def create(self, request, *args, **kwargs):
|
def create(self, request, *args, **kwargs):
|
||||||
""" junior list"""
|
""" junior list"""
|
||||||
try:
|
try:
|
||||||
info_data = {'user': request.user, 'relationship': str(request.data['relationship']), 'email': request.data['email'], 'first_name': request.data['first_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']}
|
'last_name': request.data['last_name']}
|
||||||
if User.objects.filter(username=request.data['email']):
|
if user := User.objects.filter(username=request.data['email']).first():
|
||||||
return custom_error_response(ERROR_CODE['2059'], response_status=status.HTTP_400_BAD_REQUEST)
|
self.associate_guardian(user)
|
||||||
|
return custom_response(SUCCESS_CODE['3021'], response_status=status.HTTP_200_OK)
|
||||||
# use AddJuniorSerializer serializer
|
# use AddJuniorSerializer serializer
|
||||||
serializer = AddJuniorSerializer(data=request.data, context=info_data)
|
serializer = AddJuniorSerializer(data=request.data, context=info_data)
|
||||||
if serializer.is_valid():
|
if serializer.is_valid():
|
||||||
@@ -156,6 +167,14 @@ class AddJuniorAPIView(viewsets.ModelViewSet):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
|
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
|
def associate_guardian(self, user):
|
||||||
|
junior = Junior.objects.filter(auth=user).first()
|
||||||
|
guardian = Guardian.objects.filter(user=self.request.user).first()
|
||||||
|
junior.guardian_code = [guardian.guardian_code]
|
||||||
|
junior.save()
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
class InvitedJuniorAPIView(viewsets.ModelViewSet):
|
class InvitedJuniorAPIView(viewsets.ModelViewSet):
|
||||||
"""Junior list of assosicated guardian"""
|
"""Junior list of assosicated guardian"""
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,6 @@ def send_notification(notification_type, from_user_id, to_user_id, extra_data):
|
|||||||
""" used to send the push for the given notification type """
|
""" used to send the push for the given notification type """
|
||||||
(notification_data, from_user, to_user) = get_basic_detail(notification_type, from_user_id, to_user_id)
|
(notification_data, from_user, to_user) = get_basic_detail(notification_type, from_user_id, to_user_id)
|
||||||
user_notification_type = UserNotification.objects.filter(user=to_user).first()
|
user_notification_type = UserNotification.objects.filter(user=to_user).first()
|
||||||
# data = notification_data.data
|
|
||||||
data = notification_data
|
data = notification_data
|
||||||
Notification.objects.create(notification_type=notification_type, notification_from=from_user,
|
Notification.objects.create(notification_type=notification_type, notification_from=from_user,
|
||||||
notification_to=to_user, data=data)
|
notification_to=to_user, data=data)
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ from notifications.utils import send_notification
|
|||||||
|
|
||||||
class NotificationViewSet(viewsets.GenericViewSet):
|
class NotificationViewSet(viewsets.GenericViewSet):
|
||||||
""" used to do the notification actions """
|
""" used to do the notification actions """
|
||||||
serializer_class = None
|
serializer_class = RegisterDevice
|
||||||
permission_classes = [IsAuthenticated, ]
|
permission_classes = [IsAuthenticated, ]
|
||||||
|
|
||||||
@action(methods=['post'], detail=False, url_path='device', url_name='device', serializer_class=RegisterDevice)
|
@action(methods=['post'], detail=False, url_path='device', url_name='device', serializer_class=RegisterDevice)
|
||||||
@@ -32,7 +32,7 @@ class NotificationViewSet(viewsets.GenericViewSet):
|
|||||||
serializer.save()
|
serializer.save()
|
||||||
return custom_response(SUCCESS_CODE["3000"])
|
return custom_response(SUCCESS_CODE["3000"])
|
||||||
|
|
||||||
@action(methods=['get'], detail=False, url_path='test', url_name='test', serializer_class=None)
|
@action(methods=['get'], detail=False, url_path='test', url_name='test')
|
||||||
def send_test_notification(self, request):
|
def send_test_notification(self, request):
|
||||||
"""
|
"""
|
||||||
to send test notification
|
to send test notification
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Django 4.2.2 on 2023-08-01 07:35
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('web_admin', '0003_defaultarticlecardimage_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='surveyoption',
|
||||||
|
name='survey',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='options', to='web_admin.articlesurvey'),
|
||||||
|
),
|
||||||
|
]
|
||||||
+1
-1
@@ -56,7 +56,7 @@ class SurveyOption(models.Model):
|
|||||||
"""
|
"""
|
||||||
Survey Options model
|
Survey Options model
|
||||||
"""
|
"""
|
||||||
survey = models.ForeignKey(ArticleSurvey, on_delete=models.CASCADE, related_name='survey_options')
|
survey = models.ForeignKey(ArticleSurvey, on_delete=models.CASCADE, related_name='options')
|
||||||
option = models.CharField(max_length=255)
|
option = models.CharField(max_length=255)
|
||||||
is_answer = models.BooleanField(default=False)
|
is_answer = models.BooleanField(default=False)
|
||||||
created_at = models.DateTimeField(auto_now_add=True)
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ from base.constants import (ARTICLE_SURVEY_POINTS, MAX_ARTICLE_CARD, MIN_ARTICLE
|
|||||||
from base.messages import ERROR_CODE
|
from base.messages import ERROR_CODE
|
||||||
from guardian.utils import upload_image_to_alibaba
|
from guardian.utils import upload_image_to_alibaba
|
||||||
from web_admin.models import Article, ArticleCard, SurveyOption, ArticleSurvey, DefaultArticleCardImage
|
from web_admin.models import Article, ArticleCard, SurveyOption, ArticleSurvey, DefaultArticleCardImage
|
||||||
from web_admin.utils import pop_id
|
from web_admin.utils import pop_id, get_image_url
|
||||||
|
|
||||||
USER = get_user_model()
|
USER = get_user_model()
|
||||||
|
|
||||||
@@ -32,12 +32,9 @@ class ArticleCardSerializer(serializers.ModelSerializer):
|
|||||||
fields = ('id', 'title', 'description', 'image', 'image_url')
|
fields = ('id', 'title', 'description', 'image', 'image_url')
|
||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
if 'image' in validated_data and validated_data['image'] is not None:
|
validated_data['image_url'] = get_image_url(validated_data)
|
||||||
image = validated_data.pop('image')
|
article = Article.objects.all().first()
|
||||||
filename = f"{ARTICLE_CARD_IMAGE_FOLDER}/{image.name}"
|
article_card = ArticleCard.objects.create(article=article, **validated_data)
|
||||||
# upload image on ali baba
|
|
||||||
validated_data['image_url'] = upload_image_to_alibaba(image, filename)
|
|
||||||
article_card = ArticleCard.objects.create(article_id='1', **validated_data)
|
|
||||||
return article_card
|
return article_card
|
||||||
|
|
||||||
|
|
||||||
@@ -60,14 +57,14 @@ class ArticleSurveySerializer(serializers.ModelSerializer):
|
|||||||
article survey serializer
|
article survey serializer
|
||||||
"""
|
"""
|
||||||
id = serializers.IntegerField(required=False)
|
id = serializers.IntegerField(required=False)
|
||||||
survey_options = SurveyOptionSerializer(many=True)
|
options = SurveyOptionSerializer(many=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
"""
|
"""
|
||||||
meta class
|
meta class
|
||||||
"""
|
"""
|
||||||
model = ArticleSurvey
|
model = ArticleSurvey
|
||||||
fields = ('id', 'question', 'survey_options')
|
fields = ('id', 'question', 'options')
|
||||||
|
|
||||||
|
|
||||||
class ArticleSerializer(serializers.ModelSerializer):
|
class ArticleSerializer(serializers.ModelSerializer):
|
||||||
@@ -111,16 +108,12 @@ class ArticleSerializer(serializers.ModelSerializer):
|
|||||||
|
|
||||||
for card in article_cards:
|
for card in article_cards:
|
||||||
card = pop_id(card)
|
card = pop_id(card)
|
||||||
if 'image' in card and card['image'] is not None:
|
card['image_url'] = get_image_url(card)
|
||||||
image = card.pop('image')
|
|
||||||
filename = f"{ARTICLE_CARD_IMAGE_FOLDER}/{image.name}"
|
|
||||||
# upload image on ali baba
|
|
||||||
card['image_url'] = upload_image_to_alibaba(image, filename)
|
|
||||||
ArticleCard.objects.create(article=article, **card)
|
ArticleCard.objects.create(article=article, **card)
|
||||||
|
|
||||||
for survey in article_survey:
|
for survey in article_survey:
|
||||||
survey = pop_id(survey)
|
survey = pop_id(survey)
|
||||||
options = survey.pop('survey_options')
|
options = survey.pop('options')
|
||||||
survey_obj = ArticleSurvey.objects.create(article=article, points=ARTICLE_SURVEY_POINTS, **survey)
|
survey_obj = ArticleSurvey.objects.create(article=article, points=ARTICLE_SURVEY_POINTS, **survey)
|
||||||
for option in options:
|
for option in options:
|
||||||
option = pop_id(option)
|
option = pop_id(option)
|
||||||
@@ -139,40 +132,36 @@ class ArticleSerializer(serializers.ModelSerializer):
|
|||||||
instance.title = validated_data.get('title', instance.title)
|
instance.title = validated_data.get('title', instance.title)
|
||||||
instance.description = validated_data.get('description', instance.description)
|
instance.description = validated_data.get('description', instance.description)
|
||||||
instance.save()
|
instance.save()
|
||||||
|
prev_card = list(ArticleCard.objects.filter(article=instance).values_list('id', flat=True))
|
||||||
# Update or create cards
|
# Update or create cards
|
||||||
for card_data in article_cards:
|
for card_data in article_cards:
|
||||||
card_id = card_data.get('id', None)
|
card_id = card_data.get('id', None)
|
||||||
if card_id:
|
if card_id:
|
||||||
|
prev_card.remove(card_id)
|
||||||
card = ArticleCard.objects.get(id=card_id, article=instance)
|
card = ArticleCard.objects.get(id=card_id, article=instance)
|
||||||
card.title = card_data.get('title', card.title)
|
card.title = card_data.get('title', card.title)
|
||||||
card.description = card_data.get('description', card.description)
|
card.description = card_data.get('description', card.description)
|
||||||
if 'image' in card_data and card_data['image'] is not None:
|
card.image_url = get_image_url(card_data)
|
||||||
image = card_data.pop('image')
|
|
||||||
filename = f"{ARTICLE_CARD_IMAGE_FOLDER}/{image.name}"
|
|
||||||
# upload image on ali baba
|
|
||||||
card.image_url = upload_image_to_alibaba(image, filename)
|
|
||||||
card.save()
|
card.save()
|
||||||
else:
|
else:
|
||||||
card_data = pop_id(card_data)
|
card_data = pop_id(card_data)
|
||||||
if 'image' in card_data and card_data['image'] is not None:
|
card_data['image_url'] = get_image_url(card_data)
|
||||||
image = card_data.pop('image')
|
|
||||||
filename = f"{ARTICLE_CARD_IMAGE_FOLDER}/{image.name}"
|
|
||||||
# upload image on ali baba
|
|
||||||
card_data['image_url'] = upload_image_to_alibaba(image, filename)
|
|
||||||
ArticleCard.objects.create(article=instance, **card_data)
|
ArticleCard.objects.create(article=instance, **card_data)
|
||||||
|
ArticleCard.objects.filter(id__in=prev_card, article=instance).delete()
|
||||||
|
|
||||||
|
prev_survey = list(ArticleSurvey.objects.filter(article=instance).values_list('id', flat=True))
|
||||||
# Update or create survey sections
|
# Update or create survey sections
|
||||||
for survey_data in article_survey:
|
for survey_data in article_survey:
|
||||||
survey_id = survey_data.get('id', None)
|
survey_id = survey_data.get('id', None)
|
||||||
options_data = survey_data.pop('survey_options')
|
options_data = survey_data.pop('options')
|
||||||
if survey_id:
|
if survey_id:
|
||||||
|
prev_survey.remove(survey_id)
|
||||||
survey = ArticleSurvey.objects.get(id=survey_id, article=instance)
|
survey = ArticleSurvey.objects.get(id=survey_id, article=instance)
|
||||||
survey.question = survey_data.get('question', survey.question)
|
survey.question = survey_data.get('question', survey.question)
|
||||||
survey.save()
|
survey.save()
|
||||||
else:
|
else:
|
||||||
survey_data = pop_id(survey_data)
|
survey_data = pop_id(survey_data)
|
||||||
survey = ArticleSurvey.objects.create(article=instance, **survey_data)
|
survey = ArticleSurvey.objects.create(article=instance, points=ARTICLE_SURVEY_POINTS, **survey_data)
|
||||||
|
|
||||||
# Update or create survey options
|
# Update or create survey options
|
||||||
for option_data in options_data:
|
for option_data in options_data:
|
||||||
@@ -185,6 +174,7 @@ class ArticleSerializer(serializers.ModelSerializer):
|
|||||||
else:
|
else:
|
||||||
option_data = pop_id(option_data)
|
option_data = pop_id(option_data)
|
||||||
SurveyOption.objects.create(survey=survey, **option_data)
|
SurveyOption.objects.create(survey=survey, **option_data)
|
||||||
|
ArticleSurvey.objects.filter(id__in=prev_survey, article=instance).delete()
|
||||||
|
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
@@ -210,6 +200,9 @@ class DefaultArticleCardImageSerializer(serializers.ModelSerializer):
|
|||||||
"""
|
"""
|
||||||
if 'image' not in attrs and attrs.get('image') is None:
|
if 'image' not in attrs and attrs.get('image') is None:
|
||||||
raise serializers.ValidationError({'details': ERROR_CODE['2061']})
|
raise serializers.ValidationError({'details': ERROR_CODE['2061']})
|
||||||
|
image = attrs.get('image')
|
||||||
|
if image and image.size == NUMBER['zero']:
|
||||||
|
raise serializers.ValidationError(ERROR_CODE['2035'])
|
||||||
return attrs
|
return attrs
|
||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
@@ -217,12 +210,7 @@ class DefaultArticleCardImageSerializer(serializers.ModelSerializer):
|
|||||||
to create and upload image
|
to create and upload image
|
||||||
:return: card_image object
|
:return: card_image object
|
||||||
"""
|
"""
|
||||||
image = validated_data.pop('image')
|
validated_data['image_url'] = get_image_url(validated_data)
|
||||||
filename = f"{ARTICLE_CARD_IMAGE_FOLDER}/{image.name}"
|
|
||||||
if image and image.size == NUMBER['zero']:
|
|
||||||
raise serializers.ValidationError(ERROR_CODE['2035'])
|
|
||||||
# upload image on ali baba
|
|
||||||
validated_data['image_url'] = upload_image_to_alibaba(image, filename)
|
|
||||||
|
|
||||||
card_image = DefaultArticleCardImage.objects.create(**validated_data)
|
card_image = DefaultArticleCardImage.objects.create(**validated_data)
|
||||||
return card_image
|
return card_image
|
||||||
|
|||||||
@@ -1,88 +1,134 @@
|
|||||||
"""
|
"""
|
||||||
web_admin auth serializers file
|
web_admin auth serializers file
|
||||||
"""
|
"""
|
||||||
|
# python imports
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
# django imports
|
# django imports
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from django.conf import settings
|
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from rest_framework import status
|
|
||||||
from templated_email import send_templated_mail
|
|
||||||
|
|
||||||
# local imports
|
# local imports
|
||||||
from account.models import UserEmailOtp
|
from account.models import UserEmailOtp
|
||||||
from account.utils import custom_error_response
|
from base.constants import USER_TYPE
|
||||||
from base.messages import ERROR_CODE
|
from base.messages import ERROR_CODE
|
||||||
from guardian.tasks import generate_otp
|
from guardian.tasks import generate_otp
|
||||||
|
from base.tasks import send_email_otp
|
||||||
|
|
||||||
USER = get_user_model()
|
USER = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
class AdminForgotPasswordSerializer(serializers.ModelSerializer):
|
class AdminOTPSerializer(serializers.ModelSerializer):
|
||||||
email = serializers.EmailField(required=True)
|
"""
|
||||||
|
admin forgot password serializer
|
||||||
|
"""
|
||||||
|
email = serializers.EmailField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
"""
|
||||||
|
meta class
|
||||||
|
"""
|
||||||
model = USER
|
model = USER
|
||||||
fields = ('email',)
|
fields = ('email',)
|
||||||
|
|
||||||
def validate(self, attrs):
|
def validate(self, attrs):
|
||||||
""" used to validate the incoming data """
|
""" used to validate the incoming data """
|
||||||
user = USER.objects.filter(email=attrs['email']).first()
|
user = USER.objects.filter(email=attrs.get('email')).first()
|
||||||
if not user:
|
if not user:
|
||||||
raise serializers.ValidationError(ERROR_CODE['2004'])
|
raise serializers.ValidationError({'details': ERROR_CODE['2004']})
|
||||||
elif not user.is_superuser:
|
elif not user.is_superuser:
|
||||||
raise serializers.ValidationError(ERROR_CODE['2036'])
|
raise serializers.ValidationError({'details': ERROR_CODE['2063']})
|
||||||
attrs.update({'user': user})
|
attrs.update({'user': user})
|
||||||
return attrs
|
return attrs
|
||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
|
"""
|
||||||
|
to send otp
|
||||||
|
:return: user_data
|
||||||
|
"""
|
||||||
email = validated_data['email']
|
email = validated_data['email']
|
||||||
try:
|
|
||||||
USER.objects.get(email=email)
|
|
||||||
except USER.DoesNotExist:
|
|
||||||
return custom_error_response(ERROR_CODE['2004'], response_status=status.HTTP_404_NOT_FOUND)
|
|
||||||
verification_code = generate_otp()
|
verification_code = generate_otp()
|
||||||
|
|
||||||
# Send the verification code to the user's email
|
# Send the verification code to the user's email
|
||||||
from_email = settings.EMAIL_FROM_ADDRESS
|
send_email_otp.delay(email, verification_code)
|
||||||
recipient_list = [email]
|
|
||||||
send_templated_mail(
|
|
||||||
template_name='email_reset_verification.email',
|
|
||||||
from_email=from_email,
|
|
||||||
recipient_list=recipient_list,
|
|
||||||
context={
|
|
||||||
'verification_code': verification_code
|
|
||||||
}
|
|
||||||
)
|
|
||||||
expiry = timezone.now() + timezone.timedelta(days=1)
|
expiry = timezone.now() + timezone.timedelta(days=1)
|
||||||
user_data, created = UserEmailOtp.objects.get_or_create(email=email)
|
user_data, created = UserEmailOtp.objects.update_or_create(email=email,
|
||||||
if created:
|
defaults={
|
||||||
user_data.expired_at = expiry
|
"otp": verification_code,
|
||||||
if user_data:
|
"expired_at": expiry,
|
||||||
user_data.otp = verification_code
|
"user_type": dict(USER_TYPE).get('3'),
|
||||||
user_data.expired_at = expiry
|
})
|
||||||
user_data.save()
|
|
||||||
return user_data
|
return user_data
|
||||||
|
|
||||||
|
|
||||||
class AdminVerifyOTPSerializer(serializers.Serializer):
|
class AdminVerifyOTPSerializer(serializers.Serializer):
|
||||||
|
"""
|
||||||
|
admin verify otp serializer
|
||||||
|
"""
|
||||||
|
email = serializers.EmailField()
|
||||||
otp = serializers.CharField(max_length=6, min_length=6)
|
otp = serializers.CharField(max_length=6, min_length=6)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
""" meta class """
|
""" meta class """
|
||||||
fields = ('otp',)
|
fields = ('email', 'otp',)
|
||||||
|
|
||||||
def validate(self, attrs):
|
def validate(self, attrs):
|
||||||
otp = attrs.pop('otp')
|
"""
|
||||||
|
to validate data
|
||||||
|
:return: validated data
|
||||||
|
"""
|
||||||
|
email = attrs.get('email')
|
||||||
|
otp = attrs.get('otp')
|
||||||
|
|
||||||
# fetch email otp object of the user
|
# fetch email otp object of the user
|
||||||
user_opt_details = UserEmailOtp.objects.filter(otp=otp).last()
|
user_otp_details = UserEmailOtp.objects.filter(email=email, otp=otp).last()
|
||||||
if not user_opt_details:
|
if not user_otp_details:
|
||||||
raise serializers.ValidationError(ERROR_CODE['2008'])
|
raise serializers.ValidationError({'details': ERROR_CODE['2064']})
|
||||||
if user_opt_details.expired_at.replace(tzinfo=None) < datetime.utcnow():
|
if user_otp_details.user_type != dict(USER_TYPE).get('3'):
|
||||||
raise serializers.ValidationError(ERROR_CODE['2029'])
|
raise serializers.ValidationError({'details': ERROR_CODE['2063']})
|
||||||
user_details = USER.objects.filter(email=user_opt_details.email).last()
|
if user_otp_details.expired_at.replace(tzinfo=None) < datetime.utcnow():
|
||||||
user_opt_details.delete()
|
raise serializers.ValidationError({'details': ERROR_CODE['2029']})
|
||||||
if user_details:
|
user_otp_details.is_verified = True
|
||||||
return attrs
|
user_otp_details.save()
|
||||||
|
return attrs
|
||||||
|
|
||||||
|
|
||||||
|
class AdminCreatePasswordSerializer(serializers.ModelSerializer):
|
||||||
|
"""
|
||||||
|
admin create new password serializer
|
||||||
|
"""
|
||||||
|
email = serializers.EmailField()
|
||||||
|
new_password = serializers.CharField()
|
||||||
|
confirm_password = serializers.CharField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
"""
|
||||||
|
meta class
|
||||||
|
"""
|
||||||
|
model = USER
|
||||||
|
fields = ('email', 'new_password', 'confirm_password')
|
||||||
|
|
||||||
|
def validate(self, attrs):
|
||||||
|
"""
|
||||||
|
to validate data
|
||||||
|
:return: validated data
|
||||||
|
"""
|
||||||
|
email = attrs.get('email')
|
||||||
|
new_password = attrs.get('new_password')
|
||||||
|
confirm_password = attrs.get('confirm_password')
|
||||||
|
|
||||||
|
# matching password
|
||||||
|
if new_password != confirm_password:
|
||||||
|
raise serializers.ValidationError({'details': ERROR_CODE['2065']})
|
||||||
|
|
||||||
|
user_otp_details = UserEmailOtp.objects.filter(email=email, is_verified=True).last()
|
||||||
|
if not user_otp_details:
|
||||||
|
raise serializers.ValidationError({'details': ERROR_CODE['2064']})
|
||||||
|
if user_otp_details.user_type != dict(USER_TYPE).get('3'):
|
||||||
|
raise serializers.ValidationError({'details': ERROR_CODE['2063']})
|
||||||
|
user_otp_details.delete()
|
||||||
|
return attrs
|
||||||
|
|||||||
+2
-2
@@ -7,7 +7,7 @@ from rest_framework import routers
|
|||||||
|
|
||||||
# local imports
|
# local imports
|
||||||
from web_admin.views.article import ArticleViewSet, DefaultArticleCardImagesViewSet, UserManagementViewSet
|
from web_admin.views.article import ArticleViewSet, DefaultArticleCardImagesViewSet, UserManagementViewSet
|
||||||
from web_admin.views.auth import ForgetAndResetPasswordViewSet
|
from web_admin.views.auth import ForgotAndResetPasswordViewSet
|
||||||
|
|
||||||
# initiate router
|
# initiate router
|
||||||
router = routers.SimpleRouter()
|
router = routers.SimpleRouter()
|
||||||
@@ -17,7 +17,7 @@ router.register('default-card-images', DefaultArticleCardImagesViewSet, basename
|
|||||||
router.register('user', UserManagementViewSet, basename='user')
|
router.register('user', UserManagementViewSet, basename='user')
|
||||||
|
|
||||||
# forgot and reset password api for admin
|
# forgot and reset password api for admin
|
||||||
router.register('admin', ForgetAndResetPasswordViewSet, basename='admin')
|
router.register('admin', ForgotAndResetPasswordViewSet, basename='admin')
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('api/v1/', include(router.urls)),
|
path('api/v1/', include(router.urls)),
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
"""
|
"""
|
||||||
web_utils file
|
web_utils file
|
||||||
"""
|
"""
|
||||||
|
from base.constants import ARTICLE_CARD_IMAGE_FOLDER
|
||||||
|
from guardian.utils import upload_image_to_alibaba
|
||||||
|
|
||||||
|
|
||||||
def pop_id(data):
|
def pop_id(data):
|
||||||
@@ -11,3 +13,14 @@ def pop_id(data):
|
|||||||
"""
|
"""
|
||||||
data.pop('id') if 'id' in data else data
|
data.pop('id') if 'id' in data else data
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def get_image_url(data):
|
||||||
|
if 'image_url' in data:
|
||||||
|
return data['image_url']
|
||||||
|
elif 'image' in data and data['image'] is not None:
|
||||||
|
image = data.pop('image')
|
||||||
|
filename = f"{ARTICLE_CARD_IMAGE_FOLDER}/{image.name}"
|
||||||
|
# upload image on ali baba
|
||||||
|
image_url = upload_image_to_alibaba(image, filename)
|
||||||
|
return image_url
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class ArticleViewSet(GenericViewSet, mixins.CreateModelMixin, mixins.UpdateModel
|
|||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
article = self.queryset.objects.filter(is_deleted=False).prefetch_related(
|
article = self.queryset.objects.filter(is_deleted=False).prefetch_related(
|
||||||
'article_cards', 'article_survey', 'article_survey__survey_options'
|
'article_cards', 'article_survey', 'article_survey__options'
|
||||||
).order_by('-created_at')
|
).order_by('-created_at')
|
||||||
queryset = self.filter_queryset(article)
|
queryset = self.filter_queryset(article)
|
||||||
return queryset
|
return queryset
|
||||||
@@ -110,7 +110,7 @@ class ArticleViewSet(GenericViewSet, mixins.CreateModelMixin, mixins.UpdateModel
|
|||||||
return custom_error_response(ERROR_CODE["2041"], status.HTTP_400_BAD_REQUEST)
|
return custom_error_response(ERROR_CODE["2041"], status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
@action(methods=['get'], url_name='remove_card', url_path='remove_card',
|
@action(methods=['get'], url_name='remove_card', url_path='remove_card',
|
||||||
detail=True, serializer_class=None)
|
detail=True)
|
||||||
def remove_article_card(self, request, *args, **kwargs):
|
def remove_article_card(self, request, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
article card remove (delete) api method
|
article card remove (delete) api method
|
||||||
@@ -126,7 +126,7 @@ class ArticleViewSet(GenericViewSet, mixins.CreateModelMixin, mixins.UpdateModel
|
|||||||
return custom_error_response(ERROR_CODE["2042"], response_status=status.HTTP_400_BAD_REQUEST)
|
return custom_error_response(ERROR_CODE["2042"], response_status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
@action(methods=['get'], url_name='remove_survey', url_path='remove_survey',
|
@action(methods=['get'], url_name='remove_survey', url_path='remove_survey',
|
||||||
detail=True, serializer_class=None)
|
detail=True)
|
||||||
def remove_article_survey(self, request, *args, **kwargs):
|
def remove_article_survey(self, request, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
article survey remove (delete) api method
|
article survey remove (delete) api method
|
||||||
@@ -170,7 +170,7 @@ class DefaultArticleCardImagesViewSet(GenericViewSet, mixins.CreateModelMixin, m
|
|||||||
api to upload and list default article card images
|
api to upload and list default article card images
|
||||||
"""
|
"""
|
||||||
serializer_class = DefaultArticleCardImageSerializer
|
serializer_class = DefaultArticleCardImageSerializer
|
||||||
# permission_classes = [IsAuthenticated, AdminPermission]
|
permission_classes = [IsAuthenticated, AdminPermission]
|
||||||
queryset = DefaultArticleCardImage.objects.all()
|
queryset = DefaultArticleCardImage.objects.all()
|
||||||
|
|
||||||
def create(self, request, *args, **kwargs):
|
def create(self, request, *args, **kwargs):
|
||||||
|
|||||||
+40
-20
@@ -2,42 +2,62 @@
|
|||||||
web_admin auth views file
|
web_admin auth views file
|
||||||
"""
|
"""
|
||||||
# django imports
|
# django imports
|
||||||
from rest_framework.viewsets import GenericViewSet, mixins
|
from rest_framework.viewsets import GenericViewSet
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
|
from rest_framework import status
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
|
|
||||||
# local imports
|
# local imports
|
||||||
from account.utils import custom_response
|
from account.utils import custom_response, custom_error_response
|
||||||
from base.constants import USER_TYPE
|
|
||||||
from base.messages import SUCCESS_CODE, ERROR_CODE
|
from base.messages import SUCCESS_CODE, ERROR_CODE
|
||||||
from web_admin.permission import AdminPermission
|
from web_admin.serializers.auth_serializer import (AdminOTPSerializer, AdminVerifyOTPSerializer,
|
||||||
from web_admin.serializers.auth_serializer import AdminForgotPasswordSerializer, AdminVerifyOTPSerializer
|
AdminCreatePasswordSerializer)
|
||||||
|
|
||||||
USER = get_user_model()
|
USER = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
class ForgetAndResetPasswordViewSet(GenericViewSet):
|
class ForgotAndResetPasswordViewSet(GenericViewSet):
|
||||||
|
"""
|
||||||
|
to reset admin password
|
||||||
|
"""
|
||||||
queryset = None
|
queryset = None
|
||||||
|
|
||||||
@action(methods=['post'], url_name='forgot-password', url_path='forgot-password',
|
@action(methods=['post'], url_name='otp', url_path='otp',
|
||||||
detail=False, serializer_class=AdminForgotPasswordSerializer)
|
detail=False, serializer_class=AdminOTPSerializer)
|
||||||
def admin_forgot_password(self, request):
|
def admin_otp(self, request):
|
||||||
|
"""
|
||||||
|
api method to send otp
|
||||||
|
:return: success message
|
||||||
|
"""
|
||||||
serializer = self.serializer_class(data=request.data)
|
serializer = self.serializer_class(data=request.data)
|
||||||
serializer.is_valid(raise_exception=True)
|
if serializer.is_valid():
|
||||||
serializer.save()
|
serializer.save()
|
||||||
return custom_response(SUCCESS_CODE['3015'])
|
return custom_response(SUCCESS_CODE['3015'])
|
||||||
|
return custom_error_response(ERROR_CODE['2063'], status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
@action(methods=['post'], url_name='verify-otp', url_path='verify-otp',
|
@action(methods=['post'], url_name='verify-otp', url_path='verify-otp',
|
||||||
detail=False, serializer_class=AdminVerifyOTPSerializer)
|
detail=False, serializer_class=AdminVerifyOTPSerializer)
|
||||||
def admin_verify_otp(self, request):
|
def admin_verify_otp(self, request):
|
||||||
|
"""
|
||||||
|
api method to verify otp
|
||||||
|
:return: success message
|
||||||
|
"""
|
||||||
serializer = self.serializer_class(data=request.data)
|
serializer = self.serializer_class(data=request.data)
|
||||||
serializer.is_valid(raise_exception=True)
|
if serializer.is_valid():
|
||||||
return custom_response(SUCCESS_CODE['3011'])
|
return custom_response(SUCCESS_CODE['3011'])
|
||||||
|
return custom_error_response(ERROR_CODE['2063'], status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
@action(methods=['post'], url_name='resend-otp', url_path='resend-otp',
|
@action(methods=['post'], url_name='create-password', url_path='create-password',
|
||||||
detail=False, serializer_class=AdminForgotPasswordSerializer)
|
detail=False, serializer_class=AdminCreatePasswordSerializer)
|
||||||
def admin_resend_otp(self, request):
|
def admin_create_password(self, request):
|
||||||
|
"""
|
||||||
|
api method to create new password
|
||||||
|
:return: success message
|
||||||
|
"""
|
||||||
serializer = self.serializer_class(data=request.data)
|
serializer = self.serializer_class(data=request.data)
|
||||||
serializer.is_valid(raise_exception=True)
|
if serializer.is_valid():
|
||||||
serializer.save()
|
user = USER.objects.filter(email=serializer.validated_data.get('email')).first()
|
||||||
return custom_response(SUCCESS_CODE['3015'])
|
user.set_password(serializer.validated_data.get('new_password'))
|
||||||
|
user.save()
|
||||||
|
return custom_response(SUCCESS_CODE['3007'])
|
||||||
|
return custom_error_response(ERROR_CODE['2064'], status.HTTP_400_BAD_REQUEST)
|
||||||
|
|||||||
Reference in New Issue
Block a user