Example #1
0
    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))
Example #2
0
    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))
Example #3
0
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}