Skip to content

fix #1959 #2064

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 1 commit into from
Feb 3, 2017
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
35 changes: 22 additions & 13 deletions qiita_pet/handlers/api_proxy/prep_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,8 @@ def prep_template_summary_get_req(prep_id, user_id):
Format {'status': status,
'message': message,
'num_samples': value,
'category': [(val1, count1), (val2, count2), ...], ...}
'category': [(val1, count1), (val2, count2), ...],
'editable': bool}
"""
exists = _check_prep_template_exists(int(prep_id))
if exists['status'] != 'success':
Expand All @@ -309,17 +310,21 @@ def prep_template_summary_get_req(prep_id, user_id):
access_error = check_access(prep.study_id, user_id)
if access_error:
return access_error

editable = Study(prep.study_id).can_edit(User(user_id))
df = prep.to_dataframe()
out = {'num_samples': df.shape[0],
'summary': {},
'summary': [],
'status': 'success',
'message': ''}
'message': '',
'editable': editable}

cols = list(df.columns)
cols = sorted(list(df.columns))
for column in cols:
counts = df[column].value_counts()
out['summary'][str(column)] = [(str(key), counts[key])
for key in natsorted(counts.index)]
out['summary'].append(
(str(column), [(str(key), counts[key])
for key in natsorted(counts.index)]))
return out


Expand Down Expand Up @@ -417,10 +422,11 @@ def prep_template_patch_req(user_id, req_op, req_path, req_value=None,

Returns
-------
dict of {str, str}
dict of {str, str, str}
A dictionary with the following keys:
- status: str, whether if the request is successful or not
- message: str, if the request is unsuccessful, a human readable error
- row_id: str, the row_id that we tried to delete
"""
req_path = [v for v in req_path.split('/') if v]
if req_op == 'replace':
Expand Down Expand Up @@ -458,13 +464,15 @@ def prep_template_patch_req(user_id, req_op, req_path, req_value=None,

return {'status': status, 'message': msg}
elif req_op == 'remove':
# The structure of the path should be /prep_id/{columns|samples}/name
if len(req_path) != 3:
# The structure of the path should be:
# /prep_id/row_id/{columns|samples}/name
if len(req_path) != 4:
return {'status': 'error',
'message': 'Incorrect path parameter'}
prep_id = int(req_path[0])
attribute = req_path[1]
attr_id = req_path[2]
row_id = req_path[1]
attribute = req_path[2]
attr_id = req_path[3]

# Check if the user actually has access to the study
pt = PrepTemplate(prep_id)
Expand All @@ -478,12 +486,13 @@ def prep_template_patch_req(user_id, req_op, req_path, req_value=None,
# Store the job id attaching it to the sample template id
r_client.set(PREP_TEMPLATE_KEY_FORMAT % prep_id,
dumps({'job_id': job_id, 'is_qiita_job': False}))
return {'status': 'success', 'message': ''}
return {'status': 'success', 'message': '', 'row_id': row_id}
else:
return {'status': 'error',
'message': 'Operation "%s" not supported. '
'Current supported operations: replace, remove'
% req_op}
% req_op,
'row_id': '0'}


def prep_template_samples_get_req(prep_id, user_id):
Expand Down
13 changes: 8 additions & 5 deletions qiita_pet/handlers/api_proxy/sample_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -521,13 +521,15 @@ def sample_template_patch_request(user_id, req_op, req_path, req_value=None,
if req_op == 'remove':
req_path = [v for v in req_path.split('/') if v]

if len(req_path) != 3:
# format: study_id/row_id/column|sample/attribute_id
if len(req_path) != 4:
return {'status': 'error',
'message': 'Incorrect path parameter'}

st_id = req_path[0]
attribute = req_path[1]
attr_id = req_path[2]
row_id = req_path[1]
attribute = req_path[2]
attr_id = req_path[3]

# Check if the user actually has access to the template
st = SampleTemplate(st_id)
Expand All @@ -542,9 +544,10 @@ def sample_template_patch_request(user_id, req_op, req_path, req_value=None,
r_client.set(SAMPLE_TEMPLATE_KEY_FORMAT % st_id,
dumps({'job_id': job_id}))

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

else:
return {'status': 'error',
'message': 'Operation "%s" not supported. '
'Current supported operations: remove' % req_op}
'Current supported operations: remove' % req_op,
'row_id': 0}
91 changes: 45 additions & 46 deletions qiita_pet/handlers/api_proxy/tests/test_prep_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,40 +206,9 @@ def test_prep_template_graph_get_req_no_exists(self):

def test_prep_template_summary_get_req(self):
obs = prep_template_summary_get_req(1, 'test@foo.bar')
exp = {'summary': {
'experiment_center': [('ANL', 27)],
'center_name': [('ANL', 27)],
'run_center': [('ANL', 27)],
'run_prefix': [('s_G1_L001_sequences', 27)],
'primer': [('GTGCCAGCMGCCGCGGTAA', 27)],
'target_gene': [('16S rRNA', 27)],
'sequencing_meth': [('Sequencing by synthesis', 27)],
'run_date': [('8/1/12', 27)],
'platform': [('Illumina', 27)],
'pcr_primers': [('FWD:GTGCCAGCMGCCGCGGTAA; '
'REV:GGACTACHVGGGTWTCTAAT', 27)],
'library_construction_protocol': [(
'This analysis was done as in Caporaso et al 2011 Genome '
'research. The PCR primers (F515/R806) were developed against '
'the V4 region of the 16S rRNA (both bacteria and archaea), '
'which we determined would yield optimal community clustering '
'with reads of this length using a procedure similar to that '
'of ref. 15. [For reference, this primer pair amplifies the '
'region 533_786 in the Escherichia coli strain 83972 sequence '
'(greengenes accession no. prokMSA_id:470367).] The reverse '
'PCR primer is barcoded with a 12-base error-correcting Golay '
'code to facilitate multiplexing of up to 1,500 samples per '
'lane, and both PCR primers contain sequencer adapter '
'regions.', 27)],
'experiment_design_description': [(
'micro biome of soil and rhizosphere of cannabis plants from '
'CA', 27)],
'study_center': [('CCME', 27)],
'center_project_name': [],
'sample_center': [('ANL', 27)],
'samp_size': [('.25,g', 27)],
'qiita_prep_id': [('1', 27)],
'barcode': [
exp = {
'status': 'success', 'message': '',
'summary': [('barcode', [
('AACTCCTGTGGA', 1), ('ACCTCAGTCAAG', 1), ('ACGCACATACAA', 1),
('AGCAGGCACGAA', 1), ('AGCGCTCACATC', 1), ('ATATCGCGATGA', 1),
('ATGGCCTGACTA', 1), ('CATACACGCACC', 1), ('CCACCCAGTAAC', 1),
Expand All @@ -248,15 +217,44 @@ def test_prep_template_summary_get_req(self):
('CGTAGAGCTCTC', 1), ('CGTGCACAATTG', 1), ('GATAGCACTCGT', 1),
('GCGGACTATTCA', 1), ('GTCCGCAAGTTA', 1), ('TAATGGTCGTAG', 1),
('TAGCGCGAACTT', 1), ('TCGACCAAACAC', 1), ('TGAGTGGTCTGT', 1),
('TGCTACAGACGT', 1), ('TGGTTATGGCAC', 1), ('TTGCACCGTCGA', 1)],
'emp_status': [('EMP', 27)],
'illumina_technology': [('MiSeq', 27)],
'experiment_title': [('Cannabis Soil Microbiome', 27)],
'target_subfragment': [('V4', 27)],
'instrument_model': [('Illumina MiSeq', 27)]},
'num_samples': 27,
'status': 'success',
'message': ''}
('TGCTACAGACGT', 1), ('TGGTTATGGCAC', 1), ('TTGCACCGTCGA', 1)
]), ('center_name', [('ANL', 27)]), ('center_project_name', []),
('emp_status', [('EMP', 27)]),
('experiment_center', [('ANL', 27)]),
('experiment_design_description', [
('micro biome of soil and rhizosphere of cannabis plants '
'from CA', 27)]),
('experiment_title', [('Cannabis Soil Microbiome', 27)]),
('illumina_technology', [('MiSeq', 27)]),
('instrument_model', [('Illumina MiSeq', 27)]),
('library_construction_protocol', [
('This analysis was done as in Caporaso et al 2011 Genome '
'research. The PCR primers (F515/R806) were developed '
'against the V4 region of the 16S rRNA (both bacteria '
'and archaea), which we determined would yield optimal '
'community clustering with reads of this length using a '
'procedure similar to that of ref. 15. [For reference, '
'this primer pair amplifies the region 533_786 in the '
'Escherichia coli strain 83972 sequence (greengenes '
'accession no. prokMSA_id:470367).] The reverse PCR '
'primer is barcoded with a 12-base error-correcting '
'Golay code to facilitate multiplexing of up to 1,500 '
'samples per lane, and both PCR primers contain '
'sequencer adapter regions.', 27)]),
('pcr_primers', [(
'FWD:GTGCCAGCMGCCGCGGTAA; REV:GGACTACHVGGGTWTCTAAT', 27)]),
('platform', [('Illumina', 27)]),
('primer', [('GTGCCAGCMGCCGCGGTAA', 27)]),
('qiita_prep_id', [('1', 27)]), ('run_center', [('ANL', 27)]),
('run_date', [('8/1/12', 27)]),
('run_prefix', [('s_G1_L001_sequences', 27)]),
('samp_size', [('.25,g', 27)]),
('sample_center', [('ANL', 27)]),
('sequencing_meth', [('Sequencing by synthesis', 27)]),
('study_center', [('CCME', 27)]),
('target_gene', [('16S rRNA', 27)]),
('target_subfragment', [('V4', 27)])],
'editable': True, 'num_samples': 27}
self.assertEqual(obs, exp)

def test_prep_template_summary_get_req_no_access(self):
Expand Down Expand Up @@ -476,8 +474,8 @@ def test_prep_template_patch_req(self):
# Delete a prep template column
obs = prep_template_patch_req(
'test@foo.bar', 'remove',
'/%s/columns/target_subfragment/' % pt.id)
exp = {'status': 'success', 'message': ''}
'/%s/10/columns/target_subfragment/' % pt.id)
exp = {'status': 'success', 'message': '', 'row_id': '10'}
self.assertEqual(obs, exp)
self._wait_for_parallel_job('prep_template_%s' % pt.id)
self.assertNotIn('target_subfragment', pt.categories())
Expand All @@ -489,7 +487,8 @@ def test_prep_template_patch_req(self):
'Cancer Genomics')
exp = {'status': 'error',
'message': 'Operation "add" not supported. '
'Current supported operations: replace, remove'}
'Current supported operations: replace, remove',
'row_id': '0'}
self.assertEqual(obs, exp)
# Incorrect path parameter
obs = prep_template_patch_req(
Expand Down
14 changes: 7 additions & 7 deletions qiita_pet/handlers/api_proxy/tests/test_sample_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -525,28 +525,28 @@ def test_sample_template_meta_cats_get_req_no_template(self):
def test_sample_template_patch_request(self):
# Wrong operation operation
obs = sample_template_patch_request(
"test@foo.bar", "add", "/1/columns/season_environment/")
"test@foo.bar", "add", "/1/10/columns/season_environment/")
exp = {'status': 'error',
'message': 'Operation "add" not supported. '
'Current supported operations: remove'}
'Current supported operations: remove',
'row_id': 0}
self.assertEqual(obs, exp)
# Wrong path parameter
obs = sample_template_patch_request(
"test@foo.bar", "remove", "/columns/season_environment/")
"test@foo.bar", "remove", "10/columns/season_environment/")
exp = {'status': 'error',
'message': 'Incorrect path parameter'}
self.assertEqual(obs, exp)
# No access
obs = sample_template_patch_request(
"demo@microbio.me", "remove", "/1/columns/season_environment/")
"demo@microbio.me", "remove", "/1/10/columns/season_environment/")
exp = {'status': 'error',
'message': 'User does not have access to study'}
self.assertEqual(obs, exp)
# Success
obs = sample_template_patch_request(
"test@foo.bar", "remove", "/1/columns/season_environment/")
exp = {'status': 'success',
'message': ''}
"test@foo.bar", "remove", "/1/10/columns/season_environment/")
exp = {'status': 'success', 'message': '', 'row_id': '10'}
self.assertEqual(obs, exp)

# This is needed so the clean up works - this is a distributed system
Expand Down
7 changes: 6 additions & 1 deletion qiita_pet/handlers/study_handlers/prep_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,21 +44,26 @@ class PrepTemplateSummaryAJAX(BaseHandler):
@authenticated
def get(self):
prep_id = to_int(self.get_argument('prep_id'))

res = prep_template_summary_get_req(prep_id, self.current_user.id)

self.render('study_ajax/prep_summary_table.html', pid=prep_id,
stats=res['summary'])
stats=res['summary'], editable=res['editable'])


class PrepTemplateAJAX(BaseHandler):
@authenticated
def get(self):
"""Send formatted summary page of prep template"""
prep_id = to_int(self.get_argument('prep_id'))
row_id = self.get_argument('row_id', '0')

res = prep_template_ajax_get_req(self.current_user.id, prep_id)
res['prep_id'] = prep_id
res['row_id'] = row_id
# Escape the message just in case javascript breaking characters in it
res['alert_message'] = url_escape(res['alert_message'])

self.render('study_ajax/prep_summary.html', **res)


Expand Down
3 changes: 3 additions & 0 deletions qiita_pet/handlers/study_handlers/sample_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ class SampleTemplateAJAX(BaseHandler):
def get(self):
"""Send formatted summary page of sample template"""
study_id = self.get_argument('study_id')
row_id = self.get_argument('row_id', '0')

files = [f for _, f in get_files_from_uploads_folders(study_id)
if f.endswith(('txt', 'tsv'))]
data_types = sorted(data_types_get_req()['data_types'])
Expand All @@ -95,6 +97,7 @@ def get(self):
stats['files'] = files
stats['study_id'] = study_id
stats['data_types'] = data_types
stats['row_id'] = row_id
# URL encode in case message has javascript-breaking characters in it
stats['alert_message'] = url_escape(stats['alert_message'])
self.render('study_ajax/sample_summary.html', **stats)
Expand Down
24 changes: 21 additions & 3 deletions qiita_pet/templates/study_ajax/prep_summary.html
Original file line number Diff line number Diff line change
Expand Up @@ -181,18 +181,18 @@
* prep information
*
*/
function delete_prep_column(prep_id, column_name) {
function delete_prep_column(prep_id, column_name, row_id) {
if(confirm("Are you sure you want to delete '" + column_name + "' information?")) {
$.ajax({
url: '{% raw qiita_config.portal_dir %}/prep_template/',
type: 'PATCH',
data: {'op': 'remove', 'path': '/' + prep_id + '/columns/' + column_name},
data: {'op': 'remove', 'path': '/' + prep_id + '/' + row_id + '/columns/' + column_name},
success: function(data) {
if(data.status == 'error') {
bootstrapAlert(data.message, "danger");
}
else {
populate_main_div('/study/description/prep_template/', { prep_id: prep_id, study_id: {{study_id}} });
populate_main_div('/study/description/prep_template/', { prep_id: prep_id, study_id: {{study_id}}, row_id: row_id });
}
}
});
Expand Down Expand Up @@ -329,6 +329,22 @@
}
}

/*
* Autoscroll prep info list
*
* This is a helper function so we can scroll once the prep table is ready
*/
function autoscroll_prep_list() {
// taken from: http://stackoverflow.com/a/2906009
if ({{row_id}} > 1) {
var container = $("html, body"), scrollTo = $("#row_{{row_id}}");

container.animate({
scrollTop: scrollTo.offset().top - container.offset().top + container.scrollTop()
});
}
}

$(document).ready(function () {
if("{{investigation_type}}" !== "None") {
// The prep information already has an investigation type
Expand Down Expand Up @@ -402,6 +418,8 @@
{% else %}
$('#alert-message').alert('close');
{% end %}


});
</script>

Expand Down
13 changes: 10 additions & 3 deletions qiita_pet/templates/study_ajax/prep_summary_table.html
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
<script type="text/javascript">
$(document).ready(function () {
autoscroll_prep_list();
});
</script>


{% from future.utils import viewitems %}
<div class="panel panel-default">
<div class="panel-heading">
Information summary
</div>
<div id="summary-table-div">
<table class="table">
{% for category, summary in viewitems(stats) %}
<tr>
{% for i, (category, summary) in enumerate(stats, -1) %}
<tr id="row_{{i}}">
<td>
<a class="btn btn-danger" onclick="delete_prep_column({{pid}}, '{{category}}');"><span class="glyphicon glyphicon-trash"></span></a>
<a class="btn btn-danger" onclick="delete_prep_column({{pid}}, '{{category}}', {{i}});"><span class="glyphicon glyphicon-trash"></span></a>
</td>
{% if len(summary) == 1 %}
<td colspan="2">
Expand Down
Loading