def add_step(self, questionnaireName): if not self.has_step(questionnaireName): class_name = ExportService.camel_case_it(questionnaireName) cls = ExportService.get_class(class_name) q = cls() step = Step(questionnaireName, q.__question_type__, q.__label__) self.steps.append(step)
def get(self, name, participant_id): class_ref = ExportService.get_class(name) schema = ExportService.get_schema(name, many=True) questionnaires = db.session.query(class_ref)\ .filter(class_ref.participant_id == participant_id)\ .all() return schema.dump(questionnaires)
def put(self, name, id): """ Modifies an existing questionnaire record. Parameters: name (str): Snake-cased name of the questionnaire class (should also match the table name), found in app.model.questionnaires. E.g., clinical_diagnoses_questionnaire -> ClinicalDiagnosesQuestionnaire id (int): ID of the questionnaire record to retrieve Returns: The updated questionnaire record. """ name = ExportService.camel_case_it(name) class_ref = ExportService.get_class(name) instance = db.session.query(class_ref).filter( class_ref.id == id).first() schema = ExportService.get_schema(name, session=db.session) request_data = request.get_json() if "_links" in request_data: request_data.pop("_links") try: updated = schema.load(request_data, instance=instance) except Exception as errors: raise RestException(RestException.INVALID_OBJECT, details=errors) updated.last_updated = datetime.datetime.utcnow() db.session.add(updated) db.session.commit() return schema.dump(updated)
def get(self, name): """ Retrieves metadata about the given questionnaire name. Includes JSON Formly field definition. Used for data export to get meta without specifying flow and relationship. Returns: A dict object containing the metadata about the questionnaire. Example: { table: { question_type: "sensitive", label: "Clinical Diagnosis" }, fields: [ { name: "id", key: "id", display_order: 0 }, ... ] } """ name = ExportService.camel_case_it(name) class_ref = ExportService.get_class(name) questionnaire = class_ref() meta = {"table": {}} try: meta["table"]['question_type'] = questionnaire.__question_type__ meta["table"]["label"] = questionnaire.__label__ except: pass # If these fields don't exist, just keep going. meta["fields"] = [] # This will move fields referenced by the field groups into the group, but will otherwise add them # the base meta object if they are not contained within a group. for c in questionnaire.__table__.columns: if c.info: c.info['name'] = c.name c.info['key'] = c.name meta['fields'].append(c.info) elif c.type.python_type == datetime.datetime: meta['fields'].append({ 'name': c.name, 'key': c.name, 'display_order': 0, 'type': 'DATETIME' }) else: meta['fields'].append({ 'name': c.name, 'key': c.name, 'display_order': 0 }) # Sort the fields meta['fields'] = sorted(meta['fields'], key=lambda field: field['display_order']) return meta
def get(self, flow, questionnaire_name): questionnaire_name = ExportService.camel_case_it(questionnaire_name) flow = Flows.get_flow_by_name(flow) if flow is None: raise RestException(RestException.NOT_FOUND) class_ref = ExportService.get_class(questionnaire_name) questionnaire = class_ref() return ExportService.get_meta(questionnaire, flow.relationship)
def load_data(self, export_info, log): if len(export_info.json_data) < 1: return # Nothing to do here. schema = ExportService.get_schema(export_info.class_name, many=False, is_import=True) model_class = ExportService.get_class(export_info.class_name) log_detail = DataTransferLogDetail(class_name=export_info.class_name, date_started=log.date_started, successful=True, success_count=0, failure_count=0) log.details.append(log_detail) for item in export_info.json_data: item_copy = dict(item) if "_links" in item_copy: links = item_copy.pop("_links") existing_model = self.db.session.query(model_class).filter_by( id=item['id']).first() try: if existing_model: model = schema.load(data=item_copy, session=self.db.session, instance=existing_model) else: model = schema.load(data=item_copy, session=self.db.session) try: self.db.session.add(model) self.db.session.commit() log_detail.handle_success() self.db.session.add(log_detail) if hasattr( model, '__question_type__' ) and model.__question_type__ == ExportService.TYPE_SENSITIVE: print("Sensitive Data. Calling Delete.") self.delete_record(item) except Exception as e: self.db.session.rollback() self.logger.error("Error processing " + export_info.class_name + " with id of " + str(item["id"]) + ". Error: " + str(e)) log_detail.handle_failure(e) self.db.session.add(log) self.db.session.add(log_detail) raise e except Exception as e: e = Exception("Failed to parse model " + export_info.class_name + ". " + str(e)) log_detail.handle_failure(e) self.db.session.add(log) self.db.session.add(log_detail) raise e self.db.session.commit()
def get(self, name, id): name = ExportService.camel_case_it(name) class_ref = ExportService.get_class(name) instance = db.session.query(class_ref).filter( class_ref.id == id).first() if instance is None: raise RestException(RestException.NOT_FOUND) schema = ExportService.get_schema(name) return schema.dump(instance)
def delete(self, name, id): try: name = ExportService.camel_case_it(name) class_ref = ExportService.get_class(name) instance = db.session.query(class_ref).filter( class_ref.id == id).first() db.session.delete(instance) # db.session.query(class_ref).filter(class_ref.id == id).delete() db.session.commit() except IntegrityError as error: raise RestException(RestException.CAN_NOT_DELETE) return
def put(self, name, id): name = ExportService.camel_case_it(name) class_ref = ExportService.get_class(name) instance = db.session.query(class_ref).filter( class_ref.id == id).first() schema = ExportService.get_schema(name, session=db.session) request_data = request.get_json() if "_links" in request_data: request_data.pop("_links") updated, errors = schema.load(request_data, instance=instance) if errors: raise RestException(RestException.INVALID_OBJECT, details=errors) updated.last_updated = datetime.datetime.utcnow() db.session.add(updated) db.session.commit() return schema.dump(updated)
def get(self, name, id): """ Returns a single questionnaire record. Parameters: name (str): Snake-cased name of the questionnaire class (should also match the table name), found in app.model.questionnaires. E.g., clinical_diagnoses_questionnaire -> ClinicalDiagnosesQuestionnaire id (int): ID of the questionnaire record to retrieve Returns: A single questionnaire record. """ name = ExportService.camel_case_it(name) class_ref = ExportService.get_class(name) instance = db.session.query(class_ref).filter( class_ref.id == id).first() if instance is None: raise RestException(RestException.NOT_FOUND) schema = ExportService.get_schema(name) return schema.dump(instance)
def get(self, name): name = ExportService.camel_case_it(name) class_ref = ExportService.get_class(name) questionnaire = class_ref() meta = {"table": {}} try: meta["table"]['question_type'] = questionnaire.__question_type__ meta["table"]["label"] = questionnaire.__label__ except: pass # If these fields don't exist, just keep going. meta["fields"] = [] # This will move fields referenced by the field groups into the group, but will otherwise add them # the base meta object if they are not contained within a group. for c in questionnaire.__table__.columns: if c.info: c.info['name'] = c.name c.info['key'] = c.name meta['fields'].append(c.info) elif c.type.python_type == datetime.datetime: meta['fields'].append({ 'name': c.name, 'key': c.name, 'display_order': 0, 'type': 'DATETIME' }) else: meta['fields'].append({ 'name': c.name, 'key': c.name, 'display_order': 0 }) # Sort the fields meta['fields'] = sorted(meta['fields'], key=lambda field: field['display_order']) return meta
def delete(self, name, id): """ Deletes a single questionnaire record. Parameters: name (str): Snake-cased name of the questionnaire class (should also match the table name), found in app.model.questionnaires. E.g., clinical_diagnoses_questionnaire -> ClinicalDiagnosesQuestionnaire id (int): ID of the questionnaire record to delete """ try: name = ExportService.camel_case_it(name) class_ref = ExportService.get_class(name) instance = db.session.query(class_ref).filter( class_ref.id == id).first() db.session.delete(instance) # db.session.query(class_ref).filter(class_ref.id == id).delete() db.session.commit() except IntegrityError as error: raise RestException(RestException.CAN_NOT_DELETE) return
def export_xls(name, app, user_id=None): # Flask response response = Response() response.status_code = 200 # Create an in-memory output file for the new workbook. output = io.BytesIO() if name.lower() == 'all': # Get Questionnaire Names questionnaire_names = ExportXlsService.get_questionnaire_names(app) else: cl = ExportService.get_class(name) info = ExportService.get_single_table_info(cl, None) questionnaire_names = [name] for sub_table in info.sub_tables: questionnaire_names.append(sub_table.class_name) # Create workbook workbook = xlsxwriter.Workbook(output, {'in_memory': True}) # Add a bold format to use to highlight cells. bold = workbook.add_format({'bold': True}) for qname in questionnaire_names: worksheet = workbook.add_worksheet( ExportXlsService.pretty_title_from_snakecase(qname)) # Some data we want to write to the worksheet. # Get header fields from the schema in case the first record is missing fields schema = ExportService.get_schema(qname, many=True) header_fields = schema.fields if user_id: questionnaires = schema.dump(ExportService().get_data( name=qname, user_id=user_id), many=True) else: questionnaires = schema.dump( ExportService().get_data(name=qname), many=True) # Start from the first cell. Rows and columns are zero indexed. row = 0 col = 0 # Write the column headers. for (key, value) in header_fields.items(): if key != "_links": worksheet.write(row, col, key, bold) col += 1 row += 1 # Iterate over the data and write it out row by row. for questionnaire in questionnaires: # Start from the first cell. Rows and columns are zero indexed. col = 0 for (key, value) in questionnaire.items(): if key == "_links": continue # Don't export _links if isinstance(value, dict): continue if isinstance(value, list) and len(value) > 0 and isinstance( value[0], dict): continue # Don't try to represent sub-table data. if isinstance(value, list): list_string = '' for list_value in value: list_string = list_string + str(list_value) + ', ' worksheet.write(row, col, list_string) else: worksheet.write(row, col, value) col += 1 row += 1 # Close the workbook before streaming the data. workbook.close() # Rewind the buffer. output.seek(0) # Add output to response response.data = output.read() # Set filename file_name = 'export_{}_{}.xlsx'.format(name, datetime.utcnow()) # HTTP headers for forcing file download response_headers = Headers({ 'Pragma': "public", # required, 'Expires': '0', 'Cache-Control': 'must-revalidate, private', # required for certain browsers 'Content-Type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'Content-Disposition': 'attachment; filename=\"%s\";' % file_name, 'Content-Transfer-Encoding': 'binary', 'Access-Control-Expose-Headers': 'x-filename', 'x-filename': file_name, 'Content-Length': len(response.data) }) # Add headers response.headers = response_headers # jquery.fileDownload.js requirements response.set_cookie('fileDownload', 'true', path='/') # Return the response return response
def get(self, name): name = ExportService.camel_case_it(name) class_ref = ExportService.get_class(name) schema = ExportService.get_schema(name, many=True) questionnaires = db.session.query(class_ref).all() return schema.dump(questionnaires)