Compare commits

...
26 Commits
Author SHA1 Message Date
abutalib-kiwi a211baa10a added cors Allow specific origins setting, unpublish article api, pagination in notification list 2023-09-04 15:46:36 +05:30
abutalib-kiwi ec585d35f3 added and modifid pagination 2023-09-04 13:11:25 +05:30
abutalib-kiwi d62efa2139 added and modifid pagination 2023-09-04 13:09:54 +05:30
dilipshrivastwa-kiwi e1ef289c69 Merge pull request #298 from KiwiTechLLC/sprint6-bugs
Sprint6 bugs
2023-09-01 17:05:50 +05:30
jain 4f79a690c1 unrestrict logout and refresh token api while login in multiple device 2023-09-01 16:25:05 +05:30
jain 0af2a35206 task assign to multiple junior 2023-09-01 12:14:15 +05:30
gauravmishra-kiwi a262b03292 Merge pull request #295 from KiwiTechLLC/sprint6-bugs
answer api
2023-08-29 21:32:11 +05:30
jain d24f075110 answer api 2023-08-29 21:28:36 +05:30
Ankitajain-kiwi f7624bc1e7 Merge pull request #292 from KiwiTechLLC/sprint6-bugs
answer api
2023-08-29 19:47:55 +05:30
jain dc12b35842 answer api 2023-08-29 19:38:14 +05:30
Abu Talib a80f9db557 Merge pull request #291 from KiwiTechLLC/sprint6-bugs
otp expiry
2023-08-29 19:05:18 +05:30
jain 3ad29e677d article page 2023-08-29 18:56:51 +05:30
jain 8b0a5d9a8e otp expiry 2023-08-29 18:33:47 +05:30
Ankitajain-kiwi 16d823f97d Merge pull request #290 from KiwiTechLLC/sprint6-bugs
elif for guardian code
2023-08-29 17:51:42 +05:30
jain d4008d6cc2 elif for guardian code 2023-08-29 17:50:58 +05:30
dilipshrivastwa-kiwi 3dae22a870 Merge pull request #287 from KiwiTechLLC/sprint6-bugs
Sprint6 bugs
2023-08-29 11:56:58 +05:30
jain a8d291474a search junior task 2023-08-29 11:52:47 +05:30
jain e6482167ae Merge branch 'sprint6-bugs' of github.com:KiwiTechLLC/ZODBank-Backend into sprint6-bugs 2023-08-29 11:51:11 +05:30
jain 9a932d31b5 Merge branch 'dev' of github.com:KiwiTechLLC/ZODBank-Backend into sprint6-bugs 2023-08-29 11:50:44 +05:30
jain e2c84eb83d search junior task 2023-08-29 11:49:59 +05:30
Ankitajain-kiwi 5bfc3966b3 Merge branch 'dev' into sprint6-bugs 2023-08-29 10:43:34 +05:30
jain 37d191eef8 add message for blank search 2023-08-29 10:41:44 +05:30
Abu Talib e9ee8ec8b2 Merge pull request #285 from KiwiTechLLC/sprint6-bugs
condition in add junior
2023-08-28 20:14:43 +05:30
jain cc5ecc0647 Merge branch 'dev' of github.com:KiwiTechLLC/ZODBank-Backend into sprint6-bugs 2023-08-28 20:10:36 +05:30
jain 63dfd731fc condition in add junior 2023-08-28 20:09:39 +05:30
dilipshrivastwa-kiwi e9d4d7091e Merge pull request #284 from KiwiTechLLC/ZBKBCK-48
added notification for existing junior add, modified leaderboard meth…
2023-08-28 19:51:20 +05:30
14 changed files with 169 additions and 96 deletions
+2 -1
View File
@@ -45,11 +45,12 @@ class CustomMiddleware(object):
device_type = str(request.META.get('HTTP_TYPE'))
api_endpoint = request.path
unrestricted_api = ('/api/v1/user/login/', '/api/v1/logout/', '/api/v1/generate-token/')
if request.user.is_authenticated:
# device details
if device_id:
device_details = UserDeviceDetails.objects.filter(user=request.user, device_id=device_id).last()
if not device_details and api_endpoint != '/api/v1/user/login/':
if not device_details and api_endpoint not in unrestricted_api:
custom_error = custom_error_response(ERROR_CODE['2037'], response_status=status.HTTP_404_NOT_FOUND)
response = custom_response(custom_error)
if user_type and str(user_type) == str(NUMBER['one']):
+1 -1
View File
@@ -322,7 +322,7 @@ class ForgotPasswordAPIView(views.APIView):
send_all_email.delay(
'email_reset_verification.email', email, verification_code
)
expiry = OTP_EXPIRY
expiry = timezone.now() + timezone.timedelta(days=1)
user_data, created = UserEmailOtp.objects.get_or_create(
email=email
)
+2 -2
View File
@@ -147,8 +147,8 @@ SUCCESS_CODE = {
"3018": "Task created successfully",
"3019": "Support Email sent successfully",
"3020": "Logged out successfully.",
"3021": "Add junior successfully",
"3022": "Remove junior successfully",
"3021": "Added junior successfully",
"3022": "Removed junior successfully",
"3023": "Junior is approved successfully",
"3024": "Junior request is rejected successfully",
"3025": "Task is approved successfully",
+46
View File
@@ -0,0 +1,46 @@
"""
web_admin pagination file
"""
# third party imports
from collections import OrderedDict
from rest_framework.pagination import PageNumberPagination
from account.utils import custom_response
from base.constants import NUMBER
class CustomPageNumberPagination(PageNumberPagination):
"""
custom paginator class
"""
# Set the desired page size
page_size = NUMBER['ten']
page_size_query_param = 'page_size'
# Set a maximum page size if needed
max_page_size = NUMBER['hundred']
def get_paginated_response(self, data):
"""
:param data: queryset to be paginated
:return: return a OrderedDict
"""
return custom_response(None, OrderedDict([
('count', self.page.paginator.count),
('data', data),
('current_page', self.page.number),
('total_pages', self.page.paginator.num_pages),
]))
def get_paginated_dict_response(self, data):
"""
:param data: queryset to be paginated
:return: return a simple dict obj
"""
return {
'count': self.page.paginator.count,
'data': data,
'current_page': self.page.number,
'total_pages': self.page.paginator.num_pages,
}
+13 -4
View File
@@ -218,7 +218,7 @@ class TaskSerializer(serializers.ModelSerializer):
class Meta(object):
"""Meta info"""
model = JuniorTask
fields = ['id', 'task_name','task_description','points', 'due_date', 'junior', 'default_image']
fields = ['id', 'task_name','task_description','points', 'due_date','default_image']
def validate_due_date(self, value):
"""validation on due date"""
@@ -229,11 +229,20 @@ class TaskSerializer(serializers.ModelSerializer):
return value
def create(self, validated_data):
"""create default task image data"""
validated_data['guardian'] = Guardian.objects.filter(user=self.context['user']).last()
guardian = Guardian.objects.filter(user=self.context['user']).last()
# update image of the task
images = self.context['image']
validated_data['default_image'] = images
instance = JuniorTask.objects.create(**validated_data)
junior_ids = self.context['junior_data']
junior_data = junior_ids[0].split(',')
tasks_created = []
for junior_id in junior_data:
task_data = validated_data.copy()
task_data['guardian'] = guardian
task_data['default_image'] = images
task_data['junior'] = Junior.objects.filter(id=junior_id).last()
instance = JuniorTask.objects.create(**task_data)
tasks_created.append(instance)
return instance
class GuardianDetailSerializer(serializers.ModelSerializer):
+38 -35
View File
@@ -177,42 +177,45 @@ class CreateTaskAPIView(viewsets.ModelViewSet):
"""
try:
image = request.data['default_image']
junior = request.data['junior']
junior_id = Junior.objects.filter(id=junior).last()
if junior_id:
guardian_data = Guardian.objects.filter(user=request.user).last()
index = junior_id.guardian_code.index(guardian_data.guardian_code)
status_index = junior_id.guardian_code_status[index]
if status_index == str(NUMBER['three']):
return custom_error_response(ERROR_CODE['2078'], response_status=status.HTTP_400_BAD_REQUEST)
allowed_extensions = ['.jpg', '.jpeg', '.png']
if not any(extension in str(image) for extension in allowed_extensions):
return custom_error_response(ERROR_CODE['2048'], response_status=status.HTTP_400_BAD_REQUEST)
if not junior.isnumeric():
"""junior value must be integer"""
return custom_error_response(ERROR_CODE['2047'], response_status=status.HTTP_400_BAD_REQUEST)
data = request.data
if 'https' in str(image):
image_data = image
else:
filename = f"images/{image}"
if image and image.size == NUMBER['zero']:
return custom_error_response(ERROR_CODE['2035'], response_status=status.HTTP_400_BAD_REQUEST)
image_url = upload_image_to_alibaba(image, filename)
image_data = image_url
data.pop('default_image')
# use TaskSerializer serializer
serializer = TaskSerializer(context={"user":request.user, "image":image_data}, data=data)
if serializer.is_valid():
# save serializer
task = serializer.save()
juniors = request.data['junior'].split(',')
for junior in juniors:
junior_id = Junior.objects.filter(id=junior).last()
if junior_id:
guardian_data = Guardian.objects.filter(user=request.user).last()
index = junior_id.guardian_code.index(guardian_data.guardian_code)
status_index = junior_id.guardian_code_status[index]
if status_index == str(NUMBER['three']):
return custom_error_response(ERROR_CODE['2078'], response_status=status.HTTP_400_BAD_REQUEST)
allowed_extensions = ['.jpg', '.jpeg', '.png']
if not any(extension in str(image) for extension in allowed_extensions):
return custom_error_response(ERROR_CODE['2048'], response_status=status.HTTP_400_BAD_REQUEST)
if not junior.isnumeric():
"""junior value must be integer"""
return custom_error_response(ERROR_CODE['2047'], response_status=status.HTTP_400_BAD_REQUEST)
data = request.data
if 'https' in str(image):
image_data = image
else:
filename = f"images/{image}"
if image and image.size == NUMBER['zero']:
return custom_error_response(ERROR_CODE['2035'], response_status=status.HTTP_400_BAD_REQUEST)
image_url = upload_image_to_alibaba(image, filename)
image_data = image_url
data.pop('default_image')
junior_data = data.pop('junior')
# use TaskSerializer serializer
serializer = TaskSerializer(context={"user":request.user, "image":image_data,
"junior_data":junior_data}, data=data)
if serializer.is_valid():
# save serializer
task = serializer.save()
send_notification.delay(TASK_ASSIGNED, request.auth.payload['user_id'], GUARDIAN,
junior_id.auth.id, {'task_id': task.id})
return custom_response(SUCCESS_CODE['3018'], serializer.data, 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['2047'], response_status=status.HTTP_400_BAD_REQUEST)
send_notification.delay(TASK_ASSIGNED, request.auth.payload['user_id'], GUARDIAN,
junior_id.auth.id, {'task_id': task.id})
return custom_response(SUCCESS_CODE['3018'], 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['2047'], response_status=status.HTTP_400_BAD_REQUEST)
except Exception as e:
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
+27 -25
View File
@@ -211,19 +211,24 @@ class AddJuniorAPIView(viewsets.ModelViewSet):
def associate_guardian(self, user):
junior = Junior.objects.filter(auth__email=self.request.data['email']).first()
guardian = Guardian.objects.filter(user=self.request.user).first()
if junior.guardian_code and ('-' in junior.guardian_code):
junior.guardian_code.remove('-')
if not junior:
if junior is None:
return none
if junior.guardian_code and (guardian.guardian_code in junior.guardian_code):
return False
if junior.guardian_code and ('-' in junior.guardian_code):
junior.guardian_code.remove('-')
if not junior.guardian_code:
junior.guardian_code = [guardian.guardian_code]
if type(junior.guardian_code) is list and len(junior.guardian_code) < 3:
elif type(junior.guardian_code) is list and len(junior.guardian_code) < 3:
junior.guardian_code.append(guardian.guardian_code)
else:
return "Max"
junior.guardian_code_status.append(str(NUMBER['two']))
if junior.guardian_code_status and ('-' in junior.guardian_code_status):
junior.guardian_code_status.remove('-')
if not junior.guardian_code_status:
junior.guardian_code_status = [str(NUMBER['two'])]
else:
junior.guardian_code_status.append(str(NUMBER['two']))
junior.save()
jun_data, created = JuniorGuardianRelationship.objects.get_or_create(guardian=guardian, junior=junior)
if jun_data:
@@ -341,9 +346,19 @@ class JuniorTaskListAPIView(viewsets.ModelViewSet):
"""Junior task list"""
serializer_class = TaskDetailsjuniorSerializer
permission_classes = [IsAuthenticated]
filter_backends = (SearchFilter,)
search_fields = ['task_name', ]
pagination_class = PageNumberPagination
http_method_names = ('get',)
def get_queryset(self):
queryset = JuniorTask.objects.filter(junior__auth=self.request.user
).prefetch_related('junior', 'junior__auth'
).order_by('due_date', 'created_at')
queryset = self.filter_queryset(queryset)
return queryset
def list(self, request, *args, **kwargs):
"""Junior task list
status=0
@@ -351,27 +366,14 @@ class JuniorTaskListAPIView(viewsets.ModelViewSet):
page=1"""
try:
status_value = self.request.GET.get('status')
search = self.request.GET.get('search')
if search and str(status_value) == '0':
# search with title and for all task list
queryset = JuniorTask.objects.filter(junior__auth=request.user,
task_name__icontains=search).order_by('due_date', 'created_at')
elif search and str(status_value) != '0':
# search with title and fetch task list with status wise
queryset = JuniorTask.objects.filter(junior__auth=request.user, task_name__icontains=search,
task_status=status_value).order_by('due_date', 'created_at')
if search is None and str(status_value) == '0':
# fetch all task list
queryset = JuniorTask.objects.filter(junior__auth=request.user).order_by('due_date', 'created_at')
elif search is None and str(status_value) != '0':
# fetch task list with status wise
queryset = JuniorTask.objects.filter(junior__auth=request.user,
task_status=status_value).order_by('due_date','created_at')
queryset = self.get_queryset()
if status_value and status_value != '0':
queryset = queryset.filter(task_status=status_value)
paginator = self.pagination_class()
# use Pagination
paginated_queryset = paginator.paginate_queryset(queryset, request)
# use TaskDetailsSerializer serializer
serializer = TaskDetailsjuniorSerializer(paginated_queryset, many=True)
# use TaskDetails juniorSerializer serializer
serializer = self.serializer_class(paginated_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)
@@ -593,8 +595,8 @@ class StartAssessmentAPIView(viewsets.ModelViewSet):
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')
'article_survey'
)
return article
def list(self, request, *args, **kwargs):
"""Params
+3 -2
View File
@@ -11,6 +11,7 @@ from rest_framework import viewsets, status, views
# local imports
from account.utils import custom_response, custom_error_response
from base.messages import SUCCESS_CODE, ERROR_CODE
from base.pagination import CustomPageNumberPagination
from base.tasks import notify_task_expiry, notify_top_junior
from notifications.constants import TEST_NOTIFICATION
from notifications.serializers import RegisterDevice, NotificationListSerializer, ReadNotificationSerializer
@@ -33,10 +34,10 @@ class NotificationViewSet(viewsets.GenericViewSet):
"""
queryset = Notification.objects.filter(notification_to_id=request.auth.payload['user_id']
).select_related('notification_to').order_by('-id')
paginator = self.pagination_class()
paginator = CustomPageNumberPagination()
paginated_queryset = paginator.paginate_queryset(queryset, request)
serializer = self.serializer_class(paginated_queryset, many=True)
return custom_response(None, serializer.data, count=queryset.count())
return paginator.get_paginated_response(serializer.data)
@action(methods=['post'], detail=False, url_path='device', url_name='device', serializer_class=RegisterDevice)
def fcm_registration(self, request):
-18
View File
@@ -1,18 +0,0 @@
"""
web_admin pagination file
"""
# third party imports
from rest_framework.pagination import PageNumberPagination
from base.constants import NUMBER
class CustomPageNumberPagination(PageNumberPagination):
"""
custom paginator class
"""
# Set the desired page size
page_size = NUMBER['ten']
page_size_query_param = 'page_size'
# Set a maximum page size if needed
max_page_size = NUMBER['hundred']
+3 -2
View File
@@ -81,7 +81,7 @@ class ArticleSerializer(serializers.ModelSerializer):
meta class
"""
model = Article
fields = ('id', 'title', 'description', 'article_cards', 'article_survey')
fields = ('id', 'title', 'description', 'is_published', 'article_cards', 'article_survey')
def validate(self, attrs):
"""
@@ -306,8 +306,9 @@ class StartAssessmentSerializer(serializers.ModelSerializer):
"""current page"""
context_data = self.context.get('user')
data = JuniorArticle.objects.filter(junior__auth=context_data, article=obj).last()
total_count = obj.article_survey.all().count()
if data:
return data.current_que_page
return data.current_que_page if data.current_que_page < total_count else data.current_que_page - 1
return NUMBER['zero']
class Meta(object):
"""
+2 -2
View File
@@ -23,11 +23,11 @@ from django.http import HttpResponse
# local imports
from account.utils import custom_response, get_user_full_name
from base.constants import PENDING, IN_PROGRESS, REJECTED, REQUESTED, COMPLETED, EXPIRED, DATE_FORMAT, TASK_STATUS
from base.constants import PENDING, IN_PROGRESS, REJECTED, REQUESTED, COMPLETED, EXPIRED, TASK_STATUS
from guardian.models import JuniorTask
from guardian.utils import upload_excel_file_to_alibaba
from junior.models import JuniorPoints
from web_admin.pagination import CustomPageNumberPagination
from base.pagination import CustomPageNumberPagination
from web_admin.permission import AdminPermission
from web_admin.serializers.analytics_serializer import LeaderboardSerializer, UserCSVReportSerializer
from web_admin.utils import get_dates
+16
View File
@@ -130,6 +130,22 @@ class ArticleViewSet(GenericViewSet, mixins.CreateModelMixin, mixins.UpdateModel
return custom_response(SUCCESS_CODE["3029"])
return custom_error_response(ERROR_CODE["2041"], status.HTTP_400_BAD_REQUEST)
@action(methods=['get'], url_name='status-change', url_path='status-change',
detail=True)
def article_status_change(self, request, *args, **kwargs):
"""
article un-publish or publish api method
:param request: article id
:return: success message
"""
try:
article = Article.objects.filter(id=kwargs['pk']).first()
article.is_published = False if article.is_published else True
article.save(update_fields=['is_published'])
return custom_response(SUCCESS_CODE["3038"])
except AttributeError:
return custom_error_response(ERROR_CODE["2041"], response_status=status.HTTP_400_BAD_REQUEST)
@action(methods=['get'], url_name='remove-card', url_path='remove-card',
detail=True)
def remove_article_card(self, request, *args, **kwargs):
+12 -2
View File
@@ -37,7 +37,17 @@ SECRET_KEY = os.getenv('SECRET_KEY')
DEBUG = os.getenv('DEBUG')
# cors allow setting
CORS_ORIGIN_ALLOW_ALL = True
CORS_ORIGIN_ALLOW_ALL = False
# Allow specific origins
CORS_ALLOWED_ORIGINS = [
"https://dev-api.zodqaapp.com",
"https://qa-api.zodqaapp.com",
"https://stage-api.zodqaapp.com",
# Add more trusted origins as needed
]
# if DEBUG:
# CORS_ALLOWED_ORIGINS += ["http://localhost:3000"]
# allow all host
ALLOWED_HOSTS = ['*']
@@ -53,7 +63,7 @@ INSTALLED_APPS = [
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# Add Django rest frame work apps here
# Add Django rest framework apps here
'django_extensions',
'storages',
'drf_yasg',
+4 -2
View File
@@ -20,12 +20,11 @@ from django.urls import path, include
from drf_yasg import openapi
from drf_yasg.views import get_schema_view
from django.urls import path
from django.conf import settings
schema_view = get_schema_view(openapi.Info(title="Zod Bank API", default_version='v1'), public=True, )
urlpatterns = [
path('apidoc/', schema_view.with_ui('swagger', cache_timeout=None), name='schema-swagger-ui'),
path('admin/', admin.site.urls),
path('', include(('account.urls', 'account'), namespace='account')),
path('', include('guardian.urls')),
@@ -33,3 +32,6 @@ urlpatterns = [
path('', include(('notifications.urls', 'notifications'), namespace='notifications')),
path('', include(('web_admin.urls', 'web_admin'), namespace='web_admin')),
]
if settings.DEBUG:
urlpatterns += [(path('apidoc/', schema_view.with_ui('swagger', cache_timeout=None), name='schema-swagger-ui'))]