Source code for inginious.frontend.pages.utils

# -*- coding: utf-8 -*-
#
# This file is part of INGInious. See the LICENSE and the COPYRIGHTS files for
# more information about the licensing of this file.

""" Some utils for all the pages """
import logging
from typing import List

import web
import os
from gridfs import GridFS

from inginious.common import custom_yaml
from inginious.frontend.plugin_manager import PluginManager
from inginious.frontend.submission_manager import WebAppSubmissionManager
from inginious.frontend.template_helper import TemplateHelper
from inginious.frontend.user_manager import UserManager
from inginious.frontend.parsable_text import ParsableText
from pymongo.database import Database

from inginious.common.course_factory import CourseFactory
from inginious.common.task_factory import TaskFactory
from inginious.frontend.lti_outcome_manager import LTIOutcomeManager


[docs]class INGIniousPage(object): """ A base for all the pages of the INGInious webapp. Contains references to the PluginManager, the CourseFactory, and the SubmissionManager """ @property def is_lti_page(self): """ True if the current page allows LTI sessions. False else. """ return False @property def app(self): """ Returns the web application singleton """ return web.ctx.app_stack[0] @property def plugin_manager(self) -> PluginManager: """ Returns the plugin manager singleton """ return self.app.plugin_manager @property def course_factory(self) -> CourseFactory: """ Returns the course factory singleton """ return self.app.course_factory @property def task_factory(self) -> TaskFactory: """ Returns the task factory singleton """ return self.app.task_factory @property def submission_manager(self) -> WebAppSubmissionManager: """ Returns the submission manager singleton""" return self.app.submission_manager @property def user_manager(self) -> UserManager: """ Returns the user manager singleton """ return self.app.user_manager @property def template_helper(self) -> TemplateHelper: """ Returns the Template Helper singleton """ return self.app.template_helper @property def database(self) -> Database: """ Returns the database singleton """ return self.app.database @property def gridfs(self) -> GridFS: """ Returns the GridFS singleton """ return self.app.gridfs @property def default_allowed_file_extensions(self) -> List[str]: # pylint: disable=invalid-sequence-index """ List of allowed file extensions """ return self.app.default_allowed_file_extensions @property def default_max_file_size(self) -> int: """ Default maximum file size for upload """ return self.app.default_max_file_size @property def backup_dir(self) -> str: """ Backup directory """ return self.app.backup_dir @property def containers(self) -> List[str]: # pylint: disable=invalid-sequence-index """ Available containers """ return self.app.submission_manager.get_available_environments() @property def webterm_link(self) -> str: """ Returns the link to the web terminal """ return self.app.webterm_link @property def lti_outcome_manager(self) -> LTIOutcomeManager: """ Returns the LTIOutcomeManager singleton """ return self.app.lti_outcome_manager @property def webdav_host(self) -> str: """ True if webdav is available """ return self.app.webdav_host @property def logger(self) -> logging.Logger: """ Logger """ return logging.getLogger('inginious.webapp.pages')
[docs]class INGIniousAuthPage(INGIniousPage): """ Augmented version of INGIniousPage that checks if user is authenticated. """
[docs] def POST_AUTH(self, *args, **kwargs): # pylint: disable=unused-argument raise web.notacceptable()
[docs] def GET_AUTH(self, *args, **kwargs): # pylint: disable=unused-argument raise web.notacceptable()
[docs] def GET(self, *args, **kwargs): """ Checks if user is authenticated and calls GET_AUTH or performs logout. Otherwise, returns the login template. """ if self.user_manager.session_logged_in(): if not self.user_manager.session_username() and not self.__class__.__name__ == "ProfilePage": raise web.seeother("/preferences/profile") if not self.is_lti_page and self.user_manager.session_lti_info() is not None: #lti session self.user_manager.disconnect_user() return self.template_helper.get_renderer().auth(self.user_manager.get_auth_methods(), False) return self.GET_AUTH(*args, **kwargs) else: return self.template_helper.get_renderer().auth(self.user_manager.get_auth_methods(), False)
[docs] def POST(self, *args, **kwargs): """ Checks if user is authenticated and calls POST_AUTH or performs login and calls GET_AUTH. Otherwise, returns the login template. """ if self.user_manager.session_logged_in(): if not self.user_manager.session_username() and not self.__class__.__name__ == "ProfilePage": raise web.seeother("/preferences/profile") if not self.is_lti_page and self.user_manager.session_lti_info() is not None: # lti session self.user_manager.disconnect_user() return self.template_helper.get_renderer().auth(self.user_manager.get_auth_methods_fields(), False) return self.POST_AUTH(*args, **kwargs) else: user_input = web.input() if "login" in user_input and "password" in user_input: if self.user_manager.auth_user(user_input["login"].strip(), user_input["password"]) is not None: return self.GET_AUTH(*args, **kwargs) else: return self.template_helper.get_renderer().auth(self.user_manager.get_auth_methods(), True) else: return self.template_helper.get_renderer().auth(self.user_manager.get_auth_methods(), False)
[docs]class SignInPage(INGIniousAuthPage):
[docs] def GET_AUTH(self, *args, **kwargs): raise web.seeother("/mycourses")
[docs] def POST_AUTH(self, *args, **kwargs): raise web.seeother("/mycourses")
[docs] def GET(self): return INGIniousAuthPage.GET(self)
[docs]class LogOutPage(INGIniousAuthPage):
[docs] def GET_AUTH(self, *args, **kwargs): self.user_manager.disconnect_user() raise web.seeother("/courselist")
[docs] def POST_AUTH(self, *args, **kwargs): self.user_manager.disconnect_user() raise web.seeother("/courselist")
[docs]class INGIniousStaticPage(INGIniousPage): cache = {}
[docs] def GET(self, page): return self.show_page(page)
[docs] def POST(self, page): return self.show_page(page)
[docs] def show_page(self, page): static_directory = self.app.static_directory language = self.user_manager.session_language() # Check for the file filename = None mtime = None filepaths = [os.path.join(static_directory, page + ".yaml"), os.path.join(static_directory, page + "." + language + ".yaml")] for filepath in filepaths: if os.path.exists(filepath): filename = filepath mtime = os.stat(filepath).st_mtime if not filename: raise web.notfound() # Check and update cache if INGIniousStaticPage.cache.get(filename, (0, None))[0] < mtime: with open(filename, "r") as f: INGIniousStaticPage.cache[filename] = mtime, custom_yaml.load(f) filecontent = INGIniousStaticPage.cache[filename][1] title = filecontent["title"] content = ParsableText.rst(filecontent["content"], initial_header_level=2) return self.template_helper.get_renderer().static(title, content)