Exemple #1
0
    def delete(self, *keys):
        key_tokens = [self._tokenize(key) for key in keys]
        response = self._redis.delete(*key_tokens)

        for key_token in key_tokens:
            logger.debug('Delete cache key:%s' % key_token)

        return response
Exemple #2
0
    def reviews_post(request):
        """
        creates new business review

        **authentication required with access_token**


        errors
        ======

        * status 400 - if failed to create business


        returns
        =======

        ::

            {
                "id": ""
            }
        """
        business_id = request.matchdict['business_id']
        business = Business.get_by_id(business_id)
        user = request.validated['user']
        text = request.validated['text']
        rating = request.validated['rating']
        tags = request.validated['tags']

        if tags:
            tags = tags.split(':')
        else:
            tags = []

        if business and user:
            review = Review.create(user.id, business, rating, text, tags)
            response_body = {
                'id': review.id,
            }

            # kill cache
            cache_key = 'business:{}*'.format(business.id)
            redis_cache.delete_pattern(cache_key)
        else:
            logger.debug('Failed to create review for business:{}'.format(business_id))
            request.response.status_int = 400
            response_body = {
                'status': 'error',
                'message': 'failed to create review for business'
            }

        request.response.body = json.dumps(response_body, cls=ComplexEncoder)
        request.response.content_type = 'application/json'
        return request.response
Exemple #3
0
    def reviews_get(request):
        """
        Returns the business reviews


        errors
        ======

        * status 404 - if the business can't be found


        returns
        =======

        ::

            {
                "reviews": [
                    {
                        "rating": 5,
                        "modified": "2015-08-10T00:20:17.753000",
                        "id": "55c7ee41fad9b43993d71919",
                        "user_id": "55c7ee3dfad9b43993d7190e",
                        "reviewed_id": "55c7ee3efad9b43993d7190f",
                        "tags": [
                            "awesome"
                        ],
                        "text": "This is awesome.",
                        "created": "2015-08-10T00:20:17.753000",
                        "reviewed_collection": "businesses"
                    }
                ]
            }
        """
        business_id = request.matchdict['business_id']
        business = Business.get_by_id(business_id)

        if business:
            response_body = {
                'reviews': Review.reviews_for_reviewed(business.collection, business.id)
            }
            logger.debug('Retrieved business:{} reviews'.format(business.id))
        else:
            logger.debug('Failed to retrieve business:{} reviews'.format(business_id))
            request.response.status_int = 404
            response_body = {
                'status': 'error',
                'message': 'failed to find business'
            }

        request.response.body = json.dumps(response_body, cls=ComplexEncoder)
        request.response.content_type = 'application/json'
        return request.response
Exemple #4
0
    def setex(self, key, value, seconds):
        key_token = self._tokenize(key)

        # if value is not string then pickle it
        if isinstance(value, basestring):
            stored_value = value
        else:
            pickled_value = pickle.dumps(value)
            stored_value = '%s%s' % (self._pickle_token, pickled_value)

        response = self._redis.setex(key_token, stored_value, seconds)
        logger.debug('Set cache key:%s' % key_token)
        return response
Exemple #5
0
    def save(self):
        """
        saves the list
        """
        saved = False
        now = datetime.utcnow()
        self.modified = now

        # if _id is in keys then the document has been saved, otherwise it's a new document
        if '_id' in self.data.keys():
            # the list needs updating
            ret = mongodb[self.collection].update({'_id': self.data['_id']}, self.data)

            if ret['n']:
                logger.debug('saved existing {} id:{}'.format(self.collection, self.id))
                saved = True
            else:
                logger.debug('failed to save existing {} id:{}'.format(self.collection, self.id))

        else:
            # new list
            ret = mongodb[self.collection].insert(self.data)

            if ret:
                logger.debug('saved new {} id:{}'.format(self.collection, self.id))
                saved = True
            else:
                logger.debug('failed to save new {}'.format(self.collection))

        return saved
Exemple #6
0
    def businesses_post(request):
        """
        create a new business

        **requires authentication with an access_token**


        errors
        ======

        * status 500 - if the user can't be saved


        returns
        =======

        ::

            {
                "id": ""
            }
        """
        user = request.validated['user']
        name = request.validated['name']
        address = {
            'street1': request.validated['street1'],
            'street2': request.validated['street2'],
            'city': request.validated['city'],
            'state': request.validated['state'],
            'postal_code': request.validated['postal_code'],
        }

        business = Business.create(name, address)

        if business:
            logger.debug('Created new business:{}'.format(business.id))
            response_body = {
                'id': business.id
            }
        else:
            logger.debug('Failed to create new business.')
            requests.response.status_int = 500
            response_body = {
                'status': 'error',
                'message': 'failed to create new business',
            }

        request.response.body = json.dumps(response_body, cls=ComplexEncoder)
        request.response.content_type = 'application/json'
        return request.response
Exemple #7
0
    def delete(self):
        """
        delete the document
        """
        deleted = False
        ret = mongodb[self.collection].remove({'_id': self.data['_id']})

        if ret['n']:
            logger.debug('deleted {} id:{}'.format(self.collection, self.id))
            deleted = True
        else:
            logger.debug('failed to delete {} id:{}'.format(self.collection, self.id))

        return deleted
Exemple #8
0
    def review_get(request):
        """
        Returns the business review


        errors
        ======

        * status 404 - if the review couldn't be found


        returns
        =======

        ::

            {
                "rating": 5,
                "modified": "2015-08-10T00:20:17.753000",
                "id": "55c7ee41fad9b43993d71919",
                "user_id": "55c7ee3dfad9b43993d7190e",
                "reviewed_id": "55c7ee3efad9b43993d7190f",
                "tags": [
                    "awesome"
                ],
                "text": "This is awesome.",
                "created": "2015-08-10T00:20:17.753000",
                "reviewed_collection": "businesses"
            }
        """
        business_id = request.matchdict['business_id']
        review_id = request.matchdict['review_id']
        business = Business.get_by_id(business_id)
        review = Review.get_by_id(review_id)

        if business and review and business.id == review.reviewed_id:
            response_body = review.json
            logger.debug('Retrieved business:{} review:{}'.format(business.id, review.id))
        else:
            logger.debug('Failed to retrieve business:{} review:'.format(business_id, review_id))
            request.response.status_int = 404
            response_body = json.dumps({
                'status': 'error',
                'message': 'failed to find business review'
            })

        request.response.body = response_body
        request.response.content_type = 'application/json'
        return request.response
Exemple #9
0
    def delete_pattern(self, pattern):
        """
        deletes all keys that matches the pattern
        """
        key_tokens = self.keys(pattern)

        if key_tokens:
            response = self._redis.delete(*key_tokens)
        else:
            response = True

        for key_token in key_tokens:
            logger.debug('Delete cache key:%s' % key_token)

        return response
def update_business(event):
    """
    compiles rating and tags for a business when a review is updated
    """
    from reviews.models import Review

    review = event.review
    business = Business.get_by_id(review.reviewed_id)

    if business:
        business.rating = Review.rating_for_reviewed(review.reviewed_id)
        business.tags = Review.tags_for_reviewed(review.reviewed_id)
        business.save()
        logger.debug('updated business:{} reviews'.format(business.id))
    else:
        logger.debug('failed to update business:{} reviews'.format(review.reviewd_id))
Exemple #11
0
    def set(self, key, value):
        key_token = self._tokenize(key)

        # if value is not string then pickle it
        if isinstance(value, basestring):
            stored_value = value
        else:
            pickled_value = pickle.dumps(value)
            stored_value = '%s%s' % (self._pickle_token, pickled_value)

        # set default timer, ignore if not set
        if self._timeout:
            response = self._redis.setex(key_token, stored_value, self._timeout)
        else:
            response = self._redis.set(key_token, stored_value)

        logger.debug('Set cache key:%s' % key_token)
        return response
Exemple #12
0
    def get(self, key):
        key_token = self._tokenize(key)
        value = None
        stored_value = self._redis.get(key_token)

        if stored_value:
            # check if the stored value is pickled
            if stored_value.find(self._pickle_token) == 0:
                pickled_value = stored_value.replace(self._pickle_token, '', 1)
                value = pickle.loads(pickled_value)
            else:
                value = stored_value

            logger.debug('Got cache key:%s' % key_token)
        else:
            logger.debug('Failed to get cache key:%s' % key_token)

        return value
Exemple #13
0
    def users_post(request):
        """
        an endpoint to create new users

        new users are not active by default

        TODO: have a user activation process


        errors
        ======

        * status 400 - if failed


        returns
        =======

        ::

            {
                "id": ""
            }
        """
        email = request.validated['email']
        password = request.validated['password']

        user = User.create(email, password)

        if user:
            # TODO: send activation email
            logger.debug('new user created')
            response_body = json.dumps({'id': user.json['id']})
        else:
            logger.debug('failed to create new user')
            request.response.status_int = 400
            response_body = json.dumps({
                'status': 'error',
                'message': 'failed to create new user'
            })

        request.response.body = response_body
        request.response.content_type = 'application/json'
        return request.response
Exemple #14
0
    def auth_post(request):
        """
        An endpoint to authenticate users and retrieve their access token.

        The access token is needed to authenticate requests that needs authorization::

            /endpont?access_token=<access token>


        returns
        =======

        returns 401 auth error if fails, otherswise returns::

            {
                'access_token': '',
                'user_id': ''
            }
        """
        email = request.validated['email']
        password = request.validated['password']
        user = User.authenticate_user(email, password)
        response_body = {}

        if user:
            # user found and authenticated
            logger.debug('user:{} authenticated'.format(email))
            access_token = create_access_token(user)
            response_body = json.dumps({
                'access_token': access_token,
                'user_id': str(user.id),
            })
        else:
            # user not found or authenticated
            logger.debug('user:{} failed authentication'.format(email))
            request.response.status_int = 401
            response_body = json.dumps({
                'status': 'error',
                'message': 'user failed to authenticate',
            })

        request.response.body = response_body
        request.response.content_type = 'application/json'
        return request.response
Exemple #15
0
    def user_get(request):
        """
        get user


        errors
        ======

        * status 404 - if the user couldn't be found


        returns
        =======

        ::

            {
                "modified": "2015-08-10T00:20:13.708000",
                "active": "false",
                "id": "55c7ee3dfad9b43993d7190e",
                "email": "*****@*****.**",
                "created": "2015-08-10T00:20:12.882000"
            }
        """
        user_id = request.matchdict['user_id']
        user = User.get_by_id(user_id)

        if user:
            logger.debug('got user:{}'.format(user_id))
            response_body = user.json
        else:
            logger.debug('could not find user:{}'.format(user_id))
            request.response.status_int = 404
            response_body = json.dumps({
                'status': 'error',
                'message': 'user does not exist'
            })

        request.response.body = response_body
        request.response.content_type = 'application/json'
        return request.response
Exemple #16
0
def validate_access_token(access_token):
    """
    This request requires validation. To get an access token use the ``/authenticate`` endpoint.
    """

    """
    Check to see if the access_token is valid

    The access token will invalidate if the user changes their password.


    parameters
    ==========

    * access_token - a token created with create_access_token

    returns
    =======

    returns True or False depending on if the access_token is valid
    """
    from settings import config

    validated = False

    try:
        decoded = jwt.decode(access_token, config.get('pepper', ''), algorithms=['HS256'])
    except jwt.DecodeError:
        logger.debug('jwt DecodeError')
    else:
        now = datetime.utcnow()
        then = datetime.fromtimestamp(decoded['iat'])

        age = now - then
        user = User.get_by_id(decoded['user_id'])

        # TODO: make the age configurable
        # for now the access_token is valid for 5 hours
        if age.seconds > 60 * 60 * 5:
            logger.debug('stale access token, timestamp expired')
        elif user and decoded['password'] == user.password:
            validated = {
                'user': user,
            }
            logger.debug('Valid access token for user:{}'.format(user.id))
        else:
            logger.debug('access token failed to validate')

    return validated
Exemple #17
0
def valid_key(request):
    """
    Check to see if a valid key has been sent

    If the key is valid it sets the user on the request.validated object

    ``request.validated['user']``
    """
    access_token = request.GET.get('access_token')
    validated = False

    # check which mode to authorize access
    if access_token:
        validated = validate_access_token(access_token)
    else:
        logger.debug('Invalid Access Token')
        raise Http401()

    # check if validation passed
    if validated:
        request.validated['user'] = validated.get('user')
    else:
        raise Http401()
Exemple #18
0
    def get_by_id(cls, id):
        """
        load the document by the id
        """
        obj = None

        # force id into ObjectId
        try:
            _id = ObjectId(id)
        except InvalidId:
            mongo_obj = None
            logger.debug('invalid ObjectId id:{}'.format(id))
        else:
            # get the mongo_obj
            mongo_obj = mongodb[cls.collection].find_one({'_id': _id})

        # initialize the class if mongo_obj was retrieved
        if mongo_obj:
            obj = cls(mongo=mongo_obj)
        else:
            logger.debug('did not find {} id:{}'.format(cls.collection, id))

        return obj
Exemple #19
0
    def user_password_put(request):
        """
        Update user's password


        errors
        ======

        * status 400 - if failed to update user
        * status 404 - if failed to find user


        returns
        =======

        ::

            {
                'status': 'success',
                'message': 'user password updated'
            }


        """
        user_id = request.matchdict['user_id']
        user = User.get_by_id(user_id)

        if user:
            # check for fields to update
            user.password = request.validated['password']

            # save
            if user.save():
                logger.debug('user:{} updated'.format(user_id))
                response_body = json.dumps({
                    'status': 'success',
                    'message': 'user password updated'
                })
            else:
                logger.debug('failed to save user:{} password'.format(user_id))
                request.response.status_int = 400
                response_body = json.dumps({
                    'status': 'error',
                    'message': 'failed to update user'
                })
        else:
            logger.debug('failed to update user:{} password, user not found'.format(user_id))
            request.response.status_int = 404
            response_body = json.dumps({
                'status': 'error',
                'message': 'could not find user'
            })

        request.response.body = response_body
        request.response.content_type = 'application/json'
        return request.response
Exemple #20
0
    def user_put(request):
        """
        Update user


        errors
        ======

        * status 400 - if failed to update user
        * status 404 - if user isn't found


        returns
        =======

        ::

            {
                'status': 'success',
                'message': 'user updated'
            }

        """
        user_id = request.matchdict['user_id']
        user = User.get_by_id(user_id)

        if user:
            user.active = request.validated['active']
            user.email = request.validated['email']

            # save
            if user.save():
                logger.debug('user:{} updated'.format(user_id))
                response_body = json.dumps({
                    'status': 'success',
                    'message': 'user updated'
                })
            else:
                logger.debug('failed to save user:{}'.format(user_id))
                request.response.status_int = 400
                response_body = json.dumps({
                    'status': 'error',
                    'message': 'failed to update user'
                })
        else:
            logger.debug('failed to update user:{} user not found'.format(user_id))
            request.response.status_int = 404
            response_body = json.dumps({
                'status': 'error',
                'message': 'could not find user'
            })

        request.response.body = response_body
        request.response.content_type = 'application/json'
        return request.response
Exemple #21
0
def add_endpoints(app):
    logger.debug("Adding endpoint routes.")
    app.add_url_rule('/', 'root', root)
    app.add_url_rule('/approve', 'approve', approve, methods=['POST'])
    app.add_url_rule('/token', 'token', token, methods=['GET', 'POST'])
    app.add_url_rule("/authorize", "authorize", authorize, methods=['GET', 'POST'])
Exemple #22
0
    def businesses_get(request):
        """
        Returns the businesses

        location format = [lng, lat]

        use limit and offset to paginate::

            http://localhost:8000/api/v1/businesses?limit=100&offset=0

        to restrict results withing a distance from a location use lat, lng, distance, and units::

            http://localhost:8000/api/v1/businesses?lng=-73.988395&lat=40.7461666&distance=3


        returns
        =======

        ::

            {
                "businesses": [{
                    "rating": 2.25,
                    "modified": "2015-08-10T00:20:14.370000",
                    "address": {
                        "street1": "Time Square",
                        "postal_code": "",
                        "street2": "",
                        "city": "New York",
                        "state": "NY"
                    },
                    "id": "55c7ee3efad9b43993d7190f",
                    "location": [
                        -73.985131,
                        40.758895
                    ],
                    "tags": [
                        "hello",
                        "world",
                        "example",
                        "awesome"
                    ],
                    "name": "Time Square",
                    "created": "2015-08-10T00:20:13.760000"
                }],
                "count": 1
            }
        """
        location = []
        lat = request.validated['lat']
        lng = request.validated['lng']
        distance = request.validated['distance']
        units = request.validated['units']
        limit = request.validated['limit']
        offset = request.validated['offset']

        # set location only if both lat and lng
        if lat and lng:
            location = [lng, lat]

        businesses = Business.businesses(location=location, distance=distance, units=units, limit=limit, offset=offset)

        # get business count to help pagination
        if location:
            # TODO: this count is wrong when location limiting
            businesses_count = len(businesses)
        else:
            businesses_count = Business.count()

        businesses_jsonable = []

        for business in businesses:
            businesses_jsonable.append(business.toJSON())

        response_body = {
            'businesses': businesses_jsonable,
            'count': businesses_count,
        }
        logger.debug('Retrieved businesses')

        request.response.body = json.dumps(response_body, cls=ComplexEncoder)
        request.response.content_type = 'application/json'
        return request.response
Exemple #23
0
    def business_get(request):
        """
        Returns the business

        errors
        ======

        * status 404 - if the business can't be found


        returns
        =======

        /businesses/<id>?reviews=true

        ::


            {
                "rating": 5,
                "modified": "2015-08-10T00:20:14.370000",
                "address": {
                    "street1": "Time Square",
                    "postal_code": "",
                    "street2": "",
                    "city": "New York",
                    "state": "NY"
                },
                "id": "55c7ee3efad9b43993d7190f",
                "location": [
                    -73.985131,
                    40.758895
                ],
                "reviews": [
                    {
                    "rating": 5,
                    "modified": "2015-08-10T00:20:17.753000",
                    "id": "55c7ee41fad9b43993d71919",
                    "user_id": "55c7ee3dfad9b43993d7190e",
                    "reviewed_id": "55c7ee3efad9b43993d7190f",
                    "tags": [
                        "awesome"
                    ],
                    "text": "This is awesome.",
                    "created": "2015-08-10T00:20:17.753000",
                    "reviewed_collection": "businesses"
                    }
                ],
                "tags": [
                    "awesome"
                ],
                "name": "Time Square",
                "created": "2015-08-10T00:20:13.760000"
            }
        """
        business_id = request.matchdict['business_id']
        include_reviews = request.validated['reviews']
        business = Business.get_by_id(business_id)

        # a light redis check is an example of how queries can be further optimized
        if include_reviews:
            cache_key = 'business:{}:reviews-true'.format(business_id)
        else:
            cache_key = 'business:{}:reviews-false'.format(business_id)

        cached = redis_cache.get(cache_key)

        if cached and business:
            response_body = cached
        elif business:
            response_body = business.toJSON()

            if include_reviews:
                response_body['reviews'] = Review.reviews_for_reviewed(business.collection, business.id)

            response_body = json.dumps(response_body, cls=ComplexEncoder)
            redis_cache.set(cache_key, response_body)
            logger.debug('Retrieved business:{}'.format(business.id))
        else:
            logger.debug('Failed to retrieve business:{}'.format(business_id))
            request.response.status_int = 404
            response_body = json.dumps({
                'status': 'error',
                'message': 'failed to find business'
            })

        request.response.body = response_body
        request.response.content_type = 'application/json'
        return request.response
 def __init__(self, review):
     logger.debug('new review updated event')
     self.review = review
Exemple #25
0
    def keys(self, pattern):
        pattern_token = self._tokenize(pattern)
        keys = self._redis.keys(pattern_token)

        logger.debug('Got keys for pattern:%s' % pattern_token)
        return keys
Exemple #26
0
def approve():
    logger.info("==> approve()")
    headers = {'Content-Type': 'text/html'}
    params = {}

    if not request.form:
        logger.error("Missing post parameters. Bad request.")
        return make_response(
            render_template(
                'error.html',
                error='Missing post form parameters. Bad request.'), 400,
            headers)
        # return "Bad Request", 400
    else:
        query = REQUESTS.pop(request.form['reqid'], None)
        query = query.decode('UTF-8')
        print("The query: ", query)
        if not query:
            logger.error("Did not get a query string.")
            return make_response(
                render_template('error.html', error='Bad Request'), 400,
                headers)
        else:
            params = parse.parse_qs(query)
            print(params)
        if request.form["approve"]:
            logger.debug("Approving a token request.")
            if params["response_type"][0] == 'code':
                code = generate_auth_code()
                # Not sure whwer the user comes from.
                # user = request.form['user']

                scope = params['scope'][0]
                req_scope = scope.split(' ')

                client = get_client_from_query(params)
                print(client)
                client_scope = client['scope']

                same = [item for item in req_scope if item in client_scope]
                if len(same) == 0:
                    # Client asked for a scope it could not have.
                    return make_response(
                        render_template('error.html', error='Invalid Scope'),
                        400, headers)

                # Save for later. A dictionary of stuff
                CODES[code] = {
                    'authorizationRequest': query,
                    'scope': scope,
                    'client_id': client['client_id']
                }

                # Build the redirect url
                redirect_uri = params['redirect_uri'][0]
                if redirect_uri not in client['redirect_uris']:
                    return make_response(
                        render_template('error.html',
                                        error='Invalid redirect URI.'), 400,
                        headers)

                state = params['state'][0]
                payload = {'code': code, 'state': state}

                the_location = ''.join(
                    (redirect_uri, '?', parse.urlencode(payload)))
                print(the_location)
                return redirect(the_location, code=302)

    return "Got here", 200
from service.flask import create_app
from service import logger

application = create_app()

logger.debug("Application initialized.")