Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 63 additions & 51 deletions qiita_db/meta_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
..autosummary::
:toctree: generated/

get_accessible_filepath_ids
get_lat_longs
"""
# -----------------------------------------------------------------------------
Expand Down Expand Up @@ -48,7 +47,7 @@ def _get_data_fpids(constructor, object_id):
return {fpid for fpid, _, _ in obj.get_filepaths()}


def get_accessible_filepath_ids(user):
def validate_filepath_access_by_user(user, filepath_id):
"""Gets all filepaths that this user should have access to
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you update the one sentence description of the documentation?


This gets all raw, preprocessed, and processed filepaths, for studies
Expand All @@ -59,67 +58,80 @@ def get_accessible_filepath_ids(user):
----------
user : User object
The user we are interested in

filepath_id : int
The filepath id

Returns
-------
set
A set of filepath ids
bool
If the user has access or not to the filepath_id

Notes
-----
Admins have access to all files, so all filepath ids are returned for
admins
Admins have access to all files so True is always returned
"""
with qdb.sql_connection.TRN:
if user.level == "admin":
return True
# admins have access all files
qdb.sql_connection.TRN.add(
"SELECT filepath_id FROM qiita.filepath")
return set(qdb.sql_connection.TRN.execute_fetchflatten())

# First, the studies
# There are private and shared studies
studies = user.user_studies | user.shared_studies

filepath_ids = set()
for study in studies:
# Add the sample template files
if study.sample_template:
filepath_ids.update(
{fid for fid, _ in study.sample_template.get_filepaths()})

# Add the prep template filepaths
for pt in study.prep_templates():
filepath_ids.update({fid for fid, _ in pt.get_filepaths()})

# Add the artifact filepaths
for artifact in study.artifacts():
filepath_ids.update({fid for fid, _, _ in artifact.filepaths})

# Next, the public artifacts
for artifact in qdb.artifact.Artifact.iter_public():
# Add the filepaths of the artifact
filepath_ids.update({fid for fid, _, _ in artifact.filepaths})

# Then add the filepaths of the prep templates
for pt in artifact.prep_templates:
filepath_ids.update({fid for fid, _ in pt.get_filepaths()})

# Then add the filepaths of the sample template
filepath_ids.update(
{fid
for fid, _ in artifact.study.sample_template.get_filepaths()})
access = False

# Next, analyses
# Same as before, there are public, private, and shared
analyses = qdb.analysis.Analysis.get_by_status('public') | \
user.private_analyses | user.shared_analyses

for analysis in analyses:
filepath_ids.update(analysis.all_associated_filepath_ids)

return filepath_ids
# check the public artifacts
for artifact in qdb.artifact.Artifact.iter_public():
for fid, _, _ in artifact.filepaths:
if fid == filepath_id:
access = True
break
# prep templates
if not access:
for pt in artifact.prep_templates:
for fid, _ in pt.get_filepaths():
if fid == filepath_id:
access = True
break
# sample template
if not access:
for fid, _ in artifact.study.sample_template.get_filepaths():
if fid == filepath_id:
access = True
break

# check private and shared studies with the user
if not access:
studies = user.user_studies | user.shared_studies
for study in studies:
if study.sample_template:
# sample info files
for fid, _ in study.sample_template.get_filepaths():
if fid == filepath_id:
access = True
break
# prep info files
if not access:
for pt in study.prep_templates():
for fid, _ in pt.get_filepaths():
if fid == filepath_id:
access = True
break
# artifacts
if not access:
for artifact in study.artifacts():
for fid, _, _ in artifact.filepaths:
if fid == filepath_id:
access = True
break

# next analyses
if not access:
analyses = qdb.analysis.Analysis.get_by_status('public') | \
user.private_analyses | user.shared_analyses
for analysis in analyses:
if filepath_id in analysis.all_associated_filepath_ids:
access = True
break

return access


def get_lat_longs():
Expand Down
62 changes: 30 additions & 32 deletions qiita_db/test/test_meta_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,40 +38,38 @@ def _unshare_studies(self):
def _unshare_analyses(self):
self.conn_handler.execute("DELETE FROM qiita.analysis_users")

def test_get_accessible_filepath_ids(self):
def test_validate_filepath_access_by_user(self):
self._set_artifact_private()

# shared has access to all study files and analysis files

obs = qdb.meta_util.get_accessible_filepath_ids(
qdb.user.User('shared@foo.bar'))
self.assertItemsEqual(obs, {
1, 2, 3, 4, 5, 9, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21})
user = qdb.user.User('shared@foo.bar')
for i in [1, 2, 3, 4, 5, 9, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21]:
self.assertTrue(qdb.meta_util.validate_filepath_access_by_user(
user, i))

# Now shared should not have access to the study files
self._unshare_studies()
obs = qdb.meta_util.get_accessible_filepath_ids(
qdb.user.User('shared@foo.bar'))
self.assertItemsEqual(obs, {16, 14, 15, 13})
for i in [1, 2, 3, 4, 5, 9, 12, 17, 18, 19, 20, 21]:
self.assertFalse(qdb.meta_util.validate_filepath_access_by_user(
user, i))

for i in [13, 14, 15, 16]:
self.assertTrue(qdb.meta_util.validate_filepath_access_by_user(
user, i))

# Now shared should not have access to any files
self._unshare_analyses()
obs = qdb.meta_util.get_accessible_filepath_ids(
qdb.user.User('shared@foo.bar'))
self.assertEqual(obs, set())
for i in [1, 2, 3, 4, 5, 9, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21]:
self.assertFalse(qdb.meta_util.validate_filepath_access_by_user(
user, i))

# Now shared has access to public study files
self._set_artifact_public()
obs = qdb.meta_util.get_accessible_filepath_ids(
qdb.user.User('shared@foo.bar'))
self.assertEqual(obs, {1, 2, 3, 4, 5, 9, 12, 17, 18, 19, 20, 21})
for i in [1, 2, 3, 4, 5, 9, 12, 17, 18, 19, 20, 21]:
self.assertTrue(qdb.meta_util.validate_filepath_access_by_user(
user, i))

# Test that it doesn't break: if the SampleTemplate hasn't been added
exp = {1, 2, 3, 4, 5, 9, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21}
obs = qdb.meta_util.get_accessible_filepath_ids(
qdb.user.User('test@foo.bar'))
self.assertEqual(obs, exp)

info = {
"timeseries_type_id": 1,
"metadata_complete": True,
Expand All @@ -87,24 +85,24 @@ def test_get_accessible_filepath_ids(self):
}
qdb.study.Study.create(
qdb.user.User('test@foo.bar'), "Test study", [1], info)
obs = qdb.meta_util.get_accessible_filepath_ids(
qdb.user.User('test@foo.bar'))
self.assertEqual(obs, exp)
for i in [1, 2, 3, 4, 5, 9, 12, 17, 18, 19, 20, 21]:
self.assertTrue(qdb.meta_util.validate_filepath_access_by_user(
user, i))

# test in case there is a prep template that failed
self.conn_handler.execute(
"INSERT INTO qiita.prep_template (data_type_id) VALUES (2)")
obs = qdb.meta_util.get_accessible_filepath_ids(
qdb.user.User('test@foo.bar'))
self.assertEqual(obs, exp)
for i in [1, 2, 3, 4, 5, 9, 12, 17, 18, 19, 20, 21]:
self.assertTrue(qdb.meta_util.validate_filepath_access_by_user(
user, i))

# admin should have access to everything
count = self.conn_handler.execute_fetchone("SELECT count(*) FROM "
"qiita.filepath")[0]
exp = set(range(1, count + 1))
obs = qdb.meta_util.get_accessible_filepath_ids(
qdb.user.User('admin@foo.bar'))
self.assertEqual(obs, exp)
admin = qdb.user.User('admin@foo.bar')
fids = self.conn_handler.execute_fetchall(
"SELECT filepath_id FROM qiita.filepath")
for i in fids:
self.assertTrue(qdb.meta_util.validate_filepath_access_by_user(
admin, i[0]))

def test_get_lat_longs(self):
exp = [
Expand Down
12 changes: 5 additions & 7 deletions qiita_pet/handlers/download.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,21 @@
from .base_handlers import BaseHandler
from qiita_pet.exceptions import QiitaPetAuthorizationError
from qiita_db.util import filepath_id_to_rel_path
from qiita_db.meta_util import get_accessible_filepath_ids
from qiita_db.meta_util import validate_filepath_access_by_user
from qiita_core.util import execute_as_transaction


class DownloadHandler(BaseHandler):
@authenticated
@execute_as_transaction
def get(self, filepath_id):
filepath_id = int(filepath_id)
# Check access to file
accessible_filepaths = get_accessible_filepath_ids(self.current_user)
fid = int(filepath_id)

if filepath_id not in accessible_filepaths:
if not validate_filepath_access_by_user(self.current_user, fid):
raise QiitaPetAuthorizationError(
self.current_user, 'filepath id %s' % str(filepath_id))
self.current_user, 'filepath id %s' % str(fid))

relpath = filepath_id_to_rel_path(filepath_id)
relpath = filepath_id_to_rel_path(fid)
fname = basename(relpath)

# If we don't have nginx, write a file that indicates this
Expand Down