--- a +++ b/qiita_pet/handlers/rest/study.py @@ -0,0 +1,155 @@ +# ----------------------------------------------------------------------------- +# Copyright (c) 2014--, The Qiita Development Team. +# +# Distributed under the terms of the BSD 3-clause License. +# +# The full license is in the file LICENSE, distributed with this software. +# ----------------------------------------------------------------------------- +import warnings + +from tornado.escape import json_decode + +from qiita_db.handlers.oauth2 import authenticate_oauth +from qiita_db.study import StudyPerson, Study +from qiita_db.user import User +from .rest_handler import RESTHandler +from qiita_db.metadata_template.constants import SAMPLE_TEMPLATE_COLUMNS + + +class StudyHandler(RESTHandler): + + @authenticate_oauth + def get(self, study_id): + study = self.safe_get_study(study_id) + if study is None: + return + + info = study.info + pi = info['principal_investigator'] + lp = info['lab_person'] + self.write({'title': study.title, + 'contacts': {'principal_investigator': [ + pi.name, + pi.affiliation, + pi.email], + 'lab_person': [ + lp.name, + lp.affiliation, + lp.email]}, + 'study_abstract': info['study_abstract'], + 'study_description': info['study_description'], + 'study_alias': info['study_alias']}) + self.finish() + + +class StudyCreatorHandler(RESTHandler): + + @authenticate_oauth + def post(self): + try: + payload = json_decode(self.request.body) + except ValueError: + self.fail('Could not parse body', 400) + return + + required = {'title', 'study_abstract', 'study_description', + 'study_alias', 'owner', 'contacts'} + + if not required.issubset(payload): + self.fail('Not all required arguments provided', 400) + return + + title = payload['title'] + study_abstract = payload['study_abstract'] + study_desc = payload['study_description'] + study_alias = payload['study_alias'] + notes = payload['notes'] + + owner = payload['owner'] + if not User.exists(owner): + self.fail('Unknown user', 403) + return + else: + owner = User(owner) + + contacts = payload['contacts'] + + if Study.exists(title): + self.fail('Study title already exists', 409) + return + + pi_name = contacts['principal_investigator'][0] + pi_aff = contacts['principal_investigator'][1] + if not StudyPerson.exists(pi_name, pi_aff): + self.fail('Unknown principal investigator', 403) + return + else: + pi = StudyPerson.from_name_and_affiliation(pi_name, pi_aff) + + lp_name = contacts['lab_person'][0] + lp_aff = contacts['lab_person'][1] + if not StudyPerson.exists(lp_name, lp_aff): + self.fail('Unknown lab person', 403) + return + else: + lp = StudyPerson.from_name_and_affiliation(lp_name, lp_aff) + + info = {'lab_person_id': lp, + 'principal_investigator_id': pi, + 'study_abstract': study_abstract, + 'study_description': study_desc, + 'study_alias': study_alias, + 'notes': notes, + # TODO: we believe it is accurate that mixs is false and + # metadata completion is false as these cannot be known + # at study creation here no matter what. + # we do not know what should be done with the timeseries. + 'mixs_compliant': False, + 'metadata_complete': False, + 'timeseries_type_id': 1} + study = Study.create(owner, title, info) + + self.set_status(201) + self.write({'id': study.id}) + self.finish() + + +class StudyStatusHandler(RESTHandler): + @authenticate_oauth + def get(self, study_id): + study = self.safe_get_study(study_id) + if study is None: + return + + public = study.status == 'public' + st = study.sample_template + sample_information = st is not None + if sample_information: + with warnings.catch_warnings(): + try: + st.validate(SAMPLE_TEMPLATE_COLUMNS) + except Warning: + sample_information_warnings = True + else: + sample_information_warnings = False + else: + sample_information_warnings = False + + preparations = [] + for prep in study.prep_templates(): + pid = prep.id + art = prep.artifact is not None + # TODO: unclear how to test for warnings on the preparations as + # it requires knowledge of the preparation type. It is possible + # to tease this out, but it replicates code present in + # PrepTemplate.create, see: + # https://github.com/biocore/qiita/issues/2096 + preparations.append({'id': pid, 'has_artifact': art}) + + self.write({'is_public': public, + 'has_sample_information': sample_information, + 'sample_information_has_warnings': + sample_information_warnings, + 'preparations': preparations}) + self.set_status(200) + self.finish()