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, course_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. :param configuration: configuration dict :param tasks_fs: FileSystemProvider to the courses/tasks folders :param context: a ZMQ context :param course_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.course_factory module

Factory for loading courses from disk

class inginious.frontend.course_factory.CourseFactory(filesystem, task_factory, plugin_manager, task_dispensers, database)[source]

Bases: object

Load courses from disk

add_task_dispenser(task_dispenser)[source]
Parameters

task_dispenser – TaskDispenser class

create_course(courseid, init_content)[source]

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

delete_course(courseid)[source]

Erase the content of the course folder :param courseid: the course id of the course :raise: InvalidNameException or CourseNotFoundException

get_all_courses()[source]
Returns

a table containing courseid=>Course pairs

get_course(courseid)[source]
Parameters

courseid – the course id of the course

Raise

InvalidNameException, CourseNotFoundException, CourseUnreadableException

Returns

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

get_course_descriptor_content(courseid)[source]
Parameters

courseid – the course id of the course

Raise

InvalidNameException, CourseNotFoundException, CourseUnreadableException

Returns

the content of the dict that describes the course

get_course_fs(courseid)[source]
Parameters

courseid – the course id of the course

Returns

a FileSystemProvider pointing to the directory of the course

get_fs()[source]
Returns

a FileSystemProvider pointing to the task directory

get_task(courseid, taskid)[source]

Shorthand for CourseFactory.get_course(courseid).get_task(taskid) :param courseid: the course id of the course :param taskid: the task id of the task :raise InvalidNameException, CourseNotFoundException, CourseUnreadableException, TaskNotFoundException, TaskUnreadableException :return: an object representing the task, of the type given in the constructor

get_task_dispensers()[source]

Returns the supported task dispensers by this course factory

get_task_factory()[source]
Returns

the associated task factory

update_course_descriptor_content(courseid, content)[source]

Updates the content of the dict that describes the course :param courseid: the course id of the course :param content: the new dict that replaces the old content :raise InvalidNameException, CourseNotFoundException

update_course_descriptor_element(courseid, key, value)[source]

Updates the value for the key in the dict that describes the course :param courseid: the course id of the course :param key: the element to change in the dict :param value: the new value that replaces the old one :raise InvalidNameException, CourseNotFoundException

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

Shorthand for creating Factories :param fs_provider: A FileSystemProvider leading to the courses :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, course_fs, task_factory, plugin_manager, task_dispensers, 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_description(language)[source]

Returns the course description

get_descriptor()[source]

Get (a copy) the description of the course

get_fs()[source]

Returns a FileSystemProvider which points to the folder of this 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_staff()[source]

Returns a list containing the usernames of all the staff users

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_translation_obj(language)[source]
get_tutors()[source]

Returns a list containing the usernames of the tutors assigned to this course

gettext(language, *args, **kwargs)[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)[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: inginious.frontend.parsable_text.CustomBaseAdmonition

A custom admonition with a specific class if needed

node_class

alias of docutils.nodes.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: docutils.parsers.rst.directives.admonitions.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: docutils.parsers.rst.directives.body.CodeBlock

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

Bases: docutils.parsers.rst.Directive, object

has_content = True

May the directive have content?

option_spec = {}

Mapping of option names to validator functions.

optional_arguments = 0

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(task, inputdata, debug=False)[source]

Add a job in the queue and returns a submission id. :param task: Task instance :type task: inginious.frontend.tasks.Task :param inputdata: the input as a dictionary :type inputdata: dict :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 :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(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. :param submissionid: :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(task, submission, copy=False, debug=False)[source]

Replay a submission: add the same job in the queue, keeping submission id, submission date and input data :param submission: Submission to replay :param copy: If copy is true, the submission will be copied to admin submissions before replay :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

Displyable problems

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

Bases: inginious.common.tasks_problems.CodeProblem, inginious.frontend.task_problems.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: inginious.common.tasks_problems.CodeSingleLineProblem, inginious.frontend.task_problems.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: inginious.common.tasks_problems.FileProblem, inginious.frontend.task_problems.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: inginious.common.tasks_problems.MatchProblem, inginious.frontend.task_problems.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: inginious.common.tasks_problems.MultipleChoiceProblem, inginious.frontend.task_problems.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: inginious.common.tasks_problems.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_factory module

Factory for loading tasks from disk

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

Bases: object

Load courses 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(course, taskid, init_content)[source]

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

delete_all_possible_task_files(courseid, taskid)[source]

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

delete_task(courseid, taskid)[source]

Erase the content of the task folder :param courseid: the course id of the course :param taskid: the task id of the task :raise: InvalidNameException or CourseNotFoundException

get_all_tasks(course)[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(course)[source]

Returns the list of all available tasks in a course

get_task(course, taskid)[source]
Parameters
  • course – 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(courseid, taskid)[source]
Parameters
  • courseid – the course id of the course

  • 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(courseid, taskid)[source]
Parameters
  • courseid – the course id of the course

  • taskid – the task id of the task

Raise

InvalidNameException, TaskNotFoundException

Returns

the current extension of the task descriptor

get_task_fs(courseid, taskid)[source]
Parameters
  • courseid – the course id of the course

  • taskid – the task id of the task

Raise

InvalidNameException

Returns

A FileSystemProvider to the folder containing the task files

update_cache_for_course(courseid)[source]

Clean/update the cache of all the tasks for a given course (id) :param courseid:

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

Update the task descriptor with the dict in content :param courseid: the course id of the course :param taskid: the task id of the task :param content: the content to put in the task file :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(course, taskid, content, filesystem, 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_accessible_time(plugin_override=True)[source]

Get the accessible time of this task

get_authors(language)[source]

Return the list of this task’s authors

get_categories()[source]

Returns the tags id associated to the task

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_course()[source]

Return the course that contains this task

get_course_id()[source]

Return the courseid of the course that contains this task

get_deadline()[source]

Returns a string containing the deadline for this task

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_evaluate()[source]

Indicates the default download for the task

get_fs()[source]

Returns a FileSystemProvider which points to the folder of this task

get_grading_weight()[source]

Get the relative weight of this task in the grading

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_stored_submissions()[source]

Indicates if only the last submission must be stored for the task

get_submission_limit()[source]

Returns the submission limits et for the task

get_translation_fs()[source]

Return the translation_fs parameter for this task

get_translation_obj(language)[source]
gettext(language, *args, **kwargs)[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

is_group_task()[source]

Indicates if the task submission mode is per groups

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 :param path: Path of the template, relative to the base folder :param template_folder: add the specified folder to the templates PATH. :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 allow_share()[source]
Returns

True if the auth method allow sharing, else false

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

abstract share(auth_storage, course, task, submission, language)[source]
Parameters

auth_storage – The session auth method storage dict

Returns

False if error

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 :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)[source]

Authenticate the user in database :param username: Username/Login :param password: User password :return: Returns a dict representing the user

bind_user(auth_id, user)[source]

Add a binding method to a user :param auth_id: The binding method id :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 :param course_id: a course id :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 :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 :param username: the username of the user :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 :param course: a Course object :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 :param course: a Course object :param username: The username of the user that we want to register. If None, uses self.session_username() :return: the audience description

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. :param username: :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 :param username: the username. If None, the username of the currently logged in user is taken :param include_superadmins: Boolean indicating if superadmins should be taken into account :return: True if the user has admin rights, False else

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

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

classmethod hash_password(content)[source]
Parameters

content – a str input

:return a hash of str input

is_user_activated(username)[source]

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

register_auth_method(auth_method)[source]

Registers an authentication 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 :param binding_id: The binding method id :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(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 :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(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, task, submission, result_str, grade, state, newsub)[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