From 37ed1e4da65e5809862bc1e6b8b7a4beee3b3232 Mon Sep 17 00:00:00 2001 From: tionfo Date: Thu, 19 Mar 2020 16:44:40 +0530 Subject: [PATCH 01/35] Added Django Rest Framework --- dg/base_settings.py | 10 +++++++++- dg/urls.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/dg/base_settings.py b/dg/base_settings.py index 9833fc29df..cd2ab7bbb4 100644 --- a/dg/base_settings.py +++ b/dg/base_settings.py @@ -185,7 +185,8 @@ 'mrppayment', 'smart_selects', 'loop_ivr', - 'dataexport' + 'dataexport', + 'rest_framework', # 3rd Party ) @@ -270,3 +271,10 @@ VIDEOS_PAGE = ('%s%s')%(WEBSITE_DOMAIN, 'videos/') LOOP_APP_PAGE = ('%s')%('https://play.google.com/store/apps/details?id=loop.org.digitalgreen.loop') TRAINING_APP_PAGE = ('%s')%('https://play.google.com/store/apps/details?id=org.digitalgreen.trainingapp') +REST_FRAMEWORK = { + # Use Django's standard `django.contrib.auth` permissions, + # or allow read-only access for unauthenticated users. + 'DEFAULT_PERMISSION_CLASSES': [ + 'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly' + ] +} \ No newline at end of file diff --git a/dg/urls.py b/dg/urls.py index 30a9053e3d..e88bacf651 100644 --- a/dg/urls.py +++ b/dg/urls.py @@ -65,8 +65,37 @@ # loop_ivr_admin.login_template = 'social_website/login.html' # loop_ivr_admin.logout_template = 'social_website/home.html' +from django.conf.urls import url, include +from django.contrib.auth.models import User +from rest_framework import routers, serializers, viewsets +from people.models import Person +# Serializers define the API representation. +class UserSerializer(serializers.HyperlinkedModelSerializer): + class Meta: + model = User + fields = ['url', 'username', 'email', 'is_staff'] +class FarmerSerializer(serializers.HyperlinkedModelSerializer): + class Meta: + model = Person + fields = ['person_name', 'phone_no', 'gender'] + +class FarmerViewSet(viewsets.ModelViewSet): + queryset = Person.objects.all()[:10] + serializer_class = FarmerSerializer + +# ViewSets define the view behavior. +class UserViewSet(viewsets.ModelViewSet): + queryset = User.objects.all() + serializer_class = UserSerializer + +# Routers provide an easy way of automatically determining the URL conf. +router = routers.DefaultRouter() +router.register(r'users', UserViewSet) +router.register(r'farmer', FarmerViewSet) + urlpatterns = patterns('', (r'^', include(social_website.urls)), + url(r'^api/', include(router.urls)), #(r'^', include(website_archive_urls)), url(r'', include('social.apps.django_app.urls', namespace='social')), url(r'^login/$', 'social_website.views.login_view', {'template_name': 'social_website/login.html'}, name='signin'), @@ -140,6 +169,8 @@ #(r'^agri/', include(videokheti.urls)), #AJAX for Feedback #url(r'^feedbacksubmit_json$', 'dg.feedback_view.ajax'), + url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')) + ) # Static files serving locally From 3a33446a975c4f50d84e5e4f7f2735b4916e5579 Mon Sep 17 00:00:00 2001 From: tionfo Date: Thu, 19 Mar 2020 16:48:06 +0530 Subject: [PATCH 02/35] Added DRF in requirement.txt and mysql related lib --- requirements/requirements.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/requirements/requirements.txt b/requirements/requirements.txt index ba7ac40c33..d54afcda3a 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -34,7 +34,8 @@ ipython-genutils==0.2.0 isodate==0.5.4 jdcal==1.3 Mezzanine==4.1.0 -MySQL-python==1.2.3 +MySQL-python==1.2.3 #comment this for mac +#mysqlclient #uncomment for Mac newrelic==2.82.0.62 numpy==1.12.0 oauth2==1.5.211 @@ -83,3 +84,4 @@ xlrd==0.9.2 XlsxWriter==0.5.1 xlwt==0.7.5 yolk==0.4.1 +djangorestframework==3.6.4 \ No newline at end of file From e82194cfb26a2cedbcfc5be14edfc795c1ae7665 Mon Sep 17 00:00:00 2001 From: vermastuti Date: Thu, 9 Apr 2020 16:01:19 +0530 Subject: [PATCH 03/35] geo-&-people-serializers --- dg/urls.py | 23 +++++++++------- geographies/apps.py | 7 +++++ geographies/serializers.py | 49 +++++++++++++++++++++++++++++++++ people/serializers.py | 21 +++++++++++++++ people/urls.py | 16 +++++++++++ people/views.py | 55 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 162 insertions(+), 9 deletions(-) create mode 100644 geographies/apps.py create mode 100644 geographies/serializers.py create mode 100644 people/serializers.py create mode 100644 people/urls.py create mode 100644 people/views.py diff --git a/dg/urls.py b/dg/urls.py index e88bacf651..5bcdcd4666 100644 --- a/dg/urls.py +++ b/dg/urls.py @@ -69,19 +69,16 @@ from django.contrib.auth.models import User from rest_framework import routers, serializers, viewsets from people.models import Person +from geographies.models import Country,Village +import people.urls + +from people.views import VillagesViewSet, FarmerViewSet, FarmerDetailView, BlockViewSet + # Serializers define the API representation. class UserSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = User fields = ['url', 'username', 'email', 'is_staff'] -class FarmerSerializer(serializers.HyperlinkedModelSerializer): - class Meta: - model = Person - fields = ['person_name', 'phone_no', 'gender'] - -class FarmerViewSet(viewsets.ModelViewSet): - queryset = Person.objects.all()[:10] - serializer_class = FarmerSerializer # ViewSets define the view behavior. class UserViewSet(viewsets.ModelViewSet): @@ -92,6 +89,9 @@ class UserViewSet(viewsets.ModelViewSet): router = routers.DefaultRouter() router.register(r'users', UserViewSet) router.register(r'farmer', FarmerViewSet) +router.register(r'villages', VillagesViewSet) +router.register(r'block', BlockViewSet) +# router.register(r'farmers//', FarmerDetailView.as_view(), base_name="farmer-detail") urlpatterns = patterns('', (r'^', include(social_website.urls)), @@ -110,6 +110,7 @@ class UserViewSet(viewsets.ModelViewSet): (r'^qacoco/', include(qacoco.urls)), (r'^dimagi/', include(dimagi.urls)), (r'^videos/', include(videos.urls)), + # ivrsadmin/logout/ should be above admin/ URL url(r'^ivrsadmin/logout/?$', 'django.contrib.auth.views.logout', {'next_page': '/ivrsadmin'}), (r'^ivrsadmin/', include(ivr_admin.urls)), @@ -169,7 +170,11 @@ class UserViewSet(viewsets.ModelViewSet): #(r'^agri/', include(videokheti.urls)), #AJAX for Feedback #url(r'^feedbacksubmit_json$', 'dg.feedback_view.ajax'), - url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')) + url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')), + + #changes for geographies + # (r'^people/$', include(people.urls)) + #changed till here ) diff --git a/geographies/apps.py b/geographies/apps.py new file mode 100644 index 0000000000..d16f1df571 --- /dev/null +++ b/geographies/apps.py @@ -0,0 +1,7 @@ +from __future__ import unicode_literals + +from django.apps import AppConfig + + +class GeoConfig(AppConfig): + name = 'geo' \ No newline at end of file diff --git a/geographies/serializers.py b/geographies/serializers.py new file mode 100644 index 0000000000..4c435970cf --- /dev/null +++ b/geographies/serializers.py @@ -0,0 +1,49 @@ +from .models import * +from rest_framework import serializers + +class CountrySerializer(serializers.ModelSerializer): + class Meta: + model = Country + fields = ['id', 'old_coco_id','country_name','start_date', 'active'] + +class StateSerializer(serializers.ModelSerializer): + country_id = serializers.IntegerField(source='country.id', read_only=True) + country_name = serializers.CharField(source='country.country_name', read_only=True) + class Meta: + model = State + fields = ['id','old_coco_id','state_name','country_id','country_name','start_date', 'active'] + +class DistrictSerializer(serializers.ModelSerializer): + country_id = serializers.IntegerField(source='state.country.id', read_only=True) + country_name = serializers.CharField(source='state.country.country_name', read_only=True) + state_id = serializers.IntegerField(source='state.id', read_only=True) + state_name = serializers.CharField(source='state.state_name', read_only=True) + class Meta: + model = District + fields = ['id','old_coco_id','district_name','start_date','state_id','state_name','country_id','country_name','latitude', 'longitude', 'active'] + + +class BlockSerializer(serializers.ModelSerializer): + # country_id = serializers.IntegerField(source='district.state.country.id', read_only=True) + # country_name = serializers.CharField(source='district.state.country.country_name', read_only=True) + # state_id = serializers.IntegerField(source='district.state.id', read_only=True) + # state_name = serializers.CharField(source='district.state.state_name', read_only=True) + # district_id = serializers.IntegerField(source='district.id', read_only=True) + # district_name = serializers.CharField(source='district.district_name', read_only=True) + class Meta: + model = Block #'district_id','district_name', 'state_id','state_name','country_id','country_name', + fields = ['id','old_coco_id','block_name', 'start_date','latitude', 'longitude'] + + +class VillageSerializer(serializers.ModelSerializer): + country_id = serializers.IntegerField(source='block.district.state.country.id', read_only=True) + country_name = serializers.CharField(source='block.district.state.country.country_name', read_only=True) + state_id = serializers.IntegerField(source='block.district.state.id', read_only=True) + state_name = serializers.CharField(source='block.district.state.state_name', read_only=True) + district_id = serializers.IntegerField(source='block.district.id', read_only=True) + district_name = serializers.CharField(source='block.district.district_name', read_only=True) + block_id = serializers.IntegerField(source='block.id', read_only=True) + block_name = serializers.CharField(source='block.block_name', read_only=True) + class Meta: + model = Village + fields = ['id','old_coco_id','village_name','block_id','block_name','district_id','district_name','start_date','state_id','state_name','country_id','country_name','latitude', 'longitude', 'grade','active'] diff --git a/people/serializers.py b/people/serializers.py new file mode 100644 index 0000000000..26b2f6a337 --- /dev/null +++ b/people/serializers.py @@ -0,0 +1,21 @@ +from people.models import Person +from rest_framework import serializers +from geographies.models import Village + + +class VillageSerializer(serializers.ModelSerializer): + + class Meta: + model = Village + fields = ['id', 'village_name'] + + +class FarmerSerializer(serializers.ModelSerializer): + + village_id = serializers.CharField(source='village.id', read_only=True) + village_name = serializers.CharField(source='village.village_name', read_only=True) + + class Meta: + model = Person + fields = ['person_name', 'phone_no', 'gender', 'village_id','village_name'] + diff --git a/people/urls.py b/people/urls.py new file mode 100644 index 0000000000..0953be9b13 --- /dev/null +++ b/people/urls.py @@ -0,0 +1,16 @@ +from rest_framework import routers, serializers, viewsets +from django.conf.urls import patterns, include, url +from . import views + +# router = routers.DefaultRouter() +# router.register(r'farmer', FarmerViewSet) +# router.register(r'villages', VillagesViewSet) + + +urlpatterns = patterns('', + # url(r'^$', views.index, name='index'), + # url(r'^new/$', include(router.urls)), + # (r'^villages/$', VillagesViewSet), + # (r'^farmer/$', FarmerViewSet), + +) \ No newline at end of file diff --git a/people/views.py b/people/views.py new file mode 100644 index 0000000000..bb7b93707e --- /dev/null +++ b/people/views.py @@ -0,0 +1,55 @@ +from rest_framework import routers, serializers, generics +from rest_framework.response import Response +from rest_framework import status, viewsets +# from rest_framework.decorators import action + +from people.models import Person +from geographies.models import Country, State, District, Block, Village +from people.serializers import FarmerSerializer #, VillageSerializer + +from geographies.serializers import DistrictSerializer, BlockSerializer, VillageSerializer + +from django.http import HttpResponse + + +class FarmerViewSet(viewsets.ModelViewSet): + + queryset = Person.objects.all()[:1000] + serializer_class = FarmerSerializer + + # @action(methods=['post'], detail=True) + # def set_password(self, request, pk=None): + # return Response("HI, It worked!") + +class VillagesViewSet(viewsets.ModelViewSet): + + queryset = Village.objects.all()[:10] + serializer_class = VillageSerializer + +class BlockViewSet(viewsets.ModelViewSet): + + queryset = Block.objects.all()[:10] + serializer_class = BlockSerializer + + + + +class FarmerDetailView(generics.RetrieveUpdateDestroyAPIView): + """ + GET farmer/:id/ + """ + queryset = Person.objects.all() + serializer_class = FarmerSerializer + + def get(self, request, *args, **kwargs): + try: + a_farmer = self.queryset.get(pk=kwargs["pk"]) + # farmers_all = self.queryset.filter(id__gte=10, id__lte=20) + return Response(FarmerSerializer(a_farmer, many=True).data) + except Person.DoesNotExist: + return Response( + data={ + "message": "Farmer with id: {} does not exist".format(kwargs["pk"]) + }, + status=status.HTTP_404_NOT_FOUND + ) \ No newline at end of file From 2c53b4dfb8cd367aeb4454a6d1a0b7d8c9535bf6 Mon Sep 17 00:00:00 2001 From: vermastuti Date: Fri, 8 May 2020 22:11:11 +0530 Subject: [PATCH 04/35] coco-api-version1.0.0 --- activities/serializers.py | 27 ++++ activities/urls.py | 7 + activities/views.py | 105 +++++++++++++ dg/urls.py | 41 ++--- geographies/serializers.py | 62 +++++--- geographies/urls.py | 13 ++ geographies/views.py | 286 ++++++++++++++++++++++++++++++++++ people/serializers.py | 48 ++++-- people/urls.py | 22 +-- people/views.py | 186 +++++++++++++++++----- requirements/requirements.txt | 5 +- videos/serializers.py | 28 ++++ videos/urls.py | 9 ++ videos/views.py | 70 +++++++++ 14 files changed, 793 insertions(+), 116 deletions(-) create mode 100644 activities/serializers.py create mode 100644 activities/urls.py create mode 100644 activities/views.py create mode 100644 geographies/urls.py create mode 100644 geographies/views.py create mode 100644 videos/serializers.py create mode 100644 videos/views.py diff --git a/activities/serializers.py b/activities/serializers.py new file mode 100644 index 0000000000..29a7a9044c --- /dev/null +++ b/activities/serializers.py @@ -0,0 +1,27 @@ +from .models import Screening +from rest_framework import serializers + +class DynamicFieldsModelSerializer(serializers.ModelSerializer): + """ + A ModelSerializer that takes an additional `fields` argument that + controls which fields should be displayed. + """ + + def __init__(self, *args, **kwargs): + # Don't pass the 'fields' arg up to the superclass + fields = kwargs.pop('fields', None) + + # Instantiate the superclass normally + super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs) + + if fields is not None: + # Drop any fields that are not specified in the `fields` argument. + allowed = set(fields) + existing = set(self.fields) + for field_name in existing - allowed: + self.fields.pop(field_name) + +class ScreeningSerializer(DynamicFieldsModelSerializer): + class Meta: + model = Screening + fields = '__all__' \ No newline at end of file diff --git a/activities/urls.py b/activities/urls.py new file mode 100644 index 0000000000..eb81cf23cf --- /dev/null +++ b/activities/urls.py @@ -0,0 +1,7 @@ +from django.conf.urls import url, include + +from activities import views + +urlpatterns=[ + url('upavan', views.UpavanViewSet.as_view()), +] \ No newline at end of file diff --git a/activities/views.py b/activities/views.py new file mode 100644 index 0000000000..e3eef4637c --- /dev/null +++ b/activities/views.py @@ -0,0 +1,105 @@ +# default imports +from django.shortcuts import render + +# model imports +from videos.models import * +from activities.models import * + +# serializers imports +from activities.serializers import * + +# drf imports +from rest_framework import viewsets, generics +from rest_framework import permissions +from rest_framework.response import Response +from rest_framework import status + +#authentication +from rest_framework.authentication import SessionAuthentication, BasicAuthentication, TokenAuthentication +from rest_framework.permissions import IsAuthenticated + + +class UpavanViewSet(generics.ListCreateAPIView): + ''' + coco_api class-based view to query Screening model and provide JSON response. + django-rest-framework based token passed in Header as {'Authorization': 'Token 12345exampleToken'} + is required to access data from this View. + Only POST method is allowed. + GET request sent will show a message : "Method \"GET\" not allowed." + ''' + + # django-rest-framework TokenAuthentication + authentication_classes = [TokenAuthentication] + permissions_classes =[IsAuthenticated] + + serializer_class = ScreeningSerializer + + # GET request + def get(self, request): + return Response({"detail":"Method \"GET\" not allowed"}) + + # POST request + def post(self, request, *args, **kwargs): + queryset = Screening.objects.get_queryset().order_by('id') + + + uc_id = request.POST.get('user_created') # POST param 'user_created', default value is empty string + if uc_id: + queryset = queryset.filter(user_created__exact=uc_id) # filters for numeric values with exact match + + start_day = request.POST.get('start_day') + start_month = request.POST.get('start_month') + start_year = request.POST.get('start_year') + end_day = request.POST.get('end_day') + end_month = request.POST.get('end_month') + end_year = request.POST.get('end_year') + + # case1: all values are present + if start_day and start_month and start_year and end_day and end_month and end_year: + # params type value is string, trimmed spaces,convert to int and then make date by combining values + try: + start_date = datetime.date(int(start_year.strip()),int(start_month.strip()), int(start_day.strip())) + end_date = datetime.date(int(end_year.strip()),int(end_month.strip()), int(end_day.strip())) + queryset = queryset.filter(date__range=(start_date, end_date)) # filters values in date range + except: + print("Date error occurred") + # case2: only start values are present + elif start_day and start_month and start_year and not end_day and not end_month and not end_year: + try: + start_date = datetime.date(int(start_year.strip()),int(start_month.strip()), int(start_day.strip())) + queryset = queryset.filter(date__gte=start_date) # filters values greater than or equal to start date + except: + print("Start Date error occurred") + # case3: only end values are present + elif not start_day and not start_month and not start_year and end_day and end_month and end_year: + try: + end_date = datetime.date(int(end_year.strip()),int(end_month.strip()), int(end_day.strip())) + queryset = queryset.filter(date__lte=end_date) # filters values less than or equal to end date + except: + print("End Date error occurred") + + start_limit = request.POST.get('start_limit') # POST param 'start_limit' + end_limit = request.POST.get('end_limit') # POST param 'end_limit' + + # limits the total response count + if start_limit and end_limit: # case1: both are present + queryset = queryset[int(start_limit)-1:int(end_limit)] + elif start_limit: # case2: only start_limit is present + queryset = queryset[int(start_limit)-1:] + elif end_limit: # case3: only end_limit is present + queryset = queryset[:int(end_limit)] + + count = self.request.POST.get("count", "False") + if count in ["True","true","t","T","Yes","yes","Y","y"]: + return Response({"count": queryset.count()}) + + fields_values = request.POST.get('fields', '') # POST param 'fields', default value is empty string + if fields_values: # fields provided in POST request and if not empty serves those fields only + fields_values = [val.strip() for val in fields_values.split(",")] + # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer + serializer = ScreeningSerializer(queryset, fields=fields_values, many=True) + else: + # if fields param is empty then all the fields as mentioned in serializer are served to the response + serializer = ScreeningSerializer(queryset, many=True) + # JSON Response is provided by default + return Response(serializer.data) \ No newline at end of file diff --git a/dg/urls.py b/dg/urls.py index 5bcdcd4666..83db49e15c 100644 --- a/dg/urls.py +++ b/dg/urls.py @@ -68,34 +68,12 @@ from django.conf.urls import url, include from django.contrib.auth.models import User from rest_framework import routers, serializers, viewsets -from people.models import Person -from geographies.models import Country,Village -import people.urls - -from people.views import VillagesViewSet, FarmerViewSet, FarmerDetailView, BlockViewSet - -# Serializers define the API representation. -class UserSerializer(serializers.HyperlinkedModelSerializer): - class Meta: - model = User - fields = ['url', 'username', 'email', 'is_staff'] - -# ViewSets define the view behavior. -class UserViewSet(viewsets.ModelViewSet): - queryset = User.objects.all() - serializer_class = UserSerializer - -# Routers provide an easy way of automatically determining the URL conf. -router = routers.DefaultRouter() -router.register(r'users', UserViewSet) -router.register(r'farmer', FarmerViewSet) -router.register(r'villages', VillagesViewSet) -router.register(r'block', BlockViewSet) -# router.register(r'farmers//', FarmerDetailView.as_view(), base_name="farmer-detail") + +#drf token authentication +from rest_framework.authtoken import views urlpatterns = patterns('', (r'^', include(social_website.urls)), - url(r'^api/', include(router.urls)), #(r'^', include(website_archive_urls)), url(r'', include('social.apps.django_app.urls', namespace='social')), url(r'^login/$', 'social_website.views.login_view', {'template_name': 'social_website/login.html'}, name='signin'), @@ -170,14 +148,13 @@ class UserViewSet(viewsets.ModelViewSet): #(r'^agri/', include(videokheti.urls)), #AJAX for Feedback #url(r'^feedbacksubmit_json$', 'dg.feedback_view.ajax'), - url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')), - #changes for geographies - # (r'^people/$', include(people.urls)) - #changed till here + #coco_api changes starts here + url(r'api-token-auth', views.obtain_auth_token), # POST;params: {'username':'','password':''}; generates token + url(r'api/farmer/', include('people.urls')), # includes people.urls.py + url(r'api/geo/', include('geographies.urls')), # includes geographies.urls.py + url(r'api/activities/', include('activities.urls')), # includes activities.urls.py + #coco_api changes ends here ) -# Static files serving locally -if settings.DEBUG: - urlpatterns += staticfiles_urlpatterns() diff --git a/geographies/serializers.py b/geographies/serializers.py index 4c435970cf..ed5fde76b8 100644 --- a/geographies/serializers.py +++ b/geographies/serializers.py @@ -1,41 +1,62 @@ from .models import * from rest_framework import serializers -class CountrySerializer(serializers.ModelSerializer): +class DynamicFieldsModelSerializer(serializers.ModelSerializer): + """ + A ModelSerializer that takes an additional `fields` argument that + controls which fields should be displayed. + """ + + def __init__(self, *args, **kwargs): + # Don't pass the 'fields' arg up to the superclass + fields = kwargs.pop('fields', None) + + # Instantiate the superclass normally + super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs) + + if fields is not None: + # Drop any fields that are not specified in the `fields` argument. + allowed = set(fields) + existing = set(self.fields) + for field_name in existing - allowed: + self.fields.pop(field_name) + +class CountrySerializer(DynamicFieldsModelSerializer): class Meta: model = Country - fields = ['id', 'old_coco_id','country_name','start_date', 'active'] + fields = '__all__' -class StateSerializer(serializers.ModelSerializer): +class StateSerializer(DynamicFieldsModelSerializer): country_id = serializers.IntegerField(source='country.id', read_only=True) country_name = serializers.CharField(source='country.country_name', read_only=True) + class Meta: model = State - fields = ['id','old_coco_id','state_name','country_id','country_name','start_date', 'active'] + fields = '__all__' -class DistrictSerializer(serializers.ModelSerializer): +class DistrictSerializer(DynamicFieldsModelSerializer): country_id = serializers.IntegerField(source='state.country.id', read_only=True) country_name = serializers.CharField(source='state.country.country_name', read_only=True) state_id = serializers.IntegerField(source='state.id', read_only=True) state_name = serializers.CharField(source='state.state_name', read_only=True) + class Meta: model = District - fields = ['id','old_coco_id','district_name','start_date','state_id','state_name','country_id','country_name','latitude', 'longitude', 'active'] - + fields = '__all__' -class BlockSerializer(serializers.ModelSerializer): - # country_id = serializers.IntegerField(source='district.state.country.id', read_only=True) - # country_name = serializers.CharField(source='district.state.country.country_name', read_only=True) - # state_id = serializers.IntegerField(source='district.state.id', read_only=True) - # state_name = serializers.CharField(source='district.state.state_name', read_only=True) - # district_id = serializers.IntegerField(source='district.id', read_only=True) - # district_name = serializers.CharField(source='district.district_name', read_only=True) +class BlockSerializer(DynamicFieldsModelSerializer): + country_id = serializers.IntegerField(source='district.state.country.id', read_only=True) + country_name = serializers.CharField(source='district.state.country.country_name', read_only=True) + state_id = serializers.IntegerField(source='district.state.id', read_only=True) + state_name = serializers.CharField(source='district.state.state_name', read_only=True) + district_id = serializers.IntegerField(source='district.id', read_only=True) + district_name = serializers.CharField(source='district.district_name', read_only=True) + class Meta: - model = Block #'district_id','district_name', 'state_id','state_name','country_id','country_name', - fields = ['id','old_coco_id','block_name', 'start_date','latitude', 'longitude'] + model = Block + fields = '__all__' - -class VillageSerializer(serializers.ModelSerializer): +class VillageSerializer(DynamicFieldsModelSerializer): country_id = serializers.IntegerField(source='block.district.state.country.id', read_only=True) country_name = serializers.CharField(source='block.district.state.country.country_name', read_only=True) state_id = serializers.IntegerField(source='block.district.state.id', read_only=True) @@ -44,6 +65,7 @@ class VillageSerializer(serializers.ModelSerializer): district_name = serializers.CharField(source='block.district.district_name', read_only=True) block_id = serializers.IntegerField(source='block.id', read_only=True) block_name = serializers.CharField(source='block.block_name', read_only=True) + class Meta: - model = Village - fields = ['id','old_coco_id','village_name','block_id','block_name','district_id','district_name','start_date','state_id','state_name','country_id','country_name','latitude', 'longitude', 'grade','active'] + model = Village + fields = '__all__' \ No newline at end of file diff --git a/geographies/urls.py b/geographies/urls.py new file mode 100644 index 0000000000..a3f68f2bdc --- /dev/null +++ b/geographies/urls.py @@ -0,0 +1,13 @@ +from django.conf.urls import url, include + +from geographies import views + +urlpatterns=[ + url('^$', views.DefaultView.as_view({'get': 'message'})), + url('village', views.VillageAPIView.as_view()), + url('block', views.BlockAPIView.as_view()), + url('district', views.DistrictAPIView.as_view()), + url('state', views.StateAPIView.as_view()), + url('country', views.CountryAPIView.as_view()), + # url('csv', views.CSVView.as_view()), +] diff --git a/geographies/views.py b/geographies/views.py new file mode 100644 index 0000000000..28768ca687 --- /dev/null +++ b/geographies/views.py @@ -0,0 +1,286 @@ +#default imports +from django.shortcuts import render + +# added imports +from rest_framework import viewsets, generics +from rest_framework import permissions +from rest_framework.response import Response +from rest_framework import status + +# serializers import +from geographies.serializers import * + +# model imports +from geographies.models import * + +# django-rest-framework TokenAuthentication imports +from rest_framework.authentication import SessionAuthentication, BasicAuthentication, TokenAuthentication +from rest_framework.permissions import IsAuthenticated + +class DefaultView(viewsets.ViewSet): + ''' + coco_api class-based view to provide default message in JSON format. + django-rest-framework based token passed in Header as {'Authorization': 'Token 12345exampleToken'} + is required to access data from this View. + Only POST method is allowed. + GET request sent will show a message : "Method \"GET\" not allowed." + ''' + + # django-rest-framework TokenAuthentication + authentication_classes = [TokenAuthentication] + permissions_classes =[IsAuthenticated] + + # POST request + def post(self, request): + # dictionary results as JSON format message + return Response({"message":"Welcome to COCO APIs", "base_url":"api/geo", + "url_list":["api/geo/village", + "api/geo/block", + "api/geo/district", + "api/geo/state", + "api/geo/country"]}) + # GET request + def get(self, request, *args, **kwargs): + return Response({"detail":"Method \"GET\" not allowed"}) + + +class VillageAPIView(generics.ListAPIView): + ''' + coco_api class-based view to query Village model and provide JSON response. + django-rest-framework based token passed in Header as {'Authorization': 'Token 12345exampleToken'} + is required to access data from this View. + Only POST method is allowed. + GET request sent will show a message : "Method \"GET\" not allowed." + ''' + + # django-rest-framework TokenAuthentication + authentication_classes = [TokenAuthentication] + permissions_classes =[IsAuthenticated] + + # GET request + def get(self, request): + return Response({"detail":"Method \"GET\" not allowed"}) + + # POST request + def post(self, request, *args, **kwargs): + + queryset = Village.objects.get_queryset().order_by('id') # basic query to be filtered later in this method + + fields_values = request.POST.get('fields', '') # POST param 'fields', default value is empty string + start_limit = request.POST.get('start_limit') # POST param 'start_limit' + end_limit = request.POST.get('end_limit') # POST param 'end_limit' + + # limits the total response count + if start_limit and end_limit: # case1: both are present + queryset = queryset[int(start_limit)-1:int(end_limit)] + elif start_limit: # case2: only start_limit is present + queryset = queryset[int(start_limit)-1:] + elif end_limit: # case3: only end_limit is present + queryset = queryset[:int(end_limit)] + + count = self.request.POST.get("count", "False") + if count in ["True","true","t","T","Yes","yes","Y","y"]: + return Response({"count": queryset.count()}) + + if fields_values: # fields provided in POST request and if not empty serves those fields only + fields_values = [val.strip() for val in fields_values.split(",")] + # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer + serializer = VillageSerializer(queryset, fields=fields_values ,many=True) + else: + # if fields param is empty then all the fields as mentioned in serializer are served to the response + serializer = VillageSerializer(queryset, many=True) + # JSON Response is provided by default + return Response(serializer.data) + + +class BlockAPIView(generics.ListAPIView): + ''' + coco_api class-based view to query Block model and provide JSON response. + django-rest-framework based token passed in Header as {'Authorization': 'Token 12345exampleToken'} + is required to access data from this View. + Only POST method is allowed. + GET request sent will show a message : "Method \"GET\" not allowed." + ''' + + # django-rest-framework TokenAuthentication + authentication_classes = [TokenAuthentication] + permissions_classes =[IsAuthenticated] + + # GET request + def get(self, request): + return Response({"detail":"Method \"GET\" not allowed"}) + + # POST request + def post(self, request, *args, **kwargs): + + queryset = Block.objects.get_queryset().order_by('id') # basic query to be filtered later in this method + + fields_values = request.POST.get('fields', '') # POST param 'limit', no default value specified so empty string is default value + start_limit = request.POST.get('start_limit') # POST param 'start_limit' + end_limit = request.POST.get('end_limit') # POST param 'end_limit' + + # limits the total response count + if start_limit and end_limit: # case1: both are present + queryset = queryset[int(start_limit)-1:int(end_limit)] + elif start_limit: # case2: only start_limit is present + queryset = queryset[int(start_limit)-1:] + elif end_limit: # case3: only end_limit is present + queryset = queryset[:int(end_limit)] + + count = self.request.POST.get("count", "False") + if count in ["True","true","t","T","Yes","yes","Y","y"]: + return Response({"count": queryset.count()}) + + if fields_values: # fields provided in POST request and if not empty serves those fields only + fields_values = [val.strip() for val in fields_values.split(",")] + # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer + serializer = BlockSerializer(queryset, fields=fields_values ,many=True) + else: + # if fields param is empty then all the fields as mentioned in serializer are served to the response + serializer = BlockSerializer(queryset, many=True) + # JSON Response is provided by default + return Response(serializer.data) + +class DistrictAPIView(generics.ListAPIView): + ''' + coco_api class-based view to query District model and provide JSON response. + django-rest-framework based token passed in Header as {'Authorization': 'Token 12345exampleToken'} + is required to access data from this View. + Only POST method is allowed. + GET request sent will show a message : "Method \"GET\" not allowed." + ''' + + # django-rest-framework TokenAuthentication + authentication_classes = [TokenAuthentication] + permissions_classes =[IsAuthenticated] + + # GET request + def get(self, request): + return Response({"detail":"Method \"GET\" not allowed"}) + + # POST request + def post(self, request, *args, **kwargs): + + queryset = District.objects.get_queryset().order_by('id') # basic query to be filtered later in this method + + fields_values = request.POST.get('fields', '') # POST param 'limit', no default value specified so empty string is default value + start_limit = request.POST.get('start_limit') # POST param 'start_limit' + end_limit = request.POST.get('end_limit') # POST param 'end_limit' + + # limits the total response count + if start_limit and end_limit: # case1: both are present + queryset = queryset[int(start_limit)-1:int(end_limit)] + elif start_limit: # case2: only start_limit is present + queryset = queryset[int(start_limit)-1:] + elif end_limit: # case3: only end_limit is present + queryset = queryset[:int(end_limit)] + + count = self.request.POST.get("count", "False") + if count in ["True","true","t","T","Yes","yes","Y","y"]: + return Response({"count": queryset.count()}) + + if fields_values: # fields provided in POST request and if not empty serves those fields only + fields_values = [val.strip() for val in fields_values.split(",")] + # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer + serializer = DistrictSerializer(queryset, fields=fields_values ,many=True) + else: + # if fields param is empty then all the fields as mentioned in serializer are served to the response + serializer = DistrictSerializer(queryset, many=True) + # JSON Response is provided by default + return Response(serializer.data) + +class StateAPIView(generics.ListAPIView): + ''' + coco_api class-based view to query State model and provide JSON response. + django-rest-framework based token passed in Header as {'Authorization': 'Token 12345exampleToken'} + is required to access data from this View. + Only POST method is allowed. + GET request sent will show a message : "Method \"GET\" not allowed." + ''' + + # django-rest-framework TokenAuthentication + authentication_classes = [TokenAuthentication] + permissions_classes =[IsAuthenticated] + + # GET request + def get(self, request): + return Response({"detail":"Method \"GET\" not allowed"}) + + # POST request + def post(self, request, *args, **kwargs): + + queryset = State.objects.get_queryset().order_by('id') # basic query to be filtered later in this method + + fields_values = request.POST.get('fields', '') # POST param 'limit', no default value specified so empty string is default value + start_limit = request.POST.get('start_limit') # POST param 'start_limit' + end_limit = request.POST.get('end_limit') # POST param 'end_limit' + + # limits the total response count + if start_limit and end_limit: # case1: both are present + queryset = queryset[int(start_limit)-1:int(end_limit)] + elif start_limit: # case2: only start_limit is present + queryset = queryset[int(start_limit)-1:] + elif end_limit: # case3: only end_limit is present + queryset = queryset[:int(end_limit)] + + count = self.request.POST.get("count", "False") + if count in ["True","true","t","T","Yes","yes","Y","y"]: + return Response({"count": queryset.count()}) + + if fields_values: # fields provided in POST request and if not empty serves those fields only + fields_values = [val.strip() for val in fields_values.split(",")] + # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer + serializer = StateSerializer(queryset, fields=fields_values ,many=True) + else: + # if fields param is empty then all the fields as mentioned in serializer are served to the response + serializer = StateSerializer(queryset, many=True) + # JSON Response is provided by default + return Response(serializer.data) + +class CountryAPIView(generics.ListAPIView): + ''' + coco_api class-based view to query Country model and provide JSON response. + django-rest-framework based token passed in Header as {'Authorization': 'Token 12345exampleToken'} + is required to access data from this View. + Only POST method is allowed. + GET request sent will show a message : "Method \"GET\" not allowed." + ''' + + # django-rest-framework TokenAuthentication + authentication_classes = [TokenAuthentication] + permissions_classes =[IsAuthenticated] + + # GET request + def get(self, request): + return Response({"detail":"Method \"GET\" not allowed"}) + + # POST request + def post(self, request, *args, **kwargs): + + queryset = Country.objects.get_queryset().order_by('id') # basic query to be filtered later in this method + + fields_values = request.POST.get('fields', '') # POST param 'limit', no default value specified so empty string is default value + start_limit = request.POST.get('start_limit') # POST param 'start_limit' + end_limit = request.POST.get('end_limit') # POST param 'end_limit' + + # limits the total response count + if start_limit and end_limit: # case1: both are present + queryset = queryset[int(start_limit)-1:int(end_limit)] + elif start_limit: # case2: only start_limit is present + queryset = queryset[int(start_limit)-1:] + elif end_limit: # case3: only end_limit is present + queryset = queryset[:int(end_limit)] + + count = self.request.POST.get("count", "False") + if count in ["True","true","t","T","Yes","yes","Y","y"]: + return Response({"count": queryset.count()}) + + if fields_values: # fields provided in POST request and if not empty serves those fields only + fields_values = [val.strip() for val in fields_values.split(",")] + # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer + serializer = CountrySerializer(queryset, fields=fields_values ,many=True) + else: + # if fields param is empty then all the fields as mentioned in serializer are served to the response + serializer = CountrySerializer(queryset, many=True) + # JSON Response is provided by default + return Response(serializer.data) \ No newline at end of file diff --git a/people/serializers.py b/people/serializers.py index 26b2f6a337..7dac3871e0 100644 --- a/people/serializers.py +++ b/people/serializers.py @@ -1,21 +1,51 @@ from people.models import Person from rest_framework import serializers -from geographies.models import Village +from geographies.models import Village, Block, District, State, Country +from geographies.serializers import VillageSerializer +class DynamicFieldsModelSerializer(serializers.ModelSerializer): + """ + A ModelSerializer that takes an additional `fields` argument that + controls which fields should be displayed. + """ -class VillageSerializer(serializers.ModelSerializer): + def __init__(self, *args, **kwargs): + # Don't pass the 'fields' arg up to the superclass + fields = kwargs.pop('fields', None) - class Meta: - model = Village - fields = ['id', 'village_name'] + # Instantiate the superclass normally + super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs) + + if fields is not None: + # Drop any fields that are not specified in the `fields` argument. + allowed = set(fields) + existing = set(self.fields) + for field_name in existing - allowed: + self.fields.pop(field_name) -class FarmerSerializer(serializers.ModelSerializer): +class FarmerSerializer(DynamicFieldsModelSerializer): village_id = serializers.CharField(source='village.id', read_only=True) - village_name = serializers.CharField(source='village.village_name', read_only=True) + village = serializers.CharField(source='village.village_name', read_only=True) + + block_id = serializers.IntegerField(source='village.block.id', read_only=True) + block_name = serializers.CharField(source='village.block.block_name', read_only=True) + + district_id = serializers.IntegerField(source='village.block.district.id', read_only=True) + district_name = serializers.CharField(source='village.block.district.district_name', read_only=True) + + state_id = serializers.IntegerField(source='village.block.district.state.id', read_only=True) + state_name = serializers.CharField(source='village.block.district.state.state_name', read_only=True) + + country_id = serializers.IntegerField(source='village.block.district.state.country.id', read_only=True) + country_name = serializers.CharField(source='village.block.district.state.country.country_name', read_only=True) + class Meta: - model = Person - fields = ['person_name', 'phone_no', 'gender', 'village_id','village_name'] + model = Person + fields = '__all__' + + + diff --git a/people/urls.py b/people/urls.py index 0953be9b13..22b10ca12b 100644 --- a/people/urls.py +++ b/people/urls.py @@ -1,16 +1,10 @@ -from rest_framework import routers, serializers, viewsets -from django.conf.urls import patterns, include, url -from . import views +from django.conf.urls import url, include -# router = routers.DefaultRouter() -# router.register(r'farmer', FarmerViewSet) -# router.register(r'villages', VillagesViewSet) +from people import views - -urlpatterns = patterns('', - # url(r'^$', views.index, name='index'), - # url(r'^new/$', include(router.urls)), - # (r'^villages/$', VillagesViewSet), - # (r'^farmer/$', FarmerViewSet), - -) \ No newline at end of file +urlpatterns=[ + url(r'^$', views.DefaultView.as_view()), + url('farmers', views.FarmersList.as_view()), + url(r'^csv$', views.CSVView.as_view()), # r'^$' is used for regex of exact match as mentioned + # url(r'^farmers-list', views.FarmerViewSet.as_view({'get': 'list'})), +] diff --git a/people/views.py b/people/views.py index bb7b93707e..91eacf9ef8 100644 --- a/people/views.py +++ b/people/views.py @@ -1,55 +1,163 @@ -from rest_framework import routers, serializers, generics +# default imports +from django.shortcuts import render + +# added imports +from rest_framework import viewsets, generics +from rest_framework import permissions, filters from rest_framework.response import Response -from rest_framework import status, viewsets -# from rest_framework.decorators import action -from people.models import Person -from geographies.models import Country, State, District, Block, Village -from people.serializers import FarmerSerializer #, VillageSerializer +# serializers import +from people.serializers import FarmerSerializer -from geographies.serializers import DistrictSerializer, BlockSerializer, VillageSerializer +# model imports +from people.models import * +from geographies.models import * -from django.http import HttpResponse +# django-rest-framework TokenAuthentication imports +from rest_framework.authentication import SessionAuthentication, BasicAuthentication, TokenAuthentication +from rest_framework.permissions import IsAuthenticated +# CSV View imports +from rest_framework.renderers import JSONRenderer +from rest_framework.views import APIView +from rest_framework.settings import api_settings +from rest_framework_csv import renderers as r -class FarmerViewSet(viewsets.ModelViewSet): +class DefaultView(generics.ListCreateAPIView): + ''' + coco_api class-based view to provide default message in JSON format. + django-rest-framework based token passed in Header as {'Authorization': 'Token 12345exampleToken'} + is required to access data from this View. + Only POST method is allowed. + GET request sent will show a message : "Method \"GET\" not allowed." + ''' + + # django-rest-framework TokenAuthentication + authentication_classes = [TokenAuthentication] + permissions_classes =[IsAuthenticated] - queryset = Person.objects.all()[:1000] - serializer_class = FarmerSerializer + # POST request + def post(self, request, *args, **kwargs): + # dictionary results as JSON format message + return Response({"message":"Welcome to COCO APIs", "base_url":"api/farmer", + "url_list":["api/farmer/farmers"]}) + + # GET request + def get(self, request): + return Response({"detail":"Method \"GET\" not allowed."}) - # @action(methods=['post'], detail=True) - # def set_password(self, request, pk=None): - # return Response("HI, It worked!") -class VillagesViewSet(viewsets.ModelViewSet): - - queryset = Village.objects.all()[:10] - serializer_class = VillageSerializer +class FarmersList(generics.ListCreateAPIView): + ''' + coco_api class-based view to query Person model and provide JSON response. + django-rest-framework based token passed in Header as {'Authorization': 'Token 12345exampleToken'} + is required to access data from this View. + Only POST method is allowed. + GET request sent will show a message : "Method \"GET\" not allowed." + ''' -class BlockViewSet(viewsets.ModelViewSet): - - queryset = Block.objects.all()[:10] - serializer_class = BlockSerializer + # django-rest-framework TokenAuthentication + authentication_classes = [TokenAuthentication] + permissions_classes =[IsAuthenticated] + + # GET request + def get(self, request): + return Response({"detail":"Method \"GET\" not allowed"}) + + # POST request + def post(self, request, *args, **kwargs): + country_id = self.request.POST.get('country_id', 0) # POST param 'country_id', default value is 0 + fields_values = request.POST.get('fields', '') # POST param 'fields', default value is empty string + + try: + # fetches country id from database model Country to verify param value + got_country_id = Country.objects.get(id=country_id).id + # if the country id is found same as param value entered, filters Person model + queryset = Person.objects.all().filter(village__block__district__state__country__exact=got_country_id).order_by('id') + except: + # in case of failure of above try statement, all Person objects are retrieved + queryset = Person.objects.all().order_by('id') + start_limit = request.POST.get('start_limit') # POST param 'start_limit' + end_limit = request.POST.get('end_limit') # POST param 'end_limit' + # limits the total response count + if start_limit and end_limit: # case1: both are present + queryset = queryset[int(start_limit)-1:int(end_limit)] + elif start_limit: # case2: only start_limit is present + queryset = queryset[int(start_limit)-1:] + elif end_limit: # case3: only end_limit is present + queryset = queryset[:int(end_limit)] + count = self.request.POST.get("count", "False") + if count in ["True","true","t","T","Yes","yes","Y","y"]: + return Response({"count": queryset.count()}) + if fields_values: # fields provided in POST request and if not empty serves those fields only + fields_values = [val.strip() for val in fields_values.split(",")] + # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer + serializer = FarmerSerializer(queryset, fields=fields_values, many=True) + else: + # if fields param is empty then all the fields as mentioned in serializer are served to the response + serializer = FarmerSerializer(queryset, many=True) + # JSON Response is provided by default + return Response(serializer.data) -class FarmerDetailView(generics.RetrieveUpdateDestroyAPIView): - """ - GET farmer/:id/ - """ - queryset = Person.objects.all() - serializer_class = FarmerSerializer - def get(self, request, *args, **kwargs): +class CSVView(APIView): + ''' + coco_api class-based view to query Person model and provide CSV response. + django-rest-framework based token passed in Header as {'Authorization': 'Token 12345exampleToken'} + is required to access data from this View. + Only POST method is allowed. + GET request sent will show a message : "Method \"GET\" not allowed." + ''' + + # CSV Renderer class setting to return response of this view as CSV + renderer_classes = (r.CSVRenderer, ) + tuple(api_settings.DEFAULT_RENDERER_CLASSES) + + # django-rest-framework TokenAuthentication + authentication_classes = [TokenAuthentication] + permissions_classes =[IsAuthenticated] + + # GET request + def get(self, request): + return Response({"detail":"Method \"GET\" not allowed"}) + + # POST request + def post(self, request, *args, **kwargs): + + country_id = self.request.POST.get('country_id', 0) # POST param 'country_id', default value is 0 + fields_values = request.POST.get('fields', '') # POST param 'fields', default value is empty string + try: - a_farmer = self.queryset.get(pk=kwargs["pk"]) - # farmers_all = self.queryset.filter(id__gte=10, id__lte=20) - return Response(FarmerSerializer(a_farmer, many=True).data) - except Person.DoesNotExist: - return Response( - data={ - "message": "Farmer with id: {} does not exist".format(kwargs["pk"]) - }, - status=status.HTTP_404_NOT_FOUND - ) \ No newline at end of file + # fetches country id from database model Country to verify param value + got_country_id = Country.objects.get(id=country_id).id + # if the country id is found same as param value entered, filters Person model + queryset = Person.objects.all().filter(village__block__district__state__country__exact=got_country_id).order_by('id') + except: + # in case of failure of above try statement, all Person objects are retrieved + queryset = Person.objects.all().order_by('id') + + start_limit = request.POST.get('start_limit') # POST param 'start_limit' + end_limit = request.POST.get('end_limit') # POST param 'end_limit' + # limits the total response count + if start_limit and end_limit: # case1: both are present + queryset = queryset[int(start_limit)-1:int(end_limit)] + elif start_limit: # case2: only start_limit is present + queryset = queryset[int(start_limit)-1:] + elif end_limit: # case3: only end_limit is present + queryset = queryset[:int(end_limit)] + + count = self.request.POST.get("count", "False") + if count in ["True","true","t","T","Yes","yes","Y","y"]: + return Response({"count": queryset.count()}) + + if fields_values: # fields provided in POST request and if not empty serves those fields only + fields_values = [val.strip() for val in fields_values.split(",")] + # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer + serializer = FarmerSerializer(queryset, fields=fields_values, many=True) + else: + # if fields param is empty then all the fields as mentioned in serializer are served to the response + serializer = FarmerSerializer(queryset, many=True) + # CSV Response is provided + return Response(serializer.data) \ No newline at end of file diff --git a/requirements/requirements.txt b/requirements/requirements.txt index d54afcda3a..4ed7d025b5 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -35,7 +35,7 @@ isodate==0.5.4 jdcal==1.3 Mezzanine==4.1.0 MySQL-python==1.2.3 #comment this for mac -#mysqlclient #uncomment for Mac +# mysqlclient #uncomment for Mac newrelic==2.82.0.62 numpy==1.12.0 oauth2==1.5.211 @@ -84,4 +84,5 @@ xlrd==0.9.2 XlsxWriter==0.5.1 xlwt==0.7.5 yolk==0.4.1 -djangorestframework==3.6.4 \ No newline at end of file +djangorestframework==3.6.4 +djangorestframework-csv==2.1.0 diff --git a/videos/serializers.py b/videos/serializers.py new file mode 100644 index 0000000000..753de452f7 --- /dev/null +++ b/videos/serializers.py @@ -0,0 +1,28 @@ +from .models import * +from rest_framework import serializers + +class DynamicFieldsModelSerializer(serializers.ModelSerializer): + """ + A ModelSerializer that takes an additional `fields` argument that + controls which fields should be displayed. + """ + + def __init__(self, *args, **kwargs): + # Don't pass the 'fields' arg up to the superclass + fields = kwargs.pop('fields', None) + + # Instantiate the superclass normally + super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs) + + if fields is not None: + # Drop any fields that are not specified in the `fields` argument. + allowed = set(fields) + existing = set(self.fields) + for field_name in existing - allowed: + self.fields.pop(field_name) + +class VideoSerializer(DynamicFieldsModelSerializer): + class Meta: + model = Video + fields = '__all__' + diff --git a/videos/urls.py b/videos/urls.py index 441f255063..c1b9e988ca 100644 --- a/videos/urls.py +++ b/videos/urls.py @@ -12,6 +12,10 @@ import videokheti.urls +# coco_api specific import +from videos import views + + urlpatterns = patterns('', url(r'^$', RedirectView.as_view(url=VIDEOS_PAGE)), url(r'^collection-add/(?P.+)/$', collection_edit_view, name='edit_collection'), @@ -28,4 +32,9 @@ # admin/logout/ should be above admin/ URL url(r'^admin/logout/?$', 'django.contrib.auth.views.logout', {'next_page': '/videos/admin/'}), (r'^admin/', include(website_admin.urls)), + + # coco_api video urls + # as_view method takes type of request as key and class's method name as value + url('api/videos', views.VideoViewSet.as_view()), + ) diff --git a/videos/views.py b/videos/views.py new file mode 100644 index 0000000000..5849073fd9 --- /dev/null +++ b/videos/views.py @@ -0,0 +1,70 @@ +#default +from django.shortcuts import render + +# model imports +from videos.models import * + +# serializers imports +from videos.serializers import * + +# drf imports +from rest_framework import viewsets, generics +from rest_framework import permissions +from rest_framework.response import Response + +# django-rest-framework TokenAuthentication imports +from rest_framework.authentication import SessionAuthentication, BasicAuthentication, TokenAuthentication +from rest_framework.permissions import IsAuthenticated + + +class VideoViewSet(generics.ListCreateAPIView): + ''' + coco_api class-based view to query Videos model and provide JSON response. + django-rest-framework based token passed in Header as {'Authorization': 'Token 12345exampleToken'} + is required to access data from this View. + Only POST method is allowed. + GET request sent will show a message : "Method \"GET\" not allowed." + ''' + + # django-rest-framework TokenAuthentication + authentication_classes = [TokenAuthentication] + permissions_classes =[IsAuthenticated] + + # GET request + def get(self, request): + return Response({"detail":"Method \"GET\" not allowed"}) + + # POST request + def post(self, request, *args, **kwargs): + + start_limit = request.POST.get('start_limit') # POST param 'start_limit' + end_limit = request.POST.get('end_limit') # POST param 'end_limit' + fields_values = request.POST.get('fields', '') # POST param 'fields' + video_id = self.request.POST.get('id', 0) # POST param 'id' + + if video_id: # checks if video id is present + queryset = Video.objects.filter(id__exact=video_id) + else: + queryset = Video.objects.all().order_by('id') + # limits the total response count + if start_limit and end_limit: # case1: both are present + queryset = queryset[int(start_limit)-1:int(end_limit)] + elif start_limit: # case2: only start_limit is present + queryset = queryset[int(start_limit)-1:] + elif end_limit: # case3: only end_limit is present + queryset = queryset[:int(end_limit)] + + count = self.request.POST.get("count", "False") + if count.lower() in ["true","t","yes","y"]: + return Response({"count": queryset.count()}) + + if fields_values: # fields provided in POST request and if not empty serves those fields only + fields_values = [val.strip() for val in fields_values.split(",")] + # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer + serializer = VideoSerializer(queryset, fields=fields_values, many=True) + else: + # if fields param is empty then all the fields as mentioned in serializer are served to the response + serializer = VideoSerializer(queryset, many=True) + # JSON Response is provided by default + return Response(serializer.data) + From 78ea8458eb2023768f28ae2e4910475bffd0556f Mon Sep 17 00:00:00 2001 From: vermastuti Date: Sat, 9 May 2020 14:40:02 +0530 Subject: [PATCH 05/35] count-param-edited --- activities/views.py | 5 +++-- geographies/views.py | 25 +++++++++++++++---------- people/views.py | 12 +++++++----- videos/views.py | 3 ++- 4 files changed, 27 insertions(+), 18 deletions(-) diff --git a/activities/views.py b/activities/views.py index e3eef4637c..7a8ed74294 100644 --- a/activities/views.py +++ b/activities/views.py @@ -89,8 +89,9 @@ def post(self, request, *args, **kwargs): elif end_limit: # case3: only end_limit is present queryset = queryset[:int(end_limit)] - count = self.request.POST.get("count", "False") - if count in ["True","true","t","T","Yes","yes","Y","y"]: + count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" + # returns count only if param value matched + if count.lower() in ["true","t","yes","y"]: return Response({"count": queryset.count()}) fields_values = request.POST.get('fields', '') # POST param 'fields', default value is empty string diff --git a/geographies/views.py b/geographies/views.py index 28768ca687..8410ba1dd4 100644 --- a/geographies/views.py +++ b/geographies/views.py @@ -78,8 +78,9 @@ def post(self, request, *args, **kwargs): elif end_limit: # case3: only end_limit is present queryset = queryset[:int(end_limit)] - count = self.request.POST.get("count", "False") - if count in ["True","true","t","T","Yes","yes","Y","y"]: + count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" + # returns count only if param value matched + if count.lower() in ["true","t","yes","y"]: return Response({"count": queryset.count()}) if fields_values: # fields provided in POST request and if not empty serves those fields only @@ -127,8 +128,9 @@ def post(self, request, *args, **kwargs): elif end_limit: # case3: only end_limit is present queryset = queryset[:int(end_limit)] - count = self.request.POST.get("count", "False") - if count in ["True","true","t","T","Yes","yes","Y","y"]: + count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" + # returns count only if param value matched + if count.lower() in ["true","t","yes","y"]: return Response({"count": queryset.count()}) if fields_values: # fields provided in POST request and if not empty serves those fields only @@ -175,8 +177,9 @@ def post(self, request, *args, **kwargs): elif end_limit: # case3: only end_limit is present queryset = queryset[:int(end_limit)] - count = self.request.POST.get("count", "False") - if count in ["True","true","t","T","Yes","yes","Y","y"]: + count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" + # returns count only if param value matched + if count.lower() in ["true","t","yes","y"]: return Response({"count": queryset.count()}) if fields_values: # fields provided in POST request and if not empty serves those fields only @@ -223,8 +226,9 @@ def post(self, request, *args, **kwargs): elif end_limit: # case3: only end_limit is present queryset = queryset[:int(end_limit)] - count = self.request.POST.get("count", "False") - if count in ["True","true","t","T","Yes","yes","Y","y"]: + count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" + # returns count only if param value matched + if count.lower() in ["true","t","yes","y"]: return Response({"count": queryset.count()}) if fields_values: # fields provided in POST request and if not empty serves those fields only @@ -271,8 +275,9 @@ def post(self, request, *args, **kwargs): elif end_limit: # case3: only end_limit is present queryset = queryset[:int(end_limit)] - count = self.request.POST.get("count", "False") - if count in ["True","true","t","T","Yes","yes","Y","y"]: + count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" + # returns count only if param value matched + if count.lower() in ["true","t","yes","y"]: return Response({"count": queryset.count()}) if fields_values: # fields provided in POST request and if not empty serves those fields only diff --git a/people/views.py b/people/views.py index 91eacf9ef8..e6c816607c 100644 --- a/people/views.py +++ b/people/views.py @@ -88,9 +88,10 @@ def post(self, request, *args, **kwargs): elif end_limit: # case3: only end_limit is present queryset = queryset[:int(end_limit)] - count = self.request.POST.get("count", "False") - if count in ["True","true","t","T","Yes","yes","Y","y"]: - return Response({"count": queryset.count()}) + count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" + # returns count only if param value matched + if count.lower() in ["true","t","yes","y"]: + return Response({"count": queryset.count()}) if fields_values: # fields provided in POST request and if not empty serves those fields only fields_values = [val.strip() for val in fields_values.split(",")] @@ -148,8 +149,9 @@ def post(self, request, *args, **kwargs): elif end_limit: # case3: only end_limit is present queryset = queryset[:int(end_limit)] - count = self.request.POST.get("count", "False") - if count in ["True","true","t","T","Yes","yes","Y","y"]: + count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" + # returns count only if param value matched + if count.lower() in ["true","t","yes","y"]: return Response({"count": queryset.count()}) if fields_values: # fields provided in POST request and if not empty serves those fields only diff --git a/videos/views.py b/videos/views.py index 5849073fd9..842feeea6d 100644 --- a/videos/views.py +++ b/videos/views.py @@ -54,7 +54,8 @@ def post(self, request, *args, **kwargs): elif end_limit: # case3: only end_limit is present queryset = queryset[:int(end_limit)] - count = self.request.POST.get("count", "False") + count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" + # returns count only if param value matched if count.lower() in ["true","t","yes","y"]: return Response({"count": queryset.count()}) From 04ecd3c03eb71012f55481b0e90bd7cb120dc2c4 Mon Sep 17 00:00:00 2001 From: vermastuti Date: Mon, 11 May 2020 15:33:24 +0530 Subject: [PATCH 06/35] req-txt-updated --- requirements/requirements.txt | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 4ed7d025b5..c2f12f874c 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -1,4 +1,5 @@ appdirs==1.4.3 +appnope==0.1.0 backports.shutil-get-terminal-size==1.0.0 BeautifulSoup==3.2.1 beautifulsoup4==4.5.3 @@ -17,7 +18,10 @@ django-contrib-comments==1.8.0 django-cors-headers==2.1.0 django-debug-toolbar==0.8.5 django-easy-select2==1.3.4 +django-extensions==2.2.9 django-tastypie==0.12.2 +djangorestframework==3.6.4 +djangorestframework-csv==2.1.0 enum34==1.1.6 et-xmlfile==1.0.1 filebrowser-safe==0.4.6 @@ -34,8 +38,8 @@ ipython-genutils==0.2.0 isodate==0.5.4 jdcal==1.3 Mezzanine==4.1.0 -MySQL-python==1.2.3 #comment this for mac -# mysqlclient #uncomment for Mac +mysql-connector==2.2.9 +mysqlclient==1.4.6 newrelic==2.82.0.62 numpy==1.12.0 oauth2==1.5.211 @@ -73,6 +77,7 @@ six==1.10.0 tinycss2==0.6.1 traitlets==4.3.2 twython==3.0.0 +typing==3.7.4.1 tzlocal==1.3 unicodecsv==0.9.4 uritemplate==3.0.0 @@ -84,5 +89,3 @@ xlrd==0.9.2 XlsxWriter==0.5.1 xlwt==0.7.5 yolk==0.4.1 -djangorestframework==3.6.4 -djangorestframework-csv==2.1.0 From bc688f6facaee0287c034bd5e11d2770c8262365 Mon Sep 17 00:00:00 2001 From: vermastuti Date: Mon, 11 May 2020 16:11:28 +0530 Subject: [PATCH 07/35] base_settings_updated --- dg/base_settings.py | 119 +++++++++++++++++++++++--------------------- 1 file changed, 63 insertions(+), 56 deletions(-) diff --git a/dg/base_settings.py b/dg/base_settings.py index cd2ab7bbb4..bd5f9ea3d7 100644 --- a/dg/base_settings.py +++ b/dg/base_settings.py @@ -188,6 +188,10 @@ 'dataexport', 'rest_framework', # 3rd Party + 'django_extensions', + + #drf TokenAuthentication + 'rest_framework.authtoken', ) # Store these package names here as they may change in the future since @@ -211,58 +215,58 @@ 'social.backends.google.GoogleOAuth2', ) -LOGGING = { - 'version': 1, - 'disable_existing_loggers': True, - 'formatters': { - 'standard': { - 'format' : "[%(levelname)s] [%(asctime)s] [%(name)s] %(message)s", - 'datefmt' : "%d/%b/%Y %H:%M:%S" - }, - }, - 'handlers': { - 'null': { - 'level':'DEBUG', - 'class':'django.utils.log.NullHandler', - }, - 'logfile': { - 'level':'DEBUG', - 'class':'logging.handlers.RotatingFileHandler', - 'filename': os.path.join(PROJECT_PATH, 'media/social_website/uploads/log/logfile'), - 'formatter': 'standard', - }, - 'ap_migration_log': { - 'level': 'INFO', - 'class':'logging.handlers.RotatingFileHandler', - 'filename': os.path.join(PROJECT_PATH, '../geographies/management/commands/log/ap_migration_log'), - 'formatter': 'standard', - }, - 'console':{ - 'level':'INFO', - 'class':'logging.StreamHandler', - 'formatter': 'standard' - }, +# LOGGING = { +# 'version': 1, +# 'disable_existing_loggers': True, +# 'formatters': { +# 'standard': { +# 'format' : "[%(levelname)s] [%(asctime)s] [%(name)s] %(message)s", +# 'datefmt' : "%d/%b/%Y %H:%M:%S" +# }, +# }, +# 'handlers': { +# 'null': { +# 'level':'DEBUG', +# 'class':'django.utils.log.NullHandler', +# }, +# 'logfile': { +# 'level':'DEBUG', +# 'class':'logging.handlers.RotatingFileHandler', +# 'filename': os.path.join(PROJECT_PATH, 'media/social_website/uploads/log/logfile'), +# 'formatter': 'standard', +# }, +# 'ap_migration_log': { +# 'level': 'INFO', +# 'class':'logging.handlers.RotatingFileHandler', +# 'filename': os.path.join(PROJECT_PATH, '../geographies/management/commands/log/ap_migration_log'), +# 'formatter': 'standard', +# }, +# 'console':{ +# 'level':'INFO', +# 'class':'logging.StreamHandler', +# 'formatter': 'standard' +# }, - }, - 'loggers': { - 'social_website': { - 'handlers': ['logfile'], - 'level': 'DEBUG', - }, - 'dashboard': { - 'handlers': ['logfile'], - 'level': 'DEBUG', - }, - 'loop_ivr': { - 'handlers': ['logfile'], - 'level': 'DEBUG', - }, - 'geographies': { - 'handlers': ['ap_migration_log'], - 'level' : 'INFO', - } - } -} +# }, +# 'loggers': { +# 'social_website': { +# 'handlers': ['logfile'], +# 'level': 'DEBUG', +# }, +# 'dashboard': { +# 'handlers': ['logfile'], +# 'level': 'DEBUG', +# }, +# 'loop_ivr': { +# 'handlers': ['logfile'], +# 'level': 'DEBUG', +# }, +# 'geographies': { +# 'handlers': ['ap_migration_log'], +# 'level' : 'INFO', +# } +# } +# } PRODUCT_PAGE = ('%s%s')%(WEBSITE_DOMAIN, 'solutions/') LOOP_PAGE = ('%s%s')%(WEBSITE_DOMAIN, 'loop/') @@ -271,10 +275,13 @@ VIDEOS_PAGE = ('%s%s')%(WEBSITE_DOMAIN, 'videos/') LOOP_APP_PAGE = ('%s')%('https://play.google.com/store/apps/details?id=loop.org.digitalgreen.loop') TRAINING_APP_PAGE = ('%s')%('https://play.google.com/store/apps/details?id=org.digitalgreen.trainingapp') + REST_FRAMEWORK = { - # Use Django's standard `django.contrib.auth` permissions, - # or allow read-only access for unauthenticated users. - 'DEFAULT_PERMISSION_CLASSES': [ - 'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly' - ] + 'DEFAULT_AUTHENTICATION_CLASSES': [ + 'rest_framework.authentication.BasicAuthentication', + 'rest_framework.authentication.SessionAuthentication', + ], + 'DEFAULT_PERMISSION_CLASSES': [ + 'rest_framework.permissions.IsAuthenticated', + ], } \ No newline at end of file From 6ed47eb58def79067dc1855b11838060ee178340 Mon Sep 17 00:00:00 2001 From: vermastuti Date: Tue, 19 May 2020 12:33:59 +0530 Subject: [PATCH 08/35] programs-api-added-and-csrf-auth-bug-exists --- activities/urls.py | 7 ++- activities/views.py | 20 +++++-- dg/urls.py | 3 +- programs/serializers.py | 32 ++++++++++ programs/urls.py | 12 ++++ programs/views.py | 125 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 191 insertions(+), 8 deletions(-) create mode 100644 programs/serializers.py create mode 100644 programs/urls.py create mode 100644 programs/views.py diff --git a/activities/urls.py b/activities/urls.py index eb81cf23cf..3556883e02 100644 --- a/activities/urls.py +++ b/activities/urls.py @@ -1,7 +1,10 @@ from django.conf.urls import url, include from activities import views +from django.views.decorators.csrf import csrf_exempt + urlpatterns=[ - url('upavan', views.UpavanViewSet.as_view()), -] \ No newline at end of file + url(r'^upavan', views.UpavanViewSet.as_view()), +] + diff --git a/activities/views.py b/activities/views.py index 7a8ed74294..85748e4b1d 100644 --- a/activities/views.py +++ b/activities/views.py @@ -14,12 +14,16 @@ from rest_framework.response import Response from rest_framework import status -#authentication +# authentication from rest_framework.authentication import SessionAuthentication, BasicAuthentication, TokenAuthentication from rest_framework.permissions import IsAuthenticated +# csrf +from django.views.decorators.csrf import csrf_exempt +from django.utils.decorators import method_decorator -class UpavanViewSet(generics.ListCreateAPIView): + +class UpavanViewSet( generics.ListCreateAPIView): ''' coco_api class-based view to query Screening model and provide JSON response. django-rest-framework based token passed in Header as {'Authorization': 'Token 12345exampleToken'} @@ -31,8 +35,7 @@ class UpavanViewSet(generics.ListCreateAPIView): # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] permissions_classes =[IsAuthenticated] - - serializer_class = ScreeningSerializer + # import pdb;pdb.set_trace() # GET request def get(self, request): @@ -40,6 +43,7 @@ def get(self, request): # POST request def post(self, request, *args, **kwargs): + queryset = Screening.objects.get_queryset().order_by('id') @@ -102,5 +106,11 @@ def post(self, request, *args, **kwargs): else: # if fields param is empty then all the fields as mentioned in serializer are served to the response serializer = ScreeningSerializer(queryset, many=True) + + # context = RequestContext(request) + # context_dict = {} + # # Update the dictionary with csrf_token + # conext_dict.update(csrf(request)) + # JSON Response is provided by default - return Response(serializer.data) \ No newline at end of file + return Response(serializer.data) #, context_dict, context) \ No newline at end of file diff --git a/dg/urls.py b/dg/urls.py index 83db49e15c..61bea47340 100644 --- a/dg/urls.py +++ b/dg/urls.py @@ -153,7 +153,8 @@ url(r'api-token-auth', views.obtain_auth_token), # POST;params: {'username':'','password':''}; generates token url(r'api/farmer/', include('people.urls')), # includes people.urls.py url(r'api/geo/', include('geographies.urls')), # includes geographies.urls.py - url(r'api/activities/', include('activities.urls')), # includes activities.urls.py + (r'^api/activities/', include('activities.urls')), # includes activities.urls.py + url(r'api/programs/', include('programs.urls')), # includes programs.urls.py #coco_api changes ends here ) diff --git a/programs/serializers.py b/programs/serializers.py new file mode 100644 index 0000000000..eb8e725f0f --- /dev/null +++ b/programs/serializers.py @@ -0,0 +1,32 @@ +from models import * +from rest_framework import serializers + +class DynamicFieldsModelSerializer(serializers.ModelSerializer): + """ + A ModelSerializer that takes an additional `fields` argument that + controls which fields should be displayed. + """ + + def __init__(self, *args, **kwargs): + # Don't pass the 'fields' arg up to the superclass + fields = kwargs.pop('fields', None) + + # Instantiate the superclass normally + super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs) + + if fields is not None: + # Drop any fields that are not specified in the `fields` argument. + allowed = set(fields) + existing = set(self.fields) + for field_name in existing - allowed: + self.fields.pop(field_name) + +class PartnerSerializer(DynamicFieldsModelSerializer): + class Meta: + model = Partner + fields = '__all__' + +class ProjectSerializer(DynamicFieldsModelSerializer): + class Meta: + model = Project + fields = '__all__' \ No newline at end of file diff --git a/programs/urls.py b/programs/urls.py new file mode 100644 index 0000000000..4447660e8a --- /dev/null +++ b/programs/urls.py @@ -0,0 +1,12 @@ +from django.conf.urls import url, include +from views import * + + +urlpatterns = [ + + url('partner', PartnerAPIView.as_view()), + url('project', ProjectAPIView.as_view()), + +] + + diff --git a/programs/views.py b/programs/views.py new file mode 100644 index 0000000000..5d99649a15 --- /dev/null +++ b/programs/views.py @@ -0,0 +1,125 @@ +# default imports +from django.shortcuts import render + +# rest_framework imports +from rest_framework import generics +from rest_framework.response import Response + +# app imports +from models import * +from serializers import * + +# authentication imports +from rest_framework.authentication import TokenAuthentication +from rest_framework.permissions import IsAuthenticated + +class PartnerAPIView(generics.ListCreateAPIView): + ''' + coco_api class-based view to query Partner model and provide JSON response. + django-rest-framework based token passed in Header as {'Authorization': 'Token 12345exampleToken'} + is required to access data from this View. + Only POST method is allowed. + GET request sent will show a message : "Method \"GET\" not allowed." + ''' + + # django-rest-framework TokenAuthentication + authentication_classes = [TokenAuthentication] + permissions_classes =[IsAuthenticated] + + # GET request + def get(self, request): + return Response({"detail":"Method \"GET\" not allowed"}) + + # POST request + def post(self, request, *args, **kwargs): + + start_limit = request.POST.get('start_limit') # POST param 'start_limit' + end_limit = request.POST.get('end_limit') # POST param 'end_limit' + fields_values = request.POST.get('fields', '') # POST param 'fields' + partner_id = self.request.POST.get('id', 0) # POST param 'id' + + queryset = Partner.objects.all().order_by('id') + serializer_class = PartnerSerializer + + if partner_id: # checks if video id is present + queryset = queryset.filter(id__exact=partner_id) + else: + # limits the total response count + if start_limit and end_limit: # case1: both are present + queryset = queryset[int(start_limit)-1:int(end_limit)] + elif start_limit: # case2: only start_limit is present + queryset = queryset[int(start_limit)-1:] + elif end_limit: # case3: only end_limit is present + queryset = queryset[:int(end_limit)] + + count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" + # returns count only if param value matched + if count.lower() in ["true","t","yes","y"]: + return Response({"count": queryset.count()}) + + if fields_values: # fields provided in POST request and if not empty serves those fields only + fields_values = [val.strip() for val in fields_values.split(",")] + # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer + serializer = serializer_class(queryset, fields=fields_values, many=True) + else: + # if fields param is empty then all the fields as mentioned in serializer are served to the response + serializer = serializer_class(queryset, many=True) + # JSON Response is provided by default + return Response(serializer.data) + + + + +class ProjectAPIView(generics.ListCreateAPIView): + ''' + coco_api class-based view to query Project model and provide JSON response. + django-rest-framework based token passed in Header as {'Authorization': 'Token 12345exampleToken'} + is required to access data from this View. + Only POST method is allowed. + GET request sent will show a message : "Method \"GET\" not allowed." + ''' + + # django-rest-framework TokenAuthentication + authentication_classes = [TokenAuthentication] + permissions_classes =[IsAuthenticated] + + # GET request + def get(self, request): + return Response({"detail":"Method \"GET\" not allowed"}) + + # POST request + def post(self, request, *args, **kwargs): + + start_limit = request.POST.get('start_limit') # POST param 'start_limit' + end_limit = request.POST.get('end_limit') # POST param 'end_limit' + fields_values = request.POST.get('fields', '') # POST param 'fields' + project_id = self.request.POST.get('id', 0) # POST param 'id' + + queryset = Project.objects.all().order_by('id') + serializer_class = ProjectSerializer + + if project_id: # checks if video id is present + queryset = queryset.filter(id__exact=project_id) + else: + # limits the total response count + if start_limit and end_limit: # case1: both are present + queryset = queryset[int(start_limit)-1:int(end_limit)] + elif start_limit: # case2: only start_limit is present + queryset = queryset[int(start_limit)-1:] + elif end_limit: # case3: only end_limit is present + queryset = queryset[:int(end_limit)] + + count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" + # returns count only if param value matched + if count.lower() in ["true","t","yes","y"]: + return Response({"count": queryset.count()}) + + if fields_values: # fields provided in POST request and if not empty serves those fields only + fields_values = [val.strip() for val in fields_values.split(",")] + # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer + serializer = serializer_class(queryset, fields=fields_values, many=True) + else: + # if fields param is empty then all the fields as mentioned in serializer are served to the response + serializer = serializer_class(queryset, many=True) + # JSON Response is provided by default + return Response(serializer.data) From 883dc77a55a381d4c4de0fd4987f7d0c2f54d113 Mon Sep 17 00:00:00 2001 From: vermastuti Date: Tue, 19 May 2020 14:46:46 +0530 Subject: [PATCH 09/35] resolved-csrf-issue --- activities/urls.py | 6 ++---- activities/views.py | 7 ------- dg/urls.py | 24 +++++++++++++++++------- geographies/urls.py | 2 +- people/urls.py | 4 ++-- videos/urls.py | 2 ++ 6 files changed, 24 insertions(+), 21 deletions(-) diff --git a/activities/urls.py b/activities/urls.py index 3556883e02..d479b67eed 100644 --- a/activities/urls.py +++ b/activities/urls.py @@ -1,10 +1,8 @@ -from django.conf.urls import url, include +from django.conf.urls import url, include, patterns from activities import views -from django.views.decorators.csrf import csrf_exempt - urlpatterns=[ - url(r'^upavan', views.UpavanViewSet.as_view()), + url('upavan', views.UpavanViewSet.as_view()), ] diff --git a/activities/views.py b/activities/views.py index 85748e4b1d..13bea67bbb 100644 --- a/activities/views.py +++ b/activities/views.py @@ -18,10 +18,6 @@ from rest_framework.authentication import SessionAuthentication, BasicAuthentication, TokenAuthentication from rest_framework.permissions import IsAuthenticated -# csrf -from django.views.decorators.csrf import csrf_exempt -from django.utils.decorators import method_decorator - class UpavanViewSet( generics.ListCreateAPIView): ''' @@ -35,7 +31,6 @@ class UpavanViewSet( generics.ListCreateAPIView): # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] permissions_classes =[IsAuthenticated] - # import pdb;pdb.set_trace() # GET request def get(self, request): @@ -43,10 +38,8 @@ def get(self, request): # POST request def post(self, request, *args, **kwargs): - queryset = Screening.objects.get_queryset().order_by('id') - uc_id = request.POST.get('user_created') # POST param 'user_created', default value is empty string if uc_id: queryset = queryset.filter(user_created__exact=uc_id) # filters for numeric values with exact match diff --git a/dg/urls.py b/dg/urls.py index 61bea47340..d43a61c7c5 100644 --- a/dg/urls.py +++ b/dg/urls.py @@ -20,6 +20,10 @@ import ivr.urls import training.urls import videos.urls +import people.urls +import activities.urls +import geographies.urls +import programs.urls from django.contrib import admin admin.autodiscover() @@ -89,6 +93,16 @@ (r'^dimagi/', include(dimagi.urls)), (r'^videos/', include(videos.urls)), + + #coco_api changes starts here + (r'^api-token-auth', views.obtain_auth_token), # POST;params: {'username':'','password':''}; generates token + (r'^api/farmer/', include(people.urls)), # includes people.urls.py + (r'^api/geo/', include(geographies.urls)), # includes geographies.urls.py + (r'^api/activities/', include(activities.urls)), # includes activities.urls.py + (r'^api/programs/', include(programs.urls)), # includes programs.urls.py + #coco_api changes ends here + + # ivrsadmin/logout/ should be above admin/ URL url(r'^ivrsadmin/logout/?$', 'django.contrib.auth.views.logout', {'next_page': '/ivrsadmin'}), (r'^ivrsadmin/', include(ivr_admin.urls)), @@ -149,13 +163,9 @@ #AJAX for Feedback #url(r'^feedbacksubmit_json$', 'dg.feedback_view.ajax'), - #coco_api changes starts here - url(r'api-token-auth', views.obtain_auth_token), # POST;params: {'username':'','password':''}; generates token - url(r'api/farmer/', include('people.urls')), # includes people.urls.py - url(r'api/geo/', include('geographies.urls')), # includes geographies.urls.py - (r'^api/activities/', include('activities.urls')), # includes activities.urls.py - url(r'api/programs/', include('programs.urls')), # includes programs.urls.py - #coco_api changes ends here + + + ) diff --git a/geographies/urls.py b/geographies/urls.py index a3f68f2bdc..5fd3ac1a8b 100644 --- a/geographies/urls.py +++ b/geographies/urls.py @@ -3,7 +3,7 @@ from geographies import views urlpatterns=[ - url('^$', views.DefaultView.as_view({'get': 'message'})), + url('default', views.DefaultView.as_view({'get': 'message'})), url('village', views.VillageAPIView.as_view()), url('block', views.BlockAPIView.as_view()), url('district', views.DistrictAPIView.as_view()), diff --git a/people/urls.py b/people/urls.py index 22b10ca12b..adf5fdf24f 100644 --- a/people/urls.py +++ b/people/urls.py @@ -3,8 +3,8 @@ from people import views urlpatterns=[ - url(r'^$', views.DefaultView.as_view()), + url('default', views.DefaultView.as_view()), url('farmers', views.FarmersList.as_view()), - url(r'^csv$', views.CSVView.as_view()), # r'^$' is used for regex of exact match as mentioned + url('csv', views.CSVView.as_view()), # r'^$' is used for regex of exact match as mentioned # url(r'^farmers-list', views.FarmerViewSet.as_view({'get': 'list'})), ] diff --git a/videos/urls.py b/videos/urls.py index c1b9e988ca..1372205d55 100644 --- a/videos/urls.py +++ b/videos/urls.py @@ -10,6 +10,8 @@ from dg.base_settings import VIDEOS_PAGE from dg.website_admin import website_admin +from activities import urls as acturls + import videokheti.urls # coco_api specific import From 798c1b052aa4d603dd6f1bed2a283070a19b511d Mon Sep 17 00:00:00 2001 From: vermastuti Date: Wed, 20 May 2020 15:06:28 +0530 Subject: [PATCH 10/35] standard-urls-and-names --- activities/urls.py | 2 +- activities/views.py | 2 +- dg/urls.py | 8 ++++---- geographies/urls.py | 12 ++++++------ geographies/views.py | 14 +++++++------- people/urls.py | 6 +++--- people/views.py | 10 ++++++---- programs/urls.py | 4 ++-- videos/urls.py | 2 +- videos/views.py | 2 +- 10 files changed, 32 insertions(+), 30 deletions(-) diff --git a/activities/urls.py b/activities/urls.py index d479b67eed..14fb0c8190 100644 --- a/activities/urls.py +++ b/activities/urls.py @@ -3,6 +3,6 @@ from activities import views urlpatterns=[ - url('upavan', views.UpavanViewSet.as_view()), + url(r'^api/screening', views.ScreeningAPIView.as_view()), ] diff --git a/activities/views.py b/activities/views.py index 13bea67bbb..c4a32866ae 100644 --- a/activities/views.py +++ b/activities/views.py @@ -19,7 +19,7 @@ from rest_framework.permissions import IsAuthenticated -class UpavanViewSet( generics.ListCreateAPIView): +class ScreeningAPIView( generics.ListCreateAPIView): ''' coco_api class-based view to query Screening model and provide JSON response. django-rest-framework based token passed in Header as {'Authorization': 'Token 12345exampleToken'} diff --git a/dg/urls.py b/dg/urls.py index d43a61c7c5..d4cb854192 100644 --- a/dg/urls.py +++ b/dg/urls.py @@ -96,10 +96,10 @@ #coco_api changes starts here (r'^api-token-auth', views.obtain_auth_token), # POST;params: {'username':'','password':''}; generates token - (r'^api/farmer/', include(people.urls)), # includes people.urls.py - (r'^api/geo/', include(geographies.urls)), # includes geographies.urls.py - (r'^api/activities/', include(activities.urls)), # includes activities.urls.py - (r'^api/programs/', include(programs.urls)), # includes programs.urls.py + (r'^farmer/', include(people.urls)), # includes people.urls.py + (r'^geo/', include(geographies.urls)), # includes geographies.urls.py + (r'^activities/', include(activities.urls)), # includes activities.urls.py + (r'^programs/', include(programs.urls)), # includes programs.urls.py #coco_api changes ends here diff --git a/geographies/urls.py b/geographies/urls.py index 5fd3ac1a8b..67f84ab782 100644 --- a/geographies/urls.py +++ b/geographies/urls.py @@ -3,11 +3,11 @@ from geographies import views urlpatterns=[ - url('default', views.DefaultView.as_view({'get': 'message'})), - url('village', views.VillageAPIView.as_view()), - url('block', views.BlockAPIView.as_view()), - url('district', views.DistrictAPIView.as_view()), - url('state', views.StateAPIView.as_view()), - url('country', views.CountryAPIView.as_view()), + url(r'^api/default', views.DefaultView.as_view()), + url(r'^api/village', views.VillageAPIView.as_view()), + url(r'^api/block', views.BlockAPIView.as_view()), + url(r'^api/district', views.DistrictAPIView.as_view()), + url(r'^api/state', views.StateAPIView.as_view()), + url(r'^api/country', views.CountryAPIView.as_view()), # url('csv', views.CSVView.as_view()), ] diff --git a/geographies/views.py b/geographies/views.py index 8410ba1dd4..dad1652988 100644 --- a/geographies/views.py +++ b/geographies/views.py @@ -17,7 +17,7 @@ from rest_framework.authentication import SessionAuthentication, BasicAuthentication, TokenAuthentication from rest_framework.permissions import IsAuthenticated -class DefaultView(viewsets.ViewSet): +class DefaultView(generics.ListAPIView): ''' coco_api class-based view to provide default message in JSON format. django-rest-framework based token passed in Header as {'Authorization': 'Token 12345exampleToken'} @@ -33,12 +33,12 @@ class DefaultView(viewsets.ViewSet): # POST request def post(self, request): # dictionary results as JSON format message - return Response({"message":"Welcome to COCO APIs", "base_url":"api/geo", - "url_list":["api/geo/village", - "api/geo/block", - "api/geo/district", - "api/geo/state", - "api/geo/country"]}) + return Response({"message":"Welcome to COCO APIs", "base_url":"/geo/api/", + "url_list":["/geo/api/village", + "/geo/api/block", + "/geo/api/district", + "/geo/api/state", + "/geo/api/country"]}) # GET request def get(self, request, *args, **kwargs): return Response({"detail":"Method \"GET\" not allowed"}) diff --git a/people/urls.py b/people/urls.py index adf5fdf24f..ac6484cb88 100644 --- a/people/urls.py +++ b/people/urls.py @@ -3,8 +3,8 @@ from people import views urlpatterns=[ - url('default', views.DefaultView.as_view()), - url('farmers', views.FarmersList.as_view()), - url('csv', views.CSVView.as_view()), # r'^$' is used for regex of exact match as mentioned + url(r'^api/default', views.DefaultView.as_view()), + url(r'^api/farmers', views.FarmersJsonAPIView.as_view()), + url(r'^api/csv', views.FarmersCsvAPIView.as_view()), # r'^$' is used for regex of exact match as mentioned # url(r'^farmers-list', views.FarmerViewSet.as_view({'get': 'list'})), ] diff --git a/people/views.py b/people/views.py index e6c816607c..b5da25f952 100644 --- a/people/views.py +++ b/people/views.py @@ -39,15 +39,16 @@ class DefaultView(generics.ListCreateAPIView): # POST request def post(self, request, *args, **kwargs): # dictionary results as JSON format message - return Response({"message":"Welcome to COCO APIs", "base_url":"api/farmer", - "url_list":["api/farmer/farmers"]}) + return Response({"message":"Welcome to COCO APIs", "base_url":"/farmer/api", + "url_list":["/farmer/api/farmers", "/farmer/api/csv"]}) # GET request def get(self, request): return Response({"detail":"Method \"GET\" not allowed."}) -class FarmersList(generics.ListCreateAPIView): + +class FarmersJsonAPIView(generics.ListCreateAPIView): ''' coco_api class-based view to query Person model and provide JSON response. django-rest-framework based token passed in Header as {'Authorization': 'Token 12345exampleToken'} @@ -60,6 +61,7 @@ class FarmersList(generics.ListCreateAPIView): authentication_classes = [TokenAuthentication] permissions_classes =[IsAuthenticated] + # GET request def get(self, request): return Response({"detail":"Method \"GET\" not allowed"}) @@ -104,7 +106,7 @@ def post(self, request, *args, **kwargs): return Response(serializer.data) -class CSVView(APIView): +class FarmersCsvAPIView(APIView): ''' coco_api class-based view to query Person model and provide CSV response. django-rest-framework based token passed in Header as {'Authorization': 'Token 12345exampleToken'} diff --git a/programs/urls.py b/programs/urls.py index 4447660e8a..dfc63c2662 100644 --- a/programs/urls.py +++ b/programs/urls.py @@ -4,8 +4,8 @@ urlpatterns = [ - url('partner', PartnerAPIView.as_view()), - url('project', ProjectAPIView.as_view()), + url(r'^api/partner', PartnerAPIView.as_view()), + url(r'^api/project', ProjectAPIView.as_view()), ] diff --git a/videos/urls.py b/videos/urls.py index 1372205d55..7085ccc4f4 100644 --- a/videos/urls.py +++ b/videos/urls.py @@ -37,6 +37,6 @@ # coco_api video urls # as_view method takes type of request as key and class's method name as value - url('api/videos', views.VideoViewSet.as_view()), + url(r'^api/video', views.VideoAPIView.as_view()), ) diff --git a/videos/views.py b/videos/views.py index 842feeea6d..5359d3c35c 100644 --- a/videos/views.py +++ b/videos/views.py @@ -17,7 +17,7 @@ from rest_framework.permissions import IsAuthenticated -class VideoViewSet(generics.ListCreateAPIView): +class VideoAPIView(generics.ListCreateAPIView): ''' coco_api class-based view to query Videos model and provide JSON response. django-rest-framework based token passed in Header as {'Authorization': 'Token 12345exampleToken'} From b1950c9cfdf1d5130df7c00c9e5eb3daad91bc03 Mon Sep 17 00:00:00 2001 From: vermastuti Date: Wed, 20 May 2020 23:23:36 +0530 Subject: [PATCH 11/35] phone-no-farmers-filter --- people/views.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/people/views.py b/people/views.py index b5da25f952..d81754d960 100644 --- a/people/views.py +++ b/people/views.py @@ -47,7 +47,6 @@ def get(self, request): return Response({"detail":"Method \"GET\" not allowed."}) - class FarmersJsonAPIView(generics.ListCreateAPIView): ''' coco_api class-based view to query Person model and provide JSON response. @@ -70,7 +69,8 @@ def get(self, request): def post(self, request, *args, **kwargs): country_id = self.request.POST.get('country_id', 0) # POST param 'country_id', default value is 0 fields_values = request.POST.get('fields', '') # POST param 'fields', default value is empty string - + phoneNumberExists = request.POST.get('phoneNumberExists','') # POST param 'filter_phone_no', default value is empty string + try: # fetches country id from database model Country to verify param value got_country_id = Country.objects.get(id=country_id).id @@ -80,6 +80,9 @@ def post(self, request, *args, **kwargs): # in case of failure of above try statement, all Person objects are retrieved queryset = Person.objects.all().order_by('id') + if phoneNumberExists in ["true","t","yes","y"]: + queryset = queryset.filter(phone_no__isnull=False).exclude(phone_no__in=['']) + start_limit = request.POST.get('start_limit') # POST param 'start_limit' end_limit = request.POST.get('end_limit') # POST param 'end_limit' # limits the total response count From bded5340b07e08f227317d769a404918f382f011 Mon Sep 17 00:00:00 2001 From: vermastuti Date: Thu, 21 May 2020 13:25:14 +0530 Subject: [PATCH 12/35] dashboard-F_count --- people/serializers.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/people/serializers.py b/people/serializers.py index 7dac3871e0..67ea1bd6cb 100644 --- a/people/serializers.py +++ b/people/serializers.py @@ -41,11 +41,17 @@ class FarmerSerializer(DynamicFieldsModelSerializer): country_id = serializers.IntegerField(source='village.block.district.state.country.id', read_only=True) country_name = serializers.CharField(source='village.block.district.state.country.country_name', read_only=True) + F_count = serializers.SerializerMethodField() # added for visualization class Meta: model = Person fields = '__all__' + # returns 1 to indicate present of a Person object as a numeric field + def get_F_count(self, obj): + return 1 + + From 848893afc9824d4cba908455c1269607d801d4f6 Mon Sep 17 00:00:00 2001 From: vermastuti Date: Wed, 27 May 2020 16:23:07 +0530 Subject: [PATCH 13/35] match-people-phone-numbers-api --- people/urls.py | 2 +- people/views.py | 76 +++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 75 insertions(+), 3 deletions(-) diff --git a/people/urls.py b/people/urls.py index ac6484cb88..c30f512703 100644 --- a/people/urls.py +++ b/people/urls.py @@ -6,5 +6,5 @@ url(r'^api/default', views.DefaultView.as_view()), url(r'^api/farmers', views.FarmersJsonAPIView.as_view()), url(r'^api/csv', views.FarmersCsvAPIView.as_view()), # r'^$' is used for regex of exact match as mentioned - # url(r'^farmers-list', views.FarmerViewSet.as_view({'get': 'list'})), + url(r'^api/match/phone', views.FarmersMatchAPIView.as_view()), ] diff --git a/people/views.py b/people/views.py index d81754d960..d556c1944e 100644 --- a/people/views.py +++ b/people/views.py @@ -80,6 +80,7 @@ def post(self, request, *args, **kwargs): # in case of failure of above try statement, all Person objects are retrieved queryset = Person.objects.all().order_by('id') + # phone number exists or not if phoneNumberExists in ["true","t","yes","y"]: queryset = queryset.filter(phone_no__isnull=False).exclude(phone_no__in=['']) @@ -143,7 +144,13 @@ def post(self, request, *args, **kwargs): except: # in case of failure of above try statement, all Person objects are retrieved queryset = Person.objects.all().order_by('id') - + + phoneNumberExists = request.POST.get('phoneNumberExists','') # POST param 'filter_phone_no', default value is empty string + + # phone number exists or not + if phoneNumberExists in ["true","t","yes","y"]: + queryset = queryset.filter(phone_no__isnull=False).exclude(phone_no__in=['']) + start_limit = request.POST.get('start_limit') # POST param 'start_limit' end_limit = request.POST.get('end_limit') # POST param 'end_limit' # limits the total response count @@ -167,4 +174,69 @@ def post(self, request, *args, **kwargs): # if fields param is empty then all the fields as mentioned in serializer are served to the response serializer = FarmerSerializer(queryset, many=True) # CSV Response is provided - return Response(serializer.data) \ No newline at end of file + return Response(serializer.data) + + +class FarmersMatchAPIView(generics.ListCreateAPIView): + ''' + coco_api class-based view to query Person model and provide JSON response. + django-rest-framework based token passed in Header as {'Authorization': 'Token 12345exampleToken'} + is required to access data from this View. + Only POST method is allowed. + GET request sent will show a message : "Method \"GET\" not allowed." + ''' + + # django-rest-framework TokenAuthentication + authentication_classes = [TokenAuthentication] + permissions_classes =[IsAuthenticated] + + # GET request + def get(self, request): + return Response({"detail":"Method \"GET\" not allowed"}) + + # POST request + def post(self, request, *args, **kwargs): + queryset = Person.objects.all().order_by('id') + + fields_values = request.POST.get('fields', '') # POST param 'fields', default value is empty string + phone_numbers = request.POST.get('phoneNumbers', '') # POST param 'fields', default value is empty string + + phoneNumberExists = request.POST.get('phoneNumberExists','') # POST param 'filter_phone_no', default value is empty string + + # phone number exists or not + if phoneNumberExists in ["true","t","yes","y"]: + queryset = queryset.filter(phone_no__isnull=False).exclude(phone_no__in=['']) + + + # phone number matches + if phone_numbers: + ph_no_values = [ph.strip() for ph in phone_numbers.split(",")] + queryset = queryset.filter(phone_no__in=ph_no_values) + + count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" + # returns count only if param value matched + if count.lower() in ["true","t","yes","y"]: + return Response({"count": queryset.count()}) + + + start_limit = request.POST.get('start_limit') # POST param 'start_limit' + end_limit = request.POST.get('end_limit') # POST param 'end_limit' + # limits the total response count + if start_limit and end_limit: # case1: both are present + queryset = queryset[int(start_limit)-1:int(end_limit)] + elif start_limit: # case2: only start_limit is present + queryset = queryset[int(start_limit)-1:] + elif end_limit: # case3: only end_limit is present + queryset = queryset[:int(end_limit)] + + if fields_values: # fields provided in POST request and if not empty serves those fields only + fields_values = [val.strip() for val in fields_values.split(",")] + # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer + serializer = FarmerSerializer(queryset, fields=fields_values, many=True) + else: + # if fields param is empty then all the fields as mentioned in serializer are served to the response + serializer = FarmerSerializer(queryset, many=True) + # CSV Response is provided + return Response(serializer.data) + + From 8e83408009ab4a2bb6d0c8dc2d990add986bedf9 Mon Sep 17 00:00:00 2001 From: vermastuti Date: Thu, 28 May 2020 10:10:16 +0530 Subject: [PATCH 14/35] people-post-requests-merged --- people/urls.py | 6 ++++-- people/views.py | 54 ++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/people/urls.py b/people/urls.py index c30f512703..32ca9dd99a 100644 --- a/people/urls.py +++ b/people/urls.py @@ -4,7 +4,9 @@ urlpatterns=[ url(r'^api/default', views.DefaultView.as_view()), - url(r'^api/farmers', views.FarmersJsonAPIView.as_view()), + # url(r'^api/farmers', views.FarmersJsonAPIView.as_view()), + url(r'^api/farmers', views.FarmersJsonAPIView.as_view({'post':'getAllFarmers'})), + url(r'^api/match/phone', views.FarmersJsonAPIView.as_view({'post':'getPhoneMatchedResults'})), url(r'^api/csv', views.FarmersCsvAPIView.as_view()), # r'^$' is used for regex of exact match as mentioned - url(r'^api/match/phone', views.FarmersMatchAPIView.as_view()), + # url(r'^api/match/phone', views.FarmersMatchAPIView.as_view()), ] diff --git a/people/views.py b/people/views.py index d556c1944e..04f5a13045 100644 --- a/people/views.py +++ b/people/views.py @@ -23,6 +23,7 @@ from rest_framework.settings import api_settings from rest_framework_csv import renderers as r + class DefaultView(generics.ListCreateAPIView): ''' coco_api class-based view to provide default message in JSON format. @@ -47,7 +48,7 @@ def get(self, request): return Response({"detail":"Method \"GET\" not allowed."}) -class FarmersJsonAPIView(generics.ListCreateAPIView): +class FarmersJsonAPIView(viewsets.GenericViewSet): #(generics.ListCreateAPIView): ''' coco_api class-based view to query Person model and provide JSON response. django-rest-framework based token passed in Header as {'Authorization': 'Token 12345exampleToken'} @@ -66,7 +67,7 @@ def get(self, request): return Response({"detail":"Method \"GET\" not allowed"}) # POST request - def post(self, request, *args, **kwargs): + def getAllFarmers(self, request, *args, **kwargs): country_id = self.request.POST.get('country_id', 0) # POST param 'country_id', default value is 0 fields_values = request.POST.get('fields', '') # POST param 'fields', default value is empty string phoneNumberExists = request.POST.get('phoneNumberExists','') # POST param 'filter_phone_no', default value is empty string @@ -109,6 +110,51 @@ def post(self, request, *args, **kwargs): # JSON Response is provided by default return Response(serializer.data) + # POST request + def getPhoneMatchedResults(self, request, *args, **kwargs): + queryset = Person.objects.all().order_by('id') + + fields_values = request.POST.get('fields', '') # POST param 'fields', default value is empty string + phone_numbers = request.POST.get('phoneNumbers', '') # POST param 'fields', default value is empty string + + phoneNumberExists = request.POST.get('phoneNumberExists','') # POST param 'filter_phone_no', default value is empty string + + # phone number exists or not + if phoneNumberExists in ["true","t","yes","y"]: + queryset = queryset.filter(phone_no__isnull=False).exclude(phone_no__in=['']) + + + # phone number matches + if phone_numbers: + ph_no_values = [ph.strip() for ph in phone_numbers.split(",")] + queryset = queryset.filter(phone_no__in=ph_no_values) + + count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" + # returns count only if param value matched + if count.lower() in ["true","t","yes","y"]: + return Response({"count": queryset.count()}) + + + start_limit = request.POST.get('start_limit') # POST param 'start_limit' + end_limit = request.POST.get('end_limit') # POST param 'end_limit' + # limits the total response count + if start_limit and end_limit: # case1: both are present + queryset = queryset[int(start_limit)-1:int(end_limit)] + elif start_limit: # case2: only start_limit is present + queryset = queryset[int(start_limit)-1:] + elif end_limit: # case3: only end_limit is present + queryset = queryset[:int(end_limit)] + + if fields_values: # fields provided in POST request and if not empty serves those fields only + fields_values = [val.strip() for val in fields_values.split(",")] + # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer + serializer = FarmerSerializer(queryset, fields=fields_values, many=True) + else: + # if fields param is empty then all the fields as mentioned in serializer are served to the response + serializer = FarmerSerializer(queryset, many=True) + # CSV Response is provided + return Response(serializer.data) + class FarmersCsvAPIView(APIView): ''' @@ -237,6 +283,4 @@ def post(self, request, *args, **kwargs): # if fields param is empty then all the fields as mentioned in serializer are served to the response serializer = FarmerSerializer(queryset, many=True) # CSV Response is provided - return Response(serializer.data) - - + return Response(serializer.data) \ No newline at end of file From db84ff072debfbd3726eafbc5ee4a83390daf40c Mon Sep 17 00:00:00 2001 From: vermastuti Date: Thu, 28 May 2020 12:03:26 +0530 Subject: [PATCH 15/35] limit-queryset-function --- people/views.py | 117 +++++++++++++----------------------------------- 1 file changed, 32 insertions(+), 85 deletions(-) diff --git a/people/views.py b/people/views.py index 04f5a13045..524e623e9b 100644 --- a/people/views.py +++ b/people/views.py @@ -61,6 +61,18 @@ class FarmersJsonAPIView(viewsets.GenericViewSet): #(generics.ListCreateAPIView) authentication_classes = [TokenAuthentication] permissions_classes =[IsAuthenticated] + def limitQueryset(self, queryset, start_limit, end_limit): + # limits the total response count + if start_limit and end_limit: # case1: both are present + queryset = queryset[int(start_limit)-1:int(end_limit)] + elif start_limit: # case2: only start_limit is present + queryset = queryset[int(start_limit)-1:] + elif end_limit: # case3: only end_limit is present + queryset = queryset[:int(end_limit)] + + return queryset + + # GET request def get(self, request): @@ -87,13 +99,9 @@ def getAllFarmers(self, request, *args, **kwargs): start_limit = request.POST.get('start_limit') # POST param 'start_limit' end_limit = request.POST.get('end_limit') # POST param 'end_limit' - # limits the total response count - if start_limit and end_limit: # case1: both are present - queryset = queryset[int(start_limit)-1:int(end_limit)] - elif start_limit: # case2: only start_limit is present - queryset = queryset[int(start_limit)-1:] - elif end_limit: # case3: only end_limit is present - queryset = queryset[:int(end_limit)] + + queryset = self.limitQueryset(queryset, start_limit, end_limit) + count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" # returns count only if param value matched @@ -136,14 +144,10 @@ def getPhoneMatchedResults(self, request, *args, **kwargs): start_limit = request.POST.get('start_limit') # POST param 'start_limit' - end_limit = request.POST.get('end_limit') # POST param 'end_limit' - # limits the total response count - if start_limit and end_limit: # case1: both are present - queryset = queryset[int(start_limit)-1:int(end_limit)] - elif start_limit: # case2: only start_limit is present - queryset = queryset[int(start_limit)-1:] - elif end_limit: # case3: only end_limit is present - queryset = queryset[:int(end_limit)] + end_limit = request.POST.get('end_limit') # POST param 'end_limit' + + queryset = self.limitQueryset(queryset, start_limit, end_limit) + if fields_values: # fields provided in POST request and if not empty serves those fields only fields_values = [val.strip() for val in fields_values.split(",")] @@ -172,6 +176,17 @@ class FarmersCsvAPIView(APIView): authentication_classes = [TokenAuthentication] permissions_classes =[IsAuthenticated] + def limitQueryset(self, queryset, start_limit, end_limit): + # limits the total response count + if start_limit and end_limit: # case1: both are present + queryset = queryset[int(start_limit)-1:int(end_limit)] + elif start_limit: # case2: only start_limit is present + queryset = queryset[int(start_limit)-1:] + elif end_limit: # case3: only end_limit is present + queryset = queryset[:int(end_limit)] + + return queryset + # GET request def get(self, request): return Response({"detail":"Method \"GET\" not allowed"}) @@ -199,82 +214,14 @@ def post(self, request, *args, **kwargs): start_limit = request.POST.get('start_limit') # POST param 'start_limit' end_limit = request.POST.get('end_limit') # POST param 'end_limit' - # limits the total response count - if start_limit and end_limit: # case1: both are present - queryset = queryset[int(start_limit)-1:int(end_limit)] - elif start_limit: # case2: only start_limit is present - queryset = queryset[int(start_limit)-1:] - elif end_limit: # case3: only end_limit is present - queryset = queryset[:int(end_limit)] + queryset = self.limitQueryset(queryset, start_limit, end_limit) - count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" - # returns count only if param value matched - if count.lower() in ["true","t","yes","y"]: - return Response({"count": queryset.count()}) - - if fields_values: # fields provided in POST request and if not empty serves those fields only - fields_values = [val.strip() for val in fields_values.split(",")] - # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer - serializer = FarmerSerializer(queryset, fields=fields_values, many=True) - else: - # if fields param is empty then all the fields as mentioned in serializer are served to the response - serializer = FarmerSerializer(queryset, many=True) - # CSV Response is provided - return Response(serializer.data) - - -class FarmersMatchAPIView(generics.ListCreateAPIView): - ''' - coco_api class-based view to query Person model and provide JSON response. - django-rest-framework based token passed in Header as {'Authorization': 'Token 12345exampleToken'} - is required to access data from this View. - Only POST method is allowed. - GET request sent will show a message : "Method \"GET\" not allowed." - ''' - - # django-rest-framework TokenAuthentication - authentication_classes = [TokenAuthentication] - permissions_classes =[IsAuthenticated] - - # GET request - def get(self, request): - return Response({"detail":"Method \"GET\" not allowed"}) - - # POST request - def post(self, request, *args, **kwargs): - queryset = Person.objects.all().order_by('id') - - fields_values = request.POST.get('fields', '') # POST param 'fields', default value is empty string - phone_numbers = request.POST.get('phoneNumbers', '') # POST param 'fields', default value is empty string - - phoneNumberExists = request.POST.get('phoneNumberExists','') # POST param 'filter_phone_no', default value is empty string - - # phone number exists or not - if phoneNumberExists in ["true","t","yes","y"]: - queryset = queryset.filter(phone_no__isnull=False).exclude(phone_no__in=['']) - - - # phone number matches - if phone_numbers: - ph_no_values = [ph.strip() for ph in phone_numbers.split(",")] - queryset = queryset.filter(phone_no__in=ph_no_values) count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" # returns count only if param value matched if count.lower() in ["true","t","yes","y"]: return Response({"count": queryset.count()}) - - - start_limit = request.POST.get('start_limit') # POST param 'start_limit' - end_limit = request.POST.get('end_limit') # POST param 'end_limit' - # limits the total response count - if start_limit and end_limit: # case1: both are present - queryset = queryset[int(start_limit)-1:int(end_limit)] - elif start_limit: # case2: only start_limit is present - queryset = queryset[int(start_limit)-1:] - elif end_limit: # case3: only end_limit is present - queryset = queryset[:int(end_limit)] - + if fields_values: # fields provided in POST request and if not empty serves those fields only fields_values = [val.strip() for val in fields_values.split(",")] # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer From 52d242bc0be07a8753f90c3eeb6f6a2706bcfa3a Mon Sep 17 00:00:00 2001 From: vermastuti Date: Thu, 28 May 2020 12:35:08 +0530 Subject: [PATCH 16/35] coco_api_utils --- coco_api_utils.py | 14 ++++++++++++++ people/views.py | 38 +++++++++----------------------------- 2 files changed, 23 insertions(+), 29 deletions(-) create mode 100644 coco_api_utils.py diff --git a/coco_api_utils.py b/coco_api_utils.py new file mode 100644 index 0000000000..8d9f977463 --- /dev/null +++ b/coco_api_utils.py @@ -0,0 +1,14 @@ + +class Utils: + + def limitQueryset(self, queryset, start_limit, end_limit): + # limits the total response count + if start_limit and end_limit: # case1: both are present + queryset = queryset[int(start_limit)-1:int(end_limit)] + elif start_limit: # case2: only start_limit is present + queryset = queryset[int(start_limit)-1:] + elif end_limit: # case3: only end_limit is present + queryset = queryset[:int(end_limit)] + + return queryset + diff --git a/people/views.py b/people/views.py index 524e623e9b..b1ead4d208 100644 --- a/people/views.py +++ b/people/views.py @@ -23,6 +23,8 @@ from rest_framework.settings import api_settings from rest_framework_csv import renderers as r +from coco_api_utils import Utils + class DefaultView(generics.ListCreateAPIView): ''' @@ -61,18 +63,6 @@ class FarmersJsonAPIView(viewsets.GenericViewSet): #(generics.ListCreateAPIView) authentication_classes = [TokenAuthentication] permissions_classes =[IsAuthenticated] - def limitQueryset(self, queryset, start_limit, end_limit): - # limits the total response count - if start_limit and end_limit: # case1: both are present - queryset = queryset[int(start_limit)-1:int(end_limit)] - elif start_limit: # case2: only start_limit is present - queryset = queryset[int(start_limit)-1:] - elif end_limit: # case3: only end_limit is present - queryset = queryset[:int(end_limit)] - - return queryset - - # GET request def get(self, request): @@ -100,8 +90,8 @@ def getAllFarmers(self, request, *args, **kwargs): start_limit = request.POST.get('start_limit') # POST param 'start_limit' end_limit = request.POST.get('end_limit') # POST param 'end_limit' - queryset = self.limitQueryset(queryset, start_limit, end_limit) - + utils = Utils() + queryset = utils.limitQueryset(queryset=queryset, start_limit=start_limit, end_limit=end_limit) count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" # returns count only if param value matched @@ -145,8 +135,8 @@ def getPhoneMatchedResults(self, request, *args, **kwargs): start_limit = request.POST.get('start_limit') # POST param 'start_limit' end_limit = request.POST.get('end_limit') # POST param 'end_limit' - - queryset = self.limitQueryset(queryset, start_limit, end_limit) + utils = Utils() + queryset = utils.limitQueryset(queryset=queryset, start_limit=start_limit, end_limit=end_limit) if fields_values: # fields provided in POST request and if not empty serves those fields only @@ -156,7 +146,7 @@ def getPhoneMatchedResults(self, request, *args, **kwargs): else: # if fields param is empty then all the fields as mentioned in serializer are served to the response serializer = FarmerSerializer(queryset, many=True) - # CSV Response is provided + # JSON Response is provided return Response(serializer.data) @@ -176,17 +166,6 @@ class FarmersCsvAPIView(APIView): authentication_classes = [TokenAuthentication] permissions_classes =[IsAuthenticated] - def limitQueryset(self, queryset, start_limit, end_limit): - # limits the total response count - if start_limit and end_limit: # case1: both are present - queryset = queryset[int(start_limit)-1:int(end_limit)] - elif start_limit: # case2: only start_limit is present - queryset = queryset[int(start_limit)-1:] - elif end_limit: # case3: only end_limit is present - queryset = queryset[:int(end_limit)] - - return queryset - # GET request def get(self, request): return Response({"detail":"Method \"GET\" not allowed"}) @@ -214,8 +193,9 @@ def post(self, request, *args, **kwargs): start_limit = request.POST.get('start_limit') # POST param 'start_limit' end_limit = request.POST.get('end_limit') # POST param 'end_limit' - queryset = self.limitQueryset(queryset, start_limit, end_limit) + utils = Utils() + queryset = utils.limitQueryset(queryset=queryset, start_limit=start_limit, end_limit=end_limit) count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" # returns count only if param value matched From fec3889b652f0c398f1d1acc7af402314ca36154 Mon Sep 17 00:00:00 2001 From: vermastuti Date: Mon, 1 Jun 2020 10:06:32 +0530 Subject: [PATCH 17/35] logging-changes --- activities/views.py | 7 +++ dg/base_settings.py | 112 +++++++++++++++++++++++-------------------- geographies/views.py | 23 +++++++-- people/views.py | 13 ++++- programs/views.py | 13 ++++- videos/views.py | 8 +++- 6 files changed, 117 insertions(+), 59 deletions(-) diff --git a/activities/views.py b/activities/views.py index c4a32866ae..4bdb938f63 100644 --- a/activities/views.py +++ b/activities/views.py @@ -18,6 +18,10 @@ from rest_framework.authentication import SessionAuthentication, BasicAuthentication, TokenAuthentication from rest_framework.permissions import IsAuthenticated +from django.contrib.auth.models import User + +import logging +logger = logging.getLogger('coco_api') class ScreeningAPIView( generics.ListCreateAPIView): ''' @@ -38,6 +42,9 @@ def get(self, request): # POST request def post(self, request, *args, **kwargs): + user_obj = User.objects.get(username=request.user) + logger.info("accessed: %s.ScreeningAPIView.post, user: %s" % ( __name__,user_obj)) + queryset = Screening.objects.get_queryset().order_by('id') uc_id = request.POST.get('user_created') # POST param 'user_created', default value is empty string diff --git a/dg/base_settings.py b/dg/base_settings.py index bd5f9ea3d7..0267bf9225 100644 --- a/dg/base_settings.py +++ b/dg/base_settings.py @@ -215,58 +215,68 @@ 'social.backends.google.GoogleOAuth2', ) -# LOGGING = { -# 'version': 1, -# 'disable_existing_loggers': True, -# 'formatters': { -# 'standard': { -# 'format' : "[%(levelname)s] [%(asctime)s] [%(name)s] %(message)s", -# 'datefmt' : "%d/%b/%Y %H:%M:%S" -# }, -# }, -# 'handlers': { -# 'null': { -# 'level':'DEBUG', -# 'class':'django.utils.log.NullHandler', -# }, -# 'logfile': { -# 'level':'DEBUG', -# 'class':'logging.handlers.RotatingFileHandler', -# 'filename': os.path.join(PROJECT_PATH, 'media/social_website/uploads/log/logfile'), -# 'formatter': 'standard', -# }, -# 'ap_migration_log': { -# 'level': 'INFO', -# 'class':'logging.handlers.RotatingFileHandler', -# 'filename': os.path.join(PROJECT_PATH, '../geographies/management/commands/log/ap_migration_log'), -# 'formatter': 'standard', -# }, -# 'console':{ -# 'level':'INFO', -# 'class':'logging.StreamHandler', -# 'formatter': 'standard' -# }, +LOGGING = { + 'version': 1, + 'disable_existing_loggers': True, + 'formatters': { + 'standard': { + 'format' : "[%(levelname)s] [%(asctime)s] [%(name)s] %(message)s", + 'datefmt' : "%d/%b/%Y %H:%M:%S" + }, + }, + 'handlers': { + 'null': { + 'level':'DEBUG', + 'class':'django.utils.log.NullHandler', + }, + 'logfile': { + 'level':'DEBUG', + 'class':'logging.handlers.RotatingFileHandler', + 'filename': os.path.join(PROJECT_PATH, 'media/social_website/uploads/log/logfile'), + 'formatter': 'standard', + }, + 'ap_migration_log': { + 'level': 'INFO', + 'class':'logging.handlers.RotatingFileHandler', + 'filename': os.path.join(PROJECT_PATH, '../geographies/management/commands/log/ap_migration_log'), + 'formatter': 'standard', + }, + 'console':{ + 'level':'INFO', + 'class':'logging.StreamHandler', + 'formatter': 'standard' + }, + 'api_access_log': { + 'level':'DEBUG', + 'class':'logging.handlers.RotatingFileHandler', + 'filename': os.path.join(PROJECT_PATH, '../coco_api/log/logfile'), + 'formatter': 'standard', + }, -# }, -# 'loggers': { -# 'social_website': { -# 'handlers': ['logfile'], -# 'level': 'DEBUG', -# }, -# 'dashboard': { -# 'handlers': ['logfile'], -# 'level': 'DEBUG', -# }, -# 'loop_ivr': { -# 'handlers': ['logfile'], -# 'level': 'DEBUG', -# }, -# 'geographies': { -# 'handlers': ['ap_migration_log'], -# 'level' : 'INFO', -# } -# } -# } + }, + 'loggers': { + 'social_website': { + 'handlers': ['logfile'], + 'level': 'DEBUG', + }, + 'dashboard': { + 'handlers': ['logfile'], + 'level': 'DEBUG', + }, + 'loop_ivr': { + 'handlers': ['logfile'], + 'level': 'DEBUG', + }, + 'geographies': { + 'handlers': ['ap_migration_log'], + 'level' : 'INFO', + }, + 'coco_api':{ + 'handlers': ['api_access_log'], + 'level': 'INFO', + } + } +} PRODUCT_PAGE = ('%s%s')%(WEBSITE_DOMAIN, 'solutions/') LOOP_PAGE = ('%s%s')%(WEBSITE_DOMAIN, 'loop/') diff --git a/geographies/views.py b/geographies/views.py index dad1652988..08b8fca10c 100644 --- a/geographies/views.py +++ b/geographies/views.py @@ -17,6 +17,11 @@ from rest_framework.authentication import SessionAuthentication, BasicAuthentication, TokenAuthentication from rest_framework.permissions import IsAuthenticated +from django.contrib.auth.models import User + +import logging +logger = logging.getLogger('coco_api') + class DefaultView(generics.ListAPIView): ''' coco_api class-based view to provide default message in JSON format. @@ -63,6 +68,8 @@ def get(self, request): # POST request def post(self, request, *args, **kwargs): + user_obj = User.objects.get(username=request.user) + logger.info("accessed: %s.VillageAPIView.post, user: %s" % ( __name__,user_obj)) queryset = Village.objects.get_queryset().order_by('id') # basic query to be filtered later in this method @@ -113,7 +120,9 @@ def get(self, request): # POST request def post(self, request, *args, **kwargs): - + user_obj = User.objects.get(username=request.user) + logger.info("accessed: %s.BlockAPIView.post, user: %s" % ( __name__,user_obj)) + queryset = Block.objects.get_queryset().order_by('id') # basic query to be filtered later in this method fields_values = request.POST.get('fields', '') # POST param 'limit', no default value specified so empty string is default value @@ -162,7 +171,9 @@ def get(self, request): # POST request def post(self, request, *args, **kwargs): - + user_obj = User.objects.get(username=request.user) + logger.info("accessed: %s.DistrictAPIView.post, user: %s" % ( __name__,user_obj)) + queryset = District.objects.get_queryset().order_by('id') # basic query to be filtered later in this method fields_values = request.POST.get('fields', '') # POST param 'limit', no default value specified so empty string is default value @@ -211,7 +222,9 @@ def get(self, request): # POST request def post(self, request, *args, **kwargs): - + user_obj = User.objects.get(username=request.user) + logger.info("accessed: %s.StateAPIView.post, user: %s" % ( __name__,user_obj)) + queryset = State.objects.get_queryset().order_by('id') # basic query to be filtered later in this method fields_values = request.POST.get('fields', '') # POST param 'limit', no default value specified so empty string is default value @@ -260,7 +273,9 @@ def get(self, request): # POST request def post(self, request, *args, **kwargs): - + user_obj = User.objects.get(username=request.user) + logger.info("accessed: %s.CountryAPIView.post, user: %s" % ( __name__,user_obj)) + queryset = Country.objects.get_queryset().order_by('id') # basic query to be filtered later in this method fields_values = request.POST.get('fields', '') # POST param 'limit', no default value specified so empty string is default value diff --git a/people/views.py b/people/views.py index b1ead4d208..eb47165e87 100644 --- a/people/views.py +++ b/people/views.py @@ -25,6 +25,10 @@ from coco_api_utils import Utils +from django.contrib.auth.models import User + +import logging +logger = logging.getLogger('coco_api') class DefaultView(generics.ListCreateAPIView): ''' @@ -70,6 +74,9 @@ def get(self, request): # POST request def getAllFarmers(self, request, *args, **kwargs): + user_obj = User.objects.get(username=request.user) + logger.info("accessed: %s.getAllFarmers, user: %s" % ( __name__,user_obj)) + country_id = self.request.POST.get('country_id', 0) # POST param 'country_id', default value is 0 fields_values = request.POST.get('fields', '') # POST param 'fields', default value is empty string phoneNumberExists = request.POST.get('phoneNumberExists','') # POST param 'filter_phone_no', default value is empty string @@ -110,6 +117,9 @@ def getAllFarmers(self, request, *args, **kwargs): # POST request def getPhoneMatchedResults(self, request, *args, **kwargs): + user_obj = User.objects.get(username=request.user) + logger.info("accessed: %s.getPhoneMatchedResults, user: %s" % ( __name__,user_obj)) + queryset = Person.objects.all().order_by('id') fields_values = request.POST.get('fields', '') # POST param 'fields', default value is empty string @@ -172,7 +182,8 @@ def get(self, request): # POST request def post(self, request, *args, **kwargs): - + user_obj = User.objects.get(username=request.user) + logger.info("accessed: %s.FarmersCsvAPIView.post, user: %s" % (__name__,user_obj)) country_id = self.request.POST.get('country_id', 0) # POST param 'country_id', default value is 0 fields_values = request.POST.get('fields', '') # POST param 'fields', default value is empty string diff --git a/programs/views.py b/programs/views.py index 5d99649a15..e3ab561e6d 100644 --- a/programs/views.py +++ b/programs/views.py @@ -13,6 +13,11 @@ from rest_framework.authentication import TokenAuthentication from rest_framework.permissions import IsAuthenticated +from django.contrib.auth.models import User + +import logging +logger = logging.getLogger('coco_api') + class PartnerAPIView(generics.ListCreateAPIView): ''' coco_api class-based view to query Partner model and provide JSON response. @@ -32,7 +37,9 @@ def get(self, request): # POST request def post(self, request, *args, **kwargs): - + user_obj = User.objects.get(username=request.user) + logger.info("accessed: %s.PartnerAPIView.post, user: %s" % ( __name__,user_obj)) + start_limit = request.POST.get('start_limit') # POST param 'start_limit' end_limit = request.POST.get('end_limit') # POST param 'end_limit' fields_values = request.POST.get('fields', '') # POST param 'fields' @@ -89,7 +96,9 @@ def get(self, request): # POST request def post(self, request, *args, **kwargs): - + user_obj = User.objects.get(username=request.user) + logger.info("accessed: %s.ProjectAPIView.post, user: %s" % ( __name__,user_obj)) + start_limit = request.POST.get('start_limit') # POST param 'start_limit' end_limit = request.POST.get('end_limit') # POST param 'end_limit' fields_values = request.POST.get('fields', '') # POST param 'fields' diff --git a/videos/views.py b/videos/views.py index 5359d3c35c..c46290384d 100644 --- a/videos/views.py +++ b/videos/views.py @@ -16,6 +16,10 @@ from rest_framework.authentication import SessionAuthentication, BasicAuthentication, TokenAuthentication from rest_framework.permissions import IsAuthenticated +from django.contrib.auth.models import User + +import logging +logger = logging.getLogger('coco_api') class VideoAPIView(generics.ListCreateAPIView): ''' @@ -36,7 +40,9 @@ def get(self, request): # POST request def post(self, request, *args, **kwargs): - + user_obj = User.objects.get(username=request.user) + logger.info("accessed: %s.VideoAPIView.post, user: %s" % ( __name__,user_obj)) + start_limit = request.POST.get('start_limit') # POST param 'start_limit' end_limit = request.POST.get('end_limit') # POST param 'end_limit' fields_values = request.POST.get('fields', '') # POST param 'fields' From 313009aa5aa7de79d03502c17df2499880650f32 Mon Sep 17 00:00:00 2001 From: vermastuti Date: Tue, 2 Jun 2020 02:04:58 +0530 Subject: [PATCH 18/35] logging-with-utils --- activities/views.py | 32 ++++++-------- coco_api_utils.py | 18 ++++++++ geographies/views.py | 100 ++++++++++++++++++++++--------------------- people/views.py | 38 ++++++++++------ programs/views.py | 44 +++++++++---------- videos/views.py | 23 +++++----- 6 files changed, 140 insertions(+), 115 deletions(-) diff --git a/activities/views.py b/activities/views.py index 4bdb938f63..dbdb961683 100644 --- a/activities/views.py +++ b/activities/views.py @@ -18,10 +18,8 @@ from rest_framework.authentication import SessionAuthentication, BasicAuthentication, TokenAuthentication from rest_framework.permissions import IsAuthenticated -from django.contrib.auth.models import User - -import logging -logger = logging.getLogger('coco_api') +import time +from coco_api_utils import Utils class ScreeningAPIView( generics.ListCreateAPIView): ''' @@ -42,9 +40,9 @@ def get(self, request): # POST request def post(self, request, *args, **kwargs): - user_obj = User.objects.get(username=request.user) - logger.info("accessed: %s.ScreeningAPIView.post, user: %s" % ( __name__,user_obj)) - + start_time = time.time() + utils = Utils() + queryset = Screening.objects.get_queryset().order_by('id') uc_id = request.POST.get('user_created') # POST param 'user_created', default value is empty string @@ -54,7 +52,7 @@ def post(self, request, *args, **kwargs): start_day = request.POST.get('start_day') start_month = request.POST.get('start_month') start_year = request.POST.get('start_year') - end_day = request.POST.get('end_day') + end_day = request.POST.get('1end_day') end_month = request.POST.get('end_month') end_year = request.POST.get('end_year') @@ -86,12 +84,7 @@ def post(self, request, *args, **kwargs): end_limit = request.POST.get('end_limit') # POST param 'end_limit' # limits the total response count - if start_limit and end_limit: # case1: both are present - queryset = queryset[int(start_limit)-1:int(end_limit)] - elif start_limit: # case2: only start_limit is present - queryset = queryset[int(start_limit)-1:] - elif end_limit: # case3: only end_limit is present - queryset = queryset[:int(end_limit)] + queryset = utils.limitQueryset(queryset=queryset, start_limit=start_limit, end_limit=end_limit) count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" # returns count only if param value matched @@ -107,10 +100,9 @@ def post(self, request, *args, **kwargs): # if fields param is empty then all the fields as mentioned in serializer are served to the response serializer = ScreeningSerializer(queryset, many=True) - # context = RequestContext(request) - # context_dict = {} - # # Update the dictionary with csrf_token - # conext_dict.update(csrf(request)) - + response = Response(serializer.data) + processing_time = time.time() - start_time + utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) + # JSON Response is provided by default - return Response(serializer.data) #, context_dict, context) \ No newline at end of file + return response \ No newline at end of file diff --git a/coco_api_utils.py b/coco_api_utils.py index 8d9f977463..aeae87cd54 100644 --- a/coco_api_utils.py +++ b/coco_api_utils.py @@ -1,3 +1,9 @@ +from django.contrib.auth.models import User +from django.utils import importlib +import time +import logging + + class Utils: @@ -12,3 +18,15 @@ def limitQueryset(self, queryset, start_limit, end_limit): return queryset + + + def logRequest(self, request, class_instance, view_fun, processing_time, status_code ): + logger = logging.getLogger('coco_api') + user_obj = User.objects.get(username=request.user) + ip_addr = request.META['REMOTE_ADDR'] + method = request.method + user_id = user_obj.id + class_name = class_instance.__class__.__name__ + module_name = class_instance.__module__ + # method_name = fun. + logger.info("accessed: %s.%s.%s, user_id: %s, username: %s, ip_address: %s, method: %s, processing_time: %s seconds, status_code: %s" % ( module_name, class_name, view_fun, user_id, user_obj, ip_addr, method, processing_time, status_code)) \ No newline at end of file diff --git a/geographies/views.py b/geographies/views.py index 08b8fca10c..7e0e38f9b9 100644 --- a/geographies/views.py +++ b/geographies/views.py @@ -18,9 +18,8 @@ from rest_framework.permissions import IsAuthenticated from django.contrib.auth.models import User - -import logging -logger = logging.getLogger('coco_api') +from coco_api_utils import Utils +import time class DefaultView(generics.ListAPIView): ''' @@ -68,8 +67,8 @@ def get(self, request): # POST request def post(self, request, *args, **kwargs): - user_obj = User.objects.get(username=request.user) - logger.info("accessed: %s.VillageAPIView.post, user: %s" % ( __name__,user_obj)) + start_time = time.time() + utils = Utils() queryset = Village.objects.get_queryset().order_by('id') # basic query to be filtered later in this method @@ -78,12 +77,8 @@ def post(self, request, *args, **kwargs): end_limit = request.POST.get('end_limit') # POST param 'end_limit' # limits the total response count - if start_limit and end_limit: # case1: both are present - queryset = queryset[int(start_limit)-1:int(end_limit)] - elif start_limit: # case2: only start_limit is present - queryset = queryset[int(start_limit)-1:] - elif end_limit: # case3: only end_limit is present - queryset = queryset[:int(end_limit)] + queryset = utils.limitQueryset(queryset=queryset, start_limit=start_limit, end_limit=end_limit) + count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" # returns count only if param value matched @@ -97,8 +92,13 @@ def post(self, request, *args, **kwargs): else: # if fields param is empty then all the fields as mentioned in serializer are served to the response serializer = VillageSerializer(queryset, many=True) + + response = Response(serializer.data) + processing_time = time.time() - start_time + utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) + # JSON Response is provided by default - return Response(serializer.data) + return response class BlockAPIView(generics.ListAPIView): @@ -120,8 +120,8 @@ def get(self, request): # POST request def post(self, request, *args, **kwargs): - user_obj = User.objects.get(username=request.user) - logger.info("accessed: %s.BlockAPIView.post, user: %s" % ( __name__,user_obj)) + start_time = time.time() + utils = Utils() queryset = Block.objects.get_queryset().order_by('id') # basic query to be filtered later in this method @@ -130,12 +130,8 @@ def post(self, request, *args, **kwargs): end_limit = request.POST.get('end_limit') # POST param 'end_limit' # limits the total response count - if start_limit and end_limit: # case1: both are present - queryset = queryset[int(start_limit)-1:int(end_limit)] - elif start_limit: # case2: only start_limit is present - queryset = queryset[int(start_limit)-1:] - elif end_limit: # case3: only end_limit is present - queryset = queryset[:int(end_limit)] + queryset = utils.limitQueryset(queryset=queryset, start_limit=start_limit, end_limit=end_limit) + count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" # returns count only if param value matched @@ -149,8 +145,13 @@ def post(self, request, *args, **kwargs): else: # if fields param is empty then all the fields as mentioned in serializer are served to the response serializer = BlockSerializer(queryset, many=True) + + response = Response(serializer.data) + processing_time = time.time() - start_time + utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) + # JSON Response is provided by default - return Response(serializer.data) + return response class DistrictAPIView(generics.ListAPIView): ''' @@ -171,8 +172,8 @@ def get(self, request): # POST request def post(self, request, *args, **kwargs): - user_obj = User.objects.get(username=request.user) - logger.info("accessed: %s.DistrictAPIView.post, user: %s" % ( __name__,user_obj)) + start_time = time.time() + utils = Utils() queryset = District.objects.get_queryset().order_by('id') # basic query to be filtered later in this method @@ -181,12 +182,8 @@ def post(self, request, *args, **kwargs): end_limit = request.POST.get('end_limit') # POST param 'end_limit' # limits the total response count - if start_limit and end_limit: # case1: both are present - queryset = queryset[int(start_limit)-1:int(end_limit)] - elif start_limit: # case2: only start_limit is present - queryset = queryset[int(start_limit)-1:] - elif end_limit: # case3: only end_limit is present - queryset = queryset[:int(end_limit)] + queryset = utils.limitQueryset(queryset=queryset, start_limit=start_limit, end_limit=end_limit) + count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" # returns count only if param value matched @@ -200,8 +197,13 @@ def post(self, request, *args, **kwargs): else: # if fields param is empty then all the fields as mentioned in serializer are served to the response serializer = DistrictSerializer(queryset, many=True) + + response = Response(serializer.data) + processing_time = time.time() - start_time + utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) + # JSON Response is provided by default - return Response(serializer.data) + return response class StateAPIView(generics.ListAPIView): ''' @@ -222,8 +224,8 @@ def get(self, request): # POST request def post(self, request, *args, **kwargs): - user_obj = User.objects.get(username=request.user) - logger.info("accessed: %s.StateAPIView.post, user: %s" % ( __name__,user_obj)) + start_time = time.time() + utils = Utils() queryset = State.objects.get_queryset().order_by('id') # basic query to be filtered later in this method @@ -232,12 +234,8 @@ def post(self, request, *args, **kwargs): end_limit = request.POST.get('end_limit') # POST param 'end_limit' # limits the total response count - if start_limit and end_limit: # case1: both are present - queryset = queryset[int(start_limit)-1:int(end_limit)] - elif start_limit: # case2: only start_limit is present - queryset = queryset[int(start_limit)-1:] - elif end_limit: # case3: only end_limit is present - queryset = queryset[:int(end_limit)] + queryset = utils.limitQueryset(queryset=queryset, start_limit=start_limit, end_limit=end_limit) + count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" # returns count only if param value matched @@ -251,8 +249,13 @@ def post(self, request, *args, **kwargs): else: # if fields param is empty then all the fields as mentioned in serializer are served to the response serializer = StateSerializer(queryset, many=True) + + response = Response(serializer.data) + processing_time = time.time() - start_time + utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) + # JSON Response is provided by default - return Response(serializer.data) + return response class CountryAPIView(generics.ListAPIView): ''' @@ -273,8 +276,8 @@ def get(self, request): # POST request def post(self, request, *args, **kwargs): - user_obj = User.objects.get(username=request.user) - logger.info("accessed: %s.CountryAPIView.post, user: %s" % ( __name__,user_obj)) + start_time = time.time() + utils = Utils() queryset = Country.objects.get_queryset().order_by('id') # basic query to be filtered later in this method @@ -283,12 +286,8 @@ def post(self, request, *args, **kwargs): end_limit = request.POST.get('end_limit') # POST param 'end_limit' # limits the total response count - if start_limit and end_limit: # case1: both are present - queryset = queryset[int(start_limit)-1:int(end_limit)] - elif start_limit: # case2: only start_limit is present - queryset = queryset[int(start_limit)-1:] - elif end_limit: # case3: only end_limit is present - queryset = queryset[:int(end_limit)] + queryset = utils.limitQueryset(queryset=queryset, start_limit=start_limit, end_limit=end_limit) + count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" # returns count only if param value matched @@ -302,5 +301,10 @@ def post(self, request, *args, **kwargs): else: # if fields param is empty then all the fields as mentioned in serializer are served to the response serializer = CountrySerializer(queryset, many=True) + + response = Response(serializer.data) + processing_time = time.time() - start_time + utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) + # JSON Response is provided by default - return Response(serializer.data) \ No newline at end of file + return response \ No newline at end of file diff --git a/people/views.py b/people/views.py index eb47165e87..6fe59642a8 100644 --- a/people/views.py +++ b/people/views.py @@ -27,8 +27,7 @@ from django.contrib.auth.models import User -import logging -logger = logging.getLogger('coco_api') +import time class DefaultView(generics.ListCreateAPIView): ''' @@ -74,8 +73,7 @@ def get(self, request): # POST request def getAllFarmers(self, request, *args, **kwargs): - user_obj = User.objects.get(username=request.user) - logger.info("accessed: %s.getAllFarmers, user: %s" % ( __name__,user_obj)) + start_time = time.time() country_id = self.request.POST.get('country_id', 0) # POST param 'country_id', default value is 0 fields_values = request.POST.get('fields', '') # POST param 'fields', default value is empty string @@ -112,13 +110,17 @@ def getAllFarmers(self, request, *args, **kwargs): else: # if fields param is empty then all the fields as mentioned in serializer are served to the response serializer = FarmerSerializer(queryset, many=True) + + response = Response(serializer.data) + processing_time = time.time() - start_time + utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) + # JSON Response is provided by default - return Response(serializer.data) + return response # POST request def getPhoneMatchedResults(self, request, *args, **kwargs): - user_obj = User.objects.get(username=request.user) - logger.info("accessed: %s.getPhoneMatchedResults, user: %s" % ( __name__,user_obj)) + start_time = time.time() queryset = Person.objects.all().order_by('id') @@ -156,8 +158,13 @@ def getPhoneMatchedResults(self, request, *args, **kwargs): else: # if fields param is empty then all the fields as mentioned in serializer are served to the response serializer = FarmerSerializer(queryset, many=True) - # JSON Response is provided - return Response(serializer.data) + + response = Response(serializer.data) + processing_time = time.time() - start_time + utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) + + # JSON Response is provided by default + return response class FarmersCsvAPIView(APIView): @@ -182,8 +189,8 @@ def get(self, request): # POST request def post(self, request, *args, **kwargs): - user_obj = User.objects.get(username=request.user) - logger.info("accessed: %s.FarmersCsvAPIView.post, user: %s" % (__name__,user_obj)) + start_time = time.time() + country_id = self.request.POST.get('country_id', 0) # POST param 'country_id', default value is 0 fields_values = request.POST.get('fields', '') # POST param 'fields', default value is empty string @@ -220,5 +227,10 @@ def post(self, request, *args, **kwargs): else: # if fields param is empty then all the fields as mentioned in serializer are served to the response serializer = FarmerSerializer(queryset, many=True) - # CSV Response is provided - return Response(serializer.data) \ No newline at end of file + + response = Response(serializer.data) + processing_time = time.time() - start_time + utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) + + # JSON Response is provided by default + return response \ No newline at end of file diff --git a/programs/views.py b/programs/views.py index e3ab561e6d..c9590d0223 100644 --- a/programs/views.py +++ b/programs/views.py @@ -13,10 +13,8 @@ from rest_framework.authentication import TokenAuthentication from rest_framework.permissions import IsAuthenticated -from django.contrib.auth.models import User - -import logging -logger = logging.getLogger('coco_api') +import time +from coco_api_utils import Utils class PartnerAPIView(generics.ListCreateAPIView): ''' @@ -37,8 +35,8 @@ def get(self, request): # POST request def post(self, request, *args, **kwargs): - user_obj = User.objects.get(username=request.user) - logger.info("accessed: %s.PartnerAPIView.post, user: %s" % ( __name__,user_obj)) + start_time = time.time() + utils = Utils() start_limit = request.POST.get('start_limit') # POST param 'start_limit' end_limit = request.POST.get('end_limit') # POST param 'end_limit' @@ -52,12 +50,8 @@ def post(self, request, *args, **kwargs): queryset = queryset.filter(id__exact=partner_id) else: # limits the total response count - if start_limit and end_limit: # case1: both are present - queryset = queryset[int(start_limit)-1:int(end_limit)] - elif start_limit: # case2: only start_limit is present - queryset = queryset[int(start_limit)-1:] - elif end_limit: # case3: only end_limit is present - queryset = queryset[:int(end_limit)] + queryset = utils.limitQueryset(queryset=queryset, start_limit=start_limit, end_limit=end_limit) + count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" # returns count only if param value matched @@ -71,8 +65,13 @@ def post(self, request, *args, **kwargs): else: # if fields param is empty then all the fields as mentioned in serializer are served to the response serializer = serializer_class(queryset, many=True) + + response = Response(serializer.data) + processing_time = time.time() - start_time + utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) + # JSON Response is provided by default - return Response(serializer.data) + return response @@ -96,8 +95,8 @@ def get(self, request): # POST request def post(self, request, *args, **kwargs): - user_obj = User.objects.get(username=request.user) - logger.info("accessed: %s.ProjectAPIView.post, user: %s" % ( __name__,user_obj)) + start_time = time.time() + utils = Utils() start_limit = request.POST.get('start_limit') # POST param 'start_limit' end_limit = request.POST.get('end_limit') # POST param 'end_limit' @@ -111,12 +110,8 @@ def post(self, request, *args, **kwargs): queryset = queryset.filter(id__exact=project_id) else: # limits the total response count - if start_limit and end_limit: # case1: both are present - queryset = queryset[int(start_limit)-1:int(end_limit)] - elif start_limit: # case2: only start_limit is present - queryset = queryset[int(start_limit)-1:] - elif end_limit: # case3: only end_limit is present - queryset = queryset[:int(end_limit)] + queryset = utils.limitQueryset(queryset=queryset, start_limit=start_limit, end_limit=end_limit) + count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" # returns count only if param value matched @@ -130,5 +125,10 @@ def post(self, request, *args, **kwargs): else: # if fields param is empty then all the fields as mentioned in serializer are served to the response serializer = serializer_class(queryset, many=True) + + response = Response(serializer.data) + processing_time = time.time() - start_time + utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) + # JSON Response is provided by default - return Response(serializer.data) + return response diff --git a/videos/views.py b/videos/views.py index c46290384d..679511cf38 100644 --- a/videos/views.py +++ b/videos/views.py @@ -17,9 +17,8 @@ from rest_framework.permissions import IsAuthenticated from django.contrib.auth.models import User - -import logging -logger = logging.getLogger('coco_api') +from coco_api_utils import Utils +import time class VideoAPIView(generics.ListCreateAPIView): ''' @@ -40,8 +39,8 @@ def get(self, request): # POST request def post(self, request, *args, **kwargs): - user_obj = User.objects.get(username=request.user) - logger.info("accessed: %s.VideoAPIView.post, user: %s" % ( __name__,user_obj)) + start_time = time.time() + utils = Utils() start_limit = request.POST.get('start_limit') # POST param 'start_limit' end_limit = request.POST.get('end_limit') # POST param 'end_limit' @@ -53,12 +52,7 @@ def post(self, request, *args, **kwargs): else: queryset = Video.objects.all().order_by('id') # limits the total response count - if start_limit and end_limit: # case1: both are present - queryset = queryset[int(start_limit)-1:int(end_limit)] - elif start_limit: # case2: only start_limit is present - queryset = queryset[int(start_limit)-1:] - elif end_limit: # case3: only end_limit is present - queryset = queryset[:int(end_limit)] + queryset = utils.limitQueryset(queryset=queryset, start_limit=start_limit, end_limit=end_limit) count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" # returns count only if param value matched @@ -72,6 +66,11 @@ def post(self, request, *args, **kwargs): else: # if fields param is empty then all the fields as mentioned in serializer are served to the response serializer = VideoSerializer(queryset, many=True) + + response = Response(serializer.data) + processing_time = time.time() - start_time + utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) + # JSON Response is provided by default - return Response(serializer.data) + return response From 57d53829124b7212c0c5d43eb6663645d576a2e3 Mon Sep 17 00:00:00 2001 From: vermastuti Date: Tue, 2 Jun 2020 03:25:07 +0530 Subject: [PATCH 19/35] pagination-applied --- activities/views.py | 18 +++++++++-- coco_api_utils.py | 18 +++++++++++ geographies/views.py | 77 +++++++++++++++++++++++++++++++++++++------- people/urls.py | 2 +- people/views.py | 41 +++++++++++++++++------ programs/views.py | 34 ++++++++++++++++--- videos/views.py | 17 ++++++++-- 7 files changed, 174 insertions(+), 33 deletions(-) diff --git a/activities/views.py b/activities/views.py index dbdb961683..f71662dac6 100644 --- a/activities/views.py +++ b/activities/views.py @@ -19,7 +19,7 @@ from rest_framework.permissions import IsAuthenticated import time -from coco_api_utils import Utils +from coco_api_utils import Utils, CustomPagination class ScreeningAPIView( generics.ListCreateAPIView): ''' @@ -33,6 +33,9 @@ class ScreeningAPIView( generics.ListCreateAPIView): # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] permissions_classes =[IsAuthenticated] + pagination_class = CustomPagination + serializer_class = ScreeningSerializer + # GET request def get(self, request): @@ -101,8 +104,17 @@ def post(self, request, *args, **kwargs): serializer = ScreeningSerializer(queryset, many=True) response = Response(serializer.data) + + + page = self.paginate_queryset(queryset) + if page is not None: + serializer = self.get_serializer(page, many=True) + paginated_response = self.get_paginated_response(serializer.data) + processing_time = time.time() - start_time + utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) + return paginated_response + processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) - - # JSON Response is provided by default + # JSON Response is provided return response \ No newline at end of file diff --git a/coco_api_utils.py b/coco_api_utils.py index aeae87cd54..73b3ead632 100644 --- a/coco_api_utils.py +++ b/coco_api_utils.py @@ -1,9 +1,27 @@ from django.contrib.auth.models import User from django.utils import importlib + import time import logging +# pagination +from rest_framework import pagination +from rest_framework.response import Response + + +class CustomPagination(pagination.PageNumberPagination): + page_size = 2 + page_size_query_param = 'page_size' + page_query_param = 'page' + max_page_size = 5 + def get_paginated_response(self, data): + return Response({ + 'count': self.page.paginator.count, + 'next': self.get_next_link(), + 'previous': self.get_previous_link(), + 'results': data + }) class Utils: diff --git a/geographies/views.py b/geographies/views.py index 7e0e38f9b9..b810ed5961 100644 --- a/geographies/views.py +++ b/geographies/views.py @@ -18,7 +18,7 @@ from rest_framework.permissions import IsAuthenticated from django.contrib.auth.models import User -from coco_api_utils import Utils +from coco_api_utils import Utils, CustomPagination import time class DefaultView(generics.ListAPIView): @@ -60,6 +60,8 @@ class VillageAPIView(generics.ListAPIView): # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] permissions_classes =[IsAuthenticated] + pagination_class = CustomPagination + serializer_class = VillageSerializer # GET request def get(self, request): @@ -94,10 +96,19 @@ def post(self, request, *args, **kwargs): serializer = VillageSerializer(queryset, many=True) response = Response(serializer.data) + + + page = self.paginate_queryset(queryset) + if page is not None: + serializer = self.get_serializer(page, many=True) + paginated_response = self.get_paginated_response(serializer.data) + processing_time = time.time() - start_time + utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) + return paginated_response + processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) - - # JSON Response is provided by default + # JSON Response is provided return response @@ -113,6 +124,8 @@ class BlockAPIView(generics.ListAPIView): # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] permissions_classes =[IsAuthenticated] + pagination_class = CustomPagination + serializer_class = BlockSerializer # GET request def get(self, request): @@ -147,10 +160,19 @@ def post(self, request, *args, **kwargs): serializer = BlockSerializer(queryset, many=True) response = Response(serializer.data) + + + page = self.paginate_queryset(queryset) + if page is not None: + serializer = self.get_serializer(page, many=True) + paginated_response = self.get_paginated_response(serializer.data) + processing_time = time.time() - start_time + utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) + return paginated_response + processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) - - # JSON Response is provided by default + # JSON Response is provided return response class DistrictAPIView(generics.ListAPIView): @@ -165,6 +187,8 @@ class DistrictAPIView(generics.ListAPIView): # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] permissions_classes =[IsAuthenticated] + pagination_class = CustomPagination + serializer_class = DistrictSerializer # GET request def get(self, request): @@ -199,10 +223,19 @@ def post(self, request, *args, **kwargs): serializer = DistrictSerializer(queryset, many=True) response = Response(serializer.data) + + + page = self.paginate_queryset(queryset) + if page is not None: + serializer = self.get_serializer(page, many=True) + paginated_response = self.get_paginated_response(serializer.data) + processing_time = time.time() - start_time + utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) + return paginated_response + processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) - - # JSON Response is provided by default + # JSON Response is provided return response class StateAPIView(generics.ListAPIView): @@ -217,6 +250,8 @@ class StateAPIView(generics.ListAPIView): # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] permissions_classes =[IsAuthenticated] + pagination_class = CustomPagination + serializer_class = StateSerializer # GET request def get(self, request): @@ -251,10 +286,19 @@ def post(self, request, *args, **kwargs): serializer = StateSerializer(queryset, many=True) response = Response(serializer.data) + + + page = self.paginate_queryset(queryset) + if page is not None: + serializer = self.get_serializer(page, many=True) + paginated_response = self.get_paginated_response(serializer.data) + processing_time = time.time() - start_time + utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) + return paginated_response + processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) - - # JSON Response is provided by default + # JSON Response is provided return response class CountryAPIView(generics.ListAPIView): @@ -269,6 +313,8 @@ class CountryAPIView(generics.ListAPIView): # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] permissions_classes =[IsAuthenticated] + pagination_class = CustomPagination + serializer_class = CountrySerializer # GET request def get(self, request): @@ -303,8 +349,17 @@ def post(self, request, *args, **kwargs): serializer = CountrySerializer(queryset, many=True) response = Response(serializer.data) + + + page = self.paginate_queryset(queryset) + if page is not None: + serializer = self.get_serializer(page, many=True) + paginated_response = self.get_paginated_response(serializer.data) + processing_time = time.time() - start_time + utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) + return paginated_response + processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) - - # JSON Response is provided by default + # JSON Response is provided return response \ No newline at end of file diff --git a/people/urls.py b/people/urls.py index 32ca9dd99a..3dc46825b8 100644 --- a/people/urls.py +++ b/people/urls.py @@ -7,6 +7,6 @@ # url(r'^api/farmers', views.FarmersJsonAPIView.as_view()), url(r'^api/farmers', views.FarmersJsonAPIView.as_view({'post':'getAllFarmers'})), url(r'^api/match/phone', views.FarmersJsonAPIView.as_view({'post':'getPhoneMatchedResults'})), - url(r'^api/csv', views.FarmersCsvAPIView.as_view()), # r'^$' is used for regex of exact match as mentioned + url(r'^api/csv', views.FarmersCsvAPIView.as_view({'post':'post'})), # r'^$' is used for regex of exact match as mentioned # url(r'^api/match/phone', views.FarmersMatchAPIView.as_view()), ] diff --git a/people/views.py b/people/views.py index 6fe59642a8..1f389286b6 100644 --- a/people/views.py +++ b/people/views.py @@ -23,7 +23,7 @@ from rest_framework.settings import api_settings from rest_framework_csv import renderers as r -from coco_api_utils import Utils +from coco_api_utils import Utils, CustomPagination from django.contrib.auth.models import User @@ -65,6 +65,8 @@ class FarmersJsonAPIView(viewsets.GenericViewSet): #(generics.ListCreateAPIView) # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] permissions_classes =[IsAuthenticated] + pagination_class = CustomPagination + serializer_class = FarmerSerializer # GET request @@ -112,10 +114,19 @@ def getAllFarmers(self, request, *args, **kwargs): serializer = FarmerSerializer(queryset, many=True) response = Response(serializer.data) + + + page = self.paginate_queryset(queryset) + if page is not None: + serializer = self.get_serializer(page, many=True) + paginated_response = self.get_paginated_response(serializer.data) + processing_time = time.time() - start_time + utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) + return paginated_response + processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) - - # JSON Response is provided by default + # JSON Response is provided return response # POST request @@ -127,7 +138,7 @@ def getPhoneMatchedResults(self, request, *args, **kwargs): fields_values = request.POST.get('fields', '') # POST param 'fields', default value is empty string phone_numbers = request.POST.get('phoneNumbers', '') # POST param 'fields', default value is empty string - phoneNumberExists = request.POST.get('phoneNumberExists','') # POST param 'filter_phone_no', default value is empty string + phoneNumberExists = request.POST.get('phoneNumberExists','') # POST param 'phoneNumberExists', default value is empty string # phone number exists or not if phoneNumberExists in ["true","t","yes","y"]: @@ -160,14 +171,23 @@ def getPhoneMatchedResults(self, request, *args, **kwargs): serializer = FarmerSerializer(queryset, many=True) response = Response(serializer.data) + + + page = self.paginate_queryset(queryset) + if page is not None: + serializer = self.get_serializer(page, many=True) + paginated_response = self.get_paginated_response(serializer.data) + processing_time = time.time() - start_time + utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) + return paginated_response + processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) - - # JSON Response is provided by default + # JSON Response is provided return response -class FarmersCsvAPIView(APIView): +class FarmersCsvAPIView(viewsets.GenericViewSet): ''' coco_api class-based view to query Person model and provide CSV response. django-rest-framework based token passed in Header as {'Authorization': 'Token 12345exampleToken'} @@ -182,6 +202,8 @@ class FarmersCsvAPIView(APIView): # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] permissions_classes =[IsAuthenticated] + serializer_class = FarmerSerializer + # GET request def get(self, request): @@ -231,6 +253,5 @@ def post(self, request, *args, **kwargs): response = Response(serializer.data) processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) - - # JSON Response is provided by default - return response \ No newline at end of file + # JSON Response is provided + return response diff --git a/programs/views.py b/programs/views.py index c9590d0223..e08cc623f0 100644 --- a/programs/views.py +++ b/programs/views.py @@ -14,7 +14,7 @@ from rest_framework.permissions import IsAuthenticated import time -from coco_api_utils import Utils +from coco_api_utils import Utils, CustomPagination class PartnerAPIView(generics.ListCreateAPIView): ''' @@ -28,6 +28,9 @@ class PartnerAPIView(generics.ListCreateAPIView): # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] permissions_classes =[IsAuthenticated] + pagination_class = CustomPagination + serializer_class = PartnerSerializer + # GET request def get(self, request): @@ -67,10 +70,19 @@ def post(self, request, *args, **kwargs): serializer = serializer_class(queryset, many=True) response = Response(serializer.data) + + + page = self.paginate_queryset(queryset) + if page is not None: + serializer = self.get_serializer(page, many=True) + paginated_response = self.get_paginated_response(serializer.data) + processing_time = time.time() - start_time + utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) + return paginated_response + processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) - - # JSON Response is provided by default + # JSON Response is provided return response @@ -88,6 +100,9 @@ class ProjectAPIView(generics.ListCreateAPIView): # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] permissions_classes =[IsAuthenticated] + pagination_class = CustomPagination + serializer_class = ProjectSerializer + # GET request def get(self, request): @@ -127,8 +142,17 @@ def post(self, request, *args, **kwargs): serializer = serializer_class(queryset, many=True) response = Response(serializer.data) + + + page = self.paginate_queryset(queryset) + if page is not None: + serializer = self.get_serializer(page, many=True) + paginated_response = self.get_paginated_response(serializer.data) + processing_time = time.time() - start_time + utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) + return paginated_response + processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) - - # JSON Response is provided by default + # JSON Response is provided return response diff --git a/videos/views.py b/videos/views.py index 679511cf38..ebf5de07c6 100644 --- a/videos/views.py +++ b/videos/views.py @@ -17,7 +17,7 @@ from rest_framework.permissions import IsAuthenticated from django.contrib.auth.models import User -from coco_api_utils import Utils +from coco_api_utils import Utils, CustomPagination import time class VideoAPIView(generics.ListCreateAPIView): @@ -32,6 +32,8 @@ class VideoAPIView(generics.ListCreateAPIView): # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] permissions_classes =[IsAuthenticated] + pagination_class = CustomPagination + serializer_class = VideoSerializer # GET request def get(self, request): @@ -68,9 +70,18 @@ def post(self, request, *args, **kwargs): serializer = VideoSerializer(queryset, many=True) response = Response(serializer.data) + + + page = self.paginate_queryset(queryset) + if page is not None: + serializer = self.get_serializer(page, many=True) + paginated_response = self.get_paginated_response(serializer.data) + processing_time = time.time() - start_time + utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) + return paginated_response + processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) - - # JSON Response is provided by default + # JSON Response is provided return response From b61949aaa33068996d2964cbc1a4df1d9ec139af Mon Sep 17 00:00:00 2001 From: vermastuti Date: Wed, 3 Jun 2020 02:09:53 +0530 Subject: [PATCH 20/35] view-permission-IsDGRestricted-added --- activities/views.py | 11 +++++++--- coco_api_utils.py | 10 +++++++++ geographies/views.py | 49 +++++++++++++++++++++++++++++++++----------- people/views.py | 22 ++++++++++++++------ programs/views.py | 20 +++++++++++++----- videos/views.py | 12 ++++++++--- 6 files changed, 95 insertions(+), 29 deletions(-) diff --git a/activities/views.py b/activities/views.py index f71662dac6..65f459b707 100644 --- a/activities/views.py +++ b/activities/views.py @@ -19,7 +19,7 @@ from rest_framework.permissions import IsAuthenticated import time -from coco_api_utils import Utils, CustomPagination +from coco_api_utils import Utils, CustomPagination, IsDGRestricted class ScreeningAPIView( generics.ListCreateAPIView): ''' @@ -32,7 +32,7 @@ class ScreeningAPIView( generics.ListCreateAPIView): # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] - permissions_classes =[IsAuthenticated] + permission_classes =[IsAuthenticated and IsDGRestricted] pagination_class = CustomPagination serializer_class = ScreeningSerializer @@ -108,7 +108,12 @@ def post(self, request, *args, **kwargs): page = self.paginate_queryset(queryset) if page is not None: - serializer = self.get_serializer(page, many=True) + if fields_values: # fields provided in POST request and if not empty serves those fields only + # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer + serializer = self.get_serializer(page, fields=fields_values, many=True) + else: + # if fields param is empty then all the fields as mentioned in serializer are served to the response + serializer = self.get_serializer(page, many=True) paginated_response = self.get_paginated_response(serializer.data) processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) diff --git a/coco_api_utils.py b/coco_api_utils.py index 73b3ead632..4b7e015c13 100644 --- a/coco_api_utils.py +++ b/coco_api_utils.py @@ -7,7 +7,17 @@ # pagination from rest_framework import pagination from rest_framework.response import Response +from rest_framework import permissions +class IsDGRestricted(permissions.BasePermission): + """ + View-level permission to allow restricted access to the view-based-apis. + Assumes the group of external partners exists who can't access it. + """ + + def has_permission(self, request, view): + allowed = request.user.groups.filter(name='AWAAZDE_Group').exists() + return not allowed class CustomPagination(pagination.PageNumberPagination): page_size = 2 diff --git a/geographies/views.py b/geographies/views.py index b810ed5961..2c152130e4 100644 --- a/geographies/views.py +++ b/geographies/views.py @@ -18,7 +18,7 @@ from rest_framework.permissions import IsAuthenticated from django.contrib.auth.models import User -from coco_api_utils import Utils, CustomPagination +from coco_api_utils import Utils, CustomPagination, IsDGRestricted import time class DefaultView(generics.ListAPIView): @@ -32,7 +32,7 @@ class DefaultView(generics.ListAPIView): # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] - permissions_classes =[IsAuthenticated] + permission_classes =[IsAuthenticated and IsDGRestricted] # POST request def post(self, request): @@ -59,7 +59,7 @@ class VillageAPIView(generics.ListAPIView): # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] - permissions_classes =[IsAuthenticated] + permission_classes =[IsAuthenticated and IsDGRestricted] pagination_class = CustomPagination serializer_class = VillageSerializer @@ -100,7 +100,12 @@ def post(self, request, *args, **kwargs): page = self.paginate_queryset(queryset) if page is not None: - serializer = self.get_serializer(page, many=True) + if fields_values: # fields provided in POST request and if not empty serves those fields only + # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer + serializer = self.get_serializer(page, fields=fields_values, many=True) + else: + # if fields param is empty then all the fields as mentioned in serializer are served to the response + serializer = self.get_serializer(page, many=True) paginated_response = self.get_paginated_response(serializer.data) processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) @@ -123,7 +128,7 @@ class BlockAPIView(generics.ListAPIView): # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] - permissions_classes =[IsAuthenticated] + permission_classes =[IsAuthenticated and IsDGRestricted] pagination_class = CustomPagination serializer_class = BlockSerializer @@ -164,7 +169,12 @@ def post(self, request, *args, **kwargs): page = self.paginate_queryset(queryset) if page is not None: - serializer = self.get_serializer(page, many=True) + if fields_values: # fields provided in POST request and if not empty serves those fields only + # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer + serializer = self.get_serializer(page, fields=fields_values, many=True) + else: + # if fields param is empty then all the fields as mentioned in serializer are served to the response + serializer = self.get_serializer(page, many=True) paginated_response = self.get_paginated_response(serializer.data) processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) @@ -186,7 +196,7 @@ class DistrictAPIView(generics.ListAPIView): # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] - permissions_classes =[IsAuthenticated] + permission_classes =[IsAuthenticated and IsDGRestricted] pagination_class = CustomPagination serializer_class = DistrictSerializer @@ -227,7 +237,12 @@ def post(self, request, *args, **kwargs): page = self.paginate_queryset(queryset) if page is not None: - serializer = self.get_serializer(page, many=True) + if fields_values: # fields provided in POST request and if not empty serves those fields only + # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer + serializer = self.get_serializer(page, fields=fields_values, many=True) + else: + # if fields param is empty then all the fields as mentioned in serializer are served to the response + serializer = self.get_serializer(page, many=True) paginated_response = self.get_paginated_response(serializer.data) processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) @@ -249,7 +264,7 @@ class StateAPIView(generics.ListAPIView): # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] - permissions_classes =[IsAuthenticated] + permission_classes = [IsAuthenticated and IsDGRestricted] pagination_class = CustomPagination serializer_class = StateSerializer @@ -290,7 +305,12 @@ def post(self, request, *args, **kwargs): page = self.paginate_queryset(queryset) if page is not None: - serializer = self.get_serializer(page, many=True) + if fields_values: # fields provided in POST request and if not empty serves those fields only + # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer + serializer = self.get_serializer(page, fields=fields_values, many=True) + else: + # if fields param is empty then all the fields as mentioned in serializer are served to the response + serializer = self.get_serializer(page, many=True) paginated_response = self.get_paginated_response(serializer.data) processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) @@ -312,7 +332,7 @@ class CountryAPIView(generics.ListAPIView): # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] - permissions_classes =[IsAuthenticated] + permission_classes = [IsAuthenticated and IsDGRestricted] pagination_class = CustomPagination serializer_class = CountrySerializer @@ -353,7 +373,12 @@ def post(self, request, *args, **kwargs): page = self.paginate_queryset(queryset) if page is not None: - serializer = self.get_serializer(page, many=True) + if fields_values: # fields provided in POST request and if not empty serves those fields only + # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer + serializer = self.get_serializer(page, fields=fields_values, many=True) + else: + # if fields param is empty then all the fields as mentioned in serializer are served to the response + serializer = self.get_serializer(page, many=True) paginated_response = self.get_paginated_response(serializer.data) processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) diff --git a/people/views.py b/people/views.py index 1f389286b6..b399c55a90 100644 --- a/people/views.py +++ b/people/views.py @@ -23,7 +23,7 @@ from rest_framework.settings import api_settings from rest_framework_csv import renderers as r -from coco_api_utils import Utils, CustomPagination +from coco_api_utils import Utils, CustomPagination, IsDGRestricted from django.contrib.auth.models import User @@ -40,7 +40,7 @@ class DefaultView(generics.ListCreateAPIView): # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] - permissions_classes =[IsAuthenticated] + permission_classes = [IsAuthenticated and IsDGRestricted] # POST request def post(self, request, *args, **kwargs): @@ -64,7 +64,7 @@ class FarmersJsonAPIView(viewsets.GenericViewSet): #(generics.ListCreateAPIView) # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] - permissions_classes =[IsAuthenticated] + permission_classes = [IsAuthenticated] pagination_class = CustomPagination serializer_class = FarmerSerializer @@ -118,7 +118,12 @@ def getAllFarmers(self, request, *args, **kwargs): page = self.paginate_queryset(queryset) if page is not None: - serializer = self.get_serializer(page, many=True) + if fields_values: # fields provided in POST request and if not empty serves those fields only + # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer + serializer = self.get_serializer(page, fields=fields_values, many=True) + else: + # if fields param is empty then all the fields as mentioned in serializer are served to the response + serializer = self.get_serializer(page, many=True) paginated_response = self.get_paginated_response(serializer.data) processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) @@ -175,7 +180,12 @@ def getPhoneMatchedResults(self, request, *args, **kwargs): page = self.paginate_queryset(queryset) if page is not None: - serializer = self.get_serializer(page, many=True) + if fields_values: # fields provided in POST request and if not empty serves those fields only + # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer + serializer = self.get_serializer(page, fields=fields_values, many=True) + else: + # if fields param is empty then all the fields as mentioned in serializer are served to the response + serializer = self.get_serializer(page, many=True) paginated_response = self.get_paginated_response(serializer.data) processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) @@ -201,7 +211,7 @@ class FarmersCsvAPIView(viewsets.GenericViewSet): # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] - permissions_classes =[IsAuthenticated] + permission_classes = [IsAuthenticated] serializer_class = FarmerSerializer diff --git a/programs/views.py b/programs/views.py index e08cc623f0..ece6c9068e 100644 --- a/programs/views.py +++ b/programs/views.py @@ -14,7 +14,7 @@ from rest_framework.permissions import IsAuthenticated import time -from coco_api_utils import Utils, CustomPagination +from coco_api_utils import Utils, CustomPagination, IsDGRestricted class PartnerAPIView(generics.ListCreateAPIView): ''' @@ -27,7 +27,7 @@ class PartnerAPIView(generics.ListCreateAPIView): # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] - permissions_classes =[IsAuthenticated] + permission_classes = [IsAuthenticated and IsDGRestricted] pagination_class = CustomPagination serializer_class = PartnerSerializer @@ -74,7 +74,12 @@ def post(self, request, *args, **kwargs): page = self.paginate_queryset(queryset) if page is not None: - serializer = self.get_serializer(page, many=True) + if fields_values: # fields provided in POST request and if not empty serves those fields only + # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer + serializer = self.get_serializer(page, fields=fields_values, many=True) + else: + # if fields param is empty then all the fields as mentioned in serializer are served to the response + serializer = self.get_serializer(page, many=True) paginated_response = self.get_paginated_response(serializer.data) processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) @@ -99,7 +104,7 @@ class ProjectAPIView(generics.ListCreateAPIView): # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] - permissions_classes =[IsAuthenticated] + permission_classes = [IsAuthenticated and IsDGRestricted] pagination_class = CustomPagination serializer_class = ProjectSerializer @@ -146,7 +151,12 @@ def post(self, request, *args, **kwargs): page = self.paginate_queryset(queryset) if page is not None: - serializer = self.get_serializer(page, many=True) + if fields_values: # fields provided in POST request and if not empty serves those fields only + # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer + serializer = self.get_serializer(page, fields=fields_values, many=True) + else: + # if fields param is empty then all the fields as mentioned in serializer are served to the response + serializer = self.get_serializer(page, many=True) paginated_response = self.get_paginated_response(serializer.data) processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) diff --git a/videos/views.py b/videos/views.py index ebf5de07c6..56bfe2878e 100644 --- a/videos/views.py +++ b/videos/views.py @@ -17,9 +17,10 @@ from rest_framework.permissions import IsAuthenticated from django.contrib.auth.models import User -from coco_api_utils import Utils, CustomPagination +from coco_api_utils import Utils, CustomPagination, IsDGRestricted import time + class VideoAPIView(generics.ListCreateAPIView): ''' coco_api class-based view to query Videos model and provide JSON response. @@ -31,7 +32,7 @@ class VideoAPIView(generics.ListCreateAPIView): # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] - permissions_classes =[IsAuthenticated] + permission_classes =[IsAuthenticated and IsDGRestricted] pagination_class = CustomPagination serializer_class = VideoSerializer @@ -74,7 +75,12 @@ def post(self, request, *args, **kwargs): page = self.paginate_queryset(queryset) if page is not None: - serializer = self.get_serializer(page, many=True) + if fields_values: # fields provided in POST request and if not empty serves those fields only + # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer + serializer = self.get_serializer(page, fields=fields_values, many=True) + else: + # if fields param is empty then all the fields as mentioned in serializer are served to the response + serializer = self.get_serializer(page, many=True) paginated_response = self.get_paginated_response(serializer.data) processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) From b6846f33028ed652304341509c5e69ab9ae03f27 Mon Sep 17 00:00:00 2001 From: vermastuti Date: Fri, 5 Jun 2020 04:01:44 +0530 Subject: [PATCH 21/35] permissions --- activities/views.py | 14 +--- coco_api/__init__.py | 0 coco_api/coco_api_permissions.py | 25 ++++++ .../coco_api_utils.py | 12 +-- coco_api/constants.py | 15 ++++ dg/base_settings.py | 1 + geographies/views.py | 82 ++----------------- people/views.py | 54 +++--------- programs/views.py | 37 ++------- videos/views.py | 17 ++-- 10 files changed, 79 insertions(+), 178 deletions(-) create mode 100644 coco_api/__init__.py create mode 100644 coco_api/coco_api_permissions.py rename coco_api_utils.py => coco_api/coco_api_utils.py (79%) create mode 100644 coco_api/constants.py diff --git a/activities/views.py b/activities/views.py index 65f459b707..f99bfadb12 100644 --- a/activities/views.py +++ b/activities/views.py @@ -19,7 +19,8 @@ from rest_framework.permissions import IsAuthenticated import time -from coco_api_utils import Utils, CustomPagination, IsDGRestricted +from coco_api.coco_api_utils import Utils, CustomPagination +from coco_api.coco_api_permissions import IsDGRestricted class ScreeningAPIView( generics.ListCreateAPIView): ''' @@ -83,17 +84,6 @@ def post(self, request, *args, **kwargs): except: print("End Date error occurred") - start_limit = request.POST.get('start_limit') # POST param 'start_limit' - end_limit = request.POST.get('end_limit') # POST param 'end_limit' - - # limits the total response count - queryset = utils.limitQueryset(queryset=queryset, start_limit=start_limit, end_limit=end_limit) - - count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" - # returns count only if param value matched - if count.lower() in ["true","t","yes","y"]: - return Response({"count": queryset.count()}) - fields_values = request.POST.get('fields', '') # POST param 'fields', default value is empty string if fields_values: # fields provided in POST request and if not empty serves those fields only fields_values = [val.strip() for val in fields_values.split(",")] diff --git a/coco_api/__init__.py b/coco_api/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/coco_api/coco_api_permissions.py b/coco_api/coco_api_permissions.py new file mode 100644 index 0000000000..c69e18b8f1 --- /dev/null +++ b/coco_api/coco_api_permissions.py @@ -0,0 +1,25 @@ +from rest_framework import permissions +from constants import PERMISSIONS_MAP + + +import logging +logger = logging +logger = logging.getLogger('coco_api') + + +class IsDGRestricted(permissions.BasePermission): + """ + View-level permission to allow restricted access to the view-based-apis. + Assumes the group of external partners exists who can't access it. + """ + + def has_permission(self, request, view): + view_name = view.__class__.__name__ + if PERMISSIONS_MAP.has_key(view_name): + for group_name in PERMISSIONS_MAP.get(view_name): + if request.user.groups.filter(name=group_name).exists(): + logger.info("Permission granted for view: %s to user: %s of group: %s"%(view_name, request.user, group_name)) + return True + else: + logger.info("Permission denied for view: %s to user: %s"%(view_name, request.user)) + return False \ No newline at end of file diff --git a/coco_api_utils.py b/coco_api/coco_api_utils.py similarity index 79% rename from coco_api_utils.py rename to coco_api/coco_api_utils.py index 4b7e015c13..d7ee0ffd8f 100644 --- a/coco_api_utils.py +++ b/coco_api/coco_api_utils.py @@ -7,17 +7,7 @@ # pagination from rest_framework import pagination from rest_framework.response import Response -from rest_framework import permissions -class IsDGRestricted(permissions.BasePermission): - """ - View-level permission to allow restricted access to the view-based-apis. - Assumes the group of external partners exists who can't access it. - """ - - def has_permission(self, request, view): - allowed = request.user.groups.filter(name='AWAAZDE_Group').exists() - return not allowed class CustomPagination(pagination.PageNumberPagination): page_size = 2 @@ -57,4 +47,4 @@ def logRequest(self, request, class_instance, view_fun, processing_time, status_ class_name = class_instance.__class__.__name__ module_name = class_instance.__module__ # method_name = fun. - logger.info("accessed: %s.%s.%s, user_id: %s, username: %s, ip_address: %s, method: %s, processing_time: %s seconds, status_code: %s" % ( module_name, class_name, view_fun, user_id, user_obj, ip_addr, method, processing_time, status_code)) \ No newline at end of file + logger.info("Accessed: %s.%s.%s, user_id: %s, username: %s, ip_address: %s, method: %s, processing_time: %s seconds, status_code: %s" % ( module_name, class_name, view_fun, user_id, user_obj, ip_addr, method, processing_time, status_code)) \ No newline at end of file diff --git a/coco_api/constants.py b/coco_api/constants.py new file mode 100644 index 0000000000..6ccdd82a61 --- /dev/null +++ b/coco_api/constants.py @@ -0,0 +1,15 @@ +# permission map for views and allowed user groups +PERMISSIONS_MAP = { + 'ScreeningAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], + 'DefaultView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], + 'VillageAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], + 'BlockAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], + 'DistrictAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], + 'StateAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], + 'CountryAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], + 'FarmersJsonAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS', 'AWAAZDE_Group' ], + 'FarmersCsvAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], + 'PartnerAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], + 'ProjectAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], + 'VideoAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], +} \ No newline at end of file diff --git a/dg/base_settings.py b/dg/base_settings.py index 0267bf9225..2021934099 100644 --- a/dg/base_settings.py +++ b/dg/base_settings.py @@ -187,6 +187,7 @@ 'loop_ivr', 'dataexport', 'rest_framework', + 'coco_api', # 3rd Party 'django_extensions', diff --git a/geographies/views.py b/geographies/views.py index 2c152130e4..21368d370d 100644 --- a/geographies/views.py +++ b/geographies/views.py @@ -18,7 +18,8 @@ from rest_framework.permissions import IsAuthenticated from django.contrib.auth.models import User -from coco_api_utils import Utils, CustomPagination, IsDGRestricted +from coco_api.coco_api_utils import Utils, CustomPagination +from coco_api.coco_api_permissions import IsDGRestricted import time class DefaultView(generics.ListAPIView): @@ -75,17 +76,6 @@ def post(self, request, *args, **kwargs): queryset = Village.objects.get_queryset().order_by('id') # basic query to be filtered later in this method fields_values = request.POST.get('fields', '') # POST param 'fields', default value is empty string - start_limit = request.POST.get('start_limit') # POST param 'start_limit' - end_limit = request.POST.get('end_limit') # POST param 'end_limit' - - # limits the total response count - queryset = utils.limitQueryset(queryset=queryset, start_limit=start_limit, end_limit=end_limit) - - - count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" - # returns count only if param value matched - if count.lower() in ["true","t","yes","y"]: - return Response({"count": queryset.count()}) if fields_values: # fields provided in POST request and if not empty serves those fields only fields_values = [val.strip() for val in fields_values.split(",")] @@ -95,9 +85,6 @@ def post(self, request, *args, **kwargs): # if fields param is empty then all the fields as mentioned in serializer are served to the response serializer = VillageSerializer(queryset, many=True) - response = Response(serializer.data) - - page = self.paginate_queryset(queryset) if page is not None: if fields_values: # fields provided in POST request and if not empty serves those fields only @@ -111,6 +98,7 @@ def post(self, request, *args, **kwargs): utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) return paginated_response + response = Response(serializer.data) processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) # JSON Response is provided @@ -144,17 +132,6 @@ def post(self, request, *args, **kwargs): queryset = Block.objects.get_queryset().order_by('id') # basic query to be filtered later in this method fields_values = request.POST.get('fields', '') # POST param 'limit', no default value specified so empty string is default value - start_limit = request.POST.get('start_limit') # POST param 'start_limit' - end_limit = request.POST.get('end_limit') # POST param 'end_limit' - - # limits the total response count - queryset = utils.limitQueryset(queryset=queryset, start_limit=start_limit, end_limit=end_limit) - - - count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" - # returns count only if param value matched - if count.lower() in ["true","t","yes","y"]: - return Response({"count": queryset.count()}) if fields_values: # fields provided in POST request and if not empty serves those fields only fields_values = [val.strip() for val in fields_values.split(",")] @@ -163,9 +140,6 @@ def post(self, request, *args, **kwargs): else: # if fields param is empty then all the fields as mentioned in serializer are served to the response serializer = BlockSerializer(queryset, many=True) - - response = Response(serializer.data) - page = self.paginate_queryset(queryset) if page is not None: @@ -179,7 +153,8 @@ def post(self, request, *args, **kwargs): processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) return paginated_response - + + response = Response(serializer.data) processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) # JSON Response is provided @@ -212,17 +187,6 @@ def post(self, request, *args, **kwargs): queryset = District.objects.get_queryset().order_by('id') # basic query to be filtered later in this method fields_values = request.POST.get('fields', '') # POST param 'limit', no default value specified so empty string is default value - start_limit = request.POST.get('start_limit') # POST param 'start_limit' - end_limit = request.POST.get('end_limit') # POST param 'end_limit' - - # limits the total response count - queryset = utils.limitQueryset(queryset=queryset, start_limit=start_limit, end_limit=end_limit) - - - count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" - # returns count only if param value matched - if count.lower() in ["true","t","yes","y"]: - return Response({"count": queryset.count()}) if fields_values: # fields provided in POST request and if not empty serves those fields only fields_values = [val.strip() for val in fields_values.split(",")] @@ -231,9 +195,6 @@ def post(self, request, *args, **kwargs): else: # if fields param is empty then all the fields as mentioned in serializer are served to the response serializer = DistrictSerializer(queryset, many=True) - - response = Response(serializer.data) - page = self.paginate_queryset(queryset) if page is not None: @@ -247,7 +208,8 @@ def post(self, request, *args, **kwargs): processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) return paginated_response - + + response = Response(serializer.data) processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) # JSON Response is provided @@ -280,17 +242,6 @@ def post(self, request, *args, **kwargs): queryset = State.objects.get_queryset().order_by('id') # basic query to be filtered later in this method fields_values = request.POST.get('fields', '') # POST param 'limit', no default value specified so empty string is default value - start_limit = request.POST.get('start_limit') # POST param 'start_limit' - end_limit = request.POST.get('end_limit') # POST param 'end_limit' - - # limits the total response count - queryset = utils.limitQueryset(queryset=queryset, start_limit=start_limit, end_limit=end_limit) - - - count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" - # returns count only if param value matched - if count.lower() in ["true","t","yes","y"]: - return Response({"count": queryset.count()}) if fields_values: # fields provided in POST request and if not empty serves those fields only fields_values = [val.strip() for val in fields_values.split(",")] @@ -299,9 +250,6 @@ def post(self, request, *args, **kwargs): else: # if fields param is empty then all the fields as mentioned in serializer are served to the response serializer = StateSerializer(queryset, many=True) - - response = Response(serializer.data) - page = self.paginate_queryset(queryset) if page is not None: @@ -316,6 +264,7 @@ def post(self, request, *args, **kwargs): utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) return paginated_response + response = Response(serializer.data) processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) # JSON Response is provided @@ -348,17 +297,6 @@ def post(self, request, *args, **kwargs): queryset = Country.objects.get_queryset().order_by('id') # basic query to be filtered later in this method fields_values = request.POST.get('fields', '') # POST param 'limit', no default value specified so empty string is default value - start_limit = request.POST.get('start_limit') # POST param 'start_limit' - end_limit = request.POST.get('end_limit') # POST param 'end_limit' - - # limits the total response count - queryset = utils.limitQueryset(queryset=queryset, start_limit=start_limit, end_limit=end_limit) - - - count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" - # returns count only if param value matched - if count.lower() in ["true","t","yes","y"]: - return Response({"count": queryset.count()}) if fields_values: # fields provided in POST request and if not empty serves those fields only fields_values = [val.strip() for val in fields_values.split(",")] @@ -367,9 +305,6 @@ def post(self, request, *args, **kwargs): else: # if fields param is empty then all the fields as mentioned in serializer are served to the response serializer = CountrySerializer(queryset, many=True) - - response = Response(serializer.data) - page = self.paginate_queryset(queryset) if page is not None: @@ -384,6 +319,7 @@ def post(self, request, *args, **kwargs): utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) return paginated_response + response = Response(serializer.data) processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) # JSON Response is provided diff --git a/people/views.py b/people/views.py index b399c55a90..6d7544e4b1 100644 --- a/people/views.py +++ b/people/views.py @@ -23,8 +23,8 @@ from rest_framework.settings import api_settings from rest_framework_csv import renderers as r -from coco_api_utils import Utils, CustomPagination, IsDGRestricted - +from coco_api.coco_api_utils import Utils, CustomPagination +from coco_api.coco_api_permissions import IsDGRestricted from django.contrib.auth.models import User import time @@ -64,7 +64,7 @@ class FarmersJsonAPIView(viewsets.GenericViewSet): #(generics.ListCreateAPIView) # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] - permission_classes = [IsAuthenticated] + permission_classes = [IsAuthenticated and IsDGRestricted] pagination_class = CustomPagination serializer_class = FarmerSerializer @@ -76,6 +76,7 @@ def get(self, request): # POST request def getAllFarmers(self, request, *args, **kwargs): start_time = time.time() + utils = Utils() country_id = self.request.POST.get('country_id', 0) # POST param 'country_id', default value is 0 fields_values = request.POST.get('fields', '') # POST param 'fields', default value is empty string @@ -92,18 +93,7 @@ def getAllFarmers(self, request, *args, **kwargs): # phone number exists or not if phoneNumberExists in ["true","t","yes","y"]: - queryset = queryset.filter(phone_no__isnull=False).exclude(phone_no__in=['']) - - start_limit = request.POST.get('start_limit') # POST param 'start_limit' - end_limit = request.POST.get('end_limit') # POST param 'end_limit' - - utils = Utils() - queryset = utils.limitQueryset(queryset=queryset, start_limit=start_limit, end_limit=end_limit) - - count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" - # returns count only if param value matched - if count.lower() in ["true","t","yes","y"]: - return Response({"count": queryset.count()}) + queryset = queryset.filter(phone_no__isnull=False).exclude(phone_no__in=['']) if fields_values: # fields provided in POST request and if not empty serves those fields only fields_values = [val.strip() for val in fields_values.split(",")] @@ -112,9 +102,6 @@ def getAllFarmers(self, request, *args, **kwargs): else: # if fields param is empty then all the fields as mentioned in serializer are served to the response serializer = FarmerSerializer(queryset, many=True) - - response = Response(serializer.data) - page = self.paginate_queryset(queryset) if page is not None: @@ -129,6 +116,7 @@ def getAllFarmers(self, request, *args, **kwargs): utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) return paginated_response + response = Response(serializer.data) processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) # JSON Response is provided @@ -142,7 +130,6 @@ def getPhoneMatchedResults(self, request, *args, **kwargs): fields_values = request.POST.get('fields', '') # POST param 'fields', default value is empty string phone_numbers = request.POST.get('phoneNumbers', '') # POST param 'fields', default value is empty string - phoneNumberExists = request.POST.get('phoneNumberExists','') # POST param 'phoneNumberExists', default value is empty string # phone number exists or not @@ -154,18 +141,8 @@ def getPhoneMatchedResults(self, request, *args, **kwargs): if phone_numbers: ph_no_values = [ph.strip() for ph in phone_numbers.split(",")] queryset = queryset.filter(phone_no__in=ph_no_values) - - count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" - # returns count only if param value matched - if count.lower() in ["true","t","yes","y"]: - return Response({"count": queryset.count()}) - - - start_limit = request.POST.get('start_limit') # POST param 'start_limit' - end_limit = request.POST.get('end_limit') # POST param 'end_limit' + utils = Utils() - queryset = utils.limitQueryset(queryset=queryset, start_limit=start_limit, end_limit=end_limit) - if fields_values: # fields provided in POST request and if not empty serves those fields only fields_values = [val.strip() for val in fields_values.split(",")] @@ -174,9 +151,6 @@ def getPhoneMatchedResults(self, request, *args, **kwargs): else: # if fields param is empty then all the fields as mentioned in serializer are served to the response serializer = FarmerSerializer(queryset, many=True) - - response = Response(serializer.data) - page = self.paginate_queryset(queryset) if page is not None: @@ -191,6 +165,7 @@ def getPhoneMatchedResults(self, request, *args, **kwargs): utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) return paginated_response + response = Response(serializer.data) processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) # JSON Response is provided @@ -211,7 +186,7 @@ class FarmersCsvAPIView(viewsets.GenericViewSet): # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] - permission_classes = [IsAuthenticated] + permission_classes = [IsAuthenticated and IsDGRestricted] serializer_class = FarmerSerializer @@ -239,18 +214,9 @@ def post(self, request, *args, **kwargs): # phone number exists or not if phoneNumberExists in ["true","t","yes","y"]: - queryset = queryset.filter(phone_no__isnull=False).exclude(phone_no__in=['']) - - start_limit = request.POST.get('start_limit') # POST param 'start_limit' - end_limit = request.POST.get('end_limit') # POST param 'end_limit' + queryset = queryset.filter(phone_no__isnull=False).exclude(phone_no__in=['']) utils = Utils() - queryset = utils.limitQueryset(queryset=queryset, start_limit=start_limit, end_limit=end_limit) - - count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" - # returns count only if param value matched - if count.lower() in ["true","t","yes","y"]: - return Response({"count": queryset.count()}) if fields_values: # fields provided in POST request and if not empty serves those fields only fields_values = [val.strip() for val in fields_values.split(",")] diff --git a/programs/views.py b/programs/views.py index ece6c9068e..26845f027a 100644 --- a/programs/views.py +++ b/programs/views.py @@ -14,7 +14,8 @@ from rest_framework.permissions import IsAuthenticated import time -from coco_api_utils import Utils, CustomPagination, IsDGRestricted +from coco_api.coco_api_utils import Utils, CustomPagination +from coco_api.coco_api_permissions import IsDGRestricted class PartnerAPIView(generics.ListCreateAPIView): ''' @@ -37,12 +38,12 @@ def get(self, request): return Response({"detail":"Method \"GET\" not allowed"}) # POST request - def post(self, request, *args, **kwargs): + def getPartnerById(self, request, *args, **kwargs): start_time = time.time() utils = Utils() - start_limit = request.POST.get('start_limit') # POST param 'start_limit' - end_limit = request.POST.get('end_limit') # POST param 'end_limit' + # start_limit = request.POST.get('start_limit') # POST param 'start_limit' + # end_limit = request.POST.get('end_limit') # POST param 'end_limit' fields_values = request.POST.get('fields', '') # POST param 'fields' partner_id = self.request.POST.get('id', 0) # POST param 'id' @@ -51,15 +52,6 @@ def post(self, request, *args, **kwargs): if partner_id: # checks if video id is present queryset = queryset.filter(id__exact=partner_id) - else: - # limits the total response count - queryset = utils.limitQueryset(queryset=queryset, start_limit=start_limit, end_limit=end_limit) - - - count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" - # returns count only if param value matched - if count.lower() in ["true","t","yes","y"]: - return Response({"count": queryset.count()}) if fields_values: # fields provided in POST request and if not empty serves those fields only fields_values = [val.strip() for val in fields_values.split(",")] @@ -69,9 +61,6 @@ def post(self, request, *args, **kwargs): # if fields param is empty then all the fields as mentioned in serializer are served to the response serializer = serializer_class(queryset, many=True) - response = Response(serializer.data) - - page = self.paginate_queryset(queryset) if page is not None: if fields_values: # fields provided in POST request and if not empty serves those fields only @@ -85,6 +74,7 @@ def post(self, request, *args, **kwargs): utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) return paginated_response + response = Response(serializer.data) processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) # JSON Response is provided @@ -118,8 +108,6 @@ def post(self, request, *args, **kwargs): start_time = time.time() utils = Utils() - start_limit = request.POST.get('start_limit') # POST param 'start_limit' - end_limit = request.POST.get('end_limit') # POST param 'end_limit' fields_values = request.POST.get('fields', '') # POST param 'fields' project_id = self.request.POST.get('id', 0) # POST param 'id' @@ -128,15 +116,6 @@ def post(self, request, *args, **kwargs): if project_id: # checks if video id is present queryset = queryset.filter(id__exact=project_id) - else: - # limits the total response count - queryset = utils.limitQueryset(queryset=queryset, start_limit=start_limit, end_limit=end_limit) - - - count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" - # returns count only if param value matched - if count.lower() in ["true","t","yes","y"]: - return Response({"count": queryset.count()}) if fields_values: # fields provided in POST request and if not empty serves those fields only fields_values = [val.strip() for val in fields_values.split(",")] @@ -145,9 +124,6 @@ def post(self, request, *args, **kwargs): else: # if fields param is empty then all the fields as mentioned in serializer are served to the response serializer = serializer_class(queryset, many=True) - - response = Response(serializer.data) - page = self.paginate_queryset(queryset) if page is not None: @@ -162,6 +138,7 @@ def post(self, request, *args, **kwargs): utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) return paginated_response + response = Response(serializer.data) processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) # JSON Response is provided diff --git a/videos/views.py b/videos/views.py index 56bfe2878e..52b7de02bd 100644 --- a/videos/views.py +++ b/videos/views.py @@ -17,7 +17,8 @@ from rest_framework.permissions import IsAuthenticated from django.contrib.auth.models import User -from coco_api_utils import Utils, CustomPagination, IsDGRestricted +from coco_api.coco_api_utils import Utils, CustomPagination +from coco_api.coco_api_permissions import IsDGRestricted import time @@ -45,8 +46,8 @@ def post(self, request, *args, **kwargs): start_time = time.time() utils = Utils() - start_limit = request.POST.get('start_limit') # POST param 'start_limit' - end_limit = request.POST.get('end_limit') # POST param 'end_limit' + # start_limit = request.POST.get('start_limit') # POST param 'start_limit' + # end_limit = request.POST.get('end_limit') # POST param 'end_limit' fields_values = request.POST.get('fields', '') # POST param 'fields' video_id = self.request.POST.get('id', 0) # POST param 'id' @@ -55,12 +56,12 @@ def post(self, request, *args, **kwargs): else: queryset = Video.objects.all().order_by('id') # limits the total response count - queryset = utils.limitQueryset(queryset=queryset, start_limit=start_limit, end_limit=end_limit) + # queryset = utils.limitQueryset(queryset=queryset, start_limit=start_limit, end_limit=end_limit) - count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" - # returns count only if param value matched - if count.lower() in ["true","t","yes","y"]: - return Response({"count": queryset.count()}) + # count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" + # # returns count only if param value matched + # if count.lower() in ["true","t","yes","y"]: + # return Response({"count": queryset.count()}) if fields_values: # fields provided in POST request and if not empty serves those fields only fields_values = [val.strip() for val in fields_values.split(",")] From f4549196650d88959cc1b79cb5fd26f8f7d17bc5 Mon Sep 17 00:00:00 2001 From: vermastuti Date: Thu, 11 Jun 2020 01:48:28 +0530 Subject: [PATCH 22/35] api-app-changes --- activities/views.py | 10 +- {coco_api => api}/__init__.py | 0 api/migrations/0001_initial.py | 22 ++++ api/migrations/__init__.py | 0 api/models.py | 12 ++ api/permissions.py | 24 ++++ api/scripts.py | 121 +++++++++++++++++++++ api/serializers.py | 20 ++++ coco_api/coco_api_utils.py => api/utils.py | 18 +-- coco_api/coco_api_permissions.py | 25 ----- coco_api/constants.py | 15 --- dg/base_settings.py | 4 +- dg/urls.py | 14 +-- geographies/urls.py | 1 - geographies/views.py | 33 +++--- people/urls.py | 2 - people/views.py | 26 +++-- programs/views.py | 19 ++-- videos/views.py | 27 ++--- 19 files changed, 277 insertions(+), 116 deletions(-) rename {coco_api => api}/__init__.py (100%) create mode 100644 api/migrations/0001_initial.py create mode 100644 api/migrations/__init__.py create mode 100644 api/models.py create mode 100644 api/permissions.py create mode 100644 api/scripts.py create mode 100644 api/serializers.py rename coco_api/coco_api_utils.py => api/utils.py (82%) delete mode 100644 coco_api/coco_api_permissions.py delete mode 100644 coco_api/constants.py diff --git a/activities/views.py b/activities/views.py index f99bfadb12..0f6be128bf 100644 --- a/activities/views.py +++ b/activities/views.py @@ -18,13 +18,15 @@ from rest_framework.authentication import SessionAuthentication, BasicAuthentication, TokenAuthentication from rest_framework.permissions import IsAuthenticated +# logging, pagination and permissions import time -from coco_api.coco_api_utils import Utils, CustomPagination -from coco_api.coco_api_permissions import IsDGRestricted +from api.utils import Utils, CustomPagination +from api.permissions import IsAllowed class ScreeningAPIView( generics.ListCreateAPIView): ''' - coco_api class-based view to query Screening model and provide JSON response. + This view is specifically written for coco api access. + This class-based view is to query Screening model and provide JSON response. django-rest-framework based token passed in Header as {'Authorization': 'Token 12345exampleToken'} is required to access data from this View. Only POST method is allowed. @@ -33,7 +35,7 @@ class ScreeningAPIView( generics.ListCreateAPIView): # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] - permission_classes =[IsAuthenticated and IsDGRestricted] + permission_classes =[IsAuthenticated and IsAllowed] pagination_class = CustomPagination serializer_class = ScreeningSerializer diff --git a/coco_api/__init__.py b/api/__init__.py similarity index 100% rename from coco_api/__init__.py rename to api/__init__.py diff --git a/api/migrations/0001_initial.py b/api/migrations/0001_initial.py new file mode 100644 index 0000000000..c7cbb5e551 --- /dev/null +++ b/api/migrations/0001_initial.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('auth', '0006_require_contenttypes_0002'), + ] + + operations = [ + migrations.CreateModel( + name='View', + fields=[ + ('id', models.AutoField(serialize=False, primary_key=True)), + ('view_name', models.CharField(max_length=200)), + ('permission_groups', models.ManyToManyField(to='auth.Group')), + ], + ), + ] diff --git a/api/migrations/__init__.py b/api/migrations/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/api/models.py b/api/models.py new file mode 100644 index 0000000000..3374646b2e --- /dev/null +++ b/api/models.py @@ -0,0 +1,12 @@ +from django.db import models +from django.contrib.auth.models import Group + + +class View(models.Model): + id = models.AutoField(primary_key=True) + view_name = models.CharField(max_length=200) + permission_groups = models.ManyToManyField(Group) + + def __str__(self): + "Returns the view name and groups names mapped together" + return '%s, %s'%(self.view_name, self.permission_groups) diff --git a/api/permissions.py b/api/permissions.py new file mode 100644 index 0000000000..a6fe0eb603 --- /dev/null +++ b/api/permissions.py @@ -0,0 +1,24 @@ +from rest_framework import permissions +from api.models import View + +# logger +import logging +logger = logging +logger = logging.getLogger('coco_api') + + +class IsAllowed(permissions.BasePermission): + """ + View-level permission to allow group-wise access to the view-based-apis. + """ + + def has_permission(self, request, view): + view = View.objects.get(view_name=view.__class__.__name__) + user_groups = request.user.groups.all() + if view.permission_groups.filter(name__in=list(user_groups)).exists(): + common_groups = view.permission_groups.filter(name__in=list(user_groups)) + logger.info("Permission granted for view: %s to user: %s of group: %s"%(view.view_name, request.user, common_groups)) + return True + else: + logger.info("Permission denied for view: %s to user: %s of groups: %s"%(view.view_name, request.user, user_groups)) + return False diff --git a/api/scripts.py b/api/scripts.py new file mode 100644 index 0000000000..0df7245407 --- /dev/null +++ b/api/scripts.py @@ -0,0 +1,121 @@ +# modules +from api.views import CreateView +from api.models import View +from django.contrib.auth.models import Group +# view imports +from activities.views import ScreeningAPIView +from geographies.views import VillageAPIView, BlockAPIView, DistrictAPIView, StateAPIView, CountryAPIView + +''' +How to run this script? +Here's how: +1.) Open this project folder in a terminal +2.) Activate the required environment to run this project +3.) Run the following command in the terminal: + python manage.py shell +4.) Now you'll be able to see the IPython console +5.) Run the following command in the terminal: + %run api/scripts.py +6.) If you get any location errors, then try to check the current folder using pwd command +''' + +def createAView(view_class): + ''' + This function adds a view to the database + ''' + view = View(view_name = view_class) + view.save() + return + + +def addAGroupByName(view_class_name, group_name): + ''' + This function adds a group to a view by view name to the database + ''' + view = View.objects.get(view_name=view_class_name) + gr = Group.objects.get(name=group_name) + view.permission_groups.add(gr) + view.save() + return + + +def addAGroupByID(view_id, group_id): + ''' + This function adds a group to a view by view name to the database + ''' + view = View.objects.get(id__exact=view_id) + gr = Group.objects.get(id__exact=group_id) + view.permission_groups.add(gr) + view.save() + return + + +def addAGroupByViewID(view_id, group_name): + ''' + This function adds a group to a view by view id to the database + ''' + view = View.objects.get(id__exact=view_id) + gr = Group.objects.get(name=group_name) + view.permission_groups.add(gr) + view.save() + return + + +def addAGroupByGroupID(view_class_name, group_id): + ''' + This function adds a group to a view by view name to the database + ''' + view = View.objects.get(view_name=view_class_name) + gr = Group.objects.get(id__exact=group_id) + view.permission_groups.add(gr) + view.save() + return + + +if __name__=="__main__": + ''' + This function is available to be edited according to the required view to be added in the database + ''' + # # to add a single view + # view_class = VillageAPIView.__name__ + # createAView(view_class) + + + # # to add a group to a view by view name + # group_name = "coco_api_access" + # addAGroupByName(view_class, group_name) + + + # # to add a group to a view by view id + # group_name = "coco_api_access" + # addAGroupByID(view_id, group_name) + + + # # to create multiple views and assign a group + view_class_list = [DistrictAPIView.__name__, BlockAPIView.__name__] + group_id = 20 + for view in view_class_list: + createAView(view) + addAGroupByGroupID(view, group_id) + + + # # to add multiple views belonging to multiple groups + # permission map for views and allowed user groups + PERMISSIONS_MAP = { + 'ScreeningAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], + 'DefaultView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], + 'VillageAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], + 'BlockAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], + 'DistrictAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], + 'StateAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], + 'CountryAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], + 'FarmersJsonAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS', 'AWAAZDE_Group' ], + 'FarmersCsvAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], + 'PartnerAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], + 'ProjectAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], + 'VideoAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], + 'CreateView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], + } + + + diff --git a/api/serializers.py b/api/serializers.py new file mode 100644 index 0000000000..fae7364c9d --- /dev/null +++ b/api/serializers.py @@ -0,0 +1,20 @@ +from rest_framework import serializers +from django.contrib.auth.models import Group +from models import View + +class ViewSerializer(serializers.Serializer): + + permission_group_id = serializers.CharField(source='permission_groups.id', read_only=True) + permission_group_name = serializers.CharField(source='permission_groups.name', read_only=True) + + class Meta: + model = View + fields = '__all__' + + +class GroupSerializer(serializers.Serializer): + + class Meta: + model = Group + fields = '__all__' + \ No newline at end of file diff --git a/coco_api/coco_api_utils.py b/api/utils.py similarity index 82% rename from coco_api/coco_api_utils.py rename to api/utils.py index d7ee0ffd8f..348241dbcd 100644 --- a/coco_api/coco_api_utils.py +++ b/api/utils.py @@ -7,6 +7,7 @@ # pagination from rest_framework import pagination from rest_framework.response import Response +from collections import OrderedDict class CustomPagination(pagination.PageNumberPagination): @@ -16,13 +17,15 @@ class CustomPagination(pagination.PageNumberPagination): max_page_size = 5 def get_paginated_response(self, data): - return Response({ - 'count': self.page.paginator.count, - 'next': self.get_next_link(), - 'previous': self.get_previous_link(), - 'results': data - }) + return Response(OrderedDict([ + ('count', self.page.paginator.count), + ('next', self.get_next_link()), + ('previous', self.get_previous_link()), + ('results', data) + ])) + + class Utils: def limitQueryset(self, queryset, start_limit, end_limit): @@ -47,4 +50,5 @@ def logRequest(self, request, class_instance, view_fun, processing_time, status_ class_name = class_instance.__class__.__name__ module_name = class_instance.__module__ # method_name = fun. - logger.info("Accessed: %s.%s.%s, user_id: %s, username: %s, ip_address: %s, method: %s, processing_time: %s seconds, status_code: %s" % ( module_name, class_name, view_fun, user_id, user_obj, ip_addr, method, processing_time, status_code)) \ No newline at end of file + logger.info("Accessed: %s.%s.%s, user_id: %s, username: %s, ip_address: %s, method: %s, processing_time: %s seconds, status_code: %s" % ( module_name, class_name, view_fun, user_id, user_obj, ip_addr, method, processing_time, status_code)) + \ No newline at end of file diff --git a/coco_api/coco_api_permissions.py b/coco_api/coco_api_permissions.py deleted file mode 100644 index c69e18b8f1..0000000000 --- a/coco_api/coco_api_permissions.py +++ /dev/null @@ -1,25 +0,0 @@ -from rest_framework import permissions -from constants import PERMISSIONS_MAP - - -import logging -logger = logging -logger = logging.getLogger('coco_api') - - -class IsDGRestricted(permissions.BasePermission): - """ - View-level permission to allow restricted access to the view-based-apis. - Assumes the group of external partners exists who can't access it. - """ - - def has_permission(self, request, view): - view_name = view.__class__.__name__ - if PERMISSIONS_MAP.has_key(view_name): - for group_name in PERMISSIONS_MAP.get(view_name): - if request.user.groups.filter(name=group_name).exists(): - logger.info("Permission granted for view: %s to user: %s of group: %s"%(view_name, request.user, group_name)) - return True - else: - logger.info("Permission denied for view: %s to user: %s"%(view_name, request.user)) - return False \ No newline at end of file diff --git a/coco_api/constants.py b/coco_api/constants.py deleted file mode 100644 index 6ccdd82a61..0000000000 --- a/coco_api/constants.py +++ /dev/null @@ -1,15 +0,0 @@ -# permission map for views and allowed user groups -PERMISSIONS_MAP = { - 'ScreeningAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], - 'DefaultView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], - 'VillageAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], - 'BlockAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], - 'DistrictAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], - 'StateAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], - 'CountryAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], - 'FarmersJsonAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS', 'AWAAZDE_Group' ], - 'FarmersCsvAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], - 'PartnerAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], - 'ProjectAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], - 'VideoAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], -} \ No newline at end of file diff --git a/dg/base_settings.py b/dg/base_settings.py index 2021934099..445e4deeda 100644 --- a/dg/base_settings.py +++ b/dg/base_settings.py @@ -187,7 +187,7 @@ 'loop_ivr', 'dataexport', 'rest_framework', - 'coco_api', + 'api', # 3rd Party 'django_extensions', @@ -250,7 +250,7 @@ 'api_access_log': { 'level':'DEBUG', 'class':'logging.handlers.RotatingFileHandler', - 'filename': os.path.join(PROJECT_PATH, '../coco_api/log/logfile'), + 'filename': os.path.join(PROJECT_PATH, '../api/log/logfile'), 'formatter': 'standard', }, diff --git a/dg/urls.py b/dg/urls.py index d4cb854192..15c94e2120 100644 --- a/dg/urls.py +++ b/dg/urls.py @@ -94,13 +94,13 @@ (r'^videos/', include(videos.urls)), - #coco_api changes starts here - (r'^api-token-auth', views.obtain_auth_token), # POST;params: {'username':'','password':''}; generates token - (r'^farmer/', include(people.urls)), # includes people.urls.py - (r'^geo/', include(geographies.urls)), # includes geographies.urls.py - (r'^activities/', include(activities.urls)), # includes activities.urls.py - (r'^programs/', include(programs.urls)), # includes programs.urls.py - #coco_api changes ends here + # coco_api changes starts here + (r'^api-token-auth', views.obtain_auth_token), + (r'^farmer/', include(people.urls)), + (r'^geo/', include(geographies.urls)), + (r'^activities/', include(activities.urls)), + (r'^programs/', include(programs.urls)), + # coco_api changes ends here # ivrsadmin/logout/ should be above admin/ URL diff --git a/geographies/urls.py b/geographies/urls.py index 67f84ab782..10eb307718 100644 --- a/geographies/urls.py +++ b/geographies/urls.py @@ -9,5 +9,4 @@ url(r'^api/district', views.DistrictAPIView.as_view()), url(r'^api/state', views.StateAPIView.as_view()), url(r'^api/country', views.CountryAPIView.as_view()), - # url('csv', views.CSVView.as_view()), ] diff --git a/geographies/views.py b/geographies/views.py index 21368d370d..b554a026a2 100644 --- a/geographies/views.py +++ b/geographies/views.py @@ -17,14 +17,15 @@ from rest_framework.authentication import SessionAuthentication, BasicAuthentication, TokenAuthentication from rest_framework.permissions import IsAuthenticated -from django.contrib.auth.models import User -from coco_api.coco_api_utils import Utils, CustomPagination -from coco_api.coco_api_permissions import IsDGRestricted +# logging, pagination and permissions import time +from api.utils import Utils, CustomPagination +from api.permissions import IsAllowed class DefaultView(generics.ListAPIView): ''' - coco_api class-based view to provide default message in JSON format. + This view is specifically written for coco api access. + This class-based view is to provide default message in JSON format. django-rest-framework based token passed in Header as {'Authorization': 'Token 12345exampleToken'} is required to access data from this View. Only POST method is allowed. @@ -33,7 +34,7 @@ class DefaultView(generics.ListAPIView): # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] - permission_classes =[IsAuthenticated and IsDGRestricted] + permission_classes =[IsAuthenticated and IsAllowed] # POST request def post(self, request): @@ -60,7 +61,7 @@ class VillageAPIView(generics.ListAPIView): # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] - permission_classes =[IsAuthenticated and IsDGRestricted] + permission_classes =[IsAuthenticated and IsAllowed] pagination_class = CustomPagination serializer_class = VillageSerializer @@ -107,7 +108,8 @@ def post(self, request, *args, **kwargs): class BlockAPIView(generics.ListAPIView): ''' - coco_api class-based view to query Block model and provide JSON response. + This view is specifically written for coco api access. + This class-based view is to query Block model and provide JSON response. django-rest-framework based token passed in Header as {'Authorization': 'Token 12345exampleToken'} is required to access data from this View. Only POST method is allowed. @@ -116,7 +118,7 @@ class BlockAPIView(generics.ListAPIView): # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] - permission_classes =[IsAuthenticated and IsDGRestricted] + permission_classes =[IsAuthenticated and IsAllowed] pagination_class = CustomPagination serializer_class = BlockSerializer @@ -162,7 +164,8 @@ def post(self, request, *args, **kwargs): class DistrictAPIView(generics.ListAPIView): ''' - coco_api class-based view to query District model and provide JSON response. + This view is specifically written for coco api access. + This class-based view is to query District model and provide JSON response. django-rest-framework based token passed in Header as {'Authorization': 'Token 12345exampleToken'} is required to access data from this View. Only POST method is allowed. @@ -171,7 +174,7 @@ class DistrictAPIView(generics.ListAPIView): # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] - permission_classes =[IsAuthenticated and IsDGRestricted] + permission_classes =[IsAuthenticated and IsAllowed] pagination_class = CustomPagination serializer_class = DistrictSerializer @@ -217,7 +220,8 @@ def post(self, request, *args, **kwargs): class StateAPIView(generics.ListAPIView): ''' - coco_api class-based view to query State model and provide JSON response. + This view is specifically written for coco api access. + This class-based view is to query State model and provide JSON response. django-rest-framework based token passed in Header as {'Authorization': 'Token 12345exampleToken'} is required to access data from this View. Only POST method is allowed. @@ -226,7 +230,7 @@ class StateAPIView(generics.ListAPIView): # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] - permission_classes = [IsAuthenticated and IsDGRestricted] + permission_classes = [IsAuthenticated and IsAllowed] pagination_class = CustomPagination serializer_class = StateSerializer @@ -272,7 +276,8 @@ def post(self, request, *args, **kwargs): class CountryAPIView(generics.ListAPIView): ''' - coco_api class-based view to query Country model and provide JSON response. + This view is specifically written for coco api access. + This class-based view is to query Country model and provide JSON response. django-rest-framework based token passed in Header as {'Authorization': 'Token 12345exampleToken'} is required to access data from this View. Only POST method is allowed. @@ -281,7 +286,7 @@ class CountryAPIView(generics.ListAPIView): # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] - permission_classes = [IsAuthenticated and IsDGRestricted] + permission_classes = [IsAuthenticated and IsAllowed] pagination_class = CustomPagination serializer_class = CountrySerializer diff --git a/people/urls.py b/people/urls.py index 3dc46825b8..7aadb35e48 100644 --- a/people/urls.py +++ b/people/urls.py @@ -4,9 +4,7 @@ urlpatterns=[ url(r'^api/default', views.DefaultView.as_view()), - # url(r'^api/farmers', views.FarmersJsonAPIView.as_view()), url(r'^api/farmers', views.FarmersJsonAPIView.as_view({'post':'getAllFarmers'})), url(r'^api/match/phone', views.FarmersJsonAPIView.as_view({'post':'getPhoneMatchedResults'})), url(r'^api/csv', views.FarmersCsvAPIView.as_view({'post':'post'})), # r'^$' is used for regex of exact match as mentioned - # url(r'^api/match/phone', views.FarmersMatchAPIView.as_view()), ] diff --git a/people/views.py b/people/views.py index 6d7544e4b1..9cb14466d4 100644 --- a/people/views.py +++ b/people/views.py @@ -23,15 +23,15 @@ from rest_framework.settings import api_settings from rest_framework_csv import renderers as r -from coco_api.coco_api_utils import Utils, CustomPagination -from coco_api.coco_api_permissions import IsDGRestricted -from django.contrib.auth.models import User - +# logging, pagination and permissions import time +from api.utils import Utils, CustomPagination +from api.permissions import IsAllowed class DefaultView(generics.ListCreateAPIView): ''' - coco_api class-based view to provide default message in JSON format. + This view is specifically written for coco api access. + This class-based view is to provide default message in JSON format. django-rest-framework based token passed in Header as {'Authorization': 'Token 12345exampleToken'} is required to access data from this View. Only POST method is allowed. @@ -40,7 +40,7 @@ class DefaultView(generics.ListCreateAPIView): # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] - permission_classes = [IsAuthenticated and IsDGRestricted] + permission_classes = [IsAuthenticated and IsAllowed] # POST request def post(self, request, *args, **kwargs): @@ -53,9 +53,10 @@ def get(self, request): return Response({"detail":"Method \"GET\" not allowed."}) -class FarmersJsonAPIView(viewsets.GenericViewSet): #(generics.ListCreateAPIView): +class FarmersJsonAPIView(viewsets.GenericViewSet): ''' - coco_api class-based view to query Person model and provide JSON response. + This view is specifically written for coco api access. + This class-based view is to query Person model and provide JSON response. django-rest-framework based token passed in Header as {'Authorization': 'Token 12345exampleToken'} is required to access data from this View. Only POST method is allowed. @@ -64,7 +65,7 @@ class FarmersJsonAPIView(viewsets.GenericViewSet): #(generics.ListCreateAPIView) # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] - permission_classes = [IsAuthenticated and IsDGRestricted] + permission_classes = [IsAuthenticated and IsAllowed] pagination_class = CustomPagination serializer_class = FarmerSerializer @@ -174,7 +175,8 @@ def getPhoneMatchedResults(self, request, *args, **kwargs): class FarmersCsvAPIView(viewsets.GenericViewSet): ''' - coco_api class-based view to query Person model and provide CSV response. + This view is specifically written for coco api access. + This class-based view is to query Person model and provide CSV response. django-rest-framework based token passed in Header as {'Authorization': 'Token 12345exampleToken'} is required to access data from this View. Only POST method is allowed. @@ -186,7 +188,7 @@ class FarmersCsvAPIView(viewsets.GenericViewSet): # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] - permission_classes = [IsAuthenticated and IsDGRestricted] + permission_classes = [IsAuthenticated and IsAllowed] serializer_class = FarmerSerializer @@ -230,4 +232,4 @@ def post(self, request, *args, **kwargs): processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) # JSON Response is provided - return response + return response \ No newline at end of file diff --git a/programs/views.py b/programs/views.py index 26845f027a..b5c155e3af 100644 --- a/programs/views.py +++ b/programs/views.py @@ -2,7 +2,7 @@ from django.shortcuts import render # rest_framework imports -from rest_framework import generics +from rest_framework import generics, viewsets from rest_framework.response import Response # app imports @@ -13,13 +13,15 @@ from rest_framework.authentication import TokenAuthentication from rest_framework.permissions import IsAuthenticated +# logging, pagination and permissions import time -from coco_api.coco_api_utils import Utils, CustomPagination -from coco_api.coco_api_permissions import IsDGRestricted +from api.utils import Utils, CustomPagination +from api.permissions import IsAllowed class PartnerAPIView(generics.ListCreateAPIView): ''' - coco_api class-based view to query Partner model and provide JSON response. + This view is specifically written for coco api access. + This class-based view is to query Partner model and provide JSON response. django-rest-framework based token passed in Header as {'Authorization': 'Token 12345exampleToken'} is required to access data from this View. Only POST method is allowed. @@ -28,7 +30,7 @@ class PartnerAPIView(generics.ListCreateAPIView): # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] - permission_classes = [IsAuthenticated and IsDGRestricted] + permission_classes = [IsAuthenticated and IsAllowed] pagination_class = CustomPagination serializer_class = PartnerSerializer @@ -85,7 +87,8 @@ def getPartnerById(self, request, *args, **kwargs): class ProjectAPIView(generics.ListCreateAPIView): ''' - coco_api class-based view to query Project model and provide JSON response. + This view is specifically written for coco api access. + This class-based view is to query Project model and provide JSON response. django-rest-framework based token passed in Header as {'Authorization': 'Token 12345exampleToken'} is required to access data from this View. Only POST method is allowed. @@ -94,7 +97,7 @@ class ProjectAPIView(generics.ListCreateAPIView): # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] - permission_classes = [IsAuthenticated and IsDGRestricted] + permission_classes = [IsAuthenticated and IsAllowed] pagination_class = CustomPagination serializer_class = ProjectSerializer @@ -142,4 +145,4 @@ def post(self, request, *args, **kwargs): processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) # JSON Response is provided - return response + return response \ No newline at end of file diff --git a/videos/views.py b/videos/views.py index 52b7de02bd..0b621d2758 100644 --- a/videos/views.py +++ b/videos/views.py @@ -16,15 +16,16 @@ from rest_framework.authentication import SessionAuthentication, BasicAuthentication, TokenAuthentication from rest_framework.permissions import IsAuthenticated -from django.contrib.auth.models import User -from coco_api.coco_api_utils import Utils, CustomPagination -from coco_api.coco_api_permissions import IsDGRestricted +# logging, pagination and permissions import time +from api.utils import Utils, CustomPagination +from api.permissions import IsAllowed class VideoAPIView(generics.ListCreateAPIView): ''' - coco_api class-based view to query Videos model and provide JSON response. + This view is specifically written for coco api access. + This class-based view is to query Videos model and provide JSON response. django-rest-framework based token passed in Header as {'Authorization': 'Token 12345exampleToken'} is required to access data from this View. Only POST method is allowed. @@ -33,7 +34,7 @@ class VideoAPIView(generics.ListCreateAPIView): # django-rest-framework TokenAuthentication authentication_classes = [TokenAuthentication] - permission_classes =[IsAuthenticated and IsDGRestricted] + permission_classes =[IsAuthenticated and IsAllowed] pagination_class = CustomPagination serializer_class = VideoSerializer @@ -46,8 +47,6 @@ def post(self, request, *args, **kwargs): start_time = time.time() utils = Utils() - # start_limit = request.POST.get('start_limit') # POST param 'start_limit' - # end_limit = request.POST.get('end_limit') # POST param 'end_limit' fields_values = request.POST.get('fields', '') # POST param 'fields' video_id = self.request.POST.get('id', 0) # POST param 'id' @@ -55,13 +54,6 @@ def post(self, request, *args, **kwargs): queryset = Video.objects.filter(id__exact=video_id) else: queryset = Video.objects.all().order_by('id') - # limits the total response count - # queryset = utils.limitQueryset(queryset=queryset, start_limit=start_limit, end_limit=end_limit) - - # count = self.request.POST.get("count", "False") # POST param 'count', default value is string "False" - # # returns count only if param value matched - # if count.lower() in ["true","t","yes","y"]: - # return Response({"count": queryset.count()}) if fields_values: # fields provided in POST request and if not empty serves those fields only fields_values = [val.strip() for val in fields_values.split(",")] @@ -71,9 +63,6 @@ def post(self, request, *args, **kwargs): # if fields param is empty then all the fields as mentioned in serializer are served to the response serializer = VideoSerializer(queryset, many=True) - response = Response(serializer.data) - - page = self.paginate_queryset(queryset) if page is not None: if fields_values: # fields provided in POST request and if not empty serves those fields only @@ -87,8 +76,8 @@ def post(self, request, *args, **kwargs): utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) return paginated_response + response = Response(serializer.data) processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) # JSON Response is provided - return response - + return response \ No newline at end of file From c6e66877fbb281fde4f27c60bd6e7fc1cfd1c395 Mon Sep 17 00:00:00 2001 From: vermastuti Date: Thu, 11 Jun 2020 11:11:59 +0530 Subject: [PATCH 23/35] admin-changes --- activities/views.py | 9 +-------- api/models.py | 3 +++ api/permissions.py | 4 ++-- api/scripts.py | 11 ++++++++--- dashboard/admin.py | 36 ++++++++++++++++++++++++++---------- dg/coco_admin.py | 9 +++++++-- 6 files changed, 47 insertions(+), 25 deletions(-) diff --git a/activities/views.py b/activities/views.py index 0f6be128bf..813ab7f14e 100644 --- a/activities/views.py +++ b/activities/views.py @@ -1,23 +1,18 @@ # default imports from django.shortcuts import render - # model imports from videos.models import * from activities.models import * - # serializers imports from activities.serializers import * - # drf imports from rest_framework import viewsets, generics from rest_framework import permissions from rest_framework.response import Response from rest_framework import status - # authentication from rest_framework.authentication import SessionAuthentication, BasicAuthentication, TokenAuthentication from rest_framework.permissions import IsAuthenticated - # logging, pagination and permissions import time from api.utils import Utils, CustomPagination @@ -95,9 +90,6 @@ def post(self, request, *args, **kwargs): # if fields param is empty then all the fields as mentioned in serializer are served to the response serializer = ScreeningSerializer(queryset, many=True) - response = Response(serializer.data) - - page = self.paginate_queryset(queryset) if page is not None: if fields_values: # fields provided in POST request and if not empty serves those fields only @@ -111,6 +103,7 @@ def post(self, request, *args, **kwargs): utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) return paginated_response + response = Response(serializer.data) processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) # JSON Response is provided diff --git a/api/models.py b/api/models.py index 3374646b2e..f91e6558fd 100644 --- a/api/models.py +++ b/api/models.py @@ -3,6 +3,9 @@ class View(models.Model): + ''' + This is model for View present in the views.py. Groups represent the permitted groups allowed to access it. + ''' id = models.AutoField(primary_key=True) view_name = models.CharField(max_length=200) permission_groups = models.ManyToManyField(Group) diff --git a/api/permissions.py b/api/permissions.py index a6fe0eb603..dd4eab9482 100644 --- a/api/permissions.py +++ b/api/permissions.py @@ -1,6 +1,7 @@ +# permissions from rest_framework import permissions +# app from api.models import View - # logger import logging logger = logging @@ -11,7 +12,6 @@ class IsAllowed(permissions.BasePermission): """ View-level permission to allow group-wise access to the view-based-apis. """ - def has_permission(self, request, view): view = View.objects.get(view_name=view.__class__.__name__) user_groups = request.user.groups.all() diff --git a/api/scripts.py b/api/scripts.py index 0df7245407..0b14998fbd 100644 --- a/api/scripts.py +++ b/api/scripts.py @@ -1,8 +1,8 @@ -# modules +# app from api.views import CreateView from api.models import View from django.contrib.auth.models import Group -# view imports +# view from activities.views import ScreeningAPIView from geographies.views import VillageAPIView, BlockAPIView, DistrictAPIView, StateAPIView, CountryAPIView @@ -117,5 +117,10 @@ def addAGroupByGroupID(view_class_name, group_id): 'CreateView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], } - + # for key in PERMISSIONS_MAP.keys(): + # view_name = key + # group_list = PERMISSIONS_MAP[key] + # for group_name in group_list: + # createAView(view) + # addAGroupByName(view_name, group_name) diff --git a/dashboard/admin.py b/dashboard/admin.py index 8c1fe56a22..9c9da2d483 100644 --- a/dashboard/admin.py +++ b/dashboard/admin.py @@ -27,6 +27,7 @@ class Meta: model = PersonMeetingAttendance exclude = () + class FarmerAttendanceInline(admin.TabularInline): model = PersonMeetingAttendance raw_id_fields = ("person",) @@ -58,6 +59,7 @@ class Meta: model = Screening exclude = () + class ScreeningAdmin(admin.ModelAdmin): filter_horizontal = ('videoes_screened',) list_display = ('id', 'date', 'screening_location', 'observation_status', 'screening_grade', 'observer') @@ -106,11 +108,11 @@ class DirectBeneficiariesAdmin(admin.ModelAdmin): list_display = ['id', 'direct_beneficiaries_category'] search_fields = ['direct_beneficiaries_category'] + class PartnerAdmin(admin.ModelAdmin): list_display = ['id', 'partner_name'] - class VideoAdmin(admin.ModelAdmin): inlines = [NonNegotiablesInline] fieldsets = [ @@ -134,6 +136,7 @@ class Media: settings.STATIC_URL + "js/qa_video.js", ) + class AnimatorAssignedVillages(admin.StackedInline): model = AnimatorAssignedVillage @@ -149,11 +152,13 @@ class PersonGroupInline(admin.TabularInline): model = PersonGroup extra = 5 + class AnimatorInline(admin.TabularInline): model = Animator extra = 5 exclude = ('assigned_villages',) + class VillageAdmin(admin.ModelAdmin): list_display = ('id', 'village_name', 'block', 'active') search_fields = ['village_name', 'block__block_name', 'block__district__state__state_name'] @@ -184,7 +189,6 @@ class Media: #} - class PersonGroupAdmin(admin.ModelAdmin): inlines = [PersonInline] list_display = ('group_name','village') @@ -201,6 +205,7 @@ class PersonAdoptPracticeInline(admin.StackedInline): model = PersonAdoptPractice extra = 3 + class PersonAdoptPracticeAdmin(admin.ModelAdmin): formfield_overrides = { models.CharField: {'widget': forms.CheckboxSelectMultiple(choices=NONNEGOTIABLE_OPTION)}, @@ -229,55 +234,69 @@ class PersonAdmin(admin.ModelAdmin): search_fields = ['person_name','village__village_name','group__group_name'] raw_id_fields = ('village','group') + class BlockAdmin(admin.ModelAdmin): list_display = ('id', 'block_name', 'district', 'active') search_fields = ['block_name', 'district__district_name', 'district__state__state_name'] + class DistrictAdmin(admin.ModelAdmin): list_display = ('id', 'district_name', 'state', 'active') search_fields = ['district_name', 'state__state_name'] + class StateAdmin(admin.ModelAdmin): list_display = ('id', 'state_name','active') search_fields = ['state_name', 'country__country_name'] + class SubCategoryAdmin(admin.ModelAdmin): list_display = ('subcategory_name', 'category') search_fields = ['subcategory_name', 'category__category_name'] + class VideoPracticeAdmin(admin.ModelAdmin): list_display = ('videopractice_name', 'subcategory') search_fields = ['videopractice_name', 'subcategory__subcategory_name'] + class PracticesAdmin(admin.ModelAdmin): list_display = ('id', 'practice_name', 'practice_sector', 'practice_subject', 'practice_subsector', 'practice_topic', 'practice_subtopic') search_fields = ['id', 'practice_name', 'practice_sector__name', 'practice_subject__name', 'practice_subsector__name', 'practice_topic__name', 'practice_subtopic__name'] + class PracticeSectorAdmin(admin.ModelAdmin): search_fields = ['name'] + class PracticeSubSectorAdmin(admin.ModelAdmin): search_fields = ['name'] + class PracticeTopicAdmin(admin.ModelAdmin): search_fields = ['name'] + class PracticeSubtopicAdmin(admin.ModelAdmin): search_fields = ['name'] + class PracticeSubjectAdmin(admin.ModelAdmin): search_fields = ['name'] + class CocoUserAdmin(admin.ModelAdmin): form = CocoUserForm list_display = ('id', 'user', 'partner','get_villages') search_fields = ['user__username'] + class QACocoUserAdmin(admin.ModelAdmin): form = QACocoUserForm list_display = ('user','partner','get_blocks') search_fields = ['user__username'] + class ProjectAdmin(admin.ModelAdmin): filter_horizontal = ('associate_partner',) list_display = ('id','project_name') @@ -299,8 +318,6 @@ def __init__(self, *args, **kwargs): self.fields['video'].queryset = Video.objects.filter(partner_id__in=(50,72),village__block__district__state_id= 6).exclude(id__in=mapped_videos) - - class BluefrogSubcategoryAdmin(admin.ModelAdmin): list_display = ['crop_id', 'crop_name', 'crop_name_telgu'] search_fields = ['crop_id', 'crop_name', 'crop_name_telgu'] @@ -331,10 +348,6 @@ def save_related(self, request, form, formsets, change): form.instance.video.tags.add(*current_instance_tag) - - - - class AP_DistrictAdmin(admin.ModelAdmin): list_display = ['id', 'district_code', 'district_name', 'user_created', 'time_created', '_district'] @@ -426,12 +439,12 @@ def _animator(self, obj): _animator.allow_tags = True _animator.short_description = "COCO-DB-Animator-ID" + class AP_AnimatorAssignedVillageAdmin(admin.ModelAdmin): list_display = ['id', 'animator', 'village', 'user_created', 'time_created'] search_fields = ['animator'] - class JSLPS_AnimatorAdmin(admin.ModelAdmin): list_display = ('id','animator_code', 'user_created', 'time_created', '_animator', 'activity') @@ -525,6 +538,7 @@ def _village(self, obj): def has_add_permission(self, request): return False + class JSLPS_VideoAdmin(admin.ModelAdmin): list_display = ['id', 'vc', 'title', 'user_created', 'time_created', '_video', 'activity'] @@ -564,7 +578,6 @@ def has_add_permission(self, request): return False - class JSLPS_ScreeningAdmin(admin.ModelAdmin): list_display = ['id', 'screenig_code', 'activity', 'screening', '_village', '_dg_screening_id', @@ -597,4 +610,7 @@ def has_add_permission(self, request): return False +class ViewAdmin(admin.ModelAdmin): + list_display = ('id', 'view_name', 'permission_groups') + search_fields = ['id', 'view_name'] diff --git a/dg/coco_admin.py b/dg/coco_admin.py index 742253dadc..b81e199679 100644 --- a/dg/coco_admin.py +++ b/dg/coco_admin.py @@ -1,4 +1,5 @@ from django.contrib.admin.sites import AdminSite +# admin from django.contrib.auth.admin import Group, GroupAdmin, User, UserAdmin from dashboard.admin import AnimatorAdmin from dashboard.admin import AnimatorAssignedVillageAdmin @@ -24,6 +25,9 @@ from dashboard.admin import ProjectAdmin from dashboard.admin import TagAdmin from dashboard.admin import PartnerAdmin +from dashboard.admin import ViewAdmin +# models +from api.models import View from activities.models import PersonAdoptPractice, Screening from coco.models import CocoUser from geographies.models import Block, Country, District, State, Village @@ -55,10 +59,10 @@ def has_permission(self, request): coco_admin.index_template = 'social_website/index.html' coco_admin.login_template = 'social_website/login.html' coco_admin.logout_template = 'social_website/home.html' - +# default admin coco_admin.register(User, UserAdmin) coco_admin.register(Group, GroupAdmin) - +# custom admin coco_admin.register(AnimatorAssignedVillage, AnimatorAssignedVillageAdmin) coco_admin.register(Video, VideoAdmin) coco_admin.register(Country) @@ -86,3 +90,4 @@ def has_permission(self, request): coco_admin.register(PracticeSubtopic, PracticeSubtopicAdmin) coco_admin.register(PracticeSubject, PracticeSubjectAdmin) coco_admin.register(CocoUser, CocoUserAdmin) +coco_admin.register(View, ViewAdmin) From f0cc1e2709a49fe2816c96c0caa729ac7ffd3d9a Mon Sep 17 00:00:00 2001 From: vermastuti Date: Thu, 11 Jun 2020 18:58:59 +0530 Subject: [PATCH 24/35] comments-linegaps --- .../management/commands/bluefrog_adoptions.py | 1 - activities/models.py | 8 +- activities/serializers.py | 14 +- activities/urls.py | 9 +- activities/views.py | 28 ++-- .../commands/insert_views_for_permissions.py | 81 +++++++++++ api/models.py | 6 + api/permissions.py | 18 ++- api/scripts.py | 126 ------------------ api/serializers.py | 6 + api/utils.py | 17 ++- geographies/apps.py | 2 - geographies/models.py | 2 + geographies/serializers.py | 15 ++- geographies/urls.py | 9 +- geographies/views.py | 42 +++--- loop/management/commands/Outliers.py | 4 +- people/models.py | 10 +- people/serializers.py | 16 +-- people/urls.py | 12 +- people/views.py | 25 ++-- programs/models.py | 3 +- programs/serializers.py | 9 +- programs/urls.py | 4 +- programs/views.py | 13 +- videos/models.py | 1 + videos/serializers.py | 9 +- videos/urls.py | 16 +-- videos/views.py | 24 ++-- 29 files changed, 284 insertions(+), 246 deletions(-) create mode 100644 api/management/commands/insert_views_for_permissions.py delete mode 100644 api/scripts.py diff --git a/activities/management/commands/bluefrog_adoptions.py b/activities/management/commands/bluefrog_adoptions.py index 143fe17efa..6d473dc345 100644 --- a/activities/management/commands/bluefrog_adoptions.py +++ b/activities/management/commands/bluefrog_adoptions.py @@ -78,4 +78,3 @@ def handle(self, *args, **options): wtr.writerow(['Not able to Save Adoption in AP Adoption TABLE', member_code, ap_adopt_practice, e]) - diff --git a/activities/models.py b/activities/models.py index e7fd123dd6..f946d2ffcc 100644 --- a/activities/models.py +++ b/activities/models.py @@ -33,8 +33,8 @@ class VRPpayment(models.Manager): - "Custom manager filters standard query set with given args." + def __init__(self, partner_id, block_id, start_period, end_period): super(VRPpayment, self).__init__() self.start_yyyy = start_period[-4:] @@ -95,6 +95,7 @@ class FrontLineWorkerPresent(models.Model): def __unicode__(self): return self.worker_type + class Screening(CocoModel): id = models.AutoField(primary_key=True) old_coco_id = models.BigIntegerField(editable=False, null=True) @@ -147,6 +148,7 @@ class PersonMeetingAttendance(CocoModel): def __unicode__(self): return u'%s' % (self.id) + class PersonAdoptPractice(CocoModel): id = models.AutoField(primary_key=True) old_coco_id = models.BigIntegerField(editable=False, null=True) @@ -173,9 +175,11 @@ def __unicode__(self): class Meta: unique_together = ("person", "video", "date_of_adoption") + post_save.connect(save_log, sender=PersonAdoptPractice) pre_delete.connect(delete_log, sender=PersonAdoptPractice) + class JSLPS_Screening(CocoModel): id = models.AutoField(primary_key=True) screenig_code = models.CharField(max_length=100) @@ -213,7 +217,6 @@ class Meta: verbose_name_plural = "JSLPS Adoption" - class AP_Screening(CocoModel): screening_code = models.CharField(max_length=100) screening = models.ForeignKey(Screening, null=True, blank=True) @@ -240,4 +243,3 @@ class Meta: verbose_name = "Adoption" verbose_name_plural = "Adoption" - diff --git a/activities/serializers.py b/activities/serializers.py index 29a7a9044c..ef19f967a0 100644 --- a/activities/serializers.py +++ b/activities/serializers.py @@ -1,5 +1,13 @@ -from .models import Screening +# rest framework imports from rest_framework import serializers +# app imports +from .models import Screening + +__author__ = "Stuti Verma" +__credits__ = ["Sujit Chaurasia", "Sagar Singh"] +__maintainer__ = "Stuti Verma" +__email__ = "stuti@digitalgreen.org" +__status__ = "Development" class DynamicFieldsModelSerializer(serializers.ModelSerializer): """ @@ -21,7 +29,9 @@ def __init__(self, *args, **kwargs): for field_name in existing - allowed: self.fields.pop(field_name) + class ScreeningSerializer(DynamicFieldsModelSerializer): class Meta: model = Screening - fields = '__all__' \ No newline at end of file + fields = '__all__' + diff --git a/activities/urls.py b/activities/urls.py index 14fb0c8190..77945646bf 100644 --- a/activities/urls.py +++ b/activities/urls.py @@ -1,7 +1,14 @@ +# rest framework imports from django.conf.urls import url, include, patterns - +# app imports from activities import views +__author__ = "Stuti Verma" +__credits__ = ["Sujit Chaurasia", "Sagar Singh"] +__maintainer__ = "Stuti Verma" +__email__ = "stuti@digitalgreen.org" +__status__ = "Development" + urlpatterns=[ url(r'^api/screening', views.ScreeningAPIView.as_view()), ] diff --git a/activities/views.py b/activities/views.py index 813ab7f14e..63ca1cf83f 100644 --- a/activities/views.py +++ b/activities/views.py @@ -1,23 +1,31 @@ +""" +This file consists of views for activities.models +""" # default imports from django.shortcuts import render -# model imports -from videos.models import * -from activities.models import * -# serializers imports -from activities.serializers import * -# drf imports +# rest framework imports from rest_framework import viewsets, generics from rest_framework import permissions from rest_framework.response import Response from rest_framework import status -# authentication +# app imports +from videos.models import * +from activities.models import * +from activities.serializers import * +# authentication imports from rest_framework.authentication import SessionAuthentication, BasicAuthentication, TokenAuthentication from rest_framework.permissions import IsAuthenticated -# logging, pagination and permissions +# logging, pagination and permission imports import time from api.utils import Utils, CustomPagination from api.permissions import IsAllowed +__author__ = "Stuti Verma" +__credits__ = ["Sujit Chaurasia", "Sagar Singh"] +__maintainer__ = "Stuti Verma" +__email__ = "stuti@digitalgreen.org" +__status__ = "Development" + class ScreeningAPIView( generics.ListCreateAPIView): ''' This view is specifically written for coco api access. @@ -34,7 +42,6 @@ class ScreeningAPIView( generics.ListCreateAPIView): pagination_class = CustomPagination serializer_class = ScreeningSerializer - # GET request def get(self, request): return Response({"detail":"Method \"GET\" not allowed"}) @@ -107,4 +114,5 @@ def post(self, request, *args, **kwargs): processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) # JSON Response is provided - return response \ No newline at end of file + return response + diff --git a/api/management/commands/insert_views_for_permissions.py b/api/management/commands/insert_views_for_permissions.py new file mode 100644 index 0000000000..b9fa5be9ec --- /dev/null +++ b/api/management/commands/insert_views_for_permissions.py @@ -0,0 +1,81 @@ +# django imports +from django.contrib.auth.models import Group +from django.core.management.base import BaseCommand, call_command +# csv imports +import unicodecsv as csv +# app imports +from api.views import CreateView +from api.models import View +from activities.views import ScreeningAPIView +from geographies.views import VillageAPIView, BlockAPIView, DistrictAPIView, StateAPIView, CountryAPIView, GeoInfoView +from people.views import FarmersJsonAPIView, FarmersCsvAPIView, FarmerInfoView +from programs.views import PartnerAPIView, ProjectAPIView +from videos.views import VideoAPIView + +__author__ = "Stuti Verma" +__credits__ = ["Sujit Chaurasia", "Sagar Singh"] +__maintainer__ = "Stuti Verma" +__email__ = "stuti@digitalgreen.org" +__status__ = "Development" + +# mapping of view class with group permitted to access it +PERMISSIONS_MAP = { + ScreeningAPIView.__name__: ['cocoadmin','api_access' ], + VillageAPIView.__name__: ['cocoadmin','api_access' ], + BlockAPIView.__name__: ['cocoadmin','api_access' ], + DistrictAPIView.__name__: ['cocoadmin','api_access' ], + StateAPIView.__name__: ['cocoadmin','api_access' ], + CountryAPIView.__name__: ['cocoadmin','api_access' ], + GeoInfoView.__name__: ['cocoadmin','api_access' ], + FarmersJsonAPIView.__name__: ['cocoadmin','api_access', 'AWAZDE'], + FarmersCsvAPIView.__name__: ['cocoadmin','api_access', 'AWAZDE' ], + FarmerInfoView.__name__: ['cocoadmin','api_access' ], + PartnerAPIView.__name__: ['cocoadmin','api_access' ], + ProjectAPIView.__name__: ['cocoadmin','api_access' ], + VideoAPIView.__name__: ['cocoadmin','api_access' ] +} + +class CreateViewAndAddGroups(self): + + def createAView(self, view_class): + ''' + This function adds a view to the database + ''' + + view = View(view_name = view_class) + view.save() + return + + def addAGroupByName(self, view_class_name, group_name): + ''' + This function adds a group to a view by view name to the database + ''' + + view = View.objects.get(view_name=view_class_name) + gr = Group.objects.get(name=group_name) + view.permission_groups.add(gr) + view.save() + return + + +class Command(BaseCommand): + """ + This class is used to add management commands to insert views in the database + """ + + def handle(self, *args, **options): + # error_file = open('/home/ubuntu/code/dg_git/api/management/commands/errors.csv', 'wb') + # wrtr = csv.writer(error_file, delimiter=',', quotechar='"') + createAdd = CreateViewAndAddGroups() + for key in PERMISSIONS_MAP.keys(): + view_name = key + group_list = PERMISSIONS_MAP[key] + for group_name in group_list: + try: + createAdd.createAView(view_name) + createAdd.addAGroupByName(view_name, group_name) + except Exception as e: + wrtr.writerow([key, "**insertion-error**", group_name), e]) + print(e, "**insertion-error") + + # error_file.close() diff --git a/api/models.py b/api/models.py index f91e6558fd..546f0b12d8 100644 --- a/api/models.py +++ b/api/models.py @@ -1,6 +1,11 @@ from django.db import models from django.contrib.auth.models import Group +__author__ = "Stuti Verma" +__credits__ = ["Sujit Chaurasia", "Sagar Singh"] +__maintainer__ = "Stuti Verma" +__email__ = "stuti@digitalgreen.org" +__status__ = "Development" class View(models.Model): ''' @@ -13,3 +18,4 @@ class View(models.Model): def __str__(self): "Returns the view name and groups names mapped together" return '%s, %s'%(self.view_name, self.permission_groups) + diff --git a/api/permissions.py b/api/permissions.py index dd4eab9482..64dcf8b06d 100644 --- a/api/permissions.py +++ b/api/permissions.py @@ -1,17 +1,24 @@ -# permissions -from rest_framework import permissions -# app +# rest framework imports +from rest_framework import viewsets, generics, status, permissions +from rest_framework.response import Response +# app imports from api.models import View -# logger +# logging imports import logging logger = logging logger = logging.getLogger('coco_api') - + +__author__ = "Stuti Verma" +__credits__ = ["Sujit Chaurasia", "Sagar Singh"] +__maintainer__ = "Stuti Verma" +__email__ = "stuti@digitalgreen.org" +__status__ = "Development" class IsAllowed(permissions.BasePermission): """ View-level permission to allow group-wise access to the view-based-apis. """ + def has_permission(self, request, view): view = View.objects.get(view_name=view.__class__.__name__) user_groups = request.user.groups.all() @@ -22,3 +29,4 @@ def has_permission(self, request, view): else: logger.info("Permission denied for view: %s to user: %s of groups: %s"%(view.view_name, request.user, user_groups)) return False + diff --git a/api/scripts.py b/api/scripts.py deleted file mode 100644 index 0b14998fbd..0000000000 --- a/api/scripts.py +++ /dev/null @@ -1,126 +0,0 @@ -# app -from api.views import CreateView -from api.models import View -from django.contrib.auth.models import Group -# view -from activities.views import ScreeningAPIView -from geographies.views import VillageAPIView, BlockAPIView, DistrictAPIView, StateAPIView, CountryAPIView - -''' -How to run this script? -Here's how: -1.) Open this project folder in a terminal -2.) Activate the required environment to run this project -3.) Run the following command in the terminal: - python manage.py shell -4.) Now you'll be able to see the IPython console -5.) Run the following command in the terminal: - %run api/scripts.py -6.) If you get any location errors, then try to check the current folder using pwd command -''' - -def createAView(view_class): - ''' - This function adds a view to the database - ''' - view = View(view_name = view_class) - view.save() - return - - -def addAGroupByName(view_class_name, group_name): - ''' - This function adds a group to a view by view name to the database - ''' - view = View.objects.get(view_name=view_class_name) - gr = Group.objects.get(name=group_name) - view.permission_groups.add(gr) - view.save() - return - - -def addAGroupByID(view_id, group_id): - ''' - This function adds a group to a view by view name to the database - ''' - view = View.objects.get(id__exact=view_id) - gr = Group.objects.get(id__exact=group_id) - view.permission_groups.add(gr) - view.save() - return - - -def addAGroupByViewID(view_id, group_name): - ''' - This function adds a group to a view by view id to the database - ''' - view = View.objects.get(id__exact=view_id) - gr = Group.objects.get(name=group_name) - view.permission_groups.add(gr) - view.save() - return - - -def addAGroupByGroupID(view_class_name, group_id): - ''' - This function adds a group to a view by view name to the database - ''' - view = View.objects.get(view_name=view_class_name) - gr = Group.objects.get(id__exact=group_id) - view.permission_groups.add(gr) - view.save() - return - - -if __name__=="__main__": - ''' - This function is available to be edited according to the required view to be added in the database - ''' - # # to add a single view - # view_class = VillageAPIView.__name__ - # createAView(view_class) - - - # # to add a group to a view by view name - # group_name = "coco_api_access" - # addAGroupByName(view_class, group_name) - - - # # to add a group to a view by view id - # group_name = "coco_api_access" - # addAGroupByID(view_id, group_name) - - - # # to create multiple views and assign a group - view_class_list = [DistrictAPIView.__name__, BlockAPIView.__name__] - group_id = 20 - for view in view_class_list: - createAView(view) - addAGroupByGroupID(view, group_id) - - - # # to add multiple views belonging to multiple groups - # permission map for views and allowed user groups - PERMISSIONS_MAP = { - 'ScreeningAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], - 'DefaultView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], - 'VillageAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], - 'BlockAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], - 'DistrictAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], - 'StateAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], - 'CountryAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], - 'FarmersJsonAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS', 'AWAAZDE_Group' ], - 'FarmersCsvAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], - 'PartnerAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], - 'ProjectAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], - 'VideoAPIView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], - 'CreateView': ['cocoadmin','COCOAPI_ALLOWED_USERS' ], - } - - # for key in PERMISSIONS_MAP.keys(): - # view_name = key - # group_list = PERMISSIONS_MAP[key] - # for group_name in group_list: - # createAView(view) - # addAGroupByName(view_name, group_name) - diff --git a/api/serializers.py b/api/serializers.py index fae7364c9d..fd6ebe6fa3 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -2,6 +2,12 @@ from django.contrib.auth.models import Group from models import View +__author__ = "Stuti Verma" +__credits__ = ["Sujit Chaurasia", "Sagar Singh"] +__maintainer__ = "Stuti Verma" +__email__ = "stuti@digitalgreen.org" +__status__ = "Development" + class ViewSerializer(serializers.Serializer): permission_group_id = serializers.CharField(source='permission_groups.id', read_only=True) diff --git a/api/utils.py b/api/utils.py index 348241dbcd..52ebf8f667 100644 --- a/api/utils.py +++ b/api/utils.py @@ -1,14 +1,17 @@ from django.contrib.auth.models import User from django.utils import importlib - import time import logging - -# pagination +# pagination imports from rest_framework import pagination from rest_framework.response import Response from collections import OrderedDict +__author__ = "Stuti Verma" +__credits__ = ["Sujit Chaurasia", "Sagar Singh"] +__maintainer__ = "Stuti Verma" +__email__ = "stuti@digitalgreen.org" +__status__ = "Development" class CustomPagination(pagination.PageNumberPagination): page_size = 2 @@ -24,8 +27,7 @@ def get_paginated_response(self, data): ('results', data) ])) - - + class Utils: def limitQueryset(self, queryset, start_limit, end_limit): @@ -36,11 +38,8 @@ def limitQueryset(self, queryset, start_limit, end_limit): queryset = queryset[int(start_limit)-1:] elif end_limit: # case3: only end_limit is present queryset = queryset[:int(end_limit)] - return queryset - - def logRequest(self, request, class_instance, view_fun, processing_time, status_code ): logger = logging.getLogger('coco_api') user_obj = User.objects.get(username=request.user) @@ -51,4 +50,4 @@ def logRequest(self, request, class_instance, view_fun, processing_time, status_ module_name = class_instance.__module__ # method_name = fun. logger.info("Accessed: %s.%s.%s, user_id: %s, username: %s, ip_address: %s, method: %s, processing_time: %s seconds, status_code: %s" % ( module_name, class_name, view_fun, user_id, user_obj, ip_addr, method, processing_time, status_code)) - \ No newline at end of file + diff --git a/geographies/apps.py b/geographies/apps.py index d16f1df571..dd836c6747 100644 --- a/geographies/apps.py +++ b/geographies/apps.py @@ -1,7 +1,5 @@ from __future__ import unicode_literals - from django.apps import AppConfig - class GeoConfig(AppConfig): name = 'geo' \ No newline at end of file diff --git a/geographies/models.py b/geographies/models.py index 6c1a3d456c..e7dac95337 100644 --- a/geographies/models.py +++ b/geographies/models.py @@ -73,6 +73,7 @@ def clean(self): post_save.connect(enter_to_log, sender=District) pre_delete.connect(enter_to_log, sender=District) + class Block(CocoModel): id = models.AutoField(primary_key=True) old_coco_id = models.BigIntegerField(editable=False, null=True) @@ -111,6 +112,7 @@ def get_partner(self): def __unicode__(self): return self.village_name + post_save.connect(save_log, sender = Village) pre_delete.connect(delete_log, sender = Village) diff --git a/geographies/serializers.py b/geographies/serializers.py index ed5fde76b8..c25f7dc7a5 100644 --- a/geographies/serializers.py +++ b/geographies/serializers.py @@ -1,6 +1,12 @@ from .models import * from rest_framework import serializers +__author__ = "Stuti Verma" +__credits__ = ["Sujit Chaurasia", "Sagar Singh"] +__maintainer__ = "Stuti Verma" +__email__ = "stuti@digitalgreen.org" +__status__ = "Development" + class DynamicFieldsModelSerializer(serializers.ModelSerializer): """ A ModelSerializer that takes an additional `fields` argument that @@ -21,11 +27,13 @@ def __init__(self, *args, **kwargs): for field_name in existing - allowed: self.fields.pop(field_name) + class CountrySerializer(DynamicFieldsModelSerializer): class Meta: model = Country fields = '__all__' + class StateSerializer(DynamicFieldsModelSerializer): country_id = serializers.IntegerField(source='country.id', read_only=True) country_name = serializers.CharField(source='country.country_name', read_only=True) @@ -34,6 +42,7 @@ class Meta: model = State fields = '__all__' + class DistrictSerializer(DynamicFieldsModelSerializer): country_id = serializers.IntegerField(source='state.country.id', read_only=True) country_name = serializers.CharField(source='state.country.country_name', read_only=True) @@ -44,6 +53,7 @@ class Meta: model = District fields = '__all__' + class BlockSerializer(DynamicFieldsModelSerializer): country_id = serializers.IntegerField(source='district.state.country.id', read_only=True) country_name = serializers.CharField(source='district.state.country.country_name', read_only=True) @@ -56,6 +66,7 @@ class Meta: model = Block fields = '__all__' + class VillageSerializer(DynamicFieldsModelSerializer): country_id = serializers.IntegerField(source='block.district.state.country.id', read_only=True) country_name = serializers.CharField(source='block.district.state.country.country_name', read_only=True) @@ -68,4 +79,6 @@ class VillageSerializer(DynamicFieldsModelSerializer): class Meta: model = Village - fields = '__all__' \ No newline at end of file + fields = '__all__' + + \ No newline at end of file diff --git a/geographies/urls.py b/geographies/urls.py index 10eb307718..ebff301371 100644 --- a/geographies/urls.py +++ b/geographies/urls.py @@ -1,9 +1,14 @@ from django.conf.urls import url, include - from geographies import views +__author__ = "Stuti Verma" +__credits__ = ["Sujit Chaurasia", "Sagar Singh"] +__maintainer__ = "Stuti Verma" +__email__ = "stuti@digitalgreen.org" +__status__ = "Development" + urlpatterns=[ - url(r'^api/default', views.DefaultView.as_view()), + url(r'^api/info', views.GeoInfoView.as_view()), url(r'^api/village', views.VillageAPIView.as_view()), url(r'^api/block', views.BlockAPIView.as_view()), url(r'^api/district', views.DistrictAPIView.as_view()), diff --git a/geographies/views.py b/geographies/views.py index b554a026a2..9e2591535a 100644 --- a/geographies/views.py +++ b/geographies/views.py @@ -1,28 +1,28 @@ -#default imports +# django imports from django.shortcuts import render - -# added imports +# rest framework imports from rest_framework import viewsets, generics from rest_framework import permissions from rest_framework.response import Response from rest_framework import status - -# serializers import -from geographies.serializers import * - -# model imports -from geographies.models import * - -# django-rest-framework TokenAuthentication imports +# rest framework TokenAuthentication imports from rest_framework.authentication import SessionAuthentication, BasicAuthentication, TokenAuthentication from rest_framework.permissions import IsAuthenticated - # logging, pagination and permissions import time from api.utils import Utils, CustomPagination from api.permissions import IsAllowed +# app imports +from geographies.serializers import * +from geographies.models import * -class DefaultView(generics.ListAPIView): +__author__ = "Stuti Verma" +__credits__ = ["Sujit Chaurasia", "Sagar Singh"] +__maintainer__ = "Stuti Verma" +__email__ = "stuti@digitalgreen.org" +__status__ = "Development" + +class GeoInfoView(generics.ListAPIView): ''' This view is specifically written for coco api access. This class-based view is to provide default message in JSON format. @@ -36,6 +36,10 @@ class DefaultView(generics.ListAPIView): authentication_classes = [TokenAuthentication] permission_classes =[IsAuthenticated and IsAllowed] + # GET request + def get(self, request, *args, **kwargs): + return Response({"detail":"Method \"GET\" not allowed"}) + # POST request def post(self, request): # dictionary results as JSON format message @@ -45,10 +49,7 @@ def post(self, request): "/geo/api/district", "/geo/api/state", "/geo/api/country"]}) - # GET request - def get(self, request, *args, **kwargs): - return Response({"detail":"Method \"GET\" not allowed"}) - + class VillageAPIView(generics.ListAPIView): ''' @@ -162,6 +163,7 @@ def post(self, request, *args, **kwargs): # JSON Response is provided return response + class DistrictAPIView(generics.ListAPIView): ''' This view is specifically written for coco api access. @@ -218,6 +220,7 @@ def post(self, request, *args, **kwargs): # JSON Response is provided return response + class StateAPIView(generics.ListAPIView): ''' This view is specifically written for coco api access. @@ -274,6 +277,7 @@ def post(self, request, *args, **kwargs): # JSON Response is provided return response + class CountryAPIView(generics.ListAPIView): ''' This view is specifically written for coco api access. @@ -328,4 +332,6 @@ def post(self, request, *args, **kwargs): processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) # JSON Response is provided - return response \ No newline at end of file + return response + + \ No newline at end of file diff --git a/loop/management/commands/Outliers.py b/loop/management/commands/Outliers.py index 4de29c1a61..07184b5e0e 100644 --- a/loop/management/commands/Outliers.py +++ b/loop/management/commands/Outliers.py @@ -100,4 +100,6 @@ def file_creator_per_case(self, from_to_date, case=''): create_xlsx(workbook, aggregator_wise_outliers, table_properties, table_position_to_start, worksheet_name) - return file_to_send \ No newline at end of file + return file_to_send + + \ No newline at end of file diff --git a/people/models.py b/people/models.py index 5288a3d79e..686233bbf5 100644 --- a/people/models.py +++ b/people/models.py @@ -9,6 +9,7 @@ from programs.models import Partner from training.log.training_log import enter_to_log + class Animator(CocoModel): id = models.AutoField(primary_key = True) old_coco_id = models.BigIntegerField(editable=False, null=True) @@ -48,6 +49,7 @@ class AnimatorAssignedVillage(CocoModel): village = models.ForeignKey(Village) start_date = models.DateField(null=True, blank=True) + class PersonGroup(CocoModel): id = models.AutoField(primary_key=True) old_coco_id = models.BigIntegerField(editable=False, null=True) @@ -64,6 +66,7 @@ def __unicode__(self): post_save.connect(save_log, sender=PersonGroup) pre_delete.connect(delete_log, sender=PersonGroup) + class Person(CocoModel): id = models.AutoField(primary_key=True) old_coco_id = models.BigIntegerField(editable=False, null=True) @@ -94,6 +97,7 @@ def __unicode__(self): post_save.connect(save_log, sender=Person) pre_delete.connect(delete_log, sender=Person) + class JSLPS_Animator(CocoModel): id = models.AutoField(primary_key=True) animator_code = models.CharField(max_length=100) @@ -108,6 +112,7 @@ class Meta: def __unicode__(self): return self.animator_code + class JSLPS_AnimatorAssignedVillage(CocoModel): id = models.AutoField(primary_key=True) animator = models.ForeignKey(JSLPS_Animator) @@ -118,6 +123,7 @@ class Meta: verbose_name = "JSLPS AnimatorAssignedVillage" verbose_name_plural = "JSLPS AnimatorAssignedVillage" + class JSLPS_Persongroup(CocoModel): id = models.AutoField(primary_key=True) group_code = models.CharField(max_length=100) @@ -128,6 +134,7 @@ class Meta: verbose_name = "JSLPS Persongroup" verbose_name_plural = "JSLPS Persongroup" + class JSLPS_Person(CocoModel): id = models.AutoField(primary_key=True) person_code = models.CharField(max_length=100) @@ -153,6 +160,7 @@ class Meta: def __unicode__(self): return self.animator_code + class AP_AnimatorAssignedVillage(CocoModel): animator = models.ForeignKey(AP_Animator) village = models.ForeignKey(AP_Village) @@ -162,7 +170,6 @@ class Meta: verbose_name_plural = "AP AnimatorAssignedVillage" - class AP_Person(CocoModel): person_code = models.CharField(max_length=100) person = models.ForeignKey(Person, null=True, blank=True) @@ -172,4 +179,3 @@ class Meta: verbose_name = "AP Person" verbose_name_plural = "AP Person" - diff --git a/people/serializers.py b/people/serializers.py index 67ea1bd6cb..31ad7b494c 100644 --- a/people/serializers.py +++ b/people/serializers.py @@ -3,6 +3,12 @@ from geographies.models import Village, Block, District, State, Country from geographies.serializers import VillageSerializer +__author__ = "Stuti Verma" +__credits__ = ["Sujit Chaurasia", "Sagar Singh"] +__maintainer__ = "Stuti Verma" +__email__ = "stuti@digitalgreen.org" +__status__ = "Development" + class DynamicFieldsModelSerializer(serializers.ModelSerializer): """ A ModelSerializer that takes an additional `fields` argument that @@ -41,17 +47,7 @@ class FarmerSerializer(DynamicFieldsModelSerializer): country_id = serializers.IntegerField(source='village.block.district.state.country.id', read_only=True) country_name = serializers.CharField(source='village.block.district.state.country.country_name', read_only=True) - F_count = serializers.SerializerMethodField() # added for visualization - class Meta: model = Person fields = '__all__' - - # returns 1 to indicate present of a Person object as a numeric field - def get_F_count(self, obj): - return 1 - - - - diff --git a/people/urls.py b/people/urls.py index 7aadb35e48..fd6e31c999 100644 --- a/people/urls.py +++ b/people/urls.py @@ -1,10 +1,18 @@ +# django imports from django.conf.urls import url, include - +# app imports from people import views +__author__ = "Stuti Verma" +__credits__ = ["Sujit Chaurasia", "Sagar Singh"] +__maintainer__ = "Stuti Verma" +__email__ = "stuti@digitalgreen.org" +__status__ = "Development" + urlpatterns=[ - url(r'^api/default', views.DefaultView.as_view()), + url(r'^api/info', views.FarmerInfoView.as_view()), url(r'^api/farmers', views.FarmersJsonAPIView.as_view({'post':'getAllFarmers'})), url(r'^api/match/phone', views.FarmersJsonAPIView.as_view({'post':'getPhoneMatchedResults'})), url(r'^api/csv', views.FarmersCsvAPIView.as_view({'post':'post'})), # r'^$' is used for regex of exact match as mentioned ] + diff --git a/people/views.py b/people/views.py index 9cb14466d4..e4dcabbed1 100644 --- a/people/views.py +++ b/people/views.py @@ -1,34 +1,33 @@ # default imports from django.shortcuts import render - -# added imports +# rest framework imports from rest_framework import viewsets, generics from rest_framework import permissions, filters from rest_framework.response import Response - -# serializers import +# app import from people.serializers import FarmerSerializer - -# model imports from people.models import * from geographies.models import * - # django-rest-framework TokenAuthentication imports from rest_framework.authentication import SessionAuthentication, BasicAuthentication, TokenAuthentication from rest_framework.permissions import IsAuthenticated - # CSV View imports from rest_framework.renderers import JSONRenderer from rest_framework.views import APIView from rest_framework.settings import api_settings from rest_framework_csv import renderers as r - # logging, pagination and permissions import time from api.utils import Utils, CustomPagination from api.permissions import IsAllowed -class DefaultView(generics.ListCreateAPIView): +__author__ = "Stuti Verma" +__credits__ = ["Sujit Chaurasia", "Sagar Singh"] +__maintainer__ = "Stuti Verma" +__email__ = "stuti@digitalgreen.org" +__status__ = "Development" + +class FarmerInfoView(generics.ListCreateAPIView): ''' This view is specifically written for coco api access. This class-based view is to provide default message in JSON format. @@ -69,7 +68,6 @@ class FarmersJsonAPIView(viewsets.GenericViewSet): pagination_class = CustomPagination serializer_class = FarmerSerializer - # GET request def get(self, request): return Response({"detail":"Method \"GET\" not allowed"}) @@ -191,7 +189,6 @@ class FarmersCsvAPIView(viewsets.GenericViewSet): permission_classes = [IsAuthenticated and IsAllowed] serializer_class = FarmerSerializer - # GET request def get(self, request): return Response({"detail":"Method \"GET\" not allowed"}) @@ -232,4 +229,6 @@ def post(self, request, *args, **kwargs): processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) # JSON Response is provided - return response \ No newline at end of file + return response + + \ No newline at end of file diff --git a/programs/models.py b/programs/models.py index 7b1665a352..17a625fee8 100644 --- a/programs/models.py +++ b/programs/models.py @@ -3,7 +3,6 @@ from django.db.models.signals import post_save, pre_delete from training.log.training_log import enter_to_log - class Partner(CocoModel): id = models.AutoField(primary_key=True) old_coco_id = models.BigIntegerField(editable=False, null=True, db_index=True) @@ -17,6 +16,7 @@ def __unicode__(self): post_save.connect(enter_to_log,sender=Partner) pre_delete.connect(enter_to_log,sender=Partner) + class Project(CocoModel): id = models.AutoField(primary_key=True) project_name = models.CharField(max_length=100, unique=True, help_text="Short Name of Project. It will be display on Analytics") @@ -27,3 +27,4 @@ class Project(CocoModel): def __unicode__(self): return self.project_name + diff --git a/programs/serializers.py b/programs/serializers.py index eb8e725f0f..d81697d518 100644 --- a/programs/serializers.py +++ b/programs/serializers.py @@ -1,6 +1,7 @@ from models import * from rest_framework import serializers + class DynamicFieldsModelSerializer(serializers.ModelSerializer): """ A ModelSerializer that takes an additional `fields` argument that @@ -21,12 +22,18 @@ def __init__(self, *args, **kwargs): for field_name in existing - allowed: self.fields.pop(field_name) + class PartnerSerializer(DynamicFieldsModelSerializer): + class Meta: model = Partner fields = '__all__' + class ProjectSerializer(DynamicFieldsModelSerializer): + class Meta: model = Project - fields = '__all__' \ No newline at end of file + fields = '__all__' + + \ No newline at end of file diff --git a/programs/urls.py b/programs/urls.py index dfc63c2662..3105563bf4 100644 --- a/programs/urls.py +++ b/programs/urls.py @@ -1,6 +1,5 @@ from django.conf.urls import url, include -from views import * - +from programs.views import * urlpatterns = [ @@ -9,4 +8,3 @@ ] - diff --git a/programs/views.py b/programs/views.py index b5c155e3af..3eec06a2e8 100644 --- a/programs/views.py +++ b/programs/views.py @@ -1,23 +1,20 @@ # default imports from django.shortcuts import render - # rest_framework imports from rest_framework import generics, viewsets from rest_framework.response import Response - # app imports from models import * from serializers import * - # authentication imports from rest_framework.authentication import TokenAuthentication from rest_framework.permissions import IsAuthenticated - # logging, pagination and permissions import time from api.utils import Utils, CustomPagination from api.permissions import IsAllowed + class PartnerAPIView(generics.ListCreateAPIView): ''' This view is specifically written for coco api access. @@ -34,7 +31,6 @@ class PartnerAPIView(generics.ListCreateAPIView): pagination_class = CustomPagination serializer_class = PartnerSerializer - # GET request def get(self, request): return Response({"detail":"Method \"GET\" not allowed"}) @@ -83,8 +79,6 @@ def getPartnerById(self, request, *args, **kwargs): return response - - class ProjectAPIView(generics.ListCreateAPIView): ''' This view is specifically written for coco api access. @@ -101,7 +95,6 @@ class ProjectAPIView(generics.ListCreateAPIView): pagination_class = CustomPagination serializer_class = ProjectSerializer - # GET request def get(self, request): return Response({"detail":"Method \"GET\" not allowed"}) @@ -145,4 +138,6 @@ def post(self, request, *args, **kwargs): processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) # JSON Response is provided - return response \ No newline at end of file + return response + + \ No newline at end of file diff --git a/videos/models.py b/videos/models.py index b7e2d7531f..33e7fc7bb8 100644 --- a/videos/models.py +++ b/videos/models.py @@ -238,6 +238,7 @@ def location(self): post_save.connect(save_log, sender=Video) pre_delete.connect(delete_log, sender=Video) + class NonNegotiable(CocoModel): id = models.AutoField(primary_key=True) video = models.ForeignKey(Video) diff --git a/videos/serializers.py b/videos/serializers.py index 753de452f7..9b1061fc7b 100644 --- a/videos/serializers.py +++ b/videos/serializers.py @@ -1,5 +1,11 @@ -from .models import * from rest_framework import serializers +from videos.models import * + +__author__ = "Stuti Verma" +__credits__ = ["Sujit Chaurasia", "Sagar Singh"] +__maintainer__ = "Stuti Verma" +__email__ = "stuti@digitalgreen.org" +__status__ = "Development" class DynamicFieldsModelSerializer(serializers.ModelSerializer): """ @@ -21,6 +27,7 @@ def __init__(self, *args, **kwargs): for field_name in existing - allowed: self.fields.pop(field_name) + class VideoSerializer(DynamicFieldsModelSerializer): class Meta: model = Video diff --git a/videos/urls.py b/videos/urls.py index 7085ccc4f4..0448fdd12e 100644 --- a/videos/urls.py +++ b/videos/urls.py @@ -1,23 +1,17 @@ +# django imports from django.conf.urls import include, patterns, url from django.views.generic import TemplateView from django.views.generic.base import RedirectView - -from social_website.views import collection_view, video_view, search_view, collection_edit_view, collection_add_view, partner_view -from social_website.urls import DirectTemplateView - +# app imports from output.views import video_analytics - from dg.base_settings import VIDEOS_PAGE from dg.website_admin import website_admin - +from social_website.views import collection_view, video_view, search_view, collection_edit_view, collection_add_view, partner_view +from social_website.urls import DirectTemplateView from activities import urls as acturls - import videokheti.urls - -# coco_api specific import from videos import views - urlpatterns = patterns('', url(r'^$', RedirectView.as_view(url=VIDEOS_PAGE)), url(r'^collection-add/(?P.+)/$', collection_edit_view, name='edit_collection'), @@ -36,7 +30,7 @@ (r'^admin/', include(website_admin.urls)), # coco_api video urls - # as_view method takes type of request as key and class's method name as value url(r'^api/video', views.VideoAPIView.as_view()), ) + diff --git a/videos/views.py b/videos/views.py index 0b621d2758..e19ac46ecf 100644 --- a/videos/views.py +++ b/videos/views.py @@ -1,26 +1,25 @@ -#default +# django imports from django.shortcuts import render - -# model imports -from videos.models import * - -# serializers imports -from videos.serializers import * - -# drf imports +# rest framework imports from rest_framework import viewsets, generics from rest_framework import permissions from rest_framework.response import Response - # django-rest-framework TokenAuthentication imports from rest_framework.authentication import SessionAuthentication, BasicAuthentication, TokenAuthentication from rest_framework.permissions import IsAuthenticated - # logging, pagination and permissions import time from api.utils import Utils, CustomPagination from api.permissions import IsAllowed +# app imports +from videos.models import * +from videos.serializers import * +__author__ = "Stuti Verma" +__credits__ = ["Sujit Chaurasia", "Sagar Singh"] +__maintainer__ = "Stuti Verma" +__email__ = "stuti@digitalgreen.org" +__status__ = "Development" class VideoAPIView(generics.ListCreateAPIView): ''' @@ -80,4 +79,5 @@ def post(self, request, *args, **kwargs): processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) # JSON Response is provided - return response \ No newline at end of file + return response + From 2c9f352c58b630cdb16e87e73ce9a4348ddac365 Mon Sep 17 00:00:00 2001 From: vermastuti Date: Thu, 11 Jun 2020 22:10:43 +0530 Subject: [PATCH 25/35] code-review-changes --- activities/serializers.py | 26 ++-------- activities/urls.py | 1 - activities/views.py | 10 ++-- .../commands/insert_views_for_permissions.py | 4 +- api/models.py | 1 - api/permissions.py | 1 - api/serializers.py | 7 ++- api/utils.py | 47 +++++++++++++++++-- dg/base_settings.py | 3 +- geographies/models.py | 1 - geographies/serializers.py | 41 ++++++++-------- geographies/urls.py | 1 - geographies/views.py | 3 -- people/models.py | 1 - people/serializers.py | 24 ++-------- people/urls.py | 1 - people/views.py | 1 - programs/serializers.py | 31 ++++-------- programs/views.py | 4 +- videos/serializers.py | 23 ++------- videos/urls.py | 1 - videos/views.py | 1 - 22 files changed, 96 insertions(+), 137 deletions(-) diff --git a/activities/serializers.py b/activities/serializers.py index ef19f967a0..8e5ad79253 100644 --- a/activities/serializers.py +++ b/activities/serializers.py @@ -1,37 +1,19 @@ # rest framework imports from rest_framework import serializers # app imports -from .models import Screening +from activities.models import Screening +from api.utils import DynamicFieldsModelSerializer __author__ = "Stuti Verma" __credits__ = ["Sujit Chaurasia", "Sagar Singh"] -__maintainer__ = "Stuti Verma" __email__ = "stuti@digitalgreen.org" __status__ = "Development" -class DynamicFieldsModelSerializer(serializers.ModelSerializer): +class ScreeningSerializer(DynamicFieldsModelSerializer): """ - A ModelSerializer that takes an additional `fields` argument that - controls which fields should be displayed. + Serializer class inherited from DynamicFieldsModelSerializer for Screening model """ - def __init__(self, *args, **kwargs): - # Don't pass the 'fields' arg up to the superclass - fields = kwargs.pop('fields', None) - - # Instantiate the superclass normally - super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs) - - if fields is not None: - # Drop any fields that are not specified in the `fields` argument. - allowed = set(fields) - existing = set(self.fields) - for field_name in existing - allowed: - self.fields.pop(field_name) - - -class ScreeningSerializer(DynamicFieldsModelSerializer): class Meta: model = Screening fields = '__all__' - diff --git a/activities/urls.py b/activities/urls.py index 77945646bf..68722b5547 100644 --- a/activities/urls.py +++ b/activities/urls.py @@ -5,7 +5,6 @@ __author__ = "Stuti Verma" __credits__ = ["Sujit Chaurasia", "Sagar Singh"] -__maintainer__ = "Stuti Verma" __email__ = "stuti@digitalgreen.org" __status__ = "Development" diff --git a/activities/views.py b/activities/views.py index 63ca1cf83f..d35c70df14 100644 --- a/activities/views.py +++ b/activities/views.py @@ -22,7 +22,6 @@ __author__ = "Stuti Verma" __credits__ = ["Sujit Chaurasia", "Sagar Singh"] -__maintainer__ = "Stuti Verma" __email__ = "stuti@digitalgreen.org" __status__ = "Development" @@ -68,22 +67,22 @@ def post(self, request, *args, **kwargs): if start_day and start_month and start_year and end_day and end_month and end_year: # params type value is string, trimmed spaces,convert to int and then make date by combining values try: - start_date = datetime.date(int(start_year.strip()),int(start_month.strip()), int(start_day.strip())) - end_date = datetime.date(int(end_year.strip()),int(end_month.strip()), int(end_day.strip())) + start_date = datetime.date(int(start_year.strip()), int(start_month.strip()), int(start_day.strip())) + end_date = datetime.date(int(end_year.strip()), int(end_month.strip()), int(end_day.strip())) queryset = queryset.filter(date__range=(start_date, end_date)) # filters values in date range except: print("Date error occurred") # case2: only start values are present elif start_day and start_month and start_year and not end_day and not end_month and not end_year: try: - start_date = datetime.date(int(start_year.strip()),int(start_month.strip()), int(start_day.strip())) + start_date = datetime.date(int(start_year.strip()), int(start_month.strip()), int(start_day.strip())) queryset = queryset.filter(date__gte=start_date) # filters values greater than or equal to start date except: print("Start Date error occurred") # case3: only end values are present elif not start_day and not start_month and not start_year and end_day and end_month and end_year: try: - end_date = datetime.date(int(end_year.strip()),int(end_month.strip()), int(end_day.strip())) + end_date = datetime.date(int(end_year.strip()), int(end_month.strip()), int(end_day.strip())) queryset = queryset.filter(date__lte=end_date) # filters values less than or equal to end date except: print("End Date error occurred") @@ -115,4 +114,3 @@ def post(self, request, *args, **kwargs): utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) # JSON Response is provided return response - diff --git a/api/management/commands/insert_views_for_permissions.py b/api/management/commands/insert_views_for_permissions.py index b9fa5be9ec..a113b24432 100644 --- a/api/management/commands/insert_views_for_permissions.py +++ b/api/management/commands/insert_views_for_permissions.py @@ -14,7 +14,6 @@ __author__ = "Stuti Verma" __credits__ = ["Sujit Chaurasia", "Sagar Singh"] -__maintainer__ = "Stuti Verma" __email__ = "stuti@digitalgreen.org" __status__ = "Development" @@ -36,6 +35,9 @@ } class CreateViewAndAddGroups(self): + """ + Class to create views and add groups for View model + """ def createAView(self, view_class): ''' diff --git a/api/models.py b/api/models.py index 546f0b12d8..d46e6324f2 100644 --- a/api/models.py +++ b/api/models.py @@ -3,7 +3,6 @@ __author__ = "Stuti Verma" __credits__ = ["Sujit Chaurasia", "Sagar Singh"] -__maintainer__ = "Stuti Verma" __email__ = "stuti@digitalgreen.org" __status__ = "Development" diff --git a/api/permissions.py b/api/permissions.py index 64dcf8b06d..02e2e243e7 100644 --- a/api/permissions.py +++ b/api/permissions.py @@ -10,7 +10,6 @@ __author__ = "Stuti Verma" __credits__ = ["Sujit Chaurasia", "Sagar Singh"] -__maintainer__ = "Stuti Verma" __email__ = "stuti@digitalgreen.org" __status__ = "Development" diff --git a/api/serializers.py b/api/serializers.py index fd6ebe6fa3..d865f874e9 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -4,11 +4,13 @@ __author__ = "Stuti Verma" __credits__ = ["Sujit Chaurasia", "Sagar Singh"] -__maintainer__ = "Stuti Verma" __email__ = "stuti@digitalgreen.org" __status__ = "Development" class ViewSerializer(serializers.Serializer): + """ + Serializer class for View model + """ permission_group_id = serializers.CharField(source='permission_groups.id', read_only=True) permission_group_name = serializers.CharField(source='permission_groups.name', read_only=True) @@ -19,6 +21,9 @@ class Meta: class GroupSerializer(serializers.Serializer): + """ + Serializer class for Group model + """ class Meta: model = Group diff --git a/api/utils.py b/api/utils.py index 52ebf8f667..44930f219c 100644 --- a/api/utils.py +++ b/api/utils.py @@ -1,24 +1,30 @@ +# django imports from django.contrib.auth.models import User from django.utils import importlib +# python imports import time import logging -# pagination imports -from rest_framework import pagination -from rest_framework.response import Response from collections import OrderedDict +# rest framework imports +from rest_framework import pagination, serializers +from rest_framework.response import Response __author__ = "Stuti Verma" __credits__ = ["Sujit Chaurasia", "Sagar Singh"] -__maintainer__ = "Stuti Verma" __email__ = "stuti@digitalgreen.org" __status__ = "Development" class CustomPagination(pagination.PageNumberPagination): + """ + Pagination class to paginate queryset + """ + page_size = 2 page_size_query_param = 'page_size' page_query_param = 'page' max_page_size = 5 + # overriding of method to get customised paginated response def get_paginated_response(self, data): return Response(OrderedDict([ ('count', self.page.paginator.count), @@ -27,11 +33,38 @@ def get_paginated_response(self, data): ('results', data) ])) + +class DynamicFieldsModelSerializer(serializers.ModelSerializer): + """ + A ModelSerializer that takes an additional `fields` argument that + controls which fields should be displayed. + """ + + def __init__(self, *args, **kwargs): + # Don't pass the 'fields' arg up to the superclass + fields = kwargs.pop('fields', None) + + # Instantiate the superclass normally + super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs) + + if fields is not None: + # Drop any fields that are not specified in the `fields` argument. + allowed = set(fields) + existing = set(self.fields) + for field_name in existing - allowed: + self.fields.pop(field_name) + class Utils: + """ + Utility class for api + """ def limitQueryset(self, queryset, start_limit, end_limit): - # limits the total response count + """ + limits the total response count + """ + if start_limit and end_limit: # case1: both are present queryset = queryset[int(start_limit)-1:int(end_limit)] elif start_limit: # case2: only start_limit is present @@ -41,6 +74,10 @@ def limitQueryset(self, queryset, start_limit, end_limit): return queryset def logRequest(self, request, class_instance, view_fun, processing_time, status_code ): + """ + Logs the request, username and other details + """ + logger = logging.getLogger('coco_api') user_obj = User.objects.get(username=request.user) ip_addr = request.META['REMOTE_ADDR'] diff --git a/dg/base_settings.py b/dg/base_settings.py index 445e4deeda..4c2faccabc 100644 --- a/dg/base_settings.py +++ b/dg/base_settings.py @@ -149,6 +149,7 @@ 'people', 'videos', 'activities', + 'api', #'debug_toolbar', 'output', 'django.contrib.humanize', @@ -187,10 +188,8 @@ 'loop_ivr', 'dataexport', 'rest_framework', - 'api', # 3rd Party 'django_extensions', - #drf TokenAuthentication 'rest_framework.authtoken', ) diff --git a/geographies/models.py b/geographies/models.py index e7dac95337..c521086db7 100644 --- a/geographies/models.py +++ b/geographies/models.py @@ -1,7 +1,6 @@ from django.core.validators import MaxValueValidator, MinValueValidator from django.db import models from django.db.models.signals import pre_delete, post_save - from coco.base_models import CocoModel, ACTIVITY_CHOICES from coco.data_log import delete_log, save_log from farmerbook.managers import VillageFarmerbookManager diff --git a/geographies/serializers.py b/geographies/serializers.py index c25f7dc7a5..59f811318e 100644 --- a/geographies/serializers.py +++ b/geographies/serializers.py @@ -1,40 +1,27 @@ -from .models import * from rest_framework import serializers +from geographies.models import Country, State, District, Block, Village +from api.utils import DynamicFieldsModelSerializer __author__ = "Stuti Verma" __credits__ = ["Sujit Chaurasia", "Sagar Singh"] -__maintainer__ = "Stuti Verma" __email__ = "stuti@digitalgreen.org" __status__ = "Development" -class DynamicFieldsModelSerializer(serializers.ModelSerializer): +class CountrySerializer(DynamicFieldsModelSerializer): """ - A ModelSerializer that takes an additional `fields` argument that - controls which fields should be displayed. + Serializer class inherited from DynamicFieldsModelSerializer for Country model """ - def __init__(self, *args, **kwargs): - # Don't pass the 'fields' arg up to the superclass - fields = kwargs.pop('fields', None) - - # Instantiate the superclass normally - super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs) - - if fields is not None: - # Drop any fields that are not specified in the `fields` argument. - allowed = set(fields) - existing = set(self.fields) - for field_name in existing - allowed: - self.fields.pop(field_name) - - -class CountrySerializer(DynamicFieldsModelSerializer): class Meta: model = Country fields = '__all__' class StateSerializer(DynamicFieldsModelSerializer): + """ + Serializer class inherited from DynamicFieldsModelSerializer for State model + """ + country_id = serializers.IntegerField(source='country.id', read_only=True) country_name = serializers.CharField(source='country.country_name', read_only=True) @@ -44,6 +31,10 @@ class Meta: class DistrictSerializer(DynamicFieldsModelSerializer): + """ + Serializer class inherited from DynamicFieldsModelSerializer for District model + """ + country_id = serializers.IntegerField(source='state.country.id', read_only=True) country_name = serializers.CharField(source='state.country.country_name', read_only=True) state_id = serializers.IntegerField(source='state.id', read_only=True) @@ -55,6 +46,10 @@ class Meta: class BlockSerializer(DynamicFieldsModelSerializer): + """ + Serializer class inherited from DynamicFieldsModelSerializer for Block model + """ + country_id = serializers.IntegerField(source='district.state.country.id', read_only=True) country_name = serializers.CharField(source='district.state.country.country_name', read_only=True) state_id = serializers.IntegerField(source='district.state.id', read_only=True) @@ -68,6 +63,10 @@ class Meta: class VillageSerializer(DynamicFieldsModelSerializer): + """ + Serializer class inherited from DynamicFieldsModelSerializer for Village model + """ + country_id = serializers.IntegerField(source='block.district.state.country.id', read_only=True) country_name = serializers.CharField(source='block.district.state.country.country_name', read_only=True) state_id = serializers.IntegerField(source='block.district.state.id', read_only=True) diff --git a/geographies/urls.py b/geographies/urls.py index ebff301371..c5f339539d 100644 --- a/geographies/urls.py +++ b/geographies/urls.py @@ -3,7 +3,6 @@ __author__ = "Stuti Verma" __credits__ = ["Sujit Chaurasia", "Sagar Singh"] -__maintainer__ = "Stuti Verma" __email__ = "stuti@digitalgreen.org" __status__ = "Development" diff --git a/geographies/views.py b/geographies/views.py index 9e2591535a..24b58de268 100644 --- a/geographies/views.py +++ b/geographies/views.py @@ -18,7 +18,6 @@ __author__ = "Stuti Verma" __credits__ = ["Sujit Chaurasia", "Sagar Singh"] -__maintainer__ = "Stuti Verma" __email__ = "stuti@digitalgreen.org" __status__ = "Development" @@ -333,5 +332,3 @@ def post(self, request, *args, **kwargs): utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) # JSON Response is provided return response - - \ No newline at end of file diff --git a/people/models.py b/people/models.py index 686233bbf5..0b27cf4372 100644 --- a/people/models.py +++ b/people/models.py @@ -1,6 +1,5 @@ from django.db import models from django.db.models.signals import pre_delete, post_save - from coco.data_log import delete_log, save_log from coco.base_models import CocoModel, DAY_CHOICES, GENDER_CHOICES, TYPE_OF_ROLE from farmerbook.managers import FarmerbookManager diff --git a/people/serializers.py b/people/serializers.py index 31ad7b494c..69f31f1d1b 100644 --- a/people/serializers.py +++ b/people/serializers.py @@ -2,36 +2,18 @@ from rest_framework import serializers from geographies.models import Village, Block, District, State, Country from geographies.serializers import VillageSerializer +from api.utils import DynamicFieldsModelSerializer __author__ = "Stuti Verma" __credits__ = ["Sujit Chaurasia", "Sagar Singh"] -__maintainer__ = "Stuti Verma" __email__ = "stuti@digitalgreen.org" __status__ = "Development" -class DynamicFieldsModelSerializer(serializers.ModelSerializer): +class FarmerSerializer(DynamicFieldsModelSerializer): """ - A ModelSerializer that takes an additional `fields` argument that - controls which fields should be displayed. + Serializer class inherited from DynamicFieldsModelSerializer for Village model """ - def __init__(self, *args, **kwargs): - # Don't pass the 'fields' arg up to the superclass - fields = kwargs.pop('fields', None) - - # Instantiate the superclass normally - super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs) - - if fields is not None: - # Drop any fields that are not specified in the `fields` argument. - allowed = set(fields) - existing = set(self.fields) - for field_name in existing - allowed: - self.fields.pop(field_name) - - -class FarmerSerializer(DynamicFieldsModelSerializer): - village_id = serializers.CharField(source='village.id', read_only=True) village = serializers.CharField(source='village.village_name', read_only=True) diff --git a/people/urls.py b/people/urls.py index fd6e31c999..e2aa06edcf 100644 --- a/people/urls.py +++ b/people/urls.py @@ -5,7 +5,6 @@ __author__ = "Stuti Verma" __credits__ = ["Sujit Chaurasia", "Sagar Singh"] -__maintainer__ = "Stuti Verma" __email__ = "stuti@digitalgreen.org" __status__ = "Development" diff --git a/people/views.py b/people/views.py index e4dcabbed1..32274c1cc1 100644 --- a/people/views.py +++ b/people/views.py @@ -23,7 +23,6 @@ __author__ = "Stuti Verma" __credits__ = ["Sujit Chaurasia", "Sagar Singh"] -__maintainer__ = "Stuti Verma" __email__ = "stuti@digitalgreen.org" __status__ = "Development" diff --git a/programs/serializers.py b/programs/serializers.py index d81697d518..c8e620cfd0 100644 --- a/programs/serializers.py +++ b/programs/serializers.py @@ -1,37 +1,22 @@ -from models import * +from programs.models import * from rest_framework import serializers +from api.utils import DynamicFieldsModelSerializer - -class DynamicFieldsModelSerializer(serializers.ModelSerializer): +class PartnerSerializer(DynamicFieldsModelSerializer): """ - A ModelSerializer that takes an additional `fields` argument that - controls which fields should be displayed. + Serializer class inherited from DynamicFieldsModelSerializer for Partner model """ - def __init__(self, *args, **kwargs): - # Don't pass the 'fields' arg up to the superclass - fields = kwargs.pop('fields', None) - - # Instantiate the superclass normally - super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs) - - if fields is not None: - # Drop any fields that are not specified in the `fields` argument. - allowed = set(fields) - existing = set(self.fields) - for field_name in existing - allowed: - self.fields.pop(field_name) - - -class PartnerSerializer(DynamicFieldsModelSerializer): - class Meta: model = Partner fields = '__all__' class ProjectSerializer(DynamicFieldsModelSerializer): - + """ + Serializer class inherited from DynamicFieldsModelSerializer for Project model + """ + class Meta: model = Project fields = '__all__' diff --git a/programs/views.py b/programs/views.py index 3eec06a2e8..564066d7ac 100644 --- a/programs/views.py +++ b/programs/views.py @@ -4,8 +4,8 @@ from rest_framework import generics, viewsets from rest_framework.response import Response # app imports -from models import * -from serializers import * +from programs.models import * +from programs.serializers import * # authentication imports from rest_framework.authentication import TokenAuthentication from rest_framework.permissions import IsAuthenticated diff --git a/videos/serializers.py b/videos/serializers.py index 9b1061fc7b..8855efa98d 100644 --- a/videos/serializers.py +++ b/videos/serializers.py @@ -1,34 +1,17 @@ from rest_framework import serializers from videos.models import * +from api.utils import DynamicFieldsModelSerializer __author__ = "Stuti Verma" __credits__ = ["Sujit Chaurasia", "Sagar Singh"] -__maintainer__ = "Stuti Verma" __email__ = "stuti@digitalgreen.org" __status__ = "Development" -class DynamicFieldsModelSerializer(serializers.ModelSerializer): +class VideoSerializer(DynamicFieldsModelSerializer): """ - A ModelSerializer that takes an additional `fields` argument that - controls which fields should be displayed. + Serializer class inherited from DynamicFieldsModelSerializer for Video model """ - def __init__(self, *args, **kwargs): - # Don't pass the 'fields' arg up to the superclass - fields = kwargs.pop('fields', None) - - # Instantiate the superclass normally - super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs) - - if fields is not None: - # Drop any fields that are not specified in the `fields` argument. - allowed = set(fields) - existing = set(self.fields) - for field_name in existing - allowed: - self.fields.pop(field_name) - - -class VideoSerializer(DynamicFieldsModelSerializer): class Meta: model = Video fields = '__all__' diff --git a/videos/urls.py b/videos/urls.py index 0448fdd12e..ddf3ce8b14 100644 --- a/videos/urls.py +++ b/videos/urls.py @@ -8,7 +8,6 @@ from dg.website_admin import website_admin from social_website.views import collection_view, video_view, search_view, collection_edit_view, collection_add_view, partner_view from social_website.urls import DirectTemplateView -from activities import urls as acturls import videokheti.urls from videos import views diff --git a/videos/views.py b/videos/views.py index e19ac46ecf..ea95f99fa4 100644 --- a/videos/views.py +++ b/videos/views.py @@ -17,7 +17,6 @@ __author__ = "Stuti Verma" __credits__ = ["Sujit Chaurasia", "Sagar Singh"] -__maintainer__ = "Stuti Verma" __email__ = "stuti@digitalgreen.org" __status__ = "Development" From 4f4f03bcd8ab016eca3bf30f26b1986aa5fadafb Mon Sep 17 00:00:00 2001 From: vermastuti Date: Sat, 13 Jun 2020 20:17:01 +0530 Subject: [PATCH 26/35] function-comments --- activities/views.py | 55 ++++-- api/management/__init__.py | 0 api/management/commands/__init__.py | 0 .../commands/insert_views_for_permissions.py | 61 +++---- api/permissions.py | 8 +- api/utils.py | 15 +- geographies/views.py | 172 +++++++++++++----- people/views.py | 90 ++++++--- programs/views.py | 77 +++++--- videos/views.py | 30 ++- 10 files changed, 337 insertions(+), 171 deletions(-) create mode 100644 api/management/__init__.py create mode 100644 api/management/commands/__init__.py diff --git a/activities/views.py b/activities/views.py index d35c70df14..34fa3d1d9c 100644 --- a/activities/views.py +++ b/activities/views.py @@ -47,21 +47,38 @@ def get(self, request): # POST request def post(self, request, *args, **kwargs): + """ + This function can take following optional POST params to filter on Screening obects: + user_created_id - this is id associated with CoCoModel inherited by Screening model, + start_day - takes day part value of a search in date range, + start_month - takes month part value of a search in date range, + start_year - takes year part value of a search in date range, + end_day - takes day part value of a search in date range, + end_month - takes month part value of a search in date range, + end_year - takes year part value of a search in date range, + fields - to pass comma separated value to be returned a value for each Screening object, e.g. pass + fields value as id,user_created to get only these key-value pairs for each Screening object + + If none of the above parameters are provided, then all the objects from respective model + will be sent to the response. + """ + start_time = time.time() utils = Utils() queryset = Screening.objects.get_queryset().order_by('id') - - uc_id = request.POST.get('user_created') # POST param 'user_created', default value is empty string - if uc_id: - queryset = queryset.filter(user_created__exact=uc_id) # filters for numeric values with exact match - + start_day = request.POST.get('start_day') start_month = request.POST.get('start_month') start_year = request.POST.get('start_year') - end_day = request.POST.get('1end_day') + end_day = request.POST.get('end_day') end_month = request.POST.get('end_month') end_year = request.POST.get('end_year') + fields_values = request.POST.get('fields', '') # POST param 'fields', default value is empty string + uc_id = request.POST.get('user_created_id') # POST param 'user_created', default value is empty string + + if uc_id: + queryset = queryset.filter(user_created__exact=uc_id) # filters for numeric values with exact match # case1: all values are present if start_day and start_month and start_year and end_day and end_month and end_year: @@ -71,34 +88,26 @@ def post(self, request, *args, **kwargs): end_date = datetime.date(int(end_year.strip()), int(end_month.strip()), int(end_day.strip())) queryset = queryset.filter(date__range=(start_date, end_date)) # filters values in date range except: - print("Date error occurred") + utils.logMessage(self, self.post.__name__, "Date error occurred") # case2: only start values are present elif start_day and start_month and start_year and not end_day and not end_month and not end_year: try: start_date = datetime.date(int(start_year.strip()), int(start_month.strip()), int(start_day.strip())) queryset = queryset.filter(date__gte=start_date) # filters values greater than or equal to start date except: - print("Start Date error occurred") + utils.logMessage(self, self.post.__name__, "Start Date error occurred") # case3: only end values are present - elif not start_day and not start_month and not start_year and end_day and end_month and end_year: + elif not start_day and not start_month and not start_year and end_day and end_month and end_year: try: end_date = datetime.date(int(end_year.strip()), int(end_month.strip()), int(end_day.strip())) queryset = queryset.filter(date__lte=end_date) # filters values less than or equal to end date except: - print("End Date error occurred") - - fields_values = request.POST.get('fields', '') # POST param 'fields', default value is empty string - if fields_values: # fields provided in POST request and if not empty serves those fields only - fields_values = [val.strip() for val in fields_values.split(",")] - # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer - serializer = ScreeningSerializer(queryset, fields=fields_values, many=True) - else: - # if fields param is empty then all the fields as mentioned in serializer are served to the response - serializer = ScreeningSerializer(queryset, many=True) + utils.logMessage(self, self.post.__name__, "End Date error occurred") page = self.paginate_queryset(queryset) if page is not None: if fields_values: # fields provided in POST request and if not empty serves those fields only + fields_values = [val.strip() for val in fields_values.split(",")] # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer serializer = self.get_serializer(page, fields=fields_values, many=True) else: @@ -108,6 +117,14 @@ def post(self, request, *args, **kwargs): processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) return paginated_response + + if fields_values: # fields provided in POST request and if not empty serves those fields only + fields_values = [val.strip() for val in fields_values.split(",")] + # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer + serializer = ScreeningSerializer(queryset, fields=fields_values, many=True) + else: + # if fields param is empty then all the fields as mentioned in serializer are served to the response + serializer = ScreeningSerializer(queryset, many=True) response = Response(serializer.data) processing_time = time.time() - start_time diff --git a/api/management/__init__.py b/api/management/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/api/management/commands/__init__.py b/api/management/commands/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/api/management/commands/insert_views_for_permissions.py b/api/management/commands/insert_views_for_permissions.py index a113b24432..daa1ee89d6 100644 --- a/api/management/commands/insert_views_for_permissions.py +++ b/api/management/commands/insert_views_for_permissions.py @@ -1,10 +1,9 @@ # django imports from django.contrib.auth.models import Group -from django.core.management.base import BaseCommand, call_command +from django.core.management.base import BaseCommand # csv imports import unicodecsv as csv # app imports -from api.views import CreateView from api.models import View from activities.views import ScreeningAPIView from geographies.views import VillageAPIView, BlockAPIView, DistrictAPIView, StateAPIView, CountryAPIView, GeoInfoView @@ -17,24 +16,24 @@ __email__ = "stuti@digitalgreen.org" __status__ = "Development" -# mapping of view class with group permitted to access it -PERMISSIONS_MAP = { - ScreeningAPIView.__name__: ['cocoadmin','api_access' ], - VillageAPIView.__name__: ['cocoadmin','api_access' ], - BlockAPIView.__name__: ['cocoadmin','api_access' ], - DistrictAPIView.__name__: ['cocoadmin','api_access' ], - StateAPIView.__name__: ['cocoadmin','api_access' ], - CountryAPIView.__name__: ['cocoadmin','api_access' ], - GeoInfoView.__name__: ['cocoadmin','api_access' ], - FarmersJsonAPIView.__name__: ['cocoadmin','api_access', 'AWAZDE'], - FarmersCsvAPIView.__name__: ['cocoadmin','api_access', 'AWAZDE' ], - FarmerInfoView.__name__: ['cocoadmin','api_access' ], - PartnerAPIView.__name__: ['cocoadmin','api_access' ], - ProjectAPIView.__name__: ['cocoadmin','api_access' ], - VideoAPIView.__name__: ['cocoadmin','api_access' ] +# add a view in this list to insert it in database +VIEWS_LIST = { + ScreeningAPIView.__name__, + VillageAPIView.__name__, + BlockAPIView.__name__, + DistrictAPIView.__name__, + StateAPIView.__name__, + CountryAPIView.__name__, + GeoInfoView.__name__, + FarmersJsonAPIView.__name__, + FarmersCsvAPIView.__name__, + FarmerInfoView.__name__, + PartnerAPIView.__name__, + ProjectAPIView.__name__, + VideoAPIView.__name__, } -class CreateViewAndAddGroups(self): +class CreateViewAndAddGroups(): """ Class to create views and add groups for View model """ @@ -66,18 +65,18 @@ class Command(BaseCommand): """ def handle(self, *args, **options): - # error_file = open('/home/ubuntu/code/dg_git/api/management/commands/errors.csv', 'wb') - # wrtr = csv.writer(error_file, delimiter=',', quotechar='"') + prod_path = '/home/ubuntu/code/dg_git/api/management/commands/errors.csv' + local_path = '/Users/stuti/Desktop/dg/api/management/commands/errors.csv' + error_file = open(local_path, 'wb') + wrtr = csv.writer(error_file, delimiter=',', quotechar='"') createAdd = CreateViewAndAddGroups() - for key in PERMISSIONS_MAP.keys(): - view_name = key - group_list = PERMISSIONS_MAP[key] - for group_name in group_list: - try: - createAdd.createAView(view_name) - createAdd.addAGroupByName(view_name, group_name) - except Exception as e: - wrtr.writerow([key, "**insertion-error**", group_name), e]) - print(e, "**insertion-error") + + for (i, view_name) in enumerate(VIEWS_LIST): + try: + createAdd.createAView(view_name) + # createAdd.addAGroupByName(view_name, "cocoadmin") + except Exception as e: + wrtr.writerow([i, "**insertion-error**", view_name, e]) + print(e, "**insertion-error") - # error_file.close() + error_file.close() diff --git a/api/permissions.py b/api/permissions.py index 02e2e243e7..59afe9f88a 100644 --- a/api/permissions.py +++ b/api/permissions.py @@ -5,13 +5,14 @@ from api.models import View # logging imports import logging -logger = logging -logger = logging.getLogger('coco_api') __author__ = "Stuti Verma" __credits__ = ["Sujit Chaurasia", "Sagar Singh"] __email__ = "stuti@digitalgreen.org" -__status__ = "Development" +__status__ = "Development" + +logger = logging +logger = logging.getLogger('coco_api') class IsAllowed(permissions.BasePermission): """ @@ -28,4 +29,3 @@ def has_permission(self, request, view): else: logger.info("Permission denied for view: %s to user: %s of groups: %s"%(view.view_name, request.user, user_groups)) return False - diff --git a/api/utils.py b/api/utils.py index 44930f219c..c3fd4a289b 100644 --- a/api/utils.py +++ b/api/utils.py @@ -19,10 +19,10 @@ class CustomPagination(pagination.PageNumberPagination): Pagination class to paginate queryset """ - page_size = 2 + page_size = 50 page_size_query_param = 'page_size' page_query_param = 'page' - max_page_size = 5 + max_page_size = 100 # overriding of method to get customised paginated response def get_paginated_response(self, data): @@ -85,6 +85,15 @@ def logRequest(self, request, class_instance, view_fun, processing_time, status_ user_id = user_obj.id class_name = class_instance.__class__.__name__ module_name = class_instance.__module__ - # method_name = fun. logger.info("Accessed: %s.%s.%s, user_id: %s, username: %s, ip_address: %s, method: %s, processing_time: %s seconds, status_code: %s" % ( module_name, class_name, view_fun, user_id, user_obj, ip_addr, method, processing_time, status_code)) + def logMessage(self, class_instance, view_fun, message): + """ + Logs the message associated with class and its method + """ + + logger = logging.getLogger('coco_api') + class_name = class_instance.__class__.__name__ + module_name = class_instance.__module__ + logger.info("Log for %s.%s.%s: %s " % ( module_name, class_name, view_fun, message)) + \ No newline at end of file diff --git a/geographies/views.py b/geographies/views.py index 24b58de268..d8169bf64e 100644 --- a/geographies/views.py +++ b/geographies/views.py @@ -8,7 +8,7 @@ # rest framework TokenAuthentication imports from rest_framework.authentication import SessionAuthentication, BasicAuthentication, TokenAuthentication from rest_framework.permissions import IsAuthenticated -# logging, pagination and permissions +# pagination and permissions import time from api.utils import Utils, CustomPagination from api.permissions import IsAllowed @@ -19,7 +19,7 @@ __author__ = "Stuti Verma" __credits__ = ["Sujit Chaurasia", "Sagar Singh"] __email__ = "stuti@digitalgreen.org" -__status__ = "Development" +__status__ = "Development" class GeoInfoView(generics.ListAPIView): ''' @@ -71,24 +71,31 @@ def get(self, request): # POST request def post(self, request, *args, **kwargs): + """ + This function can take following optional POST params to filter on Village obects: + 1.) id - to find village by id + 2.) fields - to pass comma separated value to be returned a value for each Village object, e.g. pass + fields value as id,village_name to get only these key-value pairs for each Village object + + If none of the above parameters are provided, then all the objects from respective model + will be sent to the response. + """ + start_time = time.time() utils = Utils() - queryset = Village.objects.get_queryset().order_by('id') # basic query to be filtered later in this method - + village_id = self.request.POST.get('id', 0) # POST param 'id' fields_values = request.POST.get('fields', '') # POST param 'fields', default value is empty string - if fields_values: # fields provided in POST request and if not empty serves those fields only - fields_values = [val.strip() for val in fields_values.split(",")] - # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer - serializer = VillageSerializer(queryset, fields=fields_values ,many=True) + if village_id: + queryset = Village.objects.filter(id__exact=village_id) # to search by id else: - # if fields param is empty then all the fields as mentioned in serializer are served to the response - serializer = VillageSerializer(queryset, many=True) + queryset = Village.objects.get_queryset().order_by('id') # basic query to be filtered later in this method page = self.paginate_queryset(queryset) if page is not None: if fields_values: # fields provided in POST request and if not empty serves those fields only + fields_values = [val.strip() for val in fields_values.split(",")] # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer serializer = self.get_serializer(page, fields=fields_values, many=True) else: @@ -99,6 +106,14 @@ def post(self, request, *args, **kwargs): utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) return paginated_response + if fields_values: # fields provided in POST request and if not empty serves those fields only + fields_values = [val.strip() for val in fields_values.split(",")] + # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer + serializer = VillageSerializer(queryset, fields=fields_values ,many=True) + else: + # if fields param is empty then all the fields as mentioned in serializer are served to the response + serializer = VillageSerializer(queryset, many=True) + response = Response(serializer.data) processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) @@ -128,24 +143,31 @@ def get(self, request): # POST request def post(self, request, *args, **kwargs): + """ + This function can take following optional POST params to filter on Block obects: + 1.) id - to find block by id + 2.) fields - to pass comma separated value to be returned a value for each Block object, e.g. pass + fields value as id,block_name to get only these key-value pairs for each Block object + + If none of the above parameters are provided, then all the objects from respective model + will be sent to the response. + """ + start_time = time.time() utils = Utils() - queryset = Block.objects.get_queryset().order_by('id') # basic query to be filtered later in this method - - fields_values = request.POST.get('fields', '') # POST param 'limit', no default value specified so empty string is default value + block_id = self.request.POST.get('id', 0) # POST param 'id' + fields_values = request.POST.get('fields', '') # POST param 'fields', default value is empty string - if fields_values: # fields provided in POST request and if not empty serves those fields only - fields_values = [val.strip() for val in fields_values.split(",")] - # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer - serializer = BlockSerializer(queryset, fields=fields_values ,many=True) + if block_id: + queryset = Block.objects.filter(id__exact=block_id) # to search by id else: - # if fields param is empty then all the fields as mentioned in serializer are served to the response - serializer = BlockSerializer(queryset, many=True) + queryset = Block.objects.get_queryset().order_by('id') # basic query to be filtered later in this method page = self.paginate_queryset(queryset) if page is not None: if fields_values: # fields provided in POST request and if not empty serves those fields only + fields_values = [val.strip() for val in fields_values.split(",")] # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer serializer = self.get_serializer(page, fields=fields_values, many=True) else: @@ -155,6 +177,14 @@ def post(self, request, *args, **kwargs): processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) return paginated_response + + if fields_values: # fields provided in POST request and if not empty serves those fields only + fields_values = [val.strip() for val in fields_values.split(",")] + # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer + serializer = BlockSerializer(queryset, fields=fields_values ,many=True) + else: + # if fields param is empty then all the fields as mentioned in serializer are served to the response + serializer = BlockSerializer(queryset, many=True) response = Response(serializer.data) processing_time = time.time() - start_time @@ -185,24 +215,31 @@ def get(self, request): # POST request def post(self, request, *args, **kwargs): + """ + This function can take following optional POST params to filter on District obects: + 1.) id - to find district by id + 2.) fields - to pass comma separated value to be returned a value for each District object, e.g. pass + fields value as id,district_name to get only these key-value pairs for each District object + + If none of the above parameters are provided, then all the objects from respective model + will be sent to the response. + """ + start_time = time.time() utils = Utils() - queryset = District.objects.get_queryset().order_by('id') # basic query to be filtered later in this method - - fields_values = request.POST.get('fields', '') # POST param 'limit', no default value specified so empty string is default value + district_id = self.request.POST.get('id', 0) # POST param 'id' + fields_values = request.POST.get('fields', '') # POST param 'fields', default value is empty string - if fields_values: # fields provided in POST request and if not empty serves those fields only - fields_values = [val.strip() for val in fields_values.split(",")] - # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer - serializer = DistrictSerializer(queryset, fields=fields_values ,many=True) + if district_id: + queryset = District.objects.filter(id__exact=district_id) # to search by id else: - # if fields param is empty then all the fields as mentioned in serializer are served to the response - serializer = DistrictSerializer(queryset, many=True) + queryset = District.objects.get_queryset().order_by('id') # basic query to be filtered later in this method page = self.paginate_queryset(queryset) if page is not None: if fields_values: # fields provided in POST request and if not empty serves those fields only + fields_values = [val.strip() for val in fields_values.split(",")] # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer serializer = self.get_serializer(page, fields=fields_values, many=True) else: @@ -212,7 +249,15 @@ def post(self, request, *args, **kwargs): processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) return paginated_response - + + if fields_values: # fields provided in POST request and if not empty serves those fields only + fields_values = [val.strip() for val in fields_values.split(",")] + # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer + serializer = DistrictSerializer(queryset, fields=fields_values ,many=True) + else: + # if fields param is empty then all the fields as mentioned in serializer are served to the response + serializer = DistrictSerializer(queryset, many=True) + response = Response(serializer.data) processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) @@ -242,24 +287,31 @@ def get(self, request): # POST request def post(self, request, *args, **kwargs): + """ + This function can take following optional POST params to filter on State obects: + 1.) id - to find state by id + 2.) fields - to pass comma separated value to be returned a value for each State object, e.g. pass + fields value as id,state_name to get only these key-value pairs for each State object + + If none of the above parameters are provided, then all the objects from respective model + will be sent to the response. + """ + start_time = time.time() utils = Utils() - queryset = State.objects.get_queryset().order_by('id') # basic query to be filtered later in this method - - fields_values = request.POST.get('fields', '') # POST param 'limit', no default value specified so empty string is default value + state_id = self.request.POST.get('id', 0) # POST param 'id' + fields_values = request.POST.get('fields', '') # POST param 'fields', default value is empty string - if fields_values: # fields provided in POST request and if not empty serves those fields only - fields_values = [val.strip() for val in fields_values.split(",")] - # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer - serializer = StateSerializer(queryset, fields=fields_values ,many=True) + if state_id: + queryset = State.objects.filter(id__exact=state_id) # to search by id else: - # if fields param is empty then all the fields as mentioned in serializer are served to the response - serializer = StateSerializer(queryset, many=True) + queryset = State.objects.get_queryset().order_by('id') # basic query to be filtered later in this method page = self.paginate_queryset(queryset) if page is not None: if fields_values: # fields provided in POST request and if not empty serves those fields only + fields_values = [val.strip() for val in fields_values.split(",")] # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer serializer = self.get_serializer(page, fields=fields_values, many=True) else: @@ -269,6 +321,15 @@ def post(self, request, *args, **kwargs): processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) return paginated_response + + + if fields_values: # fields provided in POST request and if not empty serves those fields only + fields_values = [val.strip() for val in fields_values.split(",")] + # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer + serializer = StateSerializer(queryset, fields=fields_values ,many=True) + else: + # if fields param is empty then all the fields as mentioned in serializer are served to the response + serializer = StateSerializer(queryset, many=True) response = Response(serializer.data) processing_time = time.time() - start_time @@ -299,24 +360,31 @@ def get(self, request): # POST request def post(self, request, *args, **kwargs): + """ + This function can take following optional POST params to filter on Country obects: + 1.) id - to find country by id + 2.) fields - to pass comma separated value to be returned a value for each Country object, e.g. pass + fields value as id,country_name to get only these key-value pairs for each Country object + + If none of the above parameters are provided, then all the objects from respective model + will be sent to the response. + """ + start_time = time.time() utils = Utils() - queryset = Country.objects.get_queryset().order_by('id') # basic query to be filtered later in this method - - fields_values = request.POST.get('fields', '') # POST param 'limit', no default value specified so empty string is default value - - if fields_values: # fields provided in POST request and if not empty serves those fields only - fields_values = [val.strip() for val in fields_values.split(",")] - # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer - serializer = CountrySerializer(queryset, fields=fields_values ,many=True) + country_id = self.request.POST.get('id', 0) # POST param 'id' + fields_values = request.POST.get('fields', '') # POST param 'fields', default value is empty string + + if country_id: + queryset = Country.objects.filter(id__exact=country_id) # to search by id else: - # if fields param is empty then all the fields as mentioned in serializer are served to the response - serializer = CountrySerializer(queryset, many=True) + queryset = Country.objects.get_queryset().order_by('id') # basic query to be filtered later in this method page = self.paginate_queryset(queryset) if page is not None: if fields_values: # fields provided in POST request and if not empty serves those fields only + fields_values = [val.strip() for val in fields_values.split(",")] # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer serializer = self.get_serializer(page, fields=fields_values, many=True) else: @@ -327,6 +395,14 @@ def post(self, request, *args, **kwargs): utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) return paginated_response + if fields_values: # fields provided in POST request and if not empty serves those fields only + fields_values = [val.strip() for val in fields_values.split(",")] + # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer + serializer = CountrySerializer(queryset, fields=fields_values ,many=True) + else: + # if fields param is empty then all the fields as mentioned in serializer are served to the response + serializer = CountrySerializer(queryset, many=True) + response = Response(serializer.data) processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) diff --git a/people/views.py b/people/views.py index 32274c1cc1..369bbc7445 100644 --- a/people/views.py +++ b/people/views.py @@ -24,7 +24,7 @@ __author__ = "Stuti Verma" __credits__ = ["Sujit Chaurasia", "Sagar Singh"] __email__ = "stuti@digitalgreen.org" -__status__ = "Development" +__status__ = "Development" class FarmerInfoView(generics.ListCreateAPIView): ''' @@ -73,6 +73,17 @@ def get(self, request): # POST request def getAllFarmers(self, request, *args, **kwargs): + """ + This function can take following optional POST params to filter on Person obects: + 1.) country_id - to find people belonging to a country + 2.) phoneNumberExists - to find people with valid phone numbers + 3.) fields - to pass comma separated value to be returned a value for each Person object, e.g. pass + fields value as id,person_name to get only these key-value pairs for each Person object + + If none of the above parameters are provided, then all the objects from respective model + will be sent to the response. + """ + start_time = time.time() utils = Utils() @@ -90,20 +101,13 @@ def getAllFarmers(self, request, *args, **kwargs): queryset = Person.objects.all().order_by('id') # phone number exists or not - if phoneNumberExists in ["true","t","yes","y"]: + if phoneNumberExists.lower() in ["true","t","yes","y"]: queryset = queryset.filter(phone_no__isnull=False).exclude(phone_no__in=['']) - if fields_values: # fields provided in POST request and if not empty serves those fields only - fields_values = [val.strip() for val in fields_values.split(",")] - # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer - serializer = FarmerSerializer(queryset, fields=fields_values, many=True) - else: - # if fields param is empty then all the fields as mentioned in serializer are served to the response - serializer = FarmerSerializer(queryset, many=True) - page = self.paginate_queryset(queryset) if page is not None: if fields_values: # fields provided in POST request and if not empty serves those fields only + fields_values = [val.strip() for val in fields_values.split(",")] # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer serializer = self.get_serializer(page, fields=fields_values, many=True) else: @@ -114,6 +118,14 @@ def getAllFarmers(self, request, *args, **kwargs): utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) return paginated_response + if fields_values: # fields provided in POST request and if not empty serves those fields only + fields_values = [val.strip() for val in fields_values.split(",")] + # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer + serializer = FarmerSerializer(queryset, fields=fields_values, many=True) + else: + # if fields param is empty then all the fields as mentioned in serializer are served to the response + serializer = FarmerSerializer(queryset, many=True) + response = Response(serializer.data) processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) @@ -122,7 +134,20 @@ def getAllFarmers(self, request, *args, **kwargs): # POST request def getPhoneMatchedResults(self, request, *args, **kwargs): + """ + This function can take following optional POST params to filter on Person obects: + 1.) country_id - to find people belonging to a country + 2.) phoneNumberExists - to find people with valid phone numbers + 3.) phone_numbers - to pass comma separated value to search for exact phone numbers + 4.) fields - to pass comma separated value to be returned a value for each Person object, e.g. pass + fields value as id,person_name to get only these key-value pairs for each Person object + + If none of the above parameters are provided, then all the objects from respective model + will be sent to the response. + """ + start_time = time.time() + utils = Utils() queryset = Person.objects.all().order_by('id') @@ -131,28 +156,18 @@ def getPhoneMatchedResults(self, request, *args, **kwargs): phoneNumberExists = request.POST.get('phoneNumberExists','') # POST param 'phoneNumberExists', default value is empty string # phone number exists or not - if phoneNumberExists in ["true","t","yes","y"]: + if phoneNumberExists.lower() in ["true","t","yes","y"]: queryset = queryset.filter(phone_no__isnull=False).exclude(phone_no__in=['']) - # phone number matches if phone_numbers: ph_no_values = [ph.strip() for ph in phone_numbers.split(",")] queryset = queryset.filter(phone_no__in=ph_no_values) - utils = Utils() - - if fields_values: # fields provided in POST request and if not empty serves those fields only - fields_values = [val.strip() for val in fields_values.split(",")] - # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer - serializer = FarmerSerializer(queryset, fields=fields_values, many=True) - else: - # if fields param is empty then all the fields as mentioned in serializer are served to the response - serializer = FarmerSerializer(queryset, many=True) - page = self.paginate_queryset(queryset) if page is not None: if fields_values: # fields provided in POST request and if not empty serves those fields only + fields_values = [val.strip() for val in fields_values.split(",")] # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer serializer = self.get_serializer(page, fields=fields_values, many=True) else: @@ -163,6 +178,14 @@ def getPhoneMatchedResults(self, request, *args, **kwargs): utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) return paginated_response + if fields_values: # fields provided in POST request and if not empty serves those fields only + fields_values = [val.strip() for val in fields_values.split(",")] + # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer + serializer = FarmerSerializer(queryset, fields=fields_values, many=True) + else: + # if fields param is empty then all the fields as mentioned in serializer are served to the response + serializer = FarmerSerializer(queryset, many=True) + response = Response(serializer.data) processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) @@ -194,28 +217,37 @@ def get(self, request): # POST request def post(self, request, *args, **kwargs): + """ + This function can take following optional POST params to filter on Person obects: + 1.) country_id - to find people belonging to a country + 2.) phoneNumberExists - to find people with valid phone numbers + 3.) fields - to pass comma separated value to be returned a value for each Person object, e.g. pass + fields value as id,person_name to get only these key-value pairs for each Person object + + If none of the above parameters are provided, then all the objects from respective model + will be sent to the response. + """ + start_time = time.time() + utils = Utils() country_id = self.request.POST.get('country_id', 0) # POST param 'country_id', default value is 0 fields_values = request.POST.get('fields', '') # POST param 'fields', default value is empty string + phoneNumberExists = request.POST.get('phoneNumberExists','') # POST param 'filter_phone_no', default value is empty string try: # fetches country id from database model Country to verify param value got_country_id = Country.objects.get(id=country_id).id # if the country id is found same as param value entered, filters Person model - queryset = Person.objects.all().filter(village__block__district__state__country__exact=got_country_id).order_by('id') + queryset = Person.objects.all().filter(village__block__district__state__country__exact=got_country_id).order_by('id') except: # in case of failure of above try statement, all Person objects are retrieved queryset = Person.objects.all().order_by('id') - phoneNumberExists = request.POST.get('phoneNumberExists','') # POST param 'filter_phone_no', default value is empty string - # phone number exists or not - if phoneNumberExists in ["true","t","yes","y"]: + if phoneNumberExists.lower() in ["true","t","yes","y"]: queryset = queryset.filter(phone_no__isnull=False).exclude(phone_no__in=['']) - utils = Utils() - if fields_values: # fields provided in POST request and if not empty serves those fields only fields_values = [val.strip() for val in fields_values.split(",")] # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer @@ -229,5 +261,3 @@ def post(self, request, *args, **kwargs): utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) # JSON Response is provided return response - - \ No newline at end of file diff --git a/programs/views.py b/programs/views.py index 564066d7ac..be515b9424 100644 --- a/programs/views.py +++ b/programs/views.py @@ -9,11 +9,15 @@ # authentication imports from rest_framework.authentication import TokenAuthentication from rest_framework.permissions import IsAuthenticated -# logging, pagination and permissions +# pagination and permissions import time from api.utils import Utils, CustomPagination from api.permissions import IsAllowed +__author__ = "Stuti Verma" +__credits__ = ["Sujit Chaurasia", "Sagar Singh"] +__email__ = "stuti@digitalgreen.org" +__status__ = "Development" class PartnerAPIView(generics.ListCreateAPIView): ''' @@ -36,32 +40,34 @@ def get(self, request): return Response({"detail":"Method \"GET\" not allowed"}) # POST request - def getPartnerById(self, request, *args, **kwargs): + def post(self, request, *args, **kwargs): + """ + This function can take following optional POST params to filter on Partner obects: + 1.) id - to find partner by id + 2.) fields - to pass comma separated value to be returned a value for each Partner object, e.g. pass + fields value as id,partner_name to get only these key-value pairs for each Partner object + + If none of the above parameters are provided, then all the objects from respective model + will be sent to the response. + """ + start_time = time.time() utils = Utils() - # start_limit = request.POST.get('start_limit') # POST param 'start_limit' - # end_limit = request.POST.get('end_limit') # POST param 'end_limit' fields_values = request.POST.get('fields', '') # POST param 'fields' partner_id = self.request.POST.get('id', 0) # POST param 'id' - queryset = Partner.objects.all().order_by('id') serializer_class = PartnerSerializer - if partner_id: # checks if video id is present - queryset = queryset.filter(id__exact=partner_id) - - if fields_values: # fields provided in POST request and if not empty serves those fields only - fields_values = [val.strip() for val in fields_values.split(",")] - # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer - serializer = serializer_class(queryset, fields=fields_values, many=True) + if partner_id: # checks if partner id is present + queryset = Partner.objects.filter(id__exact=partner_id) else: - # if fields param is empty then all the fields as mentioned in serializer are served to the response - serializer = serializer_class(queryset, many=True) + queryset = Partner.objects.all().order_by('id') page = self.paginate_queryset(queryset) if page is not None: if fields_values: # fields provided in POST request and if not empty serves those fields only + fields_values = [val.strip() for val in fields_values.split(",")] # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer serializer = self.get_serializer(page, fields=fields_values, many=True) else: @@ -72,6 +78,14 @@ def getPartnerById(self, request, *args, **kwargs): utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) return paginated_response + if fields_values: # fields provided in POST request and if not empty serves those fields only + fields_values = [val.strip() for val in fields_values.split(",")] + # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer + serializer = serializer_class(queryset, fields=fields_values, many=True) + else: + # if fields param is empty then all the fields as mentioned in serializer are served to the response + serializer = serializer_class(queryset, many=True) + response = Response(serializer.data) processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) @@ -101,29 +115,33 @@ def get(self, request): # POST request def post(self, request, *args, **kwargs): + """ + This function can take following optional POST params to filter on Project obects: + 1.) id - to find project by id + 2.) fields - to pass comma separated value to be returned a value for each Project object, e.g. pass + fields value as id,project_name to get only these key-value pairs for each Project object + + If none of the above parameters are provided, then all the objects from respective model + will be sent to the response. + """ + start_time = time.time() utils = Utils() fields_values = request.POST.get('fields', '') # POST param 'fields' project_id = self.request.POST.get('id', 0) # POST param 'id' - queryset = Project.objects.all().order_by('id') serializer_class = ProjectSerializer - if project_id: # checks if video id is present - queryset = queryset.filter(id__exact=project_id) - - if fields_values: # fields provided in POST request and if not empty serves those fields only - fields_values = [val.strip() for val in fields_values.split(",")] - # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer - serializer = serializer_class(queryset, fields=fields_values, many=True) + if project_id: # checks if project id is present + queryset = Project.objects.filter(id__exact=project_id) else: - # if fields param is empty then all the fields as mentioned in serializer are served to the response - serializer = serializer_class(queryset, many=True) + queryset = Project.objects.all().order_by('id') page = self.paginate_queryset(queryset) if page is not None: if fields_values: # fields provided in POST request and if not empty serves those fields only + fields_values = [val.strip() for val in fields_values.split(",")] # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer serializer = self.get_serializer(page, fields=fields_values, many=True) else: @@ -133,11 +151,18 @@ def post(self, request, *args, **kwargs): processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) return paginated_response + + if fields_values: # fields provided in POST request and if not empty serves those fields only + fields_values = [val.strip() for val in fields_values.split(",")] + # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer + serializer = serializer_class(queryset, fields=fields_values, many=True) + else: + # if fields param is empty then all the fields as mentioned in serializer are served to the response + serializer = serializer_class(queryset, many=True) response = Response(serializer.data) processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) # JSON Response is provided return response - - \ No newline at end of file + \ No newline at end of file diff --git a/videos/views.py b/videos/views.py index ea95f99fa4..7a91115ff5 100644 --- a/videos/views.py +++ b/videos/views.py @@ -18,7 +18,7 @@ __author__ = "Stuti Verma" __credits__ = ["Sujit Chaurasia", "Sagar Singh"] __email__ = "stuti@digitalgreen.org" -__status__ = "Development" +__status__ = "Development" class VideoAPIView(generics.ListCreateAPIView): ''' @@ -42,6 +42,16 @@ def get(self, request): # POST request def post(self, request, *args, **kwargs): + """ + This function can take following optional POST params to filter on Video obects: + 1.) id - to find video by id + 2.) fields - to pass comma separated value to be returned a value for each Video object, e.g. pass + fields value as id,title to get only these key-value pairs for each Video object + + If none of the above parameters are provided, then all the objects from respective model + will be sent to the response. + """ + start_time = time.time() utils = Utils() @@ -52,18 +62,11 @@ def post(self, request, *args, **kwargs): queryset = Video.objects.filter(id__exact=video_id) else: queryset = Video.objects.all().order_by('id') - - if fields_values: # fields provided in POST request and if not empty serves those fields only - fields_values = [val.strip() for val in fields_values.split(",")] - # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer - serializer = VideoSerializer(queryset, fields=fields_values, many=True) - else: - # if fields param is empty then all the fields as mentioned in serializer are served to the response - serializer = VideoSerializer(queryset, many=True) page = self.paginate_queryset(queryset) if page is not None: if fields_values: # fields provided in POST request and if not empty serves those fields only + fields_values = [val.strip() for val in fields_values.split(",")] # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer serializer = self.get_serializer(page, fields=fields_values, many=True) else: @@ -74,9 +77,16 @@ def post(self, request, *args, **kwargs): utils.logRequest(request, self, self.post.__name__ , processing_time, paginated_response.status_code) return paginated_response + if fields_values: # fields provided in POST request and if not empty serves those fields only + fields_values = [val.strip() for val in fields_values.split(",")] + # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer + serializer = VideoSerializer(queryset, fields=fields_values, many=True) + else: + # if fields param is empty then all the fields as mentioned in serializer are served to the response + serializer = VideoSerializer(queryset, many=True) + response = Response(serializer.data) processing_time = time.time() - start_time utils.logRequest(request, self, self.post.__name__ , processing_time, response.status_code) # JSON Response is provided return response - From ddf463bb898cabcf1be35af4621397f4bd9f56a0 Mon Sep 17 00:00:00 2001 From: vermastuti Date: Sun, 14 Jun 2020 03:11:35 +0530 Subject: [PATCH 27/35] add-line-EOF --- api/models.py | 1 - dg/urls.py | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/api/models.py b/api/models.py index d46e6324f2..1e18ceb403 100644 --- a/api/models.py +++ b/api/models.py @@ -17,4 +17,3 @@ class View(models.Model): def __str__(self): "Returns the view name and groups names mapped together" return '%s, %s'%(self.view_name, self.permission_groups) - diff --git a/dg/urls.py b/dg/urls.py index 15c94e2120..b2b01e274b 100644 --- a/dg/urls.py +++ b/dg/urls.py @@ -94,13 +94,13 @@ (r'^videos/', include(videos.urls)), - # coco_api changes starts here + # coco api changes start here (r'^api-token-auth', views.obtain_auth_token), (r'^farmer/', include(people.urls)), (r'^geo/', include(geographies.urls)), (r'^activities/', include(activities.urls)), (r'^programs/', include(programs.urls)), - # coco_api changes ends here + # coco api changes end here # ivrsadmin/logout/ should be above admin/ URL From 85057fae3ad17707894c32fe292810fec3ff812d Mon Sep 17 00:00:00 2001 From: vermastuti Date: Mon, 15 Jun 2020 00:13:40 +0530 Subject: [PATCH 28/35] namespaces-added-to-urls --- activities/urls.py | 2 +- api/management/log/logfile | 0 dg/base_settings.py | 2 +- dg/urls.py | 8 ++++---- geographies/urls.py | 12 ++++++------ people/urls.py | 6 +++--- programs/urls.py | 4 ++-- 7 files changed, 17 insertions(+), 17 deletions(-) create mode 100644 api/management/log/logfile diff --git a/activities/urls.py b/activities/urls.py index 68722b5547..952af84a2c 100644 --- a/activities/urls.py +++ b/activities/urls.py @@ -9,6 +9,6 @@ __status__ = "Development" urlpatterns=[ - url(r'^api/screening', views.ScreeningAPIView.as_view()), + url(r'^api/screening', views.ScreeningAPIView.as_view(), name='upavan'), ] diff --git a/api/management/log/logfile b/api/management/log/logfile new file mode 100644 index 0000000000..e69de29bb2 diff --git a/dg/base_settings.py b/dg/base_settings.py index 4c2faccabc..d18c57e479 100644 --- a/dg/base_settings.py +++ b/dg/base_settings.py @@ -249,7 +249,7 @@ 'api_access_log': { 'level':'DEBUG', 'class':'logging.handlers.RotatingFileHandler', - 'filename': os.path.join(PROJECT_PATH, '../api/log/logfile'), + 'filename': os.path.join(PROJECT_PATH, '../api/management/log/logfile'), 'formatter': 'standard', }, diff --git a/dg/urls.py b/dg/urls.py index b2b01e274b..9548c49451 100644 --- a/dg/urls.py +++ b/dg/urls.py @@ -96,10 +96,10 @@ # coco api changes start here (r'^api-token-auth', views.obtain_auth_token), - (r'^farmer/', include(people.urls)), - (r'^geo/', include(geographies.urls)), - (r'^activities/', include(activities.urls)), - (r'^programs/', include(programs.urls)), + (r'^farmer/', include('people.urls', namespace='farmer')), + (r'^geo/', include('geographies.urls', namespace='geographies')), + (r'^activities/', include('activities.urls', namespace='activities')), + (r'^programs/', include('programs.urls', namespace='programs')), # coco api changes end here diff --git a/geographies/urls.py b/geographies/urls.py index c5f339539d..682c25cebf 100644 --- a/geographies/urls.py +++ b/geographies/urls.py @@ -7,10 +7,10 @@ __status__ = "Development" urlpatterns=[ - url(r'^api/info', views.GeoInfoView.as_view()), - url(r'^api/village', views.VillageAPIView.as_view()), - url(r'^api/block', views.BlockAPIView.as_view()), - url(r'^api/district', views.DistrictAPIView.as_view()), - url(r'^api/state', views.StateAPIView.as_view()), - url(r'^api/country', views.CountryAPIView.as_view()), + url(r'^api/info', views.GeoInfoView.as_view(), name='info'), + url(r'^api/village', views.VillageAPIView.as_view(), name='village'), + url(r'^api/block', views.BlockAPIView.as_view(), name='block'), + url(r'^api/district', views.DistrictAPIView.as_view(), name='district'), + url(r'^api/state', views.StateAPIView.as_view(), name='state'), + url(r'^api/country', views.CountryAPIView.as_view(), name='country'), ] diff --git a/people/urls.py b/people/urls.py index e2aa06edcf..c371eb81a0 100644 --- a/people/urls.py +++ b/people/urls.py @@ -9,9 +9,9 @@ __status__ = "Development" urlpatterns=[ - url(r'^api/info', views.FarmerInfoView.as_view()), - url(r'^api/farmers', views.FarmersJsonAPIView.as_view({'post':'getAllFarmers'})), - url(r'^api/match/phone', views.FarmersJsonAPIView.as_view({'post':'getPhoneMatchedResults'})), + url(r'^api/info', views.FarmerInfoView.as_view(), name='info'), + url(r'^api/farmers', views.FarmersJsonAPIView.as_view({'post':'getAllFarmers'}), name='getAllFarmers'), + url(r'^api/match/phone', views.FarmersJsonAPIView.as_view({'post':'getPhoneMatchedResults'}), name='getPhoneMatchedResults'), url(r'^api/csv', views.FarmersCsvAPIView.as_view({'post':'post'})), # r'^$' is used for regex of exact match as mentioned ] diff --git a/programs/urls.py b/programs/urls.py index 3105563bf4..1dfca6427b 100644 --- a/programs/urls.py +++ b/programs/urls.py @@ -3,8 +3,8 @@ urlpatterns = [ - url(r'^api/partner', PartnerAPIView.as_view()), - url(r'^api/project', ProjectAPIView.as_view()), + url(r'^api/partner', PartnerAPIView.as_view(), name='partner'), + url(r'^api/project', ProjectAPIView.as_view(), name='project'), ] From df3f536e3c41681b5cd61c46a8a341bdacb48e59 Mon Sep 17 00:00:00 2001 From: Sagar Singh Date: Wed, 1 Jul 2020 15:39:51 +0530 Subject: [PATCH 29/35] change queries to lower case --- output/database/utility.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/output/database/utility.py b/output/database/utility.py index 5d2f2a3423..004015549f 100644 --- a/output/database/utility.py +++ b/output/database/utility.py @@ -10,6 +10,8 @@ def construct_query(var, context_dict): #This abstracts away sql part to return everything by cursor.fetchall() #which is a tuple of tuples containing row-values def run_query_raw(query_string, *query_args): + # change query to lower case + query_string = query_string.lower() if(not query_string): return () cursor = connection.cursor() @@ -18,6 +20,8 @@ def run_query_raw(query_string, *query_args): #This generates a list of dictionaries of key=column_header_name, value = row_value def run_query(query_string, *query_args): + # change query to lower case + query_string = query_string.lower() if(not query_string): return [] return_list = [] @@ -33,6 +37,8 @@ def run_query(query_string, *query_args): #{ dict_key : (tuple of remaing columns), ...} #dict_key should be the first column in returned value. def run_query_dict(query_string, dict_key, *query_args): + # change query to lower case + query_string = query_string.lower() if(not query_string): return {} return_list = {} @@ -51,6 +57,8 @@ def run_query_dict(query_string, dict_key, *query_args): #{ dict_key : [list of remaing columns], ...} #dict_key should be the first column in returned value. def run_query_dict_list(query_string, dict_key, *query_args): + # change query to lower case + query_string = query_string.lower() if(not query_string): return {} return_list = {} From 96eddb3fc0caa65408af915ae95d9a696e062db2 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Fri, 17 Jul 2020 16:08:35 +0000 Subject: [PATCH 30/35] mysql-errors-fixed --- requirements/requirements.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/requirements/requirements.txt b/requirements/requirements.txt index c2f12f874c..bfad13cc1b 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -39,7 +39,8 @@ isodate==0.5.4 jdcal==1.3 Mezzanine==4.1.0 mysql-connector==2.2.9 -mysqlclient==1.4.6 +#mysqlclient==1.4.6 +mysql-python newrelic==2.82.0.62 numpy==1.12.0 oauth2==1.5.211 From f91bc725f40628fda7e03dac135cb82b67d0c025 Mon Sep 17 00:00:00 2001 From: vermastuti Date: Wed, 22 Jul 2020 18:40:52 +0530 Subject: [PATCH 31/35] people-FarmersCsvAPIView-limitquery --- people/views.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/people/views.py b/people/views.py index 369bbc7445..3dbe1263c4 100644 --- a/people/views.py +++ b/people/views.py @@ -234,6 +234,8 @@ def post(self, request, *args, **kwargs): country_id = self.request.POST.get('country_id', 0) # POST param 'country_id', default value is 0 fields_values = request.POST.get('fields', '') # POST param 'fields', default value is empty string phoneNumberExists = request.POST.get('phoneNumberExists','') # POST param 'filter_phone_no', default value is empty string + start_limit = request.POST.get('start_limit','') # POST param 'filter_phone_no', default value is empty string + end_limit = request.POST.get('end_limit','') # POST param 'filter_phone_no', default value is empty string try: # fetches country id from database model Country to verify param value @@ -248,6 +250,8 @@ def post(self, request, *args, **kwargs): if phoneNumberExists.lower() in ["true","t","yes","y"]: queryset = queryset.filter(phone_no__isnull=False).exclude(phone_no__in=['']) + queryset = utils.limitQueryset(queryset, start_limit, end_limit) + if fields_values: # fields provided in POST request and if not empty serves those fields only fields_values = [val.strip() for val in fields_values.split(",")] # updated queryset is passed and fields provided in POST request is passed to the dynamic serializer From ea4076524c4ca92deabc6e651b428a2e64e74623 Mon Sep 17 00:00:00 2001 From: Sagar Singh Date: Wed, 16 Sep 2020 15:43:42 +0530 Subject: [PATCH 32/35] change variable name --- dg/media/Output/JS/overview_module.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dg/media/Output/JS/overview_module.js b/dg/media/Output/JS/overview_module.js index a5fe5704b4..e13bb0ce22 100644 --- a/dg/media/Output/JS/overview_module.js +++ b/dg/media/Output/JS/overview_module.js @@ -18,13 +18,13 @@ function drawCharts() { $.getJSON('/coco/analytics/overview_line_graph/' + search_params, { type: ['prod', 'screen', 'prac', 'person', 'adopt'] - }, function(json) { - overview_line(json); + }, function(analytics_data) { + overview_line(analytics_data); }); } -function overview_line(json) { - var total_line_chart_data = google.visualization.arrayToDataTable(json, false); +function overview_line(analytics_data) { + var total_line_chart_data = google.visualization.arrayToDataTable(analytics_data, false); var options = jQuery.extend(true, {}, line_options); options['legend'] = { position: 'bottom', From 77c63d028916304261ca031e10cf25b148c4de61 Mon Sep 17 00:00:00 2001 From: Sagar Singh Date: Wed, 16 Sep 2020 17:49:42 +0530 Subject: [PATCH 33/35] resolve loading issue & change google charts version --- dg/media/Output/JS/adoption_module.js | 8 ++++++-- dg/media/Output/JS/overview_module.js | 8 ++++---- dg/media/Output/JS/screening_module.js | 9 +++++++-- dg/media/Output/JS/video_module.js | 8 ++++++-- dg/templates/output/adoption_module.html | 3 ++- dg/templates/output/overview_module.html | 3 ++- dg/templates/output/screening_module.html | 3 ++- dg/templates/output/video_module.html | 3 ++- 8 files changed, 31 insertions(+), 14 deletions(-) diff --git a/dg/media/Output/JS/adoption_module.js b/dg/media/Output/JS/adoption_module.js index 356c533733..1d0d2e0d7a 100644 --- a/dg/media/Output/JS/adoption_module.js +++ b/dg/media/Output/JS/adoption_module.js @@ -1,5 +1,9 @@ -google.load("visualization", "1", { packages: ["controls"] }); -google.setOnLoadCallback(drawCharts); +// google.load("visualization", "1", { packages: ["controls"] }); +// google.setOnLoadCallback(drawCharts); +google.charts.load("current", "1", { + packages: ["controls"] +}); +google.charts.setOnLoadCallback(drawCharts); function drawCharts() { $.getJSON('/coco/analytics/adoption_geog_pie_data/' + search_params, function(json) { geog_pie(json); }); diff --git a/dg/media/Output/JS/overview_module.js b/dg/media/Output/JS/overview_module.js index e13bb0ce22..a5fe5704b4 100644 --- a/dg/media/Output/JS/overview_module.js +++ b/dg/media/Output/JS/overview_module.js @@ -18,13 +18,13 @@ function drawCharts() { $.getJSON('/coco/analytics/overview_line_graph/' + search_params, { type: ['prod', 'screen', 'prac', 'person', 'adopt'] - }, function(analytics_data) { - overview_line(analytics_data); + }, function(json) { + overview_line(json); }); } -function overview_line(analytics_data) { - var total_line_chart_data = google.visualization.arrayToDataTable(analytics_data, false); +function overview_line(json) { + var total_line_chart_data = google.visualization.arrayToDataTable(json, false); var options = jQuery.extend(true, {}, line_options); options['legend'] = { position: 'bottom', diff --git a/dg/media/Output/JS/screening_module.js b/dg/media/Output/JS/screening_module.js index db031ec122..558f121417 100644 --- a/dg/media/Output/JS/screening_module.js +++ b/dg/media/Output/JS/screening_module.js @@ -1,5 +1,10 @@ -google.load("visualization", "1", { packages: ["controls"] }); -google.setOnLoadCallback(drawCharts); +// google.load("visualization", "1", { packages: ["controls"] }); +// google.setOnLoadCallback(drawCharts); + +google.charts.load("current", "1", { + packages: ["controls"] +}); +google.charts.setOnLoadCallback(drawCharts); var geog_pie_chart; var geog_pie_chart_data; diff --git a/dg/media/Output/JS/video_module.js b/dg/media/Output/JS/video_module.js index d51cc14cbb..3a6caebc7e 100644 --- a/dg/media/Output/JS/video_module.js +++ b/dg/media/Output/JS/video_module.js @@ -1,5 +1,9 @@ -google.load("visualization", "1", { packages: ["controls"] }); -google.setOnLoadCallback(drawCharts); +// google.load("visualization", "1", { packages: ["controls"] }); +// google.setOnLoadCallback(drawCharts); +google.charts.load("current", "1", { + packages: ["controls"] +}); +google.charts.setOnLoadCallback(drawCharts); var geog_pie_chart; var geog_pie_chart_data; diff --git a/dg/templates/output/adoption_module.html b/dg/templates/output/adoption_module.html index ab90d83c75..fca4e482c9 100644 --- a/dg/templates/output/adoption_module.html +++ b/dg/templates/output/adoption_module.html @@ -352,7 +352,8 @@ - + + {% endblock contentbody %} \ No newline at end of file diff --git a/dg/templates/output/overview_module.html b/dg/templates/output/overview_module.html index 948e057d46..9d44040937 100644 --- a/dg/templates/output/overview_module.html +++ b/dg/templates/output/overview_module.html @@ -251,7 +251,8 @@ - + + {% endblock contentbody %} diff --git a/dg/templates/output/screening_module.html b/dg/templates/output/screening_module.html index ea51a83fad..6abc7e1952 100644 --- a/dg/templates/output/screening_module.html +++ b/dg/templates/output/screening_module.html @@ -254,7 +254,8 @@ - + + {% endblock contentbody %} \ No newline at end of file diff --git a/dg/templates/output/video_module.html b/dg/templates/output/video_module.html index 23bbe1865b..70765154b7 100644 --- a/dg/templates/output/video_module.html +++ b/dg/templates/output/video_module.html @@ -181,7 +181,8 @@ - + + {% endblock contentbody %} \ No newline at end of file From a4327332b02d0571206ca2468ff8314b2b8d38e1 Mon Sep 17 00:00:00 2001 From: Sagar Singh Date: Wed, 16 Sep 2020 18:31:19 +0530 Subject: [PATCH 34/35] change key name from YEAR, MONTH to year, month --- output/views/common.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/output/views/common.py b/output/views/common.py index 6c39d01c40..fde0ec81bf 100644 --- a/output/views/common.py +++ b/output/views/common.py @@ -483,22 +483,22 @@ def __cmp__(self,date1): def month_bar_data(sqlFunc, setting_from_date, setting_to_date, **args): rs = run_query(sqlFunc(**args)); if rs: - min = int(rs[0]['YEAR']) - max = int(rs[-1]['YEAR'])+1 + min = int(rs[0]['year']) + max = int(rs[-1]['year'])+1 dic = {} for y in range(min,max): dic[y] = {} for item in rs: - if int(item['YEAR'])>y: + if int(item['year'])>y: break - if int(item['YEAR'])==y: - dic[y][int(item['MONTH'])] = item['count'] + if int(item['year'])==y: + dic[y][int(item['month'])] = item['count'] else: return HttpResponse(json.dumps([['Name','Value']])); if(not(setting_from_date and setting_to_date)): - setting_from_date = str(rs[0]['YEAR'])+'-'+str(rs[0]['MONTH'])+'-01' + setting_from_date = str(rs[0]['year'])+'-'+str(rs[0]['month'])+'-01' setting_to_date = (datetime.datetime.utcnow() - datetime.timedelta(1)).strftime('%Y-%m-%d') setting_from_date = MyDate(* [int(x) for x in reversed(setting_from_date.split('-')[:2])]) setting_to_date = MyDate(* [int(x) for x in reversed(setting_to_date.split('-')[:2])]) From cb7fedcf436c0bd11106eb04c3b24f4b95c7b950 Mon Sep 17 00:00:00 2001 From: Sagar Singh Date: Wed, 16 Sep 2020 18:37:58 +0530 Subject: [PATCH 35/35] add file --- dg/media/Output/JS/video_module.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dg/media/Output/JS/video_module.js b/dg/media/Output/JS/video_module.js index 3a6caebc7e..f8a30c462e 100644 --- a/dg/media/Output/JS/video_module.js +++ b/dg/media/Output/JS/video_module.js @@ -1,5 +1,6 @@ // google.load("visualization", "1", { packages: ["controls"] }); // google.setOnLoadCallback(drawCharts); + google.charts.load("current", "1", { packages: ["controls"] }); @@ -53,8 +54,6 @@ function remove_loader(div_id) { function monthwise_column(json) { if (json.length > 1) { - - var monthwise_column_chart_data = google.visualization.arrayToDataTable(json, false); var options = jQuery.extend(true, {}, column_options); options['chartArea'] = { left: 70, top: 20, width: "80%", height: "80%" };