def get_feedback_from_submission(self,
                                     submission,
                                     only_feedback=False,
                                     show_everything=False):
        """
            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.
        """
        if only_feedback:
            submission = {
                "text": submission.get("text", None),
                "problems": dict(submission.get("problems", {}))
            }
        if "text" in submission:
            submission["text"] = ParsableText(submission["text"],
                                              submission["response_type"],
                                              show_everything).parse()
        if "problems" in submission:
            for problem in submission["problems"]:
                submission["problems"][problem] = ParsableText(
                    submission["problems"][problem],
                    submission["response_type"], show_everything).parse()
        return submission
示例#2
0
    def get_feedback_from_submission(self,
                                     submission,
                                     only_feedback=False,
                                     show_everything=False):
        """
            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.
        """
        if only_feedback:
            submission = {
                "text": submission.get("text", None),
                "problems": dict(submission.get("problems", {}))
            }
        if "text" in submission:
            submission["text"] = ParsableText(submission["text"],
                                              submission["response_type"],
                                              show_everything).parse()
        if "problems" in submission:
            for problem in submission["problems"]:
                if isinstance(submission["problems"][problem],
                              str):  # fallback for old-style submissions
                    submission["problems"][problem] = (
                        submission.get('result', 'crash'),
                        ParsableText(submission["problems"][problem],
                                     submission["response_type"],
                                     show_everything).parse())
                else:  # new-style submission
                    submission["problems"][problem] = (
                        submission["problems"][problem][0],
                        ParsableText(submission["problems"][problem][1],
                                     submission["response_type"],
                                     show_everything).parse())
        return submission
示例#3
0
    def get_basic_info(self, courseid):
        course, _ = self.get_course_and_check_rights(courseid,
                                                     allow_all_staff=False)

        container_title = "JPlag"
        container_description = ParsableText(
            "Plagiarism tool".encode('utf-8').decode("unicode_escape"), 'rst')

        container_args = {
            "task": {
                "type": "text",
                "name": "Problem to check",
                "path": "task.txt",
                "description": "Id of the problem you want to check."
            },
            "language": {
                "type":
                "text",
                "name":
                "Language",
                "path":
                "lang.txt",
                "choices": [
                    'python3', 'java17', 'java15', 'java15dm', 'java12',
                    'java11', 'c/c++', 'c#-1.2', 'char', 'text', 'scheme'
                ],
                "description":
                "Language used in the submissions."
            },
        }

        container_contest_args = container_args.copy()

        container_contest_args["contest"] = {
            "type": "text",
            "name": "Contests",
            "description": "The contest you want to check",
            "choices": {
                x: y["name"]
                for x, y in self.contest_manager.get_all_contest_data(
                    course).items()
            }
        }

        del container_contest_args["task"]

        for val in container_args.values():
            if "description" in val:
                val['description'] = ParsableText(
                    val['description'].encode('utf-8').decode(
                        "unicode_escape"), 'rst').parse()

        return course, container_title, container_description, container_args, container_contest_args
    def test_failing_parser_injection(self):
        def fake_parser(input):
            raise Exception()

        fake_parser.count = 0
        orig_rst = ParsableText.rst
        ParsableText.rst = fake_parser

        pt = ParsableText("""<script type="text/javascript">alert('Eh, XSS injection!');</script>""")
        rendered = pt.parse()

        ParsableText.rst = orig_rst

        assert "&lt;script " in rendered
 def test_wrong_rst_injection(self):
     rendered = unicode(
         ParsableText.rst("""
         makefail_
         <script type="text/javascript">alert('Eh, XSS injection!');</script>
         """))
     assert "&lt;script type=&quot;text/javascript&quot;&gt;" in rendered
示例#6
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")
    def test_failing_parser_injection(self):
        def fake_parser(input):
            raise Exception()

        fake_parser.count = 0
        orig_rst = ParsableText.rst
        ParsableText.rst = fake_parser

        pt = ParsableText(
            """<script type="text/javascript">alert('Eh, XSS injection!');</script>"""
        )
        rendered = pt.parse()

        ParsableText.rst = orig_rst

        assert "&lt;script " in rendered
    def test_hidden_until_before_admin(self):
        assert "Something" in ParsableText.rst("""
            .. hidden-until:: 22/05/2102

                Something
            """,
                                               show_everything=True)
 def test_wrong_rst_injection(self):
     rendered = unicode(ParsableText.rst(
         """
         makefail_
         <script type="text/javascript">alert('Eh, XSS injection!');</script>
         """
     ))
     assert "&lt;script type=&quot;text/javascript&quot;&gt;" in rendered
    def test_parsable_text_once(self):
        def fake_parser(input, show_everything):
            fake_parser.count += 1
            return ""

        fake_parser.count = 0
        orig_rst = ParsableText.rst
        ParsableText.rst = fake_parser

        pt = ParsableText("""``test``""", "rst")
        pt.rst = fake_parser

        pt.parse()
        str(pt)
        unicode(pt)

        ParsableText.rst = orig_rst

        assert fake_parser.count == 1
    def test_parsable_text_once(self):
        def fake_parser(input, show_everything):
            fake_parser.count += 1
            return ""

        fake_parser.count = 0
        orig_rst = ParsableText.rst
        ParsableText.rst = fake_parser

        pt = ParsableText("""``test``""", "rst")
        pt.rst = fake_parser

        pt.parse()
        str(pt)
        unicode(pt)

        ParsableText.rst = orig_rst

        assert fake_parser.count == 1
示例#12
0
    def get_basic_info(self, courseid, container_name):
        course, _ = self.get_course_and_check_rights(courseid,
                                                     allow_all_staff=False)
        try:
            metadata = self.batch_manager.get_batch_container_metadata(
                container_name)
            if metadata == (None, None, None):
                raise Exception("Container not found")
        except:
            raise web.notfound()

        container_title = metadata[0]
        container_description = ParsableText(
            metadata[1].encode('utf-8').decode("unicode_escape"), 'rst')

        container_args = copy.deepcopy(metadata[2])  # copy it
        for val in container_args.values():
            if "description" in val:
                val['description'] = ParsableText(
                    val['description'].encode('utf-8').decode(
                        "unicode_escape"), 'rst').parse()

        return course, container_title, container_description, container_args
示例#13
0
    def get_batch_container_metadata(self, container_name):
        """
            Returns the arguments needed by a particular batch container.
            :returns: a tuple in the form
                ("container title",
                 "container description in restructuredtext",
                 {"key":
                    {
                     "type:" "file", #or "text",
                     "path": "path/to/file/inside/input/dir", #not mandatory in file, by default "key"
                     "name": "name of the field", #not mandatory in file, default "key"
                     "description": "a short description of what this field is used for", #not mandatory, default ""
                     "custom_key1": "custom_value1",
                     ...
                    }
                 }
                )
        """
        if container_name not in self._batch_container:
            raise Exception(
                "This batch container is not allowed to be started")

        metadata = copy.deepcopy(
            self._job_manager.get_batch_container_metadata(container_name))
        if metadata != (None, None, None):
            for key, val in metadata[2].iteritems():
                if "description" in val:
                    val["description"] = ParsableText(
                        val["description"].replace('\\n',
                                                   '\n').replace('\\t', '\t'),
                        'rst').parse()
            metadata = (metadata[0],
                        ParsableText(
                            metadata[1].replace('\\n',
                                                '\n').replace('\\t', '\t'),
                            'rst').parse(), metadata[2])
        return metadata
示例#14
0
    def __init__(self, problem, boxid, boxData):
        super(DisplayableTextBox, self).__init__(problem, boxid, boxData)

        self._content = ParsableText(self._content, "rst")
 def test_code(self):
     rendered = ParsableText.rst("""``test``""")
     assert "<code" in rendered and "</code>" in rendered
示例#16
0
 def __init__(self, task, problemid, content):
     super(DisplayableBasicProblem, self).__init__(task, problemid, content)
     self._header = ParsableText(self._header, "rst")
    def test_hidden_until_before(self):
        assert "Something" not in ParsableText.rst("""
        .. hidden-until:: 22/05/2102

            Something
        """)
    def test_hidden_until_after(self):
        assert "Something" in ParsableText.rst("""
        .. hidden-until:: 22/05/2002

            Something
        """)
示例#19
0
    def __init__(self, task, problemid, content):
        super(DisplayableMultipleChoiceProblem,
              self).__init__(task, problemid, content)

        for choice in self._choices:
            choice["text"] = ParsableText(choice['text'], 'rst')
    def test_hidden_until_before(self):
        assert "Something" not in ParsableText.rst("""
        .. hidden-until:: 22/05/2102

            Something
        """)
 def test_html_tidy(self):
     rendered = ParsableText.html('<non existing tag></...>')
     assert '<non existing tag>' not in rendered
 def test_html_tidy(self):
     rendered = ParsableText.html('<non existing tag></...>')
     assert '<non existing tag>' not in rendered
 def test_unicode(self):
     rendered = unicode(ParsableText.rst(u"""``😁``"""))
     assert "<code" in rendered and "</code>" in rendered and u"😁" in rendered
示例#24
0
    def POST_AUTH(self, courseid, taskid, isLTI):
        """ POST a new submission """
        username = self.user_manager.session_username()
        try:
            course = self.course_factory.get_course(courseid)
            if not self.user_manager.course_is_open_to_user(
                    course, username, isLTI):
                return self.template_helper.get_renderer().course_unavailable()

            task = course.get_task(taskid)
            if not self.user_manager.task_is_visible_by_user(
                    task, username, isLTI):
                return self.template_helper.get_renderer().task_unavailable()

            self.user_manager.user_saw_task(username, courseid, taskid)

            is_staff = self.user_manager.has_staff_rights_on_course(
                course, username)
            is_admin = self.user_manager.has_admin_rights_on_course(
                course, username)

            userinput = web.input()
            if "@action" in userinput and userinput["@action"] == "customtest":
                # Reparse user input with array for multiple choices
                init_var = list_multiple_multiple_choices_and_files(task)
                userinput = task.adapt_input_for_backend(web.input(**init_var))

                if not task.input_is_consistent(
                        userinput, self.default_allowed_file_extensions,
                        self.default_max_file_size):
                    web.header('Content-Type', 'application/json')
                    return json.dumps({
                        "status":
                        "error",
                        "text":
                        "Please answer to all the questions and verify the extensions of the files "
                        "you want to upload. Your responses were not tested."
                    })

                try:
                    result, grade, problems, tests, custom, archive, stdout, stderr = self.submission_manager.add_unsaved_job(
                        task, userinput)

                    data = {
                        "status": ("done" if result[0] == "success"
                                   or result[0] == "failed" else "error"),
                        "result":
                        result[0],
                        "text":
                        ParsableText(result[1]).parse(),
                        "stdout":
                        custom.get("custom_stdout", ""),
                        "stderr":
                        custom.get("custom_stderr", "")
                    }

                    web.header('Content-Type', 'application/json')
                    return json.dumps(data)

                except Exception as ex:
                    web.header('Content-Type', 'application/json')
                    return json.dumps({"status": "error", "text": str(ex)})

            elif "@action" in userinput and userinput["@action"] == "submit":
                # Verify rights
                if not self.user_manager.task_can_user_submit(
                        task, username, isLTI):
                    return json.dumps({
                        "status":
                        "error",
                        "text":
                        "You are not allowed to submit for this task."
                    })

                # Reparse user input with array for multiple choices
                init_var = list_multiple_multiple_choices_and_files(task)
                userinput = task.adapt_input_for_backend(web.input(**init_var))

                if not task.input_is_consistent(
                        userinput, self.default_allowed_file_extensions,
                        self.default_max_file_size):
                    web.header('Content-Type', 'application/json')
                    return json.dumps({
                        "status":
                        "error",
                        "text":
                        "Please answer to all the questions and verify the extensions of the files "
                        "you want to upload. Your responses were not tested."
                    })

                # Get debug info if the current user is an admin
                debug = is_admin
                if "@debug-mode" in userinput:
                    if userinput["@debug-mode"] == "ssh" and debug:
                        debug = "ssh"
                    del userinput['@debug-mode']

                # Start the submission
                try:
                    submissionid, oldsubids = self.submission_manager.add_job(
                        task, userinput, debug)
                    web.header('Content-Type', 'application/json')
                    return json.dumps({
                        "status": "ok",
                        "submissionid": str(submissionid),
                        "remove": oldsubids
                    })
                except Exception as ex:
                    web.header('Content-Type', 'application/json')
                    return json.dumps({"status": "error", "text": str(ex)})

            elif "@action" in userinput and userinput[
                    "@action"] == "check" and "submissionid" in userinput:
                result = self.submission_manager.get_submission(
                    userinput['submissionid'])
                if result is None:
                    web.header('Content-Type', 'application/json')
                    return json.dumps({'status': "error"})
                elif self.submission_manager.is_done(result):
                    web.header('Content-Type', 'application/json')
                    result = self.submission_manager.get_input_from_submission(
                        result)
                    result = self.submission_manager.get_feedback_from_submission(
                        result, show_everything=is_staff)

                    # user_task always exists as we called user_saw_task before
                    user_task = self.database.user_tasks.find_one({
                        "courseid":
                        task.get_course_id(),
                        "taskid":
                        task.get_id(),
                        "username":
                        self.user_manager.session_username()
                    })

                    submissionid = user_task.get('submissionid', None)
                    default_submission = self.database.submissions.find_one(
                        {'_id': ObjectId(submissionid)
                         }) if submissionid else None
                    if default_submission is None:
                        self.set_selected_submission(course, task,
                                                     userinput['submissionid'])
                    return submission_to_json(
                        result, is_admin, False,
                        True if default_submission is None else
                        default_submission['_id'] == result['_id'])

                else:
                    web.header('Content-Type', 'application/json')
                    if "ssh_host" in result:
                        return json.dumps({
                            'status':
                            "waiting",
                            'ssh_host':
                            result["ssh_host"],
                            'ssh_port':
                            result["ssh_port"],
                            'ssh_password':
                            result["ssh_password"]
                        })
                    # Here we are waiting. Let's send some useful information.
                    waiting_data = self.submission_manager.get_job_queue_info(
                        result["jobid"]) if "jobid" in result else None
                    if waiting_data is not None:
                        nb_tasks_before, approx_wait_time = waiting_data
                        return json.dumps({
                            'status': "waiting",
                            'nb_tasks_before': nb_tasks_before,
                            'approx_wait_time': approx_wait_time
                        })
                    return json.dumps({'status': "waiting"})
            elif "@action" in userinput and userinput[
                    "@action"] == "load_submission_input" and "submissionid" in userinput:
                submission = self.submission_manager.get_submission(
                    userinput["submissionid"])
                submission = self.submission_manager.get_input_from_submission(
                    submission)
                submission = self.submission_manager.get_feedback_from_submission(
                    submission, show_everything=is_staff)
                if not submission:
                    raise web.notfound()
                web.header('Content-Type', 'application/json')
                return submission_to_json(submission, is_admin, True)
            elif "@action" in userinput and userinput[
                    "@action"] == "kill" and "submissionid" in userinput:
                self.submission_manager.kill_running_submission(
                    userinput["submissionid"])  # ignore return value
                web.header('Content-Type', 'application/json')
                return json.dumps({'status': 'done'})
            elif "@action" in userinput and userinput[
                    "@action"] == "set_submission" and "submissionid" in userinput:
                web.header('Content-Type', 'application/json')
                if task.get_evaluate() != 'student':
                    return json.dumps({'status': "error"})

                if self.set_selected_submission(course, task,
                                                userinput["submissionid"]):
                    return json.dumps({'status': 'done'})
                else:
                    return json.dumps({'status': 'error'})
            else:
                raise web.notfound()
        except:
            if web.config.debug:
                raise
            else:
                raise web.notfound()
 def test_code(self):
     rendered = ParsableText.rst("""``test``""")
     assert "<code" in rendered and "</code>" in rendered
 def test_html_tidy(self):
     rendered = ParsableText.html("<non existing tag></...>")
     assert "<non existing tag>" not in rendered
 def test_unicode(self):
     rendered = unicode(ParsableText.rst(u"""``😁``"""))
     assert "<code" in rendered and "</code>" in rendered and u"😁" in rendered
    def test_hidden_until_before_admin(self):
        assert "Something" in ParsableText.rst("""
            .. hidden-until:: 22/05/2102

                Something
            """, show_everything=True)
    def test_hidden_until_after(self):
        assert "Something" in ParsableText.rst("""
        .. hidden-until:: 22/05/2002

            Something
        """)