Skip to content

fix #3081 #3082

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Mar 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
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
56 changes: 56 additions & 0 deletions qiita_db/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -1976,6 +1976,62 @@ def generate_analysis_list(analysis_ids, public_only=False):
return results


def generate_analyses_list_per_study(study_id):
"""Get study analyses and their preparations

Parameters
----------
study_id : int
The study id

Returns
-------
list of dict
The available analyses and their general information
"""
# for speed and SQL simplicity, we are going to split the search in two
# queries: 1. analysis_sql: to find analyses associated with this study
# and the artifacts used to generate the analyses; and 2. extra_sql: each
# analysis details, including the artifacts (children) that belong to
# the analysis.
analysis_sql = """
SELECT DISTINCT analysis_id, array_agg(DISTINCT artifact_id) AS aids
FROM qiita.analysis_sample analysis_sample
WHERE sample_id IN (SELECT sample_id
FROM qiita.study_sample
WHERE study_id = %s)
GROUP BY analysis_id
ORDER BY analysis_id
"""
extra_sql = """
SELECT analysis_id, analysis.name, analysis.email, analysis.dflt,
array_agg(DISTINCT aa.artifact_id) FILTER (
WHERE aa.artifact_id IS NOT NULL) as artifact_ids,
ARRAY(SELECT DISTINCT prep_template_id
FROM qiita.preparation_artifact
WHERE artifact_id IN %s) as prep_ids,
array_agg(DISTINCT visibility.visibility) FILTER (
WHERE aa.artifact_id IS NOT NULL) as visibility
FROM qiita.analysis analysis
LEFT JOIN qiita.analysis_artifact aa USING (analysis_id)
LEFT JOIN qiita.artifact artifact USING (artifact_id)
LEFT JOIN qiita.visibility visibility USING (visibility_id)
WHERE analysis_id = %s
GROUP BY analysis_id, analysis.name, analysis.email, analysis.dflt
"""
results = []
with qdb.sql_connection.TRN:
qdb.sql_connection.TRN.add(analysis_sql, [study_id])
aids = qdb.sql_connection.TRN.execute_fetchindex()
for aid, artifact_ids in aids:
qdb.sql_connection.TRN.add(
extra_sql, [tuple(artifact_ids), aid])
for row in qdb.sql_connection.TRN.execute_fetchindex():
results.append(dict(row))

return results


def create_nested_path(path):
"""Wraps makedirs() to make it safe to use across multiple concurrent calls.
Returns successfully if the path was created, or if it already exists.
Expand Down
4 changes: 2 additions & 2 deletions qiita_pet/handlers/api_proxy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
# Qiita API once we build it. This will be removed and replaced with API calls
# when the API is complete.
from .sample_template import (
sample_template_filepaths_get_req,
sample_template_filepaths_get_req, analyses_associated_with_study,
sample_template_get_req, sample_template_meta_cats_get_req,
sample_template_samples_get_req, sample_template_category_get_req,
get_sample_template_processing_status)
Expand Down Expand Up @@ -61,6 +61,6 @@
'list_commands_handler_get_req',
'list_options_handler_get_req', 'workflow_handler_post_req',
'workflow_handler_patch_req', 'workflow_run_post_req',
'job_ajax_get_req',
'job_ajax_get_req', 'analyses_associated_with_study',
'get_sample_template_processing_status', 'user_jobs_get_req',
'job_ajax_patch_req', 'check_access', 'check_fp']
31 changes: 31 additions & 0 deletions qiita_pet/handlers/api_proxy/sample_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

from qiita_core.util import execute_as_transaction
from qiita_core.qiita_settings import r_client
from qiita_db.util import generate_analyses_list_per_study
from qiita_db.metadata_template.sample_template import SampleTemplate
from qiita_db.exceptions import QiitaDBUnknownIDError
from qiita_db.exceptions import QiitaDBColumnError
Expand Down Expand Up @@ -182,6 +183,36 @@ def sample_template_category_get_req(category, samp_id, user_id):
'values': values}


def analyses_associated_with_study(study_id, user_id):
"""Returns all available analyses in study_id

Parameters
----------
study_id : int or str typecastable to int
Study id to get info for
user_id : str
User requesting the sample template info

Returns
-------
dict
Returns information in the form
{'status': str,
'message': str,
'values': list of [qiita_db.analysis.Analysis,
prep_ids for this study]}
"""
access_error = check_access(study_id, user_id)
if access_error:
return access_error

values = generate_analyses_list_per_study(study_id)

return {'status': 'success',
'message': '',
'values': values}


def get_sample_template_processing_status(st_id):
# Initialize variables here
processing = False
Expand Down
26 changes: 25 additions & 1 deletion qiita_pet/handlers/api_proxy/tests/test_sample_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
sample_template_filepaths_get_req, sample_template_get_req,
_check_sample_template_exists, sample_template_samples_get_req,
sample_template_category_get_req, sample_template_meta_cats_get_req,
get_sample_template_processing_status,
get_sample_template_processing_status, analyses_associated_with_study,
SAMPLE_TEMPLATE_KEY_FORMAT)


Expand Down Expand Up @@ -127,6 +127,30 @@ def test_sample_template_get_req_no_template(self):
'message': 'Sample template %d does not '
'exist' % self.new_study.id})

def test_analyses_associated_with_study(self):
obs = analyses_associated_with_study(self.new_study.id, 'test@foo.bar')
exp = {'status': 'success', 'message': '', 'values': []}
self.assertEqual(obs, exp)

obs = analyses_associated_with_study(1, 'test@foo.bar')
exp = {'status': 'success', 'message': '', 'values': [
{'analysis_id': 1, 'name': 'SomeAnalysis', 'email': 'test@foo.bar',
'dflt': False, 'artifact_ids': [8, 9], 'prep_ids': [1],
'visibility': ['sandbox']},
{'analysis_id': 2, 'name': 'SomeSecondAnalysis',
'email': 'admin@foo.bar', 'dflt': False, 'artifact_ids': None,
'prep_ids': [1], 'visibility': None},
{'analysis_id': 3, 'name': 'test@foo.bar-dflt-1',
'email': 'test@foo.bar', 'dflt': True, 'artifact_ids': None,
'prep_ids': [1], 'visibility': None}]}
self.assertEqual(obs, exp)

obs = analyses_associated_with_study(
self.new_study.id, 'shared@foo.bar')
exp = {'status': 'error',
'message': 'User does not have access to study'}
self.assertEqual(obs, exp)

def test_get_sample_template_processing_status(self):
key = SAMPLE_TEMPLATE_KEY_FORMAT % 1

Expand Down
4 changes: 2 additions & 2 deletions qiita_pet/handlers/study_handlers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from .artifact import (ArtifactGraphAJAX, NewArtifactHandler,
ArtifactAdminAJAX, ArtifactGetSamples, ArtifactGetInfo)
from .sample_template import (
SampleTemplateHandler, SampleTemplateOverviewHandler,
SampleTemplateHandler, SampleTemplateOverviewHandler, AnalysesAjax,
SampleTemplateColumnsHandler, SampleAJAX)

__all__ = ['ListStudiesHandler', 'StudyApprovalList', 'ShareStudyAJAX',
Expand All @@ -36,6 +36,6 @@
'ListCommandsHandler', 'ListOptionsHandler', 'SampleAJAX',
'StudyDeleteAjax', 'NewPrepTemplateAjax',
'DataTypesMenuAJAX', 'StudyFilesAJAX', 'PrepTemplateSummaryAJAX',
'WorkflowHandler', 'WorkflowRunHandler',
'WorkflowHandler', 'WorkflowRunHandler', 'AnalysesAjax',
'JobAJAX', 'AutocompleteHandler', 'StudyGetTags', 'StudyTags',
'Study', 'ArtifactGetSamples', 'ArtifactGetInfo']
13 changes: 12 additions & 1 deletion qiita_pet/handlers/study_handlers/sample_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from tornado.web import authenticated, HTTPError

from qiita_core.qiita_settings import r_client
from qiita_pet.handlers.util import to_int
from qiita_pet.handlers.base_handlers import BaseHandler
from qiita_db.util import get_files_from_uploads_folders
from qiita_db.study import Study
Expand All @@ -26,7 +27,7 @@
data_types_get_req, sample_template_samples_get_req,
prep_template_samples_get_req, study_prep_get_req,
sample_template_meta_cats_get_req, sample_template_category_get_req,
get_sample_template_processing_status,
get_sample_template_processing_status, analyses_associated_with_study,
check_fp)


Expand Down Expand Up @@ -533,3 +534,13 @@ def post(self):
'message': '',
'values': values['values']
})


class AnalysesAjax(BaseHandler):
@authenticated
def get(self):
user_id = self.current_user.id
study_id = to_int(self.get_argument('study_id'))
result = analyses_associated_with_study(study_id, user_id)
self.render('study_ajax/study_analyses.html',
analyses=result['values'])
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,15 @@ def test_get(self):
self.assertIn(line, res.body.decode('ascii'))


class TestAnalysesAjax(TestHandlerBase):
def test_get(self):
res = self.get("/study/analyses/", {'study_id': 1})
self.assertEqual(res.code, 200)
# making sure at least one analysis is in the page
line = '/analysis/description/1/'
self.assertIn(line, res.body.decode('ascii'))


class TestSampleAJAX(TestHandlerBase):

def test_post(self):
Expand Down
44 changes: 44 additions & 0 deletions qiita_pet/templates/study_ajax/study_analyses.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{% from qiita_core.qiita_settings import qiita_config %}

<script type="text/javascript" src="{% raw qiita_config.portal_dir %}/static/vendor/js/jquery.validate.min.js"></script>
<script type="text/javascript>">
$('#studies-analyses-table').dataTable();
</script>
<h3>Analyses that have used this study</h3>

Note that if an analysis doesn't have a link, it means that is a "User default analysis"; which means that the analysis belongs to that user but the user has only selected artifacts and hasn't created the actual analysis. Please contact the user and ask them to delete that artifact from their analysis creation page.
<br/><br/>
<table id="studies-analyses-table" class="display table-bordered table-hover" style="width:100%">
<thead>
<tr>
<th>Analysis</th>
<th>Owner</th>
<th>Prep IDs Used</th>
<th>Is Public?</th>
<th>Artifacts in Analysis</th>
</tr>
</thead>
<tbody>
{% for a in analyses %}
<tr>
<td>
{% if a['dflt'] %}
{{a['name']}} (ID: {{a['analysis_id']}})
{% else %}
<a href="{% raw qiita_config.portal_dir %}/analysis/description/{{a['analysis_id']}}/" target="_blank">{{a['name']}} (ID: {{a['analysis_id']}})</a>
{% end %}
</td>
<td>{{a['email']}}</td>
<td>{{', '.join(map(str, a['prep_ids']))}}</td>
<td>{{a['visibility'] == ['public']}}</td>
<td>
{% if a['artifact_ids'] is None %}
0
{% else %}
{{len(a['artifact_ids'])}}
{% end %}
</td>
</tr>
{% end %}
</tbody>
</table>
1 change: 1 addition & 0 deletions qiita_pet/templates/study_base.html
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
{% if editable %}
<a class="btn btn-default btn-block" href="{% raw qiita_config.portal_dir %}/study/upload/{{study_info['study_id']}}"><span class="glyphicon glyphicon-upload"></span> Upload Files</a>
<button class="btn btn-default btn-block" onclick="populate_main_div('{% raw qiita_config.portal_dir %}/study/new_prep_template/', { study_id: {{study_info['study_id']}} })" id="add-new-preparation-btn"><span class="glyphicon glyphicon-plus-sign"></span> Add New Preparation</button>
<button class="btn btn-default btn-block" onclick="populate_main_div('{% raw qiita_config.portal_dir %}/study/analyses/', { study_id: {{study_info['study_id']}} })" id="analyses-btn"><span class="glyphicon glyphicon-info-sign"></span> Analyses using artifacts from this Study</button>
{% end %}
{% if study_info['show_biom_download_button'] %}
<a class="btn btn-default btn-block" href="{% raw qiita_config.portal_dir %}/download_study_bioms/{{study_info['study_id']}}"><span class="glyphicon glyphicon-download-alt"></span> All QIIME maps and BIOMs</a>
Expand Down
3 changes: 2 additions & 1 deletion qiita_pet/webserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
ListCommandsHandler, ListOptionsHandler, PrepTemplateSummaryAJAX,
PrepTemplateAJAX, NewArtifactHandler, SampleAJAX, StudyDeleteAjax,
ArtifactAdminAJAX, NewPrepTemplateAjax, DataTypesMenuAJAX, StudyFilesAJAX,
ArtifactGetSamples, ArtifactGetInfo, WorkflowHandler,
ArtifactGetSamples, ArtifactGetInfo, WorkflowHandler, AnalysesAjax,
WorkflowRunHandler, JobAJAX, AutocompleteHandler)
from qiita_pet.handlers.artifact_handlers import (
ArtifactSummaryAJAX, ArtifactAJAX, ArtifactSummaryHandler)
Expand Down Expand Up @@ -144,6 +144,7 @@ def __init__(self):
(r"/study/sharing/", ShareStudyAJAX),
(r"/study/sharing/autocomplete/", AutocompleteHandler),
(r"/study/new_prep_template/", NewPrepTemplateAjax),
(r"/study/analyses/", AnalysesAjax),
(r"/study/tags/(.*)", StudyTags),
(r"/study/get_tags/", StudyGetTags),
(r"/study/([0-9]+)$", Study),
Expand Down