Compare commits

...
23 Commits
Author SHA1 Message Date
abutalib-kiwi af121f5a53 changes in article update api and get image url method 2023-08-02 11:16:12 +05:30
abutalib-kiwi d3564efbb9 change in update api, added method to upload and get image url 2023-08-01 20:15:01 +05:30
abutalib-kiwi ee92c98f34 article list api changes, changed related name for survey_options to options 2023-08-01 13:14:22 +05:30
dilipshrivastwa-kiwi fbce04b97e Merge pull request #129 from KiwiTechLLC/ZBKADM-67
fixed add junior api
2023-07-28 19:30:39 +05:30
abutalib-kiwi afaed69eec fixed add junior api 2023-07-28 19:19:59 +05:30
dilipshrivastwa-kiwi 3c0eaf676e Merge pull request #128 from KiwiTechLLC/ZBKADM-67
fixed add junior api
2023-07-28 19:00:41 +05:30
abutalib-kiwi 6ffaa66a4d fixed add junior api 2023-07-28 18:57:11 +05:30
dilipshrivastwa-kiwi 4b8e7189c1 Merge pull request #127 from KiwiTechLLC/ZBKADM-67
changes in approve junior and add juinior api, added search in junior…
2023-07-28 18:11:54 +05:30
abutalib-kiwi d68f24543d changes in approve junior and add juinior api, added search in junior list api 2023-07-28 17:32:02 +05:30
dilipshrivastwa-kiwi 3534561697 Merge pull request #126 from KiwiTechLLC/ZBKADM-67
some changes in artcle api
2023-07-28 16:50:26 +05:30
abutalib-kiwi de774111c0 some changes in artcle api 2023-07-28 16:08:40 +05:30
dilipshrivastwa-kiwi bab50e4492 Merge pull request #123 from KiwiTechLLC/ZBKADM-67
some changes in admin password reset related api
2023-07-27 19:36:01 +05:30
abutalib-kiwi 151a177e76 some changes in admin password reset related api 2023-07-27 19:29:12 +05:30
dilipshrivastwa-kiwi 73a62186a7 Merge pull request #122 from KiwiTechLLC/ZBKADM-67
added request status in expired task cronjob
2023-07-27 15:32:17 +05:30
abutalib-kiwi 83c66ab3b6 added request status in expired task cronjob 2023-07-27 15:31:25 +05:30
dilipshrivastwa-kiwi 94e53e1dcd Merge pull request #121 from KiwiTechLLC/ZBKADM-67
added task to send otp on email
2023-07-27 13:12:36 +05:30
abutalib-kiwi 68b77ef766 added task to send otp on email 2023-07-27 12:59:41 +05:30
dilipshrivastwa-kiwi a2000459d3 Merge pull request #119 from KiwiTechLLC/ZBKADM-67
some changes in forgot password api
2023-07-27 11:06:09 +05:30
abutalib-kiwi c079f3ceca some changes in forgot password api 2023-07-27 10:59:10 +05:30
dilipshrivastwa-kiwi 671cdfc27b Merge pull request #118 from KiwiTechLLC/ZBKADM-67
change password api
2023-07-26 17:51:32 +05:30
abutalib-kiwi a83e27b12a Merge branch 'dev' into ZBKADM-67 2023-07-26 17:45:22 +05:30
abutalib-kiwi 87aa1af02b change password api 2023-07-26 17:16:36 +05:30
dilipshrivastwa-kiwi 5f3026f08f Merge pull request #116 from KiwiTechLLC/sprint3
jira-28 notification
2023-07-26 16:51:46 +05:30
18 changed files with 254 additions and 112 deletions
+1 -1
View File
@@ -21,4 +21,4 @@ static/*
__pycache__/ __pycache__/
*.env *.env
ve/* ve/*
celerybeat-schedule
+4 -1
View File
@@ -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 = {
+29
View File
@@ -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.
+3
View File
@@ -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
View File
@@ -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:
+3
View File
@@ -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
View File
@@ -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"""
-1
View File
@@ -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)
+2 -2
View File
@@ -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
View File
@@ -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)
+22 -34
View File
@@ -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
+87 -41
View File
@@ -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
View File
@@ -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)),
+13
View File
@@ -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
+4 -4
View File
@@ -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
View File
@@ -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)