def build_workflow_from_dict( self, trans, data, source=None, add_to_menu=False, publish=False, create_stored_workflow=True, exact_tools=False, ): # Put parameters in workflow mode trans.workflow_building_mode = True # If there's a source, put it in the workflow name. if source: name = "%s (imported from %s)" % (data['name'], source) else: name = data['name'] workflow, missing_tool_tups = self._workflow_from_dict( trans, data, name=name, exact_tools=exact_tools, ) if 'uuid' in data: workflow.uuid = data['uuid'] if create_stored_workflow: # Connect up stored = model.StoredWorkflow() stored.name = workflow.name workflow.stored_workflow = stored stored.latest_workflow = workflow stored.user = trans.user stored.published = publish if data['annotation']: annotation = sanitize_html(data['annotation'], 'utf-8', 'text/html') self.add_item_annotation(trans.sa_session, stored.user, stored, annotation) # Persist trans.sa_session.add(stored) if add_to_menu: if trans.user.stored_workflow_menu_entries is None: trans.user.stored_workflow_menu_entries = [] menuEntry = model.StoredWorkflowMenuEntry() menuEntry.stored_workflow = stored trans.user.stored_workflow_menu_entries.append(menuEntry) else: stored = None # Persist trans.sa_session.add(workflow) trans.sa_session.flush() return CreatedWorkflow(stored_workflow=stored, workflow=workflow, missing_tools=missing_tool_tups)
def update( self, trans, id, payload, **kwds ): """ * PUT /api/workflows/{id} updates the workflow stored with ``id`` :type id: str :param id: the encoded id of the workflow to update :type payload: dict :param payload: a dictionary containing any or all the * workflow the json description of the workflow as would be produced by GET workflows/<id>/download or given to `POST workflows` The workflow contents will be updated to target this. * name optional string name for the workflow, if not present in payload, name defaults to existing name * annotation optional string annotation for the workflow, if not present in payload, annotation defaults to existing annotation * menu_entry optional boolean marking if the workflow should appear in the user's menu, if not present, workflow menu entries are not modified :rtype: dict :returns: serialized version of the workflow """ stored_workflow = self.__get_stored_workflow( trans, id ) if 'workflow' in payload: stored_workflow.name = sanitize_html(payload['name']) if ('name' in payload) else stored_workflow.name if 'annotation' in payload: newAnnotation = sanitize_html(payload['annotation']) self.add_item_annotation(trans.sa_session, trans.get_user(), stored_workflow, newAnnotation) if 'menu_entry' in payload: if payload['menu_entry']: menuEntry = model.StoredWorkflowMenuEntry() menuEntry.stored_workflow = stored_workflow trans.get_user().stored_workflow_menu_entries.append(menuEntry) else: # remove if in list entries = {x.stored_workflow_id: x for x in trans.get_user().stored_workflow_menu_entries} if (trans.security.decode_id(id) in entries): trans.get_user().stored_workflow_menu_entries.remove(entries[trans.security.decode_id(id)]) try: workflow, errors = self.workflow_contents_manager.update_workflow_from_dict( trans, stored_workflow, payload[ 'workflow' ], ) except workflows.MissingToolsException: raise exceptions.MessageException( "This workflow contains missing tools. It cannot be saved until they have been removed from the workflow or installed." ) else: message = "Updating workflow requires dictionary containing 'workflow' attribute with new JSON description." raise exceptions.RequestParameterInvalidException( message ) return self.workflow_contents_manager.workflow_to_dict( trans, stored_workflow, style="instance" )
def set_workflow_menu(self, trans, **kwd): """ Save workflow menu to be shown in the tool panel PUT /api/workflows/menu """ payload = kwd.get('payload') user = trans.get_user() workflow_ids = payload.get('workflow_ids') if workflow_ids is None: workflow_ids = [] elif type(workflow_ids) != list: workflow_ids = [workflow_ids] workflow_ids_decoded = [] # Decode the encoded workflow ids for ids in workflow_ids: workflow_ids_decoded.append(trans.security.decode_id(ids)) sess = trans.sa_session # This explicit remove seems like a hack, need to figure out # how to make the association do it automatically. for m in user.stored_workflow_menu_entries: sess.delete(m) user.stored_workflow_menu_entries = [] q = sess.query(model.StoredWorkflow) # To ensure id list is unique seen_workflow_ids = set() for wf_id in workflow_ids_decoded: if wf_id in seen_workflow_ids: continue else: seen_workflow_ids.add(wf_id) m = model.StoredWorkflowMenuEntry() m.stored_workflow = q.get(wf_id) user.stored_workflow_menu_entries.append(m) sess.flush() message = "Menu updated." trans.set_message(message) return {'message': message, 'status': 'done'}
def update(self, trans, id, payload, **kwds): """ * PUT /api/workflows/{id} updates the workflow stored with ``id`` :type id: str :param id: the encoded id of the workflow to update :type payload: dict :param payload: a dictionary containing any or all the * workflow the json description of the workflow as would be produced by GET workflows/<id>/download or given to `POST workflows` The workflow contents will be updated to target this. * name optional string name for the workflow, if not present in payload, name defaults to existing name * annotation optional string annotation for the workflow, if not present in payload, annotation defaults to existing annotation * menu_entry optional boolean marking if the workflow should appear in the user's menu, if not present, workflow menu entries are not modified :rtype: dict :returns: serialized version of the workflow """ stored_workflow = self.__get_stored_workflow(trans, id) workflow_dict = payload.get('workflow') or payload if workflow_dict: raw_workflow_description = self.__normalize_workflow( trans, workflow_dict) workflow_dict = raw_workflow_description.as_dict new_workflow_name = workflow_dict.get('name') or workflow_dict.get( 'name') if new_workflow_name and new_workflow_name != stored_workflow.name: sanitized_name = sanitize_html(new_workflow_name) workflow = stored_workflow.latest_workflow.copy() workflow.stored_workflow = stored_workflow workflow.name = sanitized_name stored_workflow.name = sanitized_name stored_workflow.latest_workflow = workflow trans.sa_session.add(workflow, stored_workflow) trans.sa_session.flush() if 'annotation' in workflow_dict: newAnnotation = sanitize_html(workflow_dict['annotation']) self.add_item_annotation(trans.sa_session, trans.get_user(), stored_workflow, newAnnotation) if 'menu_entry' in workflow_dict or 'show_in_tool_panel' in workflow_dict: if workflow_dict.get('menu_entry') or workflow_dict.get( 'show_in_tool_panel'): menuEntry = model.StoredWorkflowMenuEntry() menuEntry.stored_workflow = stored_workflow trans.get_user().stored_workflow_menu_entries.append( menuEntry) else: # remove if in list entries = { x.stored_workflow_id: x for x in trans.get_user().stored_workflow_menu_entries } if (trans.security.decode_id(id) in entries): trans.get_user().stored_workflow_menu_entries.remove( entries[trans.security.decode_id(id)]) # set tags trans.app.tag_handler.set_tags_from_list( user=trans.user, item=stored_workflow, new_tags_list=workflow_dict.get('tags', [])) if 'steps' in workflow_dict: try: from_dict_kwds = self.__import_or_update_kwds(payload) workflow, errors = self.workflow_contents_manager.update_workflow_from_raw_description( trans, stored_workflow, raw_workflow_description, **from_dict_kwds) except workflows.MissingToolsException: raise exceptions.MessageException( "This workflow contains missing tools. It cannot be saved until they have been removed from the workflow or installed." ) else: # We only adjusted tags and menu entry return payload else: message = "Updating workflow requires dictionary containing 'workflow' attribute with new JSON description." raise exceptions.RequestParameterInvalidException(message) return self.workflow_contents_manager.workflow_to_dict( trans, stored_workflow, style="instance")
def build_workflow_from_dict(self, trans, data, source=None, add_to_menu=False, publish=False): # Put parameters in workflow mode trans.workflow_building_mode = True # Create new workflow from incoming dict workflow = model.Workflow() # If there's a source, put it in the workflow name. if source: name = "%s (imported from %s)" % (data['name'], source) else: name = data['name'] workflow.name = name if 'uuid' in data: workflow.uuid = data['uuid'] # Assume no errors until we find a step that has some workflow.has_errors = False # Create each step steps = [] # The editor will provide ids for each step that we don't need to save, # but do need to use to make connections steps_by_external_id = {} # Keep track of tools required by the workflow that are not available in # the local Galaxy instance. Each tuple in the list of missing_tool_tups # will be ( tool_id, tool_name, tool_version ). missing_tool_tups = [] for step_dict in self.__walk_step_dicts(data): module, step = self.__module_from_dict(trans, step_dict, secure=False) steps.append(step) steps_by_external_id[step_dict['id']] = step if module.type == 'tool' and module.tool is None: # A required tool is not available in the local Galaxy instance. missing_tool_tup = (step_dict['tool_id'], step_dict['name'], step_dict['tool_version']) if missing_tool_tup not in missing_tool_tups: missing_tool_tups.append(missing_tool_tup) # Save the entire step_dict in the unused config field, be parsed later # when we do have the tool step.config = json.dumps(step_dict) if step.tool_errors: workflow.has_errors = True # Second pass to deal with connections between steps self.__connect_workflow_steps(steps, steps_by_external_id) # Order the steps if possible attach_ordered_steps(workflow, steps) # Connect up stored = model.StoredWorkflow() stored.name = workflow.name workflow.stored_workflow = stored stored.latest_workflow = workflow stored.user = trans.user stored.published = publish if data['annotation']: annotation = sanitize_html(data['annotation'], 'utf-8', 'text/html') self.add_item_annotation(trans.sa_session, stored.user, stored, annotation) # Persist trans.sa_session.add(stored) trans.sa_session.flush() if add_to_menu: if trans.user.stored_workflow_menu_entries is None: trans.user.stored_workflow_menu_entries = [] menuEntry = model.StoredWorkflowMenuEntry() menuEntry.stored_workflow = stored trans.user.stored_workflow_menu_entries.append(menuEntry) trans.sa_session.flush() return CreatedWorkflow(stored_workflow=stored, missing_tools=missing_tool_tups)