inginious.frontend package

Package that implements a webapp for INGInious

Subpackages

Submodules

inginious.frontend.accessible_time module

Contains AccessibleTime, class that represents the period of time when a course/task is accessible

class inginious.frontend.accessible_time.AccessibleTime(val=None)[source]

Bases: object

represents the period of time when a course/task is accessible

after_start(when=None)[source]

Returns True if the task/course is or have been accessible in the past

before_start(when=None)[source]

Returns True if the task/course is not yet accessible

get_end_date()[source]

Return a datetime object, representing the deadline for accessibility

get_soft_end_date()[source]

Return a datetime object, representing the soft deadline for accessibility

get_start_date()[source]

Return a datetime object, representing the date when the task/course become accessible

get_std_end_date()[source]

If the date is custom, return the end datetime with the format %Y-%m-%d %H:%M:%S. Else, returns “”.

get_std_soft_end_date()[source]

If the date is custom, return the soft datetime with the format %Y-%m-%d %H:%M:%S. Else, returns “”.

get_std_start_date()[source]

If the date is custom, return the start datetime with the format %Y-%m-%d %H:%M:%S. Else, returns “”.

is_always_accessible()[source]

Returns true if the course/task is always accessible

is_never_accessible()[source]

Returns true if the course/task is never accessible

is_open(when=None)[source]

Returns True if the course/task is still open

is_open_with_soft_deadline(when=None)[source]

Returns True if the course/task is still open with the soft deadline

inginious.frontend.accessible_time.parse_date(date, default=None)[source]

Parse a valid date

inginious.frontend.arch_helper module

inginious.frontend.arch_helper.create_arch(configuration, tasks_fs, context, taskset_factory)[source]

Helper that can start a simple complete INGInious arch locally if needed, or a client to a remote backend. Intended to be used on command line, makes uses of exit() and the logger inginious.frontend. :type configuration: :param configuration: configuration dict :type tasks_fs: :param tasks_fs: FileSystemProvider to the courses/tasks folders :type context: :param context: a ZMQ context :type taskset_factory: :param taskset_factory: The course factory to be used by the frontend :param is_testing: boolean :return: a Client object

inginious.frontend.arch_helper.start_asyncio_and_zmq(debug_asyncio=False)[source]

Init asyncio and ZMQ. Starts a daemon thread in which the asyncio loops run. :return: a ZMQ context and a Thread object (as a tuple)

inginious.frontend.app module

Starts the webapp

inginious.frontend.app.get_app(config)[source]
Parameters:

config – the configuration dict

Returns:

A new app

inginious.frontend.app.get_homepath(ignore_session=False, force_cookieless=False)[source]
Parameters:
  • ignore_session – Ignore the cookieless session_id that should be put in the URL

  • force_cookieless – Force the cookieless session; the link will include the session_creator if needed.

inginious.frontend.taskset_factory module

Factory for loading tasksets from disk

class inginious.frontend.taskset_factory.TasksetFactory(filesystem, task_factory, task_dispensers, database)[source]

Bases: object

Load tasksets from disk

add_task_dispenser(task_dispenser)[source]
Parameters:

task_dispenser – TaskDispenser class

create_taskset(tasksetid, init_content)[source]

Create a new taskset folder and set initial descriptor content, folder can already exist :type tasksetid: :param tasksetid: the taskset id of the taskset :type init_content: :param init_content: initial descriptor content :raise: InvalidNameException or CourseAlreadyExistsException

delete_taskset(tasksetid)[source]

Erase the content of the taskset folder :type tasksetid: :param tasksetid: the taskset id of the taskset :raise: InvalidNameException or CourseNotFoundException

get_all_tasksets()[source]
Returns:

a table containing tasksetid => Taskset pairs

get_fs()[source]
Returns:

a FileSystemProvider pointing to the task directory

get_task_dispensers()[source]

Returns the supported task dispensers by this taskset factory

get_task_factory()[source]
Returns:

the associated task factory

get_taskset(tasksetid)[source]
Parameters:

tasksetid – the taskset id id of the taskset

Raise:

InvalidNameException, CourseNotFoundException, CourseUnreadableException

Returns:

an object representing the taskset, of the type given in the constructor

get_taskset_descriptor_content(tasksetid)[source]
Parameters:

tasksetid – the taskset id of the taskset

Raise:

InvalidNameException, TasksetNotFoundException, TasksetUnreadableException

Returns:

the content of the dict that describes the task set

get_taskset_fs(tasksetid)[source]
Parameters:

tasksetid – the taskset id of the task set

Returns:

a FileSystemProvider pointing to the directory of the task set

update_taskset_descriptor_content(tasksetid, content)[source]

Updates the content of the dict that describes the task set :type tasksetid: :param tasksetid: the taskset id of the task set :type content: :param content: the new dict that replaces the old content :raise InvalidNameException, TasksetNotFoundException

update_taskset_descriptor_element(tasksetid, key, value)[source]

Updates the value for the key in the dict that describes the task set :type tasksetid: :param tasksetid: the taskset id of the task set :type key: :param key: the element to change in the dict :type value: :param value: the new value that replaces the old one :raise InvalidNameException, TasksetNotFoundException

inginious.frontend.taskset_factory.create_factories(fs_provider, task_dispensers, task_problem_types, plugin_manager=None, database=None)[source]

Shorthand for creating Factories :type fs_provider: :param fs_provider: A FileSystemProvider leading to the tasksets :type plugin_manager: :param plugin_manager: a Plugin Manager instance. If None, a new Hook Manager is created :param task_class: :return: a tuple with two objects: the first being of type CourseFactory, the second of type TaskFactory

inginious.frontend.courses module

A course class with some modification for users

class inginious.frontend.courses.Course(courseid, content, taskset_factory, task_factory, plugin_manager, database)[source]

Bases: object

A course with some modification for users

allow_preview()[source]
allow_unregister(plugin_override=True)[source]

Returns True if students can unregister from course

can_students_choose_group()[source]

Returns True if the students can choose their groups

get_access_control_accept()[source]

Returns either True (accept) or False (deny), depending on the control type used to verify that users can register to the course

get_access_control_list()[source]

Returns the list of all users/emails/binding methods/… (see get_access_control_method) allowed by the AC list

Return type:

List[str]

get_access_control_method()[source]

Returns either None, “username”, “binding”, or “email”, depending on the method used to verify that users can register to the course

get_accessibility(plugin_override=True)[source]

Return the AccessibleTime object associated with the accessibility of this course

get_admins()[source]

Returns a list containing the usernames of the administrators of this course

get_course_user_settings()[source]
Returns:

The course user settings dictionary for a course.

get_description(language)[source]

Returns the course description

get_descriptor()[source]

Get (a copy) the description of the course

get_id()[source]

Return the _id of this course

get_name(language)[source]

Return the name of this course

get_registration_accessibility()[source]

Return the AccessibleTime object associated with the registration

get_registration_password()[source]

Returns the password needed for registration (None if there is no password)

get_tags()[source]
get_task(taskid)[source]

Returns a Task object

get_task_dispenser()[source]
Returns:

the structure of the course

get_tasks(ordered=False)[source]
get_taskset()[source]
get_translation_obj(language)[source]
gettext(language, text)[source]
is_lti()[source]

True if the current course is in LTI mode

is_open_to_non_staff()[source]

Returns true if the course is accessible by users that are not administrator of this course

is_password_needed_for_registration()[source]

Returns true if a password is needed for registration

is_registration_possible(user_info)[source]

Returns true if users can register for this course

is_user_accepted_by_access_control(user_info)[source]

Returns True if the user is allowed by the ACL

lti_keys()[source]

{name: key} for the LTI customers

lti_send_back_grade()[source]

True if the current course should send back grade to the LTI Tool Consumer

lti_url()[source]

Returns the URL to the external platform the course is hosted on

inginious.frontend.installer module

Custom installer for the web app

class inginious.frontend.installer.Installer(config_path=None, default=False)[source]

Bases: object

Custom installer for the WebApp frontend

ask_backend()[source]

Ask the user to choose the backend

configuration_filename()[source]

Returns the name of the configuration file

configure_authentication(database)[source]

Configure the authentication

configure_backup_directory()[source]

Configure backup directory

configure_misc()[source]

Configure various things

configure_mongodb()[source]

Configure MongoDB

configure_task_directory()[source]

Configure task directory

ldap_plugin()[source]

Configures the LDAP plugin

run()[source]

Run the installator

select_containers_to_build()[source]
support_remote_debugging()[source]

Returns True if the frontend supports remote debugging, False else

test_local_docker_conf()[source]

Test to connect to a local Docker daemon

try_mongodb_opts(host='localhost', database_name='INGInious')[source]

Try MongoDB configuration

inginious.frontend.parsable_text module

Tools to parse text

class inginious.frontend.parsable_text.CustomAdmonition(name, arguments, options, content, lineno, content_offset, block_text, state, state_machine)[source]

Bases: CustomBaseAdmonition

A custom admonition with a specific class if needed

node_class

alias of admonition

required_arguments = 1

Number of required directive arguments.

class inginious.frontend.parsable_text.CustomBaseAdmonition(name, arguments, options, content, lineno, content_offset, block_text, state, state_machine)[source]

Bases: BaseAdmonition

A custom admonition that can have a title

option_spec = {'class': <function class_option>, 'name': <function unchanged>, 'title': <function unchanged>}

Mapping of option names to validator functions.

class inginious.frontend.parsable_text.EmptiableCodeBlock(name, arguments, options, content, lineno, content_offset, block_text, state, state_machine)[source]

Bases: CodeBlock

run()[source]
class inginious.frontend.parsable_text.HiddenUntilDirective(name, arguments, options, content, lineno, content_offset, block_text, state, state_machine)[source]

Bases: Directive, object

has_content = True

May the directive have content?

option_spec = {}

Mapping of option names to validator functions.

optional_arguments = 1

Number of optional arguments after the required arguments.

required_arguments = 1

Number of required directive arguments.

run()[source]
class inginious.frontend.parsable_text.ParsableText(content, mode='rst', show_everything=False, translation=<gettext.NullTranslations object>)[source]

Bases: object

Allow to parse a string with different parsers

classmethod html(string, show_everything=False, translation=<gettext.NullTranslations object>)[source]

Parses HTML

original_content()[source]

Returns the original content

parse(debug=False)[source]

Returns parsed text

classmethod rst(string, show_everything=False, translation=<gettext.NullTranslations object>, initial_header_level=3, debug=False)[source]

Parses reStructuredText

inginious.frontend.plugin_manager module

Plugin Manager

class inginious.frontend.plugin_manager.PluginManager[source]

Bases: object

Registers an manage plugins. The init method inits only the Hook Manager; you have to call the method load() to start the plugins

add_hook(name, callback, prio=0)[source]

Add a new hook that can be called with the call_hook function. prio is the priority. Higher priority hooks are called before lower priority ones. This function does not enforce a particular order between hooks with the same priorities.

add_page(pattern, classname_or_viewfunc)[source]

Add a new page to the web application. Only available after that the Plugin Manager is loaded

add_task_file_manager(task_file_manager)[source]

Add a task file manager. Only available after that the Plugin Manager is loaded

call_hook(name, **kwargs)[source]

Call all hooks registered with this name. Returns a list of the returns values of the hooks (in the order the hooks were added)

call_hook_recursive(name, **kwargs)[source]

Call all hooks registered with this name. Each hook receives as arguments the return value of the previous hook call, or the initial params for the first hook. As such, each hook must return a dictionary with the received (eventually modified) args. Returns the modified args.

get_database()[source]

Returns the frontend database

get_submission_manager()[source]

Returns the submission manager

get_user_manager()[source]

Returns the user manager

load(client, flask_app, course_factory, task_factory, database, user_manager, submission_manager, config)[source]

Loads the plugin manager. Must be done after the initialisation of the client

register_auth_method(auth_method)[source]

Register a new authentication method

name

the name of the authentication method, typically displayed by the webapp

input_to_display

Only available after that the Plugin Manager is loaded

exception inginious.frontend.plugin_manager.PluginManagerNotLoadedException[source]

Bases: Exception

inginious.frontend.submission_manager module

Manages submissions

class inginious.frontend.submission_manager.WebAppSubmissionManager(client, user_manager, database, gridfs, plugin_manager, lti_outcome_manager)[source]

Bases: object

Manages submissions. Communicates with the database and the client.

add_job(course, task, inputdata, task_dispenser, debug=False)[source]

Add a job in the queue and returns a submission id. :type task: :param task: Task instance :type task: inginious.frontend.tasks.Task :type inputdata: :param inputdata: the input as a dictionary :type inputdata: dict :type debug: :param debug: If debug is true, more debug data will be saved :type debug: bool or string :returns: the new submission id and the removed submission id

get_available_environments()[source]

:return a list of available environments

Return type:

Dict[str, List[str]]

get_feedback_from_submission(submission, only_feedback=False, show_everything=False, translation=<gettext.NullTranslations object>)[source]

Get the input of a submission. If only_input is False, returns the full submissions with a dictionnary object at the key “input”. Else, returns only the dictionnary.

If show_everything is True, feedback normally hidden is shown.

get_gridfs()[source]

Returns the GridFS used by the submission manager

get_input_from_submission(submission, only_input=False)[source]

Get the input of a submission. If only_input is False, returns the full submissions with a dictionnary object at the key “input”. Else, returns only the dictionnary.

get_job_queue_info(jobid)[source]

Get job queue info :type jobid: :param jobid: the JOB id (not the submission id!). You should retrieve it before calling this function by calling get_submission(...)["job_id"]. :return: If the submission is in the queue, then returns a tuple (nb tasks before running (or -1 if running), approx wait time in seconds) Else, returns None

get_job_queue_snapshot()[source]

Get a snapshot of the remote backend job queue. May be a cached version. May not contain recent jobs. May return None if no snapshot is available

Returns:

a tuple of two lists (None, None):

  • jobs_running : a list of tuples in the form (job_id, is_current_client_job, info, launcher, started_at, max_time) where

    • job_id is a job id. It may be from another client.

    • is_current_client_job is a boolean indicating if the client that asked the request has started the job

    • agent_name is the agent name

    • info is “courseid/taskid”

    • launcher is the name of the launcher, which may be anything

    • started_at the time (in seconds since UNIX epoch) at which the job started

    • max_time the maximum time that can be used, or -1 if no timeout is set

  • jobs_waiting : a list of tuples in the form (job_id, is_current_client_job, info, launcher, max_time) where

    • job_id is a job id. It may be from another client.

    • is_current_client_job is a boolean indicating if the client that asked the request has started the job

    • info is “courseid/taskid”

    • launcher is the name of the launcher, which may be anything

    • max_time the maximum time that can be used, or -1 if no timeout is set

get_submission(submissionid, user_check=True)[source]

Get a submission from the database

get_submission_archive(course, submissions, sub_folders, archive_file=None, simplify=False)[source]
Parameters:
  • course – the course object linked to the submission

  • submissions – a list of submissions

  • sub_folders

    a list of folders in which to place the submission. For example, [“taskid”, “submissionid”] place each submission inside a folder taskid/submissionid/ (with taskid replaced with the actual task id, the same being true for submissionid). The possible values are: - “taskid”: replaced by the task id - “submissionid”: replaced by the submission id - “audience”: replaced by the name of the audience “audiencedesc_(audienceid)” - “group”: replaced by the list of username who submitted - “username”: replaced by the username Some of these (like “username” and “audience”) are not unique for a submission. If they are multiple answers possible, the files are duplicated at multiple locations.

    For example: given a submission #9083081 by the group [“a”, “b”], and a sub_folders value of [“username”, “submissionid”], the archive will contain two folders: - a/9083081/ - b/9083081/

Returns:

a file-like object containing a tgz archive of all the submissions

get_user_last_submissions(limit=5, mongo_request=None)[source]

Get last submissions of a user

get_user_submissions(course, task)[source]

Get all the user’s submissions for a given task

is_done(submissionid_or_submission, user_check=True)[source]

Tells if a submission is done and its result is available

is_running(submissionid, user_check=True)[source]

Tells if a submission is running/in queue

kill_running_submission(submissionid, user_check=True)[source]

Attempt to kill the remote job associated with this submission id. :type submissionid: :param submissionid: :type user_check: :param user_check: Check if the current user owns this submission :return: True if the message asking to kill the job was sent, False if an error occurred

replay_job(course, task, submission, task_dispenser, copy=False, debug=False)[source]

Replay a submission: add the same job in the queue, keeping submission id, submission date and input data :type submission: :param submission: Submission to replay :type copy: :param copy: If copy is true, the submission will be copied to admin submissions before replay :type debug: :param debug: If debug is true, more debug data will be saved

user_is_submission_owner(submission)[source]

Returns true if the current user is the owner of this jobid, false else

inginious.frontend.submission_manager.update_pending_jobs(database)[source]

Updates pending jobs status in the database

inginious.frontend.task_problems module

Displayable problems

class inginious.frontend.task_problems.DisplayableCodeProblem(problemid, content, translations, taskfs)[source]

Bases: CodeProblem, DisplayableProblem

A basic class to display all BasicCodeProblem derivatives

adapt_input_for_backend(input_data)[source]

Adapt the input from web.py for the inginious.backend

classmethod get_type_name(language)[source]
classmethod show_editbox(template_helper, key, language)[source]

get the edit box html for this problem

classmethod show_editbox_templates(template_helper, key, language)[source]
show_input(template_helper, language, seed)[source]

Show BasicCodeProblem and derivatives

class inginious.frontend.task_problems.DisplayableCodeSingleLineProblem(problemid, content, translations, taskfs)[source]

Bases: CodeSingleLineProblem, DisplayableProblem

A displayable single code line problem

adapt_input_for_backend(input_data)[source]

Adapt the input from web.py for the inginious.backend

classmethod get_type_name(language)[source]
classmethod show_editbox(template_helper, key, language)[source]

get the edit box html for this problem

classmethod show_editbox_templates(template_helper, key, language)[source]
show_input(template_helper, language, seed)[source]

Show InputBox

class inginious.frontend.task_problems.DisplayableFileProblem(problemid, content, translations, taskfs)[source]

Bases: FileProblem, DisplayableProblem

A displayable code problem

adapt_input_for_backend(input_data)[source]

Adapt the input from web.py for the inginious.backend

classmethod get_type_name(language)[source]
classmethod show_editbox(template_helper, key, language)[source]

get the edit box html for this problem

classmethod show_editbox_templates(template_helper, key, language)[source]
show_input(template_helper, language, seed)[source]

Show FileBox

class inginious.frontend.task_problems.DisplayableMatchProblem(problemid, content, translations, taskfs)[source]

Bases: MatchProblem, DisplayableProblem

A displayable match problem

classmethod get_type_name(language)[source]
classmethod show_editbox(template_helper, key, language)[source]

get the edit box html for this problem

classmethod show_editbox_templates(template_helper, key, language)[source]
show_input(template_helper, language, seed)[source]

Show MatchProblem

class inginious.frontend.task_problems.DisplayableMultipleChoiceProblem(problemid, content, translations, taskfs)[source]

Bases: MultipleChoiceProblem, DisplayableProblem

A displayable multiple choice problem

classmethod get_type_name(language)[source]
classmethod show_editbox(template_helper, key, language)[source]

get the edit box html for this problem

classmethod show_editbox_templates(template_helper, key, language)[source]
show_input(template_helper, language, seed)[source]

Show multiple choice problems

class inginious.frontend.task_problems.DisplayableProblem(problemid, content, translations, taskfs)[source]

Bases: Problem

Basic problem

adapt_input_for_backend(input_data)[source]

Adapt the input from web.py for the inginious.backend

abstract classmethod get_type_name(language)[source]
abstract classmethod show_editbox(template_helper, key, language)[source]

get the edit box html for this problem

abstract classmethod show_editbox_templates(template_helper, key, language)[source]
abstract show_input(template_helper, language, seed)[source]

get the html for this problem

inginious.frontend.task_problems.get_default_displayable_problem_types()[source]

Get the mapping of default DisplayableProblem types available by inspecting the current module.

Return type:

dict

Returns:

The mapping of problem name and problem class.

inginious.frontend.task_problems.get_displayable_problem_types(name)[source]

Get the mapping of DisplayableProblem types available by inspecting a given module.

Parameters:

name (str) – The name of the module to inspect.

Return type:

dict

Returns:

The mapping of problem name and problem class.

inginious.frontend.task_factory module

Factory for loading tasks from disk

class inginious.frontend.task_factory.TaskFactory(filesystem, plugin_manager, task_problem_types)[source]

Bases: object

Load tasks from disk

add_custom_task_file_manager(task_file_manager)[source]

Add a custom task file manager

add_problem_type(problem_type)[source]
Parameters:

problem_type – Problem class

create_task(taskset, taskid, init_content)[source]

Create a new taskset folder and set initial descriptor content, folder can already exist :type taskset: :param taskset: a Course object :type taskid: :param taskid: the task id of the task :type init_content: :param init_content: initial descriptor content :raise: InvalidNameException or TaskAlreadyExistsException

delete_all_possible_task_files(tasksetid, taskid)[source]

Deletes all possibles task files in directory, to allow to change the format

delete_task(tasksetid, taskid)[source]

Erase the content of the task folder :type tasksetid: :param tasksetid: the taskset id of the taskset :type taskid: :param taskid: the task id of the task :raise: InvalidNameException or CourseNotFoundException

get_all_tasks(taskset)[source]
Returns:

a table containing taskid=>Task pairs

get_available_task_file_extensions()[source]

Get a list of all the extensions possible for task descriptors

get_problem_types()[source]

Returns the supported problem types by this task factory

get_readable_tasks(taskset)[source]

Returns the list of all available tasks in a taskset

get_task(taskset, taskid)[source]
Parameters:
  • taskset – a Course object

  • taskid – the task id of the task

Raise:

InvalidNameException, TaskNotFoundException, TaskUnreadableException

Returns:

an object representing the task, of the type given in the constructor

get_task_descriptor_content(tasksetid, taskid)[source]
Parameters:
  • tasksetid – the taskset id of the taskset

  • taskid – the task id of the task

Raise:

InvalidNameException, TaskNotFoundException, TaskUnreadableException

Returns:

the content of the task descriptor, as a dict

get_task_descriptor_extension(tasksetid, taskid)[source]
Parameters:
  • tasksetid – the taskset id of the taskset

  • taskid – the task id of the task

Raise:

InvalidNameException, TaskNotFoundException

Returns:

the current extension of the task descriptor

get_task_fs(tasksetid, taskid)[source]
Parameters:
  • tasksetid – the taskset id of the taskset

  • taskid – the task id of the task

Raise:

InvalidNameException

Returns:

A FileSystemProvider to the folder containing the task files

set_problem_types(problem_types)[source]

Set the problem types for the current TaskFactory.

Parameters:

problem_types – A mapping of problem types and their associated name.

update_cache_for_taskset(tasksetid)[source]

Clean/update the cache of all the tasks for a given taskset (id) :type tasksetid: :param tasksetid:

update_task_descriptor_content(tasksetid, taskid, content, force_extension=None)[source]

Update the task descriptor with the dict in content :type tasksetid: :param tasksetid: the taskset id of the taskset :type taskid: :param taskid: the task id of the task :type content: :param content: the content to put in the task file :type force_extension: :param force_extension: If None, save it the same format. Else, save with the given extension :raise InvalidNameException, TaskNotFoundException, TaskUnreadableException

inginious.frontend.tasks module

Classes modifying basic tasks, problems and boxes classes

class inginious.frontend.tasks.Task(taskset, taskid, content, plugin_manager, task_problem_types)[source]

Bases: object

A task that stores additional context information, specific to the web app

adapt_input_for_backend(input_data)[source]

Adapt the input from web.py for the inginious.backend

get_authors(language)[source]

Return the list of this task’s authors

get_contact_url(_language)[source]

Return the contact link format string for this task

get_context(language)[source]

Get the context(description) of this task

get_dispenser_settings(fields)[source]

Fetch the legacy config fields now used by task dispensers

get_environment_id()[source]

Returns the environment in which the agent have to launch this task

get_environment_parameters()[source]

Returns the raw environment parameters, which is a dictionnary that is envtype dependent.

get_environment_type()[source]

Returns the environment type in which the agent have to launch this task

get_fs()[source]

Returns a FileSystemProvider which points to the folder of this task

get_hook()[source]

Returns the hook manager parameter for this task

get_id()[source]

Get the id of this task

get_name(language)[source]

Returns the name of this task

get_number_input_random()[source]

Return the number of random inputs

get_problems()[source]

Get problems contained in this task

get_problems_dict()[source]

Get problems dict contained in this task

get_response_type()[source]

Returns the method used to parse the output of the task: HTML or rst

get_translation_fs()[source]

Return the translation_fs parameter for this task

get_translation_obj(language)[source]
gettext(language, text)[source]
input_is_consistent(task_input, default_allowed_extension, default_max_size)[source]

Check if an input for a task is consistent. Return true if this is case, false else

regenerate_input_random()[source]

Indicates if random inputs should be regenerated

inginious.frontend.template_helper module

TemplateManager

class inginious.frontend.template_helper.TemplateHelper(plugin_manager, user_manager, use_minified=True)[source]

Bases: object

Class accessible from templates that calls function defined in the Python part of the code.

add_css(link)[source]

Add a css file to load

add_javascript(link, position='footer')[source]

Add a javascript file to load. Position can either be “header” or “footer”

add_other(name, func)[source]

Add another callback to the template helper

add_to_template_globals(name, value)[source]

Add a variable to will be accessible in the templates

call(name, **kwargs)[source]
is_lti()[source]

True if the current session is an LTI one

render(path, template_folder='', **tpl_kwargs)[source]

Parse the Jinja template named “path” and render it with args *tpl_args and **tpl_kwargs :type path: :param path: Path of the template, relative to the base folder :type template_folder: :param template_folder: add the specified folder to the templates PATH. :type tpl_kwargs: :param tpl_kwargs: named args sent to the template :return: the rendered template, as a str

inginious.frontend.user_manager module

Manages users data and session

exception inginious.frontend.user_manager.AuthInvalidInputException[source]

Bases: Exception

exception inginious.frontend.user_manager.AuthInvalidMethodException[source]

Bases: Exception

class inginious.frontend.user_manager.AuthMethod[source]

Bases: object

abstract callback(auth_storage)[source]
Parameters:

auth_storage – The session auth method storage dict

Returns:

User tuple and , or None, if failed

Parameters:

auth_storage – The session auth method storage dict

Returns:

The authentication link

abstract get_id()[source]
Returns:

The auth method id

Returns:

The image link

abstract get_name()[source]
Returns:

The name of the auth method, to be displayed publicly

class inginious.frontend.user_manager.UserInfo(realname, email, username, bindings, language, activated)

Bases: tuple

activated

Alias for field number 5

bindings

Alias for field number 3

email

Alias for field number 1

language

Alias for field number 4

realname

Alias for field number 0

username

Alias for field number 2

class inginious.frontend.user_manager.UserManager(database, superadmins)[source]

Bases: object

activate_user(activate_hash)[source]

Active a user based on his/her activation hash :type activate_hash: :param activate_hash: The activation hash of a user :return A boolean if the user was found and updated

attempt_lti_login()[source]

Given that the current session is an LTI one (session_lti_info does not return None), attempt to find an INGInious user linked to this lti username/consumer_key. If such user exists, logs in using it.

Returns True (resp. False) if the login was successful

auth_user(username, password, do_connect=True)[source]

Authenticate the user in database :type username: :param username: Username/Login :type password: :param password: User password :type do_connect: :param do_connect: indicates if the user must be connected after authentification, True by default :return: Returns a dict representing the user, or None if the authentication was not successful

bind_user(auth_id, user)[source]

Add a binding method to a user :type auth_id: :param auth_id: The binding method id :type user: :param user: User object :return: Boolean if method has been add

connect_user(username, realname, email, language, tos_accepted)[source]

Opens a session for the user

Parameters:
  • username – Username

  • realname – User real name

  • email – User email

course_is_open_to_user(course, username=None, lti=None, return_reason=False)[source]

Checks if a user is can access a course

Parameters:
  • course – a Course object

  • username – The username of the user that we want to check. If None, uses self.session_username()

  • lti

    indicates if the user is currently in a LTI session or not.

    • None to ignore the check

    • True to indicate the user is in a LTI session

    • False to indicate the user is not in a LTI session

    • ”auto” to enable the check and take the information from the current session

  • return_reason

    instead of False, returns a string indicating for which reason the course is not open to the user. Reasons may be :

    • ”closed” if the course is not open

    • ”unregistered_not_previewable” user is not registered and course is not previewable

    • ”lti_only” the current session is not a LTI session and this course requires at LTI session

    • ”lti_not_registered” this LTI course can be accessed outside an LTI session only if the user register first via the LTI interface

Returns:

True if the user can access the course, False (or the reason if return_reason is True) otherwise

course_is_user_registered(course, username=None)[source]

Checks if a user is registered

Parameters:
  • course – a Course object

  • username – The username of the user that we want to check. If None, uses self.session_username()

Returns:

True if the user is registered, False else

course_register_user(course, username=None, password=None, force=False)[source]

Register a user to the course

Parameters:
  • course – a Course object

  • username – The username of the user that we want to register. If None, uses self.session_username()

  • password – Password for the course. Needed if course.is_password_needed_for_registration() and force != True

  • force – Force registration

Returns:

True if the registration succeeded, False else

course_unregister_user(course_id, username=None)[source]

Unregister a user to the course :type course_id: :param course_id: a course id :type username: :param username: The username of the user that we want to unregister. If None, uses self.session_username()

create_lti_session(user_id, roles, realname, email, course_id, task_id, consumer_key, outcome_service_url, outcome_result_id, tool_name, tool_desc, tool_url, context_title, context_label)[source]

Creates an LTI cookieless session. Returns the new session id

create_user(values)[source]

Create a new user :type values: :param values: Dictionary of fields :return: An error message if something went wrong else None

delete_user(username, confirmation_email=None)[source]

Delete a user based on username :type username: :param username: the username of the user :type confirmation_email: :param confirmation_email: An email to confirm suppression. May be None :return a boolean if a user was deleted

disconnect_user()[source]

Disconnects the user currently logged-in

classmethod generate_api_key()[source]
get_auth_method(auth_method_id)[source]

:param the auth method id, as provided by get_auth_methods_inputs() :return: AuthMethod if it exists, otherwise None

get_auth_methods()[source]
Returns:

The auth methods dict

get_course_audiences(course)[source]

Returns a list of the course audiences

get_course_audiences_per_student(course)[source]

Returns a dictionnary mapping student -> list of audiences it belongs to, for a given course

get_course_cache(username, course)[source]
Parameters:
  • username – The username

  • course – A Course object

Returns:

a dict containing info about the course, in the form:

{"task_tried": 0, "total_tries": 0, "task_succeeded": 0, "task_grades":{"task_1": 100.0, "task_2": 0.0, ...}}

Note that only the task already seen at least one time will be present in the dict task_grades.

get_course_caches(usernames, course)[source]
Parameters:
  • usernames – List of username for which we want info. If usernames is None, data from all users will be returned.

  • course – A Course object

Returns:

Returns data of the specified users for a specific course. users is a list of username.

The returned value is a dict:

{"username": {"task_tried": 0, "total_tries": 0, "task_succeeded": 0, "task_grades":{"task_1": 100.0, "task_2": 0.0, ...}}}

Note that only the task already seen at least one time will be present in the dict task_grades.

get_course_groups(course)[source]

Returns a list of the course groups

get_course_registered_users(course, with_admins=True)[source]

Get all the users registered to a course :type course: :param course: a Course object :type with_admins: :param with_admins: include admins? :return: a list of usernames that are registered to the course

get_course_user_group(course, username=None)[source]

Returns the audience whose username belongs to :type course: :param course: a Course object :type username: :param username: The username of the user that we want to register. If None, uses self.session_username() :return: the audience description

get_course_user_settings(username, course)[source]
get_task_cache(username, courseid, taskid)[source]

Shorthand for get_task_caches([username], courseid, taskid)[username]

get_task_caches(usernames, courseid, taskid)[source]
Parameters:
  • usernames – List of username for which we want info. If usernames is None, data from all users will be returned.

  • courseid – the course id

  • taskid – the task id

Returns:

A dict in the form:

{
    "username": {
        "courseid": courseid,
        "taskid": taskid,
        "tried": 0,
        "succeeded": False,
        "grade": 0.0
    }
}

get_user_activate_hash(username)[source]

Get activate hash for a user :return the activate hash

get_user_api_key(username, create=True)[source]

Get the API key of a given user. API keys are generated on demand. :type username: :param username: :type create: :param create: Create the API key if none exists yet :return: the API key assigned to the user, or None if none exists and create is False.

get_user_email(username)[source]
Parameters:

username

Returns:

the email of the user if it can be found, None else

get_user_info(username)[source]
Parameters:

username

Return type:

Optional[UserInfo]

Returns:

a tuple (realname, email) if the user can be found, None else

get_user_realname(username)[source]
Parameters:

username

Returns:

the real name of the user if it can be found, None else

get_users_count()[source]
get_users_info(usernames, limit=0, skip=0)[source]
Parameters:

usernames – a list of usernames

:param limit A limit of users requested :param skip A quantity of users to skip :rtype: Dict[str, Optional[UserInfo]] :return: a dict, in the form {username: val}, where val is either None if the user cannot be found, or a UserInfo. If the list of usernames is empty, return an empty dict.

has_admin_rights_on_course(course, username=None, include_superadmins=True)[source]

Check if a user can be considered as having admin rights for a course :type course: inginious.frontend.courses.Course :type username: :param username: the username. If None, the username of the currently logged in user is taken :type include_superadmins: :param include_superadmins: Boolean indicating if superadmins should be taken into account :return: True if the user has admin rights, False else

classmethod hash_password(content)[source]

Encapsulates the other password hashing functions :type content: :param content: a str input :return a hash of str input

classmethod hash_password_argon2id(content)[source]
Parameters:

content – a str input

:return a hash of str input

classmethod hash_password_sha512(content)[source]
Parameters:

content – a str input

:return a hash of str input

is_user_activated(username)[source]

Verify if user is activated :type username: :param username: Username/Login :return Returns a boolean with value of activation

register_auth_method(auth_method)[source]

Registers an authentication method :type auth_method: :param auth_method: an AuthMethod object

reset_user_task_state(courseid, taskid, username)[source]
revoke_binding(username, binding_id)[source]

Revoke a binding method for a user :type binding_id: :param binding_id: The binding method id :type username: :param username: username of the user :return: Boolean if error occurred and message if necessary

classmethod sanitize_email(email)[source]

Sanitize an email address and put the bar part of an address foo@bar in lower case.

Return type:

str

session_api_key()[source]

Returns the API key for the current user. Created on first demand.

session_auth_storage()[source]

Returns the oauth state for login

session_cookieless()[source]

Indicates if the current session is cookieless

session_email()[source]

Returns the email of the current user in the session, if one is open. Else, returns None

session_id()[source]

Returns the current session id

session_language()[source]

Returns the current session language

session_logged_in()[source]

Returns True if a user is currently connected in this session, False else

session_lti_info()[source]

If the current session is an LTI one, returns a dict in the form

{
    "email": email,
    "username": username
    "realname": realname,
    "roles": roles,
    "task": (course_id, task_id),
    "outcome_service_url": outcome_service_url,
    "outcome_result_id": outcome_result_id,
    "consumer_key": consumer_key
}

where all these data where provided by the LTI consumer, and MAY NOT be equivalent to the data contained in database for the currently connected user.

If the current session is not an LTI one, returns None.

session_realname()[source]

Returns the real name of the current user in the session, if one is open. Else, returns None

session_token()[source]

Returns the token of the current user in the session, if one is open. Else, returns None

session_tos_signed()[source]

Returns True if the current user has signed the tos

session_username()[source]

Returns the username from the session, if one is open. Else, returns None

set_session_language(language)[source]
set_session_realname(realname)[source]

Sets the real name of the current user in the session, if one is open.

set_session_token(token)[source]

Sets the token of the current user in the session, if one is open.

set_session_tos_signed()[source]

Sets the real name of the current user in the session, if one is open.

task_can_user_submit(course, task, username=None, only_check=None, lti=None)[source]

returns true if the user can submit his work for this task :param only_check : only checks for ‘groups’, ‘tokens’, or None if all checks :type lti: :param lti: indicates if the user is currently in a LTI session or not. - None to ignore the check - True to indicate the user is in a LTI session - False to indicate the user is not in a LTI session - “auto” to enable the check and take the information from the current session

task_is_visible_by_user(course, task, username=None, lti=None)[source]

Returns true if the task is visible and can be accessed by the user

Parameters:

lti

indicates if the user is currently in a LTI session or not.

  • None to ignore the check

  • True to indicate the user is in a LTI session

  • False to indicate the user is not in a LTI session

  • ”auto” to enable the check and take the information from the current session

update_user_stats(username, course, task, submission, result_str, grade, state, newsub, task_dispenser)[source]

Update stats with a new submission

user_is_superadmin(username=None)[source]
Parameters:

username – the username. If None, the username of the currently logged in user is taken

Returns:

True if the user is superadmin, False else

user_saw_task(username, courseid, taskid)[source]

Set in the database that the user has viewed this task

verify_hash(db_hash, password, method='sha512')[source]

Verify a hash :type db_hash: :param db_hash: The hash to verify :type password: :param password: The password to verify :type method: :param method: The hash method :return: A boolean if the hash is correct

verify_hash_argon2id(db_hash, password)[source]
verify_hash_sha512(db_hash, password)[source]