Beispiel #1
0
    def retrieve(self, request, *args, **kwargs):
        xform = self.get_object()
        serializer = self.get_serializer(xform)
        dd = xform.data_dictionary()

        field_name = request.QUERY_PARAMS.get('field_name')
        fields = request.QUERY_PARAMS.get('fields')
        fmt = kwargs.get('format')

        self.headers = merge_dicts(
            self.headers, last_modified_header(get_date(xform, 'modified')))
        if fields:
            if fmt is not None and fmt != 'json':
                raise ParseError("Error: only JSON format supported.")

            xform = self.get_object()
            self.headers['Last-Modified'] = get_date(xform, 'modified')
            context = self.get_serializer_context()
            serializer = FieldsChartSerializer(instance=xform, context=context)

            return Response(serializer.data)

        if field_name:
            # check if its the special _submission_time META
            if field_name == common_tags.SUBMISSION_TIME:
                field = common_tags.SUBMISSION_TIME
            else:
                # use specified field to get summary
                fields = filter(lambda f: f.name == field_name,
                                [e for e in dd.survey_elements])

                if len(fields) == 0:
                    raise Http404("Field %s does not not exist on the form" %
                                  field_name)

                field = fields[0]

            data = build_chart_data_for_field(xform, field)

            if request.accepted_renderer.format == 'json':
                xform = xform.pk
            elif request.accepted_renderer.format == 'html' and 'data' in data:
                for item in data['data']:
                    if isinstance(item[field_name], list):
                        item[field_name] = u', '.join(item[field_name])

            data.update({'xform': xform})

            return Response(data, template_name='chart_detail.html')

        if fmt != 'json' and field_name is None:
            raise ParseError("Not supported")

        data = serializer.data
        data["fields"] = {}
        for field in dd.survey_elements:
            field_url = get_form_field_chart_url(data["url"], field.name)
            data["fields"][field.name] = field_url

        return Response(data)
Beispiel #2
0
    def retrieve(self, request, *args, **kwargs):
        data_id = str(kwargs.get('dataid'))
        _format = kwargs.get('format')

        if not data_id.isdigit():
            raise ParseError(_(u"Data ID should be an integer"))

        try:
            instance = Instance.objects.get(pk=data_id)
            self.headers = merge_dicts(
                self.headers,
                last_modified_header(get_date(instance, 'modified')))

            if _format == 'json' or _format is None:
                return Response(instance.json)
            elif _format == 'xml':
                return Response(instance.xml)
            else:
                raise ParseError(
                    _(u"'%(_format)s' format unknown or not implemented!" %
                      {'_format': _format}))
        except Instance.DoesNotExist:
            raise ParseError(
                _(u"data with id '%(data_id)s' not found!" %
                  {'data_id': data_id}))
Beispiel #3
0
    def forms(self, request, **kwargs):
        """Add a form to a project or list forms for the project.

        The request key `xls_file` holds the XLSForm file object.
        """
        project = get_object_or_404(Project, pk=kwargs.get('pk'))
        self.headers = merge_dicts(
            self.headers, last_modified_header(get_date(project, 'modified')))
        if request.method.upper() == 'POST':
            survey = utils.publish_project_xform(request, project)

            if isinstance(survey, XForm):
                xform = XForm.objects.get(pk=survey.pk)
                serializer = XFormSerializer(
                    xform, context={'request': request})

                return Response(serializer.data,
                                status=status.HTTP_201_CREATED)

            return Response(survey, status=status.HTTP_400_BAD_REQUEST)

        project_xforms = project.projectxform_set.values('xform')
        xforms = XForm.objects.filter(pk__in=project_xforms)
        serializer = XFormSerializer(xforms, context={'request': request},
                                     many=True)

        return Response(serializer.data)
Beispiel #4
0
    def retrieve(self, request, *args, **kwargs):
        data_id = str(kwargs.get('dataid'))
        _format = kwargs.get('format')

        if not data_id.isdigit():
            raise ParseError(_(u"Data ID should be an integer"))

        try:
            instance = Instance.objects.get(pk=data_id)
            self.headers = merge_dicts(
                self.headers,
                last_modified_header(get_date(instance, 'modified')))

            if _format == 'json' or _format is None:
                return Response(instance.json)
            elif _format == 'xml':
                return Response(instance.xml)
            else:
                raise ParseError(
                    _(u"'%(_format)s' format unknown or not implemented!" %
                      {'_format': _format})
                )
        except Instance.DoesNotExist:
            raise ParseError(
                _(u"data with id '%(data_id)s' not found!" %
                  {'data_id': data_id})
            )
Beispiel #5
0
    def labels(self, request, *args, **kwargs):
        http_status = status.HTTP_400_BAD_REQUEST
        instance = self.get_object()
        self.headers = merge_dicts(
            self.headers, last_modified_header(get_date(instance, 'modified')))

        if request.method == 'POST':
            if add_tags_to_instance(request, instance):
                http_status = status.HTTP_201_CREATED

        tags = instance.tags
        label = kwargs.get('label', None)

        if request.method == 'GET' and label:
            data = [
                tag['name'] for tag in tags.filter(name=label).values('name')
            ]

        elif request.method == 'DELETE' and label:
            count = tags.count()
            tags.remove(label)

            # Accepted, label does not exist hence nothing removed
            http_status = status.HTTP_200_OK if count == tags.count() \
                else status.HTTP_404_NOT_FOUND

            data = list(tags.names())
        else:
            data = list(tags.names())

        if request.method == 'GET':
            http_status = status.HTTP_200_OK

        return Response(data, status=http_status)
Beispiel #6
0
    def finalize_response(self, request, response, *args, **kwargs):
        if request.method == 'GET' and response.status_code < 300:
            if self.last_modified_date is not None:
                self.headers.update(
                    last_modified_header(self.last_modified_date))
            else:
                obj = None
                if hasattr(self, 'object_list'):
                    generator_type = isinstance(self.object_list,
                                                types.GeneratorType)
                    if isinstance(self.object_list, list) \
                            and len(self.object_list):
                        obj = self.object_list[len(self.object_list) - 1]
                    elif not isinstance(self.object_list, list) and \
                            not generator_type:
                        obj = self.object_list.last()

                if hasattr(self, 'object'):
                    obj = self.object

                if not obj:
                    obj = self.queryset.last()

                self.headers.update(last_modified_header(get_date(obj)))

        return super(LastModifiedMixin,
                     self).finalize_response(request, response, *args,
                                             **kwargs)
Beispiel #7
0
    def forms(self, request, **kwargs):
        """Add a form to a project or list forms for the project.

        The request key `xls_file` holds the XLSForm file object.
        """
        project = get_object_or_404(Project, pk=kwargs.get('pk'))
        self.headers = merge_dicts(
            self.headers, last_modified_header(get_date(project, 'modified')))
        if request.method.upper() == 'POST':
            survey = utils.publish_project_xform(request, project)

            if isinstance(survey, XForm):
                xform = XForm.objects.get(pk=survey.pk)
                serializer = XFormSerializer(xform,
                                             context={'request': request})

                return Response(serializer.data,
                                status=status.HTTP_201_CREATED)

            return Response(survey, status=status.HTTP_400_BAD_REQUEST)

        project_xforms = project.projectxform_set.values('xform')
        xforms = XForm.objects.filter(pk__in=project_xforms)
        serializer = XFormSerializer(xforms,
                                     context={'request': request},
                                     many=True)

        return Response(serializer.data)
Beispiel #8
0
    def finalize_response(self, request, response, *args, **kwargs):
        if request.method == 'GET' and response.status_code < 300:
            if self.last_modified_date is not None:
                self.headers.update(
                    last_modified_header(self.last_modified_date))
            else:
                obj = None
                if hasattr(self, 'object_list'):
                    generator_type = isinstance(self.object_list,
                                                types.GeneratorType)
                    if isinstance(self.object_list, list) \
                            and len(self.object_list):
                        obj = self.object_list[len(self.object_list) - 1]
                    elif not isinstance(self.object_list, list) and \
                            not generator_type:
                        obj = self.object_list.last()

                if hasattr(self, 'object'):
                    obj = self.object

                if not obj:
                    obj = self.queryset.last()

                self.headers.update(last_modified_header(get_date(obj)))

        return super(LastModifiedMixin, self).finalize_response(
            request, response, *args, **kwargs)
Beispiel #9
0
    def labels(self, request, *args, **kwargs):
        http_status = status.HTTP_400_BAD_REQUEST
        instance = self.get_object()
        self.headers = merge_dicts(
            self.headers, last_modified_header(get_date(instance, 'modified')))

        if request.method == 'POST':
            if add_tags_to_instance(request, instance):
                http_status = status.HTTP_201_CREATED

        tags = instance.tags
        label = kwargs.get('label', None)

        if request.method == 'GET' and label:
            data = [tag['name'] for tag in
                    tags.filter(name=label).values('name')]

        elif request.method == 'DELETE' and label:
            count = tags.count()
            tags.remove(label)

            # Accepted, label does not exist hence nothing removed
            http_status = status.HTTP_200_OK if count == tags.count() \
                else status.HTTP_404_NOT_FOUND

            data = list(tags.names())
        else:
            data = list(tags.names())

        if request.method == 'GET':
            http_status = status.HTTP_200_OK

        return Response(data, status=http_status)
Beispiel #10
0
    def starred(self, request, *args, **kwargs):
        """Return projects starred for this user."""
        user_profile = self.get_object()
        self.headers = merge_dicts(
            self.headers,
            last_modified_header(get_date(user_profile, 'joined')))
        user = user_profile.user
        projects = user.project_set.all()
        serializer = ProjectSerializer(projects,
                                       context={'request': request},
                                       many=True)

        return Response(data=serializer.data)
Beispiel #11
0
    def starred(self, request, *args, **kwargs):
        """Return projects starred for this user."""
        user_profile = self.get_object()
        self.headers = merge_dicts(
            self.headers,
            last_modified_header(get_date(user_profile, 'joined')))
        user = user_profile.user
        projects = user.project_set.all()
        serializer = ProjectSerializer(projects,
                                       context={'request': request},
                                       many=True)

        return Response(data=serializer.data)
    def finalize_response(self, request, response, *args, **kwargs):
        if request.method == 'GET':
            obj = None
            if hasattr(self, 'object_list'):
                obj = self.object_list.last()

            if hasattr(self, 'object'):
                obj = self.object

            if not obj:
                obj = self.queryset.last()

            if response.status_code < 400:
                self.headers.update(last_modified_header(get_date(obj)))

        return super(LastModifiedMixin, self).finalize_response(
            request, response, *args, **kwargs)
    def finalize_response(self, request, response, *args, **kwargs):
        if request.method == 'GET':
            obj = None
            if hasattr(self, 'object_list'):
                obj = self.object_list.last()

            if hasattr(self, 'object'):
                obj = self.object

            if not obj:
                obj = self.queryset.last()

            if response.status_code < 400:
                self.headers.update(last_modified_header(get_date(obj)))

        return super(LastModifiedMixin,
                     self).finalize_response(request, response, *args,
                                             **kwargs)
Beispiel #14
0
    def star(self, request, *args, **kwargs):
        user = request.user
        project = get_object_or_404(Project, pk=kwargs.get('pk'))
        self.headers = merge_dicts(
            self.headers, last_modified_header(get_date(project, 'modified')))

        if request.method == 'DELETE':
            project.user_stars.remove(user)
        elif request.method == 'POST':
            project.user_stars.add(user)
        elif request.method == 'GET':
            users = project.user_stars.values('pk')
            user_profiles = UserProfile.objects.filter(user__in=users)
            serializer = UserProfileSerializer(user_profiles,
                                               context={'request': request},
                                               many=True)

            return Response(serializer.data)

        return Response(status=status.HTTP_204_NO_CONTENT)
Beispiel #15
0
    def star(self, request, *args, **kwargs):
        user = request.user
        project = get_object_or_404(Project, pk=kwargs.get('pk'))
        self.headers = merge_dicts(
            self.headers, last_modified_header(get_date(project, 'modified')))

        if request.method == 'DELETE':
            project.user_stars.remove(user)
        elif request.method == 'POST':
            project.user_stars.add(user)
        elif request.method == 'GET':
            users = project.user_stars.values('pk')
            user_profiles = UserProfile.objects.filter(user__in=users)
            serializer = UserProfileSerializer(user_profiles,
                                               context={'request': request},
                                               many=True)

            return Response(serializer.data)

        return Response(status=status.HTTP_204_NO_CONTENT)
Beispiel #16
0
    def retrieve(self, request, *args, **kwargs):
        self.object = self.get_object()
        self.headers = merge_dicts(
            self.headers,
            last_modified_header(get_date(self.object, 'modified')))

        if isinstance(request.accepted_renderer, MediaFileRenderer) \
                and self.object.media_file is not None:
            data = self.object.media_file.read()

            return Response(data, content_type=self.object.mimetype)

        filename = request.QUERY_PARAMS.get('filename')
        serializer = self.get_serializer(self.object)

        if filename:
            if filename == self.object.media_file.name:
                return Response(serializer.get_download_url(self.object))
            else:
                raise Http404(_("Filename '%s' not found." % filename))

        return Response(serializer.data)
Beispiel #17
0
    def retrieve(self, request, *args, **kwargs):
        self.object = self.get_object()
        self.headers = merge_dicts(
            self.headers,
            last_modified_header(get_date(self.object, 'modified')))

        if isinstance(request.accepted_renderer, MediaFileRenderer) \
                and self.object.media_file is not None:
            data = self.object.media_file.read()

            return Response(data, content_type=self.object.mimetype)

        filename = request.QUERY_PARAMS.get('filename')
        serializer = self.get_serializer(self.object)

        if filename:
            if filename == self.object.media_file.name:
                return Response(serializer.get_download_url(self.object))
            else:
                raise Http404(_("Filename '%s' not found." % filename))

        return Response(serializer.data)
Beispiel #18
0
    def enketo(self, request, *args, **kwargs):
        self.object = self.get_object()
        data = {}
        if isinstance(self.object, XForm):
            raise ParseError(_(u"Data id not provided."))
        elif (isinstance(self.object, Instance)):
            self.headers = merge_dicts(
                self.headers,
                last_modified_header(get_date(self.object, 'modified')))
            if request.user.has_perm("change_xform", self.object.xform):
                return_url = request.QUERY_PARAMS.get('return_url')
                if not return_url:
                    raise ParseError(_(u"return_url not provided."))

                try:
                    data["url"] = get_enketo_edit_url(request, self.object,
                                                      return_url)
                except EnketoError as e:
                    data['detail'] = "{}".format(e)
            else:
                raise PermissionDenied(_(u"You do not have edit permissions."))

        return Response(data=data)
Beispiel #19
0
    def enketo(self, request, *args, **kwargs):
        self.object = self.get_object()
        data = {}
        if isinstance(self.object, XForm):
            raise ParseError(_(u"Data id not provided."))
        elif(isinstance(self.object, Instance)):
            self.headers = merge_dicts(
                self.headers,
                last_modified_header(get_date(self.object, 'modified')))
            if request.user.has_perm("change_xform", self.object.xform):
                return_url = request.QUERY_PARAMS.get('return_url')
                if not return_url:
                    raise ParseError(_(u"return_url not provided."))

                try:
                    data["url"] = get_enketo_edit_url(
                        request, self.object, return_url)
                except EnketoError as e:
                    data['detail'] = "{}".format(e)
            else:
                raise PermissionDenied(_(u"You do not have edit permissions."))

        return Response(data=data)
Beispiel #20
0
    def members(self, request, *args, **kwargs):
        organization = self.get_object()
        self.headers = merge_dicts(
            self.headers,
            last_modified_header(get_date(organization, 'joined')))
        status_code = status.HTTP_200_OK
        data = []
        username = request.DATA.get('username') or request.QUERY_PARAMS.get(
            'username')

        if request.method in ['DELETE', 'POST', 'PUT'] and not username:
            status_code = status.HTTP_400_BAD_REQUEST
            data = {'username': [_(u"This field is required.")]}
        elif request.method == 'POST':
            data, status_code = _add_username_to_organization(
                organization, username)
        elif request.method == 'PUT':
            role = request.DATA.get('role')
            role_cls = ROLES.get(role)

            if not role or not role_cls:
                status_code = status.HTTP_400_BAD_REQUEST
                message = (_(u"'%s' is not a valid role." %
                             role) if role else _(u"This field is required."))
                data = {'role': [message]}
            else:
                _update_username_role(organization, username, role_cls)
        elif request.method == 'DELETE':
            data, status_code = _remove_username_to_organization(
                organization, username)

        if status_code in [status.HTTP_200_OK, status.HTTP_201_CREATED]:
            members = get_organization_members(organization)
            data = [u.username for u in members]

        return Response(data, status=status_code)
    def members(self, request, *args, **kwargs):
        organization = self.get_object()
        self.headers = merge_dicts(
            self.headers,
            last_modified_header(get_date(organization, 'joined')))
        status_code = status.HTTP_200_OK
        data = []
        username = request.DATA.get('username') or request.QUERY_PARAMS.get(
            'username')

        if request.method in ['DELETE', 'POST', 'PUT'] and not username:
            status_code = status.HTTP_400_BAD_REQUEST
            data = {'username': [_(u"This field is required.")]}
        elif request.method == 'POST':
            data, status_code = _add_username_to_organization(
                organization, username)
        elif request.method == 'PUT':
            role = request.DATA.get('role')
            role_cls = ROLES.get(role)

            if not role or not role_cls:
                status_code = status.HTTP_400_BAD_REQUEST
                message = (_(u"'%s' is not a valid role." % role) if role
                           else _(u"This field is required."))
                data = {'role': [message]}
            else:
                _update_username_role(organization, username, role_cls)
        elif request.method == 'DELETE':
            data, status_code = _remove_username_to_organization(
                organization, username)

        if status_code in [status.HTTP_200_OK, status.HTTP_201_CREATED]:
            members = get_organization_members(organization)
            data = [u.username for u in members]

        return Response(data, status=status_code)
Beispiel #22
0
class ProjectViewSet(LabelsMixin, ModelViewSet):
    """
List, Retrieve, Update, Create Project and Project Forms

Where:

- `pk` - is the project id
- `formid` - is the form id
- `owner` - is the username for the user or organization of the project

## Register a new Project
<pre class="prettyprint">
<b>POST</b> /api/v1/projects</pre>
> Example
>
>       {
>           "url": "https://ona.io/api/v1/projects/1",
>           "owner": "https://ona.io/api/v1/users/ona",
>           "name": "project 1",
>           "date_created": "2013-07-24T13:37:39Z",
>           "date_modified": "2013-07-24T13:37:39Z"
>       }

## List of Projects

<pre class="prettyprint"><b>GET</b> /api/v1/projects</pre>
> Example
>
>       curl -X GET https://ona.io/api/v1/projects

> Response
>
>       [
>           {
>               "url": "https://ona.io/api/v1/projects/1",
>               "owner": "https://ona.io/api/v1/users/ona",
>               "name": "project 1",
>               "date_created": "2013-07-24T13:37:39Z",
>               "date_modified": "2013-07-24T13:37:39Z"
>           },
>           {
>               "url": "https://ona.io/api/v1/projects/4",
>               "owner": "https://ona.io/api/v1/users/ona",
>               "name": "project 2",
>               "date_created": "2013-07-24T13:59:10Z",
>               "date_modified": "2013-07-24T13:59:10Z"
>           }, ...
>       ]

## List of Projects filter by owner/organization

<pre class="prettyprint">
<b>GET</b> /api/v1/projects?<code>owner</code>=<code>owner_username</code>
</pre>
> Example
>
>       curl -X GET https://ona.io/api/v1/projects?owner=ona

## Retrieve Project Information

<pre class="prettyprint">
<b>GET</b> /api/v1/projects/<code>{pk}</code></pre>
> Example
>
>       curl -X GET https://ona.io/api/v1/projects/1

> Response
>
>       {
>           "url": "https://ona.io/api/v1/projects/1",
>           "owner": "https://ona.io/api/v1/users/ona",
>           "name": "project 1",
>           "date_created": "2013-07-24T13:37:39Z",
>           "date_modified": "2013-07-24T13:37:39Z"
>       }

## Update Project Information

<pre class="prettyprint">
<b>PUT</b> /api/v1/projects/<code>{pk}</code> or \
<b>PATCH</b> /api/v1/projects/<code>{pk}</code></pre></pre>
> Example

>        curl -X PATCH -d 'metadata={"description": "Lorem ipsum",\
"location": "Nakuru, Kenya",\
"category": "water"}' \
https://ona.io/api/v1/projects/1

> Response
>
>       {
>           "url": "https://ona.io/api/v1/projects/1",
>           "owner": "https://ona.io/api/v1/users/ona",
>           "name": "project 1",
>           "metadata": {
>                        "description": "Lorem ipsum",
>                        "location": "Nakuru, Kenya",
>                        "category": "water"
>                        }
>           "date_created": "2013-07-24T13:37:39Z",
>           "date_modified": "2013-07-24T13:37:39Z"
>       }

## Share a project with a specific user

You can share a project with a specific user by `POST` a payload with

- `username` of the user you want to share the form with and
- `role` you want the user to have on the project. \
Available roles are `readonly`,
`dataentry`, `editor`, `manager`.

<pre class="prettyprint">
<b>POST</b> /api/v1/projects/<code>{pk}</code>/share
</pre>

> Example
>
>       curl -X POST -d username=alice -d role=readonly\
 https://ona.io/api/v1/projects/1/share

> Response
>
>        HTTP 204 NO CONTENT

## Send an email to users on project share
An email is only sent when the `email_msg` request variable is present.
<pre class="prettyprint">
<b>POST</b> /api/v1/projects/<code>{pk}</code>/share
</pre>

> Example
>
>       curl -X POST -d username=alice -d role=readonly -d email_msg=I have\
 shared the project with you\
 https://ona.io/api/v1/projects/1/share

> Response
>
>        HTTP 204 NO CONTENT

## Remove a user from a project
You can remove a specific user from a project using `POST` with payload:

- `username` of the user you want to remove
- `role` the user has on the project
- `remove` set remove to True

> Example
>
>       curl -X POST -d "username=alice" -d "role=readonly" \
 -d "remove=True" http://localhost:8000/api/v1/projects/1/share

> Response
>
>        HTTP 204 NO CONTENT

## Assign a form to a project
To [re]assign an existing form to a project you need to `POST` a payload of
`formid=FORMID` to the endpoint below.

<pre class="prettyprint">
<b>POST</b> /api/v1/projects/<code>{pk}</code>/forms</pre>
> Example
>
>       curl -X POST -d '{"formid": 28058}' \
https://ona.io/api/v1/projects/1/forms -H "Content-Type: application/json"

> Response
>
>       {
>           "url": "https://ona.io/api/v1/forms/28058",
>           "formid": 28058,
>           "uuid": "853196d7d0a74bca9ecfadbf7e2f5c1f",
>           "id_string": "Birds",
>           "sms_id_string": "Birds",
>           "title": "Birds",
>           "allows_sms": false,
>           "bamboo_dataset": "",
>           "description": "",
>           "downloadable": true,
>           "encrypted": false,
>           "owner": "ona",
>           "public": false,
>           "public_data": false,
>           "date_created": "2013-07-25T14:14:22.892Z",
>           "date_modified": "2013-07-25T14:14:22.892Z"
>       }

## Upload XLSForm to a project

<pre class="prettyprint">
<b>POST</b> /api/v1/projects/<code>{pk}</code>/forms</pre>
> Example
>
>       curl -X POST -F xls_file=@/path/to/form.xls\
 https://ona.io/api/v1/projects/1/forms

> Response
>
>       {
>           "url": "https://ona.io/api/v1/forms/28058",
>           "formid": 28058,
>           "uuid": "853196d7d0a74bca9ecfadbf7e2f5c1f",
>           "id_string": "Birds",
>           "sms_id_string": "Birds",
>           "title": "Birds",
>           "allows_sms": false,
>           "bamboo_dataset": "",
>           "description": "",
>           "downloadable": true,
>           "encrypted": false,
>           "owner": "ona",
>           "public": false,
>           "public_data": false,
>           "date_created": "2013-07-25T14:14:22.892Z",
>           "date_modified": "2013-07-25T14:14:22.892Z"
>       }

## Get forms for a project

<pre class="prettyprint">
<b>GET</b> /api/v1/projects/<code>{pk}</code>/forms
</pre>
> Example
>
>       curl -X GET https://ona.io/api/v1/projects/1/forms

> Response
>
>       [
>           {
>              "url": "https://ona.io/api/v1/forms/28058",
>               "formid": 28058,
>               "uuid": "853196d7d0a74bca9ecfadbf7e2f5c1f",
>               "id_string": "Birds",
>               "sms_id_string": "Birds",
>               "title": "Birds",
>               "allows_sms": false,
>               "bamboo_dataset": "",
>               "description": "",
>               "downloadable": true,
>               "encrypted": false,
>               "owner": "ona",
>               "public": false,
>               "public_data": false,
>               "date_created": "2013-07-25T14:14:22.892Z",
>               "date_modified": "2013-07-25T14:14:22.892Z",
>               "tags": [],
>               "users": [
>                   {
>                       "role": "owner",
>                       "user": "******",
>                       "permissions": ["report_xform", ...]
>                   },
>                   ...
>               ]
>           },
>           ...
>       ]

## Get list of projects with specific tag(s)

Use the `tags` query parameter to filter the list of projects, `tags` should be
a comma separated list of tags.

<pre class="prettyprint">
<b>GET</b> /api/v1/projects?<code>tags</code>=<code>tag1,tag2</code></pre>

List projects tagged `smart` or `brand new` or both.
> Request
>
>       curl -X GET https://ona.io/api/v1/projects?tag=smart,brand+new

> Response
>        HTTP 200 OK
>
>       [
>           {
>               "url": "https://ona.io/api/v1/projects/1",
>               "owner": "https://ona.io/api/v1/users/ona",
>               "name": "project 1",
>               "date_created": "2013-07-24T13:37:39Z",
>               "date_modified": "2013-07-24T13:37:39Z"
>           },
>           ...
>       ]


## Get list of Tags for a specific Project
<pre class="prettyprint">
<b>GET</b> /api/v1/project/<code>{pk}</code>/labels
</pre>
> Request
>
>       curl -X GET https://ona.io/api/v1/projects/28058/labels

> Response
>
>       ["old", "smart", "clean house"]

## Tag a Project

A `POST` payload of parameter `tags` with a comma separated list of tags.

Examples

- `animal fruit denim` - space delimited, no commas
- `animal, fruit denim` - comma delimited

<pre class="prettyprint">
<b>POST</b> /api/v1/projects/<code>{pk}</code>/labels
</pre>

Payload

    {"tags": "tag1, tag2"}

## Remove a tag from a Project

<pre class="prettyprint">
<b>DELETE</b> /api/v1/projects/<code>{pk}</code>/labels/<code>tag_name</code>
</pre>

> Request
>
>       curl -X DELETE \
https://ona.io/api/v1/projects/28058/labels/tag1
>
> or to delete the tag "hello world"
>
>       curl -X DELETE \
https://ona.io/api/v1/projects/28058/labels/hello%20world
>
> Response
>
>        HTTP 200 OK

## Add a star to a project
<pre class="prettypriProjectnt">
<b>POST</b> /api/v1/projects/<code>{pk}</code>/star</pre>

## Remove a star to a project
<pre class="prettyprint">
<b>DELETE</b> /api/v1/projects/<code>{pk}</code>/star</pre>

## Get user profiles that have starred a project
<pre class="prettyprint">
<b>GET</b> /api/v1/projects/<code>{pk}</code>/star</pre>
    """
    queryset = Project.objects.all()
    default_response_headers = last_modified_header(
        get_date(Project.objects.last(), 'modified'))
    serializer_class = ProjectSerializer
    lookup_field = 'pk'
    extra_lookup_fields = None
    permission_classes = [ProjectPermissions]
    filter_backends = (AnonUserProjectFilter, ProjectOwnerFilter, TagFilter)

    @action(methods=['POST', 'GET'])
    def forms(self, request, **kwargs):
        """Add a form to a project or list forms for the project.

        The request key `xls_file` holds the XLSForm file object.
        """
        project = get_object_or_404(Project, pk=kwargs.get('pk'))
        self.headers = merge_dicts(
            self.headers, last_modified_header(get_date(project, 'modified')))
        if request.method.upper() == 'POST':
            survey = utils.publish_project_xform(request, project)

            if isinstance(survey, XForm):
                xform = XForm.objects.get(pk=survey.pk)
                serializer = XFormSerializer(xform,
                                             context={'request': request})

                return Response(serializer.data,
                                status=status.HTTP_201_CREATED)

            return Response(survey, status=status.HTTP_400_BAD_REQUEST)

        project_xforms = project.projectxform_set.values('xform')
        xforms = XForm.objects.filter(pk__in=project_xforms)
        serializer = XFormSerializer(xforms,
                                     context={'request': request},
                                     many=True)

        return Response(serializer.data)

    @action(methods=['PUT'])
    def share(self, request, *args, **kwargs):
        self.object = self.get_object()
        data = dict(request.DATA.items() + [('project', self.object.pk)])
        serializer = ShareProjectSerializer(data=data)

        if serializer.is_valid():
            if data.get("remove"):
                serializer.remove_user()
            else:
                serializer.save()
                email_msg = data.get('email_msg')

                if email_msg:
                    # send out email message.
                    user = serializer.object.user
                    send_mail(SHARE_PROJECT_SUBJECT.format(self.object.name),
                              email_msg, DEFAULT_FROM_EMAIL, (user.email, ))

        else:
            return Response(data=serializer.errors,
                            status=status.HTTP_400_BAD_REQUEST)

        return Response(status=status.HTTP_204_NO_CONTENT)

    @action(methods=['DELETE', 'GET', 'POST'])
    def star(self, request, *args, **kwargs):
        user = request.user
        project = get_object_or_404(Project, pk=kwargs.get('pk'))
        self.headers = merge_dicts(
            self.headers, last_modified_header(get_date(project, 'modified')))

        if request.method == 'DELETE':
            project.user_stars.remove(user)
        elif request.method == 'POST':
            project.user_stars.add(user)
        elif request.method == 'GET':
            users = project.user_stars.values('pk')
            user_profiles = UserProfile.objects.filter(user__in=users)
            serializer = UserProfileSerializer(user_profiles,
                                               context={'request': request},
                                               many=True)

            return Response(serializer.data)

        return Response(status=status.HTTP_204_NO_CONTENT)
Beispiel #23
0
    def retrieve(self, request, *args, **kwargs):
        xform = self.get_object()
        serializer = self.get_serializer(xform)
        dd = xform.data_dictionary()

        field_name = request.QUERY_PARAMS.get('field_name')
        fields = request.QUERY_PARAMS.get('fields')
        fmt = kwargs.get('format')

        self.headers = merge_dicts(
            self.headers, last_modified_header(get_date(xform, 'modified')))
        if fields:
            if fmt is not None and fmt != 'json':
                raise ParseError("Error: only JSON format supported.")

            xform = self.get_object()
            self.headers['Last-Modified'] = get_date(xform, 'modified')
            context = self.get_serializer_context()
            serializer = FieldsChartSerializer(instance=xform, context=context)

            return Response(serializer.data)

        if field_name:
            # check if its the special _submission_time META
            if field_name == common_tags.SUBMISSION_TIME:
                field = common_tags.SUBMISSION_TIME
            else:
                # use specified field to get summary
                fields = filter(
                    lambda f: f.name == field_name,
                    [e for e in dd.survey_elements])

                if len(fields) == 0:
                    raise Http404(
                        "Field %s does not not exist on the form" % field_name)

                field = fields[0]

            data = build_chart_data_for_field(xform, field)

            if request.accepted_renderer.format == 'json':
                xform = xform.pk
            elif request.accepted_renderer.format == 'html' and 'data' in data:
                for item in data['data']:
                    if isinstance(item[field_name], list):
                        item[field_name] = u', '.join(item[field_name])

            data.update({
                'xform': xform
            })

            return Response(data, template_name='chart_detail.html')

        if fmt != 'json' and field_name is None:
            raise ParseError("Not supported")

        data = serializer.data
        data["fields"] = {}
        for field in dd.survey_elements:
            field_url = get_form_field_chart_url(data["url"], field.name)
            data["fields"][field.name] = field_url

        return Response(data)
Beispiel #24
0
class OrganizationProfileViewSet(ObjectLookupMixin, ModelViewSet):
    """
List, Retrieve, Update, Create/Register Organizations

## Register a new Organization
<pre class="prettyprint"><b>POST</b> /api/v1/orgs</pre>
> Example
>
>        {
>            "org": "modilabs",
>            "name": "Modi Labs Research",
>            "email": "*****@*****.**",
>            "city": "New York",
>            "country": "US",
>            ...
>        }

## List of Organizations
<pre class="prettyprint"><b>GET</b> /api/v1/orgs</pre>
> Example
>
>       curl -X GET https://ona.io/api/v1/orgs

> Response
>
>       [
>        {
>            "url": "https://ona.io/api/v1/orgs/modilabs",
>            "org": "modilabs",
>            "name": "Modi Labs Research",
>            "email": "*****@*****.**",
>            "city": "New York",
>            "country": "US",
>            "website": "",
>            "twitter": "",
>            "gravatar": "https://secure.gravatar.com/avatar/xxxxxx",
>            "require_auth": false,
>            "user": "******"
>            "creator": "https://ona.io/api/v1/users/demo"
>        },
>        {
>           ...}, ...
>       ]

## Retrieve Organization Profile Information

<pre class="prettyprint"><b>GET</b> /api/v1/orgs/{username}</pre>
> Example
>
>       curl -X GET https://ona.io/api/v1/orgs/modilabs

> Response
>
>        {
>            "url": "https://ona.io/api/v1/orgs/modilabs",
>            "org": "modilabs",
>            "name": "Modi Labs Research",
>            "email": "*****@*****.**",
>            "city": "New York",
>            "country": "US",
>            "website": "",
>            "twitter": "",
>            "gravatar": "https://secure.gravatar.com/avatar/xxxxxx",
>            "require_auth": false,
>            "user": "******"
>            "creator": "https://ona.io/api/v1/users/demo"
>        }

## List Organization members

Get a list of organization members.

<pre class="prettyprint"><b>GET</b> /api/v1/orgs/{username}/members</pre>
> Example
>
>       curl -X GET https://ona.io/api/v1/orgs/modilabs/members

> Response
>
>       ["member1", "member2"]

## Add a user to an organization

To add a user to an organization requires a JSON payload of
`{"username": "******"}`.

<pre class="prettyprint"><b>POST</b> /api/v1/orgs/{username}/members</pre>
> Example
>
>       curl -X POST -d '{"username": "******"}' \
https://ona.io/api/v1/orgs/modilabs/members -H "Content-Type: application/json"

> Response
>
>       ["member1"]

## Change the role of a user in an organization

To change the role of a user in an organization pass the username and role
`{"username": "******", "role": "owner|manager|editor|dataentry|readonly"}`.

<pre class="prettyprint"><b>PUT</b> /api/v1/orgs/{username}/members</pre>
> Example
>
>       curl -X PUT -d '{"username": "******", "role": "editor"}' \
https://ona.io/api/v1/orgs/modilabs/members -H "Content-Type: application/json"

> Response
>
>       ["member1"]

## Remove a user from an organization

To remove a user from an organization requires a JSON payload of
`{"username": "******"}`.

<pre class="prettyprint"><b>DELETE</b> /api/v1/orgs/{username}/members</pre>
> Example
>
>       curl -X DELETE -d '{"username": "******"}' \
https://ona.io/api/v1/orgs/modilabs/members -H "Content-Type: application/json"

> Response
>
>       []
"""
    queryset = OrganizationProfile.objects.all()
    default_response_headers = last_modified_header(
        get_date(OrganizationProfile.objects.last(), 'joined'))
    serializer_class = OrganizationSerializer
    lookup_field = 'user'
    permission_classes = [permissions.DjangoObjectPermissions]
    filter_backends = (OrganizationPermissionFilter, )

    @action(methods=['DELETE', 'GET', 'POST', 'PUT'])
    def members(self, request, *args, **kwargs):
        organization = self.get_object()
        self.headers = merge_dicts(
            self.headers,
            last_modified_header(get_date(organization, 'joined')))
        status_code = status.HTTP_200_OK
        data = []
        username = request.DATA.get('username') or request.QUERY_PARAMS.get(
            'username')

        if request.method in ['DELETE', 'POST', 'PUT'] and not username:
            status_code = status.HTTP_400_BAD_REQUEST
            data = {'username': [_(u"This field is required.")]}
        elif request.method == 'POST':
            data, status_code = _add_username_to_organization(
                organization, username)
        elif request.method == 'PUT':
            role = request.DATA.get('role')
            role_cls = ROLES.get(role)

            if not role or not role_cls:
                status_code = status.HTTP_400_BAD_REQUEST
                message = (_(u"'%s' is not a valid role." %
                             role) if role else _(u"This field is required."))
                data = {'role': [message]}
            else:
                _update_username_role(organization, username, role_cls)
        elif request.method == 'DELETE':
            data, status_code = _remove_username_to_organization(
                organization, username)

        if status_code in [status.HTTP_200_OK, status.HTTP_201_CREATED]:
            members = get_organization_members(organization)
            data = [u.username for u in members]

        return Response(data, status=status_code)
Beispiel #25
0
class UserViewSet(ReadOnlyModelViewSet):
    """
This endpoint allows you to list and retrieve user's first and last names.

## List Users
> Example
>
>       curl -X GET https://ona.io/api/v1/users

> Response:

>       [
>            {
>                "username": "******",
>                "first_name": "First",
>                "last_name": "Last"
>            },
>            {
>                "username": "******",
>                "first_name": "Another",
>                "last_name": "Demo"
>            },
>            ...
>        ]


## Retrieve a specific user info

<pre class="prettyprint"><b>GET</b> /api/v1/users/{username}</pre>

> Example:
>
>        curl -X GET https://ona.io/api/v1/users/demo

> Response:
>
>       {
>           "username": "******",
>           "first_name": "First",
>           "last_name": "Last"
>       }


## Search for a users using email
> Example
>
>       curl -X GET https://ona.io/api/v1/[email protected]

> Response:

>        [
>            {
>                "username": "******",
>                "first_name": "First",
>                "last_name": "Last"
>            },
>            {
>                "username": "******",
>                "first_name": "Another",
>                "last_name": "Demo"
>            },
>            ...
>        ]

"""
    queryset = User.objects.exclude(pk=settings.ANONYMOUS_USER_ID)
    default_response_headers = last_modified_header(
        get_date(User.objects.last(), 'joined'))
    serializer_class = UserSerializer
    lookup_field = 'username'
    permission_classes = [permissions.UserViewSetPermissions]
    filter_backends = (filters.SearchFilter, )
    search_fields = ('=email', )

    def get_object(self, queryset=None):
        """Lookup a  username by pk else use lookup_field"""
        if queryset is None:
            queryset = self.filter_queryset(self.get_queryset())

        lookup = self.kwargs.get(self.lookup_field)
        filter_kwargs = {self.lookup_field: lookup}

        try:
            pk = int(lookup)
        except ValueError:
            pass
        else:
            filter_kwargs = {'pk': pk}

        obj = get_object_or_404(queryset, **filter_kwargs)

        # May raise a permission denied
        self.check_object_permissions(self.request, obj)

        return obj
Beispiel #26
0
class XFormViewSet(AnonymousUserPublicFormsMixin, LabelsMixin, ModelViewSet):
    """
Publish XLSForms, List, Retrieve Published Forms.

Where:

- `pk` - is the form unique identifier

## Upload XLSForm

To publish and xlsform, you need to provide either the xlsform via `xls_file` \
parameter or a link to the xlsform via the `xls_url` parameter.
Optionally, you can specify the target account where the xlsform should be \
published using the `owner` parameter, which specifies the username to the
account.

- `xls_file`: the xlsform file.
- `xls_url`: the url to an xlsform
- `owner`: username to the target account (Optional)

<pre class="prettyprint">
<b>POST</b> /api/v1/forms</pre>
> Example
>
>       curl -X POST -F xls_file=@/path/to/form.xls \
https://ona.io/api/v1/forms
>
> OR post an xlsform url
>
>       curl -X POST -d \
"xls_url=https://ona.io/ukanga/forms/tutorial/form.xls" \
https://ona.io/api/v1/forms

> Response
>
>       {
>           "url": "https://ona.io/api/v1/forms/28058",
>           "formid": 28058,
>           "uuid": "853196d7d0a74bca9ecfadbf7e2f5c1f",
>           "id_string": "Birds",
>           "sms_id_string": "Birds",
>           "title": "Birds",
>           "allows_sms": false,
>           "bamboo_dataset": "",
>           "description": "",
>           "downloadable": true,
>           "encrypted": false,
>           "owner": "ona",
>           "public": false,
>           "public_data": false,
>           "date_created": "2013-07-25T14:14:22.892Z",
>           "date_modified": "2013-07-25T14:14:22.892Z"
>       }

## Get list of forms

<pre class="prettyprint">
<b>GET</b> /api/v1/forms</pre>

> Request
>
>       curl -X GET https://ona.io/api/v1/forms


## Get list of forms filter by owner

<pre class="prettyprint">
<b>GET</b> /api/v1/forms?<code>owner</code>=<code>owner_username</code></pre>

> Request
>
>       curl -X GET https://ona.io/api/v1/forms?owner=ona

## Get Form Information

<pre class="prettyprint">
<b>GET</b> /api/v1/forms/<code>{pk}</code></pre>

> Example
>
>       curl -X GET https://ona.io/api/v1/forms/28058

> Response
>
>       {
>           "url": "https://ona.io/api/v1/forms/28058",
>           "formid": 28058,
>           "uuid": "853196d7d0a74bca9ecfadbf7e2f5c1f",
>           "id_string": "Birds",
>           "sms_id_string": "Birds",
>           "title": "Birds",
>           "allows_sms": false,
>           "bamboo_dataset": "",
>           "description": "",
>           "downloadable": true,
>           "encrypted": false,
>           "owner": "https://ona.io/api/v1/users/ona",
>           "public": false,
>           "public_data": false,
>           "require_auth": false,
>           "date_created": "2013-07-25T14:14:22.892Z",
>           "date_modified": "2013-07-25T14:14:22.892Z"
>       }

## 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,
downloadable, owner, public, public_data, title, xls_file` fields.
 With `PATCH` you only need provide at least one of the fields.

- `xls_file`: Can only be updated when there are no submissions.

<pre class="prettyprint">
<b>PATCH</b> /api/v1/forms/<code>{pk}</code></pre>

> Example
>
>       curl -X PATCH -d "public=True" -d "description=Le description"\
https://ona.io/api/v1/forms/28058

> Response
>
>       {
>           "url": "https://ona.io/api/v1/forms/28058",
>           "formid": 28058,
>           "uuid": "853196d7d0a74bca9ecfadbf7e2f5c1f",
>           "id_string": "Birds",
>           "sms_id_string": "Birds",
>           "title": "Birds",
>           "allows_sms": false,
>           "bamboo_dataset": "",
>           "description": "Le description",
>           "downloadable": true,
>           "encrypted": false,
>           "owner": "https://ona.io/api/v1/users/ona",
>           "public": true,
>           "public_data": false,
>           "date_created": "2013-07-25T14:14:22.892Z",
>           "date_modified": "2013-07-25T14:14:22.892Z"
>       }

## Delete Form

<pre class="prettyprint">
<b>DELETE</b> /api/v1/forms/<code>{pk}</code></pre>
> Example
>
>       curl -X DELETE https://ona.io/api/v1/forms/28058
>
> Response
>
>       HTTP 204 NO CONTENT

## List Forms
<pre class="prettyprint">
<b>GET</b> /api/v1/forms
</pre>
> Example
>
>       curl -X GET https://ona.io/api/v1/forms

> Response
>
>       [{
>           "url": "https://ona.io/api/v1/forms/28058",
>           "formid": 28058,
>           "uuid": "853196d7d0a74bca9ecfadbf7e2f5c1f",
>           "id_string": "Birds",
>           "sms_id_string": "Birds",
>           "title": "Birds",
>           ...
>       }, ...]

## Get `JSON` | `XML` | `XLS` Form Representation
<pre class="prettyprint">
<b>GET</b> /api/v1/forms/<code>{pk}</code>/form.\
<code>{format}</code></pre>
> JSON Example
>
>       curl -X GET https://ona.io/api/v1/forms/28058/form.json

> Response
>
>        {
>            "name": "Birds",
>            "title": "Birds",
>            "default_language": "default",
>            "id_string": "Birds",
>            "type": "survey",
>            "children": [
>                {
>                    "type": "text",
>                    "name": "name",
>                    "label": "1. What is your name?"
>                },
>                ...
>                ]
>        }

> XML Example
>
>       curl -X GET https://ona.io/api/v1/forms/28058/form.xml

> Response
>
>        <?xml version="1.0" encoding="utf-8"?>
>        <h:html xmlns="http://www.w3.org/2002/xforms" ...>
>          <h:head>
>            <h:title>Birds</h:title>
>            <model>
>              <itext>
>                 .....
>          </h:body>
>        </h:html>

> XLS Example
>
>       curl -X GET https://ona.io/api/v1/forms/28058/form.xls

> Response
>
>       Xls file downloaded

## Get list of forms with specific tag(s)

Use the `tags` query parameter to filter the list of forms, `tags` should be a
comma separated list of tags.

<pre class="prettyprint">
<b>GET</b> /api/v1/forms?<code>tags</code>=<code>tag1,tag2</code></pre>

List forms tagged `smart` or `brand new` or both.
> Request
>
>       curl -X GET https://ona.io/api/v1/forms?tag=smart,brand+new

> Response
>        HTTP 200 OK
>
>       [{
>           "url": "https://ona.io/api/v1/forms/28058",
>           "formid": 28058,
>           "uuid": "853196d7d0a74bca9ecfadbf7e2f5c1f",
>           "id_string": "Birds",
>           "sms_id_string": "Birds",
>           "title": "Birds",
>           ...
>       }, ...]


## Get list of Tags for a specific Form
<pre class="prettyprint">
<b>GET</b> /api/v1/forms/<code>{pk}</code>/labels
</pre>
> Request
>
>       curl -X GET https://ona.io/api/v1/forms/28058/labels

> Response
>
>       ["old", "smart", "clean house"]

## Tag forms

A `POST` payload of parameter `tags` with a comma separated list of tags.

Examples

- `animal fruit denim` - space delimited, no commas
- `animal, fruit denim` - comma delimited

<pre class="prettyprint">
<b>POST</b> /api/v1/forms/<code>{pk}</code>/labels
</pre>

Payload

    {"tags": "tag1, tag2"}

## Delete a specific tag

<pre class="prettyprint">
<b>DELETE</b> /api/v1/forms/<code>{pk}</code>/labels/<code>tag_name</code>
</pre>

> Request
>
>       curl -X DELETE \
https://ona.io/api/v1/forms/28058/labels/tag1
>
> or to delete the tag "hello world"
>
>       curl -X DELETE \
https://ona.io/api/v1/forms/28058/labels/hello%20world
>
> Response
>
>        HTTP 200 OK

## Get webform/enketo link

<pre class="prettyprint">
<b>GET</b> /api/v1/forms/<code>{pk}</code>/enketo</pre>

> Request
>
>       curl -X GET \
https://ona.io/api/v1/forms/28058/enketo
>
> Response
>
>       {"enketo_url": "https://h6ic6.enketo.org/webform"}
>
>        HTTP 200 OK

## Get form data in xls, csv format.

Get form data exported as xls, csv, csv zip, sav zip format.

Where:

- `pk` - is the form unique identifier
- `format` - is the data export format i.e csv, xls, csvzip, savzip

Params for the custom xls report

- `meta`  - the metadata id containing the template url
-  `token`  - the template url

<pre class="prettyprint">
<b>GET</b> /api/v1/forms/{pk}.{format}</code>
</pre>
> Example
>
>       curl -X GET https://ona.io/api/v1/forms/28058.xls

> Binary file export of the format specified is returned as the response for
>the download.
>
> Response
>
>        HTTP 200 OK

> Example 2 Custom XLS reports (beta)
>
>       curl -X GET https://ona.io/api/v1/forms/28058.xls?meta=12121
>                   or
>       curl -X GET https://ona.io/api/v1/forms/28058.xls?token={url}
>
> XLS file is downloaded
>
> Response
>
>        HTTP 200 OK

## Get list of public forms

<pre class="prettyprint">
<b>GET</b> /api/v1/forms/public
</pre>

## Share a form with a specific user

You can share a form with a  specific user by `POST` a payload with

- `username` of the user you want to share the form with and
- `role` you want the user to have on the form. Available roles are `readonly`,
`dataentry`, `editor`, `manager`.

<pre class="prettyprint">
<b>POST</b> /api/v1/forms/<code>{pk}</code>/share
</pre>

> Example
>
>       curl -X POST -d '{"username": "******", "role": "readonly"}' \
https://ona.io/api/v1/forms/123.json

> Response
>
>        HTTP 204 NO CONTENT

## Clone a form to a specific user account

You can clone a form to a specific user account using `GET` with

- `username` of the user you want to clone the form to

<pre class="prettyprint">
<b>GET</b> /api/v1/forms/<code>{pk}</code>/clone
</pre>

> Example
>
>       curl -X GET https://ona.io/api/v1/forms/123/clone \
-d username=alice

> Response
>
>        HTTP 201 CREATED
>       {
>           "url": "https://ona.io/api/v1/forms/124",
>           "formid": 124,
>           "uuid": "853196d7d0a74bca9ecfadbf7e2f5c1e",
>           "id_string": "Birds_cloned_1",
>           "sms_id_string": "Birds_cloned_1",
>           "title": "Birds_cloned_1",
>           ...
>       }

## Import CSV data to existing form

- `csv_file` a valid csv file with exported \
data (instance/submission per row)

<pre class="prettyprint">
<b>GET</b> /api/v1/forms/<code>{pk}</code>/csv_import
</pre>

> Example
>
>       curl -X POST https://ona.io/api/v1/forms/123/csv_import \
-F csv_file=@/path/to/csv_import.csv
>
> Response
>
>        HTTP 200 OK
>       {
>           "additions": 9,
>           "updates": 0
>       }
"""
    renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES + [
        renderers.XLSRenderer, renderers.XLSXRenderer, renderers.CSVRenderer,
        renderers.CSVZIPRenderer, renderers.SAVZIPRenderer,
        renderers.SurveyRenderer
    ]
    queryset = XForm.objects.all()
    default_response_headers = last_modified_header(
        get_date(XForm.objects.last(), 'modified'))
    serializer_class = XFormSerializer
    lookup_field = 'pk'
    extra_lookup_fields = None
    permission_classes = [
        XFormPermissions,
    ]
    updatable_fields = set(('description', 'downloadable', 'require_auth',
                            'shared', 'shared_data', 'title'))
    filter_backends = (filters.AnonDjangoObjectPermissionFilter,
                       filters.TagFilter, filters.XFormOwnerFilter)

    public_forms_endpoint = 'public'

    def create(self, request, *args, **kwargs):
        try:
            owner = _get_owner(request)
        except ValidationError as e:
            return Response({'message': e.messages[0]},
                            status=status.HTTP_400_BAD_REQUEST)

        survey = utils.publish_xlsform(request, owner)
        if isinstance(survey, XForm):
            xform = XForm.objects.get(pk=survey.pk)
            serializer = XFormSerializer(xform, context={'request': request})
            headers = self.get_success_headers(serializer.data)

            return Response(serializer.data,
                            status=status.HTTP_201_CREATED,
                            headers=headers)

        return Response(survey, status=status.HTTP_400_BAD_REQUEST)

    @action(methods=['GET'])
    def form(self, request, format='json', **kwargs):
        form = self.get_object()
        if format not in ['json', 'xml', 'xls']:
            return HttpResponseBadRequest('400 BAD REQUEST',
                                          content_type='application/json',
                                          status=400)
        return response_for_format(form, format=format)

    @action(methods=['GET'])
    def enketo(self, request, **kwargs):
        self.object = self.get_object()
        form_url = _get_form_url(request, self.object.user.username)

        data = {'message': _(u"Enketo not properly configured.")}
        http_status = status.HTTP_400_BAD_REQUEST

        try:
            url = enketo_url(form_url, self.object.id_string)
        except EnketoError:
            pass
        else:
            if url:
                http_status = status.HTTP_200_OK
                data = {"enketo_url": url}

        return Response(data, http_status)

    def retrieve(self, request, *args, **kwargs):
        lookup_field = self.lookup_field
        lookup = self.kwargs.get(lookup_field)

        if lookup == self.public_forms_endpoint:
            self.object_list = self._get_public_forms_queryset()

            page = self.paginate_queryset(self.object_list)
            if page is not None:
                serializer = self.get_pagination_serializer(page)
            else:
                serializer = self.get_serializer(self.object_list, many=True)

            return Response(serializer.data)

        xform = self.get_object()
        export_type = kwargs.get('format')
        query = request.GET.get("query", {})
        token = request.GET.get('token')
        meta = request.GET.get('meta')

        if export_type is None or export_type in ['json']:
            # perform default viewset retrieve, no data export
            return super(XFormViewSet, self).retrieve(request, *args, **kwargs)

        return custom_response_handler(request, xform, query, export_type,
                                       token, meta)

    @action(methods=['POST'])
    def share(self, request, *args, **kwargs):
        self.object = self.get_object()

        data = {}
        for key, val in request.DATA.iteritems():
            data[key] = val
        data.update({'xform': self.object.pk})

        serializer = ShareXFormSerializer(data=data)

        if serializer.is_valid():
            serializer.save()
        else:
            return Response(data=serializer.errors,
                            status=status.HTTP_400_BAD_REQUEST)

        return Response(status=status.HTTP_204_NO_CONTENT)

    @action(methods=['GET'])
    def clone(self, request, *args, **kwargs):
        self.object = self.get_object()
        data = {'xform': self.object.pk, 'username': request.DATA['username']}
        serializer = CloneXFormSerializer(data=data)
        if serializer.is_valid():
            clone_to_user = User.objects.get(username=data['username'])
            if not request.user.has_perm('can_add_xform',
                                         clone_to_user.profile):
                raise exceptions.PermissionDenied(
                    detail=_(u"User %(user)s has no permission to add "
                             "xforms to account %(account)s" % {
                                 'user': request.user.username,
                                 'account': data['username']
                             }))
            xform = serializer.save()
            serializer = XFormSerializer(xform.cloned_form,
                                         context={'request': request})

            return Response(data=serializer.data,
                            status=status.HTTP_201_CREATED)

        return Response(data=serializer.errors,
                        status=status.HTTP_400_BAD_REQUEST)

    @detail_route(methods=['POST'])
    def csv_import(self, request, *args, **kwargs):
        """ Endpoint for CSV data imports

        Calls :py:func:`onadata.libs.utils.csv_import.submit_csv`
        passing with the `request.FILES.get('csv_file')` upload for import.
        """
        resp = submit_csv(request.user.username, self.get_object(),
                          request.FILES.get('csv_file'))

        return Response(data=resp,
                        status=status.HTTP_200_OK if resp.get('error') is None
                        else status.HTTP_400_BAD_REQUEST)

    def partial_update(self, request, *args, **kwargs):
        try:
            owner = _get_owner(request)
        except ValidationError as e:
            return Response({'message': e.messages[0]},
                            status=status.HTTP_400_BAD_REQUEST)

        self.object = self.get_object()

        # updating the file
        if request.FILES:
            return _try_update_xlsform(request, self.object, owner)

        return super(XFormViewSet,
                     self).partial_update(request, *args, **kwargs)
Beispiel #27
0
class MetaDataViewSet(viewsets.ModelViewSet):
    """
    This endpoint provides access to form metadata, for example, supporting
    documents, media files to be used in the form, source documents and map
    layers.

    - `pk` - primary key for the metadata
    - `formid` - the form id for a form
    - `format` - is the extension of a file format e.g `png`, `csv`

    ### Permissions

    This endpoint applys the same permissions someone has on the form.

    ## Get list of metadata

    Returns a list of metadata accross all forms requesting user has access to.

    <pre class="prettyprint">GET /api/v1/metadata</pre>

        HTTP 200 OK

        [
            {
                "data_file": "",
                "data_file_type": null,
                "data_type": "public_link",
                "data_value": "http://mylink",
                "id": 406,
                "url": "https://ona.io/api/v1/metadata/406",
                "xform": 328
            },
            {
                "data_file": "username/form-media/a.png",
                "data_file_type": "image/png",
                "data_type": "media",
                "data_value": "a.png",
                "id": 7100,
                "url": "https://ona.io/api/v1/metadata/7100",
                "xform": 320
            },
            ....
        ]

    ## Get list of metadata for a specific form

    The form endpoint, `/api/v1/forms/formid`, contains a `metadata` field
    has list of metadata for the form. Alternatively, you can supply the query
    parameter `xform` with the `formid` as the value.

    <pre class="prettyprint">
    GET /api/v1/metdata?<code>xform=formid</code></pre>

        HTTP 200 OK

        [
            {
                "data_file": "username/form-media/a.png",
                "data_file_type": "image/png",
                "data_type": "media",
                "data_value": "a.png",
                "id": 7100,
                "url": "https://ona.io/api/v1/metadata/7100",
                "xform": 320
            },
            ....
        ]

    ## Get a specific metadata

    <pre class="prettyprint">
    GET /api/v1/metadata/<code>{pk}</code></pre>

        curl -X GET https://ona.io/api/v1/metadata/7100

        HTTP 200 OK

        {
            "data_file": "username/form-media/a.png",
            "data_file_type": "image/png",
            "data_type": "media",
            "data_value": "a.png",
            "id": 7100,
            "url": "https://ona.io/api/v1/metadata/7100",
            "xform": 320
        }

    If the metadata is a file, appending the extension of the file type would
    return the file itself e.g:

    <pre class="prettyprint">
    GET /api/v1/metadata/<code>{pk}.{format}</code></pre>

        curl -X GET https://ona.io/api/v1/metadata/7100.png -o a.png

    Alternatively, if the request is made with an `Accept` header of the
    content type of the file the file would be returned e.g

    <pre class="prettyprint">GET /api/v1/metadata/<code>{pk}</code> \
Accept: image/png </pre>

         curl -X GET https://ona.io/api/v1/metadata/7100 \
-H "Accept: image/png" -o a.png

    ## Add metadata or media file to a form

    <pre class="prettyprint">POST /api/v1/metadata</pre>
    Payload

           {"xform": <formid>, "data_type": "<data_type>", \
"data_value": "<data_value>"}

    Where:

    - `data_type` - can be 'media' or 'source' or 'supporting_doc'
    - `data_value` - can be text or a file name
    - `xform` - the form id you are adding the media to
    - `data_file` - optional, should be the file you want to upload

    Example:

            curl -X POST -d "{"data_type": "mapbox_layer", "data_value": \
"example||https://api.tiles.mapbox.com/v3/examples.map-0l53fhk2.json||example\
 attribution", "xform": 320}" https://ona.io/api/v1/metadata \
-H "Content-Type: appliction/json"

            HTTP 201 CREATED

            {
            "id": 7119,
            "xform": 320,
            "data_value": "example||https://api.tiles.mapbox.com/v3/examples\
.map-0l53fhk2.json||example attribution",
            "data_type": "mapbox_layer",
            "data_file": null,
            "data_file_type": null,
            "url": "https://ona.io/api/v1/metadata/7119.json"
            }

    Media upload example:

            curl -X POST -F 'data_type=media' -F 'data_value=demo.jpg' \
-F 'xform=320' -F "[email protected]" https://ona.io/api/v1/metadata.json

            HTTP 201 CREATED

            {
            "id": 7121,
            "xform": 320,
            "data_value": "folder.jpg",
            "data_type": "media",
            "data_file": "ukanga/formid-media/folder.jpg",
            "data_file_type": "image/jpeg",
            "url": "https://ona.io/api/v1/metadata/7121.json"
            }


    ## Delete Metadata

    <pre class="prettyprint">DELETE /api/v1/metadata/<code>{pk}</code></pre>

    """
    content_negotiation_class = MediaFileContentNegotiation
    filter_backends = (filters.MetaDataFilter, )
    queryset = MetaData.objects.all()
    default_response_headers = last_modified_header(
        get_date(MetaData.objects.last(), 'modified'))
    permission_classes = (MetaDataObjectPermissions, )
    renderer_classes = (renderers.JSONRenderer, renderers.BrowsableAPIRenderer,
                        MediaFileRenderer)
    serializer_class = MetaDataSerializer

    def retrieve(self, request, *args, **kwargs):
        self.object = self.get_object()

        if isinstance(request.accepted_renderer, MediaFileRenderer) \
                and self.object.data_file is not None:

            return get_media_file_response(self.object)

        serializer = self.get_serializer(self.object)

        return Response(serializer.data)
Beispiel #28
0
class AttachmentViewSet(viewsets.ReadOnlyModelViewSet):
    """

    ## Lists attachments of all xforms
    >       GET /api/v1/media/
    > Example
    >
    >       curl -X GET https://ona.io/api/v1/media

    > Response
    >
    >        [{
    >           "download_url": "http://ona.io/api/v1/media/1.jpg",
    >           "small_download_url": "http://ona.io/api/v1/media/1-small.jpg",
    >           "medium_download_url": "http://ona.io/api/v1/media/\
1-medium.jpg",
    >           "filename": "doe/attachments/1408520136827.jpg",
    >           "id": 1,
    >           "instance": 1,
    >           "mimetype": "image/jpeg",
    >           "url": "http://ona.io/api/v1/media/1",
    >           "xform": 1,
    >        }
    >        ...

    ## Retrieve details of an attachment
    ><pre class="prettyprint">  GET /api/v1/media/<code>{pk}</code></pre>
    >
    > Example
    >
    >       curl -X GET https://ona.io/api/v1/media/1

    > Response
    >
    >        {
    >           "download_url": "http://ona.io/api/v1/media/1.jpg",
    >           "small_download_url": "http://ona.io/api/v1/media/1-small.jpg",
    >           "medium_download_url": "http://ona.io/api/v1/media/\
1-medium.jpg",
    >           "filename": "doe/attachments/1408520136827.jpg",
    >           "id": 1,
    >           "instance": 1,
    >           "mimetype": "image/jpeg",
    >           "url": "http://ona.io/api/v1/media/1",
    >           "xform": 1,
    >        }

    ## Retrieve an attachment file

    ><pre class="prettyprint">
    >     GET /api/v1/media/<code>{pk}.{format}</code></pre>
    >
    >         curl -X GET https://ona.io/api/v1/media/1.png -o a.png

    Alternatively, if the request is made with an `Accept` header of the
    content type of the file the file would be returned e.g

    ><pre class="prettyprint">
    > GET /api/v1/media/<code>{pk}</code> Accept: image/png </pre>
    >
    > Example
    >
    >     curl -X GET https://ona.io/api/v1/media/1 -H "Accept: image/png" -o
    >     a.png

    ## Lists attachments of a specific xform
    ><pre class="prettyprint">
    > GET /api/v1/media/?xform=<code>{xform}</code></pre>
    >
    > Example
    >
    >     curl -X GET https://ona.io/api/v1/media?xform=1

    > Response
    >
    >        [{
    >           "download_url": "http://ona.io/api/v1/media/1.jpg",
    >           "small_download_url": "http://ona.io/api/v1/media/1-small.jpg",
    >           "medium_download_url": "http://ona.io/api/v1/media/\
1-medium.jpg",
    >           "filename": "doe/attachments/1408520136827.jpg",
    >           "id": 1,
    >           "instance": 1,
    >           "mimetype": "image/jpeg",
    >           "url": "http://ona.io/api/v1/media/1",
    >           "xform": 1,
    >        }
    >        ...

    ## Lists attachments of a specific instance
    ><pre class="prettyprint">
    > GET /api/v1/media?instance=<code>{instance}</code></pre>
    >
    > Example
    >
    >     curl -X GET https://ona.io/api/v1/media?instance=1

    > Response
    >
    >        [{
    >           "download_url": "http://ona.io/api/v1/media/1.jpg",
    >           "small_download_url": "http://ona.io/api/v1/media/1-small.jpg",
    >           "medium_download_url": "http://ona.io/api/v1/media/\
1-medium.jpg",
    >           "filename": "doe/attachments/1408520136827.jpg",
    >           "id": 1,
    >           "instance": 1,
    >           "mimetype": "image/jpeg",
    >           "url": "http://ona.io/api/v1/media/1",
    >           "xform": 1,
    >        }
    >        ...

    ## Retrieve image link of an attachment
    ><pre class="prettyprint">  GET /api/v1/media/<code>{pk}</code></pre>
    >
    > Example
    >
    >       curl -X GET https://ona.io/api/v1/media/1\
?filename=doe/attachments/1408520136827.jpg

    > Response
    >
    >        http://ona.io/api/v1/media/1.jpg

    """
    content_negotiation_class = MediaFileContentNegotiation
    filter_backends = (filters.AttachmentFilter, )
    lookup_field = 'pk'
    queryset = Attachment.objects.all()
    default_response_headers = last_modified_header(
        get_date(Attachment.objects.last(), 'modified'))
    permission_classes = (AttachmentObjectPermissions, )
    serializer_class = AttachmentSerializer
    renderer_classes = (renderers.JSONRenderer, renderers.BrowsableAPIRenderer,
                        MediaFileRenderer)

    def retrieve(self, request, *args, **kwargs):
        self.object = self.get_object()
        self.headers = merge_dicts(
            self.headers,
            last_modified_header(get_date(self.object, 'modified')))

        if isinstance(request.accepted_renderer, MediaFileRenderer) \
                and self.object.media_file is not None:
            data = self.object.media_file.read()

            return Response(data, content_type=self.object.mimetype)

        filename = request.QUERY_PARAMS.get('filename')
        serializer = self.get_serializer(self.object)

        if filename:
            if filename == self.object.media_file.name:
                return Response(serializer.get_download_url(self.object))
            else:
                raise Http404(_("Filename '%s' not found." % filename))

        return Response(serializer.data)
Beispiel #29
0
class UserProfileViewSet(ObjectLookupMixin, ModelViewSet):
    """
List, Retrieve, Update, Create/Register users.

## Register a new User
<pre class="prettyprint"><b>POST</b> /api/v1/profiles</pre>
> Example
>
>        {
>            "username": "******",
>            "name": "Demo User",
>            "email": "*****@*****.**",
>            "city": "Kisumu",
>            "country": "KE",
>            ...
>        }

## List User Profiles
<pre class="prettyprint"><b>GET</b> /api/v1/profiles</pre>
> Example
>
>       curl -X GET https://ona.io/api/v1/profiles

> Response
>
>       [
>        {
>            "url": "https://ona.io/api/v1/profiles/demo",
>            "username": "******",
>            "name": "Demo User",
>            "email": "*****@*****.**",
>            "city": "",
>            "country": "",
>            "organization": "",
>            "website": "",
>            "twitter": "",
>            "gravatar": "https://secure.gravatar.com/avatar/xxxxxx",
>            "require_auth": false,
>            "user": "******"
>            "metadata": {},
>            "joined_on": "2014-11-10T14:22:20.394Z"
>        },
>        {
>           ...}, ...
>       ]

## Retrieve User Profile Information

<pre class="prettyprint"><b>GET</b> /api/v1/profiles/{username}</pre>
<pre class="prettyprint"><b>GET</b> /api/v1/profiles/{pk}</pre>
> Example
>
>       curl -X GET https://ona.io/api/v1/profiles/demo

> Response
>
>        {
>            "url": "https://ona.io/api/v1/profiles/demo",
>            "username": "******",
>            "name": "Demo User",
>            "email": "*****@*****.**",
>            "city": "",
>            "country": "",
>            "organization": "",
>            "website": "",
>            "twitter": "",
>            "gravatar": "https://secure.gravatar.com/avatar/xxxxxx",
>            "require_auth": false,
>            "user": "******"
>            "metadata": {},
>            "joined_on": "2014-11-10T14:22:20.394Z"

## Partial updates of User Profile Information

Properties of the UserProfile can be updated using `PATCH` http method.
Payload required is for properties that are to be changed in JSON,
for example, `{"country": "KE"}` will set the country to `KE`.

<pre class="prettyprint"><b>PATCH</b> /api/v1/profiles/{username}</pre>
> Example
>
>     \
curl -X PATCH -d '{"country": "KE"}' https://ona.io/api/v1/profiles/demo \
-H "Content-Type: application/json"

> Response
>
>        {
>            "url": "https://ona.io/api/v1/profiles/demo",
>            "username": "******",
>            "name": "Demo User",
>            "email": "*****@*****.**",
>            "city": "",
>            "country": "KE",
>            "organization": "",
>            "website": "",
>            "twitter": "",
>            "gravatar": "https://secure.gravatar.com/avatar/xxxxxx",
>            "require_auth": false,
>            "user": "******"
>            "metadata": {},
>            "joined_on": "2014-11-10T14:22:20.394Z"
>        }

## Change authenticated user's password
> Example
>
>       curl -X POST -d current_password=password1 -d new_password=password2\
 https://ona.io/api/v1/profile/demouser/change_password
> Response:
>
>        HTTP 200 OK
"""
    queryset = UserProfile.objects.exclude(user__pk=settings.ANONYMOUS_USER_ID)
    default_response_headers = last_modified_header(
        get_date(UserProfile.objects.last(), 'joined'))
    serializer_class = UserProfileSerializer
    lookup_field = 'user'
    permission_classes = [UserProfilePermissions]
    ordering = ('user__username', )

    def get_object(self, queryset=None):
        """Lookup user profile by pk or username"""
        if self.kwargs.get(self.lookup_field, None) is None:
            raise ParseError('Expected URL keyword argument `%s`.' %
                             self.lookup_field)
        if queryset is None:
            queryset = self.filter_queryset(self.get_queryset())

        serializer = self.get_serializer()
        lookup_field = self.lookup_field

        if self.lookup_field in serializer.get_fields():
            k = serializer.get_fields()[self.lookup_field]
            if isinstance(k, serializers.HyperlinkedRelatedField):
                lookup_field = '%s__%s' % (self.lookup_field, k.lookup_field)

        lookup = self.kwargs[self.lookup_field]
        filter_kwargs = {lookup_field: lookup}

        try:
            pk = int(lookup)
        except (TypeError, ValueError):
            pass
        else:
            filter_kwargs = {'user__pk': pk}

        obj = get_object_or_404(queryset, **filter_kwargs)

        # May raise a permission denied
        self.check_object_permissions(self.request, obj)

        return obj

    @action(methods=['POST'])
    def change_password(self, request, *args, **kwargs):
        user_profile = self.get_object()
        current_password = request.DATA.get('current_password', None)
        new_password = request.DATA.get('new_password', None)

        if new_password:
            if user_profile.user.check_password(current_password):
                user_profile.user.set_password(new_password)
                user_profile.user.save()

                return Response(status=status.HTTP_200_OK)

        return Response(status=status.HTTP_400_BAD_REQUEST)
Beispiel #30
0
class TeamViewSet(ModelViewSet):

    """
This endpoint allows you to create, update and view team information.

## GET List of Teams
Provides a json list of teams and the projects the team is assigned to.

<pre class="prettyprint">
<b>GET</b> /api/v1/teams
</pre>

> Example
>
>       curl -X GET https://ona.io/api/v1/teams

> Response
>
>        [
>            {
>                "url": "https://ona.io/api/v1/teams/1",
>                "name": "Owners",
>                "organization": "bruize",
>                "projects": []
>            },
>            {
>                "url": "https://ona.io/api/v1/teams/2",
>                "name": "demo team",
>                "organization": "bruize",
>                "projects": []
>            }
>        ]

## GET Team Info for a specific team.

Shows teams details and the projects the team is assigned to, where:

* `pk` - unique identifier for the team

<pre class="prettyprint">
<b>GET</b> /api/v1/teams/<code>{pk}</code>
</pre>

> Example
>
>       curl -X GET https://ona.io/api/v1/teams/1

> Response
>
>        {
>            "url": "https://ona.io/api/v1/teams/1",
>            "name": "Owners",
>            "organization": "bruize",
>            "projects": []
>        }

## List members of a team

A list of usernames is the response for members of the team.

<pre class="prettyprint">
<b>GET</b> /api/v1/teams/<code>{pk}/members</code>
</pre>

> Example
>
>       curl -X GET https://ona.io/api/v1/teams/1/members

> Response
>
>       ["member1"]
>

## Add a user to a team

POST `{"username": "******"}`
to `/api/v1/teams/<pk>/members` to add a user to
the specified team.
A list of usernames is the response for members of the team.

<pre class="prettyprint">
<b>POST</b> /api/v1/teams/<code>{pk}</code>/members
</pre>

> Response
>
>       ["someusername"]

"""
    queryset = Team.objects.all()
    default_response_headers = last_modified_header(
        get_date(Team.objects.last(), 'modified'))
    serializer_class = TeamSerializer
    lookup_field = 'pk'
    extra_lookup_fields = None
    permission_classes = [DjangoObjectPermissions]
    filter_backends = (filters.DjangoObjectPermissionsFilter,)

    @action(methods=['DELETE', 'GET', 'POST'])
    def members(self, request, *args, **kwargs):
        team = self.get_object()
        data = {}
        status_code = status.HTTP_200_OK

        if request.method in ['DELETE', 'POST']:
            username = request.DATA.get('username') or\
                request.QUERY_PARAMS.get('username')

            if username:
                try:
                    user = User.objects.get(username__iexact=username)
                except User.DoesNotExist:
                    status_code = status.HTTP_400_BAD_REQUEST
                    data['username'] = [
                        _(u"User `%(username)s` does not exist."
                          % {'username': username})]
                else:
                    if request.method == 'POST':
                        add_user_to_team(team, user)
                    elif request.method == 'DELETE':
                        remove_user_from_team(team, user)
                    status_code = status.HTTP_201_CREATED
            else:
                status_code = status.HTTP_400_BAD_REQUEST
                data['username'] = [_(u"This field is required.")]

        if status_code in [status.HTTP_200_OK, status.HTTP_201_CREATED]:
            data = [u.username for u in team.user_set.all()]

        return Response(data, status=status_code)
Beispiel #31
0
class ChartsViewSet(AnonymousUserPublicFormsMixin,
                    viewsets.ReadOnlyModelViewSet):
    """
View chart for specific fields in a form or dataset.

### List of chart chart endpoints accessible to registered user
<pre class="prettyprint">
<b>GET</b> /api/v1/charts</pre>

> Example
>
>       curl -X GET https://ona.io/api/v1/charts

> Response
>
>        [{
>
>            "id": 4240,
>            "id_string": "dhis2form"
>            "url": "https://ona.io/api/v1/charts/4240",
>        }
>        ...

### Get a list of chart field endpoints for a specific form or dataset.

<pre class="prettyprint">
<b>GET</b> /api/v1/charts/<code>{formid}</code></pre>

> Example
>
>       curl -X GET https://ona.io/api/v1/charts/4240

> Response
>
>        {
>
>            "id": 4240,
>            "id_string": "dhis2form"
>            "url": "https://ona.io/api/v1/charts/4240",
>            "fields": {
>                "uuid": "https://ona.io/api/v1/charts/4240?field_name=uuid",
>                "num": "https://ona.io/api/v1/charts/4240?field_name=num",
>                ...
>            }
>        }

### Get a chart for a specific field in a form

- `field_name` - a field name in the form
- `format` - can be `html` or `json`

<pre class="prettyprint">
<b>GET</b> /api/v1/charts/<code>{formid}</code>.<code>{format}</code>?\
field_name=<code>field_name</code></pre>

> Example
>
>       curl -X GET https://ona.io/api/v1/charts/4240.html?field_name=age

> Response
>
> - `html` format response is a html, javascript and css to the chart
> - `json` format response is the `JSON` data that can be passed to a charting
> library

### Get a chart data for all fields in a form

The only field ommitted is instanceID since it is unique for every record.

- `fields` - is a comma separated list of fields to be included in the \
response. If `fields=all` then all the fields of the form will be returned.

<pre class="prettyprint">
<b>GET</b> /api/v1/charts/<code>{formid}</code>?<code>fields=all</code>
</pre>

> Example
>
>       curl -X GET https://ona.io/api/v1/charts/4240?fields=all

> Response
>
> - `json` format response is the `JSON` data for each field that can be
> passed to a charting library
    """
    filter_backends = (filters.AnonDjangoObjectPermissionFilter, )
    queryset = XForm.objects.all()
    default_response_headers = last_modified_header(
        get_date(XForm.objects.last(), 'modified'))
    serializer_class = ChartSerializer
    lookup_field = 'pk'
    renderer_classes = (
        ChartBrowsableAPIRenderer,
        JSONRenderer,
        TemplateHTMLRenderer,
    )
    permission_classes = [
        XFormPermissions,
    ]

    def retrieve(self, request, *args, **kwargs):
        xform = self.get_object()
        serializer = self.get_serializer(xform)
        dd = xform.data_dictionary()

        field_name = request.QUERY_PARAMS.get('field_name')
        fields = request.QUERY_PARAMS.get('fields')
        fmt = kwargs.get('format')

        self.headers = merge_dicts(
            self.headers, last_modified_header(get_date(xform, 'modified')))
        if fields:
            if fmt is not None and fmt != 'json':
                raise ParseError("Error: only JSON format supported.")

            xform = self.get_object()
            self.headers['Last-Modified'] = get_date(xform, 'modified')
            context = self.get_serializer_context()
            serializer = FieldsChartSerializer(instance=xform, context=context)

            return Response(serializer.data)

        if field_name:
            # check if its the special _submission_time META
            if field_name == common_tags.SUBMISSION_TIME:
                field = common_tags.SUBMISSION_TIME
            else:
                # use specified field to get summary
                fields = filter(lambda f: f.name == field_name,
                                [e for e in dd.survey_elements])

                if len(fields) == 0:
                    raise Http404("Field %s does not not exist on the form" %
                                  field_name)

                field = fields[0]

            data = build_chart_data_for_field(xform, field)

            if request.accepted_renderer.format == 'json':
                xform = xform.pk
            elif request.accepted_renderer.format == 'html' and 'data' in data:
                for item in data['data']:
                    if isinstance(item[field_name], list):
                        item[field_name] = u', '.join(item[field_name])

            data.update({'xform': xform})

            return Response(data, template_name='chart_detail.html')

        if fmt != 'json' and field_name is None:
            raise ParseError("Not supported")

        data = serializer.data
        data["fields"] = {}
        for field in dd.survey_elements:
            field_url = get_form_field_chart_url(data["url"], field.name)
            data["fields"][field.name] = field_url

        return Response(data)
Beispiel #32
0
class ConnectViewSet(ObjectLookupMixin, viewsets.GenericViewSet):
    """This endpoint allows you retrieve the authenticated user's profile info.

# Retrieve profile
> Example
>
>       curl -X GET https://ona.io/api/v1/user

> Response:

>       {
            "api_token": "76121138a080c5ae94f318a8b9be91e7ebebb484",
            "temp_token": "0668993ad2f9fa6a0bff58389996cf85f11894ca"
            "city": "Nairobi",
            "country": "Kenya",
            "gravatar": "avatar.png",
            "name": "Demo User",
            "email": "*****@*****.**",
            "organization": "",
            "require_auth": false,
            "twitter": "",
            "url": "http://localhost:8000/api/v1/profiles/demo",
            "user": "******",
            "username": "******",
            "website": "",
}

# Get projects that the authenticating user has starred
<pre class="prettyprint">
<b>GET</b> /api/v1/user/<code>{username}</code>/starred</pre>

# Request password reset
<pre class="prettyprint">
<b>POST</b> /api/v1/user/reset
</pre>

- Sends an email to the user's email with a url that \
redirects to a reset password form on the API consumer's website.
- `email` and `reset_url` are expected in the POST payload.
- Expected reset_url format is `reset_url=https:/domain/path/to/reset/form`.
- Example of reset url sent to user's email is\
`http://mydomain.com/reset_form?uid=Mg&token=2f3f334g3r3434&username=dXNlcg==`.
- `uid` is the users `unique key` which is a base64 encoded integer value that\
 can be used to access the users info at `/api/v1/users/<pk>` or \
`/api/v1/profiles/<pk>`. You can retrieve the integer value in `javascript` \
using the `window.atob();` function.
`username` is a base64 encoded value of the user's username
- `token` is a onetime use token that allows password reset

>
> Example
>
>       curl -X POST -d [email protected]\
 url=http://example-url.com/reset https://ona.io/api/v1/user/reset
>
> Response:
>
>        HTTP 204 OK


>
# Reset user password
<pre class="prettyprint">
<b>POST</b> /api/v1/user/reset
</pre>

- Resets user's password
- `uid`, `token` and `new_password` are expected in the POST payload.
- minimum password length is 4 characters

>
> Example
>
>       curl -X POST -d uid=Mg -d token=qndoi209jf02n4 \
-d new_password=usernewpass https://ona.io/api/v1/user/reset
>
> Response:
>
>        HTTP 204 OK
>
# Expire temporary token
<pre class="prettyprint">
<b>DELETE</b> /api/v1/user/expire
</pre>

- Expires the temporary token

>
> Example
>
>       curl -X DELETE https://ona.io/api/v1/user/expire \
-u <username>:<password>
>
> Response:
>
>        HTTP 204 OK
>

"""
    lookup_field = 'user'
    queryset = UserProfile.objects.all()
    default_response_headers = last_modified_header(
        get_date(UserProfile.objects.last(), 'joined'))
    permission_classes = (ConnectViewsetPermissions, )
    serializer_class = UserProfileWithTokenSerializer

    def list(self, request, *args, **kwargs):
        """ Returns authenticated user profile"""

        if request and not request.user.is_anonymous():
            session = getattr(request, "session")
            if not session.session_key:
                # login user to create session token
                # TODO cannot call this without calling authenticate first or
                # setting the backend, commented for now.
                # login(request, request.user)
                session.set_expiry(DEFAULT_SESSION_EXPIRY_TIME)

        serializer = UserProfileWithTokenSerializer(
            instance=request.user.profile, context={"request": request})

        return Response(serializer.data)

    @action(methods=['GET'])
    def starred(self, request, *args, **kwargs):
        """Return projects starred for this user."""
        user_profile = self.get_object()
        self.headers = merge_dicts(
            self.headers,
            last_modified_header(get_date(user_profile, 'joined')))
        user = user_profile.user
        projects = user.project_set.all()
        serializer = ProjectSerializer(projects,
                                       context={'request': request},
                                       many=True)

        return Response(data=serializer.data)

    @list_route(methods=['POST'])
    def reset(self, request, *args, **kwargs):
        context = {'request': request}
        data = request.DATA if request.DATA is not None else {}
        if 'token' in request.DATA:
            serializer = PasswordResetChangeSerializer(data=data,
                                                       context=context)
        else:
            serializer = PasswordResetSerializer(data=data, context=context)

        if serializer.is_valid():
            serializer.save()

            return Response(status=status.HTTP_204_NO_CONTENT)

        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    @list_route(methods=['DELETE'])
    def expire(self, request, *args, **kwargs):
        try:
            TempToken.objects.get(user=request.user).delete()
        except TempToken.DoesNotExist:
            raise ParseError(_(u"Temporary token not found!"))

        return Response(status=status.HTTP_204_NO_CONTENT)
Beispiel #33
0
class DataViewSet(AnonymousUserPublicFormsMixin, ModelViewSet):
    """
This endpoint provides access to submitted data in JSON format. Where:

* `pk` - the form unique identifier
* `dataid` - submission data unique identifier
* `owner` - username of the owner(user/organization) of the data point

## GET JSON List of data end points

Lists the data endpoints accessible to requesting user, for anonymous access
a list of public data endpoints is returned.

<pre class="prettyprint">
<b>GET</b> /api/v1/data
</pre>

> Example
>
>       curl -X GET https://ona.io/api/v1/data

> Response
>
>        [{
>            "id": 4240,
>            "id_string": "dhis2form"
>            "title": "dhis2form"
>            "description": "dhis2form"
>            "url": "https://ona.io/api/v1/data/4240"
>         },
>            ...
>        ]

## Download data in `csv` format
<pre class="prettyprint">
<b>GET</b> /api/v1/data.csv</pre>
>
>       curl -O https://ona.io/api/v1/data.csv

## GET JSON List of data end points filter by owner

Lists the data endpoints accessible to requesting user, for the specified
`owner` as a query parameter.

<pre class="prettyprint">
<b>GET</b> /api/v1/data?<code>owner</code>=<code>owner_username</code>
</pre>

> Example
>
>       curl -X GET https://ona.io/api/v1/data?owner=ona

## Get Submitted data for a specific form
Provides a list of json submitted data for a specific form.
<pre class="prettyprint">
<b>GET</b> /api/v1/data/<code>{pk}</code></pre>
> Example
>
>       curl -X GET https://ona.io/api/v1/data/22845

> Response
>
>        [
>            {
>                "_id": 4503,
>                "_bamboo_dataset_id": "",
>                "_deleted_at": null,
>                "expense_type": "service",
>                "_xform_id_string": "exp",
>                "_geolocation": [
>                    null,
>                    null
>                ],
>                "end": "2013-01-03T10:26:25.674+03",
>                "start": "2013-01-03T10:25:17.409+03",
>                "expense_date": "2011-12-23",
>                "_status": "submitted_via_web",
>                "today": "2013-01-03",
>                "_uuid": "2e599f6fe0de42d3a1417fb7d821c859",
>                "imei": "351746052013466",
>                "formhub/uuid": "46ea15e2b8134624a47e2c4b77eef0d4",
>                "kind": "monthly",
>                "_submission_time": "2013-01-03T02:27:19",
>                "required": "yes",
>                "_attachments": [],
>                "item": "Rent",
>                "amount": "35000.0",
>                "deviceid": "351746052013466",
>                "subscriberid": "639027...60317"
>            },
>            {
>                ....
>                "subscriberid": "639027...60317"
>            }
>        ]

## Get a single data submission for a given form

Get a single specific submission json data providing `pk`
 and `dataid` as url path parameters, where:

* `pk` - is the identifying number for a specific form
* `dataid` - is the unique id of the data, the value of `_id` or `_uuid`

<pre class="prettyprint">
<b>GET</b> /api/v1/data/<code>{pk}</code>/<code>{dataid}</code></pre>
> Example
>
>       curl -X GET https://ona.io/api/v1/data/22845/4503

> Response
>
>            {
>                "_id": 4503,
>                "_bamboo_dataset_id": "",
>                "_deleted_at": null,
>                "expense_type": "service",
>                "_xform_id_string": "exp",
>                "_geolocation": [
>                    null,
>                    null
>                ],
>                "end": "2013-01-03T10:26:25.674+03",
>                "start": "2013-01-03T10:25:17.409+03",
>                "expense_date": "2011-12-23",
>                "_status": "submitted_via_web",
>                "today": "2013-01-03",
>                "_uuid": "2e599f6fe0de42d3a1417fb7d821c859",
>                "imei": "351746052013466",
>                "formhub/uuid": "46ea15e2b8134624a47e2c4b77eef0d4",
>                "kind": "monthly",
>                "_submission_time": "2013-01-03T02:27:19",
>                "required": "yes",
>                "_attachments": [],
>                "item": "Rent",
>                "amount": "35000.0",
>                "deviceid": "351746052013466",
>                "subscriberid": "639027...60317"
>            },
>            {
>                ....
>                "subscriberid": "639027...60317"
>            }
>        ]

## Query submitted data of a specific form
Provides a list of json submitted data for a specific form. Use `query`
parameter to apply form data specific, see
<a href="http://docs.mongodb.org/manual/reference/operator/query/">
http://docs.mongodb.org/manual/reference/operator/query/</a>.

For more details see
<a href="https://github.com/modilabs/formhub/wiki/Formhub-Access-Points-(API)#
api-parameters">
API Parameters</a>.
<pre class="prettyprint">
<b>GET</b> /api/v1/data/<code>{pk}</code>?query={"field":"value"}</b>
<b>GET</b> /api/v1/data/<code>{pk}</code>?query={"field":{"op": "value"}}"</b>
</pre>
> Example
>
>       curl -X GET 'https://ona.io/api/v1/data/22845?query={"kind": \
"monthly"}'
>       curl -X GET 'https://ona.io/api/v1/data/22845?query={"date": \
{"gt$": "2014-09-29T01:02:03+0000"}}'

> Response
>
>        [
>            {
>                "_id": 4503,
>                "_bamboo_dataset_id": "",
>                "_deleted_at": null,
>                "expense_type": "service",
>                "_xform_id_string": "exp",
>                "_geolocation": [
>                    null,
>                    null
>                ],
>                "end": "2013-01-03T10:26:25.674+03",
>                "start": "2013-01-03T10:25:17.409+03",
>                "expense_date": "2011-12-23",
>                "_status": "submitted_via_web",
>                "today": "2013-01-03",
>                "_uuid": "2e599f6fe0de42d3a1417fb7d821c859",
>                "imei": "351746052013466",
>                "formhub/uuid": "46ea15e2b8134624a47e2c4b77eef0d4",
>                "kind": "monthly",
>                "_submission_time": "2013-01-03T02:27:19",
>                "required": "yes",
>                "_attachments": [],
>                "item": "Rent",
>                "amount": "35000.0",
>                "deviceid": "351746052013466",
>                "subscriberid": "639027...60317"
>            },
>            {
>                ....
>                "subscriberid": "639027...60317"
>            }
>        ]

## Query submitted data of a specific form using Tags
Provides a list of json submitted data for a specific form matching specific
tags. Use the `tags` query parameter to filter the list of forms, `tags`
should be a comma separated list of tags.

<pre class="prettyprint">
<b>GET</b> /api/v1/data?<code>tags</code>=<code>tag1,tag2</code></pre>
<pre class="prettyprint">
<b>GET</b> /api/v1/data/<code>{pk}</code>?<code>tags\
</code>=<code>tag1,tag2</code></pre>

> Example
>
>       curl -X GET https://ona.io/api/v1/data/22845?tags=monthly

## Tag a submission data point

A `POST` payload of parameter `tags` with a comma separated list of tags.

Examples

- `animal fruit denim` - space delimited, no commas
- `animal, fruit denim` - comma delimited

<pre class="prettyprint">
<b>POST</b> /api/v1/data/<code>{pk}</code>/<code>{dataid}</code>/labels</pre>

Payload

    {"tags": "tag1, tag2"}

## Delete a specific tag from a submission

<pre class="prettyprint">
<b>DELETE</b> /api/v1/data/<code>{pk}</code>/<code>\
{dataid}</code>/labels/<code>tag_name</code></pre>

> Request
>
>       curl -X DELETE \
https://ona.io/api/v1/data/28058/20/labels/tag1
or to delete the tag "hello world"
>
>       curl -X DELETE \
https://ona.io/api/v1/data/28058/20/labels/hello%20world
>
> Response
>
>        HTTP 200 OK

## Get list of public data endpoints

<pre class="prettyprint">
<b>GET</b> /api/v1/data/public
</pre>

> Example
>
>       curl -X GET https://ona.io/api/v1/data/public

> Response
>
>        [{
>            "id": 4240,
>            "id_string": "dhis2form"
>            "title": "dhis2form"
>            "description": "dhis2form"
>            "url": "https://ona.io/api/v1/data/4240"
>         },
>            ...
>        ]

## Get enketo edit link for a submission instance

<pre class="prettyprint">
<b>GET</b> /api/v1/data/<code>{pk}</code>/<code>{dataid}</code>/enketo
</pre>

> Example
>
>       curl -X GET https://ona.io/api/v1/data/28058/20/enketo?return_url=url

> Response
>       {"url": "https://hmh2a.enketo.formhub.org"}
>
>

## Delete a specific submission instance

Delete a specific submission in a form

<pre class="prettyprint">
<b>DELETE</b> /api/v1/data/<code>{pk}</code>/<code>{dataid}</code>
</pre>

> Example
>
>       curl -X DELETE https://ona.io/api/v1/data/28058/20

> Response
>
>       HTTP 204 No Content
>
>
"""
    renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES + [
        renderers.XLSRenderer, renderers.XLSXRenderer, renderers.CSVRenderer,
        renderers.CSVZIPRenderer, renderers.SAVZIPRenderer,
        renderers.SurveyRenderer
    ]

    filter_backends = (filters.AnonDjangoObjectPermissionFilter,
                       filters.XFormOwnerFilter)
    serializer_class = DataSerializer
    permission_classes = (XFormPermissions, )
    lookup_field = 'pk'
    lookup_fields = ('pk', 'dataid')
    extra_lookup_fields = None
    public_data_endpoint = 'public'

    queryset = XForm.objects.all()
    default_response_headers = last_modified_header(
        get_date(XForm.objects.last(), 'modified'))

    def get_serializer_class(self):
        pk_lookup, dataid_lookup = self.lookup_fields
        pk = self.kwargs.get(pk_lookup)
        dataid = self.kwargs.get(dataid_lookup)
        if pk is not None and dataid is None \
                and pk != self.public_data_endpoint:
            serializer_class = DataListSerializer
        elif pk is not None and dataid is not None:
            serializer_class = DataInstanceSerializer
        else:
            serializer_class = \
                super(DataViewSet, self).get_serializer_class()

        return serializer_class

    def get_object(self, queryset=None):
        obj = super(DataViewSet, self).get_object(queryset)
        pk_lookup, dataid_lookup = self.lookup_fields
        pk = self.kwargs.get(pk_lookup)
        dataid = self.kwargs.get(dataid_lookup)

        if pk is not None and dataid is not None:
            try:
                int(dataid)
            except ValueError:
                raise ParseError(
                    _(u"Invalid dataid %(dataid)s" % {'dataid': dataid}))

            obj = get_object_or_404(Instance, pk=dataid, xform__pk=pk)

        return obj

    def _get_public_forms_queryset(self):
        return XForm.objects.filter(Q(shared=True) | Q(shared_data=True))

    def _filtered_or_shared_qs(self, qs, pk):
        filter_kwargs = {self.lookup_field: pk}
        qs = qs.filter(**filter_kwargs)

        if not qs:
            filter_kwargs['shared_data'] = True
            qs = XForm.objects.filter(**filter_kwargs)

            if not qs:
                raise Http404(_(u"No data matches with given query."))

        return qs

    def filter_queryset(self, queryset, view=None):
        qs = super(DataViewSet, self).filter_queryset(queryset)
        pk = self.kwargs.get(self.lookup_field)
        tags = self.request.QUERY_PARAMS.get('tags', None)

        if tags and isinstance(tags, six.string_types):
            tags = tags.split(',')
            qs = qs.filter(tags__name__in=tags).distinct()

        if pk:
            try:
                int(pk)
            except ValueError:
                if pk == self.public_data_endpoint:
                    qs = self._get_public_forms_queryset()
                else:
                    raise ParseError(_(u"Invalid pk %(pk)s" % {'pk': pk}))
            else:
                qs = self._filtered_or_shared_qs(qs, pk)

        return qs

    @action(methods=['GET', 'POST', 'DELETE'], extra_lookup_fields=[
        'label',
    ])
    def labels(self, request, *args, **kwargs):
        http_status = status.HTTP_400_BAD_REQUEST
        instance = self.get_object()
        self.headers = merge_dicts(
            self.headers, last_modified_header(get_date(instance, 'modified')))

        if request.method == 'POST':
            if add_tags_to_instance(request, instance):
                http_status = status.HTTP_201_CREATED

        tags = instance.tags
        label = kwargs.get('label', None)

        if request.method == 'GET' and label:
            data = [
                tag['name'] for tag in tags.filter(name=label).values('name')
            ]

        elif request.method == 'DELETE' and label:
            count = tags.count()
            tags.remove(label)

            # Accepted, label does not exist hence nothing removed
            http_status = status.HTTP_200_OK if count == tags.count() \
                else status.HTTP_404_NOT_FOUND

            data = list(tags.names())
        else:
            data = list(tags.names())

        if request.method == 'GET':
            http_status = status.HTTP_200_OK

        return Response(data, status=http_status)

    @action(methods=['GET'])
    def enketo(self, request, *args, **kwargs):
        self.object = self.get_object()
        data = {}
        if isinstance(self.object, XForm):
            raise ParseError(_(u"Data id not provided."))
        elif (isinstance(self.object, Instance)):
            self.headers = merge_dicts(
                self.headers,
                last_modified_header(get_date(self.object, 'modified')))
            if request.user.has_perm("change_xform", self.object.xform):
                return_url = request.QUERY_PARAMS.get('return_url')
                if not return_url:
                    raise ParseError(_(u"return_url not provided."))

                try:
                    data["url"] = get_enketo_edit_url(request, self.object,
                                                      return_url)
                except EnketoError as e:
                    data['detail'] = "{}".format(e)
            else:
                raise PermissionDenied(_(u"You do not have edit permissions."))

        return Response(data=data)

    def destroy(self, request, *args, **kwargs):
        self.object = self.get_object()

        if isinstance(self.object, XForm):
            raise ParseError(_(u"Data id not provided."))
        elif isinstance(self.object, Instance):

            if request.user.has_perm("delete_xform", self.object.xform):
                self.object.delete()
            else:
                raise PermissionDenied(
                    _(u"You do not have delete "
                      u"permissions."))

        return Response(status=status.HTTP_204_NO_CONTENT)

    def retrieve(self, request, *args, **kwargs):
        data_id = str(kwargs.get('dataid'))
        _format = kwargs.get('format')

        if not data_id.isdigit():
            raise ParseError(_(u"Data ID should be an integer"))

        try:
            instance = Instance.objects.get(pk=data_id)
            self.headers = merge_dicts(
                self.headers,
                last_modified_header(get_date(instance, 'modified')))

            if _format == 'json' or _format is None:
                return Response(instance.json)
            elif _format == 'xml':
                return Response(instance.xml)
            else:
                raise ParseError(
                    _(u"'%(_format)s' format unknown or not implemented!" %
                      {'_format': _format}))
        except Instance.DoesNotExist:
            raise ParseError(
                _(u"data with id '%(data_id)s' not found!" %
                  {'data_id': data_id}))

    def list(self, request, *args, **kwargs):
        lookup_field = self.lookup_field
        lookup = self.kwargs.get(lookup_field)

        if lookup_field not in kwargs.keys():
            self.object_list = self.filter_queryset(self.get_queryset())
            serializer = self.get_serializer(self.object_list, many=True)

            return Response(serializer.data)

        if lookup == self.public_data_endpoint:
            self.object_list = self._get_public_forms_queryset()

            page = self.paginate_queryset(self.object_list)
            if page is not None:
                serializer = self.get_pagination_serializer(page)
            else:
                serializer = self.get_serializer(self.object_list, many=True)

            return Response(serializer.data)

        xform = self.get_object()
        query = request.GET.get("query", {})
        export_type = kwargs.get('format')
        if export_type is None or export_type in ['json']:
            # perform default viewset retrieve, no data export
            return super(DataViewSet, self).list(request, *args, **kwargs)

        return custom_response_handler(request, xform, query, export_type)
Beispiel #34
0
class StatsViewSet(AnonymousUserPublicFormsMixin,
                   viewsets.ReadOnlyModelViewSet):
    """
Stats summary for median, mean, mode, range, max, min.
A query parameter `method` can be used to limit the results to either
`mean`, `median`, `mode` or `range` only results.

Example:

    GET /api/v1/stats/1?

Response:

    [
        {
            "age":
                {
                    "median": 8,
                    "mean": 23.4,
                    "mode": 23,
                    "range": 24,
                    "max": 28,
                    "min": 4
                },
        ...
    ]

Example:

    GET /api/v1/stats/1?method=median

Response:

    [
        {
            "age":
                {
                    "median": 8,
                },
        ...
    ]
"""
    lookup_field = 'pk'
    queryset = XForm.objects.all()
    default_response_headers = last_modified_header(
        get_date(XForm.objects.last(), 'modified'))
    filter_backends = (filters.AnonDjangoObjectPermissionFilter, )
    permission_classes = [
        XFormPermissions,
    ]
    serializer_class = StatsSerializer

    def get_serializer_class(self):
        lookup = self.kwargs.get(self.lookup_field)
        if lookup is not None:
            serializer_class = StatsInstanceSerializer
        else:
            serializer_class = \
                super(StatsViewSet, self).get_serializer_class()

        return serializer_class