def get_session_overview(user):
    """
    Returns information about the last session student has been practicing.

    Returns:
        namedtuple 'session_overview'
    """
    student = StudentModel.objects.get_or_create(user=user)[0]
    session = sess_service.get_session(student)
    if session is None:
        instances = []
    else:
        instances = session.get_task_instances()
        if instances == [] or instances[-1].time_end is None:
            overall_time = 0
        else:
            overall_delta = instances[-1].time_end - instances[0].time_start
            overall_time = overall_delta.seconds
    percentils = []
    for instance in instances:
        percentils.append(statistics_service.percentil(instance) if instance.solved else None)
    return SessionOverview(
            task_instances = instances,
            overall_time = overall_time,
            percentils = percentils
            )
def process_attempt_report(user, report):
    """Process reported result of a solution attempt of a task

    Args:
        user: current user (user who took the attempt
        report: dictionary with the following fields:
            - task-instance-id
            - attempt
            - solved
            - time
            - code
    Returns:
        - whether the task is solved for the first time
        - number of earned-credits
        - speed-bonus: bool
    Raises:
        ValueError:
            - If the user argument is None.
            - If the report doesn't belong to the student.
            - If it's reporting an obsolete attempt (i.e. new attempt was
              already processed).
    """
    student = StudentModel.objects.get(user=user)
    # TODO: move the parsing of parameters to the view
    task_instance_id = report['task-instance-id']
    attempt_count = report['attempt']
    solved = report['solved']
    time = report['time']
    code = report['code']

    logger.info("Reporting attempt for student %s with result %s", student.pk, solved)
    task_instance = TaskInstanceModel.objects.get(id=task_instance_id)
    if  attempt_count < task_instance.attempt_count:
        # It means that this report is obsolete. Note that we allow for
        # equality of attempts count, which means that we want to update the
        # last report with more information (e.g. added flow report).
        raise ValueError("Obsolete attempt report can't be processed.")

    if student.pk != task_instance.student.pk:
        raise ValueError("Report doesn't belong to the student.")

    task_instance.update_after_attempt(
            attempt_count=attempt_count,
            time=time,
            solved=solved,
    )
    task_instance.save()
    task = task_instance.task
    student_task_info = StudentTaskInfoModel.objects.get_or_create(student=student, task=task)[0]
    solved_before = student_task_info.last_solved_instance is not None
    student_task_info.update(task_instance)
    student_task_info.save()

    if solved:
        see_task_concepts(student, task)

    credits = 0
    speed_bonus = False
    progress = []
    time, percentil = None, None

    if solved:
        task = task_instance.task
        time = task_instance.time_spent
        percentil = statistics_service.percentil(task_instance)
        if not solved_before:
            level = task.get_level()
            credits, speed_bonus = compute_credits(level, percentil)
            task_instance.earned_credits = credits
            task_instance.speed_bonus = speed_bonus
            progress = level_progress(student, credits)
            student.save()
            task_instance.save()

    Attempt.objects.create(
        task_instance=task_instance,
        order=task_instance.attempt_count,
        success=task_instance.solved,
        code=code
    )

    task_solved_first_time = solved and not solved_before
    logger.info("Reporting attempt was successful for student %s with result %s", student.pk, solved)
    result = namedtuple('processAttemptReportResult',
                        ['task_solved_first_time', 'time', 'percentil', 'credits', 'speed_bonus', 'progress'])\
                        (task_solved_first_time, time, percentil, credits, speed_bonus, progress)
    return result