def launch_operation(self, current_user_id, model_file, project_gid, algorithm_module, algorithm_classname, fetch_file): temp_folder = FilesHelper.create_temp_folder() model_h5_path = FilesHelper.save_temporary_file( model_file, temp_folder) try: project = self.project_service.find_project_lazy_by_gid( project_gid) except ProjectServiceException: raise InvalidIdentifierException() algorithm = AlgorithmService.get_algorithm_by_module_and_class( algorithm_module, algorithm_classname) if algorithm is None: raise InvalidIdentifierException( 'No algorithm found for: %s.%s' % (algorithm_module, algorithm_classname)) try: adapter_instance = ABCAdapter.build_adapter(algorithm) view_model = adapter_instance.get_view_model_class()() view_model_h5 = ViewModelH5(model_h5_path, view_model) view_model_gid = view_model_h5.gid.load() operation = self.operation_service.prepare_operation( current_user_id, project.id, algorithm.id, algorithm.algorithm_category, view_model_gid.hex, None, {}) storage_path = self.files_helper.get_project_folder( project, str(operation.id)) if isinstance(adapter_instance, ABCUploader): for key, value in adapter_instance.get_form_class( ).get_upload_information().items(): data_file = fetch_file(request_file_key=key, file_extension=value) data_file_path = FilesHelper.save_temporary_file( data_file, temp_folder) file_name = os.path.basename(data_file_path) upload_field = getattr(view_model_h5, key) upload_field.store(os.path.join(storage_path, file_name)) shutil.move(data_file_path, storage_path) shutil.move(model_h5_path, storage_path) os.rmdir(temp_folder) view_model_h5.close() OperationService().launch_operation(operation.id, True) return operation.gid except Exception as excep: self.logger.error(excep, exc_info=True) raise ServiceException(str(excep))
def launch_operation(self, current_user_id, model_file, project_gid, algorithm_module, algorithm_classname, fetch_file): temp_folder = create_temp_folder() model_h5_path = save_temporary_file(model_file, temp_folder) try: project = self.project_service.find_project_lazy_by_gid( project_gid) except ProjectServiceException: raise InvalidIdentifierException() try: algorithm = AlgorithmService.get_algorithm_by_module_and_class( algorithm_module, algorithm_classname) if algorithm is None: raise InvalidIdentifierException( 'No algorithm found for: %s.%s' % (algorithm_module, algorithm_classname)) adapter_instance = ABCAdapter.build_adapter(algorithm) view_model = h5.load_view_model_from_file(model_h5_path) if isinstance(adapter_instance, ABCUploader): with ViewModelH5(model_h5_path, view_model) as view_model_h5: for key, value in adapter_instance.get_form_class( ).get_upload_information().items(): data_file = fetch_file(request_file_key=key, file_extension=value) data_file_path = save_temporary_file( data_file, temp_folder) view_model_h5.store_metadata_param(key, data_file_path) view_model = h5.load_view_model_from_file(model_h5_path) operation = self.operation_service.prepare_operation( current_user_id, project, algorithm, view_model=view_model) if os.path.exists(model_h5_path): os.remove(model_h5_path) OperationService().launch_operation(operation.id, True) return operation.gid except Exception as excep: self.logger.error(excep, exc_info=True) raise ServiceException(str(excep))
class BaseController(object): """ This class contains the methods served at the root of the Web site. """ def __init__(self): self.logger = get_logger(self.__class__.__module__) self.user_service = UserService() self.algorithm_service = AlgorithmService() self.analyze_category_link = '/flow/step_analyzers' self.analyze_adapters = None self.connectivity_tab_link = '/flow/step_connectivity' view_category = self.algorithm_service.get_visualisers_category() conn_id = self.algorithm_service.get_algorithm_by_module_and_class(IntrospectionRegistry.CONNECTIVITY_MODULE, IntrospectionRegistry.CONNECTIVITY_CLASS).id connectivity_link = self.get_url_adapter(view_category.id, conn_id) self.connectivity_submenu = [dict(title="Large Scale Connectivity", link=connectivity_link, subsection=WebStructure.SUB_SECTION_CONNECTIVITY, description="View Connectivity Regions. Perform Connectivity lesions"), dict(title="Local Connectivity", link='/spatial/localconnectivity/step_1/1', subsection=WebStructure.SUB_SECTION_LOCAL_CONNECTIVITY, description="Create or view existent Local Connectivity entities.")] allen_algo = self.algorithm_service.get_algorithm_by_module_and_class( IntrospectionRegistry.ALLEN_CREATOR_MODULE, IntrospectionRegistry.ALLEN_CREATOR_CLASS) if allen_algo and not allen_algo.removed: # Only add the Allen Creator if AllenSDK is installed allen_link = self.get_url_adapter(allen_algo.fk_category, allen_algo.id) self.connectivity_submenu.append(dict(title="Allen Connectome Builder", link=allen_link, subsection=WebStructure.SUB_SECTION_ALLEN, description="Download data from Allen dataset and create a mouse connectome")) self.burst_submenu = [dict(link='/burst', subsection=WebStructure.SUB_SECTION_BURST, title='Simulation Cockpit', description='Manage simulations'), dict(link='/burst/dynamic', subsection='dynamic', title='Phase plane', description='Configure model dynamics')] @staticmethod def mark_file_for_delete(file_name, delete_parent_folder=False): """ This method stores provided file name in session, and later on when request is done, all these files/folders are deleted :param file_name: name of the file or folder to be deleted :param delete_parent_folder: specify if the parent folder of the file should be removed too. """ # No processing if no file specified if file_name is None: return files_list = common.get_from_session(FILES_TO_DELETE_ATTR) if files_list is None: files_list = [] common.add2session(FILES_TO_DELETE_ATTR, files_list) # Now add file/folder to list if delete_parent_folder: folder_name = os.path.split(file_name)[0] files_list.append(folder_name) else: files_list.append(file_name) def _mark_selected(self, project): """ Set the project passed as parameter as the selected project. """ previous_project = common.get_current_project() # Update project stored in selection, with latest Project entity from DB. members = self.user_service.get_users_for_project("", project.id)[1] project.members = members if previous_project is None or previous_project.id != project.id: # Clean Burst selection from session in case of a different project. common.clean_project_data_from_session() # Store in DB new project selection user = common.get_from_session(common.KEY_USER) if user is not None: self.user_service.save_project_to_user(user.id, project.id) # Display info message about project change self.logger.debug("Selected project is now " + project.name) common.set_info_message("Your current working project is: " + str(project.name)) # Add the project entity to session every time, as it might be changed (e.g. after edit) common.add2session(common.KEY_PROJECT, project) @staticmethod def get_url_adapter(step_key, adapter_id, back_page=None): """ Compute the URLs for a given adapter. Same URL is used both for GET and POST. """ result_url = '/flow/' + str(step_key) + '/' + str(adapter_id) if back_page is not None: result_url = result_url + "?back_page=" + str(back_page) return result_url @cherrypy.expose def index(self): """ / Path response Redirects to /tvb """ raise cherrypy.HTTPRedirect('/user') @cherrypy.expose() @using_template('user/base_user') def tvb(self, error=False, **data): """ /tvb URL Returns the home page with the messages stored in the user's session. """ self.logger.debug("Unused submit attributes:" + str(data)) template_dictionary = dict(mainContent="index", title="The Virtual Brain Project") template_dictionary = self._fill_user_specific_attributes(template_dictionary) if common.get_from_session(common.KEY_IS_RESTART): template_dictionary[common.KEY_IS_RESTART] = True common.remove_from_session(common.KEY_IS_RESTART) return self.fill_default_attributes(template_dictionary, error) @cherrypy.expose @using_template('user/base_user') def error(self, **data): """Error page to redirect when something extremely bad happened""" template_specification = dict(mainContent="error", title="Error page", data=data) template_specification = self._fill_user_specific_attributes(template_specification) return self.fill_default_attributes(template_specification) def _populate_user_and_project(self, template_dictionary, escape_db_operations=False): """ Populate the template dictionary with current logged user (from session). """ logged_user = common.get_logged_user() template_dictionary[common.KEY_USER] = logged_user show_help = logged_user is not None and logged_user.is_online_help_active() template_dictionary[common.KEY_SHOW_ONLINE_HELP] = show_help project = common.get_current_project() template_dictionary[common.KEY_PROJECT] = project if project is not None and not escape_db_operations: self.update_operations_count() return template_dictionary @staticmethod def _populate_message(template_dictionary): """ Populate the template dictionary with current message stored in session. Also specify the message type (default INFO). Clear from session current message (to avoid displaying it twice). """ msg = common.pop_message_from_session() template_dictionary.update(msg) return template_dictionary @staticmethod def _populate_web_keycloak_config(template_dictionary): if common.KEY_KEYCLOAK_WEB not in template_dictionary and TvbProfile.current.KEYCLOAK_LOGIN_ENABLED \ and TvbProfile.current.KEYCLOAK_WEB_CONFIG: template_dictionary[common.KEY_KEYCLOAK_WEB] = TvbProfile.current.KEYCLOAK_WEB_CONFIG return template_dictionary def _populate_menu(self, template_dictionary): """ Populate current template with information for the Left Menu. """ if common.KEY_FIRST_RUN not in template_dictionary: template_dictionary[common.KEY_FIRST_RUN] = False template_dictionary[common.KEY_LINK_ANALYZE] = self.analyze_category_link template_dictionary[common.KEY_LINK_CONNECTIVITY_TAB] = self.connectivity_tab_link if common.KEY_BACK_PAGE not in template_dictionary: template_dictionary[common.KEY_BACK_PAGE] = False template_dictionary[common.KEY_SECTION_TITLES] = WebStructure.WEB_SECTION_TITLES template_dictionary[common.KEY_SUBSECTION_TITLES] = WebStructure.WEB_SUBSECTION_TITLES return template_dictionary def _populate_section(self, algorithm, result_template, is_burst=True): """ Populate Section and Sub-Section fields from current Algorithm-Group. """ if algorithm.module == IntrospectionRegistry.CONNECTIVITY_MODULE: result_template[common.KEY_SECTION] = WebStructure.SECTION_CONNECTIVITY result_template[common.KEY_SUB_SECTION] = WebStructure.SUB_SECTION_CONNECTIVITY result_template[common.KEY_SUBMENU_LIST] = self.connectivity_submenu elif algorithm.module == IntrospectionRegistry.ALLEN_CREATOR_MODULE: result_template[common.KEY_SECTION] = WebStructure.SECTION_CONNECTIVITY result_template[common.KEY_SUB_SECTION] = WebStructure.SUB_SECTION_ALLEN result_template[common.KEY_SUBMENU_LIST] = self.connectivity_submenu elif algorithm.algorithm_category.display: ## We are having a visualizer: if is_burst: result_template[common.KEY_SECTION] = WebStructure.SECTION_BURST result_template[common.KEY_SUBMENU_LIST] = self.burst_submenu else: result_template[common.KEY_SECTION] = WebStructure.SECTION_PROJECT result_template[common.KEY_SUB_SECTION] = 'view_' + algorithm.subsection_name elif algorithm.algorithm_category.rawinput: ### Upload algorithms result_template[common.KEY_SECTION] = WebStructure.SECTION_PROJECT result_template[common.KEY_SUB_SECTION] = WebStructure.SUB_SECTION_DATA_STRUCTURE elif 'RAW_DATA' in algorithm.algorithm_category.defaultdatastate: ### Creators result_template[common.KEY_SECTION] = WebStructure.SECTION_STIMULUS result_template[common.KEY_SUB_SECTION] = WebStructure.SUB_SECTION_STIMULUS_MENU else: ### Analyzers result_template[common.KEY_SECTION] = algorithm.algorithm_category.displayname.lower() result_template[common.KEY_SUB_SECTION] = algorithm.subsection_name result_template[common.KEY_SUBMENU_LIST] = self.analyze_adapters def _fill_user_specific_attributes(self, template_dictionary): """ Attributes needed for base_user template. """ template_dictionary[common.KEY_INCLUDE_TOOLTIP] = False template_dictionary[common.KEY_WRAP_CONTENT_IN_MAIN_DIV] = True template_dictionary[common.KEY_CURRENT_TAB] = 'none' return template_dictionary def fill_default_attributes(self, template_dictionary, escape_db_operations=False): """ Fill into 'template_dictionary' data that we want to have ready in UI. """ template_dictionary = self._populate_user_and_project(template_dictionary, escape_db_operations) template_dictionary = self._populate_message(template_dictionary) template_dictionary = self._populate_menu(template_dictionary) template_dictionary = self._populate_web_keycloak_config(template_dictionary) if common.KEY_ERRORS not in template_dictionary: template_dictionary[common.KEY_ERRORS] = {} if common.KEY_FORM_DATA not in template_dictionary: template_dictionary[common.KEY_FORM_DATA] = {} if common.KEY_SUB_SECTION not in template_dictionary and common.KEY_SECTION in template_dictionary: template_dictionary[common.KEY_SUB_SECTION] = template_dictionary[common.KEY_SECTION] if common.KEY_SUBMENU_LIST not in template_dictionary: template_dictionary[common.KEY_SUBMENU_LIST] = None js_suffix = TvbProfile.current.version.CURRENT_VERSION.replace(".", "").replace("-", "") template_dictionary[common.KEY_CURRENT_VERSION] = TvbProfile.current.version.BASE_VERSION template_dictionary[common.KEY_CURRENT_JS_VERSION] = js_suffix return template_dictionary def fill_overlay_attributes(self, template_dictionary, title, description, content_template, css_class, tabs_horizontal=None, overlay_indexes=None, tabs_vertical=None): """ This method prepares parameters for rendering overlay (overlay.html) :param title: overlay title :param description: overlay description :param content_template: path&name of the template file which will fill overlay content (without .html) :param css_class: CSS class to be applied on overlay :param tabs_horizontal: list of strings containing names of the tabs spread horizontally :param tabs_vertical: list of strings containing names of the tabs spread vertically """ if template_dictionary is None: template_dictionary = dict() template_dictionary[common.KEY_OVERLAY_TITLE] = title template_dictionary[common.KEY_OVERLAY_DESCRIPTION] = description template_dictionary[common.KEY_OVERLAY_CONTENT_TEMPLATE] = content_template template_dictionary[common.KEY_OVERLAY_CLASS] = css_class template_dictionary[common.KEY_OVERLAY_TABS_HORIZONTAL] = tabs_horizontal if tabs_horizontal is not None else [] template_dictionary[common.KEY_OVERLAY_TABS_VERTICAL] = tabs_vertical if tabs_vertical is not None else [] if overlay_indexes is not None: template_dictionary[common.KEY_OVERLAY_INDEXES] = overlay_indexes else: template_dictionary[common.KEY_OVERLAY_INDEXES] = list(range(len(tabs_horizontal))) \ if tabs_horizontal is not None else [] template_dictionary[common.KEY_OVERLAY_PAGINATION] = False return template_dictionary @cherrypy.expose @using_template('overlay_blocker') def showBlockerOverlay(self, **data): """ Returns the content of the blocking overlay (covers entire page and do not allow any action) """ return self.fill_default_attributes(dict(data)) def update_operations_count(self): """ If a project is selected, update Operation Numbers in call-out. """ project = common.get_current_project() if project is not None: fns, sta, err, canceled, pending = self.algorithm_service.get_operation_numbers(project.id) project.operations_finished = fns project.operations_started = sta project.operations_error = err project.operations_canceled = canceled project.operations_pending = pending common.add2session(common.KEY_PROJECT, project) @using_template('form_fields/form') def render_adapter_form(self, adapter_form, is_callout=False): show_online_help = common.get_logged_user().is_online_help_active() return {'adapter_form': adapter_form, 'showOnlineHelp': show_online_help, 'isCallout': is_callout}