Example #1
0
    def __init__(self, courseid):
        Course.__init__(self, courseid)

        if self._content.get('nofrontend', False):
            raise Exception("That course is not allowed to be displayed directly in the frontend")

        if "name" in self._content and "admins" in self._content and isinstance(self._content["admins"], list):
            self._name = self._content['name']
            self._admins = self._content['admins']
            self._accessible = AccessibleTime(self._content.get("accessible", None))
            self._registration = AccessibleTime(self._content.get("registration", None))
            self._registration_password = self._content.get('registration_password', None)
            self._registration_ac = self._content.get('registration_ac', None)
            if self._registration_ac not in [None, "username", "realname", "email"]:
                raise Exception("Course has an invalid value for registration_ac: " + courseid)
            self._registration_ac_list = self._content.get('registration_ac_list', [])
        else:
            raise Exception("Course has an invalid description: " + courseid)
Example #2
0
    def __init__(self, course, taskid, init_data=None):
        # We load the descriptor of the task here to allow plugins to modify settings of the task before it is read by the Task constructor
        if not id_checker(taskid):
            raise Exception("Task with invalid id: " + course.get_id() + "/" + taskid)
        if init_data is None:
            try:
                init_data = get_task_file_manager(course.get_id(), taskid).read()
            except Exception as inst:
                raise Exception("Error while reading task file: " + self._course.get_id() + "/" + self._taskid + " :\n" + str(inst))
        PluginManager.get_instance().call_hook('modify_task_data', course=course, taskid=taskid, data=init_data)

        # Now init the task
        common.tasks.Task.__init__(self, course, taskid, init_data)

        self._name = self._data.get('name', 'Task {}'.format(taskid))

        self._context = ParsableText(self._data.get('context', ""), "HTML" if self._data.get("contextIsHTML", False) else "rst")

        # Authors
        if isinstance(self._data.get('author'), basestring):  # verify if author is a string
            self._author = [self._data['author']]
        elif isinstance(self._data.get('author'), list):  # verify if author is a list
            for author in self._data['author']:
                if not isinstance(author, basestring):  # authors must be strings
                    raise Exception("This task has an invalid author")
            self._author = self._data['author']
        else:
            self._author = []

        # Grade weight
        self._weight = float(self._data.get("weight", 1.0))

        # _accessible
        self._accessible = AccessibleTime(self._data.get("accessible", None))

        # Order
        self._order = int(self._data.get('order', -1))
Example #3
0
class FrontendCourse(Course):
    """ A course with some modification for users """

    _task_class = FrontendTask

    def __init__(self, courseid):
        Course.__init__(self, courseid)

        if self._content.get('nofrontend', False):
            raise Exception("That course is not allowed to be displayed directly in the frontend")

        if "name" in self._content and "admins" in self._content and isinstance(self._content["admins"], list):
            self._name = self._content['name']
            self._admins = self._content['admins']
            self._tutors = self._content.get('tutors', [])
            self._accessible = AccessibleTime(self._content.get("accessible", None))
            self._registration = AccessibleTime(self._content.get("registration", None))
            self._registration_password = self._content.get('registration_password', None)
            self._registration_ac = self._content.get('registration_ac', None)
            if self._registration_ac not in [None, "username", "realname", "email"]:
                raise Exception("Course has an invalid value for registration_ac: " + courseid)
            self._registration_ac_list = self._content.get('registration_ac_list', [])
            self._groups = self._content.get("groups", False)
            self._groups_student_choice = self._content.get("groups_student_choice", False)
        else:
            raise Exception("Course has an invalid description: " + courseid)

    def get_name(self):
        """ Return the name of this course """
        return self._name

    def get_staff(self, with_superadmin=True):
        """ Returns a list containing the usernames of all the staff users """
        return list(set(self.get_tutors() + self.get_admins(with_superadmin)))

    def get_admins(self, with_superadmin=True):
        """ Returns a list containing the usernames of the administrators of this course """
        if with_superadmin:
            return list(set(self._admins + INGIniousConfiguration.get('superadmins', [])))
        else:
            return self._admins

    def get_tutors(self):
        """ Returns a list containing the usernames of the tutors assigned to this course """
        return self._tutors

    def is_open_to_non_staff(self):
        """ Returns true if the course is accessible by users that are not administrator of this course """
        return self._accessible.is_open()

    def is_open_to_user(self, username, check_group=False):
        """ Returns true if the course is open to this user """
        return (self._accessible.is_open() and self.is_user_registered(username, check_group)) or username in self.get_staff()

    def is_registration_possible(self, username):
        """ Returns true if users can register for this course """
        return self._accessible.is_open() and self._registration.is_open() and self.is_user_accepted_by_access_control(username)

    def is_password_needed_for_registration(self):
        """ Returns true if a password is needed for registration """
        return self._registration_password is not None

    def get_registration_password(self):
        """ Returns the password needed for registration (None if there is no password) """
        return self._registration_password

    def register_user(self, username, password=None, force=False):
        """ Register a user to the course. Returns True if the registration succeeded, False else. """
        if not force:
            if not self.is_registration_possible(username):
                return False
            if self.is_password_needed_for_registration() and self._registration_password != password:
                return False
        if self.is_open_to_user(username):
            return False  # already registered?
        get_database().registration.insert({"username": username, "courseid": self.get_id(), "date": datetime.now()})
        return True

    def unregister_user(self, username):
        """ Unregister a user from this course """
        get_database().registration.remove({"username": username, "courseid": self.get_id()})
        if self.is_group_course():
            get_database().groups.update({"course_id": self.get_id(), "users": username}, {"$pull":{"users": username}})

    def is_user_registered(self, username, check_group=False):
        """ Returns True if the user is registered """
        has_group = (not check_group) or \
                    (get_database().groups.find_one({"users": username, "course_id": self.get_id()}) is not None)

        return (get_database().registration.find_one({"username": username, "courseid": self.get_id()}) is not None)\
               and has_group or username in self.get_staff()

    def get_registered_users(self, with_admins=True):
        """ Get all the usernames that are registered to this course (in no particular order)"""
        l = [entry['username'] for entry in list(get_database().registration.find({"courseid": self.get_id()}, {"username": True, "_id": False}))]
        if with_admins:
            return list(set(l + self.get_staff()))
        else:
            return l

    def get_accessibility(self):
        """ Return the AccessibleTime object associated with the accessibility of this course """
        return self._accessible

    def get_registration_accessibility(self):
        """ Return the AccessibleTime object associated with the registration """
        return self._registration

    def get_user_completion_percentage(self, username=None):
        """ Returns the percentage (integer) of completion of this course by the current user (or username if it is not None)"""
        if username is None:
            import frontend.user as User

            username = User.get_username()
        cache = UserData(username).get_course_data(self.get_id())
        if cache is None:
            return 0
        if cache["total_tasks"] == 0:
            return 100
        return int(cache["task_succeeded"] * 100 / cache["total_tasks"])

    def get_user_grade(self, username=None):
        """ Return the grade (a floating-point number between 0 and 100) of the user (if username is None, it uses the currently logged-in user) """
        if username is None:
            import frontend.user as User

            username = User.get_username()
        cache = UserData(username).get_course_data(self.get_id())
        if cache is None:
            return 0
        total_weight = 0
        grade = 0

        for task_id, task in self.get_tasks().iteritems():
            if task.is_visible_by_user(username):
                total_weight += task.get_grading_weight()
                grade += cache["task_grades"].get(task_id, 0.0) * task.get_grading_weight()

        if total_weight == 0:
            return 0

        return grade / total_weight

    def get_user_last_submissions(self, limit=5, one_per_task=False):
        """ Returns a given number (default 5) of submissions of task from this course """
        from frontend.submission_manager import get_user_last_submissions as extern_get_user_last_submissions

        task_ids = []
        for task_id in self.get_tasks():
            task_ids.append(task_id)
        return extern_get_user_last_submissions({"courseid": self.get_id(), "taskid": {"$in": task_ids}}, limit, one_per_task)

    def get_tasks(self):
        return OrderedDict(sorted(Course.get_tasks(self).items(), key=lambda t: t[1].get_order()))

    def get_access_control_method(self):
        """ Returns either None, "username", "realname", or "email", depending on the method used to verify that users can register to the course """
        return self._registration_ac

    def get_access_control_list(self):
        """ Returns the list of all users allowed by the AC list """
        return self._registration_ac_list

    def get_user_group(self, username):
        """ Returns the group whose username belongs to """
        return get_database().groups.find_one({"course_id": self.get_id(), "users": username})

    def is_group_course(self):
        """ Returns True if the course submissions are made by groups """
        return self._groups

    def can_students_choose_group(self):
        """ Returns True if the students can choose their groups """
        return self._groups_student_choice

    def is_user_accepted_by_access_control(self, username):
        """ Returns True if the user is allowed by the ACL """
        if self.get_access_control_method() is None:
            return True
        elif self.get_access_control_method() == "username":
            return username in self.get_access_control_list()
        elif self.get_access_control_method() == "realname":
            return UserData(username).get_data()["realname"] in self.get_access_control_list()
        elif self.get_access_control_method() == "email":
            return UserData(username).get_data()["email"] in self.get_access_control_list()
        return False
Example #4
0
class FrontendTask(common.tasks.Task):

    """ A task that stores additionnal context informations """

    # Redefine _problem_types with displayable ones
    _problem_types = {
        "code": DisplayableCodeProblem,
        "code-file": DisplayableCodeFileProblem,
        "code-single-line": DisplayableCodeSingleLineProblem,
        "multiple-choice": DisplayableMultipleChoiceProblem,
        "match": DisplayableMatchProblem}

    def __init__(self, course, taskid, init_data=None):
        # We load the descriptor of the task here to allow plugins to modify settings of the task before it is read by the Task constructor
        if not id_checker(taskid):
            raise Exception("Task with invalid id: " + course.get_id() + "/" + taskid)
        if init_data is None:
            try:
                init_data = get_task_file_manager(course.get_id(), taskid).read()
            except Exception as inst:
                raise Exception("Error while reading task file: " + self._course.get_id() + "/" + self._taskid + " :\n" + str(inst))
        PluginManager.get_instance().call_hook('modify_task_data', course=course, taskid=taskid, data=init_data)

        # Now init the task
        common.tasks.Task.__init__(self, course, taskid, init_data)

        self._name = self._data.get('name', 'Task {}'.format(taskid))

        self._context = ParsableText(self._data.get('context', ""), "HTML" if self._data.get("contextIsHTML", False) else "rst")

        # Authors
        if isinstance(self._data.get('author'), basestring):  # verify if author is a string
            self._author = [self._data['author']]
        elif isinstance(self._data.get('author'), list):  # verify if author is a list
            for author in self._data['author']:
                if not isinstance(author, basestring):  # authors must be strings
                    raise Exception("This task has an invalid author")
            self._author = self._data['author']
        else:
            self._author = []

        # Grade weight
        self._weight = float(self._data.get("weight", 1.0))

        # _accessible
        self._accessible = AccessibleTime(self._data.get("accessible", None))

        # Order
        self._order = int(self._data.get('order', -1))

    def get_name(self):
        """ Returns the name of this task """
        return self._name

    def get_context(self):
        """ Get the context(description) of this task """
        return self._context

    def get_authors(self):
        """ Return the list of this task's authors """
        return self._author

    def get_order(self):
        """ Get the position of this task in the course """
        return self._order

    def get_grading_weight(self):
        """ Get the relative weight of this task in the grading """
        return self._weight

    def is_visible_by_students(self):
        """ Returns true if the task is accessible by all students that are not administrator of the course """
        return self.get_course().is_open_to_non_admin() and self._accessible.after_start()

    def is_visible_by_user(self, username=None):
        """ Returns true if the task is visible by the user """
        if username is None:
            import frontend.user as User
            username = User.get_username()
        return (self.get_course().is_open_to_user(username) and self._accessible.after_start()) or username in self.get_course().get_admins()

    def can_user_submit(self, username=None):
        """ returns true if the user can submit his work for this task """
        if username is None:
            import frontend.user as User
            username = User.get_username()
        return (self.get_course().is_open_to_user(username) and self._accessible.is_open()) or username in self.get_course().get_admins()

    def get_deadline(self):
        """ Returns a string containing the deadline for this task """
        if self._accessible.is_always_accessible():
            return "No deadline"
        elif self._accessible.is_never_accessible():
            return "It's too late"
        else:
            return self._accessible.get_end_date().strftime("%d/%m/%Y %H:%M:%S")

    def get_user_status(self):
        """ Returns "succeeded" if the current user solved this task, "failed" if he failed, and "notattempted" if he did not try it yet """
        import frontend.user as User  # insert here to avoid initialisation of session
        task_cache = User.get_data().get_task_data(self.get_course_id(), self.get_id())
        if task_cache is None:
            return "notviewed"
        if task_cache["tried"] == 0:
            return "notattempted"
        return "succeeded" if task_cache["succeeded"] else "failed"

    def get_user_grade(self):
        """ Returns the grade (a floating-point number between 0 and 100) of the student """
        import frontend.user as User  # insert here to avoid initialisation of session
        task_cache = User.get_data().get_task_data(self.get_course_id(), self.get_id())
        if task_cache is None:
            return 0.0
        return task_cache.get("grade", 0.0)

    def adapt_input_for_backend(self, input_data):
        """ Adapt the input from web.py for the backend """
        for problem in self._problems:
            input_data = problem.adapt_input_for_backend(input_data)
        return input_data