Skip to content

Commit

Permalink
Merge pull request #832 from onaio/readonly-perms-fix
Browse files Browse the repository at this point in the history
added can view xform all perm to readonly
denniswambua authored Oct 26, 2016

Unverified

This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
2 parents cc8520c + fee3c67 commit 6d59cdc
Showing 3 changed files with 133 additions and 2 deletions.
122 changes: 122 additions & 0 deletions onadata/apps/api/management/commands/fix_readonly_role_perms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
from guardian.shortcuts import get_perms

from django.core.management.base import BaseCommand, CommandError
from django.contrib.auth.models import User
from django.utils.translation import gettext as _
from django.conf import settings
from onadata.apps.api.models import Team


from onadata.libs.permissions import ReadOnlyRole, DataEntryRole,\
EditorRole, ManagerRole, OwnerRole, ReadOnlyRoleNoDownload,\
DataEntryOnlyRole, DataEntryMinorRole, EditorMinorRole
from onadata.libs.utils.model_tools import queryset_iterator


class Command(BaseCommand):
args = '<app model [created_perm] >'
help = _(u"Reassign permission to the model when permissions are changed")

def handle(self, *args, **options):
self.stdout.write("Re-assigining started", ending='\n')

if not args:
raise CommandError('Param not set. <app model [created_perm]>')

if len(args) < 3:
raise CommandError('Param not set. <app model [created_perm]>')

app = args[0]
model = args[1]
username = args[2]
new_perms = list(args[3:])

if username == "all":
users = User.objects.exclude(
username__iexact=settings.ANONYMOUS_DEFAULT_USERNAME
)

teams = Team.objects.all()
else:
users = User.objects.filter(username=username)
teams = Team.objects.filter(organization__username=username)
# Get all the users
for user in queryset_iterator(users):
self.reassign_perms(user, app, model, new_perms)

for team in queryset_iterator(teams):
self.reassign_perms(team, app, model, new_perms)

self.stdout.write("Re-assigining finished", ending='\n')

def reassign_perms(self, user, app, model, new_perm):
"""
Gets all the permissions the user has on objects and assigns the new
permission to them
:param user:
:param app:
:param model:
:param new_perm:
:return:
"""

# Get the unique permission model objects filtered by content type
# for the user
if isinstance(user, Team):
if model == "project":
objects = user.projectgroupobjectpermission_set.filter(
group_id=user.pk).distinct('content_object_id')
else:
objects = user.xformgroupobjectpermission_set.filter(
group_id=user.pk).distinct('content_object_id')
else:
if model == 'project':
objects = user.projectuserobjectpermission_set.all()
else:
objects = user.xformuserobjectpermission_set.all()

for perm_obj in objects:
obj = perm_obj.content_object
ROLES = [ReadOnlyRoleNoDownload,
ReadOnlyRole,
DataEntryOnlyRole,
DataEntryMinorRole,
DataEntryRole,
EditorMinorRole,
EditorRole,
ManagerRole,
OwnerRole]

# For each role reassign the perms
for role_class in reversed(ROLES):
# want to only process for readonly perms
if role_class.user_has_role(user, obj) or role_class \
not in [ReadOnlyRoleNoDownload, ReadOnlyRole]:
continue

if self.check_role(role_class, user, obj, new_perm):
# If true
role_class.add(user, obj)
break

def check_role(self, role_class, user, obj, new_perm=[]):
"""
Test if the user has the role for the object provided
:param role_class:
:param user:
:param obj:
:param new_perm:
:return:
"""
# remove the new permission because the old model doesnt have it
perm_list = role_class.class_to_permissions[type(obj)]
old_perm_set = set(perm_list)
newly_added_perm = set(new_perm)

if newly_added_perm.issubset(old_perm_set):
diff_set = old_perm_set.difference(newly_added_perm)

if isinstance(user, Team):
return set(get_perms(user, obj)) == diff_set

return user.has_perms(list(diff_set), obj)
9 changes: 7 additions & 2 deletions onadata/apps/api/tests/viewsets/test_data_viewset.py
Original file line number Diff line number Diff line change
@@ -212,8 +212,6 @@ def test_data_jsonp(self):
self.assertEqual(len(response.data), 4)

def _assign_user_role(self, user, role):
self.assertFalse(role.user_has_role(user, self.xform))

# share bob's project with alice and give alice an editor role
data = {'username': user.username, 'role': role.name}
request = self.factory.put('/', data=data, **self.extra)
@@ -291,6 +289,13 @@ def test_returned_data_is_based_on_form_permissions(self):
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 4)

self._assign_user_role(user_alice, ReadOnlyRole)

request = self.factory.get('/', **alices_extra)
response = view(request, pk=formid)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 4)

def test_data_entryonly_can_submit_but_not_view(self):
# create user alice
user_alice = self._create_user('alice', 'alice')
4 changes: 4 additions & 0 deletions onadata/libs/permissions.py
Original file line number Diff line number Diff line change
@@ -100,6 +100,8 @@ class ReadOnlyRoleNoDownload(Role):
(CAN_VIEW_ORGANIZATION_PROFILE, OrganizationProfile),
(CAN_VIEW_XFORM, XForm),
(CAN_VIEW_PROJECT, Project),
(CAN_VIEW_XFORM_ALL, XForm),
(CAN_VIEW_PROJECT_ALL, Project),
)


@@ -111,6 +113,8 @@ class ReadOnlyRole(Role):
(CAN_VIEW_PROJECT, Project),
(CAN_EXPORT_XFORM, XForm),
(CAN_EXPORT_PROJECT, Project),
(CAN_VIEW_XFORM_ALL, XForm),
(CAN_VIEW_PROJECT_ALL, Project),
)


0 comments on commit 6d59cdc

Please sign in to comment.