Exemplo n.º 1
0
    def __init__(self, context, backend_addr, friendly_name, concurrency,
                 tasks_filesystem, problem_types):
        """
        :param context: ZeroMQ context for this process
        :param backend_addr: address of the backend (for example, "tcp://127.0.0.1:2222")
        :param friendly_name: a string containing a friendly name to identify agent
        :param tasks_filesystem: FileSystemProvider to the course/tasks
        :param problem_types: Problem types dictionary
        """
        super().__init__(context, backend_addr, friendly_name, concurrency,
                         tasks_filesystem)
        self._logger = logging.getLogger("inginious.agent.mcq")
        self._problem_types = problem_types

        # Init gettext
        self._translations = {"en": gettext.NullTranslations()}
        available_translations = [
            x for x in os.listdir(get_root_path() + '/agent/mcq_agent/i18n')
            if os.path.isdir(
                os.path.join(get_root_path() + '/agent/mcq_agent/i18n', x))
        ]
        self._translations.update({
            lang:
            gettext.translation('messages',
                                get_root_path() + '/agent/mcq_agent/i18n',
                                [lang])
            for lang in available_translations
        })
Exemplo n.º 2
0
    def get_custom_renderer(self, dir_path, layout=True):
        """
        Create a template renderer on templates in the directory specified, and returns it.

        See the web.py documentation.
        This function is deprecated, use render() (that uses Jinja) instead.

        :param dir_path: the path to the template dir. If it is not absolute, it will be taken from the root of the inginious package.
        :param layout: can either be True (use the base layout of the running app), False (use no layout at all), or the path to the layout to use.
                       If this path is relative, it is taken from the INGInious package root.
        """

        # if dir_path/base is a absolute path, os.path.join(something, an_absolute_path) returns an_absolute_path.
        root_path = inginious.get_root_path()

        if isinstance(layout, str):
            layout_path = os.path.join(root_path, layout)
        elif layout is True:
            layout_path = os.path.join(root_path, self._layout)
        else:
            layout_path = None

        return web.template.render(os.path.join(root_path, dir_path),
                                  globals=self._template_globals,
                                  base=layout_path)
Exemplo n.º 3
0
    def __init__(self, context, backend_addr, friendly_name, concurrency,
                 tasks_filesystem):
        """
        :param context: ZeroMQ context for this process
        :param backend_addr: address of the backend (for example, "tcp://127.0.0.1:2222")
        :param friendly_name: a string containing a friendly name to identify agent
        :param tasks_filesystem: FileSystemProvider to the course/tasks
        """
        super().__init__(context, backend_addr, friendly_name, concurrency,
                         tasks_filesystem)
        self._logger = logging.getLogger("inginious.agent.mcq")

        # Create a course factory
        course_factory, _ = create_factories(tasks_filesystem)
        self.course_factory = course_factory

        # Init gettext
        languages = ["en", "fr"]
        self._translations = {
            lang:
            gettext.translation('messages',
                                get_root_path() + '/agent/mcq_agent/i18n',
                                [lang])
            for lang in languages
        }
Exemplo n.º 4
0
    def _get_jinja_renderer(self, template_folder=""):
        # Always include the main template folder
        template_folders = [
            os.path.join(inginious.get_root_path(), self._template_dir)
        ]

        # Include the additional template folder if specified
        if template_folder:
            template_folders += [
                os.path.join(inginious.get_root_path(), template_folder)
            ]

        env = Environment(loader=FileSystemLoader(template_folders),
                          autoescape=select_autoescape(['html', 'htm', 'xml']))
        env.globals.update(self._template_globals)

        return env
Exemplo n.º 5
0
    def _get_jinja_renderer(self, base_template_folder=None):
        if base_template_folder is None:
            base_template_folder = self._template_dir
        # if base_template_folder is not an absolute path, take it wrt INGInious root folder
        base_template_folder = os.path.join(inginious.get_root_path(), base_template_folder)

        env = Environment(loader=FileSystemLoader(base_template_folder),
                          autoescape=select_autoescape(['html', 'htm', 'xml']))
        env.globals.update(self._template_globals)

        return env
Exemplo n.º 6
0
    def __init__(self, context, backend_addr, friendly_name, concurrency, tasks_filesystem, course_factory):
        """
        :param context: ZeroMQ context for this process
        :param backend_addr: address of the backend (for example, "tcp://127.0.0.1:2222")
        :param friendly_name: a string containing a friendly name to identify agent
        :param tasks_filesystem: FileSystemProvider to the course/tasks
        :param course_factory: Course factory used to get course/tasks
        """
        super().__init__(context, backend_addr, friendly_name, concurrency, tasks_filesystem)
        self._logger = logging.getLogger("inginious.agent.mcq")
        self.course_factory = course_factory

        # Init gettext
        languages = ["en", "fr"]
        self._translations = {
            lang: gettext.translation('messages', get_root_path() + '/agent/mcq_agent/i18n', [lang]) for lang in languages
        }
Exemplo n.º 7
0
    def get_custom_renderer(self, dir_path, layout=True):
        """
        Create a template renderer on templates in the directory specified, and returns it.
        :param dir_path: the path to the template dir. If it is not absolute, it will be taken from the root of the inginious package.
        :param layout: can either be True (use the base layout of the running app), False (use no layout at all), or the path to the layout to use.
                       If this path is relative, it is taken from the INGInious package root.
        """

        # if dir_path/base is a absolute path, os.path.join(something, an_absolute_path) returns an_absolute_path.
        root_path = inginious.get_root_path()

        if isinstance(layout, str):
            layout_path = os.path.join(root_path, layout)
        elif layout is True:
            layout_path = os.path.join(root_path, self._layout)
        else:
            layout_path = None

        return web.template.render(os.path.join(root_path, dir_path),
                                   globals=self._template_globals,
                                   base=layout_path)
Exemplo n.º 8
0
def get_app(config):
    """
    :param config: the configuration dict
    :return: A new app
    """
    config = _put_configuration_defaults(config)

    mongo_client = MongoClient(
        host=config.get('mongo_opt', {}).get('host', 'localhost'))
    database = mongo_client[config.get('mongo_opt',
                                       {}).get('database', 'INGInious')]
    gridfs = GridFS(database)

    # Init database if needed
    db_version = database.db_version.find_one({})
    if db_version is None:
        database.submissions.ensure_index([("username", pymongo.ASCENDING)])
        database.submissions.ensure_index([("courseid", pymongo.ASCENDING)])
        database.submissions.ensure_index([("courseid", pymongo.ASCENDING),
                                           ("taskid", pymongo.ASCENDING)])
        database.submissions.ensure_index([("submitted_on", pymongo.DESCENDING)
                                           ])  # sort speed
        database.user_tasks.ensure_index([("username", pymongo.ASCENDING),
                                          ("courseid", pymongo.ASCENDING),
                                          ("taskid", pymongo.ASCENDING)],
                                         unique=True)
        database.user_tasks.ensure_index([("username", pymongo.ASCENDING),
                                          ("courseid", pymongo.ASCENDING)])
        database.user_tasks.ensure_index([("courseid", pymongo.ASCENDING),
                                          ("taskid", pymongo.ASCENDING)])
        database.user_tasks.ensure_index([("courseid", pymongo.ASCENDING)])
        database.user_tasks.ensure_index([("username", pymongo.ASCENDING)])

    appli = CookieLessCompatibleApplication(MongoStore(database, 'sessions'))

    # Init gettext
    available_languages = {"en": "English", "fr": "Français"}

    for lang in available_languages.keys():
        appli.add_translation(
            lang,
            gettext.translation('messages',
                                get_root_path() + '/frontend/i18n', [lang]))

    builtins.__dict__['_'] = appli.gettext

    if config.get("maintenance", False):
        template_helper = TemplateHelper(PluginManager(), None,
                                         'frontend/templates',
                                         'frontend/templates/layout',
                                         'frontend/templates/layout_lti',
                                         config.get('use_minified_js', True))
        template_helper.add_to_template_globals("get_homepath",
                                                appli.get_homepath)
        template_helper.add_to_template_globals("_", _)
        appli.template_helper = template_helper
        appli.init_mapping(urls_maintenance)
        return appli.wsgifunc(), appli.stop

    default_allowed_file_extensions = config['allowed_file_extensions']
    default_max_file_size = config['max_file_size']

    zmq_context, __ = start_asyncio_and_zmq(config.get('debug_asyncio', False))

    # Init the different parts of the app
    plugin_manager = PluginManager()

    # Create the FS provider
    if "fs" in config:
        fs_provider = filesystem_from_config_dict(config["fs"])
    else:
        task_directory = config["tasks_directory"]
        fs_provider = LocalFSProvider(task_directory)

    default_problem_types = {
        problem_type.get_type(): problem_type
        for problem_type in [
            DisplayableCodeProblem, DisplayableCodeSingleLineProblem,
            DisplayableFileProblem, DisplayableMultipleChoiceProblem,
            DisplayableMatchProblem
        ]
    }

    course_factory, task_factory = create_factories(fs_provider,
                                                    default_problem_types,
                                                    plugin_manager,
                                                    WebAppCourse, WebAppTask)

    user_manager = UserManager(appli.get_session(), database,
                               config.get('superadmins', []))

    update_pending_jobs(database)

    client = create_arch(config, fs_provider, zmq_context, course_factory)

    lti_outcome_manager = LTIOutcomeManager(database, user_manager,
                                            course_factory)

    submission_manager = WebAppSubmissionManager(client, user_manager,
                                                 database, gridfs,
                                                 plugin_manager,
                                                 lti_outcome_manager)

    template_helper = TemplateHelper(plugin_manager, user_manager,
                                     'frontend/templates',
                                     'frontend/templates/layout',
                                     'frontend/templates/layout_lti',
                                     config.get('use_minified_js', True))

    # Init web mail
    smtp_conf = config.get('smtp', None)
    if smtp_conf is not None:
        web.config.smtp_server = smtp_conf["host"]
        web.config.smtp_port = int(smtp_conf["port"])
        web.config.smtp_starttls = bool(smtp_conf.get("starttls", False))
        web.config.smtp_username = smtp_conf.get("username", "")
        web.config.smtp_password = smtp_conf.get("password", "")
        web.config.smtp_sendername = smtp_conf.get("sendername",
                                                   "*****@*****.**")

    # Add some helpers for the templates
    template_helper.add_to_template_globals("_", _)
    template_helper.add_to_template_globals("str", str)
    template_helper.add_to_template_globals("available_languages",
                                            available_languages)
    template_helper.add_to_template_globals("get_homepath", appli.get_homepath)
    template_helper.add_to_template_globals(
        "allow_registration", config.get("allow_registration", True))
    template_helper.add_to_template_globals("user_manager", user_manager)
    template_helper.add_to_template_globals("default_allowed_file_extensions",
                                            default_allowed_file_extensions)
    template_helper.add_to_template_globals("default_max_file_size",
                                            default_max_file_size)
    template_helper.add_other(
        "course_admin_menu",
        lambda course, current: course_admin_utils.get_menu(
            course, current, template_helper.get_renderer(False),
            plugin_manager, user_manager))
    template_helper.add_other(
        "preferences_menu", lambda current: preferences_utils.get_menu(
            appli, current, template_helper.get_renderer(False),
            plugin_manager, user_manager))

    # Not found page
    appli.notfound = lambda: web.notfound(template_helper.get_renderer().
                                          notfound('Page not found'))

    # Enable stacktrace display if logging is at level DEBUG
    if config.get('log_level', 'INFO') == 'DEBUG':
        appli.internalerror = debugerror

    # Insert the needed singletons into the application, to allow pages to call them
    appli.plugin_manager = plugin_manager
    appli.course_factory = course_factory
    appli.task_factory = task_factory
    appli.submission_manager = submission_manager
    appli.user_manager = user_manager
    appli.template_helper = template_helper
    appli.database = database
    appli.gridfs = gridfs
    appli.default_allowed_file_extensions = default_allowed_file_extensions
    appli.default_max_file_size = default_max_file_size
    appli.backup_dir = config.get("backup_directory", './backup')
    appli.webterm_link = config.get("webterm", None)
    appli.lti_outcome_manager = lti_outcome_manager
    appli.allow_registration = config.get("allow_registration", True)
    appli.allow_deletion = config.get("allow_deletion", True)
    appli.available_languages = available_languages
    appli.welcome_page = config.get("welcome_page", None)
    appli.static_directory = config.get("static_directory", "./static")
    appli.webdav_host = config.get("webdav_host", None)

    # Init the mapping of the app
    appli.init_mapping(urls)

    # Loads plugins
    plugin_manager.load(client, appli, course_factory, task_factory, database,
                        user_manager, submission_manager,
                        config.get("plugins", []))

    # Start the inginious.backend
    client.start()

    return appli.wsgifunc(), lambda: _close_app(appli, mongo_client, client)
Exemplo n.º 9
0
def get_app(config):
    """
    :param config: the configuration dict
    :return: A new app
    """
    # First, disable debug. It will be enabled in the configuration, later.
    web.config.debug = False

    config = _put_configuration_defaults(config)

    web.config.session_parameters.update(config['session_parameters'])

    mongo_client = MongoClient(
        host=config.get('mongo_opt', {}).get('host', 'localhost'))
    database = mongo_client[config.get('mongo_opt',
                                       {}).get('database', 'INGInious')]
    gridfs = GridFS(database)

    # Init database if needed
    db_version = database.db_version.find_one({})
    if db_version is None:
        database.submissions.ensure_index([("username", pymongo.ASCENDING)])
        database.submissions.ensure_index([("courseid", pymongo.ASCENDING)])
        database.submissions.ensure_index([("courseid", pymongo.ASCENDING),
                                           ("taskid", pymongo.ASCENDING)])
        database.submissions.ensure_index([("submitted_on", pymongo.DESCENDING)
                                           ])  # sort speed
        database.user_tasks.ensure_index([("username", pymongo.ASCENDING),
                                          ("courseid", pymongo.ASCENDING),
                                          ("taskid", pymongo.ASCENDING)],
                                         unique=True)
        database.user_tasks.ensure_index([("username", pymongo.ASCENDING),
                                          ("courseid", pymongo.ASCENDING)])
        database.user_tasks.ensure_index([("courseid", pymongo.ASCENDING),
                                          ("taskid", pymongo.ASCENDING)])
        database.user_tasks.ensure_index([("courseid", pymongo.ASCENDING)])
        database.user_tasks.ensure_index([("username", pymongo.ASCENDING)])

    appli = CookieLessCompatibleApplication(MongoStore(database, 'sessions'))

    # Init gettext
    available_translations = {
        "fr": "Français",
        "es": "Español",
        "pt": "Português",
        "el": "ελληνικά",
        "vi": "Tiếng Việt",
        "nl": "Nederlands",
        "de": "Deutsch"
    }

    available_languages = {"en": "English"}
    available_languages.update(available_translations)

    appli.add_translation(
        "en",
        gettext.NullTranslations())  # English does not need translation ;-)
    for lang in available_translations.keys():
        appli.add_translation(
            lang,
            gettext.translation('messages',
                                get_root_path() + '/frontend/i18n', [lang]))

    builtins.__dict__['_'] = appli.gettext

    if config.get("maintenance", False):
        template_helper = TemplateHelper(PluginManager(), None,
                                         'frontend/templates',
                                         'frontend/templates/layout',
                                         'frontend/templates/layout_lti',
                                         config.get('use_minified_js', True))
        template_helper.add_to_template_globals("get_homepath",
                                                appli.get_homepath)
        template_helper.add_to_template_globals("_", _)
        appli.template_helper = template_helper
        appli.init_mapping(urls_maintenance)
        return appli.wsgifunc(), appli.stop

    default_allowed_file_extensions = config['allowed_file_extensions']
    default_max_file_size = config['max_file_size']

    zmq_context, __ = start_asyncio_and_zmq(config.get('debug_asyncio', False))

    # Init the different parts of the app
    plugin_manager = PluginManager()

    # Add the "agent types" inside the frontend, to allow loading tasks and managing envs
    register_base_env_types()

    # Create the FS provider
    if "fs" in config:
        fs_provider = filesystem_from_config_dict(config["fs"])
    else:
        task_directory = config["tasks_directory"]
        fs_provider = LocalFSProvider(task_directory)

    default_task_dispensers = {
        task_dispenser.get_id(): task_dispenser
        for task_dispenser in [TableOfContents, CombinatoryTest]
    }

    default_problem_types = {
        problem_type.get_type(): problem_type
        for problem_type in [
            DisplayableCodeProblem, DisplayableCodeSingleLineProblem,
            DisplayableFileProblem, DisplayableMultipleChoiceProblem,
            DisplayableMatchProblem
        ]
    }

    course_factory, task_factory = create_factories(fs_provider,
                                                    default_task_dispensers,
                                                    default_problem_types,
                                                    plugin_manager)

    user_manager = UserManager(appli.get_session(), database,
                               config.get('superadmins', []))

    update_pending_jobs(database)

    client = create_arch(config, fs_provider, zmq_context, course_factory)

    lti_outcome_manager = LTIOutcomeManager(database, user_manager,
                                            course_factory)

    submission_manager = WebAppSubmissionManager(client, user_manager,
                                                 database, gridfs,
                                                 plugin_manager,
                                                 lti_outcome_manager)

    template_helper = TemplateHelper(plugin_manager, user_manager,
                                     'frontend/templates',
                                     'frontend/templates/layout',
                                     'frontend/templates/layout_lti',
                                     config.get('use_minified_js', True))

    register_utils(database, user_manager, template_helper)

    is_tos_defined = config.get("privacy_page", "") and config.get(
        "terms_page", "")

    # Init web mail
    smtp_conf = config.get('smtp', None)
    if smtp_conf is not None:
        web.config.smtp_server = smtp_conf["host"]
        web.config.smtp_port = int(smtp_conf["port"])
        web.config.smtp_starttls = bool(smtp_conf.get("starttls", False))
        web.config.smtp_username = smtp_conf.get("username", "")
        web.config.smtp_password = smtp_conf.get("password", "")
        web.config.smtp_sendername = smtp_conf.get("sendername",
                                                   "*****@*****.**")

    # Add some helpers for the templates
    template_helper.add_to_template_globals("_", _)
    template_helper.add_to_template_globals("str", str)
    template_helper.add_to_template_globals("available_languages",
                                            available_languages)
    template_helper.add_to_template_globals("get_homepath", appli.get_homepath)
    template_helper.add_to_template_globals(
        "allow_registration", config.get("allow_registration", True))
    template_helper.add_to_template_globals("sentry_io_url",
                                            config.get("sentry_io_url"))
    template_helper.add_to_template_globals("user_manager", user_manager)
    template_helper.add_to_template_globals("default_allowed_file_extensions",
                                            default_allowed_file_extensions)
    template_helper.add_to_template_globals("default_max_file_size",
                                            default_max_file_size)
    template_helper.add_to_template_globals("is_tos_defined", is_tos_defined)
    template_helper.add_other(
        "course_admin_menu",
        lambda course, current: course_admin_utils.get_menu(
            course, current, template_helper.get_renderer(False),
            plugin_manager, user_manager))
    template_helper.add_other(
        "preferences_menu", lambda current: preferences_utils.get_menu(
            appli, current, template_helper.get_renderer(False),
            plugin_manager, user_manager))

    # Not found page
    appli.notfound = lambda message='Page not found': web.notfound(
        template_helper.get_renderer().notfound(message))

    # Forbidden page
    appli.forbidden = lambda message='Forbidden': web.forbidden(
        template_helper.get_renderer().forbidden(message))

    # Enable stacktrace display if needed
    web_debug = config.get('web_debug', False)
    appli.internalerror = internalerror_generator(
        template_helper.get_renderer(False))
    if web_debug is True:
        web.config.debug = True
        appli.internalerror = debugerror
    elif isinstance(web_debug, str):
        web.config.debug = False
        appli.internalerror = emailerrors(web_debug, appli.internalerror)

    # Insert the needed singletons into the application, to allow pages to call them
    appli.plugin_manager = plugin_manager
    appli.course_factory = course_factory
    appli.task_factory = task_factory
    appli.submission_manager = submission_manager
    appli.user_manager = user_manager
    appli.template_helper = template_helper
    appli.database = database
    appli.gridfs = gridfs
    appli.client = client
    appli.default_allowed_file_extensions = default_allowed_file_extensions
    appli.default_max_file_size = default_max_file_size
    appli.backup_dir = config.get("backup_directory", './backup')
    appli.webterm_link = config.get("webterm", None)
    appli.lti_outcome_manager = lti_outcome_manager
    appli.allow_registration = config.get("allow_registration", True)
    appli.allow_deletion = config.get("allow_deletion", True)
    appli.available_languages = available_languages
    appli.welcome_page = config.get("welcome_page", None)
    appli.terms_page = config.get("terms_page", None)
    appli.privacy_page = config.get("privacy_page", None)
    appli.static_directory = config.get("static_directory", "./static")
    appli.webdav_host = config.get("webdav_host", None)

    # Init the mapping of the app
    appli.init_mapping(urls)

    # Loads plugins
    plugin_manager.load(client, appli, course_factory, task_factory, database,
                        user_manager, submission_manager,
                        config.get("plugins", []))

    # Start the inginious.backend
    client.start()

    return appli.wsgifunc(), lambda: _close_app(appli, mongo_client, client)
Exemplo n.º 10
0
def get_app(config):
    """
    :param config: the configuration dict
    :return: A new app
    """
    # First, disable debug. It will be enabled in the configuration, later.

    config = _put_configuration_defaults(config)
    mongo_client = MongoClient(
        host=config.get('mongo_opt', {}).get('host', 'localhost'))
    database = mongo_client[config.get('mongo_opt',
                                       {}).get('database', 'INGInious')]
    gridfs = GridFS(database)

    # Init database if needed
    db_version = database.db_version.find_one({})
    if db_version is None:
        database.submissions.ensure_index([("username", pymongo.ASCENDING)])
        database.submissions.ensure_index([("courseid", pymongo.ASCENDING)])
        database.submissions.ensure_index([("courseid", pymongo.ASCENDING),
                                           ("taskid", pymongo.ASCENDING)])
        database.submissions.ensure_index([("submitted_on", pymongo.DESCENDING)
                                           ])  # sort speed
        database.user_tasks.ensure_index([("username", pymongo.ASCENDING),
                                          ("courseid", pymongo.ASCENDING),
                                          ("taskid", pymongo.ASCENDING)],
                                         unique=True)
        database.user_tasks.ensure_index([("username", pymongo.ASCENDING),
                                          ("courseid", pymongo.ASCENDING)])
        database.user_tasks.ensure_index([("courseid", pymongo.ASCENDING),
                                          ("taskid", pymongo.ASCENDING)])
        database.user_tasks.ensure_index([("courseid", pymongo.ASCENDING)])
        database.user_tasks.ensure_index([("username", pymongo.ASCENDING)])

    flask_app = flask.Flask(__name__)

    flask_app.config.from_mapping(**config)
    flask_app.session_interface = MongoDBSessionInterface(
        mongo_client,
        config.get('mongo_opt', {}).get('database', 'INGInious'),
        "sessions",
        config.get('SESSION_USE_SIGNER', False),
        True  # config.get('SESSION_PERMANENT', True)
    )

    # Init gettext
    available_translations = {
        "fr": "Français",
        "es": "Español",
        "pt": "Português",
        "el": "ελληνικά",
        "vi": "Tiếng Việt",
        "nl": "Nederlands",
        "de": "Deutsch"
    }

    available_languages = {"en": "English"}
    available_languages.update(available_translations)

    l10n_manager = L10nManager()

    l10n_manager.translations["en"] = gettext.NullTranslations(
    )  # English does not need translation ;-)
    for lang in available_translations.keys():
        l10n_manager.translations[lang] = gettext.translation(
            'messages',
            get_root_path() + '/frontend/i18n', [lang])

    builtins.__dict__['_'] = l10n_manager.gettext

    if config.get("maintenance", False):
        template_helper = TemplateHelper(PluginManager(), None,
                                         config.get('use_minified_js', True))
        template_helper.add_to_template_globals("get_homepath", get_homepath)
        template_helper.add_to_template_globals("pkg_version", __version__)
        template_helper.add_to_template_globals("available_languages",
                                                available_languages)
        template_helper.add_to_template_globals("_", _)
        flask_app.template_helper = template_helper
        init_flask_maintenance_mapping(flask_app)
        return flask_app.wsgi_app, lambda: None

    default_allowed_file_extensions = config['allowed_file_extensions']
    default_max_file_size = config['max_file_size']

    zmq_context, __ = start_asyncio_and_zmq(config.get('debug_asyncio', False))

    # Init the different parts of the app
    plugin_manager = PluginManager()

    # Add the "agent types" inside the frontend, to allow loading tasks and managing envs
    register_base_env_types()

    # Create the FS provider
    if "fs" in config:
        fs_provider = filesystem_from_config_dict(config["fs"])
    else:
        task_directory = config["tasks_directory"]
        fs_provider = LocalFSProvider(task_directory)

    default_task_dispensers = {
        task_dispenser.get_id(): task_dispenser
        for task_dispenser in [TableOfContents, CombinatoryTest]
    }

    default_problem_types = {
        problem_type.get_type(): problem_type
        for problem_type in [
            DisplayableCodeProblem, DisplayableCodeSingleLineProblem,
            DisplayableFileProblem, DisplayableMultipleChoiceProblem,
            DisplayableMatchProblem
        ]
    }

    course_factory, task_factory = create_factories(fs_provider,
                                                    default_task_dispensers,
                                                    default_problem_types,
                                                    plugin_manager)

    user_manager = UserManager(database, config.get('superadmins', []))

    update_pending_jobs(database)

    client = create_arch(config, fs_provider, zmq_context, course_factory)

    lti_outcome_manager = LTIOutcomeManager(database, user_manager,
                                            course_factory)

    submission_manager = WebAppSubmissionManager(client, user_manager,
                                                 database, gridfs,
                                                 plugin_manager,
                                                 lti_outcome_manager)

    template_helper = TemplateHelper(plugin_manager, user_manager,
                                     config.get('use_minified_js', True))

    register_utils(database, user_manager, template_helper)

    is_tos_defined = config.get("privacy_page", "") and config.get(
        "terms_page", "")

    # Init web mail
    mail.init_app(flask_app)

    # Add some helpers for the templates
    template_helper.add_to_template_globals("_", _)
    template_helper.add_to_template_globals("str", str)
    template_helper.add_to_template_globals("available_languages",
                                            available_languages)
    template_helper.add_to_template_globals("get_homepath", get_homepath)
    template_helper.add_to_template_globals("pkg_version", __version__)
    template_helper.add_to_template_globals(
        "allow_registration", config.get("allow_registration", True))
    template_helper.add_to_template_globals("sentry_io_url",
                                            config.get("sentry_io_url"))
    template_helper.add_to_template_globals("user_manager", user_manager)
    template_helper.add_to_template_globals("default_allowed_file_extensions",
                                            default_allowed_file_extensions)
    template_helper.add_to_template_globals("default_max_file_size",
                                            default_max_file_size)
    template_helper.add_to_template_globals("is_tos_defined", is_tos_defined)
    template_helper.add_other(
        "course_admin_menu",
        lambda course, current: course_admin_utils.get_menu(
            course, current, template_helper.render, plugin_manager,
            user_manager))
    template_helper.add_other(
        "preferences_menu", lambda current: preferences_utils.get_menu(
            config.get("allow_deletion", True), current, template_helper.
            render, plugin_manager, user_manager))

    # Not found page
    def flask_not_found(e):
        return template_helper.render("notfound.html",
                                      message=e.description), 404

    flask_app.register_error_handler(404, flask_not_found)

    # Forbidden page
    def flask_forbidden(e):
        return template_helper.render("forbidden.html",
                                      message=e.description), 403

    flask_app.register_error_handler(403, flask_forbidden)

    # Enable stacktrace display if needed
    web_debug = config.get('web_debug', False)

    def flask_internalerror(e):
        return template_helper.render("internalerror.html",
                                      message=e.description), 500

    flask_app.register_error_handler(InternalServerError, flask_internalerror)

    if web_debug is True:
        flask_app.debug = True
    elif isinstance(web_debug, str):
        flask_app.debug = False

    # Insert the needed singletons into the application, to allow pages to call them
    flask_app.get_homepath = get_homepath
    flask_app.plugin_manager = plugin_manager
    flask_app.course_factory = course_factory
    flask_app.task_factory = task_factory
    flask_app.submission_manager = submission_manager
    flask_app.user_manager = user_manager
    flask_app.l10n_manager = l10n_manager
    flask_app.template_helper = template_helper
    flask_app.database = database
    flask_app.gridfs = gridfs
    flask_app.client = client
    flask_app.default_allowed_file_extensions = default_allowed_file_extensions
    flask_app.default_max_file_size = default_max_file_size
    flask_app.backup_dir = config.get("backup_directory", './backup')
    flask_app.webterm_link = config.get("webterm", None)
    flask_app.lti_outcome_manager = lti_outcome_manager
    flask_app.allow_registration = config.get("allow_registration", True)
    flask_app.allow_deletion = config.get("allow_deletion", True)
    flask_app.available_languages = available_languages
    flask_app.welcome_page = config.get("welcome_page", None)
    flask_app.terms_page = config.get("terms_page", None)
    flask_app.privacy_page = config.get("privacy_page", None)
    flask_app.static_directory = config.get("static_directory", "./static")
    flask_app.webdav_host = config.get("webdav_host", None)

    # Init the mapping of the app
    init_flask_mapping(flask_app)

    # Loads plugins
    plugin_manager.load(client, flask_app, course_factory, task_factory,
                        database, user_manager, submission_manager,
                        config.get("plugins", []))

    # Start the inginious.backend
    client.start()

    return flask_app.wsgi_app, lambda: _close_app(mongo_client, client)
Exemplo n.º 11
0
def get_app(config):
    """
    :param config: the configuration dict
    :return: A new app
    """
    # First, disable debug. It will be enabled in the configuration, later.
    web.config.debug = False

    config = _put_configuration_defaults(config)

    mongo_client = MongoClient(host=config.get('mongo_opt', {}).get('host', 'localhost'))
    database = mongo_client[config.get('mongo_opt', {}).get('database', 'INGInious')]
    gridfs = GridFS(database)

    # Init database if needed
    db_version = database.db_version.find_one({})
    if db_version is None:
        database.submissions.ensure_index([("username", pymongo.ASCENDING)])
        database.submissions.ensure_index([("courseid", pymongo.ASCENDING)])
        database.submissions.ensure_index([("courseid", pymongo.ASCENDING), ("taskid", pymongo.ASCENDING)])
        database.submissions.ensure_index([("submitted_on", pymongo.DESCENDING)])  # sort speed
        database.user_tasks.ensure_index(
            [("username", pymongo.ASCENDING), ("courseid", pymongo.ASCENDING), ("taskid", pymongo.ASCENDING)],
            unique=True)
        database.user_tasks.ensure_index([("username", pymongo.ASCENDING), ("courseid", pymongo.ASCENDING)])
        database.user_tasks.ensure_index([("courseid", pymongo.ASCENDING), ("taskid", pymongo.ASCENDING)])
        database.user_tasks.ensure_index([("courseid", pymongo.ASCENDING)])
        database.user_tasks.ensure_index([("username", pymongo.ASCENDING)])

    appli = CookieLessCompatibleApplication(MongoStore(database, 'sessions'))

    # Init gettext
    available_languages = {
        "en": "English",
        "fr": "Français"
    }

    for lang in available_languages.keys():
        appli.add_translation(lang, gettext.translation('messages', get_root_path() + '/frontend/i18n', [lang]))

    builtins.__dict__['_'] = appli.gettext

    if config.get("maintenance", False):
        template_helper = TemplateHelper(PluginManager(), None,
                                         'frontend/templates',
                                         'frontend/templates/layout',
                                         'frontend/templates/layout_lti',
                                         config.get('use_minified_js', True))
        template_helper.add_to_template_globals("get_homepath", appli.get_homepath)
        template_helper.add_to_template_globals("_", _)
        appli.template_helper = template_helper
        appli.init_mapping(urls_maintenance)
        return appli.wsgifunc(), appli.stop

    default_allowed_file_extensions = config['allowed_file_extensions']
    default_max_file_size = config['max_file_size']

    zmq_context, __ = start_asyncio_and_zmq(config.get('debug_asyncio', False))

    # Init the different parts of the app
    plugin_manager = PluginManager()

    # Create the FS provider
    if "fs" in config:
        fs_provider = filesystem_from_config_dict(config["fs"])
    else:
        task_directory = config["tasks_directory"]
        fs_provider = LocalFSProvider(task_directory)

    default_problem_types = {
        problem_type.get_type(): problem_type for problem_type in [DisplayableCodeProblem,
                                                                   DisplayableCodeSingleLineProblem,
                                                                   DisplayableFileProblem,
                                                                   DisplayableMultipleChoiceProblem,
                                                                   DisplayableMatchProblem]
    }

    course_factory, task_factory = create_factories(fs_provider, default_problem_types, plugin_manager, WebAppCourse, WebAppTask)

    user_manager = UserManager(appli.get_session(), database, config.get('superadmins', []))

    update_pending_jobs(database)

    client = create_arch(config, fs_provider, zmq_context, course_factory)

    lti_outcome_manager = LTIOutcomeManager(database, user_manager, course_factory)

    submission_manager = WebAppSubmissionManager(client, user_manager, database, gridfs, plugin_manager, lti_outcome_manager)

    template_helper = TemplateHelper(plugin_manager, user_manager, 'frontend/templates',
                                     'frontend/templates/layout',
                                     'frontend/templates/layout_lti',
                                     config.get('use_minified_js', True))



    # Init web mail
    smtp_conf = config.get('smtp', None)
    if smtp_conf is not None:
        web.config.smtp_server = smtp_conf["host"]
        web.config.smtp_port = int(smtp_conf["port"])
        web.config.smtp_starttls = bool(smtp_conf.get("starttls", False))
        web.config.smtp_username = smtp_conf.get("username", "")
        web.config.smtp_password = smtp_conf.get("password", "")
        web.config.smtp_sendername = smtp_conf.get("sendername", "*****@*****.**")

    # Add some helpers for the templates
    template_helper.add_to_template_globals("_", _)
    template_helper.add_to_template_globals("str", str)
    template_helper.add_to_template_globals("available_languages", available_languages)
    template_helper.add_to_template_globals("get_homepath", appli.get_homepath)
    template_helper.add_to_template_globals("allow_registration", config.get("allow_registration", True))
    template_helper.add_to_template_globals("user_manager", user_manager)
    template_helper.add_to_template_globals("default_allowed_file_extensions", default_allowed_file_extensions)
    template_helper.add_to_template_globals("default_max_file_size", default_max_file_size)
    template_helper.add_other("course_admin_menu",
                              lambda course, current: course_admin_utils.get_menu(course, current, template_helper.get_renderer(False),
                                                                                  plugin_manager, user_manager))
    template_helper.add_other("preferences_menu",
                              lambda current: preferences_utils.get_menu(appli, current, template_helper.get_renderer(False),
                                                                                 plugin_manager, user_manager))

    # Not found page
    appli.notfound = lambda: web.notfound(template_helper.get_renderer().notfound('Page not found'))

    # Enable stacktrace display if needed
    web_debug = config.get('web_debug', False)
    appli.internalerror = internalerror_generator(template_helper.get_renderer(False))
    if web_debug is True:
        web.config.debug = True
        appli.internalerror = debugerror
    elif isinstance(web_debug, str):
        web.config.debug = False
        appli.internalerror = emailerrors(web_debug, appli.internalerror)

    # Insert the needed singletons into the application, to allow pages to call them
    appli.plugin_manager = plugin_manager
    appli.course_factory = course_factory
    appli.task_factory = task_factory
    appli.submission_manager = submission_manager
    appli.user_manager = user_manager
    appli.template_helper = template_helper
    appli.database = database
    appli.gridfs = gridfs
    appli.default_allowed_file_extensions = default_allowed_file_extensions
    appli.default_max_file_size = default_max_file_size
    appli.backup_dir = config.get("backup_directory", './backup')
    appli.webterm_link = config.get("webterm", None)
    appli.lti_outcome_manager = lti_outcome_manager
    appli.allow_registration = config.get("allow_registration", True)
    appli.allow_deletion = config.get("allow_deletion", True)
    appli.available_languages = available_languages
    appli.welcome_page = config.get("welcome_page", None)
    appli.static_directory = config.get("static_directory", "./static")
    appli.webdav_host = config.get("webdav_host", None)

    # Init the mapping of the app
    appli.init_mapping(urls)

    # Loads plugins
    plugin_manager.load(client, appli, course_factory, task_factory, database, user_manager, submission_manager, config.get("plugins", []))

    # Start the inginious.backend
    client.start()

    return appli.wsgifunc(), lambda: _close_app(appli, mongo_client, client)