<commit_before>##########################################################################
#          (C) Vrije Universiteit, Amsterdam (the Netherlands)            #
#                                                                         #
# This file is part of AmCAT - The Amsterdam Content Analysis Toolkit     #
#                                                                         #
# AmCAT is free software: you can redistribute it and/or modify it under  #
# the terms of the GNU Affero General Public License as published by the  #
# Free Software Foundation, either version 3 of the License, or (at your  #
# option) any later version.                                              #
#                                                                         #
# AmCAT is distributed in the hope that it will be useful, but WITHOUT    #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or   #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public     #
# License for more details.                                               #
#                                                                         #
# You should have received a copy of the GNU Affero General Public        #
# License along with AmCAT.  If not, see <http://www.gnu.org/licenses/>.  #
###########################################################################
from __future__ import unicode_literals
from functools import partial
from operator import getitem, attrgetter
from django.core.exceptions import ValidationError

from rest_framework.exceptions import APIException
from rest_framework.metadata import SimpleMetadata
from rest_framework.response import Response
from rest_framework.views import APIView

from amcat.models import Project, CodingJob
from amcat.tools.caching import cached


def wrap_query_action(qaction):
    class AutoQueryActionViewSet(QueryActionView):
        help_text = qaction.__doc__
        query_action = qaction
    return AutoQueryActionViewSet


class QueryActionMetadata(SimpleMetadata):
    def determine_metadata(self, request, view):
        form = view.get_form()
        field_names = form.fields.keys()
        fields = map(partial(getitem, form), field_names)

        return {
            "help_texts": dict(zip(field_names, [f.help_text.strip() or None for f in fields])),
            "form": dict(zip(field_names, [f.as_widget() for f in fields])),
            "labels": dict(zip(field_names, [f.label for f in fields])),
            "help_text": view.get_view_description(),
        }


class QueryActionView(APIView):
    query_action = None
    metadata_class = QueryActionMetadata

    def __init__(self, **kwargs):
        super(QueryActionView, self).__init__(**kwargs)

    @property
    def project(self):
        return self.get_project()

    @property
    def articlesets(self):
        return self.get_articlesets()

    @property
    def codingjobs(self):
        return self.get_codingjobs()

    @cached
    def get_project(self):
        try:
            return Project.objects.get(id=int(self.request.GET["project"]))
        except KeyError:
            raise APIException({"details": "You need to provide 'project' GET parameter."})
        except ValueError:
            raise APIException({"details": "You need to specify an integer as project id."})
        except Project.DoesNotExist:
            raise APIException({"details": "Project does not exist."})

    @cached
    def get_articlesets(self):
        # Articlesets are given by GET parameter `sets` and separated by commas
        articleset_ids = map(int, filter(unicode.isdigit, self.request.GET.get("sets", "").split(",")))
        articlesets = self.project.all_articlesets().filter(id__in=articleset_ids)
        return articlesets.only("id", "name")

    @cached
    def get_codingjobs(self):
        # Codingjobs are given by GET parameter `jobs` and separated by commas. If *no* jobs are
        # given, we also return no jobs, in contrast to get_articlesets which yields all articlesets
        # belonging to the current project.
        codingjob_ids = map(int, filter(unicode.isdigit, self.request.GET.get("jobs", "").split(",")))
        codingjobs = self.project.codingjob_set.filter(id__in=codingjob_ids).only("id", "name")
        return codingjobs if codingjob_ids else CodingJob.objects.none()

    @cached
    def get_query_action(self):
        return self.query_action(
            user=self.request.user, project=self.get_project(), codingjobs=self.get_codingjobs(),
            articlesets=self.get_articlesets(), data=self.request.POST or self.request.DATA or None
        )

    def get_form(self):
        return self.get_query_action().get_form()

    def get_view_name(self):
        from urls import get_action_name
        return get_action_name(self).title()

    def get_view_description(self, html=False):
        return (self.query_action.__doc__ or "").strip()

    def dispatch(self, request, *args, **kwargs):
        return super(QueryActionView, self).dispatch(request, *args, **kwargs)

    def get(self, request, format=None):
        return Response({"details": "POST/OPTIONS only."})

    def post(self, request, format=None):
        try:
           task_handler = self.get_query_action().run_delayed()
        except ValidationError as e:
            return Response(e.message_dict, status=400)
        else:
            return Response({"uuid": task_handler.task.uuid})
<commit_msg>Set latest query to session. fixes #339<commit_after>##########################################################################
#          (C) Vrije Universiteit, Amsterdam (the Netherlands)            #
#                                                                         #
# This file is part of AmCAT - The Amsterdam Content Analysis Toolkit     #
#                                                                         #
# AmCAT is free software: you can redistribute it and/or modify it under  #
# the terms of the GNU Affero General Public License as published by the  #
# Free Software Foundation, either version 3 of the License, or (at your  #
# option) any later version.                                              #
#                                                                         #
# AmCAT is distributed in the hope that it will be useful, but WITHOUT    #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or   #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public     #
# License for more details.                                               #
#                                                                         #
# You should have received a copy of the GNU Affero General Public        #
# License along with AmCAT.  If not, see <http://www.gnu.org/licenses/>.  #
###########################################################################
from __future__ import unicode_literals
from functools import partial
from operator import getitem, attrgetter
from django.core.exceptions import ValidationError

from rest_framework.exceptions import APIException
from rest_framework.metadata import SimpleMetadata
from rest_framework.response import Response
from rest_framework.views import APIView

from amcat.models import Project, CodingJob
from amcat.tools.caching import cached


def wrap_query_action(qaction):
    class AutoQueryActionViewSet(QueryActionView):
        help_text = qaction.__doc__
        query_action = qaction
    return AutoQueryActionViewSet


class QueryActionMetadata(SimpleMetadata):
    def determine_metadata(self, request, view):
        form = view.get_form()
        field_names = form.fields.keys()
        fields = map(partial(getitem, form), field_names)

        return {
            "help_texts": dict(zip(field_names, [f.help_text.strip() or None for f in fields])),
            "form": dict(zip(field_names, [f.as_widget() for f in fields])),
            "labels": dict(zip(field_names, [f.label for f in fields])),
            "help_text": view.get_view_description(),
        }


class QueryActionView(APIView):
    query_action = None
    metadata_class = QueryActionMetadata

    def __init__(self, **kwargs):
        super(QueryActionView, self).__init__(**kwargs)

    @property
    def project(self):
        return self.get_project()

    @property
    def articlesets(self):
        return self.get_articlesets()

    @property
    def codingjobs(self):
        return self.get_codingjobs()

    @cached
    def get_project(self):
        try:
            return Project.objects.get(id=int(self.request.GET["project"]))
        except KeyError:
            raise APIException({"details": "You need to provide 'project' GET parameter."})
        except ValueError:
            raise APIException({"details": "You need to specify an integer as project id."})
        except Project.DoesNotExist:
            raise APIException({"details": "Project does not exist."})

    @cached
    def get_articlesets(self):
        # Articlesets are given by GET parameter `sets` and separated by commas
        articleset_ids = map(int, filter(unicode.isdigit, self.request.GET.get("sets", "").split(",")))
        articlesets = self.project.all_articlesets().filter(id__in=articleset_ids)
        return articlesets.only("id", "name")

    @cached
    def get_codingjobs(self):
        # Codingjobs are given by GET parameter `jobs` and separated by commas. If *no* jobs are
        # given, we also return no jobs, in contrast to get_articlesets which yields all articlesets
        # belonging to the current project.
        codingjob_ids = map(int, filter(unicode.isdigit, self.request.GET.get("jobs", "").split(",")))
        codingjobs = self.project.codingjob_set.filter(id__in=codingjob_ids).only("id", "name")
        return codingjobs if codingjob_ids else CodingJob.objects.none()

    @cached
    def get_query_action(self):
        return self.query_action(
            user=self.request.user, project=self.get_project(), codingjobs=self.get_codingjobs(),
            articlesets=self.get_articlesets(), data=self.request.POST or self.request.DATA or None
        )

    def get_form(self):
        return self.get_query_action().get_form()

    def get_view_name(self):
        from urls import get_action_name
        return get_action_name(self).title()

    def get_view_description(self, html=False):
        return (self.query_action.__doc__ or "").strip()

    def dispatch(self, request, *args, **kwargs):
        return super(QueryActionView, self).dispatch(request, *args, **kwargs)

    def get(self, request, format=None):
        return Response({"details": "POST/OPTIONS only."})

    def post(self, request, format=None):
        try:
            qa = self.get_query_action()

            #HACK! Sets query to session for article higlighting
            request.session['query'] = qa.data['query']

            task_handler = qa.run_delayed()
        except ValidationError as e:
            return Response(e.message_dict, status=400)
        else:
            return Response({"uuid": task_handler.task.uuid})

{'fraction_non_alphanumeric': 0.11572327044025157, 'fraction_numerical': 0.0009883198562443845, 'mean_word_length': 2.5124644998422214, 'pattern_counts': {'":': 18, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 32, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '890209', 'n_tokens_mistral': 2911, 'n_tokens_neox': 2792, 'n_words': 852}