diff --git a/api/api.py b/api/api.py index f29265a4bd6f9f607826637e80d839699775141a..97334aa9a8d1c9897dd31aac951325fe1d2896b2 100644 --- a/api/api.py +++ b/api/api.py @@ -192,8 +192,6 @@ endpoints = [ route('/<cid:{gid}>/<list_name:tags>', TagsListHandler, m=['POST']), route('/<cid:{gid}>/<list_name:tags>/<value:{tag}>', TagsListHandler, m=['GET', 'PUT', 'DELETE']), - - route( '/<cid:{gid}>/analyses', AnalysesHandler, h='get_all', m=['GET']), ]), diff --git a/api/dao/basecontainerstorage.py b/api/dao/basecontainerstorage.py index 73670c46767ecff93f7153b432f4f54a0fa29f99..f06f0e682017a20ade8933d259084f1b51d3332e 100644 --- a/api/dao/basecontainerstorage.py +++ b/api/dao/basecontainerstorage.py @@ -62,6 +62,31 @@ class ContainerStorage(object): return subclass() return cls(containerutil.pluralize(cont_name)) + @classmethod + def get_top_down_hierarchy(cls, cont_name, cid): + parent_to_child = { + 'groups': 'projects', + 'projects': 'sessions', + 'sessions': 'acquisitions' + } + + parent_tree = { + cont_name: [cid] + } + parent_name = cont_name + while parent_to_child.get(parent_name): + # Parent storage + storage = ContainerStorage.factory(parent_name) + child_name = parent_to_child[parent_name] + parent_tree[child_name] = [] + + # For each parent id, find all of its children and add them to the list of child ids in the parent tree + for parent_id in parent_tree[parent_name]: + parent_tree[child_name] = parent_tree[child_name] + [cont["_id"] for cont in storage.get_children(parent_id, projection={'_id':1})] + + parent_name = child_name + return parent_tree + def _fill_default_values(self, cont): if cont: defaults = BASE_DEFAULTS.copy() diff --git a/api/handlers/refererhandler.py b/api/handlers/refererhandler.py index dfbee617858c7715440aeeee0a4fb60026a88235..01ec481e3e9f006364ab85d97a15a928d7a4364e 100644 --- a/api/handlers/refererhandler.py +++ b/api/handlers/refererhandler.py @@ -6,6 +6,7 @@ and are stored in their own collection instead of an embedded list on the container (eg. ListHandler) """ +import bson import os import zipfile import datetime @@ -17,6 +18,8 @@ from .. import util from .. import validators from ..auth import containerauth, always_ok from ..dao import containerstorage, noop +from ..dao.basecontainerstorage import ContainerStorage +from ..dao.containerutil import singularize from ..web import base from ..web.errors import APIStorageException from ..web.request import log_access, AccessType @@ -137,50 +140,23 @@ class AnalysesHandler(RefererHandler): return analysis def get_all(self, cont_name, cid): - - parent_to_child = { - 'groups': 'projects', - 'projects': 'sessions', - 'sessions': 'acquisitions' - } - - storages = { - 'groups': containerstorage.GroupStorage(), - 'projects': containerstorage.ProjectStorage(), - 'sessions': containerstorage.SessionStorage(), - 'acquisitions': containerstorage.AcquisitionStorage() - } - parent_names = ['groups','projects','sessions', 'acquisitions'] - - # Only support groups/projects/sessions/acquisitions - if cont_name not in parent_names: - self.abort(400, "Analysis list not supported for {}".format(cont_name)) - + cid = bson.ObjectId(cid) # Check that user has permission to container - container = storages[cont_name].get_container(cid) + container = ContainerStorage.factory(cont_name).get_container(cid) + if not container: + self.abort(404, 'Element not found in container {} {}'.format(cont_name, cid)) permchecker = self.get_permchecker(container) permchecker(noop)('GET') - parent_tree = { - cont_name: [cid] - } - parent_name = cont_name - while parent_to_child.get(parent_name): - # Parent storage - storage = storages[parent_name] - child_name = parent_to_child[parent_name] - parent_tree[child_name] = [] - - # For each parent id, find all of its children and add them to the list of child ids in the parent tree - for parent_id in parent_tree[parent_name]: - parent_tree[child_name] = parent_tree[child_name] + [cont["_id"] for cont in storage.get_children(parent_id, projection={'_id':1}, uid=self.uid)] - - parent_name = child_name - # We only need a list of all the ids, no need for the tree anymore - parents = [pid for parent in parent_tree.keys() for pid in parent_tree[parent]] - - # We set User to None because we check for permission when finding the parents - analyses = containerstorage.AnalysisStorage().get_all_el({'parent.id':{'$in':parents}},None,{'info': 0, 'files.info': 0}) + if self.is_true("children"): + parent_tree = ContainerStorage.get_top_down_hierarchy(cont_name, cid) + # We only need a list of all the ids, no need for the tree anymore + parents = [pid for parent in parent_tree.keys() for pid in parent_tree[parent]] + + # We set User to None because we check for permission when finding the parents + analyses = containerstorage.AnalysisStorage().get_all_el({'parent.id':{'$in':parents}},None,{'info': 0, 'files.info': 0}) + else: + analyses = containerstorage.AnalysisStorage().get_all_el({'parent.id':cid, 'parent.type':singularize(cont_name)},None,{'info': 0, 'files.info': 0}) return analyses diff --git a/tests/integration_tests/python/test_containers.py b/tests/integration_tests/python/test_containers.py index 1e28b0325b595388cbf302aa31d19be6037e90b3..0b475abbbaa745ad353720863becc5aa5e36d107 100644 --- a/tests/integration_tests/python/test_containers.py +++ b/tests/integration_tests/python/test_containers.py @@ -211,20 +211,29 @@ def test_get_all_containers(data_builder, as_admin, as_user, as_public, file_for # Test get_all analyses project_3 = data_builder.create_project(public=False) - session_2 = data_builder.create_session(project=project_3) + session_2 = data_builder.create_session(project=project_3, public=False) analysis_1 = as_admin.post('/sessions/' + session_2 + '/analyses', files=file_form( 'analysis.csv', meta={'label': 'no-job', 'inputs': [{'name': 'analysis.csv'}]})).json()["_id"] + session_3 = data_builder.create_session(project=project_3) acquisition = data_builder.create_acquisition(session=session_3) analysis_2 = as_admin.post('/acquisitions/' + acquisition + '/analyses', files=file_form( 'analysis.csv', meta={'label': 'no-job', 'inputs': [{'name': 'analysis.csv'}]})).json()["_id"] - r = as_admin.get('/projects/' + project_3 + '/analyses') + r = as_admin.get('/projects/' + project_3 + '/analyses', params={'children':True}) assert r.ok assert len(r.json()) == 2 - r = as_user.get('/projects/' + project_3 + '/analyses') + r = as_user.get('/projects/' + project_3 + '/analyses', params={'children':True}) + assert r.status_code == 403 + + + r = as_admin.get('/sessions/' + session_2 + '/analyses', params={'children':False}) + assert r.ok + assert len(r.json()) == 1 + + r = as_user.get('/sessions/' + session_2 + '/analyses', params={'children':False}) assert r.status_code == 403