<commit_before># -*- coding: utf-8 -*-
from __future__ import with_statement

from bson.objectid import ObjectId
from bson import json_util
from datetime import datetime
from flask import current_app, abort, request, make_response, g, redirect
from flask.views import MethodView
from flask.ext.slither.authentication import NoAuthentication
from flask.ext.slither.authorization import NoAuthorization
from flask.ext.slither.decorators import preflight_checks, crossdomain
from flask.ext.slither.exceptions import ApiException
from flask.ext.slither.validation import NoValidation

import json
import pymongo
import re
import time


class BaseResource(MethodView):
    model = None
    lookup_field = 'name'
    DATE_FORMAT = "%Y-%m-%d %H:%M:%S"

    """ The authentication class has one method called `is_authenticated` and
    returns True or False depending on whether the request is authenticated or
    not. If not, a 401 is returned, otherwise the process continues"""
    authentication = NoAuthentication()

    """ The authorization class has one method called `is_authorized`. It
    determines if the user issuing the request is authorized to make this
    request. If not a 403 is returned. """
    authorization = NoAuthorization()

    """ The collection name this api is responsible for. This *must* be
    defined in a child class otherwise mongo won't know which collection to
    use for its transactions."""
    collection = None

    """ The `validation` method gets called and stores the
    errors in a dict called `errors`."""
    validation = NoValidation()

    """ A list of HTTP methods that are open for use. Any method not on this
    list will return a 405 if accessed."""
    allowed_methods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']

    """ By default all POST and PUT methods must have their payloads wrapped
       in the collection name. Setting this to `False` will prevent the
       default behaviour"""
    enforce_payload_collection = True

    """ The default respons will use the mongo json library to convert
        ObjectIds into {$oid: foo}. When this switch is turned off, the `_id`
        field will be renamed to `id`, and all ObjectId values will be passed
        through as strings"""
    payload_mongo_format = True

    """By default the json base key is the collection name. However by changing
       this value, it will become the root key of every request"""
    root_key = collection

    """ Always return payload matching updated instance. More fine-grain
       control can be achieved but setting `always_return_payload_<VERB>` where
       <VERB> is either post, put or patch"""
    always_return_payload = False
    always_return_payload_post = True

    """Allow cors requests"""
    cors_enabled = False

    """Maximum time a CORS requests can live before having to re-establish
       their validity (in seconds)"""
    cors_max_age = 21600

    """Methods allowed by CORS requests. The default allows all methonds.
       Note: CORS is only enabled if the `OPTIONS` method is allowed in
       `allowed_methods`. It is disabled by default."""
    cors_methods = ["GET", "POST", "PUT", "PATCH", "DELETE"]

    """A list of origins from which the API may accept requests. If it is None,
       then all origins (except blacklisted ones) are accepted"""
    cors_allowed = None

    """Any request from a blacklisted origin won't be allowed to connect to the
       API. This takes precidence over the allowed origins"""
    cors_blacklist = []

    """Specify particular headers that are allowed in CORS requests. Defaults
       to all."""
    cors_headers = None

    def __init__(self, app=None):
        if app is not None:
            self.app = app
            self.init_app(self.app)
        else:
            self.app = None

    def init_app(self, app):
        # Use the newstyle teardown_appcontext if it's available,
        # otherwise fall back to the request context
        if hasattr(app, 'teardown_appcontext'):
            app.teardown_appcontext(self.teardown)
        else:
            app.teardown_request(self.teardown)

    def _get_root(self):
        """ Returns the expected json root in the payload"""
        if getattr(self, 'root_key') and self.root_key is not None:
            return self.root_key
        return self.collection

    def _link(self, rel, **kwargs):
        title = kwargs.get('title', self.collection[:-1].title())
        obj_id = kwargs.get('obj_id', "")
        obj_id = "" if obj_id == "" else "/{}".format(obj_id)
        prefix = current_app.blueprints[request.blueprint].url_prefix
        prefix = "" if prefix is None else prefix
        # TODO: figure out to get this 1.0 prefix from the blueprint url_prefix
        prefix = "/1.0"
        return ('<link rel="%(rel)s" title="%(title)s" '
                'href="%(prefix)s/%(collection)s%(obj_id)s" />') % \
            {'rel': rel, 'title': title, 'prefix': prefix,
             'collection': self.collection, 'obj_id': obj_id}

    def _datetime_parser(self, dct):
        for k, v in dct.items():
            # TODO: update regex to match time better
            if isinstance(v, basestring) and re.search("\ UTC", v):
                try:
                    dct[k] = datetime.strptime(v, self.DATE_FORMAT)
                except:
                    # this is a normal string
                    pass
        return dct

    def _exception_handler(self, e):
        if isinstance(e.message, dict):
            return self._prep_response(
                e.message['msg'], status=e.message['status'])
        if e.message.find('Validation') == 0:
            return self._prep_response(self.validation.errors, status=400)
        elif e.message.find('No record') == 0:
            return self._prep_response(status=404)
        else:
            return self._prep_response({'message': e.message},
                                       status=409)

    ######################################
    # Preparing response into proper mime
    def _prep_response(self, dct={}, last_modified=None, etag=None,
                       status=200, **kwargs):
        if str(status)[0] == '2' and hasattr(self, 'redirect'):
            return redirect(self.redirect)
        # TODO: handle more mime types
        mime = "application/json"
        rendered = self._get_json_payload(dct)
        resp = make_response(rendered, status)
        resp.headers.add('Cache-Control',
                         'max-age=%s,must-revalidate' % 30)
        for h in kwargs.get('headers', []):
            resp.headers.add(h[0], h[1])
        resp.expires = time.time() + 30
        if etag:
            resp.headers.add('ETag', etag)
        if last_modified:
            resp.headers.add('Last-Modified',
                             self._datetime_parser(last_modified))
        if rendered != "":
            resp.mimetype = mime
        return resp

    def _get_json_payload(self, dct):
        def mydefault(obj):
            if isinstance(obj, ObjectId):
                return str(obj)
            return json_util.default

        if getattr(self, 'payload_mongo_format', True):
            return json_util.dumps(dct)
        else:
            if '_id' in dct[self._get_root()]:
                dct[self._get_root()]['id'] = dct[self._get_root()].pop('_id')
            return json.dumps(dct, default=mydefault)

    def access_limits(self, **kwargs):
        """ Returns a query which filters the current collection based on
        authentication access"""
        return {}

    def delete_query(self, **kwargs):
        obj = self._get_instance(**kwargs)[self._get_root()]
        return obj['_id']

    def limit_fields(self, **kwargs):<commit_msg>Fixed bug for mongo format payload<commit_after># -*- coding: utf-8 -*-
from __future__ import with_statement

from bson.objectid import ObjectId
from bson import json_util
from datetime import datetime
from flask import current_app, abort, request, make_response, g, redirect
from flask.views import MethodView
from flask.ext.slither.authentication import NoAuthentication
from flask.ext.slither.authorization import NoAuthorization
from flask.ext.slither.decorators import preflight_checks, crossdomain
from flask.ext.slither.exceptions import ApiException
from flask.ext.slither.validation import NoValidation

import json
import pymongo
import re
import time


class BaseResource(MethodView):
    model = None
    lookup_field = 'name'
    DATE_FORMAT = "%Y-%m-%d %H:%M:%S"

    """ The authentication class has one method called `is_authenticated` and
    returns True or False depending on whether the request is authenticated or
    not. If not, a 401 is returned, otherwise the process continues"""
    authentication = NoAuthentication()

    """ The authorization class has one method called `is_authorized`. It
    determines if the user issuing the request is authorized to make this
    request. If not a 403 is returned. """
    authorization = NoAuthorization()

    """ The collection name this api is responsible for. This *must* be
    defined in a child class otherwise mongo won't know which collection to
    use for its transactions."""
    collection = None

    """ The `validation` method gets called and stores the
    errors in a dict called `errors`."""
    validation = NoValidation()

    """ A list of HTTP methods that are open for use. Any method not on this
    list will return a 405 if accessed."""
    allowed_methods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']

    """ By default all POST and PUT methods must have their payloads wrapped
       in the collection name. Setting this to `False` will prevent the
       default behaviour"""
    enforce_payload_collection = True

    """ The default respons will use the mongo json library to convert
        ObjectIds into {$oid: foo}. When this switch is turned off, the `_id`
        field will be renamed to `id`, and all ObjectId values will be passed
        through as strings"""
    payload_mongo_format = True

    """By default the json base key is the collection name. However by changing
       this value, it will become the root key of every request"""
    root_key = collection

    """ Always return payload matching updated instance. More fine-grain
       control can be achieved but setting `always_return_payload_<VERB>` where
       <VERB> is either post, put or patch"""
    always_return_payload = False
    always_return_payload_post = True

    """Allow cors requests"""
    cors_enabled = False

    """Maximum time a CORS requests can live before having to re-establish
       their validity (in seconds)"""
    cors_max_age = 21600

    """Methods allowed by CORS requests. The default allows all methonds.
       Note: CORS is only enabled if the `OPTIONS` method is allowed in
       `allowed_methods`. It is disabled by default."""
    cors_methods = ["GET", "POST", "PUT", "PATCH", "DELETE"]

    """A list of origins from which the API may accept requests. If it is None,
       then all origins (except blacklisted ones) are accepted"""
    cors_allowed = None

    """Any request from a blacklisted origin won't be allowed to connect to the
       API. This takes precidence over the allowed origins"""
    cors_blacklist = []

    """Specify particular headers that are allowed in CORS requests. Defaults
       to all."""
    cors_headers = None

    def __init__(self, app=None):
        if app is not None:
            self.app = app
            self.init_app(self.app)
        else:
            self.app = None

    def init_app(self, app):
        # Use the newstyle teardown_appcontext if it's available,
        # otherwise fall back to the request context
        if hasattr(app, 'teardown_appcontext'):
            app.teardown_appcontext(self.teardown)
        else:
            app.teardown_request(self.teardown)

    def _get_root(self):
        """ Returns the expected json root in the payload"""
        if getattr(self, 'root_key') and self.root_key is not None:
            return self.root_key
        return self.collection

    def _link(self, rel, **kwargs):
        title = kwargs.get('title', self.collection[:-1].title())
        obj_id = kwargs.get('obj_id', "")
        obj_id = "" if obj_id == "" else "/{}".format(obj_id)
        prefix = current_app.blueprints[request.blueprint].url_prefix
        prefix = "" if prefix is None else prefix
        # TODO: figure out to get this 1.0 prefix from the blueprint url_prefix
        prefix = "/1.0"
        return ('<link rel="%(rel)s" title="%(title)s" '
                'href="%(prefix)s/%(collection)s%(obj_id)s" />') % \
            {'rel': rel, 'title': title, 'prefix': prefix,
             'collection': self.collection, 'obj_id': obj_id}

    def _datetime_parser(self, dct):
        for k, v in dct.items():
            # TODO: update regex to match time better
            if isinstance(v, basestring) and re.search("\ UTC", v):
                try:
                    dct[k] = datetime.strptime(v, self.DATE_FORMAT)
                except:
                    # this is a normal string
                    pass
        return dct

    def _exception_handler(self, e):
        if isinstance(e.message, dict):
            return self._prep_response(
                e.message['msg'], status=e.message['status'])
        if e.message.find('Validation') == 0:
            return self._prep_response(self.validation.errors, status=400)
        elif e.message.find('No record') == 0:
            return self._prep_response(status=404)
        else:
            return self._prep_response({'message': e.message},
                                       status=409)

    ######################################
    # Preparing response into proper mime
    def _prep_response(self, dct={}, last_modified=None, etag=None,
                       status=200, **kwargs):
        if str(status)[0] == '2' and hasattr(self, 'redirect'):
            return redirect(self.redirect)
        # TODO: handle more mime types
        mime = "application/json"
        rendered = self._get_json_payload(dct)
        resp = make_response(rendered, status)
        resp.headers.add('Cache-Control',
                         'max-age=%s,must-revalidate' % 30)
        for h in kwargs.get('headers', []):
            resp.headers.add(h[0], h[1])
        resp.expires = time.time() + 30
        if etag:
            resp.headers.add('ETag', etag)
        if last_modified:
            resp.headers.add('Last-Modified',
                             self._datetime_parser(last_modified))
        if rendered != "":
            resp.mimetype = mime
        return resp

    def _get_json_payload(self, dct):
        def mydefault(obj):
            if isinstance(obj, ObjectId):
                return str(obj)
            return json_util.default

        if getattr(self, 'payload_mongo_format', True):
            return json_util.dumps(dct)
        else:
            if isinstance(dct, dict) and \
                    '_id' in dct.get(self._get_root(), []):
                dct[self._get_root()]['id'] = dct[self._get_root()].pop('_id')
            return json.dumps(dct, default=mydefault)

    def access_limits(self, **kwargs):
        """ Returns a query which filters the current collection based on
        authentication access"""
        return {}

    def delete_query(self, **kwargs):
        obj = self._get_instance(**kwargs)[self._get_root()]
        return obj['_id']

    def limit_fields(self, **kwargs):
{'fraction_non_alphanumeric': 0.10293075684380032, 'fraction_numerical': 0.005410628019323672, 'mean_word_length': 2.527834583049307, 'pattern_counts': {'":': 2, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4907666', 'n_tokens_mistral': 4336, 'n_tokens_neox': 4146, 'n_words': 1467}