Exemplo n.º 1
0
def add_job(task, inputdata, debug=False):
    """ Add a job in the queue and returns a submission id.
        task is a Task instance and inputdata is the input as a dictionary
        If debug is true, more debug data will be saved
    """
    if not User.is_logged_in():
        raise Exception("A user must be logged in to submit an object")

    username = User.get_username()
    course = FrontendCourse(task.get_course_id())

    obj = {
        "courseid": task.get_course_id(),
        "taskid": task.get_id(),
        "input": get_gridfs().put(
            json.dumps(inputdata)),
        "status": "waiting",
        "submitted_on": datetime.now()}

    if course.is_group_course() and username not in course.get_staff(True):
        group = get_database().groups.find_one({"course_id": task.get_course_id(), "users": username})
        obj.update({"username": group["users"]})
    else:
        obj.update({"username": [username]})

    submissionid = get_database().submissions.insert(obj)

    PluginManager.get_instance().call_hook("new_submission", submissionid=submissionid, submission=obj, inputdata=inputdata)

    get_job_manager().new_job(task, inputdata, (lambda job: _job_done_callback(submissionid, task, job)), "Frontend - {}".format(username), debug)

    return submissionid
Exemplo n.º 2
0
def get_course_and_check_rights(courseid, taskid=None, allow_all_staff=True):
    """ Returns the course with id ```courseid``` and the task with id ```taskid```, and verify the rights of the user.
        Raise web.notfound() when there is no such course of if the users has not enough rights.

        :param courseid: the course on which to check rights
        :param taskid: If not None, returns also the task with id ```taskid```
        :param allow_all_staff: allow admins AND tutors to see the page. If false, all only admins.
        :returns (Course, Task)
    """

    try:
        if User.is_logged_in():
            course = FrontendCourse(courseid)
            if allow_all_staff:
                if User.get_username() not in course.get_staff():
                    raise web.notfound()
            else:
                if User.get_username() not in course.get_admins():
                    raise web.notfound()

            if taskid is None:
                return (course, None)
            else:
                return (course, course.get_task(taskid))
        else:
            raise web.notfound()
    except:
        raise web.notfound()
Exemplo n.º 3
0
    def GET(self, courseid, taskid, path):
        """ GET request """
        if User.is_logged_in():
            try:
                course = FrontendCourse(courseid)
                if not course.is_open_to_user(User.get_username()):
                    return renderer.course_unavailable()

                task = course.get_task(taskid)
                if not task.is_visible_by_user(User.get_username()):
                    return renderer.task_unavailable()

                path_norm = posixpath.normpath(urllib.unquote(path))
                public_folder_path = os.path.normpath(os.path.realpath(os.path.join(INGIniousConfiguration["tasks_directory"], courseid, taskid, "public")))
                file_path = os.path.normpath(os.path.realpath(os.path.join(public_folder_path, path_norm)))

                # Verify that we are still inside the public directory
                if os.path.normpath(os.path.commonprefix([public_folder_path, file_path])) != public_folder_path:
                    raise web.notfound()

                if os.path.isfile(file_path):
                    mimetypes.init()
                    mime_type = mimetypes.guess_type(file_path)
                    web.header('Content-Type', mime_type[0])
                    with open(file_path) as static_file:
                        return static_file.read()
                else:
                    raise web.notfound()
            except:
                if web.config.debug:
                    raise
                else:
                    raise web.notfound()
        else:
            return renderer.index(False)
Exemplo n.º 4
0
    def GET(self, courseid):
        """ GET request """

        if User.is_logged_in():
            try:
                course = FrontendCourse(courseid)
                if not course.is_open_to_user(User.get_username()):
                    return renderer.course_unavailable()

                last_submissions = course.get_user_last_submissions(one_per_task=True)
                except_free_last_submissions = []
                for submission in last_submissions:
                    try:
                        submission["task"] = course.get_task(submission['taskid'])
                        except_free_last_submissions.append(submission)
                    except:
                        pass
                return renderer.course(course, except_free_last_submissions)
            except:
                if web.config.debug:
                    raise
                else:
                    raise web.notfound()
        else:
            return renderer.index(False)
Exemplo n.º 5
0
    def GET(self, courseid):
        """ GET request """

        if User.is_logged_in():
            try:
                course = FrontendCourse(courseid)
                registration_uncomplete = not course.is_open_to_user(User.get_username(), course.is_group_course())
                if registration_uncomplete and course.can_students_choose_group():
                    raise web.seeother("/group/"+courseid)
                elif registration_uncomplete:
                    return renderer.course_unavailable()

                last_submissions = course.get_user_last_submissions(one_per_task=True)
                except_free_last_submissions = []
                for submission in last_submissions:
                    try:
                        submission["task"] = course.get_task(submission['taskid'])
                        except_free_last_submissions.append(submission)
                    except:
                        pass

                return renderer.course(course, except_free_last_submissions)
            except:
                if web.config.debug:
                    raise
                else:
                    raise web.notfound()
        else:
            return renderer.index(False)
Exemplo n.º 6
0
def update_database():
    db_version = get_database().db_version.find_one({})
    if db_version is None:
        db_version = 0
    else:
        db_version = db_version['db_version']

    if db_version < 1:
        print "Updating database to db_version 1"
        # Init the database
        get_database().submissions.ensure_index([("username", pymongo.ASCENDING)])
        get_database().submissions.ensure_index([("courseid", pymongo.ASCENDING)])
        get_database().submissions.ensure_index([("courseid", pymongo.ASCENDING), ("taskid", pymongo.ASCENDING)])
        get_database().submissions.ensure_index([("submitted_on", pymongo.DESCENDING)])  # sort speed

        get_database().user_tasks.ensure_index([("username", pymongo.ASCENDING), ("courseid", pymongo.ASCENDING), ("taskid", pymongo.ASCENDING)],
                                               unique=True)
        get_database().user_tasks.ensure_index([("username", pymongo.ASCENDING), ("courseid", pymongo.ASCENDING)])
        get_database().user_tasks.ensure_index([("courseid", pymongo.ASCENDING), ("taskid", pymongo.ASCENDING)])
        get_database().user_tasks.ensure_index([("courseid", pymongo.ASCENDING)])
        get_database().user_tasks.ensure_index([("username", pymongo.ASCENDING)])

        db_version = 1

    if db_version < 2:
        print "Updating database to db_version 2"
        # Register users that submitted some tasks to the related courses
        data = get_database().user_tasks.aggregate([{"$group": {"_id": "$courseid", "usernames": {"$addToSet": "$username"}}}])
        for r in list(data):
            try:
                course = FrontendCourse(r['_id'])
                for u in r['usernames']:
                    course.register_user(u, force=True)
            except:
                print "There was an error while updating the database. Some users may have been unregistered from the course {}".format(r['_id'])
        db_version = 2

    if db_version < 3:
        print "Updating database to db_version 3"
        # Add the grade for all the old submissions
        get_database().submissions.update({}, {"$set": {"grade": 0.0}}, multi=True)
        get_database().submissions.update({"result": "success"}, {"$set": {"grade": 100.0}}, multi=True)
        get_database().user_tasks.update({}, {"$set": {"grade": 0.0}}, multi=True)
        get_database().user_tasks.update({"succeeded": True}, {"$set": {"grade": 100.0}}, multi=True)
        db_version = 3

    get_database().db_version.update({}, {"$set": {"db_version": db_version}}, upsert=True)
Exemplo n.º 7
0
    def get_course_data_for_users(cls, courseid, users=None):
        """
            Returns data of users for a specific course. users is a list of username. If users is none, data from all users will be returned.

            The returned value is a dict:

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

            Please note that only the task already seen at least one time will be present in the dict task_grades.
        """
        from frontend.custom.courses import FrontendCourse

        course = FrontendCourse(courseid)
        match = {"courseid": courseid}
        if users is not None:
            match["username"] = {"$in": users}

        tasks = course.get_tasks()
        taskids = tasks.keys()
        match["taskid"] = {"$in": taskids}

        data = list(get_database().user_tasks.aggregate(
            [
                {"$match": match},
                {"$group": {
                    "_id": "$username",
                    "task_tried": {"$sum": {"$cond": [{"$ne": ["$tried", 0]}, 1, 0]}},
                    "total_tries": {"$sum": "$tried"},
                    "task_succeeded": {"$addToSet": {"$cond": ["$succeeded", "$taskid", False]}},
                    "task_grades": {"$addToSet": {"taskid": "$taskid", "grade": "$grade"}}
                }}
            ]))
        if len(data) != 0:
            return_data = {}
            for result in data:
                username = result["_id"]
                user_tasks = set([taskid for taskid, task in tasks.iteritems() if task.is_visible_by_user(username)])
                result["total_tasks"] = len(user_tasks)
                result["task_succeeded"] = len(set(result["task_succeeded"]).intersection(user_tasks))
                result["task_grades"] = {dg["taskid"]: dg["grade"] for dg in result["task_grades"] if dg["taskid"] in user_tasks}
                del result["_id"]
                return_data[username] = result
            return return_data
        else:
            return {}
Exemplo n.º 8
0
def get_course_and_check_rights(courseid, taskid=None):
    """ Return the course with id, and verify the rights of the user to administer it.
        Raise web.notfound() when there is no such course of if the users has not enough rights.
        If taskid is not None, also returns tyhe tuple (course, task). """
    try:
        if User.is_logged_in():
            course = FrontendCourse(courseid)
            if User.get_username() not in course.get_admins():
                raise web.notfound()

            if taskid is None:
                return course
            else:
                return (course, course.get_task(taskid))
        else:
            raise web.notfound()
    except:
        raise web.notfound()
Exemplo n.º 9
0
    def GET(self, courseid, taskid):
        """ GET request """
        if User.is_logged_in():
            try:
                course = FrontendCourse(courseid)
                if not course.is_open_to_user(User.get_username()):
                    return renderer.course_unavailable()

                task = course.get_task(taskid)
                if not task.is_visible_by_user(User.get_username()):
                    return renderer.task_unavailable()

                User.get_data().view_task(courseid, taskid)

                userinput = web.input()
                if "submissionid" in userinput and "questionid" in userinput:
                    # Download a previously submitted file
                    submission = submission_manager.get_submission(userinput["submissionid"], True)
                    if submission is None:
                        raise web.notfound()
                    sinput = submission_manager.get_input_from_submission(submission, True)
                    if userinput["questionid"] not in sinput:
                        raise web.notfound()

                    if isinstance(sinput[userinput["questionid"]], dict):
                        # File uploaded previously
                        mimetypes.init()
                        mime_type = mimetypes.guess_type(urllib.pathname2url(sinput[userinput["questionid"]]['filename']))
                        web.header('Content-Type', mime_type[0])
                        return base64.b64decode(sinput[userinput["questionid"]]['value'])
                    else:
                        # Other file, download it as text
                        web.header('Content-Type', 'text/plain')
                        return sinput[userinput["questionid"]]
                else:
                    # Display the task itself
                    return renderer.task(course, task, submission_manager.get_user_submissions(task))
            except:
                if web.config.debug:
                    raise
                else:
                    raise web.notfound()
        else:
            return renderer.index(False)
Exemplo n.º 10
0
    def call_main(self):
        """ Display main page (only when logged) """

        username = User.get_username()

        # Handle registration to a course
        user_input = web.input()
        registration_status = None
        if "register_courseid" in user_input and user_input["register_courseid"] != "":
            try:
                course = FrontendCourse(user_input["register_courseid"])
                if not course.is_registration_possible(username):
                    registration_status = False
                else:
                    registration_status = course.register_user(username, user_input.get("register_password", None))
            except:
                registration_status = False
        if "unregister_courseid" in user_input:
            try:
                course = FrontendCourse(user_input["unregister_courseid"])
                course.unregister_user(username)
            except:
                pass

        # Display
        last_submissions = get_user_last_submissions({}, 5, True)
        except_free_last_submissions = []
        for submission in last_submissions:
            try:
                submission["task"] = FrontendCourse(submission['courseid']).get_task(submission['taskid'])
                except_free_last_submissions.append(submission)
            except:
                pass

        all_courses = FrontendCourse.get_all_courses()

        open_courses = {courseid: course for courseid, course in all_courses.iteritems() if course.is_open_to_user(username)}
        open_courses = OrderedDict(sorted(open_courses.iteritems(), key=lambda x: x[1].get_name()))

        registerable_courses = {courseid: course for courseid, course in all_courses.iteritems() if not course.is_open_to_user(username) and course.is_registration_possible(username)}
        registerable_courses = OrderedDict(sorted(registerable_courses.iteritems(), key=lambda x: x[1].get_name()))

        return renderer.main(open_courses, registerable_courses, except_free_last_submissions, registration_status)
Exemplo n.º 11
0
    def POST(self, courseid, taskid):
        """ POST a new submission """
        if User.is_logged_in():
            try:
                course = FrontendCourse(courseid)
                if not course.is_open_to_user(User.get_username()):
                    return renderer.course_unavailable()

                task = course.get_task(taskid)
                if not task.is_visible_by_user(User.get_username()):
                    return renderer.task_unavailable()

                User.get_data().view_task(courseid, taskid)
                userinput = web.input()
                if "@action" in userinput and userinput["@action"] == "submit":
                    # Verify rights
                    if not task.can_user_submit(User.get_username()):
                        return json.dumps({"status": "error", "text": "The deadline is over"})

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

                    if not task.input_is_consistent(userinput):
                        web.header('Content-Type', 'application/json')
                        return json.dumps({"status": "error", "text": "Please answer to all the questions. Your responses were not tested."})
                    del userinput['@action']

                    # Get debug info if the current user is an admin
                    debug = User.get_username() in course.get_admins()

                    # Start the submission
                    submissionid = submission_manager.add_job(task, userinput, debug)

                    web.header('Content-Type', 'application/json')
                    return json.dumps({"status": "ok", "submissionid": str(submissionid)})
                elif "@action" in userinput and userinput["@action"] == "check" and "submissionid" in userinput:
                    if submission_manager.is_done(userinput['submissionid']):
                        web.header('Content-Type', 'application/json')
                        result = submission_manager.get_submission(userinput['submissionid'])
                        result = submission_manager.get_input_from_submission(result)
                        return self.submission_to_json(result, User.get_username() in course.get_admins())
                    else:
                        web.header('Content-Type', 'application/json')
                        return json.dumps({'status': "waiting"})
                elif "@action" in userinput and userinput["@action"] == "load_submission_input" and "submissionid" in userinput:
                    submission = submission_manager.get_submission(userinput["submissionid"])
                    submission = submission_manager.get_input_from_submission(submission)
                    if not submission:
                        raise web.notfound()
                    web.header('Content-Type', 'application/json')
                    return self.submission_to_json(submission, (User.get_username() in course.get_admins()), True)
                else:
                    raise web.notfound()
            except:
                if web.config.debug:
                    raise
                else:
                    raise web.notfound()
        else:
            return renderer.index(False)
Exemplo n.º 12
0
    def GET(self, courseid):
        # try:
        course = FrontendCourse(courseid)
        contest_data = get_contest_data(course)
        if not contest_data['enabled']:
            raise web.notfound()
        start = datetime.strptime(contest_data['start'], "%Y-%m-%d %H:%M:%S")
        end = datetime.strptime(contest_data['end'], "%Y-%m-%d %H:%M:%S")
        blackout = end - timedelta(hours=contest_data['blackout'])

        users = course.get_registered_users(True)
        tasks = course.get_tasks().keys()

        db_results = get_database().submissions.find({
            "username": {"$in": users},
            "courseid": courseid,
            "submitted_on": {"$gte": start, "$lt": blackout},
            "status": "done"},
            {"username": True, "_id": False, "taskid": True, "result": True, "submitted_on": True}).sort([("submitted_on", pymongo.ASCENDING)])

        task_status = {taskid: {"status": "NA", "tries": 0} for taskid in tasks}
        results = {username: {"name": UserData(username).get_data()['realname'], "tasks": copy.deepcopy(task_status)} for username in users}
        activity = []

        # Compute stats for each submission
        task_succeeded = {taskid: False for taskid in tasks}
        for submission in db_results:
            if submission['taskid'] not in tasks:
                continue
            if submission['username'] not in users:
                continue
            status = results[submission['username']]["tasks"][submission['taskid']]
            if status["status"] == "AC" or status["status"] == "ACF":
                continue
            else:
                if submission['result'] == "success":
                    if not task_succeeded[submission['taskid']]:
                        status["status"] = "ACF"
                        task_succeeded[submission['taskid']] = True
                    else:
                        status["status"] = "AC"
                    status["tries"] += 1
                    status["time"] = submission['submitted_on']
                    status["score"] = ((submission['submitted_on'] + (
                    timedelta(minutes=contest_data["penalty"]) * (status["tries"] - 1))) - start).total_seconds() / 60
                elif submission['result'] == "failed":
                    status["status"] = "WA"
                    status["tries"] += 1
                elif submission['result'] == "timeout":
                    status["status"] = "TLE"
                    status["tries"] += 1
                else:  # other internal error
                    continue
                activity.append({"user": results[submission['username']]["name"],
                                 "when": submission['submitted_on'],
                                 "result": (status["status"] == 'AC' or status["status"] == 'ACF'),
                                 "taskid": submission['taskid']})
        activity.reverse()
        # Compute current score
        for user in results:
            score = [0, 0]
            for data in results[user]["tasks"].values():
                if "score" in data:
                    score[0] += 1
                    score[1] += data["score"]
            results[user]["score"] = tuple(score)

        # Sort everybody
        results = OrderedDict(sorted(results.items(), key=lambda t: (-t[1]["score"][0], t[1]["score"][1])))

        # Compute ranking
        old = None
        current_rank = 0
        for cid, user in enumerate(results.keys()):
            if results[user]["score"] != old:
                old = results[user]["score"]
                current_rank = cid + 1
                results[user]["rank"] = current_rank
                results[user]["displayed_rank"] = str(current_rank)
            else:
                results[user]["rank"] = current_rank
                results[user]["displayed_rank"] = ""

        return get_template_renderer('plugins/contests', '../../templates/layout').scoreboard(course, start, end, blackout, tasks, results, activity)