Skip to content

Commit

Permalink
Merge pull request #1460 from #1428 Add submission reviews
Browse files Browse the repository at this point in the history
  • Loading branch information
ukanga authored Sep 6, 2018
2 parents a1308bd + 2b53e90 commit c3a9248
Show file tree
Hide file tree
Showing 29 changed files with 1,163 additions and 166 deletions.
52 changes: 51 additions & 1 deletion onadata/apps/api/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,20 @@
from django.http import Http404
from django.shortcuts import get_object_or_404
from django.conf import settings

from rest_framework import exceptions
from rest_framework.permissions import (
BasePermission, DjangoModelPermissionsOrAnonReadOnly,
DjangoObjectPermissions, IsAuthenticated)

from onadata.apps.api.tools import (check_inherit_permission_from_project,
get_instance_xform_or_none,
get_user_profile_or_none)
from onadata.apps.logger.models import DataView, Instance, Project, XForm
from onadata.apps.main.models.user_profile import UserProfile
from onadata.libs.permissions import (CAN_ADD_XFORM_TO_PROFILE,
CAN_CHANGE_XFORM, CAN_DELETE_SUBMISSION,
ReadOnlyRoleNoDownload)
ManagerRole, ReadOnlyRoleNoDownload)

SAFE_METHODS = ('GET', 'HEAD', 'OPTIONS')

Expand All @@ -26,6 +28,7 @@ class AlternateHasObjectPermissionMixin(object): # pylint: disable=R0903
"""
AlternateHasObjectPermissionMixin - checks if user has read permissions.
"""

def _has_object_permission(self, request, model_cls, user, obj):
perms = self.get_required_object_permissions(request.method, model_cls)

Expand Down Expand Up @@ -146,6 +149,46 @@ def has_object_permission(self, request, view, obj):
request, view, obj)


class SubmissionReviewPermissions(XFormPermissions):
"""
Custom Permission Checks for SubmissionReviews
"""
perms_map = {
'GET': [],
'OPTIONS': [],
'HEAD': [],
'POST': ['logger.add_xform'],
'PUT': ['logger.change_xform'],
'PATCH': ['logger.change_xform'],
'DELETE': ['logger.delete_xform'],
}

def has_permission(self, request, view):
"""
Custom has_permission method
"""
is_authenticated = request and request.user.is_authenticated()

if is_authenticated and view.action == 'create':
instance_id = request.data.get('instance')
xform = get_instance_xform_or_none(instance_id)
return request.user.has_perm(CAN_CHANGE_XFORM, xform)

return super(SubmissionReviewPermissions, self).has_permission(
request, view)

def has_object_permission(self, request, view, obj):
"""
Custom has_object_permission method
"""
if (request.method == 'DELETE' and view.action == 'destroy') or (
request.method == 'PATCH' and view.action == 'partial_update'):
return ManagerRole.user_has_role(request.user, obj.instance.xform)

return super(SubmissionReviewPermissions, self).has_object_permission(
request, view, obj)


class UserProfilePermissions(DjangoObjectPermissions):
"""
UserProfilePermissions - allows anonymous users to create a profile.
Expand Down Expand Up @@ -257,6 +300,7 @@ class MetaDataObjectPermissions(AlternateHasObjectPermissionMixin,
"""
MetaData ObjectPermissions - apply Xform permision for given response.
"""

def has_object_permission(self, request, view, obj):
model_cls = obj.content_object.__class__
user = request.user
Expand Down Expand Up @@ -292,6 +336,7 @@ class ConnectViewsetPermissions(IsAuthenticated):
"""
ConnectViewsetPermissions - allows reset passwords to all users.
"""

def has_permission(self, request, view):
if view.action == 'reset':
return True
Expand All @@ -304,6 +349,7 @@ class UserViewSetPermissions(DjangoModelPermissionsOrAnonReadOnly):
"""
User ViewSetPermissions - do not allow user search for anonymous users.
"""

def has_permission(self, request, view):

if request.user.is_anonymous() and view.action == 'list':
Expand Down Expand Up @@ -347,6 +393,7 @@ class RestServiceObjectPermissions(AlternateHasObjectPermissionMixin,
RestService ObjectPermissions - apply XForm permisions for a RestService
model.
"""

def has_object_permission(self, request, view, obj):
model_cls = XForm
user = request.user
Expand Down Expand Up @@ -398,6 +445,7 @@ class OrganizationProfilePermissions(DjangoObjectPermissionsAllowAnon):
"""
OrganizationProfilePermissions - allow authenticated users to delete an org
"""

def has_object_permission(self, request, view, obj):
is_authenticated = request and request.user.is_authenticated() and \
request.user.username == request.data.get(
Expand All @@ -416,6 +464,7 @@ class OpenDataViewSetPermissions(IsAuthenticated,
OpenDataViewSetPermissions - allow anonymous access to schema and data
end-points of an open dataset.
"""

def has_permission(self, request, view):
if request.user.is_anonymous() and view.action in ['schema', 'data']:
return True
Expand All @@ -436,6 +485,7 @@ class IsAuthenticatedSubmission(BasePermission):
IsAuthenticatedSubmission - checks if profile requires authentication
during a submission request.
"""

def has_permission(self, request, view):
username = view.kwargs.get('username')
if request.method in ['HEAD', 'POST'] and request.user.is_anonymous():
Expand Down
4 changes: 2 additions & 2 deletions onadata/apps/api/tests/viewsets/test_merged_xform_viewset.py
Original file line number Diff line number Diff line change
Expand Up @@ -427,8 +427,8 @@ def test_md_csv_export(self):
self.assertEqual(headers, [
'fruit', 'meta/instanceID', '_id', '_uuid', '_submission_time',
'_tags', '_notes', '_version', '_duration', '_submitted_by',
'_total_media', '_media_count', '_media_all_received'
])
'_total_media', '_media_count', '_review_status',
'_review_comment', '_media_all_received'])
row1 = next(csv_reader)
self.assertEqual(row1[0], 'orange')
row2 = next(csv_reader)
Expand Down
2 changes: 1 addition & 1 deletion onadata/apps/api/tests/viewsets/test_ona_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ def test_number_of_viewsets(self):
request = self.factory.get(path)
request.resolver_match = resolve(path)
response = view(request)
self.assertEquals(len(response.data), 27)
self.assertEquals(len(response.data), 28)
Loading

0 comments on commit c3a9248

Please sign in to comment.