Пример #1
0
 def create_api_blueprint(self, model=None, collection_name=None, app=None, methods=READONLY_METHODS,
                          url_prefix='/api', exclude_columns=None,
                          include_columns=None, include_methods=None,
                          results_per_page=10, max_results_per_page=100,
                          preprocess=None, postprocess=None, primary_key=None, *args, **kw):
     if collection_name is None:
         msg = ('collection_name is not valid.')
         raise IllegalArgumentError(msg)
         
     if exclude_columns is not None and include_columns is not None:
         msg = ('Cannot simultaneously specify both include columns and'
                ' exclude columns.')
         raise IllegalArgumentError(msg)
     
     if app is None:
         app = self.app
         
     restapi_ext = app.extensions[self.name]
     
     methods = frozenset((m.upper() for m in methods))
     no_instance_methods = methods & frozenset(('POST', ))
     instance_methods = methods & frozenset(('GET', 'PATCH', 'DELETE', 'PUT'))
     possibly_empty_instance_methods = methods & frozenset(('GET', ))
     
     # the base URL of the endpoints on which requests will be made
     collection_endpoint = '/{0}'.format(collection_name)
     
     apiname = APIManager.api_name(collection_name)
     
     preprocessors_ = defaultdict(list)
     postprocessors_ = defaultdict(list)
     preprocessors_.update(preprocess or {})
     postprocessors_.update(postprocess or {})
     
     api_view = self.view_cls.as_view(model=model, collection_name=collection_name,exclude_columns=exclude_columns,\
                         include_columns=include_columns, include_methods=include_methods,\
                         results_per_page=results_per_page, max_results_per_page=max_results_per_page, \
                         preprocess=preprocessors_, postprocess=postprocessors_, primary_key=primary_key,\
                         db=restapi_ext.db)
                            
     blueprintname = APIManager._next_blueprint_name(app.blueprints, apiname)
     blueprint = Blueprint(blueprintname, url_prefix=url_prefix)
     blueprint.add_route(api_view,collection_endpoint,methods=no_instance_methods)
     
     #DELETE, GET, PUT
     instance_endpoint = '{0}/<instid>'.format(collection_endpoint)
     blueprint.add_route(api_view,instance_endpoint,methods=instance_methods)
     
     return blueprint
Пример #2
0
    def create_api_blueprint(self, model=None, collection_name=None, app=None, methods=READONLY_METHODS,
                             url_prefix='/api', exclude_columns=None,
                             include_columns=None, include_methods=None,
                             results_per_page=10, max_results_per_page=100,
                             preprocess=None, postprocess=None, primary_key=None, *args, **kw):
        if collection_name is None:
            msg = ('collection_name is not valid.')
            raise IllegalArgumentError(msg)

        if exclude_columns is not None and include_columns is not None:
            msg = ('Cannot simultaneously specify both include columns and'
                   ' exclude columns.')
            raise IllegalArgumentError(msg)

        if app is None:
            app = self.app

        restapi_ext = app.extensions[self.name]

        methods = frozenset((m.upper() for m in methods))
        no_instance_methods = methods & frozenset(('POST', ))
        instance_methods = methods & frozenset(
            ('GET', 'PATCH', 'DELETE', 'PUT'))
        possibly_empty_instance_methods = methods & frozenset(('GET', ))

        # the base URL of the endpoints on which requests will be made
        collection_endpoint = '/{0}'.format(collection_name)

        apiname = APIManager.api_name(collection_name)

        preprocessors_ = defaultdict(list)
        postprocessors_ = defaultdict(list)
        preprocessors_.update(preprocess or {})
        postprocessors_.update(postprocess or {})

        api_view = self.view_cls.as_view(model=model, collection_name=collection_name, exclude_columns=exclude_columns,
                                         include_columns=include_columns, include_methods=include_methods,
                                         results_per_page=results_per_page, max_results_per_page=max_results_per_page,
                                         preprocess=preprocessors_, postprocess=postprocessors_, primary_key=primary_key,
                                         db=restapi_ext.db)

        blueprintname = APIManager._next_blueprint_name(
            app.blueprints, apiname)
        blueprint = Blueprint(blueprintname, url_prefix=url_prefix)
        blueprint.add_route(api_view, collection_endpoint,
                            methods=no_instance_methods)

        #DELETE, GET, PUT
        instance_endpoint = '{0}/<instid>'.format(collection_endpoint)
        blueprint.add_route(api_view, instance_endpoint,
                            methods=instance_methods)

        return blueprint
Пример #3
0
import os
import random
import string

from gatco.response import json
from gatco import Blueprint

import aiofiles

from application.server import app

upload = Blueprint('image', url_prefix='/image')


@upload.route('/')
async def bp_root(request):
    return json({'image': 'blueprint'})


@upload.route('/upload', methods=['POST'])
async def imgupload(request):
    ret = None
    url = app.config['IMAGE_SERVICE_URL']
    fsroot = app.config['FS_ROOT']
    if request.method == 'POST':
        file = request.files.get('image', None)
        if file:
            rand = ''.join(random.choice(string.digits) for _ in range(5))
            file_name = os.path.splitext(file.name)[0]
            extname = os.path.splitext(file.name)[1]
            newfilename = file_name + "-" + rand + extname
Пример #4
0
from gatco.response import json
from gatco import Blueprint
from jinja2 import Environment, PackageLoader
from goblin.extensions import jinja
from goblin.server import app

admin = Blueprint('admin', url_prefix='/admin')
jinja.add_loader("admin", PackageLoader("goblin.admin", 'templates'))


@admin.route('/')
async def index(request):
    return jinja.render('admin/index.html', request)


@admin.route('/login')
async def login(request):
    return json({'my': 'login'})


@admin.route('/logout')
async def logout(request):
    return json({'my': 'logout'})
Пример #5
0
from sqlalchemy.sql.expression import except_
import time
from datetime import datetime
from math import floor
from application.client import HTTPClient
from sqlalchemy import or_, and_, desc
from application.extensions import auth
import ujson
# import xlrender
# import xlrenderpy as xlrender
from openpyxl import Workbook
from openpyxl.styles import PatternFill, Border, Side, Alignment, Protection, Font

from gatco import Blueprint
exportbp = Blueprint('exportbp', url_prefix='/export')


@exportbp.route('/me')
async def me(request):
    return json({'my': 'blueprint'})


# @app.route('/exportexcel/test', methods=['GET'])
# async def get_token(request):
#     filename = "test.xlsx"
#     deffile = "sample.json"
#     template = "sample.xlsx"
#     render = xlrender.xlrender(template, deffile)
#     data = {
#         "data": []
Пример #6
0
    def create_api_blueprint(self,
                             model,
                             app=None,
                             methods=READONLY_METHODS,
                             url_prefix='/api',
                             collection_name=None,
                             allow_patch_many=False,
                             allow_delete_many=False,
                             allow_functions=False,
                             exclude_columns=None,
                             include_columns=None,
                             include_methods=None,
                             validation_exceptions=None,
                             results_per_page=10,
                             max_results_per_page=100,
                             post_form_preprocessor=None,
                             preprocess=None,
                             postprocess=None,
                             primary_key=None,
                             serializer=None,
                             deserializer=None):
        """Creates and returns a ReSTful API interface as a blueprint, but does
        not register it on any :class:`flask.Flask` application.

        The endpoints for the API for ``model`` will be available at
        ``<url_prefix>/<collection_name>``. If `collection_name` is ``None``,
        the lowercase name of the provided model class will be used instead, as
        accessed by ``model.__tablename__``. (If any black magic was performed
        on ``model.__tablename__``, this will be reflected in the endpoint
        URL.) For more information, see :ref:`collectionname`.

        This function must be called at most once for each model for which you
        wish to create a ReSTful API. Its behavior (for now) is undefined if
        called more than once.

        This function returns the :class:`flask.Blueprint` object which handles
        the endpoints for the model. The returned :class:`~flask.Blueprint` has
        already been registered with the :class:`~flask.Flask` application
        object specified in the constructor of this class, so you do *not* need
        to register it yourself.

        `model` is the SQLAlchemy model class for which a ReSTful interface
        will be created. Note this must be a class, not an instance of a class.

        `app` is the :class:`Flask` object on which we expect the blueprint
        created in this method to be eventually registered. If not specified,
        the Flask application specified in the constructor of this class is
        used.

        `methods` specify the HTTP methods which will be made available on the
        ReSTful API for the specified model, subject to the following caveats:

        * If :http:method:`get` is in this list, the API will allow getting a
          single instance of the model, getting all instances of the model, and
          searching the model using search parameters.
        * If :http:method:`patch` is in this list, the API will allow updating
          a single instance of the model, updating all instances of the model,
          and updating a subset of all instances of the model specified using
          search parameters.
        * If :http:method:`delete` is in this list, the API will allow deletion
          of a single instance of the model per request.
        * If :http:method:`post` is in this list, the API will allow posting a
          new instance of the model per request.

        The default set of methods provides a read-only interface (that is,
        only :http:method:`get` requests are allowed).

        `collection_name` is the name of the collection specified by the given
        model class to be used in the URL for the ReSTful API created. If this
        is not specified, the lowercase name of the model will be used.

        `url_prefix` the URL prefix at which this API will be accessible.

        If `allow_patch_many` is ``True``, then requests to
        :http:patch:`/api/<collection_name>?q=<searchjson>` will attempt to
        patch the attributes on each of the instances of the model which match
        the specified search query. This is ``False`` by default. For
        information on the search query parameter ``q``, see
        :ref:`searchformat`.

        If `allow_delete_many` is ``True``, then requests to
        :http:delete:`/api/<collection_name>?q=<searchjson>` will attempt to
        delete each instance of the model that matches the specified search
        query. This is ``False`` by default. For information on the search
        query parameter ``q``, see :ref:`searchformat`.

        `validation_exceptions` is the tuple of possible exceptions raised by
        validation of your database models. If this is specified, validation
        errors will be captured and forwarded to the client in JSON format. For
        more information on how to use validation, see :ref:`validation`.

        If `allow_functions` is ``True``, then requests to
        :http:get:`/api/eval/<collection_name>` will return the result of
        evaluating SQL functions specified in the body of the request. For
        information on the request format, see :ref:`functionevaluation`. This
        if ``False`` by default. Warning: you must not create an API for a
        model whose name is ``'eval'`` if you set this argument to ``True``.

        If either `include_columns` or `exclude_columns` is not ``None``,
        exactly one of them must be specified. If both are not ``None``, then
        this function will raise a :exc:`IllegalArgumentError`.
        `exclude_columns` must be an iterable of strings specifying the columns
        of `model` which will *not* be present in the JSON representation of
        the model provided in response to :http:method:`get` requests.
        Similarly, `include_columns` specifies the *only* columns which will be
        present in the returned dictionary. In other words, `exclude_columns`
        is a blacklist and `include_columns` is a whitelist; you can only use
        one of them per API endpoint. If either `include_columns` or
        `exclude_columns` contains a string which does not name a column in
        `model`, it will be ignored.

        If you attempt to either exclude a primary key field or not include a
        primary key field for :http:method:`post` requests, this method will
        raise an :exc:`IllegalArgumentError`.

        If `include_columns` is an iterable of length zero (like the empty
        tuple or the empty list), then the returned dictionary will be
        empty. If `include_columns` is ``None``, then the returned dictionary
        will include all columns not excluded by `exclude_columns`.

        If `include_methods` is an iterable of strings, the methods with names
        corresponding to those in this list will be called and their output
        included in the response.

        See :ref:`includes` for information on specifying included or excluded
        columns on fields of related models.

        `results_per_page` is a positive integer which represents the default
        number of results which are returned per page. Requests made by clients
        may override this default by specifying ``results_per_page`` as a query
        argument. `max_results_per_page` is a positive integer which represents
        the maximum number of results which are returned per page. This is a
        "hard" upper bound in the sense that even if a client specifies that
        greater than `max_results_per_page` should be returned, only
        `max_results_per_page` results will be returned. For more information,
        see :ref:`serverpagination`.

        .. deprecated:: 0.9.2
           The `post_form_preprocessor` keyword argument is deprecated in
           version 0.9.2. It will be removed in version 1.0. Replace code that
           looks like this::

               manager.create_api(Person, post_form_preprocessor=foo)

           with code that looks like this::

               manager.create_api(Person, preprocess=dict(POST=[foo]))

           See :ref:`processors` for more information and examples.

        `post_form_preprocessor` is a callback function which takes
        POST input parameters loaded from JSON and enhances them with other
        key/value pairs. The example use of this is when your ``model``
        requires to store user identity and for security reasons the identity
        is not read from the post parameters (where malicious user can tamper
        with them) but from the session.

        `preprocess` is a dictionary mapping strings to lists of
        functions. Each key is the name of an HTTP method (for example,
        ``'GET'`` or ``'POST'``). Each value is a list of functions, each of
        which will be called before any other code is executed when this API
        receives the corresponding HTTP request. The functions will be called
        in the order given here. The `postprocess` keyword argument is
        essentially the same, except the given functions are called after all
        other code. For more information on preprocess and postprocess,
        see :ref:`processors`.

        `primary_key` is a string specifying the name of the column of `model`
        to use as the primary key for the purposes of creating URLs. If the
        `model` has exactly one primary key, there is no need to provide a
        value for this. If `model` has two or more primary keys, you must
        specify which one to use.

        `serializer` and `deserializer` are custom serialization functions. The
        former function must take a single argument representing the instance
        of the model to serialize, and must return a dictionary representation
        of that instance. The latter function must take a single argument
        representing the dictionary representation of an instance of the model
        and must return an instance of `model` that has those attributes. For
        more information, see :ref:`serialization`.

        """

        if exclude_columns is not None and include_columns is not None:
            msg = ('Cannot simultaneously specify both include columns and'
                   ' exclude columns.')
            raise IllegalArgumentError(msg)
        # If no Flask application is specified, use the one (we assume) was
        # specified in the constructor.
        if app is None:
            app = self.app
        restlessinfo = app.extensions['restapi']
        if collection_name is None:
            collection_name = model.__tablename__

        # convert all method names to upper case
        methods = frozenset((m.upper() for m in methods))
        # sets of methods used for different types of endpoints
        no_instance_methods = methods & frozenset(('POST', ))
        instance_methods = \
            methods & frozenset(('GET', 'PATCH', 'DELETE', 'PUT'))
        possibly_empty_instance_methods = methods & frozenset(('GET', ))
        if allow_patch_many and ('PATCH' in methods or 'PUT' in methods):
            possibly_empty_instance_methods |= frozenset(('PATCH', 'PUT'))
        if allow_delete_many and 'DELETE' in methods:
            possibly_empty_instance_methods |= frozenset(('DELETE', ))

        # Check that primary_key is included for no_instance_methods
        if no_instance_methods:
            pk_name = primary_key or primary_key_name(model)
            if (include_columns and pk_name not in include_columns
                    or exclude_columns and pk_name in exclude_columns):
                msg = ('The primary key must be included for APIs with POST.')
                raise IllegalArgumentError(msg)

        # the base URL of the endpoints on which requests will be made
        collection_endpoint = '/{0}'.format(collection_name)

        # the name of the API, for use in creating the view and the blueprint
        apiname = APIManager.api_name(collection_name)

        # Prepend the universal preprocess and postprocess specified in
        # the constructor of this class.
        preprocessors_ = defaultdict(list)
        postprocessors_ = defaultdict(list)
        preprocessors_.update(preprocess or {})
        postprocessors_.update(postprocess or {})
        for key, value in restlessinfo.universal_preprocess.items():
            preprocessors_[key] = value + preprocessors_[key]
        for key, value in restlessinfo.universal_postprocess.items():
            postprocessors_[key] = value + postprocessors_[key]

        # the view function for the API for this model
        #api_view = API.as_view(apiname, restlessinfo.session, model,
        #                      exclude_columns, include_columns,
        #                       include_methods, validation_exceptions,
        #                       results_per_page, max_results_per_page,
        #                       post_form_preprocessor, preprocessors_,
        #                       postprocessors_, primary_key, serializer,
        #                       deserializer)

        api_view = API.as_view(restlessinfo.session, model, exclude_columns,
                               include_columns, include_methods,
                               validation_exceptions, results_per_page,
                               max_results_per_page, post_form_preprocessor,
                               preprocessors_, postprocessors_, primary_key,
                               serializer, deserializer)

        # suffix an integer to apiname according to already existing blueprints
        blueprintname = APIManager._next_blueprint_name(
            app.blueprints, apiname)

        # add the URL rules to the blueprint: the first is for methods on the
        # collection only, the second is for methods which may or may not
        # specify an instance, the third is for methods which must specify an
        # instance
        # TODO what should the second argument here be?
        # TODO should the url_prefix be specified here or in register_blueprint
        blueprint = Blueprint(blueprintname, url_prefix=url_prefix)
        # For example, /api/person.
        #POST --create POST item
        blueprint.add_route(api_view,
                            collection_endpoint,
                            methods=no_instance_methods)

        #blueprint.add_url_rule(collection_endpoint,
        #                       methods=no_instance_methods, view_func=api_view)
        # For example, /api/person/1.
        #GET
        #instance_endpoint = '{0}/<instid>/<relationname>/<relationinstid>'.format(collection_endpoint)
        #blueprint.add_route(api_view,instance_endpoint,methods=possibly_empty_instance_methods)

        #blueprint.add_url_rule(collection_endpoint,
        #                       defaults={'instid': None, 'relationname': None,
        #                                 'relationinstid': None},
        #                       methods=possibly_empty_instance_methods,
        #                       view_func=api_view)

        # the per-instance endpoints will allow both integer and string primary
        # key accesses
        # For example, /api/person/1.
        #DELETE, GET, PUT
        instance_endpoint = '{0}/<instid>'.format(collection_endpoint)
        blueprint.add_route(api_view,
                            instance_endpoint,
                            methods=instance_methods)
        #blueprint.add_url_rule(instance_endpoint, methods=instance_methods,
        #                       defaults={'relationname': None,
        #                                 'relationinstid': None},
        #                       view_func=api_view)

        # add endpoints which expose related models
        relation_endpoint = '{0}/<relationname>'.format(instance_endpoint)
        relation_instance_endpoint = \
            '{0}/<relationinstid>'.format(relation_endpoint)
        # For example, /api/person/1/computers.
        #blueprint.add_url_rule(relation_endpoint,
        #                       methods=possibly_empty_instance_methods,
        #                       defaults={'relationinstid': None},
        #                       view_func=api_view)
        # For example, /api/person/1/computers/2.
        #blueprint.add_url_rule(relation_instance_endpoint,
        #                       methods=instance_methods,
        #                       view_func=api_view)

        blueprint.add_route(api_view,
                            relation_endpoint,
                            methods=possibly_empty_instance_methods)
        blueprint.add_route(api_view,
                            relation_instance_endpoint,
                            methods=instance_methods)

        # if function evaluation is allowed, add an endpoint at /api/eval/...
        # which responds only to GET requests and responds with the result of
        # evaluating functions on all instances of the specified model
        if allow_functions:
            eval_api_name = apiname + 'eval'
            eval_api_view = FunctionAPI.as_view(eval_api_name,
                                                restlessinfo.session, model)
            eval_endpoint = '/eval' + collection_endpoint
            blueprint.add_url_rule(eval_endpoint,
                                   methods=['GET'],
                                   view_func=eval_api_view)
        # Finally, record that this APIManager instance has created an API for
        # the specified model.
        self.created_apis_for[model] = APIInfo(collection_name, blueprint.name)
        return blueprint