From 527e88b4477958b2d9d6e5371051fe2bada234b8 Mon Sep 17 00:00:00 2001 From: pld Date: Sun, 2 Nov 2014 13:30:03 -0500 Subject: [PATCH 1/7] PLD: add field to show xform active status --- onadata/libs/serializers/xform_serializer.py | 29 ++++++++++---------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/onadata/libs/serializers/xform_serializer.py b/onadata/libs/serializers/xform_serializer.py index 9280b14034..028e36d933 100644 --- a/onadata/libs/serializers/xform_serializer.py +++ b/onadata/libs/serializers/xform_serializer.py @@ -10,24 +10,24 @@ class XFormSerializer(serializers.HyperlinkedModelSerializer): - url = serializers.HyperlinkedIdentityField(view_name='xform-detail', - lookup_field='pk') + active = BooleanField(source='downloadable', + widget=widgets.CheckboxInput()) formid = serializers.Field(source='id') + metadata = serializers.SerializerMethodField('get_xform_metadata') + owner = serializers.HyperlinkedRelatedField(view_name='user-detail', + source='user', + lookup_field='username') + public = BooleanField(source='shared', widget=widgets.CheckboxInput()) + public_data = BooleanField(source='shared_data') + require_auth = BooleanField(source='require_auth', + widget=widgets.CheckboxInput()) submission_count_for_today = serializers.Field( source='submission_count_for_today') - title = serializers.CharField(max_length=255, source='title') - owner = serializers.HyperlinkedRelatedField( - view_name='user-detail', - source='user', lookup_field='username') - public = BooleanField( - source='shared', widget=widgets.CheckboxInput()) - public_data = BooleanField( - source='shared_data') - require_auth = BooleanField( - source='require_auth', widget=widgets.CheckboxInput()) tags = TagListSerializer(read_only=True) + title = serializers.CharField(max_length=255, source='title') + url = serializers.HyperlinkedIdentityField(view_name='xform-detail', + lookup_field='pk') users = serializers.SerializerMethodField('get_xform_permissions') - metadata = serializers.SerializerMethodField('get_xform_metadata') class Meta: model = XForm @@ -89,7 +89,8 @@ class XFormManifestSerializer(serializers.Serializer): def get_url(self, obj): if obj: - kwargs = {'pk': obj.xform.pk, 'username': obj.xform.user.username, + kwargs = {'pk': obj.xform.pk, + 'username': obj.xform.user.username, 'metadata': obj.pk} request = self.context.get('request') format = obj.data_value[obj.data_value.rindex('.') + 1:] From 004ebcbc0aae73d783ea4b4c58f3547ec6a6b08f Mon Sep 17 00:00:00 2001 From: pld Date: Sun, 2 Nov 2014 14:04:46 -0500 Subject: [PATCH 2/7] PLD: remove active, add check_obj decorator --- onadata/libs/serializers/xform_serializer.py | 50 ++++++++++---------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/onadata/libs/serializers/xform_serializer.py b/onadata/libs/serializers/xform_serializer.py index 028e36d933..c42e362ce4 100644 --- a/onadata/libs/serializers/xform_serializer.py +++ b/onadata/libs/serializers/xform_serializer.py @@ -9,9 +9,13 @@ from onadata.libs.serializers.metadata_serializer import MetaDataSerializer +def check_obj(f): + def f_wrapper(*args, **kwargs): + if args[0]: + return f(*args, **kwargs) + + class XFormSerializer(serializers.HyperlinkedModelSerializer): - active = BooleanField(source='downloadable', - widget=widgets.CheckboxInput()) formid = serializers.Field(source='id') metadata = serializers.SerializerMethodField('get_xform_metadata') owner = serializers.HyperlinkedRelatedField(view_name='user-detail', @@ -61,25 +65,23 @@ class XFormListSerializer(serializers.Serializer): def get_version(self, obj): return None + @check_obj def get_hash(self, obj): - if obj: - return u"md5:%s" % obj.hash + return u"md5:%s" % obj.hash + @check_obj def get_url(self, obj): - if obj: - kwargs = {'pk': obj.pk, 'username': obj.user.username} - request = self.context.get('request') + kwargs = {'pk': obj.pk, 'username': obj.user.username} + request = self.context.get('request') - return reverse('download_xform', kwargs=kwargs, - request=request) + return reverse('download_xform', kwargs=kwargs, request=request) + @check_obj def get_manifest_url(self, obj): - if obj: - kwargs = {'pk': obj.pk, 'username': obj.user.username} - request = self.context.get('request') + kwargs = {'pk': obj.pk, 'username': obj.user.username} + request = self.context.get('request') - return reverse('manifest-url', kwargs=kwargs, - request=request) + return reverse('manifest-url', kwargs=kwargs, request=request) class XFormManifestSerializer(serializers.Serializer): @@ -87,17 +89,17 @@ class XFormManifestSerializer(serializers.Serializer): hash = serializers.SerializerMethodField('get_hash') downloadUrl = serializers.SerializerMethodField('get_url') + @check_obj def get_url(self, obj): - if obj: - kwargs = {'pk': obj.xform.pk, - 'username': obj.xform.user.username, - 'metadata': obj.pk} - request = self.context.get('request') - format = obj.data_value[obj.data_value.rindex('.') + 1:] + kwargs = {'pk': obj.xform.pk, + 'username': obj.xform.user.username, + 'metadata': obj.pk} + request = self.context.get('request') + format = obj.data_value[obj.data_value.rindex('.') + 1:] - return reverse('xform-media', kwargs=kwargs, - request=request, format=format.lower()) + return reverse('xform-media', kwargs=kwargs, + request=request, format=format.lower()) + @check_obj def get_hash(self, obj): - if obj: - return u"%s" % (obj.file_hash or 'md5:') + return u"%s" % (obj.file_hash or 'md5:') From 8a61427ee17a8e171447bab313bb7ae946b8d173 Mon Sep 17 00:00:00 2001 From: pld Date: Sun, 2 Nov 2014 14:08:56 -0500 Subject: [PATCH 3/7] PLD: use wraps add to project serializer --- .../libs/serializers/project_serializer.py | 33 ++++++++++--------- onadata/libs/serializers/xform_serializer.py | 7 +--- onadata/libs/utils/decorators.py | 9 +++++ 3 files changed, 27 insertions(+), 22 deletions(-) diff --git a/onadata/libs/serializers/project_serializer.py b/onadata/libs/serializers/project_serializer.py index 5df81dfbc8..9327c01580 100644 --- a/onadata/libs/serializers/project_serializer.py +++ b/onadata/libs/serializers/project_serializer.py @@ -2,11 +2,12 @@ from rest_framework import serializers from onadata.apps.api.models import Project +from onadata.apps.logger.models import Instance from onadata.libs.permissions import get_object_users_with_permissions from onadata.libs.serializers.fields.boolean_field import BooleanField from onadata.libs.serializers.fields.json_field import JsonField from onadata.libs.serializers.tag_list_serializer import TagListSerializer -from onadata.apps.logger.models import Instance +from onadata.libs.utils.decorators import check_obj class ProjectSerializer(serializers.HyperlinkedModelSerializer): @@ -65,35 +66,35 @@ def restore_object(self, attrs, instance=None): def get_project_permissions(self, obj): return get_object_users_with_permissions(obj) + @check_obj def get_project_forms(self, obj): - if obj is not None: - xforms_details = obj.projectxform_set.values( - 'xform__pk', 'xform__title') - return [{'name': form['xform__title'], 'id':form['xform__pk']} - for form in xforms_details] + xforms_details = obj.projectxform_set.values( + 'xform__pk', 'xform__title') + return [{'name': form['xform__title'], 'id':form['xform__pk']} + for form in xforms_details] + @check_obj def get_num_datasets(self, obj): """Return the number of datasets attached to the object. :param obj: The project to find datasets for. """ - if obj: - return obj.projectxform_set.count() + return obj.projectxform_set.count() + @check_obj def get_last_submission_date(self, obj): """Return the most recent submission date to any of the projects datasets. :param obj: The project to find the last submission date for. """ - if obj: - xform_ids = obj.projectxform_set.values_list('xform', flat=True) - last_submission = Instance.objects.\ - order_by('-date_created').\ - filter(xform_id__in=xform_ids).values_list('date_created', - flat=True) - - return last_submission and last_submission[0] + xform_ids = obj.projectxform_set.values_list('xform', flat=True) + last_submission = Instance.objects.\ + order_by('-date_created').\ + filter(xform_id__in=xform_ids).values_list('date_created', + flat=True) + + return last_submission and last_submission[0] def is_starred_project(self, obj): request = self.context['request'] diff --git a/onadata/libs/serializers/xform_serializer.py b/onadata/libs/serializers/xform_serializer.py index c42e362ce4..28943fe4d9 100644 --- a/onadata/libs/serializers/xform_serializer.py +++ b/onadata/libs/serializers/xform_serializer.py @@ -7,12 +7,7 @@ from onadata.libs.serializers.fields.boolean_field import BooleanField from onadata.libs.serializers.tag_list_serializer import TagListSerializer from onadata.libs.serializers.metadata_serializer import MetaDataSerializer - - -def check_obj(f): - def f_wrapper(*args, **kwargs): - if args[0]: - return f(*args, **kwargs) +from onadata.libs.utils.decorators import check_obj class XFormSerializer(serializers.HyperlinkedModelSerializer): diff --git a/onadata/libs/utils/decorators.py b/onadata/libs/utils/decorators.py index 5bf67caf89..3924b62a76 100644 --- a/onadata/libs/utils/decorators.py +++ b/onadata/libs/utils/decorators.py @@ -10,6 +10,15 @@ from onadata.apps.logger.models import XForm +def check_obj(f): + @wraps(f) + def with_check_obj(*args, **kwargs): + if args[0]: + return f(*args, **kwargs) + + return with_check_obj + + def is_owner(view_func): @wraps(view_func, assigned=available_attrs(view_func)) def _wrapped_view(request, *args, **kwargs): From 2fb493bd7ded15cb236ae52477c089f516edcb7e Mon Sep 17 00:00:00 2001 From: pld Date: Sun, 2 Nov 2014 14:11:33 -0500 Subject: [PATCH 4/7] PLD: more check_obj --- onadata/libs/serializers/attachment_serializer.py | 5 +++-- onadata/libs/serializers/data_serializer.py | 9 +++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/onadata/libs/serializers/attachment_serializer.py b/onadata/libs/serializers/attachment_serializer.py index d085c913cb..b11988a0da 100644 --- a/onadata/libs/serializers/attachment_serializer.py +++ b/onadata/libs/serializers/attachment_serializer.py @@ -1,5 +1,6 @@ from rest_framework import serializers from onadata.apps.logger.models.attachment import Attachment +from onadata.libs.utils.decorators import check_obj from onadata.libs.utils.image_tools import image_url @@ -21,9 +22,9 @@ class Meta: lookup_field = 'pk' model = Attachment + @check_obj def get_download_url(self, obj): - if obj is not None: - return obj.media_file.url if obj.media_file.url else None + return obj.media_file.url if obj.media_file.url else None def get_small_download_url(self, obj): if obj.mimetype.startswith('image'): diff --git a/onadata/libs/serializers/data_serializer.py b/onadata/libs/serializers/data_serializer.py index 51316ee0ef..2531dcb35d 100644 --- a/onadata/libs/serializers/data_serializer.py +++ b/onadata/libs/serializers/data_serializer.py @@ -6,6 +6,7 @@ from onadata.apps.logger.models.xform import XForm from onadata.apps.viewer.models.parsed_instance import ParsedInstance +from onadata.libs.utils.decorators import check_obj class DataSerializer(serializers.HyperlinkedModelSerializer): @@ -64,9 +65,9 @@ def to_native(self, obj): class DataInstanceSerializer(serializers.Serializer): + @check_obj def to_native(self, obj): - if obj is None: - return super(DataInstanceSerializer, self).to_native(obj) + return super(DataInstanceSerializer, self).to_native(obj) request = self.context.get('request') query_params = (request and request.QUERY_PARAMS) or {} @@ -87,9 +88,9 @@ def to_native(self, obj): class SubmissionSerializer(serializers.Serializer): + @check_obj def to_native(self, obj): - if obj is None: - return super(SubmissionSerializer, self).to_native(obj) + return super(SubmissionSerializer, self).to_native(obj) return { 'message': _("Successful submission."), From a037bc3c41636c67b14d05a210347d26facfa6b1 Mon Sep 17 00:00:00 2001 From: pld Date: Sun, 2 Nov 2014 14:41:13 -0500 Subject: [PATCH 5/7] PLD: revert reversed check --- onadata/libs/serializers/data_serializer.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/onadata/libs/serializers/data_serializer.py b/onadata/libs/serializers/data_serializer.py index 2531dcb35d..51316ee0ef 100644 --- a/onadata/libs/serializers/data_serializer.py +++ b/onadata/libs/serializers/data_serializer.py @@ -6,7 +6,6 @@ from onadata.apps.logger.models.xform import XForm from onadata.apps.viewer.models.parsed_instance import ParsedInstance -from onadata.libs.utils.decorators import check_obj class DataSerializer(serializers.HyperlinkedModelSerializer): @@ -65,9 +64,9 @@ def to_native(self, obj): class DataInstanceSerializer(serializers.Serializer): - @check_obj def to_native(self, obj): - return super(DataInstanceSerializer, self).to_native(obj) + if obj is None: + return super(DataInstanceSerializer, self).to_native(obj) request = self.context.get('request') query_params = (request and request.QUERY_PARAMS) or {} @@ -88,9 +87,9 @@ def to_native(self, obj): class SubmissionSerializer(serializers.Serializer): - @check_obj def to_native(self, obj): - return super(SubmissionSerializer, self).to_native(obj) + if obj is None: + return super(SubmissionSerializer, self).to_native(obj) return { 'message': _("Successful submission."), From 0f1929fa3f6541424a7f5a19b5555d4091dce665 Mon Sep 17 00:00:00 2001 From: pld Date: Sun, 2 Nov 2014 15:01:23 -0500 Subject: [PATCH 6/7] PLD: add downloadable as an updatable field --- onadata/apps/api/viewsets/xform_viewset.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/onadata/apps/api/viewsets/xform_viewset.py b/onadata/apps/api/viewsets/xform_viewset.py index 5b946a17c6..d4eab1cd87 100644 --- a/onadata/apps/api/viewsets/xform_viewset.py +++ b/onadata/apps/api/viewsets/xform_viewset.py @@ -301,9 +301,9 @@ class XFormViewSet(AnonymousUserPublicFormsMixin, LabelsMixin, ModelViewSet): ## Set Form Information You can use `PUT` or `PATCH` http methods to update or set form data elements. -If you are using `PUT`, you have to provide the `uuid, description, owner, -public, public_data` fields. With `PATCH` you only need provide atleast one -of the fields. +If you are using `PUT`, you have to provide the `uuid, description, +downloadable, owner, public, public_data` fields. With `PATCH` you only need +provide atleast one of the fields.
 PATCH /api/v1/forms/{pk}
@@ -600,7 +600,7 @@ class XFormViewSet(AnonymousUserPublicFormsMixin, LabelsMixin, ModelViewSet): lookup_field = 'pk' extra_lookup_fields = None permission_classes = [XFormPermissions, ] - updatable_fields = set(('description', 'require_auth', + updatable_fields = set(('description', 'downloadable', 'require_auth', 'shared', 'shared_data', 'title')) filter_backends = (filters.AnonDjangoObjectPermissionFilter, filters.TagFilter, From 415e8a09770c4a6fe4169faf9c521a1e3b2fa390 Mon Sep 17 00:00:00 2001 From: pld Date: Sun, 2 Nov 2014 16:05:21 -0500 Subject: [PATCH 7/7] PLD: update docs to say title is required --- onadata/apps/api/tests/viewsets/test_xform_viewset.py | 4 +++- onadata/apps/api/viewsets/xform_viewset.py | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/onadata/apps/api/tests/viewsets/test_xform_viewset.py b/onadata/apps/api/tests/viewsets/test_xform_viewset.py index e9b07cd849..12c95b179e 100644 --- a/onadata/apps/api/tests/viewsets/test_xform_viewset.py +++ b/onadata/apps/api/tests/viewsets/test_xform_viewset.py @@ -404,7 +404,8 @@ def test_partial_update(self): }) title = u'مرحب' description = 'DESCRIPTION' - data = {'public': True, 'description': description, 'title': title} + data = {'public': True, 'description': description, 'title': title, + 'downloadable': True} self.assertFalse(self.xform.shared) @@ -412,6 +413,7 @@ def test_partial_update(self): response = view(request, pk=self.xform.id) self.xform.reload() + self.assertTrue(self.xform.downloadable) self.assertTrue(self.xform.shared) self.assertEqual(self.xform.description, description) self.assertEqual(response.data['public'], True) diff --git a/onadata/apps/api/viewsets/xform_viewset.py b/onadata/apps/api/viewsets/xform_viewset.py index d4eab1cd87..20960d1c12 100644 --- a/onadata/apps/api/viewsets/xform_viewset.py +++ b/onadata/apps/api/viewsets/xform_viewset.py @@ -302,8 +302,8 @@ class XFormViewSet(AnonymousUserPublicFormsMixin, LabelsMixin, ModelViewSet): You can use `PUT` or `PATCH` http methods to update or set form data elements. If you are using `PUT`, you have to provide the `uuid, description, -downloadable, owner, public, public_data` fields. With `PATCH` you only need -provide atleast one of the fields. +downloadable, owner, public, public_data, title` fields. With `PATCH` you only +need provide at least one of the fields.
 PATCH /api/v1/forms/{pk}