Skip to content

Commit

Permalink
Jkmarx/add dataset read meta (#2409)
Browse files Browse the repository at this point in the history
* Add dataset permission read_meta field.

* Add a readmetaonly flag which defaults to false.

* Update dataset share permissions.

* Add exclude facets capabilities.

* Extend solr_query and assay/files api to handle meta_only.

* Add data_set_uuid param.

* Add unit tests.

* Shift perm to data set only.

* Fix typo.

* Revert data set api response.

* Fix unit test avoid reference change.

* Revert group perms, unneccessary for object perm.

* Update UI to add read_meta

* Update owner perms and share perms for data sets.

* Swap order of read perms.

* Update unit tests.

* Read_meta is true if change or read is.

* Fix unit test's dependency on outside method.

* Update perms service.

* Refactor perms service.

* Fix get bug.

* Fix write bug.

* Revert unneccessary method change.

* Add comment.

* Fix unit test and revert iffy

* Refactor to bottom most perm.

* Update unit test.

* Move params inside for consistency.

* Fix typo with tests.

* Fix another typo with str.

* Revert params location.

* Fix styling.

* Update name for clarity.

* Fix order for clarity.

* Add logout to tearDown.

* Copy vs slice to avoid pass by ref.

* Add comments to help with clarity.

* Fix param defaults.

* Fix order.

* Workflows do not show the text: No workflows.

* Fix workflow bug.

* Add back integration test.

* Revert accidental changes.

* Update resoource for user/dataset and add helper method with test.

* Add dataSetUuid to provenance for assay/files.

* Fix param name.

* Revert bug fix.
  • Loading branch information
jkmarx committed Dec 13, 2017
1 parent 67b5634 commit e53a8a5
Show file tree
Hide file tree
Showing 16 changed files with 373 additions and 47 deletions.
38 changes: 28 additions & 10 deletions refinery/core/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@
Invitation, Project, ResourceStatistics, Tutorials,
UserAuthentication, UserProfile, Workflow,
WorkflowInputRelationships)
from core.utils import get_data_sets_annotations, get_resources_for_user
from core.utils import (get_data_sets_annotations, get_resources_for_user,
which_default_read_perm)
from data_set_manager.api import (AssayResource, InvestigationResource,
StudyResource)
from data_set_manager.models import Attribute, Node, Study
Expand Down Expand Up @@ -75,11 +76,15 @@ def is_manager_group(self, group):
def get_perms(self, res, group):
# Default values.
perms = {'read': False, 'change': False}
if self.res_type._meta.verbose_name == 'dataset':
perms['read_meta'] = False

# Find matching ones if available.
for i in res.get_groups():
if i['group'].group_ptr.id == group.id:
perms = {'read': i['read'], 'change': i['change']}
if self.res_type._meta.verbose_name == 'dataset':
perms['read_meta'] = i['read_meta']

return perms

Expand Down Expand Up @@ -169,9 +174,8 @@ def transform_res_list(self, user, res_list, request, **kwargs):
public_res_set = Set(
get_objects_for_group(
ExtendedGroup.objects.public_group(),
'core.read_%s' %
self.res_type._meta.verbose_name).values_list("id",
flat=True))
which_default_read_perm(self.res_type._meta.verbose_name)
).values_list("id", flat=True))

# Get content type, needed to map Guardian group permission.
content_type = ContentType.objects.get(model='dataset')
Expand Down Expand Up @@ -313,7 +317,7 @@ def res_sharing(self, request, **kwargs):

if request.method == 'GET':
# user has read permissions
if not user.has_perm('core.read_dataset', res):
if not user.has_perm('core.read_meta_dataset', res):
return HttpUnauthorized()
kwargs['sharing'] = True
mod_res = self.transform_res_list(user, [res], request, **kwargs)
Expand Down Expand Up @@ -344,7 +348,15 @@ def res_sharing(self, request, **kwargs):
is_read_only = can_read and not can_change
should_share = can_read or can_change

if should_share:
# datasets handled seperate due to object-level perm
if self.res_type._meta.verbose_name == 'dataset':
is_read_meta_only = False
if not should_share and i['read_meta']: # read_meta only
is_read_meta_only = i['read_meta']
should_share = is_read_meta_only
if should_share: # read, read_meta, or change
res.share(group, is_read_only, is_read_meta_only)
elif should_share:
res.share(group, is_read_only)

return HttpAccepted()
Expand Down Expand Up @@ -654,7 +666,7 @@ def filter_by_group(self, request, obj_list):

if group:
obj_list = list(get_objects_for_group(
group, 'core.read_dataset'
group, 'core.read_meta_dataset'
))

return obj_list
Expand Down Expand Up @@ -697,7 +709,8 @@ def obj_create(self, bundle, **kwargs):
return SharableResourceAPIInterface.obj_create(self, bundle, **kwargs)

def get_all_ids(self, request, **kwargs):
data_sets = get_objects_for_user(request.user, 'core.read_dataset')
data_sets = get_objects_for_user(request.user,
'core.read_meta_dataset')
return self.create_response(
request,
{
Expand Down Expand Up @@ -729,7 +742,7 @@ def get_by_db_id(self, request, **kwargs):
except:
user_uuid = None

if ds and request.user.has_perm('core.read_dataset', ds):
if ds and request.user.has_perm('core.read_meta_dataset', ds):
return_obj['accession'] = ds.accession
return_obj['accession_source'] = ds.accession_source
return_obj['creation_date'] = ds.creation_date
Expand Down Expand Up @@ -1262,17 +1275,22 @@ def get_perms(self, res, group):
'change': False
}

if self.res_type._meta.verbose_name == 'dataset':
perms['read_meta'] = False

# Find matching perms if available.
for i in res.get_groups():
if i['group'].group_ptr.id == group.id:
perms['read'] = i['read']
perms['change'] = i['change']
if self.res_type._meta.verbose_name == 'dataset':
perms['read_meta'] = i['read_meta']

return perms

def get_perm_list(self, group):
dataset_perms = filter(
lambda r: r['read'],
lambda r: r['read_meta'],
map(lambda r: self.get_perms(r, group), DataSet.objects.all()))
project_perms = filter(
lambda r: r['read'],
Expand Down
18 changes: 18 additions & 0 deletions refinery/core/migrations/0013_auto_20171127_1432.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations


class Migration(migrations.Migration):

dependencies = [
('core', '0012_auto_20171026_0939'),
]

operations = [
migrations.AlterModelOptions(
name='dataset',
options={'verbose_name': 'dataset', 'permissions': (('read_dataset', 'Can read dataset'), ('read_meta_dataset', 'Can read meta dataset'), ('share_dataset', 'Can share dataset'))},
),
]
32 changes: 26 additions & 6 deletions refinery/core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,8 @@ def set_owner(self, user):
assign_perm("read_%s" % self._meta.verbose_name, user, self)
assign_perm("delete_%s" % self._meta.verbose_name, user, self)
assign_perm("change_%s" % self._meta.verbose_name, user, self)
if self._meta.verbose_name == 'dataset':
assign_perm("read_meta_%s" % self._meta.verbose_name, user, self)

def get_owner(self):
# ownership is determined by "add" permission
Expand Down Expand Up @@ -381,7 +383,7 @@ def unshare(self, group):
remove_perm('share_%s' % self._meta.verbose_name, group, self)

# TODO: clean this up
def get_groups(self, changeonly=False, readonly=False):
def get_groups(self, changeonly=False, readonly=False, readmetaonly=False):
permissions = get_groups_with_perms(self, attach_perms=True)

groups = []
Expand All @@ -393,11 +395,17 @@ def get_groups(self, changeonly=False, readonly=False):
group["id"] = group["group"].id
group["change"] = False
group["read"] = False
if self._meta.verbose_name == 'dataset':
group["read_meta"] = False

for permission in permission_list:
if permission.startswith("change"):
group["change"] = True
if permission.startswith("read"):
elif permission.startswith("read_meta"):
group["read_meta"] = True
elif permission.startswith("read"):
group["read"] = True

if group["change"] and readonly:
continue
if group["read"] and changeonly:
Expand Down Expand Up @@ -425,9 +433,8 @@ def is_public(self):
for permission in permission_list:
if permission.startswith("change"):
return True
if permission.startswith("read"):
if permission.startswith("read"): # read_meta & read
return True

return False

class Meta:
Expand Down Expand Up @@ -512,6 +519,7 @@ class Meta:
verbose_name = "dataset"
permissions = (
('read_%s' % verbose_name, 'Can read %s' % verbose_name),
('read_meta_%s' % verbose_name, 'Can read meta %s' % verbose_name),
('share_%s' % verbose_name, 'Can share %s' % verbose_name),
)

Expand Down Expand Up @@ -762,8 +770,18 @@ def get_pre_isa_archive(self):
AttributeError) as e:
logger.debug("Couldn't fetch FileStoreItem: %s", e)

def share(self, group, readonly=True):
def share(self, group, readonly=True, readmetaonly=False):
# change: !readonly & !readmetaonly, read: readonly & !readmetaonly
super(DataSet, self).share(group, readonly)
assign_perm('read_meta_%s' % self._meta.verbose_name, group, self)

# read_meta only case; super reads as edit and is fixed here because
# it only applies to data set
if not readonly and readmetaonly:
remove_perm('read_%s' % self._meta.verbose_name, group, self)
remove_perm('add_%s' % self._meta.verbose_name, group, self)
remove_perm('change_%s' % self._meta.verbose_name, group, self)

update_data_set_index(self)
invalidate_cached_object(self)
user_ids = map(lambda user: user.id, group.user_set.all())
Expand All @@ -779,13 +797,15 @@ def share(self, group, readonly=True):

def unshare(self, group):
super(DataSet, self).unshare(group)
remove_perm('read_meta_%s' % self._meta.verbose_name, group, self)

update_data_set_index(self)
# Need to check if the users of the group that is unshared still have
# access via other groups or by ownership
users = group.user_set.all()
user_ids = []
for user in users:
if not user.has_perm('core.read_dataset', DataSet):
if not user.has_perm('core.read_meta_dataset', DataSet):
user_ids.append(user.id)

# We need to give the anonymous user read access too.
Expand Down
11 changes: 10 additions & 1 deletion refinery/core/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@
WorkflowEngine, invalidate_cached_object)
from .search_indexes import DataSetIndex
from .utils import (filter_nodes_uuids_in_solr, get_aware_local_time,
get_resources_for_user, move_obj_to_front)
get_resources_for_user, move_obj_to_front,
which_default_read_perm)
from .views import AnalysesViewSet, DataSetsViewSet

cache = memcache.Client(["127.0.0.1:11211"])
Expand Down Expand Up @@ -1234,6 +1235,14 @@ def test_move_obj_to_front_missing_prop(self):
self.assertEqual(response_arr[0].get('name'),
nodes_list[0].get('name'))

def test_which_default_read_perm_for_dataset(self):
self.assertEqual(which_default_read_perm('dataset'),
'core.read_meta_dataset')

def test_which_default_read_perm_for_analysis(self):
self.assertEqual(which_default_read_perm('analysis'),
'core.read_analysis')


class UserTutorialsTest(TestCase):
"""
Expand Down
8 changes: 7 additions & 1 deletion refinery/core/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1005,5 +1005,11 @@ def get_resources_for_user(user, resource_type):
return get_objects_for_user(
user if user.is_authenticated()
else get_anonymous_user(),
'core.read_%s' % resource_type
which_default_read_perm(resource_type)
)


def which_default_read_perm(resource_type):
if resource_type == 'dataset':
return 'core.read_meta_dataset'
return 'core.read_%s' % resource_type
4 changes: 2 additions & 2 deletions refinery/core/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,8 +297,8 @@ def data_set(request, data_set_uuid, analysis_uuid=None):
data_set = get_object_or_404(DataSet, uuid=data_set_uuid)
public_group = ExtendedGroup.objects.public_group()

if not request.user.has_perm('core.read_dataset', data_set):
if 'read_dataset' not in get_perms(public_group, data_set):
if not request.user.has_perm('core.read_meta_dataset', data_set):
if 'read_meta_dataset' not in get_perms(public_group, data_set):
if request.user.is_authenticated():
return HttpResponseForbidden(
custom_error_page(request, '403.html',
Expand Down

0 comments on commit e53a8a5

Please sign in to comment.