Пример #1
0
def cache_solution_info(user, solutions):
    task_ids = [x.task_id for x in solutions]
    tasks = [x.task for x in solutions]
    check_prerequisites_for_tasks(tasks, user)

    if user.is_authenticated():
        my_solutions = Solution.objects.filter(author=user, task_id__in=task_ids)
        my_solutions = {x.task_id: x for x in my_solutions}
    else:
        my_solutions = {}

    # Can view solutions?
    # First, ignore those with SOLUTIONS_VISIBLE setting, and remove duplicates.
    explicit_ids = set([x.task_id for x in solutions    \
        if x.task.solution_settings != Task.SOLUTIONS_VISIBLE   \
        and x.task.author_id != user.id])
    if explicit_ids:
        # Second, if any left, ask for permissions.
        explicit_ids = get_object_ids_with_exclusive_permission(
            user, VIEW_SOLUTIONS, model=Task, filter_ids=explicit_ids)
    explicit_ids = set(explicit_ids)

    for y in solutions:
        y._cache_my_solution = my_solutions.get(y.task_id)
        y.task._cache_can_view_solutions = y.task_id in explicit_ids    \
            or y.task.solution_settings == Task.SOLUTIONS_VISIBLE       \
            or y.task.author_id == user.id

    return ''
Пример #2
0
 def _check_prereqs(self, tasks, user, expected):
     """
     Checks prerequisites for given tasks for "current" user.
     """
     check_prerequisites_for_tasks(tasks, user)
     for k, task in enumerate(tasks):
         msg = "{} is not {} for k = {}".format(
                 not expected[k], expected[k], k)
         self.assertEqual(task.cache_prerequisites_met, expected[k], msg=msg)
Пример #3
0
def cache_task_info_lite(context, tasks):
    """
        Prepares data for task list in options mode, where whole queryset
        is selected, and only basic info is visible (such as queryset length...)
    """
    ids = [x.id for x in tasks]

    check_prerequisites_for_tasks(tasks, context['user'])
    unlocked_ids = [x.id for x in tasks if not x.cache_prerequisites_met]

    # ------ context variables --------
    context['task_ids'] = ids
    context['unlocked_task_count'] = len(unlocked_ids)
    return ''
Пример #4
0
def homepage(request):
    recent_tasks = list(Task.objects.for_user(request.user, VIEW).select_related("content").order_by("-id")[:10])

    check_prerequisites_for_tasks(recent_tasks, request.user)

    # Filter visible tasks
    recent_tasks = [x for x in recent_tasks if x.cache_prerequisites_met]

    if len(recent_tasks) > 2:
        recent_tasks = random.sample(recent_tasks, 2)

    if request.user.is_authenticated():
        return homepage_online(request, recent_tasks)
    else:
        return homepage_offline(request, recent_tasks)
Пример #5
0
def homepage_online(request, recent_tasks):
    recommend = UserRecommendation.objects.raw(
        "SELECT A.id, A.task_id FROM recommend_userrecommendation A"
        "   LEFT JOIN solution_solution B"
        "       ON (A.task_id = B.task_id AND A.user_id = B.author_id)"
        "   WHERE A.user_id = {} AND (B.status IS NULL OR B.status = 0);".format(request.user.id)
    )
    recommend = list(x.task_id for x in recommend)
    if len(recommend) > 4:
        recommend = random.sample(recommend, 4)
    else:
        recommend = []  # Simplify design, accept only if there are 4 tasks.

    todo = Solution.objects.filter(author=request.user, status=SolutionStatus.TODO).values_list("task_id", flat=True)[
        :20
    ]
    if len(todo) > 2:
        todo = random.sample(todo, 2)
    else:
        todo = []  # Simplify design, ignore if only one to do task.

    all_tasks_to_read = todo + recommend
    if all_tasks_to_read:
        all_tasks = Task.objects.select_related("content").in_bulk(all_tasks_to_read)

        # Just in case something went wrong (probably with recommendations).
        check_prerequisites_for_tasks(all_tasks.itervalues(), request.user)
        all_tasks = {id: task for id, task in all_tasks.iteritems() if task.cache_prerequisites_met}

        recommend = [all_tasks[id] for id in recommend]
        todo = [all_tasks[id] for id in todo]

    # context, tasks
    cache_task_info({"user": request.user}, recommend + recent_tasks)

    return (
        "homepage_online.html",
        {
            "homepage": True,
            "folder_shortcut_desc": settings.FOLDER_HOMEPAGE_SHORTCUTS_ONLINE,
            "recent_tasks": recent_tasks,
            "recommend": recommend,
            "todo": todo,
        },
    )
Пример #6
0
def cache_task_info(context, tasks):
    """
        Prepares data (tags, solution status and similar) for task list.
        Usually just one page of tasks is considered.
    """
    # TODO: cache_task_info util method that takes user, not context.
    user = context['user']
    task_content_type = ContentType.objects.get_by_natural_key(app_label="task", model="task")
    ids = [x.id for x in tasks]

    # ----- tags -----
    tagovi = TaggedItem.objects.filter(content_type=task_content_type,
        object_id__in=ids).select_related('tag')
    tagged_items = collections.defaultdict(list)
    for x in tagovi:
        tagged_items[x.object_id].append(x)

    for task in tasks:
        task._cache_tagged_items = sorted(tagged_items[task.id],
            key=lambda x: (x.tag.name, x.votes_sum))

    # ----- solutions ------
    if user.is_authenticated():
        solutions = Solution.objects.filter(author=user, task_id__in=ids)
        solutions = {x.task_id: x for x in solutions}
        for task in tasks:
            task.cache_solution = solutions.get(task.id)

    check_prerequisites_for_tasks(tasks, user)

    # ----- folder edit -----
    if user.is_authenticated():
        folder = user.profile.selected_folder
        if folder is not None:
            selected_tasks = folder.tasks.filter(id__in=ids).values_list('id', flat=True)
            for task in tasks:
                task.is_in_folder = task.id in selected_tasks


    # ------ context variables --------
    context['task_ids'] = ids
    return ''
Пример #7
0
def profile(request, pk):
    if request.user.pk == pk:
        user = request.user
        solutions = Solution.objects
        tasks = Task.objects
    else:
        user = get_object_or_404(User.objects.select_related('profile'), pk=pk)
        solutions = Solution.objects.filter_visible_tasks_for_user(request.user)
        tasks = Task.objects.for_user(request.user, VIEW)

    # DEPRECATED. Distribution should be now updated automatically...
    # user.profile.refresh_diff_distribution()

    distribution = user.profile.get_diff_distribution()
    high = max(distribution)
    if high > 0:
        scale = 100.0 / max(high, 10)
        scaled = [int(x * scale) for x in distribution]
        distribution = zip(DIFFICULTY_RATING_ATTRS['titles'], scaled, distribution)
    else:
        distribution = None

    if request.user.id == pk:
        visible_groups = user.groups.select_related('data')
    else:
        where = '((SELECT id FROM auth_user_groups AG2 '            \
                    'WHERE AG2.group_id = auth_group.id AND AG2.user_id = {} ' \
                    'LIMIT 1)'                                      \
                ' IS NOT NULL OR usergroup_usergroup.hidden != 0)'  \
                .format(user.id)
        visible_groups = user.groups.select_related('data').extra(where=[where])

    visible_groups = visible_groups.exclude(id=user.get_profile().private_group_id)

    tags = UserTagScore.objects.filter(user=user).select_related('tag').order_by('-cache_score')[:10]


    solutions = solutions.filter(author_id=pk)  \
        .select_related('task')                 \
        .order_by('-date_created')
    todo = solutions.filter(status=SolutionStatus.TODO)[:10]
    solved = solutions.filter(
        status__in=[SolutionStatus.AS_SOLVED, SolutionStatus.SUBMITTED])[:10]

    if pk != request.user.pk:
        # TODO: optimize, do not load unnecessary my_solution
        # (separate check_accessibility should_obfuscate?)
        cache_solution_info(request.user, solved)
        for x in solved:
            x.t_can_view, dummy = x.check_accessibility(
                request.user, x._cache_my_solution)

    task_added = tasks.filter(author_id=pk).order_by('-id')[:10]

    all_tasks = [x.task for x in solved]    \
        + [x.task for x in todo]            \
        + list(task_added)

    check_prerequisites_for_tasks(all_tasks, request.user)

    return render_to_response('profile_detail.html', {
        'profile': user,
        'distribution': distribution,
        'visible_groups': visible_groups,
        'tags': tags,
        'todo': todo,
        'task_added': task_added,
        'solved': solved,
    }, context_instance=RequestContext(request))
Пример #8
0
def export(request, format=None, ids=None):
    """
        Exports tasks with given ids to given format.
        Format and ids can be given as GET or POST information.
    """

    # Please note that both TaskExportForm and unnamed form (format, ids)
    # use POST method. To prevent collision, submit button in TaskExportForm
    # is named 'action'.

    POST = request.POST.copy()

    # Move URL / GET data to POST
    if format and ids:
        POST['format'] = format
        POST['ids'] = ids
    else:
        format = POST.get('format')
        ids  = POST.get('ids')


    available_formats = dict(EXPORT_FORMAT_CHOICES)
    if not ids or format not in available_formats:
        raise Http404

    try:
        id_list = [int(x) for x in ids.split(',')]
    except ValueError:
        raise Http404

    # check for permissions
    # TODO: use some permissions util method
    tasks = Task.objects.for_user(request.user, VIEW).filter(id__in=id_list).distinct()
    if len(tasks) != len(id_list):
        raise Http404('Neki od navedenih zadataka ne postoje ili su skriveni.')

    check_prerequisites_for_tasks(tasks, request.user)
    removed_tasks = [x for x in tasks if not x.cache_prerequisites_met]

    if removed_tasks:
        # Remove them for the list.
        id_list = [x.id for x in tasks if x.cache_prerequisites_met]
        ids = ','.join(str(x) for x in id_list)

    # permission ok, use shortened query
    tasks = Task.objects.filter(id__in=id_list)

    # keep the same order as in id_list
    task_position = {id: position for position, id in enumerate(id_list)}
    sorted_tasks = list(tasks)
    sorted_tasks.sort(key=lambda task: task_position[task.id])

    for x in sorted_tasks:
        x.cache_prerequisites_met = True

    # force queryset evaluation and prepare all attachments...
    content_to_task = {}
    for task in tasks:
        task.cache_file_list = []
        content_to_task[task.content_id] = task

    # attachments
    query = "SELECT A.* FROM mathcontent_attachment A"                  \
            " INNER JOIN task_task B ON A.content_id = B.content_id"    \
            " WHERE B.id IN ({})".format(ids)
    attachments = list(Attachment.objects.raw(query))
    for attachment in attachments:
        content_to_task[attachment.content_id].cache_file_list.append(attachment)

    invalid_tasks = None
    if request.method == 'POST' and 'action' in POST:
        form = TaskExportForm(POST)
        if form.is_valid():
            # note that attachments are imported into each task as .cache_file_list
            ignore_exceptions = request.POST.get('ignore-exceptions')
            try:
                return _export(ids, sorted_tasks, tasks, form,
                        ignore_exceptions)
            except _ConvertException as e:
                invalid_tasks = e.invalid_tasks

    # otherwise, if form not given or not valid:

    create_archive = len(attachments) > 0
    if len(id_list) == 1:
        data = (format, ids, True, True, True, False, False, create_archive)
    else:
        data = (format, ids, False, False, False, False, True, create_archive)

    data = dict(zip(('format', 'ids', 'has_title', 'has_url', 'has_source',
        'has_index', 'has_id', 'create_archive'), data))
    form = TaskExportForm(data)

    if len(attachments):
        form.fields['create_archive'].label = \
            'Zip arhiva (ukupno datoteka: {}+1)'.format(len(attachments))
    else:
        form.fields['create_archive'].widget = forms.HiddenInput()

    return {
        'all_tasks': removed_tasks + sorted_tasks,
        'attachments': attachments,
        'form': form,
        'format': available_formats[format],
        'invalid_tasks': invalid_tasks,
        'removed_tasks': removed_tasks,
        'tasks': sorted_tasks,
    }