def test_check_artifact_access(self): # "Study" artifact a = Artifact(1) # The user has access u = User('*****@*****.**') check_artifact_access(u, a) # Admin has access to everything admin = User('*****@*****.**') check_artifact_access(admin, a) # Demo user doesn't have access demo_u = User('*****@*****.**') with self.assertRaises(HTTPError): check_artifact_access(demo_u, a) # "Analysis" artifact a = Artifact(8) a.visibility = 'private' check_artifact_access(u, a) check_artifact_access(admin, a) with self.assertRaises(HTTPError): check_artifact_access(demo_u, a) check_artifact_access(User('*****@*****.**'), a) a.visibility = 'public' check_artifact_access(demo_u, a)
def test_check_artifact_access(self): # "Study" artifact a = Artifact(1) # The user has access u = User('*****@*****.**') check_artifact_access(u, a) # Admin has access to everything admin = User('*****@*****.**') check_artifact_access(admin, a) # Demo user doesn't have access demo_u = User('*****@*****.**') with self.assertRaises(HTTPError): check_artifact_access(demo_u, a) # "Analysis" artifact a = Artifact(8) a.visibility = 'private' check_artifact_access(u, a) check_artifact_access(admin, a) with self.assertRaises(HTTPError): check_artifact_access(demo_u, a) check_artifact_access(User('*****@*****.**'), a) a.visibility = 'public' check_artifact_access(demo_u, a)
def artifact_status_put_req(artifact_id, user_id, visibility): """Set the status of the artifact given Parameters ---------- artifact_id : int Artifact being acted on user_id : str The user requesting the action visibility : {'sandbox', 'awaiting_approval', 'private', 'public'} What to change the visibility to Returns ------- dict Status of action, in the form {'status': status, 'message': msg} status: status of the action, either success or error message: Human readable message for status """ if visibility not in get_visibilities(): return {'status': 'error', 'message': 'Unknown visibility value: %s' % visibility} pd = Artifact(int(artifact_id)) sid = pd.study.id access_error = check_access(sid, user_id) if access_error: return access_error user = User(str(user_id)) status = 'success' msg = 'Artifact visibility changed to %s' % visibility # Set the approval to private if needs approval and admin if visibility == 'private': if not qiita_config.require_approval: pd.visibility = 'private' # Set the approval to private if approval not required elif user.level == 'admin': pd.visibility = 'private' # Trying to set approval without admin privileges else: status = 'error' msg = 'User does not have permissions to approve change' else: pd.visibility = visibility LogEntry.create('Warning', '%s changed artifact %s (study %d) to %s' % ( user_id, artifact_id, sid, visibility)) return {'status': status, 'message': msg}
def approve_study(self, study, user, callback): """Approves the current study if and only if the current user is admin Parameters ---------- study : Study The current study object user : User The current user object callback : function The callback function to call with the results once the processing is done """ if _approve(user.level): pd_id = int(self.get_argument('pd_id')) pd = Artifact(pd_id) pd.visibility = 'private' _propagate_visibility(pd) msg = "Processed data approved" msg_level = "success" else: msg = ("The current user does not have permission to approve " "the processed data") msg_level = "danger" callback((msg, msg_level, "processed_data_tab", pd_id, None))
def approve_study(self, study, user, callback): """Approves the current study if and only if the current user is admin Parameters ---------- study : Study The current study object user : User The current user object callback : function The callback function to call with the results once the processing is done """ if _approve(user.level): pd_id = int(self.get_argument('pd_id')) pd = Artifact(pd_id) pd.visibility = 'private' _propagate_visibility(pd) msg = "Processed data approved" msg_level = "success" else: msg = ("The current user does not have permission to approve " "the processed data") msg_level = "danger" callback((msg, msg_level, "processed_data_tab", pd_id, None))
def artifact_status_put_req(artifact_id, user_id, visibility): """Set the status of the artifact given Parameters ---------- artifact_id : int Artifact being acted on user_id : str The user requesting the action visibility : {'sandbox', 'awaiting_approval', 'private', 'public'} What to change the visibility to Returns ------- dict Status of action, in the form {'status': status, 'message': msg} status: status of the action, either success or error message: Human readable message for status """ if visibility not in get_visibilities(): return {'status': 'error', 'message': 'Unknown visiblity value: %s' % visibility} pd = Artifact(int(artifact_id)) access_error = check_access(pd.study.id, user_id) if access_error: return access_error user = User(str(user_id)) status = 'success' msg = 'Artifact visibility changed to %s' % visibility # Set the approval to private if needs approval and admin if visibility == 'private': if not qiita_config.require_approval: pd.visibility = 'private' # Set the approval to private if approval not required elif user.level == 'admin': pd.visibility = 'private' # Trying to set approval without admin privileges else: status = 'error' msg = 'User does not have permissions to approve change' else: pd.visibility = visibility return {'status': status, 'message': msg}
def test_propagate_visibility(self): a = Artifact(4) a.visibility = 'public' _propagate_visibility(a) self.assertEqual(Artifact(1).visibility, 'public') self.assertEqual(Artifact(2).visibility, 'public') self.assertEqual(Artifact(4).visibility, 'public') a.visibility = 'private' _propagate_visibility(a) self.assertEqual(Artifact(1).visibility, 'private') self.assertEqual(Artifact(2).visibility, 'private') self.assertEqual(Artifact(4).visibility, 'private') a = Artifact(2) a.visibility = 'public' _propagate_visibility(a) self.assertEqual(Artifact(1).visibility, 'private') self.assertEqual(Artifact(2).visibility, 'private') self.assertEqual(Artifact(4).visibility, 'private')
def test_propagate_visibility(self): a = Artifact(4) a.visibility = 'public' _propagate_visibility(a) self.assertEqual(Artifact(1).visibility, 'public') self.assertEqual(Artifact(2).visibility, 'public') self.assertEqual(Artifact(4).visibility, 'public') a.visibility = 'private' _propagate_visibility(a) self.assertEqual(Artifact(1).visibility, 'private') self.assertEqual(Artifact(2).visibility, 'private') self.assertEqual(Artifact(4).visibility, 'private') a = Artifact(2) a.visibility = 'public' _propagate_visibility(a) self.assertEqual(Artifact(1).visibility, 'private') self.assertEqual(Artifact(2).visibility, 'private') self.assertEqual(Artifact(4).visibility, 'private')
def make_public(self, study, user, callback): """Makes the current study public Parameters ---------- study : Study The current study object user : User The current user object callback : function The callback function to call with the results once the processing is done """ pd_id = int(self.get_argument('pd_id')) pd = Artifact(pd_id) pd.visibility = 'public' _propagate_visibility(pd) msg = "Processed data set to public" msg_level = "success" callback((msg, msg_level, "processed_data_tab", pd_id, None))
def make_sandbox(self, study, user, callback): """Reverts the current study to the 'sandbox' status Parameters ---------- study : Study The current study object user : User The current user object callback : function The callback function to call with the results once the processing is done """ pd_id = int(self.get_argument('pd_id')) pd = Artifact(pd_id) pd.visibility = 'sandbox' _propagate_visibility(pd) msg = "Processed data reverted to sandbox" msg_level = "success" callback((msg, msg_level, "processed_data_tab", pd_id, None))
def request_approval(self, study, user, callback): """Changes the status of the current study to "awaiting_approval" Parameters ---------- study : Study The current study object user : User The current user object callback : function The callback function to call with the results once the processing is done """ pd_id = int(self.get_argument('pd_id')) pd = Artifact(pd_id) pd.visibility = 'awaiting_approval' _propagate_visibility(pd) msg = "Processed data sent to admin for approval" msg_level = "success" callback((msg, msg_level, "processed_data_tab", pd_id, None))
def make_sandbox(self, study, user, callback): """Reverts the current study to the 'sandbox' status Parameters ---------- study : Study The current study object user : User The current user object callback : function The callback function to call with the results once the processing is done """ pd_id = int(self.get_argument('pd_id')) pd = Artifact(pd_id) pd.visibility = 'sandbox' _propagate_visibility(pd) msg = "Processed data reverted to sandbox" msg_level = "success" callback((msg, msg_level, "processed_data_tab", pd_id, None))
def request_approval(self, study, user, callback): """Changes the status of the current study to "awaiting_approval" Parameters ---------- study : Study The current study object user : User The current user object callback : function The callback function to call with the results once the processing is done """ pd_id = int(self.get_argument('pd_id')) pd = Artifact(pd_id) pd.visibility = 'awaiting_approval' _propagate_visibility(pd) msg = "Processed data sent to admin for approval" msg_level = "success" callback((msg, msg_level, "processed_data_tab", pd_id, None))
def make_public(self, study, user, callback): """Makes the current study public Parameters ---------- study : Study The current study object user : User The current user object callback : function The callback function to call with the results once the processing is done """ pd_id = int(self.get_argument('pd_id')) pd = Artifact(pd_id) pd.visibility = 'public' _propagate_visibility(pd) msg = "Processed data set to public" msg_level = "success" callback((msg, msg_level, "processed_data_tab", pd_id, None))
def test_artifact_summary_get_request(self): # Artifact w/o summary obs = artifact_summary_get_request('*****@*****.**', 1) exp_p_jobs = [[ '063e553b-327c-4818-ab4a-adfe58e49860', 'Split libraries FASTQ', 'queued', None, None ], [ 'bcc7ebcd-39c1-43e4-af2d-822e3589f14d', 'Split libraries', 'running', 'demultiplexing', None ]] exp_files = [ (1L, '1_s_G1_L001_sequences.fastq.gz (raw forward seqs)'), (2L, '1_s_G1_L001_sequences_barcodes.fastq.gz (raw barcodes)') ] exp = { 'status': 'success', 'message': '', 'name': 'Raw data 1', 'summary': None, 'job': None, 'processing_jobs': exp_p_jobs, 'errored_jobs': [], 'visibility': 'private', 'buttons': '<button onclick="if (confirm(\'Are you sure you ' 'want to make public artifact id: 1?\')) { ' 'set_artifact_visibility(\'public\', 1) }" ' 'class="btn btn-primary btn-sm">Make public</button>' ' <button onclick="if (confirm(\'Are you sure you ' 'want to revert to sandbox artifact id: 1?\')) ' '{ set_artifact_visibility(\'sandbox\', 1) }" ' 'class="btn btn-primary btn-sm">Revert to ' 'sandbox</button>', 'files': exp_files, 'editable': True, 'prep_id': 1, 'study_id': 1 } self.assertEqual(obs, exp) # Artifact with summary being generated job = ProcessingJob.create( User('*****@*****.**'), Parameters.load(Command(7), values_dict={'input_data': 1})) job._set_status('queued') obs = artifact_summary_get_request('*****@*****.**', 1) exp = { 'status': 'success', 'message': '', 'name': 'Raw data 1', 'summary': None, 'job': [job.id, 'queued', None], 'processing_jobs': exp_p_jobs, 'errored_jobs': [], 'visibility': 'private', 'buttons': '<button onclick="if (confirm(\'Are you sure you ' 'want to make public artifact id: 1?\')) { ' 'set_artifact_visibility(\'public\', 1) }" ' 'class="btn btn-primary btn-sm">Make public</button>' ' <button onclick="if (confirm(\'Are you sure you ' 'want to revert to sandbox artifact id: 1?\')) { ' 'set_artifact_visibility(\'sandbox\', 1) }" ' 'class="btn btn-primary btn-sm">Revert to ' 'sandbox</button>', 'files': exp_files, 'editable': True, 'prep_id': 1, 'study_id': 1 } self.assertEqual(obs, exp) # Artifact with summary fd, fp = mkstemp(suffix=".html") close(fd) with open(fp, 'w') as f: f.write('<b>HTML TEST - not important</b>\n') a = Artifact(1) a.html_summary_fp = fp self._files_to_remove.extend([fp, a.html_summary_fp[1]]) exp_files.append( (a.html_summary_fp[0], '%s (html summary)' % basename(a.html_summary_fp[1]))) obs = artifact_summary_get_request('*****@*****.**', 1) exp = { 'status': 'success', 'message': '', 'name': 'Raw data 1', 'summary': '<b>HTML TEST - not important</b>\n', 'job': None, 'processing_jobs': exp_p_jobs, 'errored_jobs': [], 'visibility': 'private', 'buttons': '<button onclick="if (confirm(\'Are you sure you ' 'want to make public artifact id: 1?\')) { ' 'set_artifact_visibility(\'public\', 1) }" ' 'class="btn btn-primary btn-sm">Make public</button>' ' <button onclick="if (confirm(\'Are you sure you ' 'want to revert to sandbox artifact id: 1?\')) { ' 'set_artifact_visibility(\'sandbox\', 1) }" ' 'class="btn btn-primary btn-sm">Revert to ' 'sandbox</button>', 'files': exp_files, 'editable': True, 'prep_id': 1, 'study_id': 1 } self.assertEqual(obs, exp) # No access obs = artifact_summary_get_request('*****@*****.**', 1) exp = { 'status': 'error', 'message': 'User does not have access to study' } self.assertEqual(obs, exp) # A non-owner/share user can't see the files a.visibility = 'public' obs = artifact_summary_get_request('*****@*****.**', 1) exp = { 'status': 'success', 'message': '', 'name': 'Raw data 1', 'summary': '<b>HTML TEST - not important</b>\n', 'job': None, 'processing_jobs': exp_p_jobs, 'errored_jobs': [], 'visibility': 'public', 'buttons': '', 'files': [], 'editable': False, 'prep_id': 1, 'study_id': 1 } self.assertEqual(obs, exp)
def test_artifact_summary_get_request(self): user = User('*****@*****.**') # Artifact w/o summary obs = artifact_summary_get_request(user, 1) exp_p_jobs = [[ '063e553b-327c-4818-ab4a-adfe58e49860', 'Split libraries FASTQ', 'queued', None, None ], [ 'bcc7ebcd-39c1-43e4-af2d-822e3589f14d', 'Split libraries', 'running', 'demultiplexing', None ]] exp_files = [ (1L, '1_s_G1_L001_sequences.fastq.gz (raw forward seqs)'), (2L, '1_s_G1_L001_sequences_barcodes.fastq.gz (raw barcodes)') ] exp = { 'name': 'Raw data 1', 'artifact_id': 1, 'visibility': 'private', 'editable': True, 'buttons': ('<button onclick="if (confirm(\'Are you sure you ' 'want to make public artifact id: 1?\')) { ' 'set_artifact_visibility(\'public\', 1) }" ' 'class="btn btn-primary btn-sm">Make public' '</button> <button onclick="if (confirm(\'Are you ' 'sure you want to revert to sandbox artifact id: ' '1?\')) { set_artifact_visibility(\'sandbox\', 1) ' '}" class="btn btn-primary btn-sm">Revert to ' 'sandbox</button>'), 'processing_parameters': {}, 'files': exp_files, 'summary': None, 'job': None, 'processing_jobs': exp_p_jobs, 'errored_jobs': [] } self.assertEqual(obs, exp) # Artifact with summary being generated job = ProcessingJob.create( User('*****@*****.**'), Parameters.load(Command(7), values_dict={'input_data': 1})) job._set_status('queued') obs = artifact_summary_get_request(user, 1) exp = { 'name': 'Raw data 1', 'artifact_id': 1, 'visibility': 'private', 'editable': True, 'buttons': ('<button onclick="if (confirm(\'Are you sure you ' 'want to make public artifact id: 1?\')) { ' 'set_artifact_visibility(\'public\', 1) }" ' 'class="btn btn-primary btn-sm">Make public' '</button> <button onclick="if (confirm(\'Are you ' 'sure you want to revert to sandbox artifact id: ' '1?\')) { set_artifact_visibility(\'sandbox\', 1) ' '}" class="btn btn-primary btn-sm">Revert to ' 'sandbox</button>'), 'processing_parameters': {}, 'files': exp_files, 'summary': None, 'job': [job.id, 'queued', None], 'processing_jobs': exp_p_jobs, 'errored_jobs': [] } self.assertEqual(obs, exp) # Artifact with summary fd, fp = mkstemp(suffix=".html") close(fd) with open(fp, 'w') as f: f.write('<b>HTML TEST - not important</b>\n') a = Artifact(1) a.set_html_summary(fp) self._files_to_remove.extend([fp, a.html_summary_fp[1]]) exp_files.append( (a.html_summary_fp[0], '%s (html summary)' % basename(a.html_summary_fp[1]))) exp_summary_path = relpath(a.html_summary_fp[1], qiita_config.base_data_dir) obs = artifact_summary_get_request(user, 1) exp = { 'name': 'Raw data 1', 'artifact_id': 1, 'visibility': 'private', 'editable': True, 'buttons': ('<button onclick="if (confirm(\'Are you sure you ' 'want to make public artifact id: 1?\')) { ' 'set_artifact_visibility(\'public\', 1) }" ' 'class="btn btn-primary btn-sm">Make public' '</button> <button onclick="if (confirm(\'Are you ' 'sure you want to revert to sandbox artifact id: ' '1?\')) { set_artifact_visibility(\'sandbox\', 1) ' '}" class="btn btn-primary btn-sm">Revert to ' 'sandbox</button>'), 'processing_parameters': {}, 'files': exp_files, 'summary': exp_summary_path, 'job': None, 'processing_jobs': exp_p_jobs, 'errored_jobs': [] } self.assertEqual(obs, exp) # No access demo_u = User('*****@*****.**') with self.assertRaises(QiitaHTTPError): obs = artifact_summary_get_request(demo_u, 1) # A non-owner/share user can't see the files a.visibility = 'public' obs = artifact_summary_get_request(demo_u, 1) exp = { 'name': 'Raw data 1', 'artifact_id': 1, 'visibility': 'public', 'editable': False, 'buttons': '', 'processing_parameters': {}, 'files': [], 'summary': exp_summary_path, 'job': None, 'processing_jobs': exp_p_jobs, 'errored_jobs': [] } self.assertEqual(obs, exp) # returnig to private a.visibility = 'private' # admin gets buttons obs = artifact_summary_get_request(User('*****@*****.**'), 2) exp_p_jobs = [[ 'd19f76ee-274e-4c1b-b3a2-a12d73507c55', 'Pick closed-reference OTUs', 'error', 'generating demux file', 'Error message' ]] exp_files = [(3L, '1_seqs.fna (preprocessed fasta)'), (4L, '1_seqs.qual (preprocessed fastq)'), (5L, '1_seqs.demux (preprocessed demux)')] exp = { 'name': 'Demultiplexed 1', 'artifact_id': 2, 'visibility': 'private', 'editable': True, 'buttons': ('<button onclick="if (confirm(\'Are you sure you ' 'want to make public artifact id: 2?\')) { ' 'set_artifact_visibility(\'public\', 2) }" ' 'class="btn btn-primary btn-sm">Make public' '</button> <button onclick="if (confirm(\'Are you ' 'sure you want to revert to sandbox artifact id: ' '2?\')) { set_artifact_visibility(\'sandbox\', 2) ' '}" class="btn btn-primary btn-sm">Revert to ' 'sandbox</button> <a class="btn btn-primary ' 'btn-sm" href="/ebi_submission/2"><span ' 'class="glyphicon glyphicon-export"></span> ' 'Submit to EBI</a> <a class="btn btn-primary ' 'btn-sm" href="/vamps/2"><span class="glyphicon ' 'glyphicon-export"></span> Submit to VAMPS</a>'), 'processing_parameters': { 'max_barcode_errors': 1.5, 'sequence_max_n': 0, 'max_bad_run_length': 3, 'phred_offset': u'auto', 'rev_comp': False, 'phred_quality_threshold': 3, 'input_data': 1, 'rev_comp_barcode': False, 'rev_comp_mapping_barcodes': False, 'min_per_read_length_fraction': 0.75, 'barcode_type': u'golay_12' }, 'files': exp_files, 'summary': None, 'job': None, 'processing_jobs': exp_p_jobs, 'errored_jobs': [] } self.assertEqual(obs, exp) # analysis artifact obs = artifact_summary_get_request(user, 8) exp = { 'name': 'noname', 'artifact_id': 8, 'visibility': 'sandbox', 'editable': True, 'buttons': '', 'processing_parameters': {}, 'files': [(27, 'biom_table.biom (biom)')], 'summary': None, 'job': None, 'processing_jobs': [], 'errored_jobs': [] } self.assertEqual(obs, exp)
def artifact_patch_request(user, artifact_id, req_op, req_path, req_value=None, req_from=None): """Modifies an attribute of the artifact Parameters ---------- user : qiita_db.user.User The user performing the patch operation artifact_id : int Id of the artifact in which the patch operation is being performed req_op : str The operation to perform on the artifact req_path : str The prep information and attribute to patch req_value : str, optional The value that needs to be modified req_from : str, optional The original path of the element Raises ------ QiitaHTTPError If `req_op` != 'replace' If the path parameter is incorrect If missing req_value If the attribute to replace is not known """ if req_op == 'replace': req_path = [v for v in req_path.split('/') if v] if len(req_path) != 1: raise QiitaHTTPError(404, 'Incorrect path parameter') attribute = req_path[0] # Check if the user actually has access to the artifact artifact = Artifact(artifact_id) check_artifact_access(user, artifact) if not req_value: raise QiitaHTTPError(404, 'Missing value to replace') if attribute == 'name': artifact.name = req_value return elif attribute == 'visibility': if req_value not in get_visibilities(): raise QiitaHTTPError( 400, 'Unknown visibility value: %s' % req_value) # Set the approval to private if needs approval and admin if req_value == 'private': if not qiita_config.require_approval: artifact.visibility = 'private' # Set the approval to private if approval not required elif user.level == 'admin': artifact.visibility = 'private' # Trying to set approval without admin privileges else: raise QiitaHTTPError( 403, 'User does not have permissions ' 'to approve change') else: artifact.visibility = req_value else: # We don't understand the attribute so return an error raise QiitaHTTPError( 404, 'Attribute "%s" not found. Please, ' 'check the path parameter' % attribute) else: raise QiitaHTTPError( 400, 'Operation "%s" not supported. Current ' 'supported operations: replace' % req_op)
def test_artifact_summary_get_request(self): # Artifact w/o summary obs = artifact_summary_get_request('*****@*****.**', 1) exp_p_jobs = [[ '063e553b-327c-4818-ab4a-adfe58e49860', 'Split libraries FASTQ', 'queued', None, None ], [ 'bcc7ebcd-39c1-43e4-af2d-822e3589f14d', 'Split libraries', 'running', 'demultiplexing', None ]] exp_files = [ (1L, '1_s_G1_L001_sequences.fastq.gz (raw forward seqs)'), (2L, '1_s_G1_L001_sequences_barcodes.fastq.gz (raw barcodes)') ] exp = { 'status': 'success', 'message': '', 'name': 'Raw data 1', 'summary': None, 'job': None, 'processing_jobs': exp_p_jobs, 'errored_jobs': [], 'visibility': 'private', 'buttons': ('<button onclick="if (confirm(\'Are you sure you ' 'want to make public artifact id: 1?\')) { ' 'set_artifact_visibility(\'public\', 1) }" ' 'class="btn btn-primary btn-sm">Make public' '</button> <button onclick="if (confirm(\'Are you ' 'sure you want to revert to sandbox artifact id: ' '1?\')) { set_artifact_visibility(\'sandbox\', 1) ' '}" class="btn btn-primary btn-sm">Revert to ' 'sandbox</button>'), 'files': exp_files, 'editable': True, 'prep_id': 1, 'study_id': 1 } self.assertEqual(obs, exp) # Artifact with summary being generated job = ProcessingJob.create( User('*****@*****.**'), Parameters.load(Command(7), values_dict={'input_data': 1})) job._set_status('queued') obs = artifact_summary_get_request('*****@*****.**', 1) exp = { 'status': 'success', 'message': '', 'name': 'Raw data 1', 'summary': None, 'job': [job.id, 'queued', None], 'processing_jobs': exp_p_jobs, 'errored_jobs': [], 'visibility': 'private', 'buttons': ('<button onclick="if (confirm(\'Are you sure you ' 'want to make public artifact id: 1?\')) { ' 'set_artifact_visibility(\'public\', 1) }" ' 'class="btn btn-primary btn-sm">Make public' '</button> <button onclick="if (confirm(\'Are you ' 'sure you want to revert to sandbox artifact id: ' '1?\')) { set_artifact_visibility(\'sandbox\', 1) ' '}" class="btn btn-primary btn-sm">Revert to ' 'sandbox</button>'), 'files': exp_files, 'editable': True, 'prep_id': 1, 'study_id': 1 } self.assertEqual(obs, exp) # Artifact with summary fd, fp = mkstemp(suffix=".html") close(fd) with open(fp, 'w') as f: f.write('<b>HTML TEST - not important</b>\n') a = Artifact(1) a.html_summary_fp = fp self._files_to_remove.extend([fp, a.html_summary_fp[1]]) exp_files.append( (a.html_summary_fp[0], '%s (html summary)' % basename(a.html_summary_fp[1]))) obs = artifact_summary_get_request('*****@*****.**', 1) exp = { 'status': 'success', 'message': '', 'name': 'Raw data 1', 'summary': '<b>HTML TEST - not important</b>\n', 'job': None, 'processing_jobs': exp_p_jobs, 'errored_jobs': [], 'visibility': 'private', 'buttons': ('<button onclick="if (confirm(\'Are you sure you ' 'want to make public artifact id: 1?\')) { ' 'set_artifact_visibility(\'public\', 1) }" ' 'class="btn btn-primary btn-sm">Make public' '</button> <button onclick="if (confirm(\'Are you ' 'sure you want to revert to sandbox artifact id: ' '1?\')) { set_artifact_visibility(\'sandbox\', 1) ' '}" class="btn btn-primary btn-sm">Revert to ' 'sandbox</button>'), 'files': exp_files, 'editable': True, 'prep_id': 1, 'study_id': 1 } self.assertEqual(obs, exp) # No access obs = artifact_summary_get_request('*****@*****.**', 1) exp = { 'status': 'error', 'message': 'User does not have access to study' } self.assertEqual(obs, exp) # A non-owner/share user can't see the files a.visibility = 'public' obs = artifact_summary_get_request('*****@*****.**', 1) exp = { 'status': 'success', 'message': '', 'name': 'Raw data 1', 'summary': '<b>HTML TEST - not important</b>\n', 'job': None, 'processing_jobs': exp_p_jobs, 'errored_jobs': [], 'visibility': 'public', 'buttons': '', 'files': [], 'editable': False, 'prep_id': 1, 'study_id': 1 } self.assertEqual(obs, exp) # returnig to private a.visibility = 'sandbox' # admin gets buttons obs = artifact_summary_get_request('*****@*****.**', 2) exp_p_jobs = [[ 'd19f76ee-274e-4c1b-b3a2-a12d73507c55', 'Pick closed-reference OTUs', 'error', 'generating demux file', 'Error message' ]] exp_files = [(3L, '1_seqs.fna (preprocessed fasta)'), (4L, '1_seqs.qual (preprocessed fastq)'), (5L, '1_seqs.demux (preprocessed demux)')] exp = { 'status': 'success', 'files': exp_files, 'errored_jobs': [], 'editable': True, 'visibility': 'private', 'job': None, 'message': '', 'name': 'Demultiplexed 1', 'processing_jobs': exp_p_jobs, 'summary': None, 'buttons': ('<button onclick="if (confirm(\'Are you sure you ' 'want to make public artifact id: 2?\')) { ' 'set_artifact_visibility(\'public\', 2) }" ' 'class="btn btn-primary btn-sm">Make public' '</button> <button onclick="if (confirm(\'Are you ' 'sure you want to revert to sandbox artifact id: ' '2?\')) { set_artifact_visibility(\'sandbox\', 2) ' '}" class="btn btn-primary btn-sm">Revert to ' 'sandbox</button> <a class="btn btn-primary ' 'btn-sm" href="/vamps/2"><span class="glyphicon ' 'glyphicon-export"></span> Submit to VAMPS</a>'), 'study_id': 1, 'prep_id': 1 } self.assertEqual(obs, exp)
def test_artifact_summary_get_request(self): # Artifact w/o summary obs = artifact_summary_get_request('*****@*****.**', 1) exp_p_jobs = [ ['063e553b-327c-4818-ab4a-adfe58e49860', 'Split libraries FASTQ', 'queued', None, None], ['bcc7ebcd-39c1-43e4-af2d-822e3589f14d', 'Split libraries', 'running', 'demultiplexing', None]] exp_files = [ (1L, '1_s_G1_L001_sequences.fastq.gz (raw forward seqs)'), (2L, '1_s_G1_L001_sequences_barcodes.fastq.gz (raw barcodes)')] exp = {'status': 'success', 'message': '', 'name': 'Raw data 1', 'processing_parameters': {}, 'summary': None, 'job': None, 'processing_jobs': exp_p_jobs, 'errored_jobs': [], 'visibility': 'private', 'buttons': ('<button onclick="if (confirm(\'Are you sure you ' 'want to make public artifact id: 1?\')) { ' 'set_artifact_visibility(\'public\', 1) }" ' 'class="btn btn-primary btn-sm">Make public' '</button> <button onclick="if (confirm(\'Are you ' 'sure you want to revert to sandbox artifact id: ' '1?\')) { set_artifact_visibility(\'sandbox\', 1) ' '}" class="btn btn-primary btn-sm">Revert to ' 'sandbox</button>'), 'files': exp_files, 'editable': True, 'prep_id': 1, 'study_id': 1} self.assertEqual(obs, exp) # Artifact with summary being generated job = ProcessingJob.create( User('*****@*****.**'), Parameters.load(Command(7), values_dict={'input_data': 1}) ) job._set_status('queued') obs = artifact_summary_get_request('*****@*****.**', 1) exp = {'status': 'success', 'message': '', 'name': 'Raw data 1', 'processing_parameters': {}, 'summary': None, 'job': [job.id, 'queued', None], 'processing_jobs': exp_p_jobs, 'errored_jobs': [], 'visibility': 'private', 'buttons': ('<button onclick="if (confirm(\'Are you sure you ' 'want to make public artifact id: 1?\')) { ' 'set_artifact_visibility(\'public\', 1) }" ' 'class="btn btn-primary btn-sm">Make public' '</button> <button onclick="if (confirm(\'Are you ' 'sure you want to revert to sandbox artifact id: ' '1?\')) { set_artifact_visibility(\'sandbox\', 1) ' '}" class="btn btn-primary btn-sm">Revert to ' 'sandbox</button>'), 'files': exp_files, 'editable': True, 'prep_id': 1, 'study_id': 1} self.assertEqual(obs, exp) # Artifact with summary fd, fp = mkstemp(suffix=".html") close(fd) with open(fp, 'w') as f: f.write('<b>HTML TEST - not important</b>\n') a = Artifact(1) a.html_summary_fp = fp self._files_to_remove.extend([fp, a.html_summary_fp[1]]) exp_files.append( (a.html_summary_fp[0], '%s (html summary)' % basename(a.html_summary_fp[1]))) obs = artifact_summary_get_request('*****@*****.**', 1) exp = {'status': 'success', 'message': '', 'name': 'Raw data 1', 'processing_parameters': {}, 'summary': '<b>HTML TEST - not important</b>\n', 'job': None, 'processing_jobs': exp_p_jobs, 'errored_jobs': [], 'visibility': 'private', 'buttons': ('<button onclick="if (confirm(\'Are you sure you ' 'want to make public artifact id: 1?\')) { ' 'set_artifact_visibility(\'public\', 1) }" ' 'class="btn btn-primary btn-sm">Make public' '</button> <button onclick="if (confirm(\'Are you ' 'sure you want to revert to sandbox artifact id: ' '1?\')) { set_artifact_visibility(\'sandbox\', 1) ' '}" class="btn btn-primary btn-sm">Revert to ' 'sandbox</button>'), 'files': exp_files, 'editable': True, 'prep_id': 1, 'study_id': 1} self.assertEqual(obs, exp) # No access obs = artifact_summary_get_request('*****@*****.**', 1) exp = {'status': 'error', 'message': 'User does not have access to study'} self.assertEqual(obs, exp) # A non-owner/share user can't see the files a.visibility = 'public' obs = artifact_summary_get_request('*****@*****.**', 1) exp = {'status': 'success', 'message': '', 'name': 'Raw data 1', 'processing_parameters': {}, 'summary': '<b>HTML TEST - not important</b>\n', 'job': None, 'processing_jobs': exp_p_jobs, 'errored_jobs': [], 'visibility': 'public', 'buttons': '', 'files': [], 'editable': False, 'prep_id': 1, 'study_id': 1} self.assertEqual(obs, exp) # returnig to private a.visibility = 'sandbox' # admin gets buttons obs = artifact_summary_get_request('*****@*****.**', 2) exp_p_jobs = [ ['d19f76ee-274e-4c1b-b3a2-a12d73507c55', 'Pick closed-reference OTUs', 'error', 'generating demux file', 'Error message']] exp_files = [ (3L, '1_seqs.fna (preprocessed fasta)'), (4L, '1_seqs.qual (preprocessed fastq)'), (5L, '1_seqs.demux (preprocessed demux)')] exp = {'status': 'success', 'files': exp_files, 'errored_jobs': [], 'editable': True, 'visibility': 'private', 'job': None, 'message': '', 'name': 'Demultiplexed 1', 'processing_jobs': exp_p_jobs, 'processing_parameters': { 'max_barcode_errors': 1.5, 'sequence_max_n': 0, 'max_bad_run_length': 3, 'phred_offset': u'auto', 'rev_comp': False, 'phred_quality_threshold': 3, 'input_data': 1, 'rev_comp_barcode': False, 'rev_comp_mapping_barcodes': False, 'min_per_read_length_fraction': 0.75, 'barcode_type': u'golay_12'}, 'summary': None, 'buttons': ('<button onclick="if (confirm(\'Are you sure you ' 'want to make public artifact id: 2?\')) { ' 'set_artifact_visibility(\'public\', 2) }" ' 'class="btn btn-primary btn-sm">Make public' '</button> <button onclick="if (confirm(\'Are you ' 'sure you want to revert to sandbox artifact id: ' '2?\')) { set_artifact_visibility(\'sandbox\', 2) ' '}" class="btn btn-primary btn-sm">Revert to ' 'sandbox</button> <a class="btn btn-primary ' 'btn-sm" href="/vamps/2"><span class="glyphicon ' 'glyphicon-export"></span> Submit to VAMPS</a>'), 'study_id': 1, 'prep_id': 1} self.assertEqual(obs, exp)
def test_artifact_summary_get_request(self): user = User('*****@*****.**') main_buttons = ( '<button onclick="if (confirm(' "\'Are you sure you want to make " "public artifact id: 1?')) { set_artifact_visibility('public', 1) " '}" class="btn btn-primary btn-sm">Make public</button> <button ' 'onclick="if (confirm(' "'Are you sure you want to revert to " "sandbox artifact id: 1?')) { set_artifact_visibility('sandbox', 1" ') }" class="btn btn-primary btn-sm">Revert to sandbox</button> ') private_download_button = ( '<button class="btn btn-primary btn-sm" type="button" ' 'aria-expanded="false" aria-controls="privateDownloadLink" ' 'onclick="generate_private_download_link(%s)">Generate Download ' 'Link</button><div class="collapse" id="privateDownloadLink"><div ' 'class="card card-body" id="privateDownloadText">Generating ' 'Download Link...</div></div>') # Artifact w/o summary obs = artifact_summary_get_request(user, 1) exp_files = [ (1, '1_s_G1_L001_sequences.fastq.gz (raw forward seqs)', '2125826711', '58 Bytes'), (2, '1_s_G1_L001_sequences_barcodes.fastq.gz (raw barcodes)', '2125826711', '58 Bytes') ] exp = { 'name': 'Raw data 1', 'artifact_id': 1, 'artifact_type': 'FASTQ', 'artifact_timestamp': '2012-10-01 09:10', 'visibility': 'private', 'editable': True, 'buttons': main_buttons + private_download_button % 1, 'processing_info': {}, 'files': exp_files, 'is_from_analysis': False, 'summary': None, 'job': None, 'errored_summary_jobs': [] } self.assertEqual(obs, exp) # Artifact with summary being generated job = ProcessingJob.create( User('*****@*****.**'), Parameters.load(Command(7), values_dict={'input_data': 1})) job._set_status('queued') obs = artifact_summary_get_request(user, 1) exp = { 'name': 'Raw data 1', 'artifact_id': 1, 'artifact_type': 'FASTQ', 'artifact_timestamp': '2012-10-01 09:10', 'visibility': 'private', 'editable': True, 'buttons': main_buttons + private_download_button % 1, 'processing_info': {}, 'files': exp_files, 'is_from_analysis': False, 'summary': None, 'job': [job.id, 'queued', None], 'errored_summary_jobs': [] } self.assertEqual(obs, exp) # Artifact with summary fd, fp = mkstemp(suffix=".html") close(fd) with open(fp, 'w') as f: f.write('<b>HTML TEST - not important</b>\n') a = Artifact(1) a.set_html_summary(fp) self._files_to_remove.extend([fp, a.html_summary_fp[1]]) exp_files.append((a.html_summary_fp[0], '%s (html summary)' % basename(a.html_summary_fp[1]), '1642196267', '33 Bytes')) exp_summary_path = relpath(a.html_summary_fp[1], qiita_config.base_data_dir) obs = artifact_summary_get_request(user, 1) exp = { 'name': 'Raw data 1', 'artifact_id': 1, 'artifact_type': 'FASTQ', 'artifact_timestamp': '2012-10-01 09:10', 'visibility': 'private', 'editable': True, 'buttons': main_buttons + private_download_button % 1, 'processing_info': {}, 'files': exp_files, 'is_from_analysis': False, 'summary': exp_summary_path, 'job': None, 'errored_summary_jobs': [] } self.assertEqual(obs, exp) # No access demo_u = User('*****@*****.**') with self.assertRaises(QiitaHTTPError): obs = artifact_summary_get_request(demo_u, 1) # A non-owner/share user can't see the files a.visibility = 'public' obs = artifact_summary_get_request(demo_u, 1) exp = { 'name': 'Raw data 1', 'artifact_id': 1, 'artifact_type': 'FASTQ', 'artifact_timestamp': '2012-10-01 09:10', 'visibility': 'public', 'editable': False, 'buttons': '', 'processing_info': {}, 'files': [], 'is_from_analysis': False, 'summary': exp_summary_path, 'job': None, 'errored_summary_jobs': [] } self.assertEqual(obs, exp) # testing sandbox a.visibility = 'sandbox' obs = artifact_summary_get_request(user, 1) exp = { 'name': 'Raw data 1', 'artifact_id': 1, 'artifact_type': 'FASTQ', 'artifact_timestamp': '2012-10-01 09:10', 'visibility': 'sandbox', 'editable': True, 'buttons': private_download_button % 1, 'processing_info': {}, 'files': exp_files, 'is_from_analysis': False, 'summary': exp_summary_path, 'job': None, 'errored_summary_jobs': [] } self.assertEqual(obs, exp) # returnig to private a.visibility = 'private' # admin gets buttons obs = artifact_summary_get_request(User('*****@*****.**'), 2) exp_files = [(3, '1_seqs.fna (preprocessed fasta)', '', '0 Bytes'), (4, '1_seqs.qual (preprocessed fastq)', '', '0 Bytes'), (5, '1_seqs.demux (preprocessed demux)', '', '0 Bytes')] exp = { 'name': 'Demultiplexed 1', 'artifact_id': 2, 'artifact_type': 'Demultiplexed', 'artifact_timestamp': '2012-10-01 10:10', 'visibility': 'private', 'editable': True, 'buttons': ('<button onclick="if (confirm(\'Are you sure you ' 'want to make public artifact id: 2?\')) { ' 'set_artifact_visibility(\'public\', 2) }" ' 'class="btn btn-primary btn-sm">Make public' '</button> <button onclick="if (confirm(\'Are you ' 'sure you want to revert to sandbox artifact id: ' '2?\')) { set_artifact_visibility(\'sandbox\', 2) ' '}" class="btn btn-primary btn-sm">Revert to ' 'sandbox</button> <a class="btn btn-primary ' 'btn-sm" href="/ebi_submission/2"><span ' 'class="glyphicon glyphicon-export"></span> ' 'Submit to EBI</a> <a class="btn btn-primary ' 'btn-sm" href="/vamps/2"><span class="glyphicon ' 'glyphicon-export"></span> Submit to VAMPS</a> ' + private_download_button % 2), 'processing_info': { 'command_active': True, 'software_deprecated': False, 'command': 'Split libraries FASTQ', 'processing_parameters': { 'max_barcode_errors': '1.5', 'sequence_max_n': '0', 'max_bad_run_length': '3', 'phred_offset': 'auto', 'rev_comp': 'False', 'phred_quality_threshold': '3', 'input_data': '1', 'rev_comp_barcode': 'False', 'rev_comp_mapping_barcodes': 'False', 'min_per_read_length_fraction': '0.75', 'barcode_type': 'golay_12' }, 'software_version': '1.9.1', 'software': 'QIIME' }, 'files': exp_files, 'is_from_analysis': False, 'summary': None, 'job': None, 'errored_summary_jobs': [] } self.assertEqual(obs, exp) # analysis artifact obs = artifact_summary_get_request(user, 8) exp = { 'name': 'noname', 'artifact_id': 8, 'artifact_type': 'BIOM', # this value changes on build so copy from obs 'artifact_timestamp': obs['artifact_timestamp'], 'visibility': 'sandbox', 'editable': True, 'buttons': private_download_button % 8, 'processing_info': {}, 'files': [(22, 'biom_table.biom (biom)', '1756512010', '1.1 MB')], 'is_from_analysis': True, 'summary': None, 'job': None, 'errored_summary_jobs': [] } self.assertEqual(obs, exp)
def artifact_patch_request(user, artifact_id, req_op, req_path, req_value=None, req_from=None): """Modifies an attribute of the artifact Parameters ---------- user : qiita_db.user.User The user performing the patch operation artifact_id : int Id of the artifact in which the patch operation is being performed req_op : str The operation to perform on the artifact req_path : str The prep information and attribute to patch req_value : str, optional The value that needs to be modified req_from : str, optional The original path of the element Raises ------ QiitaHTTPError If `req_op` != 'replace' If the path parameter is incorrect If missing req_value If the attribute to replace is not known """ if req_op == 'replace': req_path = [v for v in req_path.split('/') if v] if len(req_path) != 1: raise QiitaHTTPError(404, 'Incorrect path parameter') attribute = req_path[0] # Check if the user actually has access to the artifact artifact = Artifact(artifact_id) check_artifact_access(user, artifact) if not req_value: raise QiitaHTTPError(404, 'Missing value to replace') if attribute == 'name': artifact.name = req_value return elif attribute == 'visibility': if req_value not in get_visibilities(): raise QiitaHTTPError( 400, 'Unknown visibility value: %s' % req_value) if (req_value == 'private' and qiita_config.require_approval and not user.level == 'admin'): raise QiitaHTTPError( 403, 'User does not have permissions ' 'to approve change') try: artifact.visibility = req_value except Exception as e: raise QiitaHTTPError(403, str(e).replace('\n', '<br/>')) sid = artifact.study.id if artifact.visibility == 'awaiting_approval': email_to = '*****@*****.**' subject = ('QIITA: Artifact %s awaiting_approval. Study %d, ' 'Prep %d' % (artifact_id, sid, artifact.prep_templates[0].id)) message = ('%s requested approval. <a ' 'href="https://qiita.ucsd.edu/study/description/' '%d">Study %d</a>.' % (user.email, sid, sid)) try: send_email(email_to, subject, message) except Exception: msg = ("Couldn't send email to admins, please email us " "directly to <a href='mailto:{0}'>{0}</a>.".format( email_to)) raise QiitaHTTPError(400, msg) else: msg = '%s changed artifact %s (study %d) to %s' % ( user.email, artifact_id, sid, req_value) LogEntry.create('Warning', msg) else: # We don't understand the attribute so return an error raise QiitaHTTPError( 404, 'Attribute "%s" not found. Please, ' 'check the path parameter' % attribute) else: raise QiitaHTTPError( 400, 'Operation "%s" not supported. Current ' 'supported operations: replace' % req_op)
def test_artifact_summary_get_request(self): user = User('*****@*****.**') # Artifact w/o summary obs = artifact_summary_get_request(user, 1) exp_files = [ (1L, '1_s_G1_L001_sequences.fastq.gz (raw forward seqs)'), (2L, '1_s_G1_L001_sequences_barcodes.fastq.gz (raw barcodes)')] exp = {'name': 'Raw data 1', 'artifact_id': 1, 'artifact_type': 'FASTQ', 'artifact_timestamp': '2012-10-01 09:10', 'visibility': 'private', 'editable': True, 'buttons': ('<button onclick="if (confirm(\'Are you sure you ' 'want to make public artifact id: 1?\')) { ' 'set_artifact_visibility(\'public\', 1) }" ' 'class="btn btn-primary btn-sm">Make public' '</button> <button onclick="if (confirm(\'Are you ' 'sure you want to revert to sandbox artifact id: ' '1?\')) { set_artifact_visibility(\'sandbox\', 1) ' '}" class="btn btn-primary btn-sm">Revert to ' 'sandbox</button>'), 'processing_info': {}, 'files': exp_files, 'is_from_analysis': False, 'summary': None, 'job': None, 'errored_summary_jobs': []} self.assertEqual(obs, exp) # Artifact with summary being generated job = ProcessingJob.create( User('*****@*****.**'), Parameters.load(Command(7), values_dict={'input_data': 1}) ) job._set_status('queued') obs = artifact_summary_get_request(user, 1) exp = {'name': 'Raw data 1', 'artifact_id': 1, 'artifact_type': 'FASTQ', 'artifact_timestamp': '2012-10-01 09:10', 'visibility': 'private', 'editable': True, 'buttons': ('<button onclick="if (confirm(\'Are you sure you ' 'want to make public artifact id: 1?\')) { ' 'set_artifact_visibility(\'public\', 1) }" ' 'class="btn btn-primary btn-sm">Make public' '</button> <button onclick="if (confirm(\'Are you ' 'sure you want to revert to sandbox artifact id: ' '1?\')) { set_artifact_visibility(\'sandbox\', 1) ' '}" class="btn btn-primary btn-sm">Revert to ' 'sandbox</button>'), 'processing_info': {}, 'files': exp_files, 'is_from_analysis': False, 'summary': None, 'job': [job.id, 'queued', None], 'errored_summary_jobs': []} self.assertEqual(obs, exp) # Artifact with summary fd, fp = mkstemp(suffix=".html") close(fd) with open(fp, 'w') as f: f.write('<b>HTML TEST - not important</b>\n') a = Artifact(1) a.set_html_summary(fp) self._files_to_remove.extend([fp, a.html_summary_fp[1]]) exp_files.append( (a.html_summary_fp[0], '%s (html summary)' % basename(a.html_summary_fp[1]))) exp_summary_path = relpath( a.html_summary_fp[1], qiita_config.base_data_dir) obs = artifact_summary_get_request(user, 1) exp = {'name': 'Raw data 1', 'artifact_id': 1, 'artifact_type': 'FASTQ', 'artifact_timestamp': '2012-10-01 09:10', 'visibility': 'private', 'editable': True, 'buttons': ('<button onclick="if (confirm(\'Are you sure you ' 'want to make public artifact id: 1?\')) { ' 'set_artifact_visibility(\'public\', 1) }" ' 'class="btn btn-primary btn-sm">Make public' '</button> <button onclick="if (confirm(\'Are you ' 'sure you want to revert to sandbox artifact id: ' '1?\')) { set_artifact_visibility(\'sandbox\', 1) ' '}" class="btn btn-primary btn-sm">Revert to ' 'sandbox</button>'), 'processing_info': {}, 'files': exp_files, 'is_from_analysis': False, 'summary': exp_summary_path, 'job': None, 'errored_summary_jobs': []} self.assertEqual(obs, exp) # No access demo_u = User('*****@*****.**') with self.assertRaises(QiitaHTTPError): obs = artifact_summary_get_request(demo_u, 1) # A non-owner/share user can't see the files a.visibility = 'public' obs = artifact_summary_get_request(demo_u, 1) exp = {'name': 'Raw data 1', 'artifact_id': 1, 'artifact_type': 'FASTQ', 'artifact_timestamp': '2012-10-01 09:10', 'visibility': 'public', 'editable': False, 'buttons': '', 'processing_info': {}, 'files': [], 'is_from_analysis': False, 'summary': exp_summary_path, 'job': None, 'errored_summary_jobs': []} self.assertEqual(obs, exp) # returnig to private a.visibility = 'private' # admin gets buttons obs = artifact_summary_get_request(User('*****@*****.**'), 2) exp_files = [ (3L, '1_seqs.fna (preprocessed fasta)'), (4L, '1_seqs.qual (preprocessed fastq)'), (5L, '1_seqs.demux (preprocessed demux)')] exp = {'name': 'Demultiplexed 1', 'artifact_id': 2, 'artifact_type': 'Demultiplexed', 'artifact_timestamp': '2012-10-01 10:10', 'visibility': 'private', 'editable': True, 'buttons': ('<button onclick="if (confirm(\'Are you sure you ' 'want to make public artifact id: 2?\')) { ' 'set_artifact_visibility(\'public\', 2) }" ' 'class="btn btn-primary btn-sm">Make public' '</button> <button onclick="if (confirm(\'Are you ' 'sure you want to revert to sandbox artifact id: ' '2?\')) { set_artifact_visibility(\'sandbox\', 2) ' '}" class="btn btn-primary btn-sm">Revert to ' 'sandbox</button> <a class="btn btn-primary ' 'btn-sm" href="/ebi_submission/2"><span ' 'class="glyphicon glyphicon-export"></span> ' 'Submit to EBI</a> <a class="btn btn-primary ' 'btn-sm" href="/vamps/2"><span class="glyphicon ' 'glyphicon-export"></span> Submit to VAMPS</a>'), 'processing_info': { 'command': 'Split libraries FASTQ', 'software': 'QIIME', 'software_version': '1.9.1', 'processing_parameters': { 'max_barcode_errors': '1.5', 'sequence_max_n': '0', 'max_bad_run_length': '3', 'phred_offset': u'auto', 'rev_comp': 'False', 'phred_quality_threshold': '3', 'input_data': '1', 'rev_comp_barcode': 'False', 'rev_comp_mapping_barcodes': 'False', 'min_per_read_length_fraction': '0.75', 'barcode_type': u'golay_12'}}, 'files': exp_files, 'is_from_analysis': False, 'summary': None, 'job': None, 'errored_summary_jobs': []} self.assertEqual(obs, exp) # analysis artifact obs = artifact_summary_get_request(user, 8) exp = {'name': 'noname', 'artifact_id': 8, 'artifact_type': 'BIOM', # this value changes on build so copy from obs 'artifact_timestamp': obs['artifact_timestamp'], 'visibility': 'sandbox', 'editable': True, 'buttons': '', 'processing_info': {}, 'files': [(27, 'biom_table.biom (biom)')], 'is_from_analysis': True, 'summary': None, 'job': None, 'errored_summary_jobs': []} self.assertEqual(obs, exp)
def artifact_patch_request(user, artifact_id, req_op, req_path, req_value=None, req_from=None): """Modifies an attribute of the artifact Parameters ---------- user : qiita_db.user.User The user performing the patch operation artifact_id : int Id of the artifact in which the patch operation is being performed req_op : str The operation to perform on the artifact req_path : str The prep information and attribute to patch req_value : str, optional The value that needs to be modified req_from : str, optional The original path of the element Raises ------ QiitaHTTPError If `req_op` != 'replace' If the path parameter is incorrect If missing req_value If the attribute to replace is not known """ if req_op == 'replace': req_path = [v for v in req_path.split('/') if v] if len(req_path) != 1: raise QiitaHTTPError(404, 'Incorrect path parameter') attribute = req_path[0] # Check if the user actually has access to the artifact artifact = Artifact(artifact_id) check_artifact_access(user, artifact) if not req_value: raise QiitaHTTPError(404, 'Missing value to replace') if attribute == 'name': artifact.name = req_value return elif attribute == 'visibility': if req_value not in get_visibilities(): raise QiitaHTTPError(400, 'Unknown visibility value: %s' % req_value) if (req_value == 'private' and qiita_config.require_approval and not user.level == 'admin'): raise QiitaHTTPError(403, 'User does not have permissions ' 'to approve change') try: artifact.visibility = req_value except Exception as e: raise QiitaHTTPError(403, str(e).replace('\n', '<br/>')) if artifact.visibility == 'awaiting_approval': email_to = '*****@*****.**' sid = artifact.study.id subject = ('QIITA: Artifact %s awaiting_approval. Study %d, ' 'Prep %d' % (artifact_id, sid, artifact.prep_templates[0].id)) message = ('%s requested approval. <a ' 'href="https://qiita.ucsd.edu/study/description/' '%d">Study %d</a>.' % (user.email, sid, sid)) try: send_email(email_to, subject, message) except Exception: msg = ("Couldn't send email to admins, please email us " "directly to <a href='mailto:{0}'>{0}</a>.".format( email_to)) raise QiitaHTTPError(400, msg) else: # We don't understand the attribute so return an error raise QiitaHTTPError(404, 'Attribute "%s" not found. Please, ' 'check the path parameter' % attribute) else: raise QiitaHTTPError(400, 'Operation "%s" not supported. Current ' 'supported operations: replace' % req_op)
def test_artifact_summary_get_request(self): # Artifact w/o summary obs = artifact_summary_get_request('*****@*****.**', 1) exp_p_jobs = [ ['063e553b-327c-4818-ab4a-adfe58e49860', 'Split libraries FASTQ', 'queued', None, None], ['bcc7ebcd-39c1-43e4-af2d-822e3589f14d', 'Split libraries', 'running', 'demultiplexing', None]] exp_files = [ (1L, '1_s_G1_L001_sequences.fastq.gz (raw forward seqs)'), (2L, '1_s_G1_L001_sequences_barcodes.fastq.gz (raw barcodes)')] exp = {'status': 'success', 'message': '', 'name': 'Raw data 1', 'summary': None, 'job': None, 'processing_jobs': exp_p_jobs, 'errored_jobs': [], 'visibility': 'private', 'buttons': '<button onclick="if (confirm(\'Are you sure you ' 'want to make public artifact id: 1?\')) { ' 'set_artifact_visibility(\'public\', 1) }" ' 'class="btn btn-primary btn-sm">Make public</button>' ' <button onclick="if (confirm(\'Are you sure you ' 'want to revert to sandbox artifact id: 1?\')) ' '{ set_artifact_visibility(\'sandbox\', 1) }" ' 'class="btn btn-primary btn-sm">Revert to ' 'sandbox</button>', 'files': exp_files, 'editable': True} self.assertEqual(obs, exp) # Artifact with summary being generated job = ProcessingJob.create( User('*****@*****.**'), Parameters.load(Command(7), values_dict={'input_data': 1}) ) job._set_status('queued') obs = artifact_summary_get_request('*****@*****.**', 1) exp = {'status': 'success', 'message': '', 'name': 'Raw data 1', 'summary': None, 'job': [job.id, 'queued', None], 'processing_jobs': exp_p_jobs, 'errored_jobs': [], 'visibility': 'private', 'buttons': '<button onclick="if (confirm(\'Are you sure you ' 'want to make public artifact id: 1?\')) { ' 'set_artifact_visibility(\'public\', 1) }" ' 'class="btn btn-primary btn-sm">Make public</button>' ' <button onclick="if (confirm(\'Are you sure you ' 'want to revert to sandbox artifact id: 1?\')) { ' 'set_artifact_visibility(\'sandbox\', 1) }" ' 'class="btn btn-primary btn-sm">Revert to ' 'sandbox</button>', 'files': exp_files, 'editable': True} self.assertEqual(obs, exp) # Artifact with summary fd, fp = mkstemp(suffix=".html") close(fd) with open(fp, 'w') as f: f.write('<b>HTML TEST - not important</b>\n') a = Artifact(1) a.html_summary_fp = fp self._files_to_remove.extend([fp, a.html_summary_fp[1]]) exp_files.append( (a.html_summary_fp[0], '%s (html summary)' % basename(a.html_summary_fp[1]))) obs = artifact_summary_get_request('*****@*****.**', 1) exp = {'status': 'success', 'message': '', 'name': 'Raw data 1', 'summary': '<b>HTML TEST - not important</b>\n', 'job': None, 'processing_jobs': exp_p_jobs, 'errored_jobs': [], 'visibility': 'private', 'buttons': '<button onclick="if (confirm(\'Are you sure you ' 'want to make public artifact id: 1?\')) { ' 'set_artifact_visibility(\'public\', 1) }" ' 'class="btn btn-primary btn-sm">Make public</button>' ' <button onclick="if (confirm(\'Are you sure you ' 'want to revert to sandbox artifact id: 1?\')) { ' 'set_artifact_visibility(\'sandbox\', 1) }" ' 'class="btn btn-primary btn-sm">Revert to ' 'sandbox</button>', 'files': exp_files, 'editable': True} self.assertEqual(obs, exp) # No access obs = artifact_summary_get_request('*****@*****.**', 1) exp = {'status': 'error', 'message': 'User does not have access to study'} self.assertEqual(obs, exp) # A non-owner/share user can't see the files a.visibility = 'public' obs = artifact_summary_get_request('*****@*****.**', 1) exp = {'status': 'success', 'message': '', 'name': 'Raw data 1', 'summary': '<b>HTML TEST - not important</b>\n', 'job': None, 'processing_jobs': exp_p_jobs, 'errored_jobs': [], 'visibility': 'public', 'buttons': '', 'files': [], 'editable': False} self.assertEqual(obs, exp)
def artifact_patch_request(user, artifact_id, req_op, req_path, req_value=None, req_from=None): """Modifies an attribute of the artifact Parameters ---------- user : qiita_db.user.User The user performing the patch operation artifact_id : int Id of the artifact in which the patch operation is being performed req_op : str The operation to perform on the artifact req_path : str The prep information and attribute to patch req_value : str, optional The value that needs to be modified req_from : str, optional The original path of the element Raises ------ QiitaHTTPError If `req_op` != 'replace' If the path parameter is incorrect If missing req_value If the attribute to replace is not known """ if req_op == 'replace': req_path = [v for v in req_path.split('/') if v] if len(req_path) != 1: raise QiitaHTTPError(404, 'Incorrect path parameter') attribute = req_path[0] # Check if the user actually has access to the artifact artifact = Artifact(artifact_id) check_artifact_access(user, artifact) if not req_value: raise QiitaHTTPError(404, 'Missing value to replace') if attribute == 'name': artifact.name = req_value return elif attribute == 'visibility': if req_value not in get_visibilities(): raise QiitaHTTPError(400, 'Unknown visibility value: %s' % req_value) # Set the approval to private if needs approval and admin if req_value == 'private': if not qiita_config.require_approval: artifact.visibility = 'private' # Set the approval to private if approval not required elif user.level == 'admin': artifact.visibility = 'private' # Trying to set approval without admin privileges else: raise QiitaHTTPError(403, 'User does not have permissions ' 'to approve change') else: artifact.visibility = req_value else: # We don't understand the attribute so return an error raise QiitaHTTPError(404, 'Attribute "%s" not found. Please, ' 'check the path parameter' % attribute) else: raise QiitaHTTPError(400, 'Operation "%s" not supported. Current ' 'supported operations: replace' % req_op)