<commit_before>from django.http import HttpResponseBadRequest, HttpResponseForbidden

from ..simplified import PermissionDenied
from errors import InvalidRequestDataError
from restview import RestfulView
from serializers import serializers, SerializableResult


class ErrorMsgSerializableResult(SerializableResult):
    def __init__(self, errormessage, httpresponsecls):
        super(ErrorMsgSerializableResult, self).__init__(dict(errormessages=[errormessage]),
                                                         httpresponsecls=httpresponsecls)

class ForbiddenSerializableResult(ErrorMsgSerializableResult):
    def __init__(self):
        super(ForbiddenSerializableResult, self).__init__('Forbidden',
                                                          HttpResponseForbidden)


class ModelRestfulView(RestfulView):
    """
    :class:`ModelRestfulView` is used in conjunction with the
    :class:`restful_modelapi`-decorator to autogenerate a RESTful
    interface for a simplified class (see :ref:`simplified`).
    """

    @classmethod
    def _searchform_to_kwargs(cls, getdata):
        """
        Converts the ``data`` to a validated :class:`SearchForm`.

        Throws :class:`errors.InvalidRequestDataError` if the form does not
        validate.
        """
        form = cls.SearchForm(getdata)
        if form.is_valid():
            return form.cleaned_data
        else:
            raise InvalidRequestDataError(form)

    @classmethod
    def filter_urlmap(cls, itemdct):
        if not hasattr(cls._meta, 'urlmap'):
            return itemdct
        for fieldname, mapping in cls._meta.urlmap.iteritems():
            url = mapping.restfulcls.get_rest_url(itemdct[mapping.idfield])
            itemdct[fieldname] = url
        return itemdct

    @classmethod
    def filter_resultitem(cls, itemdct):
        return cls.filter_urlmap(itemdct)


    def _extjswrap(self, data, success=True):
        if self.use_extjshacks:
            if isinstance(data, list):
                result = dict(total = len(data),
                              items = data)
            elif isinstance(data, dict):
                result = dict(items=data)
            result['success'] = success
            return result
        else:
            return data

    def _extjswrap_failure(self, data):
        return self._extjswrap(data, success=False)


    def restultqry_to_list(self, qryresultwrapper):
        return [self.__class__.filter_resultitem(itemdct) \
                for itemdct in qryresultwrapper]

    def _create_or_replace(self, instance=None):
        data = serializers.deserialize(self.comformat, self.request.raw_post_data)
        #for key in data: # NOTE: Should not be needed anymore since __ is not used for foreign keys.
            #if '__' in key:  # Foreign keys
                #item = data.pop(key)
                #newkey = key.split('__')[0]
                #data[newkey] = item
        form = self.__class__.EditForm(data, instance=instance)
        result = None
        if form.is_valid():
            form.save()
            data['id'] = form.instance.id
            result = self._extjswrap(data)
            return SerializableResult(result)
        else:
            fielderrors = dict(form.errors)
            non_field_errors = list(form.non_field_errors())
            result = dict(fielderrors=fielderrors, errormessages=non_field_errors)
            self._extjswrap_failure(result)
            return SerializableResult(result, httpresponsecls=HttpResponseBadRequest)



    def crud_search(self, request, **kwargs):
        """ Maps to the ``search`` method of the simplified class. """
        if 'getdata_in_qrystring' in self.request.GET: # NOTE: For easier ExtJS integration
            data = self.request.GET
        else:
            try:
                data = serializers.deserialize(self.comformat, self.request.raw_post_data)
            except ValueError, e:
                return ErrorMsgSerializableResult(('Bad request data: {0}. Perhaps you ment to'
                                                   'send GET data as a querystring? In that case, add '
                                                   'getdata_in_qrystring=1 to your querystring.'.format(e)),
                                                  httpresponsecls=HttpResponseBadRequest)
        try:
            form = self.__class__._searchform_to_kwargs(data)
        except InvalidRequestDataError, e:
            return ErrorMsgSerializableResult("Bad request: %s" % e,
                                              httpresponsecls=HttpResponseBadRequest)

        form.update(**kwargs) # add variables from url PATH
        qryresultwrapper = self._meta.simplified.search(self.request.user, **form)
        resultlist = self.restultqry_to_list(qryresultwrapper)
        result = self._extjswrap(resultlist)
        return SerializableResult(result)


    def crud_read(self, request, id):
        """ Maps to the ``read`` method of the simplified class. """
        try:
            data = self._meta.simplified.read(self.request.user, id)
        except PermissionDenied, e:
            return ForbiddenSerializableResult()
        if self.use_extjshacks:
            data = dict(items=data, total=1, success=True)
        return SerializableResult(data)


    def crud_create(self, request):
        """ Maps to the ``create`` method of the simplified class. """
        return self._create_or_replace()

    def crud_update(self, request, id):
        """ Maps to the ``update`` method of the simplified class. """
        try:
            instance = self._meta.simplified._meta.model.objects.get(pk=id)
        except self._meta.simplified._meta.model.DoesNotExist, e:
            return ForbiddenSerializableResult()
        return self._create_or_replace(instance)

    def crud_delete(self, request, id):
        """ Maps to the ``delete`` method of the simplified class. """
        self._meta.simplified.delete(request.user, id)
        try:
            data = self._extjswrap(dict(pk=id))
            return SerializableResult(data)
        except PermissionDenied, e:
            return ForbiddenSerializableResult()
<commit_msg>restful.modelrestview: Use and validate forms for read and search.<commit_after>from django.http import HttpResponseBadRequest, HttpResponseForbidden
from django import forms

from ..simplified import PermissionDenied
from errors import InvalidRequestDataError
from restview import RestfulView
from serializers import serializers, SerializableResult
import fields


class ErrorMsgSerializableResult(SerializableResult):
    def __init__(self, errormessage, httpresponsecls):
        super(ErrorMsgSerializableResult, self).__init__(dict(errormessages=[errormessage]),
                                                         httpresponsecls=httpresponsecls)

class ForbiddenSerializableResult(ErrorMsgSerializableResult):
    def __init__(self):
        super(ForbiddenSerializableResult, self).__init__('Forbidden',
                                                          HttpResponseForbidden)

class FormErrorSerializableResult(SerializableResult):
    def __init__(self, form):
        fielderrors = dict(form.errors)
        non_field_errors = list(form.non_field_errors())
        result = dict(fielderrors=fielderrors, errormessages=non_field_errors)
        result = self._extjswrap_failure(result)
        super(FormErrorSerializableResult, self).__init__(result, httpresponsecls=HttpResponseBadRequest)


class ReadForm(forms.Form):
    result_fieldgroups = fields.CharListWithFallbackField()


class ModelRestfulView(RestfulView):
    """
    :class:`ModelRestfulView` is used in conjunction with the
    :class:`restful_modelapi`-decorator to autogenerate a RESTful
    interface for a simplified class (see :ref:`simplified`).
    """


    @classmethod
    def _searchform_to_kwargs(cls, getdata):
        """
        Converts the ``data`` to a validated :class:`SearchForm`.

        Throws :class:`errors.InvalidRequestDataError` if the form does not
        validate.
        """
        form = cls.SearchForm(getdata)
        if form.is_valid():
            return form.cleaned_data
        else:
            raise InvalidRequestDataError(form)

    @classmethod
    def filter_urlmap(cls, itemdct):
        if not hasattr(cls._meta, 'urlmap'):
            return itemdct
        for fieldname, mapping in cls._meta.urlmap.iteritems():
            url = mapping.restfulcls.get_rest_url(itemdct[mapping.idfield])
            itemdct[fieldname] = url
        return itemdct

    @classmethod
    def filter_resultitem(cls, itemdct):
        return cls.filter_urlmap(itemdct)


    def _extjswrap(self, data, success=True):
        if self.use_extjshacks:
            if isinstance(data, list):
                result = dict(total = len(data),
                              items = data)
            elif isinstance(data, dict):
                result = dict(items=data)
            result['success'] = success
            return result
        else:
            return data

    def _extjswrap_failure(self, data):
        return self._extjswrap(data, success=False)


    def restultqry_to_list(self, qryresultwrapper):
        return [self.__class__.filter_resultitem(itemdct) \
                for itemdct in qryresultwrapper]

    def _create_or_replace(self, instance=None):
        data = serializers.deserialize(self.comformat, self.request.raw_post_data)
        form = self.__class__.EditForm(data, instance=instance)
        result = None
        if form.is_valid():
            form.save()
            data['id'] = form.instance.id
            result = self._extjswrap(data)
            return SerializableResult(result)
        else:
            return FormErrorSerializableResult(form)


    def _load_getdata(self):
        if 'getdata_in_qrystring' in self.request.GET: # NOTE: For easier ExtJS integration
            data = self.request.GET
        else:
            try:
                data = serializers.deserialize(self.comformat, self.request.raw_post_data)
            except ValueError, e:
                return ErrorMsgSerializableResult(('Bad request data: {0}. Perhaps you ment to'
                                                   'send GET data as a querystring? In that case, add '
                                                   'getdata_in_qrystring=1 to your querystring.'.format(e)),
                                                  httpresponsecls=HttpResponseBadRequest)
        return data

    def crud_search(self, request, **kwargs):
        """ Maps to the ``search`` method of the simplified class. """
        getdata = self._load_getdata()
        form = self.__class__.SearchForm(getdata)
        if form.is_valid():
            cleaned_data = form.cleaned_data
            cleaned_data.update(**kwargs) # add variables from url PATH
            qryresultwrapper = self._meta.simplified.search(self.request.user, **cleaned_data)
            resultlist = self.restultqry_to_list(qryresultwrapper)
            result = self._extjswrap(resultlist)
            return SerializableResult(result)
        else:
            return FormErrorSerializableResult(form)



    def crud_read(self, request, id):
        """ Maps to the ``read`` method of the simplified class. """
        getdata = self._load_getdata()
        form = ReadForm(getdata)
        if form.is_valid():
            cleaned_data = form.cleaned_data
            try:
                data = self._meta.simplified.read(self.request.user, id, **cleaned_data)
            except PermissionDenied, e:
                return ForbiddenSerializableResult()
            if self.use_extjshacks:
                data = dict(items=data, total=1, success=True)
            return SerializableResult(data)
        else:
            return FormErrorSerializableResult(form)


    def crud_create(self, request):
        """ Maps to the ``create`` method of the simplified class. """
        return self._create_or_replace()

    def crud_update(self, request, id):
        """ Maps to the ``update`` method of the simplified class. """
        try:
            instance = self._meta.simplified._meta.model.objects.get(pk=id)
        except self._meta.simplified._meta.model.DoesNotExist, e:
            return ForbiddenSerializableResult()
        return self._create_or_replace(instance)

    def crud_delete(self, request, id):
        """ Maps to the ``delete`` method of the simplified class. """
        self._meta.simplified.delete(request.user, id)
        try:
            data = self._extjswrap(dict(pk=id))
            return SerializableResult(data)
        except PermissionDenied, e:
            return ForbiddenSerializableResult()

{'fraction_non_alphanumeric': 0.08541650340882376, 'fraction_numerical': 0.0005485463521667581, 'mean_word_length': 2.306217616580311, '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': 22, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3081342', 'n_tokens_mistral': 3424, 'n_tokens_neox': 3334, 'n_words': 793}