<commit_before># This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from django.contrib import messages
from django.shortcuts import get_object_or_404, redirect
from django.views import generic

from django_filters.views import FilterView
from rest_framework import generics, permissions
from tower import ugettext as _

from oneanddone.base.util import get_object_or_none
from oneanddone.tasks.filters import AvailableTasksFilterSet
from oneanddone.tasks.forms import FeedbackForm
from oneanddone.tasks.mixins import TaskMustBePublishedMixin
from oneanddone.tasks.models import Feedback, Task, TaskArea, TaskAttempt
from oneanddone.tasks.serializers import TaskSerializer, TaskAreaSerializer
from oneanddone.users.mixins import UserProfileRequiredMixin


class AvailableTasksView(TaskMustBePublishedMixin, FilterView):
    queryset = Task.objects.order_by('-execution_time')
    context_object_name = 'available_tasks'
    template_name = 'tasks/available.html'
    paginate_by = 10
    filterset_class = AvailableTasksFilterSet


class TaskDetailView(TaskMustBePublishedMixin, generic.DetailView):
    model = Task
    template_name = 'tasks/detail.html'
    allow_expired_tasks = True

    def get_context_data(self, *args, **kwargs):
        ctx = super(TaskDetailView, self).get_context_data(*args, **kwargs)
        if self.request.user.is_authenticated():
            ctx['attempt'] = get_object_or_none(TaskAttempt, user=self.request.user,
                                                task=self.object, state=TaskAttempt.STARTED)
        return ctx


class StartTaskView(UserProfileRequiredMixin, TaskMustBePublishedMixin,
                    generic.detail.SingleObjectMixin, generic.View):
    model = Task

    def post(self, *args, **kwargs):
        task = self.get_object()
        if not task.is_available:
            messages.error(self.request, _('That task is unavailable at this time.'))
            return redirect('tasks.available')

        attempt, created = TaskAttempt.objects.get_or_create(user=self.request.user, task=task,
                                                             state=TaskAttempt.STARTED)
        return redirect(task)


class AbandonTaskView(UserProfileRequiredMixin, TaskMustBePublishedMixin,
                      generic.detail.SingleObjectMixin, generic.View):
    model = Task

    def post(self, *args, **kwargs):
        task = self.get_object()
        attempt = get_object_or_404(TaskAttempt, user=self.request.user, task=task,
                                    state=TaskAttempt.STARTED)
        attempt.state = TaskAttempt.ABANDONED
        attempt.save()
<commit_msg>Fixes #27 - Limit users to one task at a time<commit_after># This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from django.contrib import messages
from django.shortcuts import get_object_or_404, redirect
from django.views import generic

from django_filters.views import FilterView
from rest_framework import generics, permissions
from tower import ugettext as _

from oneanddone.base.util import get_object_or_none
from oneanddone.tasks.filters import AvailableTasksFilterSet
from oneanddone.tasks.forms import FeedbackForm
from oneanddone.tasks.mixins import TaskMustBePublishedMixin
from oneanddone.tasks.models import Feedback, Task, TaskArea, TaskAttempt
from oneanddone.tasks.serializers import TaskSerializer, TaskAreaSerializer
from oneanddone.users.mixins import UserProfileRequiredMixin


class AvailableTasksView(TaskMustBePublishedMixin, FilterView):
    queryset = Task.objects.order_by('-execution_time')
    context_object_name = 'available_tasks'
    template_name = 'tasks/available.html'
    paginate_by = 10
    filterset_class = AvailableTasksFilterSet


class TaskDetailView(TaskMustBePublishedMixin, generic.DetailView):
    model = Task
    template_name = 'tasks/detail.html'
    allow_expired_tasks = True

    def get_context_data(self, *args, **kwargs):
        ctx = super(TaskDetailView, self).get_context_data(*args, **kwargs)
        if self.request.user.is_authenticated():
            ctx['attempt'] = get_object_or_none(TaskAttempt, user=self.request.user,
                                                task=self.object, state=TaskAttempt.STARTED)
        return ctx


class StartTaskView(UserProfileRequiredMixin, TaskMustBePublishedMixin,
                    generic.detail.SingleObjectMixin, generic.View):
    model = Task

    def post(self, *args, **kwargs):

        # Do not allow users to take more than one task at a time
        if self.request.user.attempts_in_progress.exists():
            messages.error(self.request, _('You may only work on one task at a time.'))
            return redirect('users.profile.detail')

        task = self.get_object()
        if not task.is_available:
            messages.error(self.request, _('That task is unavailable at this time.'))
            return redirect('tasks.available')

        attempt, created = TaskAttempt.objects.get_or_create(user=self.request.user, task=task,
                                                             state=TaskAttempt.STARTED)
        return redirect(task)


class AbandonTaskView(UserProfileRequiredMixin, TaskMustBePublishedMixin,
                      generic.detail.SingleObjectMixin, generic.View):
    model = Task

    def post(self, *args, **kwargs):
        task = self.get_object()
        attempt = get_object_or_404(TaskAttempt, user=self.request.user, task=task,
                                    state=TaskAttempt.STARTED)
        attempt.state = TaskAttempt.ABANDONED
        attempt.save()

{'fraction_non_alphanumeric': 0.07776261937244201, 'fraction_numerical': 0.004433833560709414, 'mean_word_length': 3.1952789699570814, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '782047', 'n_tokens_mistral': 1641, 'n_tokens_neox': 1553, 'n_words': 411}