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.models import Base
|
||||
from cookie_api.app import application_factory
|
@ -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 marshmallow import Schema, fields
|
||||
|
||||
from cookie_api.types import Datetime, Decimal
|
||||
|
||||
|
||||
# class CookieSchema(Schema):
|
||||
# id = fields.Int()
|
||||
# created_date = fields.DateTime()
|
||||
# modified_date = fields.DateTime()
|
||||
# name = fields.Str(required=True)
|
||||
# recipe_url = fields.Str()
|
||||
# sku = fields.Str(required=True)
|
||||
# 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
|
||||
}
|
||||
from apistar import types, validators
|
||||
from cookie_api.util import Decimal
|
||||
|
||||
|
||||
class CookieSchema(types.Type):
|
||||
id = validators.Integer(allow_null=True)
|
||||
created_date = validators.DateTime(allow_null=True)
|
||||
modified_date = validators.DateTime(allow_null=True)
|
||||
name = validators.String(max_length=50)
|
||||
recipe_url = validators.String(max_length=255)
|
||||
sku = validators.String(max_length=55)
|
||||
qoh = validators.Integer(minimum=0)
|
||||
unit_cost = Decimal(minimum=0.0)
|
||||
|
@ -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
|
||||
apistar==0.3.9
|
||||
apistar-alembic-migrations==0.0.6
|
||||
apistar-jwt==0.2.1
|
||||
alembic==0.9.9
|
||||
apistar==0.5.10
|
||||
apistar-jwt==0.4.2
|
||||
bcrypt==3.1.4
|
||||
certifi==2017.7.27.1
|
||||
cffi==1.11.2
|
||||
certifi==2018.4.16
|
||||
cffi==1.11.5
|
||||
chardet==3.0.4
|
||||
colorama==0.3.9
|
||||
coreapi==2.3.3
|
||||
coreschema==0.0.4
|
||||
idna==2.6
|
||||
itypes==1.1.0
|
||||
Jinja2==2.9.6
|
||||
Logbook==1.1.0
|
||||
Jinja2==2.10
|
||||
Logbook==1.3.3
|
||||
Mako==1.0.7
|
||||
MarkupSafe==1.0
|
||||
marshmallow==2.15.0
|
||||
psycopg2==2.7.3.1
|
||||
py==1.4.34
|
||||
psycopg2==2.7.4
|
||||
pycparser==2.18
|
||||
PyJWT==1.5.3
|
||||
pytest==3.2.3
|
||||
python-dateutil==2.6.1
|
||||
PyJWT==1.6.1
|
||||
python-dateutil==2.7.2
|
||||
python-editor==1.0.3
|
||||
requests==2.18.4
|
||||
six==1.11.0
|
||||
SQLAlchemy==1.1.14
|
||||
uritemplate==3.0.0
|
||||
SQLAlchemy==1.2.7
|
||||
urllib3==1.22
|
||||
Werkzeug==0.12.2
|
||||
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
|
||||
Werkzeug==0.14.1
|
||||
whitenoise==3.3.1
|
||||
|
Loading…
Reference in New Issue