Ejemplo n.º 1
0
def next_task(guts):
    """Get the next task for a user, and redirect.
    
    It is possible this belongs with the task views.

    # TODO: Testing
    
    The input request should have a logged in user. The result
    should be:
     * If the user has nothing to do, redirect to the home page.
     * If the user has a pending review, redirect to that review's page.
     * If the user has a task in an auto-review project to look at,
       redirect to that page.
     * If the user either has a WorkInProgress or there is a task
       available for them to work on, a redirect to that task's page.
     * If a WorkInProgress exists, the .start_time property of the
       WIP should be updated to the current time.
     * If no WIP exists, one should be created with the next available
       task and the current logged in user.
    """
    review = Review.objects.filter(response__user=guts.user, complete=False)
    if review.count():
        return ViewResponse('main:next-review')

    auto_review_pending = AutoReview.objects.filter(user=guts.user,
                                                    start_time__isnull=False,
                                                    end_time__isnull=True)
    if auto_review_pending.exists():
        return ViewResponse('main:view-task', auto_review_pending[0].task.id)
    new_auto_reviews = AutoReview.objects.filter(
        user=guts.user,
        task__project__priority__gte=0,
        start_time__isnull=True,
        end_time__isnull=True,
    ).order_by("-task__project__priority")
    if new_auto_reviews.exists():
        auto_review = new_auto_reviews[0]
        auto_review.start_time = timezone.now()
        auto_review.full_clean()
        auto_review.save()
        return ViewResponse('main:view-task', auto_review.task.id)

    wip = None
    wips = WorkInProgress.objects.filter(user=guts.user)
    if wips.count():
        wip = wips[0]
        wip.start_time = timezone.now()
        wip.full_clean()
        wip.save()
    else:
        task = Task.objects.next_for(guts.user)
        if task:
            wip = WorkInProgress(user=guts.user, task=task)
            wip.full_clean()
            wip.save()
    if wip:
        return ViewResponse('main:view-task', wip.task.id)
    else:
        return ViewResponse('main:home')
Ejemplo n.º 2
0
def next_review(guts):
    """If a user has an outstanding task to review, redirect them to it.
       Otherwise, redirect them to the homepage."""
    import main.views.base

    review = Review.objects.filter(response__user=guts.user, complete=False)
    if review.count():
        review = review[0]
        return ViewResponse('main:view-task', review.id)
    return ViewResponse('main:home')
Ejemplo n.º 3
0
def wip_review(get, guts):
    if guts.user.is_superuser:
        wips = WorkInProgress.objects.all()
    elif Project.objects.filter(admin=guts.user).count():
        wips = WorkInProgress.objects.filter(task__project__admin=guts.user)
    else:
        return ForbiddenResponse(
            "Only project administrators and superusers may see this page.")
    if get:
        wip_list = [{
            "id": wip.id,
            "user": wip.user.username,
            "task_id": wip.task.id,
            "task_url": wip.task.get_absolute_url(),
            "project_id": wip.task.project.id,
            "project_name": wip.task.project.title,
            "project_url": wip.task.project.get_absolute_url(),
            "start_time": wip.start_time,
        } for wip in wips.order_by("-start_time")]
        template_data = {"wips": wip_list}
        template = get_template("wip-review.html")
        return TemplateResponse(template, template_data)
    else:
        try:
            wips_to_delete = [
                wips.get(pk=pk)
                for pk in guts.parameters.getlist("wips_to_delete")
            ]
            for wip in wips_to_delete:
                wip.delete()
            return ViewResponse('main:wip-list')
        except WorkInProgress.DoesNotExist:
            return ForbiddenResponse("You can only delete a project "
                                     "that you are an admin for.")
Ejemplo n.º 4
0
def task_review(get, guts, review_id):
    """Present an interface to request the user to review 
       a given task."""
    review = get_object_or_404(Review, pk=review_id)
    response = review.response
    ## NOTE: an earlier version of this code would throw a Review.DoesNotExist exception
    ## if the Review object with the right id and user had complete=True.  I don't see
    ## the harm in re-reviewing so I am not checking for that here.
    if (response.user != guts.user) and not (guts.user.is_superuser or get):
        return ForbiddenResponse("You are not authorized to see this review.")
    if get:
        task = response.task
        project_type = get_project_type(task.project)
        task = project_type.cast(task)
        try:
            template = get_template(review.review_template)
        except NotImplementedError:
            template = task.template()
        template_data = task.template_data(review=review)
        return TemplateResponse(template, template_data)
    else:
        review.complete = True
        review.full_clean()
        review.save()
        return ViewResponse('main:next-review')
Ejemplo n.º 5
0
def task_adhoc_review(get, guts):
    if get:
        response_id = guts.parameters['response']
        response = Response.objects.get(pk=response_id)
        reviews = Review.objects.filter(response=response)
        if reviews.count() == 1:
            review = reviews[0]
        else:
            review = Review(response=response, comment="")
        task = response.task
        result = task.result
        # Tagger or merger can both view, as well as super-user
        if ((response.user != guts.user) and not (guts.user.is_superuser)
                and (result.user != guts.user)):
            return ForbiddenResponse(
                "You are not authorized to see this review.")
        project_type = get_project_type(task.project)
        task = project_type.cast(task)
        try:
            template = get_template(review.review_template)
        except NotImplementedError:
            template = task.template()
        template_data = task.template_data(review=review)
        return TemplateResponse(template, template_data)
    else:
        return ViewResponse('main:next-review')
Ejemplo n.º 6
0
def unmerge(get, guts, task_id):
    """Given a task that has already been merged, undo the merge, give
    the user a WIP for re-merging it, and redirect to the page for
    handling that WIP.  This operation may not be supported for all
    project types, and may only be executed by a superuser."""
    if guts.user.is_superuser:
        if not get:
            task = get_object_or_404(Task, pk=task_id)
            project_type = get_project_type(task.project)
            task = project_type.cast(task)
            task.handle_unmerge()
            wip = WorkInProgress(user=guts.user, task=task)
            wip.full_clean()
            wip.save()
        return ViewResponse('main:view-task', task_id)
    else:
        return ForbiddenResponse("Only superusers may perform this operation.")
Ejemplo n.º 7
0
def project_upload(get, guts, project):
    """Take an upload, and queue it for running through the task processor.
    
    # TODO: Testing
    # TODO: Return something better than the current Upload complete response. (template)
    # TODO: fix allowing user to select project form a dropdown (project is in the URL).
    # TODO: only allow certain users to upload projects
    """
    ptype = get_project_type(project)
    project = ptype.cast(project)
    if get:
        template = get_template("project/upload_form.html")
        return TemplateResponse(template, {"form": UploadForm()})
    else:
        action = guts.parameters["action"]
        if action == "Upload":
            pu = ProjectUpload(project=project)
            item = UploadForm(guts.parameters, guts.files, instance=pu)
            if item.is_valid():
                item.save()
                if not hasattr(settings,
                               "PROCESS_INLINE") or settings.PROCESS_INLINE:
                    project.handle_input(pu)
                    if project.auto_review:
                        project.add_auto_reviews()
                    pu.complete = True
                    pu.save()
                    message = (
                        "Upload complete to project %s, tasks processed" %
                        project.id)
                else:
                    message = "Upload complete, queued as %s" % pu.id
                guts.log_info(message)
                return DefaultResponse(message)
            else:
                ## re-present the page with input errors marked
                template = get_template("project/upload_form.html")
                return TemplateResponse(template, {"form": item})
        elif action == "Empty":
            ## NOTE: if subclasses have customized the delete() method,
            ## this bulk-delete will not call it.
            Task.objects.filter(project=project).delete()
            return ViewResponse('main:view-project', project.id)
        else:
            return ErrorResponse("Bad form",
                                 "Action parameter %s not understood" % action)
Ejemplo n.º 8
0
def abandon_wip(get, guts):
    """A view to abandon a WIP. When GETting this page, the user sees
    the \"are you sure?\" page.  When POSTing, the first WIP that the
    user has is deleted.
    """
    if get:
        wips = WorkInProgress.objects.filter(user=guts.user)
        template = get_template("abandon_wip.html")
        return TemplateResponse(template, {'wips': wips})
    else:
        wips = WorkInProgress.objects.filter(user=guts.user)
        if wips.count():
            wip = wips[0]
            wip.delete()
            return ViewResponse('main:home')
        else:
            template = get_template("abandon_wip.html")
            return TemplateResponse(template, {"wips": wips})
Ejemplo n.º 9
0
def change_password(get, guts):
    message = ""
    if get:
        f = ChangePassForm()
    else:
        f = ChangePassForm(guts.parameters)
        if f.is_valid():
            cleaned = f.cleaned_data
            if (guts.user.check_password(cleaned['old_pass'])
                    and cleaned['pass1'] == cleaned['pass2']):
                guts.user.set_password(cleaned['pass1'])
                guts.user.save()
                return ViewResponse('main:home')
            elif not guts.user.check_password(cleaned['old_pass']):
                message = "You did not enter your current password correctly"
            else:
                message = "Passwords didn't match."
    template = get_template("change_password.html")
    return TemplateResponse(template, {
        'form': f,
        'user': guts.user,
        'message': message
    })
Ejemplo n.º 10
0
def task_view(get, guts, task_id):
    """View a given task ID or submit a response to it; in either
    case, this should dispatch appropriately based on the task's
    type."""
    import main.views.base

    task = Task.objects.get(pk=task_id)
    project_type = type_list[task.project.type]
    task = project_type.cast(task)
    try:
        wip = WorkInProgress.objects.get(task=task, user=guts.user)
    except WorkInProgress.DoesNotExist:
        if task.project.auto_review:
            try:
                ## Tasks in auto-review projects have a kludgey workflow:
                ## the task is responsible for noticing that it is in an
                ## auto-review project and adjusting the output of template()
                ## and template_data accordingly.
                ## When GETting the page, if a Response object already exists, then
                ## the output should be appropriate for displaying a review.
                auto_review = AutoReview.objects.get(task=task, user=guts.user)
                if get:
                    ## If the Task subclass has not been retrofitted to handle
                    ## auto-review projects, then this line will throw an exception
                    ## "TypeError: ... unexpected keyword argument 'auto_review_user'"
                    return TemplateResponse(
                        task.template(),
                        task.template_data(auto_review_user=guts.user))
                else:
                    ## NOTE: does the downcasting of task screw this query up?
                    response_query = Response.objects.filter(user=guts.user,
                                                             task=task)
                    if not response_query.exists():
                        ## No response?  Ask the task to make one!
                        kwargs = {
                            "user": guts.user,
                            "task": task,
                            "start_time": auto_review.start_time,
                        }
                        task.handle_response(guts, **kwargs)
                        ## (Note that this code path does NOT update the task's
                        ## completed_assignments field, because auto-review projects
                        ## do not have a limit on how many responses they can have.)
                        ##
                        ## And then GET this page again, so the user can see the review.
                        return ViewResponse('main:view-task', task_id)
                    else:
                        ## The user must have clicked the "I read this review" button.
                        auto_review.end_time = timezone.now()
                        auto_review.full_clean()
                        auto_review.save()
                        return ViewResponse('main:next-task')
            except AutoReview.DoesNotExist:
                ## fall through to the case below, since an admin is allowed to
                ## look at someone else's auto-review
                pass
        ## an admin can look at any task, but not even an admin
        ## can submit a response or result to a task without getting a WIP first
        if not (task.viewable_by(guts.user) and get):
            return ForbiddenResponse("You are not allowed to view %s." %
                                     six.text_type(task))
    if get:
        return TemplateResponse(task.template(), task.template_data())
    else:
        ## TODO: if we successfully make handle_response a method of the task,
        ## then we don't have to pass the task in kwargs
        kwargs = {
            "user": guts.user,
            "task": task,
            "start_time": wip.start_time
        }
        try:
            task.handle_response(guts, **kwargs)
            if task.completed:
                if 'review_user' in guts.parameters:
                    users = guts.parameters.getlist('review_user')
                    for user in users:
                        user_obj = User.objects.get(pk=user)
                        comment = guts.parameters.get("comment_%s" % user, "")
                        rev = Review(
                            response=task.response_set.get(user=user_obj),
                            comment=comment,
                        )
                        rev.full_clean()
                        rev.save()
            else:
                task.completed_assignments = task.completed_assignments + 1
                task.full_clean()
                task.save()
            wip.delete()
            if 'stop_working' in guts.parameters:
                return ViewResponse('main:home')
            else:
                return ViewResponse('main:next-task')
        except MultiValueDictKeyError:
            ## translate the MultiValueDict into a list of (key, list) pairs
            params = guts.parameters.lists()
            exc_type, exc_value, exc_traceback = sys.exc_info()
            tb_info = traceback.extract_tb(exc_traceback)
            template = get_template("parameter-error-in-task.html")
            context = {
                "task": str(task),
                "params": params,
                "exc_value": exc_value,
                "traceback": tb_info,
            }
            guts.log_error("Bad form? " + repr(context))
            return TemplateResponse(template, context, status=500)