Пример #1
0
    def update_task_descriptor_content(self, courseid, taskid, content, force_extension=None):
        """
        Update the task descriptor with the dict in content
        :param course: 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
        """
        if not id_checker(courseid):
            raise InvalidNameException("Course with invalid name: " + courseid)
        if not id_checker(taskid):
            raise InvalidNameException("Task with invalid name: " + taskid)

        if force_extension is None:
            path_to_descriptor, _, descriptor_manager = self._get_task_descriptor_info(courseid, taskid)
        elif force_extension in self.get_available_task_file_extensions():
            path_to_descriptor = os.path.join(self._tasks_directory, courseid, taskid, "task." + force_extension)
            descriptor_manager = self._task_file_managers[force_extension]
        else:
            raise TaskReaderNotFoundException()

        try:
            with codecs.open(path_to_descriptor, 'w', 'utf-8') as fd:
                fd.write(descriptor_manager.dump(content))
        except:
            raise TaskNotFoundException()
Пример #2
0
 def get_directory_path(self, courseid, taskid):
     """
     :param courseid: the course id of the course
     :param taskid: the task id of the task
     :raise InvalidNameException
     :return: The path to the directory that contains the files related to the task
     """
     if not id_checker(courseid):
         raise InvalidNameException("Course with invalid name: " + courseid)
     if not id_checker(taskid):
         raise InvalidNameException("Task with invalid name: " + taskid)
     return os.path.join(self._tasks_directory, courseid, taskid)
Пример #3
0
 def get_task_fs(self, courseid, taskid):
     """
     :param courseid: the course id of the course
     :param taskid: the task id of the task
     :raise InvalidNameException
     :return: A FileSystemProvider to the folder containing the task files
     """
     if not id_checker(courseid):
         raise InvalidNameException("Course with invalid name: " + courseid)
     if not id_checker(taskid):
         raise InvalidNameException("Task with invalid name: " + taskid)
     return self._filesystem.from_subfolder(courseid).from_subfolder(taskid)
Пример #4
0
 def delete_all_possible_task_files(self, courseid, taskid):
     """ Deletes all possibles task files in directory, to allow to change the format """
     if not id_checker(courseid):
         raise InvalidNameException("Course with invalid name: " + courseid)
     if not id_checker(taskid):
         raise InvalidNameException("Task with invalid name: " + taskid)
     task_fs = self.get_task_fs(courseid, taskid)
     for ext in self.get_available_task_file_extensions():
         try:
             task_fs.delete("task." + ext)
         except:
             pass
Пример #5
0
 def get_directory_path(self, courseid, taskid):
     """
     :param courseid: the course id of the course
     :param taskid: the task id of the task
     :raise InvalidNameException
     :return: The path to the directory that contains the files related to the task
     """
     if not id_checker(courseid):
         raise InvalidNameException("Course with invalid name: " + courseid)
     if not id_checker(taskid):
         raise InvalidNameException("Task with invalid name: " + taskid)
     return os.path.join(self._tasks_directory, courseid, taskid)
Пример #6
0
 def get_task_descriptor_extension(self, courseid, taskid):
     """
         :param courseid: the course id of the course
         :param taskid: the task id of the task
         :raise InvalidNameException, TaskNotFoundException
         :return: the current extension of the task descriptor
         """
     if not id_checker(courseid):
         raise InvalidNameException("Course with invalid name: " + courseid)
     if not id_checker(taskid):
         raise InvalidNameException("Task with invalid name: " + taskid)
     _, descriptor_ext, _2 = self._get_task_descriptor_info(courseid, taskid)
     return descriptor_ext
Пример #7
0
 def get_task_descriptor_extension(self, courseid, taskid):
     """
         :param courseid: the course id of the course
         :param taskid: the task id of the task
         :raise InvalidNameException, TaskNotFoundException
         :return: the current extension of the task descriptor
         """
     if not id_checker(courseid):
         raise InvalidNameException("Course with invalid name: " + courseid)
     if not id_checker(taskid):
         raise InvalidNameException("Task with invalid name: " + taskid)
     descriptor_path = self._get_task_descriptor_info(courseid, taskid)[0]
     return splitext(descriptor_path)[1]
Пример #8
0
    def GET_AUTH(self, courseid, taskid):  # pylint: disable=arguments-differ
        """ Edit a task """
        if not id_checker(taskid):
            raise Exception("Invalid task id")

        course, __ = self.get_course_and_check_rights(courseid,
                                                      allow_all_staff=False)

        try:
            task_data = self.task_factory.get_task_descriptor_content(
                courseid, taskid)
        except:
            task_data = None
        if task_data is None:
            task_data = {}

        environments = self.containers

        current_filetype = None
        try:
            current_filetype = self.task_factory.get_task_descriptor_extension(
                courseid, taskid)
        except:
            pass
        available_filetypes = self.task_factory.get_available_task_file_extensions(
        )

        return self.template_helper.get_renderer().course_admin.task_edit(
            course, taskid, self.task_factory.get_problem_types(), task_data,
            environments, json.dumps(task_data.get('problems', {})),
            self.contains_is_html(task_data), current_filetype,
            available_filetypes, AccessibleTime,
            CourseTaskFiles.get_task_filelist(self.task_factory, courseid,
                                              taskid))
Пример #9
0
    def __init__(self, course, taskid, content, directory_path, task_problem_types=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)

        task_problem_types = task_problem_types or {
            "code": DisplayableCodeProblem,
            "code-file": DisplayableCodeFileProblem,
            "code-single-line": DisplayableCodeSingleLineProblem,
            "multiple-choice": DisplayableMultipleChoiceProblem,
            "match": DisplayableMatchProblem}

        super(FrontendTask, self).__init__(course, taskid, content, directory_path, task_problem_types)

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

        self._context = ParsableText(self._data.get('context', ""), "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 = []
Пример #10
0
    def get_temporal_task_file_content(self, course, taskid):
        """
        :param course: a Course object
        :param taskid: the task id of the task
        :raise InvalidNameException, TaskUnreadableException
        :return: the content of the temporary task file
        """

        if not id_checker(taskid):
            raise InvalidNameException("Task with invalid name: " + taskid)

        task_file_manager = None

        task_fs = self.get_task_fs(course.get_id(), taskid)
        for file_extension, file_manager in self._task_file_managers.items():
            if task_fs.get("task_temp." + file_extension):
                task_file_manager = file_manager

        temporal_task_file_content = {}
        try:
            temporal_task_file_content["data"] = task_file_manager.load(
                task_fs.get("task_temp.yaml"))
        except Exception as e:
            raise TaskUnreadableException(str(e))

        return temporal_task_file_content
Пример #11
0
    def __init__(self, course, taskid, content, directory_path, hook_manager, task_problem_types=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)

        task_problem_types = task_problem_types or {
            "code": DisplayableCodeProblem,
            "code-file": DisplayableCodeFileProblem,
            "code-single-line": DisplayableCodeSingleLineProblem,
            "multiple-choice": DisplayableMultipleChoiceProblem,
            "match": DisplayableMatchProblem}

        super(FrontendTask, self).__init__(course, taskid, content, directory_path, hook_manager, task_problem_types)

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

        self._context = ParsableText(self._data.get('context', ""), "rst")

        # Authors
        if isinstance(self._data.get('author'), str):  # 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, str):  # authors must be strings
                    raise Exception("This task has an invalid author")
            self._author = self._data['author']
        else:
            self._author = []

        # Submission storage
        self._stored_submissions = int(self._data.get("stored_submissions", 0))

        # Default download
        self._evaluate = self._data.get("evaluate", "best")
Пример #12
0
    def get_input(self):
        """ Loads web input, initialise default values and check/sanitise some inputs from users """
        user_input = web.input(
            user=[],
            task=[],
            aggregation=[],
            org_tags=[],
            grade_min='',
            grade_max='',
            sort_by="submitted_on",
            order='0',  # "0" for pymongo.DESCENDING, anything else for pymongo.ASCENDING
            limit='',
            filter_tags=[],
            filter_tags_presence=[],
            date_after='',
            date_before='',
            stat='with_stat',
        )

        # Sanitise inputs
        for item in itertools.chain(user_input.user, user_input.task, user_input.aggregation):
            if not id_checker(item):
                raise web.notfound()

        if user_input.sort_by not in self._allowed_sort:
            raise web.notfound()

        digits = [user_input.grade_min, user_input.grade_max, user_input.order, user_input.limit]
        for d in digits:
            if d != '' and not d.isdigit():
                raise web.notfound()

        return user_input 
Пример #13
0
def import_course(course, new_courseid, username, course_factory):
    if not id_checker(new_courseid):
        raise ImportCourseException("Course with invalid name: " + new_courseid)
    course_fs = course_factory.get_course_fs(new_courseid)

    if course_fs.exists("course.yaml") or course_fs.exists("course.json"):
        raise ImportCourseException("Course with id " + new_courseid + " already exists.")

    try:
        git.clone(course.get_link(), course_fs.prefix)
    except:
        raise ImportCourseException(_("Couldn't clone course into your instance"))

    try:
        old_descriptor = course_factory.get_course_descriptor_content(new_courseid)
    except:
        old_descriptor ={}

    try:
        new_descriptor = {"description": old_descriptor.get("description", ""),
                          'admins': [username],
                          "accessible": False,
                          "tags": old_descriptor.get("tags", {})}
        if "name" in old_descriptor:
            new_descriptor["name"] = old_descriptor["name"] + " - " + new_courseid
        else:
            new_descriptor["name"] = new_courseid
        if "toc" in old_descriptor:
            new_descriptor["toc"] = old_descriptor["toc"]
        course_factory.update_course_descriptor_content(new_courseid, new_descriptor)
    except:
        course_factory.delete_course(new_courseid)
        raise ImportCourseException(_("An error occur while editing the course description"))

    get_course_logger(new_courseid).info("Course %s cloned from the marketplace.", new_courseid)
Пример #14
0
    def GET_AUTH(self, courseid, taskid):  # pylint: disable=arguments-differ
        """ Edit a task """
        if not id_checker(taskid):
            raise NotFound(description=_("Invalid task id"))

        self.get_course_and_check_rights(courseid, allow_all_staff=False)

        user_input = flask.request.args
        if user_input.get("action") == "download" and user_input.get(
                'path') is not None:
            return self.action_download(courseid, taskid,
                                        user_input.get('path'))
        elif user_input.get("action") == "delete" and user_input.get(
                'path') is not None:
            return self.action_delete(courseid, taskid, user_input.get('path'))
        elif user_input.get("action") == "rename" and user_input.get(
                'path') is not None and user_input.get('new_path') is not None:
            return self.action_rename(courseid, taskid, user_input.get('path'),
                                      user_input.get('new_path'))
        elif user_input.get("action") == "create" and user_input.get(
                'path') is not None:
            return self.action_create(courseid, taskid, user_input.get('path'))
        elif user_input.get("action") == "edit" and user_input.get(
                'path') is not None:
            return self.action_edit(courseid, taskid, user_input.get('path'))
        else:
            return self.show_tab_file(courseid, taskid)
Пример #15
0
    def update_temporal_task_file(self, course, taskid, data):
        """
        :param course: a Course object
        :param taskid: the task id of the task
        :param data: a Dict with the temporary data of the task to be stored
        :raise InvalidNameException, TaskReaderNotFoundException, TaskNotFoundException
      
        Create or Update a temporary task file that is used to store the task data that is required for some plugins
        """
        if not id_checker(taskid):
            raise InvalidNameException("Task with invalid name: " + taskid)

        task_fs = self.get_task_fs(course.get_id(), taskid)

        task_file_manager = None

        try:
            for file_extension, file_manager in self._task_file_managers.items(
            ):
                if file_extension is "yaml":
                    task_file_manager = file_manager

        except:
            raise TaskReaderNotFoundException()

        if task_file_manager:
            temporal_task_file_content = task_file_manager.dump(data)

        try:
            task_fs.put("task_temp.yaml", temporal_task_file_content)
        except:
            raise TaskNotFoundException()
Пример #16
0
    def create_course(self, courseid, init_content):
        """
        :param courseid: the course id of the course
        :param init_content: initial descriptor content
        :raise InvalidNameException or CourseAlreadyExistsException
        Create a new course folder and set initial descriptor content, folder can already exist
        """
        if not id_checker(courseid):
            raise InvalidNameException("Course with invalid name: " + courseid)

        course_directory = os.path.join(self._tasks_directory, courseid)
        if not os.path.exists(course_directory):
            os.mkdir(course_directory)

        base_file = os.path.join(course_directory, "course")
        if not os.path.isfile(base_file +
                              ".yaml") and not os.path.isfile(base_file +
                                                              ".json"):
            write_yaml(os.path.join(course_directory, "course.yaml"),
                       init_content)
        else:
            raise CourseAlreadyExistsException("Course with id " + courseid +
                                               " already exists.")

        get_course_logger(courseid).info("Course %s created in the factory.",
                                         courseid)
Пример #17
0
    def _update_cache(self, course, taskid):
        """
        Updates the cache
        :param course: a Course object
        :param taskid: a (valid) task id
        :raise InvalidNameException, TaskNotFoundException, TaskUnreadableException
        """
        if not id_checker(taskid):
            raise InvalidNameException("Task with invalid name: " + taskid)

        task_fs = self.get_task_fs(course.get_id(), taskid)
        descriptor_name, descriptor_reader = self._get_task_descriptor_info(course.get_id(), taskid)
        try:
            task_content = descriptor_reader.load(task_fs.get(descriptor_name))
        except Exception as e:
            raise TaskUnreadableException(str(e))

        last_modif = {descriptor_name: task_fs.get_last_modification_time(descriptor_name)}
        translations_fs = task_fs.from_subfolder("$i18n")
        if translations_fs.exists():
            for f in translations_fs.list(folders=False, files=True, recursive=False):
                lang = f[0:len(f) - 3]
                if translations_fs.exists(lang + ".mo"):
                    last_modif["$i18n/" + lang + ".mo"] = translations_fs.get_last_modification_time(lang + ".mo")

        self._cache[(course.get_id(), taskid)] = (
            self._task_class(course, taskid, task_content, task_fs, self._hook_manager, self._task_problem_types),
            last_modif
        )
Пример #18
0
    def get_input(self):
        """ Loads web input, initialise default values and check/sanitise some inputs from users """
        user_input = web.input(
            user=[],
            task=[],
            aggregation=[],
            org_tags=[],
            grade_min='',
            grade_max='',
            sort_by="submitted_on",
            order='0',  # "0" for pymongo.DESCENDING, anything else for pymongo.ASCENDING
            limit='',
            filter_tags=[],
            filter_tags_presence=[],
            date_after='',
            date_before='',
            stat='with_stat',
        )

        # Sanitise inputs
        for item in itertools.chain(user_input.task, user_input.aggregation):
            if not id_checker(item):
                raise web.notfound()

        if user_input.sort_by not in self._allowed_sort:
            raise web.notfound()

        digits = [user_input.grade_min, user_input.grade_max, user_input.order, user_input.limit]
        for d in digits:
            if d != '' and not d.isdigit():
                raise web.notfound()

        return user_input 
Пример #19
0
    def create_course(self, courseid, init_content):
        """
        :param courseid: the course id of the course
        :param init_content: initial descriptor content
        :raise InvalidNameException or CourseAlreadyExistsException
        Create a new course folder and set initial descriptor content, folder can already exist
        """
        if not id_checker(courseid):
            raise InvalidNameException("Course with invalid name: " + courseid)

        course_fs = self.get_course_fs(courseid)
        course_fs.ensure_exists()

        if course_fs.exists("course.yaml") or course_fs.exists("course.json"):
            raise CourseAlreadyExistsException("Course with id " + courseid +
                                               " already exists.")
        else:
            course_fs.put("course.yaml",
                          get_json_or_yaml("course.yaml", init_content))

        get_course_logger(courseid).info("Course %s created in the factory.",
                                         courseid)
        self._hook_manager.call_hook('course_created',
                                     courseid=courseid,
                                     new_content=init_content)
Пример #20
0
    def _cache_update_needed(self, course, taskid):
        """
        :param course: a Course object
        :param taskid: a (valid) task id
        :raise InvalidNameException, TaskNotFoundException
        :return: True if an update of the cache is needed, False else
        """
        if not id_checker(taskid):
            raise InvalidNameException("Task with invalid name: " + taskid)

        task_fs = self.get_task_fs(course.get_id(), taskid)

        if (course.get_id(), taskid) not in self._cache:
            return True

        try:
            descriptor_name = self._get_task_descriptor_info(course.get_id(), taskid)[0]
            last_update = {descriptor_name: task_fs.get_last_modification_time(descriptor_name)}
            translations_fs = task_fs.from_subfolder("$i18n")
            if translations_fs.exists():
                for f in translations_fs.list(folders=False, files=True, recursive=False):
                    lang = f[0:len(f) - 3]
                    if translations_fs.exists(lang + ".mo"):
                        last_update["$i18n/" + lang + ".mo"] = translations_fs.get_last_modification_time(lang + ".mo")
        except:
            raise TaskNotFoundException()

        last_modif = self._cache[(course.get_id(), taskid)][1]
        for filename, mftime in last_update.items():
            if filename not in last_modif or last_modif[filename] < mftime:
                return True

        return False
Пример #21
0
    def GET_AUTH(self, courseid, taskid):  # pylint: disable=arguments-differ
        """ Edit a task """
        if not id_checker(taskid):
            raise Exception("Invalid task id")

        self.get_course_and_check_rights(courseid, allow_all_staff=False)
        tmp = courseid
        try:
            self.task_factory.get_task_descriptor_content(courseid, taskid)
        except:
            try:
                courseid = self.bank_name
                self.task_factory.get_task_descriptor_content(courseid, taskid)
            except:
                courseid = tmp
        request = web.input()
        if request.get("action") == "download" and request.get(
                'path') is not None:
            return self.action_download(courseid, taskid, request.get('path'))
        elif request.get("action") == "delete" and request.get(
                'path') is not None:
            return self.action_testcase_delete(courseid, taskid,
                                               request.get('path'))
        elif request.get("action") == "rename" and request.get(
                'path') is not None and request.get('new_path') is not None:
            return self.action_rename(courseid, taskid, request.get('path'),
                                      request.get('new_path'))
        elif request.get("action") == "create" and request.get(
                'path') is not None:
            return self.action_create(courseid, taskid, request.get('path'))
        elif request.get("action") == "edit" and request.get(
                'path') is not None:
            return self.action_edit(courseid, taskid, request.get('path'))
        else:
            return self.show_tab_file(courseid, taskid)
Пример #22
0
    def POST_AUTH(self, courseid, taskid):  # pylint: disable=arguments-differ
        """ Upload or modify a file """
        if not id_checker(taskid):
            raise Exception("Invalid task id")

        self.get_course_and_check_rights(courseid, allow_all_staff=False)
        tmp = courseid
        try:
            self.task_factory.get_task_descriptor_content(courseid, taskid)
        except:
            try:
                courseid = self.bank_name
                self.task_factory.get_task_descriptor_content(courseid, taskid)
            except:
                courseid = tmp
        request = web.input(testcase_input={},
                            testcase_output={},
                            testcase_feedback={})
        if request.get("action") == "upload" and request.get(
                'testcase_desc') is not None and request.get(
                    'testcase_input') is not None and request.get(
                        'testcase_output') is not None:
            output_value = request.get(
                'testcase_output').value if not isinstance(
                    request.get('testcase_output'), str) else 1
            return self.action_upload_testcase(
                courseid, taskid, request.get('testcase_desc'),
                request.get('testcase_input'), request.get('testcase_output'),
                request.get('testcase_feedback', {}), output_value)
        elif request.get("action") == "edit_save" and request.get(
                'path') is not None and request.get('content') is not None:
            return self.action_edit_save(courseid, taskid, request.get('path'),
                                         request.get('content'))
        else:
            return self.show_tab_file(courseid, taskid)
Пример #23
0
    def _cache_update_needed(self, course, taskid):
        """
        :param course: a Course object
        :param taskid: a (valid) task id
        :raise InvalidNameException, TaskNotFoundException
        :return: True if an update of the cache is needed, False else
        """
        if not id_checker(taskid):
            raise InvalidNameException("Task with invalid name: " + taskid)

        task_fs = self.get_task_fs(course.get_id(), taskid)

        if (course.get_id(), taskid) not in self._cache:
            return True

        try:
            last_update, __, __ = self._get_last_updates(
                course, taskid, task_fs, False)
        except:
            raise TaskNotFoundException()

        last_modif = self._cache[(course.get_id(), taskid)][1]
        for filename, mftime in last_update.items():
            if filename not in last_modif or last_modif[filename] < mftime:
                return True

        return False
Пример #24
0
    def delete_task(self, courseid, taskid):
        """ 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
        """
        if not id_checker(courseid):
            raise InvalidNameException("Course with invalid name: " + courseid)
        if not id_checker(taskid):
            raise InvalidNameException("Task with invalid name: " + taskid)

        task_fs = self.get_task_fs(courseid, taskid)

        if task_fs.exists():
            task_fs.delete()
            get_course_logger(courseid).info("Task %s erased from the factory.", taskid)
Пример #25
0
 def get_course_fs(self, courseid):
     """
     :param courseid: 
     :return: a FileSystemProvider pointing to the directory of the course 
     """
     if not id_checker(courseid):
         raise InvalidNameException("Course with invalid name: " + courseid)
     return self._filesystem.from_subfolder(courseid)
Пример #26
0
    def __init__(self, task, problemid, content):
        if not id_checker(problemid):
            raise Exception("Invalid problem _id: " + problemid)

        self._id = problemid
        self._task = task
        self._name = content['name'] if "name" in content else ""
        self._original_content = content
Пример #27
0
 def get_course_fs(self, courseid):
     """
     :param courseid: 
     :return: a FileSystemProvider pointing to the directory of the course 
     """
     if not id_checker(courseid):
         raise InvalidNameException("Course with invalid name: " + courseid)
     return self._filesystem.from_subfolder(courseid)
Пример #28
0
 def __init__(self, structure):
     Section.__init__(self, structure)
     if not all(id_checker(id) for id in structure["tasks_list"]):
         raise InvalidTocException(
             _("One task id contains non alphanumerical characters"))
     self._task_list = [
         task for task, _ in sorted(structure["tasks_list"].items(),
                                    key=lambda x: x[1])
     ]
Пример #29
0
    def __init__(self, task, problemid, content, translations=None):
        if not id_checker(problemid):
            raise Exception("Invalid problem _id: " + problemid)

        self._translations = translations
        self._id = problemid
        self._task = task
        self._name = content['name'] if "name" in content else ""
        self._original_content = content
Пример #30
0
    def _create_task_problem(self, problemid, problem_content, task_problem_types):
        """Creates a new instance of the right class for a given problem."""
        # Basic checks
        if not id_checker(problemid):
            raise Exception("Invalid problem _id: " + problemid)
        if problem_content.get('type', "") not in task_problem_types:
            raise Exception("Invalid type for problem " + problemid)

        return task_problem_types.get(problem_content.get('type', ""))(self, problemid, problem_content)
Пример #31
0
    def get_task_descriptor_content(self, courseid, taskid):
        """
        :param courseid: the course id of the course
        :param taskid: the task id of the task
        :raise InvalidNameException, TaskNotFoundException, TaskUnreadableException
        :return: the content of the task descriptor, as a dict
        """
        if not id_checker(courseid):
            raise InvalidNameException("Course with invalid name: " + courseid)
        if not id_checker(taskid):
            raise InvalidNameException("Task with invalid name: " + taskid)

        descriptor_path, descriptor_manager = self._get_task_descriptor_info(courseid, taskid)
        try:
            task_content = descriptor_manager.load(self.get_task_fs(courseid, taskid).get(descriptor_path))
        except Exception as e:
            raise TaskUnreadableException(str(e))
        return task_content
Пример #32
0
    def __init__(self, course, taskid, content, task_fs, translations_fs,
                 hook_manager, task_problem_types):
        # 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)

        super(WebAppTask,
              self).__init__(course, taskid, content, task_fs, translations_fs,
                             hook_manager, task_problem_types)

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

        self._context = self._data.get('context', "")

        # Authors
        if isinstance(self._data.get('author'),
                      str):  # verify if author is a string
            self._author = self._data['author']
        else:
            self._author = ""

        if isinstance(self._data.get('contact_url'), str):
            self._contact_url = self._data['contact_url']
        else:
            self._contact_url = ""

        # Submission storage
        self._stored_submissions = int(self._data.get("stored_submissions", 0))

        # Default download
        self._evaluate = self._data.get("evaluate", "best")

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

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

        # Group task
        self._groups = bool(self._data.get("groups", False))

        # Submission limits
        self._submission_limit = self._data.get("submission_limit", {
            "amount": -1,
            "period": -1
        })

        # Input random
        self._input_random = int(self._data.get("input_random", 0))

        # Regenerate input random
        self._regenerate_input_random = bool(
            self._data.get("regenerate_input_random", False))

        # Category tags
        self._categories = self._data.get("categories", [])
Пример #33
0
 def get_task_descriptor_content(self, courseid, taskid):
     """
     :param courseid: the course id of the course
     :param taskid: the task id of the task
     :raise InvalidNameException, TaskNotFoundException, TaskUnreadableException
     :return: the content of the task descriptor, as a dict
     """
     if not id_checker(courseid):
         raise InvalidNameException("Course with invalid name: " + courseid)
     if not id_checker(taskid):
         raise InvalidNameException("Task with invalid name: " + taskid)
     path_to_descriptor, _, descriptor_manager = self._get_task_descriptor_info(courseid, taskid)
     try:
         with codecs.open(path_to_descriptor, 'r', 'utf-8') as fd:
             task_content = descriptor_manager.load(fd.read())
     except Exception as e:
         raise TaskUnreadableException(str(e))
     return task_content
Пример #34
0
 def get_task_descriptor_content(self, courseid, taskid):
     """
     :param courseid: the course id of the course
     :param taskid: the task id of the task
     :raise InvalidNameException, TaskNotFoundException, TaskUnreadableException
     :return: the content of the task descriptor, as a dict
     """
     if not id_checker(courseid):
         raise InvalidNameException("Course with invalid name: " + courseid)
     if not id_checker(taskid):
         raise InvalidNameException("Task with invalid name: " + taskid)
     path_to_descriptor, descriptor_ext, descriptor_manager = self._get_task_descriptor_info(courseid, taskid)
     try:
         with codecs.open(path_to_descriptor, 'r', 'utf-8') as fd:
             task_content = descriptor_manager.load(fd.read())
     except Exception as e:
         raise TaskUnreadableException(str(e))
     return task_content
Пример #35
0
    def __init__(self,
                 course,
                 taskid,
                 content,
                 task_fs,
                 hook_manager,
                 task_problem_types=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)

        task_problem_types = task_problem_types or {
            "code": DisplayableCodeProblem,
            "code-file": DisplayableCodeFileProblem,
            "code-single-line": DisplayableCodeSingleLineProblem,
            "multiple-choice": DisplayableMultipleChoiceProblem,
            "match": DisplayableMatchProblem
        }

        super(WebAppTask, self).__init__(course, taskid, content, task_fs,
                                         hook_manager, task_problem_types)

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

        self._context = self._data.get('context', "")

        # Authors
        if isinstance(self._data.get('author'),
                      str):  # verify if author is a string
            self._author = self._data['author']
        else:
            self._author = ""

        # Submission storage
        self._stored_submissions = int(self._data.get("stored_submissions", 0))

        # Default download
        self._evaluate = self._data.get("evaluate", "best")

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

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

        # Group task
        self._groups = bool(self._data.get("groups", False))

        # Submission limits
        self._submission_limit = self._data.get("submission_limit", {
            "amount": -1,
            "period": -1
        })

        # Tags
        self._tags = Tag.create_tags_from_dict(self._data.get("tags", {}))
Пример #36
0
    def _create_task_problem(self, problemid, problem_content, task_problem_types):
        """Creates a new instance of the right class for a given problem."""
        # Basic checks
        if not id_checker(problemid):
            raise Exception("Invalid problem _id: " + problemid)
        if problem_content.get('type', "") not in task_problem_types:
            raise Exception("Invalid type for problem " + problemid)

        return task_problem_types.get(problem_content.get('type', ""))(self, problemid, problem_content, self._translations)
Пример #37
0
    def __init__(self, problemid, content, translations, taskfs):
        if not id_checker(problemid):
            raise Exception("Invalid problem _id: " + problemid)

        self._id = problemid
        self._translations = translations
        self._name = content['name'] if "name" in content else ""
        self._original_content = content
        self._task_fs = taskfs
Пример #38
0
    def __init__(self, task, problemid, content):
        if not id_checker(problemid):
            raise Exception("Invalid problem _id: " + problemid)

        self._id = problemid
        self._task = task
        self._name = content['name'] if "name" in content else ""
        self._header = content['header'] if "header" in content else ""
        self._original_content = content
Пример #39
0
 def _create_box(self, boxid, box_content):
     """ Create adequate box """
     if not id_checker(boxid) and not boxid == "":
         raise Exception("Invalid box _id " + boxid)
     if "type" not in box_content:
         raise Exception("Box " + boxid + " does not have a type")
     try:
         return self._box_types[box_content["type"]](self, boxid, box_content)
     except:
         raise Exception("Unknow box type " + box_content["type"] + "for box _id " + boxid)
    def _create_box(self, boxid, box_content):
        """ Create adequate box """
        if not id_checker(boxid) and not boxid == "":
            raise Exception("Invalid box _id " + boxid)
        if "type" not in box_content:
            raise Exception("Box " + boxid + " does not have a type")
        if box_content["type"] not in self._box_types:
            raise Exception("Unknown box type " + box_content["type"] + " for box _id " + boxid)

        return self._box_types[box_content["type"]](self, boxid, box_content)
Пример #41
0
    def __init__(self, task, problemid, content, translations=None):
        if not id_checker(problemid):
            raise Exception("Invalid problem _id: " + problemid)

        self._translations = translations
        self._id = problemid
        self._task = task
        self._name = content['name'] if "name" in content else ""
        self._header = content['header'] if "header" in content else ""
        self._original_content = content
Пример #42
0
 def get_course(self, courseid):
     """
     :param courseid: the course id of the course
     :raise InvalidNameException, CourseNotFoundException, CourseUnreadableException
     :return: an object representing the course, of the type given in the constructor
     """
     if not id_checker(courseid):
         raise InvalidNameException("Course with invalid name: " + courseid)
     if self._cache_update_needed(courseid):
         self._update_cache(courseid)
     return self._cache[courseid][0]
Пример #43
0
    def _get_task_descriptor_info(self, courseid, taskid):
        """
        :param courseid: the course id of the course
        :param taskid: the task id of the task
        :raise InvalidNameException, TaskNotFoundException
        :return: a tuple, containing:
            (the path to the descriptor of the task,
             extension of the descriptor,
             task file manager for the descriptor)
        """
        if not id_checker(courseid):
            raise InvalidNameException("Course with invalid name: " + courseid)
        if not id_checker(taskid):
            raise InvalidNameException("Task with invalid name: " + taskid)
        base_file = os.path.join(self._tasks_directory, courseid, taskid, "task")

        for ext, task_file_manager in self._task_file_managers.iteritems():
            if os.path.isfile(base_file + "." + ext):
                return (base_file + "." + ext, ext, task_file_manager)

        raise TaskNotFoundException()
Пример #44
0
 def get_task(self, course, taskid):
     """
     :param course: a Course object
     :param taskid: the task id of the task
     :raise InvalidNameException, TaskNotFoundException, TaskUnreadableException
     :return: an object representing the task, of the type given in the constructor
     """
     if not id_checker(taskid):
         raise InvalidNameException("Task with invalid name: " + taskid)
     if self._cache_update_needed(course, taskid):
         self._update_cache(course, taskid)
     return self._cache[(course.get_id(), taskid)][0]
Пример #45
0
    def POST_AUTH(self, courseid, taskid):
        if not id_checker(taskid):
            raise Exception("Invalid task id")

        self.get_course_and_check_rights(courseid, allow_all_staff=False)

        request = web.input(file={})
        if request.get('file') is not None:
            file = request.get('file')
            name = request.get('name')
            filename = "/"+name
            wanted_path = self.verify_path(courseid, taskid, filename, True)
            self.action_upload(courseid, taskid, wanted_path, file)
            return json.dumps("success")
Пример #46
0
    def POST(self, courseid, taskid):
        """ Upload or modify a file """
        if not id_checker(taskid):
            raise Exception("Invalid task id")

        self.get_course_and_check_rights(courseid, allow_all_staff=False)

        request = web.input(file={})
        if request.get("action") == "upload" and request.get('path') is not None and request.get('file') is not None:
            return self.action_upload(courseid, taskid, request.get('path'), request.get('file'))
        elif request.get("action") == "edit_save" and request.get('path') is not None and request.get('content') is not None:
            return self.action_edit_save(courseid, taskid, request.get('path'), request.get('content'))
        else:
            return self.show_tab_file(courseid, taskid)
Пример #47
0
 def _get_course_descriptor_path(self, courseid):
     """
     :param courseid: the course id of the course
     :raise InvalidNameException, CourseNotFoundException
     :return: the path to the descriptor of the course
     """
     if not id_checker(courseid):
         raise InvalidNameException("Course with invalid name: " + courseid)
     course_fs = self.get_course_fs(courseid)
     if course_fs.exists("course.yaml"):
         return courseid+"/course.yaml"
     if course_fs.exists("course.json"):
         return courseid+"/course.json"
     raise CourseNotFoundException()
Пример #48
0
 def _get_course_descriptor_path(self, courseid):
     """
     :param courseid: the course id of the course
     :raise InvalidNameException, CourseNotFoundException
     :return: the path to the descriptor of the course
     """
     if not id_checker(courseid):
         raise InvalidNameException("Course with invalid name: " + courseid)
     base_file = os.path.join(self._tasks_directory, courseid, "course")
     if os.path.isfile(base_file + ".yaml"):
         return base_file + ".yaml"
     elif os.path.isfile(base_file + ".json"):
         return base_file + ".json"
     else:
         raise CourseNotFoundException()
Пример #49
0
    def GET(self, courseid, taskid):
        """ Edit a task """
        if not id_checker(taskid):
            raise Exception("Invalid task id")

        course, _ = self.get_course_and_check_rights(courseid, allow_all_staff=False)

        try:
            task_data = self.task_factory.get_task_descriptor_content(courseid, taskid)
        except:
            task_data = None
        if task_data is None:
            task_data = {}

        environments = self.containers

        current_filetype = None
        try:
            current_filetype = self.task_factory.get_task_descriptor_extension(courseid, taskid)
        except:
            pass
        available_filetypes = self.task_factory.get_available_task_file_extensions()

        # custom problem-type:
        for pid in task_data.get("problems", {}):
            problem = task_data["problems"][pid]
            if (problem["type"] == "code" and "boxes" in problem) or problem["type"] not in (
                    "code", "code-single-line", "code-file", "match", "multiple-choice"):
                problem_copy = copy.deepcopy(problem)
                for i in ["name", "header"]:
                    if i in problem_copy:
                        del problem_copy[i]
                problem["custom"] = inginious.common.custom_yaml.dump(problem_copy)

        return self.template_helper.get_renderer().course_admin.edit_task(
            course,
            taskid,
            task_data,
            environments,
            json.dumps(
                task_data.get(
                    'problems',
                    {})),
            self.contains_is_html(task_data),
            current_filetype,
            available_filetypes,
            AccessibleTime,
            CourseTaskFiles.get_task_filelist(self.task_factory, courseid, taskid))
Пример #50
0
    def delete_course(self, courseid):
        """
        :param courseid: the course id of the course
        :raise InvalidNameException or CourseNotFoundException
        Erase the content of the course folder
        """
        if not id_checker(courseid):
            raise InvalidNameException("Course with invalid name: " + courseid)

        course_fs = self.get_course_fs(courseid)

        if not course_fs.exists():
            raise CourseNotFoundException()

        course_fs.delete()

        get_course_logger(courseid).info("Course %s erased from the factory.", courseid)
Пример #51
0
    def create_course(self, courseid, init_content):
        """
        :param courseid: the course id of the course
        :param init_content: initial descriptor content
        :raise InvalidNameException or CourseAlreadyExistsException
        Create a new course folder and set initial descriptor content, folder can already exist
        """
        if not id_checker(courseid):
            raise InvalidNameException("Course with invalid name: " + courseid)

        course_fs = self.get_course_fs(courseid)
        course_fs.ensure_exists()

        if course_fs.exists("course.yaml") or course_fs.exists("course.json"):
            raise CourseAlreadyExistsException("Course with id " + courseid + " already exists.")
        else:
            course_fs.put("course.yaml", get_json_or_yaml("course.yaml", init_content))

        get_course_logger(courseid).info("Course %s created in the factory.", courseid)
Пример #52
0
    def __init__(self, course, taskid, content, task_fs, translations_fs, hook_manager, task_problem_types):
        # 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)

        super(WebAppTask, self).__init__(course, taskid, content, task_fs, translations_fs, hook_manager, task_problem_types)

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

        self._context = self._data.get('context', "")

        # Authors
        if isinstance(self._data.get('author'), str):  # verify if author is a string
            self._author = self._data['author']
        else:
            self._author = ""

        # Submission storage
        self._stored_submissions = int(self._data.get("stored_submissions", 0))

        # Default download
        self._evaluate = self._data.get("evaluate", "best")

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

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

        # Group task
        self._groups = bool(self._data.get("groups", False))

        # Submission limits
        self._submission_limit = self._data.get("submission_limit", {"amount": -1, "period": -1})
        
        # Input random
        self._input_random = int(self._data.get("input_random", 0))
        
        # Regenerate input random
        self._regenerate_input_random = bool(self._data.get("regenerate_input_random", False))

        # Tags
        self._tags = Tag.create_tags_from_dict(self._data.get("tags", {}))
Пример #53
0
    def GET(self, courseid, taskid):
        """ Edit a task """
        if not id_checker(taskid):
            raise Exception("Invalid task id")

        self.get_course_and_check_rights(courseid, allow_all_staff=False)

        request = web.input()
        if request.get("action") == "download" and request.get('path') is not None:
            return self.action_download(courseid, taskid, request.get('path'))
        elif request.get("action") == "delete" and request.get('path') is not None:
            return self.action_delete(courseid, taskid, request.get('path'))
        elif request.get("action") == "rename" and request.get('path') is not None and request.get('new_path') is not None:
            return self.action_rename(courseid, taskid, request.get('path'), request.get('new_path'))
        elif request.get("action") == "create" and request.get('path') is not None:
            return self.action_create(courseid, taskid, request.get('path'))
        elif request.get("action") == "edit" and request.get('path') is not None:
            return self.action_edit(courseid, taskid, request.get('path'))
        else:
            return self.show_tab_file(courseid, taskid)
Пример #54
0
    def GET_AUTH(self, courseid, taskid):  # pylint: disable=arguments-differ
        """ Edit a task """
        if not id_checker(taskid):
            raise Exception("Invalid task id")

        course, __ = self.get_course_and_check_rights(courseid, allow_all_staff=False)

        try:
            task_data = self.task_factory.get_task_descriptor_content(courseid, taskid)
        except:
            task_data = None
        if task_data is None:
            task_data = {}

        environments = self.containers

        current_filetype = None
        try:
            current_filetype = self.task_factory.get_task_descriptor_extension(courseid, taskid)
        except:
            pass
        available_filetypes = self.task_factory.get_available_task_file_extensions()

        additional_tabs = self.plugin_manager.call_hook('task_editor_tab', course=course, taskid=taskid,
                                                        task_data=task_data, template_helper=self.template_helper)

        return self.template_helper.get_renderer().course_admin.task_edit(
            course,
            taskid,
            self.task_factory.get_problem_types(),
            task_data,
            environments,
            task_data.get('problems',{}),
            self.contains_is_html(task_data),
            current_filetype,
            available_filetypes,
            AccessibleTime,
            CourseTaskFiles.get_task_filelist(self.task_factory, courseid, taskid),
            additional_tabs
        )
Пример #55
0
    def POST_AUTH(self, courseid, taskid):  # pylint: disable=arguments-differ
        """ Edit a task """
        if not id_checker(taskid) or not id_checker(courseid):
            raise Exception("Invalid course/task id")

        course, __ = self.get_course_and_check_rights(courseid, allow_all_staff=False)
        data = web.input(task_file={})

        # Delete task ?
        if "delete" in data:
            self.task_factory.delete_task(courseid, taskid)
            if data.get("wipe", False):
                self.wipe_task(courseid, taskid)
            raise web.seeother(self.app.get_homepath() + "/admin/"+courseid+"/tasks")

        # Else, parse content
        try:
            try:
                task_zip = data.get("task_file").file
            except:
                task_zip = None
            del data["task_file"]

            problems = self.dict_from_prefix("problem", data)
            limits = self.dict_from_prefix("limits", data)

            #Tags
            tags = self.dict_from_prefix("tags", data)
            if tags is None:
                tags = {}
            tags = OrderedDict(sorted(tags.items(), key=lambda item: item[0])) # Sort by key

            # Repair tags
            for k in tags:
                tags[k]["visible"] = ("visible" in tags[k])  # Since unckecked checkboxes are not present here, we manually add them to avoid later errors
                tags[k]["type"] = int(tags[k]["type"])
                if not "id" in tags[k]:
                    tags[k]["id"] = "" # Since textinput is disabled when the tag is organisational, the id field is missing. We add it to avoid Keys Errors
                if tags[k]["type"] == 2:
                    tags[k]["id"] = "" # Force no id if organisational tag

            # Remove uncompleted tags (tags with no name or no id)
            for k in list(tags.keys()):
                if (tags[k]["id"] == "" and tags[k]["type"] != 2) or tags[k]["name"] == "":
                    del tags[k]

            # Find duplicate ids. Return an error if some tags use the same id.
            for k in tags:
                if tags[k]["type"] != 2: # Ignore organisational tags since they have no id.
                    count = 0
                    id = str(tags[k]["id"])
                    if (" " in id):
                        return json.dumps({"status": "error", "message": _("You can not use spaces in the tag id field.")})
                    if not id_checker(id):
                        return json.dumps({"status": "error", "message": _("Invalid tag id: {}").format(id)})
                    for k2 in tags:
                        if tags[k2]["type"] != 2 and tags[k2]["id"] == id:
                            count = count+1
                    if count > 1:
                        return json.dumps({"status": "error", "message": _("Some tags have the same id! The id of a tag must be unique.")})

            data = {key: val for key, val in data.items() if
                    not key.startswith("problem")
                    and not key.startswith("limits")
                    and not key.startswith("tags")
                    and not key.startswith("/")}
            del data["@action"]

            # Determines the task filetype
            if data["@filetype"] not in self.task_factory.get_available_task_file_extensions():
                return json.dumps({"status": "error", "message": _("Invalid file type: {}").format(str(data["@filetype"]))})
            file_ext = data["@filetype"]
            del data["@filetype"]

            # Parse and order the problems (also deletes @order from the result)
            if problems is None:
                data["problems"] = OrderedDict([])
            else:
                data["problems"] = OrderedDict([(key, self.parse_problem(val))
                                                for key, val in sorted(iter(problems.items()), key=lambda x: int(x[1]['@order']))])

            # Task limits
            data["limits"] = limits
            data["tags"] = OrderedDict(sorted(tags.items(), key=lambda x: x[1]['type']))
            if "hard_time" in data["limits"] and data["limits"]["hard_time"] == "":
                del data["limits"]["hard_time"]

            # Weight
            try:
                data["weight"] = float(data["weight"])
            except:
                return json.dumps({"status": "error", "message": _("Grade weight must be a floating-point number")})

            # Groups
            if "groups" in data:
                data["groups"] = True if data["groups"] == "true" else False

            # Submision storage
            if "store_all" in data:
                try:
                    stored_submissions = data["stored_submissions"]
                    data["stored_submissions"] = 0 if data["store_all"] == "true" else int(stored_submissions)
                except:
                    return json.dumps(
                        {"status": "error", "message": _("The number of stored submission must be positive!")})

                if data["store_all"] == "false" and data["stored_submissions"] <= 0:
                    return json.dumps({"status": "error", "message": _("The number of stored submission must be positive!")})
                del data['store_all']

            # Submission limits
            if "submission_limit" in data:
                if data["submission_limit"] == "none":
                    result = {"amount": -1, "period": -1}
                elif data["submission_limit"] == "hard":
                    try:
                        result = {"amount": int(data["submission_limit_hard"]), "period": -1}
                    except:
                        return json.dumps({"status": "error", "message": _("Invalid submission limit!")})

                else:
                    try:
                        result = {"amount": int(data["submission_limit_soft_0"]), "period": int(data["submission_limit_soft_1"])}
                    except:
                        return json.dumps({"status": "error", "message": _("Invalid submission limit!")})

                del data["submission_limit_hard"]
                del data["submission_limit_soft_0"]
                del data["submission_limit_soft_1"]
                data["submission_limit"] = result

            # Accessible
            if data["accessible"] == "custom":
                data["accessible"] = "{}/{}/{}".format(data["accessible_start"], data["accessible_soft_end"], data["accessible_end"])
            elif data["accessible"] == "true":
                data["accessible"] = True
            else:
                data["accessible"] = False
            del data["accessible_start"]
            del data["accessible_end"]
            del data["accessible_soft_end"]

            # Checkboxes
            if data.get("responseIsHTML"):
                data["responseIsHTML"] = True

            # Network grading
            data["network_grading"] = "network_grading" in data
        except Exception as message:
            return json.dumps({"status": "error", "message": _("Your browser returned an invalid form ({})").format(message)})

        # Get the course
        try:
            course = self.course_factory.get_course(courseid)
        except:
            return json.dumps({"status": "error", "message": _("Error while reading course's informations")})

        # Get original data
        try:
            orig_data = self.task_factory.get_task_descriptor_content(courseid, taskid)
            data["order"] = orig_data["order"]
        except:
            pass

        task_fs = self.task_factory.get_task_fs(courseid, taskid)
        task_fs.ensure_exists()

        # Call plugins and return the first error
        plugin_results = self.plugin_manager.call_hook('task_editor_submit', course=course, taskid=taskid,
                                                       task_data=data, task_fs=task_fs)

        # Retrieve the first non-null element
        error = next(filter(None, plugin_results), None)
        if error is not None:
            return error

        try:
            WebAppTask(course, taskid, data, task_fs, None, self.plugin_manager, self.task_factory.get_problem_types())
        except Exception as message:
            return json.dumps({"status": "error", "message": _("Invalid data: {}").format(str(message))})

        if task_zip:
            try:
                zipfile = ZipFile(task_zip)
            except Exception:
                return json.dumps({"status": "error", "message": _("Cannot read zip file. Files were not modified")})

            with tempfile.TemporaryDirectory() as tmpdirname:
                try:
                    zipfile.extractall(tmpdirname)
                except Exception:
                    return json.dumps(
                        {"status": "error", "message": _("There was a problem while extracting the zip archive. Some files may have been modified")})
                task_fs.copy_to(tmpdirname)

        self.task_factory.delete_all_possible_task_files(courseid, taskid)
        self.task_factory.update_task_descriptor_content(courseid, taskid, data, force_extension=file_ext)
        course.update_all_tags_cache()

        return json.dumps({"status": "ok"})
Пример #56
0
 def test_id_checker_invalid_3(self):
     assert id_checker("test/test") is False
Пример #57
0
 def test_id_checker_invalid_1(self):
     assert id_checker("a@a") is False
Пример #58
0
    def POST(self, courseid, taskid):
        """ Edit a task """
        if not id_checker(taskid) or not id_checker(courseid):
            raise Exception("Invalid course/task id")

        course, _ = self.get_course_and_check_rights(courseid, allow_all_staff=False)

        # Parse content
        try:
            data = web.input(task_file={})

            try:
                task_zip = data.get("task_file").file
            except:
                task_zip = None
            del data["task_file"]

            problems = self.dict_from_prefix("problem", data)
            limits = self.dict_from_prefix("limits", data)

            data = {key: val for key, val in data.iteritems() if not key.startswith("problem") and not key.startswith("limits")}
            del data["@action"]

            if data["@filetype"] not in self.task_factory.get_available_task_file_extensions():
                return json.dumps({"status": "error", "message": "Invalid file type: {}".format(str(data["@filetype"]))})
            file_ext = data["@filetype"]
            del data["@filetype"]

            if problems is None:
                return json.dumps({"status": "error", "message": "You cannot create a task without subproblems"})

            # Order the problems (this line also deletes @order from the result)
            data["problems"] = OrderedDict([(key, self.parse_problem(val))
                                            for key, val in sorted(problems.iteritems(), key=lambda x: int(x[1]['@order']))])
            data["limits"] = limits
            if "hard_time" in data["limits"] and data["limits"]["hard_time"] == "":
                del data["limits"]["hard_time"]

            # Weight
            try:
                data["weight"] = float(data["weight"])
            except:
                return json.dumps({"status": "error", "message": "Grade weight must be a floating-point number"})

            # Groups
            if "groups" in data:
                data["groups"] = True if data["groups"] == "true" else False

            # Accessible
            if data["accessible"] == "custom":
                data["accessible"] = "{}/{}".format(data["accessible_start"], data["accessible_end"])
            elif data["accessible"] == "true":
                data["accessible"] = True
            else:
                data["accessible"] = False
            del data["accessible_start"]
            del data["accessible_end"]

            # Checkboxes
            if data.get("responseIsHTML"):
                data["responseIsHTML"] = True

            # Network grading
            data["network_grading"] = "network_grading" in data
        except Exception as message:
            return json.dumps({"status": "error", "message": "Your browser returned an invalid form ({})".format(str(message))})

        # Get the course
        try:
            course = self.course_factory.get_course(courseid)
        except:
            return json.dumps({"status": "error", "message": "Error while reading course's informations"})

        # Get original data
        try:
            orig_data = self.task_factory.get_task_descriptor_content(courseid, taskid)
            data["order"] = orig_data["order"]
        except:
            pass

        directory_path = self.task_factory.get_directory_path(courseid, taskid)
        try:
            WebAppTask(course, taskid, data, directory_path)
        except Exception as message:
            return json.dumps({"status": "error", "message": "Invalid data: {}".format(str(message))})

        if not os.path.exists(directory_path):
            os.mkdir(directory_path)

        if task_zip:
            try:
                zipfile = ZipFile(task_zip)
            except Exception as message:
                return json.dumps({"status": "error", "message": "Cannot read zip file. Files were not modified"})

            try:
                zipfile.extractall(directory_path)
            except Exception as message:
                return json.dumps(
                    {"status": "error", "message": "There was a problem while extracting the zip archive. Some files may have been modified"})

        self.task_factory.delete_all_possible_task_files(courseid, taskid)
        self.task_factory.update_task_descriptor_content(courseid, taskid, data, force_extension=file_ext)

        return json.dumps({"status": "ok"})
Пример #59
0
 def test_id_checker_invalid_2(self):
     assert id_checker("") is False
Пример #60
0
 def _validate_list(self, usernames):
     """ Prevent MongoDB injections by verifying arrays sent to it """
     for i in usernames:
         if not id_checker(i):
             raise web.notfound()