Exemplo n.º 1
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.º 2
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)