<commit_before>import operator, json
import uuid
from functools import reduce

from django import forms
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
from django.db.models import Case, Count, Q, When
from django.db.models.functions import Lower
from django.http import HttpResponseRedirect
from django.shortcuts import reverse
from django.utils import timezone
from django.views import generic

from accounts.models import User
from accounts.utils import (get_permitted_triggers, status_tooltip_text,
                            update_trigger)
from guardian.mixins import LoginRequiredMixin
from guardian.shortcuts import (get_objects_for_user, get_perms,
                                get_users_with_perms)
from studies.forms import StudyEditForm, StudyForm
from studies.models import Study, StudyLog


class StudyCreateView(LoginRequiredMixin, PermissionRequiredMixin, generic.CreateView):
    '''
    StudyCreateView allows a user to create a study and then redirects
    them to the detail view for that study.
    '''
    fields = ('name', 'organization', 'blocks', )
    model = Study
    permission_required = 'studies.can_create_study'
    raise_exception = True

    def get_form_class(self):
        return StudyForm

    def form_valid(self, form):
        user = self.request.user
        form.instance.creator = user
        form.instance.organization = user.organization
        self.object = form.save()
        # TODO Should this be moved to the model - adding creator to study admin group on creation?
        self.add_creator_to_study_admin_group()
        return HttpResponseRedirect(self.get_success_url())

    def add_creator_to_study_admin_group(self):
        study_admin_group = self.object.study_admin_group
        study_admin_group.user_set.add(self.request.user)
        return study_admin_group

    def get_success_url(self):
        return reverse('exp:study-detail', kwargs=dict(pk=self.object.id))


class StudyListView(LoginRequiredMixin, PermissionRequiredMixin, generic.ListView):
    '''
    StudyListView shows a list of studies that a user has permission to.
    '''
    model = Study
    template_name = 'studies/study_list.html'
    permission_required = 'studies.can_view_study'
    raise_exception = True

    def get_queryset(self, *args, **kwargs):
        request = self.request.GET
        queryset = get_objects_for_user(self.request.user, 'studies.can_view_study').exclude(state='archived')

        state = request.get('state')
        if state and state != 'all':
            if state == 'myStudies':
                queryset = queryset.filter(creator=self.request.user)
            else:
                queryset = queryset.filter(state=state)

        match = request.get('match')
        if match:
            queryset = queryset.filter(reduce(operator.or_,
              (Q(name__icontains=term) | Q(short_description__icontains=term) for term in match.split())))

        sort = request.get('sort')
        if sort:
            if 'name' in sort:
                queryset = queryset.order_by(sort)
            elif 'beginDate' in sort:
                # TODO optimize using subquery
                queryset = sorted(queryset, key=lambda t: t.begin_date or timezone.now(), reverse=True if '-' in sort else False)
            elif 'endDate' in sort:
                # TODO optimize using subquery
                queryset = sorted(queryset, key=lambda t: t.end_date or timezone.now(), reverse=True if '-' in sort else False)

        queryset = queryset.select_related('creator')
        queryset = queryset.annotate(completed_responses_count=Count(Case(When(responses__completed=True, then=1))))
        queryset = queryset.annotate(incomplete_responses_count=Count(Case(When(responses__completed=False, then=1))))

        return queryset

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['state'] = self.request.GET.get('state', 'all')
        context['match'] = self.request.GET.get('match') or ''
        context['sort'] = self.request.GET.get('sort') or ''
        return context


class StudyDetailView(LoginRequiredMixin, PermissionRequiredMixin, generic.DetailView):
    '''
    StudyDetailView shows information about a study.
    '''
    template_name = 'studies/study_detail.html'
    model = Study
    permission_required = 'studies.can_view_study'
    raise_exception = True

    def post(self, *args, **kwargs):
        update_trigger(self)
        if self.request.POST.get('clone_study'):
            clone = self.get_object().clone()
            clone.creator = self.request.user
            clone.organization = self.request.user.organization<commit_msg>Move queryset.select_related and queryset.annotate above potential conversion of queryset to list.<commit_after>import operator, json
import uuid
from functools import reduce

from django import forms
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
from django.db.models import Case, Count, Q, When
from django.db.models.functions import Lower
from django.http import HttpResponseRedirect
from django.shortcuts import reverse
from django.utils import timezone
from django.views import generic

from accounts.models import User
from accounts.utils import (get_permitted_triggers, status_tooltip_text,
                            update_trigger)
from guardian.mixins import LoginRequiredMixin
from guardian.shortcuts import (get_objects_for_user, get_perms,
                                get_users_with_perms)
from studies.forms import StudyEditForm, StudyForm
from studies.models import Study, StudyLog


class StudyCreateView(LoginRequiredMixin, PermissionRequiredMixin, generic.CreateView):
    '''
    StudyCreateView allows a user to create a study and then redirects
    them to the detail view for that study.
    '''
    fields = ('name', 'organization', 'blocks', )
    model = Study
    permission_required = 'studies.can_create_study'
    raise_exception = True

    def get_form_class(self):
        return StudyForm

    def form_valid(self, form):
        user = self.request.user
        form.instance.creator = user
        form.instance.organization = user.organization
        self.object = form.save()
        # TODO Should this be moved to the model - adding creator to study admin group on creation?
        self.add_creator_to_study_admin_group()
        return HttpResponseRedirect(self.get_success_url())

    def add_creator_to_study_admin_group(self):
        study_admin_group = self.object.study_admin_group
        study_admin_group.user_set.add(self.request.user)
        return study_admin_group

    def get_success_url(self):
        return reverse('exp:study-detail', kwargs=dict(pk=self.object.id))


class StudyListView(LoginRequiredMixin, PermissionRequiredMixin, generic.ListView):
    '''
    StudyListView shows a list of studies that a user has permission to.
    '''
    model = Study
    template_name = 'studies/study_list.html'
    permission_required = 'studies.can_view_study'
    raise_exception = True

    def get_queryset(self, *args, **kwargs):
        request = self.request.GET
        queryset = get_objects_for_user(self.request.user, 'studies.can_view_study').exclude(state='archived')
        queryset = queryset.select_related('creator')
        queryset = queryset.annotate(completed_responses_count=Count(Case(When(responses__completed=True, then=1))))
        queryset = queryset.annotate(incomplete_responses_count=Count(Case(When(responses__completed=False, then=1))))


        state = request.get('state')
        if state and state != 'all':
            if state == 'myStudies':
                queryset = queryset.filter(creator=self.request.user)
            else:
                queryset = queryset.filter(state=state)

        match = request.get('match')
        if match:
            queryset = queryset.filter(reduce(operator.or_,
              (Q(name__icontains=term) | Q(short_description__icontains=term) for term in match.split())))

        sort = request.get('sort')
        if sort:
            if 'name' in sort:
                queryset = queryset.order_by(sort)
            elif 'beginDate' in sort:
                # TODO optimize using subquery
                queryset = sorted(queryset, key=lambda t: t.begin_date or timezone.now(), reverse=True if '-' in sort else False)
            elif 'endDate' in sort:
                # TODO optimize using subquery
                queryset = sorted(queryset, key=lambda t: t.end_date or timezone.now(), reverse=True if '-' in sort else False)

        return queryset

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['state'] = self.request.GET.get('state', 'all')
        context['match'] = self.request.GET.get('match') or ''
        context['sort'] = self.request.GET.get('sort') or ''
        return context


class StudyDetailView(LoginRequiredMixin, PermissionRequiredMixin, generic.DetailView):
    '''
    StudyDetailView shows information about a study.
    '''
    template_name = 'studies/study_detail.html'
    model = Study
    permission_required = 'studies.can_view_study'
    raise_exception = True

    def post(self, *args, **kwargs):
        update_trigger(self)
        if self.request.POST.get('clone_study'):
            clone = self.get_object().clone()
            clone.creator = self.request.user
            clone.organization = self.request.user.organization
{'fraction_non_alphanumeric': 0.09107864470003109, 'fraction_numerical': 0.00041446482229820747, 'mean_word_length': 3.124786324786325, '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': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7416829', 'n_tokens_mistral': 2739, 'n_tokens_neox': 2622, 'n_words': 665}