leveled up, minus auth
							parent
							
								
									7b23ad97d8
								
							
						
					
					
						commit
						d0a9b556c6
					
				@ -1,3 +1 @@
 | 
				
			|||||||
from cookie_api.renders import JSONRenderer
 | 
					 | 
				
			||||||
from cookie_api.app import application_factory
 | 
					from cookie_api.app import application_factory
 | 
				
			||||||
from cookie_api.models import Base
 | 
					 | 
				
			||||||
@ -1,16 +0,0 @@
 | 
				
			|||||||
from apistar import Command
 | 
					 | 
				
			||||||
from apistar.backends.sqlalchemy_backend import Session
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from cookie_api.models import User
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def create_user(session: Session, email, password):
 | 
					 | 
				
			||||||
    user = User(email, password)
 | 
					 | 
				
			||||||
    session.add(user)
 | 
					 | 
				
			||||||
    session.commit()
 | 
					 | 
				
			||||||
    print('User added')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
commands = [
 | 
					 | 
				
			||||||
    Command('create_user', create_user)
 | 
					 | 
				
			||||||
]
 | 
					 | 
				
			||||||
@ -1,25 +0,0 @@
 | 
				
			|||||||
import datetime as dt
 | 
					 | 
				
			||||||
import decimal
 | 
					 | 
				
			||||||
import json
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from apistar import http
 | 
					 | 
				
			||||||
from apistar.renderers import Renderer
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def extended_encoder(obj):
 | 
					 | 
				
			||||||
    """JSON encoder function with support for ISO 8601 datetime serialization and Decimal to float casting"""
 | 
					 | 
				
			||||||
    if isinstance(obj, dt.datetime):
 | 
					 | 
				
			||||||
        return obj.isoformat()
 | 
					 | 
				
			||||||
    elif isinstance(obj, decimal.Decimal):
 | 
					 | 
				
			||||||
        return float(obj)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class JSONRenderer(Renderer):
 | 
					 | 
				
			||||||
    """JSON Render with support for ISO 8601 datetime serialization and Decimal to float casting"""
 | 
					 | 
				
			||||||
    media_type = 'application/json'
 | 
					 | 
				
			||||||
    charset = None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def render(self, data: http.ResponseData) -> bytes:
 | 
					 | 
				
			||||||
        return json.dumps(data, default=extended_encoder).encode('utf-8')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# TODO add an XML render
 | 
					 | 
				
			||||||
@ -1,48 +1,13 @@
 | 
				
			|||||||
from apistar import typesystem
 | 
					from apistar import types, validators
 | 
				
			||||||
# from marshmallow import Schema, fields
 | 
					from cookie_api.util import Decimal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from cookie_api.types import Datetime, Decimal
 | 
					
 | 
				
			||||||
 | 
					class CookieSchema(types.Type):
 | 
				
			||||||
 | 
					    id = validators.Integer(allow_null=True)
 | 
				
			||||||
# class CookieSchema(Schema):
 | 
					    created_date = validators.DateTime(allow_null=True)
 | 
				
			||||||
#     id = fields.Int()
 | 
					    modified_date = validators.DateTime(allow_null=True)
 | 
				
			||||||
#     created_date = fields.DateTime()
 | 
					    name = validators.String(max_length=50)
 | 
				
			||||||
#     modified_date = fields.DateTime()
 | 
					    recipe_url = validators.String(max_length=255)
 | 
				
			||||||
#     name = fields.Str(required=True)
 | 
					    sku = validators.String(max_length=55)
 | 
				
			||||||
#     recipe_url = fields.Str()
 | 
					    qoh = validators.Integer(minimum=0)
 | 
				
			||||||
#     sku = fields.Str(required=True)
 | 
					    unit_cost = Decimal(minimum=0.0)
 | 
				
			||||||
#     qoh = fields.Int(required=True)
 | 
					 | 
				
			||||||
#     unit_cost = fields.Decimal(required=True)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class UserSchema(typesystem.Object):
 | 
					 | 
				
			||||||
    description = 'A User respresentation'
 | 
					 | 
				
			||||||
    properties = {
 | 
					 | 
				
			||||||
        'id': typesystem.integer(),
 | 
					 | 
				
			||||||
        'created_date': Datetime,
 | 
					 | 
				
			||||||
        'modified_date': Datetime,
 | 
					 | 
				
			||||||
        'email': typesystem.string(max_length=255),
 | 
					 | 
				
			||||||
        'confirmed': typesystem.boolean(),
 | 
					 | 
				
			||||||
        'admin': typesystem.boolean()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class UserCreateSchema(typesystem.Object):
 | 
					 | 
				
			||||||
    description = 'A User respresentation for creating a user'
 | 
					 | 
				
			||||||
    properties = {
 | 
					 | 
				
			||||||
        'email': typesystem.string(max_length=255),
 | 
					 | 
				
			||||||
        'password': typesystem.string(max_length=255)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class CookieSchema(typesystem.Object):
 | 
					 | 
				
			||||||
    properties = {
 | 
					 | 
				
			||||||
        'id': typesystem.integer(),
 | 
					 | 
				
			||||||
        'created_date': Datetime,
 | 
					 | 
				
			||||||
        'modified_date': Datetime,
 | 
					 | 
				
			||||||
        'name': typesystem.string(),
 | 
					 | 
				
			||||||
        'recipe_url': typesystem.string(),
 | 
					 | 
				
			||||||
        'sku': typesystem.string(),
 | 
					 | 
				
			||||||
        'qoh': typesystem.integer(),
 | 
					 | 
				
			||||||
        'unit_cost': Decimal
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -1,25 +0,0 @@
 | 
				
			|||||||
import datetime
 | 
					 | 
				
			||||||
import decimal
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import dateutil
 | 
					 | 
				
			||||||
from apistar import typesystem
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Datetime(datetime.datetime):
 | 
					 | 
				
			||||||
    native_type = datetime.datetime
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def __new__(cls, *args, **kwargs) -> datetime:
 | 
					 | 
				
			||||||
        if args and isinstance(args[0], cls.native_type):
 | 
					 | 
				
			||||||
            return args[0]
 | 
					 | 
				
			||||||
        if args and isinstance(args[0], str):
 | 
					 | 
				
			||||||
            try:
 | 
					 | 
				
			||||||
                return dateutil.parser.parse(args[0])
 | 
					 | 
				
			||||||
            except ValueError:
 | 
					 | 
				
			||||||
                raise typesystem.TypeSystemError(cls=cls, code='type') from None
 | 
					 | 
				
			||||||
        return cls.native_type(*args, **kwargs)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Decimal(typesystem._NumericType, decimal.Decimal):
 | 
					 | 
				
			||||||
    native_type = decimal.Decimal
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@ -0,0 +1,106 @@
 | 
				
			|||||||
 | 
					import datetime as dt
 | 
				
			||||||
 | 
					import decimal
 | 
				
			||||||
 | 
					from math import isfinite
 | 
				
			||||||
 | 
					import typing
 | 
				
			||||||
 | 
					from apistar import types, validators
 | 
				
			||||||
 | 
					from apistar.http import JSONResponse, Response
 | 
				
			||||||
 | 
					from apistar.server.components import Component
 | 
				
			||||||
 | 
					from sqlalchemy.engine import Engine
 | 
				
			||||||
 | 
					from sqlalchemy.orm import sessionmaker, Session, scoped_session
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Decimal(validators.NumericType):
 | 
				
			||||||
 | 
					    numeric_type = decimal.Decimal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def validate(self, value, definitions=None, allow_coerce=False):
 | 
				
			||||||
 | 
					        if value is None and self.allow_null:
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					        elif value is None:
 | 
				
			||||||
 | 
					            self.error('null')
 | 
				
			||||||
 | 
					        elif isinstance(value, bool):
 | 
				
			||||||
 | 
					            self.error('type')
 | 
				
			||||||
 | 
					        elif self.numeric_type is int and isinstance(value, float) and not value.is_integer():
 | 
				
			||||||
 | 
					            self.error('integer')
 | 
				
			||||||
 | 
					        elif not isinstance(value, (int, float, decimal.Decimal)) and not allow_coerce:
 | 
				
			||||||
 | 
					            self.error('type')
 | 
				
			||||||
 | 
					        elif isinstance(value, float) and not isfinite(value):
 | 
				
			||||||
 | 
					            self.error('finite')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            value = self.numeric_type(value)
 | 
				
			||||||
 | 
					        except (TypeError, ValueError):
 | 
				
			||||||
 | 
					            self.error('type')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if self.enum is not None:
 | 
				
			||||||
 | 
					            if value not in self.enum:
 | 
				
			||||||
 | 
					                if len(self.enum) == 1:
 | 
				
			||||||
 | 
					                    self.error('exact')
 | 
				
			||||||
 | 
					                self.error('enum')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if self.minimum is not None:
 | 
				
			||||||
 | 
					            if self.exclusive_minimum:
 | 
				
			||||||
 | 
					                if value <= self.minimum:
 | 
				
			||||||
 | 
					                    self.error('exclusive_minimum')
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                if value < self.minimum:
 | 
				
			||||||
 | 
					                    self.error('minimum')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if self.maximum is not None:
 | 
				
			||||||
 | 
					            if self.exclusive_maximum:
 | 
				
			||||||
 | 
					                if value >= self.maximum:
 | 
				
			||||||
 | 
					                    self.error('exclusive_maximum')
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                if value > self.maximum:
 | 
				
			||||||
 | 
					                    self.error('maximum')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if self.multiple_of is not None:
 | 
				
			||||||
 | 
					            if isinstance(self.multiple_of, float):
 | 
				
			||||||
 | 
					                if not (value * (1 / self.multiple_of)).is_integer():
 | 
				
			||||||
 | 
					                    self.error('multiple_of')
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                if value % self.multiple_of:
 | 
				
			||||||
 | 
					                    self.error('multiple_of')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ExtJSONResponse(JSONResponse):
 | 
				
			||||||
 | 
					    """JSON Response with support for ISO 8601 datetime serialization and Decimal to float casting"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def default(self, obj: typing.Any) -> typing.Any:
 | 
				
			||||||
 | 
					        if isinstance(obj, types.Type):
 | 
				
			||||||
 | 
					            return dict(obj)
 | 
				
			||||||
 | 
					        if isinstance(obj, dt.datetime):
 | 
				
			||||||
 | 
					            return obj.isoformat()
 | 
				
			||||||
 | 
					        elif isinstance(obj, decimal.Decimal):
 | 
				
			||||||
 | 
					            return float(obj)
 | 
				
			||||||
 | 
					        error = "Object of type '%s' is not JSON serializable."
 | 
				
			||||||
 | 
					        return TypeError(error % type(obj).__name_)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DBSession = scoped_session(sessionmaker())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SQLAlchemySession(Component):
 | 
				
			||||||
 | 
					    def __init__(self, engine=None):
 | 
				
			||||||
 | 
					        if not isinstance(engine, Engine):
 | 
				
			||||||
 | 
					            raise ValueError('SQLAlchemySession must be instantiated with a sqlalchemy.engine.Engine object')
 | 
				
			||||||
 | 
					        self.engine = engine
 | 
				
			||||||
 | 
					        DBSession.configure(bind=self.engine)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def resolve(self) -> Session:
 | 
				
			||||||
 | 
					        return DBSession()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SQLAlchemyHook:
 | 
				
			||||||
 | 
					    def on_request(self, session: Session):
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_response(self, session: Session, response: Response):
 | 
				
			||||||
 | 
					        DBSession.remove()
 | 
				
			||||||
 | 
					        return response
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_error(self, session: Session, response: Response):
 | 
				
			||||||
 | 
					        session.rollback()
 | 
				
			||||||
 | 
					        DBSession.remove()
 | 
				
			||||||
 | 
					        return response
 | 
				
			||||||
@ -1,66 +1,23 @@
 | 
				
			|||||||
alembic==0.9.6
 | 
					alembic==0.9.9
 | 
				
			||||||
apistar==0.3.9
 | 
					apistar==0.5.10
 | 
				
			||||||
apistar-alembic-migrations==0.0.6
 | 
					apistar-jwt==0.4.2
 | 
				
			||||||
apistar-jwt==0.2.1
 | 
					 | 
				
			||||||
bcrypt==3.1.4
 | 
					bcrypt==3.1.4
 | 
				
			||||||
certifi==2017.7.27.1
 | 
					certifi==2018.4.16
 | 
				
			||||||
cffi==1.11.2
 | 
					cffi==1.11.5
 | 
				
			||||||
chardet==3.0.4
 | 
					chardet==3.0.4
 | 
				
			||||||
colorama==0.3.9
 | 
					 | 
				
			||||||
coreapi==2.3.3
 | 
					 | 
				
			||||||
coreschema==0.0.4
 | 
					 | 
				
			||||||
idna==2.6
 | 
					idna==2.6
 | 
				
			||||||
itypes==1.1.0
 | 
					Jinja2==2.10
 | 
				
			||||||
Jinja2==2.9.6
 | 
					Logbook==1.3.3
 | 
				
			||||||
Logbook==1.1.0
 | 
					 | 
				
			||||||
Mako==1.0.7
 | 
					Mako==1.0.7
 | 
				
			||||||
MarkupSafe==1.0
 | 
					MarkupSafe==1.0
 | 
				
			||||||
marshmallow==2.15.0
 | 
					psycopg2==2.7.4
 | 
				
			||||||
psycopg2==2.7.3.1
 | 
					 | 
				
			||||||
py==1.4.34
 | 
					 | 
				
			||||||
pycparser==2.18
 | 
					pycparser==2.18
 | 
				
			||||||
PyJWT==1.5.3
 | 
					PyJWT==1.6.1
 | 
				
			||||||
pytest==3.2.3
 | 
					python-dateutil==2.7.2
 | 
				
			||||||
python-dateutil==2.6.1
 | 
					 | 
				
			||||||
python-editor==1.0.3
 | 
					python-editor==1.0.3
 | 
				
			||||||
requests==2.18.4
 | 
					requests==2.18.4
 | 
				
			||||||
six==1.11.0
 | 
					six==1.11.0
 | 
				
			||||||
SQLAlchemy==1.1.14
 | 
					SQLAlchemy==1.2.7
 | 
				
			||||||
uritemplate==3.0.0
 | 
					 | 
				
			||||||
urllib3==1.22
 | 
					urllib3==1.22
 | 
				
			||||||
Werkzeug==0.12.2
 | 
					Werkzeug==0.14.1
 | 
				
			||||||
whitenoise==3.3.1
 | 
					 | 
				
			||||||
alembic==0.9.6
 | 
					 | 
				
			||||||
apistar==0.3.9
 | 
					 | 
				
			||||||
apistar-alembic-migrations==0.0.6
 | 
					 | 
				
			||||||
apistar-jwt==0.2.1
 | 
					 | 
				
			||||||
apistar-mail==0.2.0
 | 
					 | 
				
			||||||
bcrypt==3.1.4
 | 
					 | 
				
			||||||
certifi==2017.7.27.1
 | 
					 | 
				
			||||||
cffi==1.11.2
 | 
					 | 
				
			||||||
chardet==3.0.4
 | 
					 | 
				
			||||||
colorama==0.3.9
 | 
					 | 
				
			||||||
coreapi==2.3.3
 | 
					 | 
				
			||||||
coreschema==0.0.4
 | 
					 | 
				
			||||||
idna==2.6
 | 
					 | 
				
			||||||
itsdangerous==0.24
 | 
					 | 
				
			||||||
itypes==1.1.0
 | 
					 | 
				
			||||||
Jinja2==2.9.6
 | 
					 | 
				
			||||||
Logbook==1.1.0
 | 
					 | 
				
			||||||
Mako==1.0.7
 | 
					 | 
				
			||||||
MarkupSafe==1.0
 | 
					 | 
				
			||||||
marshmallow==2.15.0
 | 
					 | 
				
			||||||
psycopg2==2.7.3.1
 | 
					 | 
				
			||||||
py==1.4.34
 | 
					 | 
				
			||||||
pycparser==2.18
 | 
					 | 
				
			||||||
PyJWT==1.5.3
 | 
					 | 
				
			||||||
pytest==3.2.3
 | 
					 | 
				
			||||||
python-dateutil==2.6.1
 | 
					 | 
				
			||||||
python-editor==1.0.3
 | 
					 | 
				
			||||||
requests==2.18.4
 | 
					 | 
				
			||||||
six==1.11.0
 | 
					 | 
				
			||||||
SQLAlchemy==1.1.14
 | 
					 | 
				
			||||||
uritemplate==3.0.0
 | 
					 | 
				
			||||||
urllib3==1.22
 | 
					 | 
				
			||||||
Werkzeug==0.12.2
 | 
					 | 
				
			||||||
whitenoise==3.3.1
 | 
					whitenoise==3.3.1
 | 
				
			||||||
 | 
				
			|||||||
					Loading…
					
					
				
		Reference in New Issue