From 7b23ad97d877fd36f1c52a0a96057bbf740088bf Mon Sep 17 00:00:00 2001 From: androiddrew Date: Tue, 27 Feb 2018 19:54:01 -0500 Subject: [PATCH] Moving to Typesystem Moving to type system. Added registration endpoint. Added custom Decimal type. --- cookie_api/app.py | 11 +++++--- cookie_api/auth.py | 21 ++++++---------- cookie_api/schema.py | 60 +++++++++++++++++++++++++++++++++++--------- cookie_api/types.py | 10 ++++++-- tests/conftest.py | 6 ++--- 5 files changed, 74 insertions(+), 34 deletions(-) diff --git a/cookie_api/app.py b/cookie_api/app.py index e2d0a89..cea3042 100644 --- a/cookie_api/app.py +++ b/cookie_api/app.py @@ -1,3 +1,5 @@ +import typing + from apistar import Include, Route, http, annotate from apistar.backends import sqlalchemy_backend from apistar.backends.sqlalchemy_backend import Session @@ -14,6 +16,7 @@ import logbook from cookie_api.auth import auth_routes, auth_components from cookie_api.commands import commands from cookie_api.models import Cookie +#from cookie_api.schema import CookieSchema from cookie_api.schema import CookieSchema from cookie_api import logging @@ -31,19 +34,19 @@ def get_state(injector: Injector, auth: Auth): return d -def get_cookies(session: Session): +def get_cookies(session: Session) -> typing.List[CookieSchema]: logger.info("Accessing the Cookies resource") cookies = session.query(Cookie).all() - return cookie_schema.dump(cookies, many=True).data + return [CookieSchema(cookie) for cookie in cookies] -def get_cookie(session: Session, id): +def get_cookie(session: Session, id) -> CookieSchema: cookie = session.query(Cookie).filter_by(id=id).one_or_none() if cookie is None: logger.warn("Someone keeps requesting bad cookie locations") msg = {"error": "404 Not Found"} return http.Response(msg, status=404) - return cookie_schema.dump(cookie).data + return CookieSchema(cookie) def create_cookie(session: Session, json_data: http.RequestData, route: Router): diff --git a/cookie_api/auth.py b/cookie_api/auth.py index aabf8ec..ace17f1 100644 --- a/cookie_api/auth.py +++ b/cookie_api/auth.py @@ -10,6 +10,7 @@ from sqlalchemy.exc import IntegrityError, InvalidRequestError from sqlalchemy.orm.exc import NoResultFound from cookie_api.models import User +from cookie_api.schema import UserSchema, UserCreateSchema auth_components = [ Component(JWT, init=get_jwt) @@ -59,11 +60,8 @@ def logout(): # TODO Add user registration -def register(json_data: http.RequestData, session: Session, mail: Mail): - user_id = json_data.get('email') - password = json_data.get('password') - - email_check = session.query(User).filter_by(email=user_id).one_or_none() +def register(user_rep: UserCreateSchema, session: Session, mail: Mail): + email_check = session.query(User).filter_by(email=user_rep['email']).one_or_none() if email_check is not None: message = { @@ -72,12 +70,12 @@ def register(json_data: http.RequestData, session: Session, mail: Mail): } return http.Response(message, status=400) - user = User(email=user_id, password=password) + user = User(email=user_rep['email'], password=user_rep['password']) session.add(user) session.commit() - msg = Message("Thank you for registering please confirm your email", recipients=[user_id]) + msg = Message("Thank you for registering please confirm your email", recipients=[user_rep['email']]) mail.send(msg) headers = {} @@ -85,18 +83,15 @@ def register(json_data: http.RequestData, session: Session, mail: Mail): 'status': 'success', 'message': 'Please check your inbox and confirm your email' } - return http.Response(message, status=200, headers=headers) + return http.Response(message, status=201, headers=headers) @annotate(authentication=[JWTAuthentication()]) -def user_profile(auth: Auth, settings: Settings, session: Session): +def user_profile(auth: Auth, settings: Settings, session: Session) -> UserSchema: token = JWT(token=auth.token, settings=settings) user_id = token.payload.get('sub') user = session.query(User).filter_by(id=user_id).one() - result = user.to_dict() - result.pop('password', None) - return result - + return UserSchema(user) # TODO Add email confirmation def confirm(json_data: http.RequestData, session: Session): diff --git a/cookie_api/schema.py b/cookie_api/schema.py index 87c82e2..49cd572 100644 --- a/cookie_api/schema.py +++ b/cookie_api/schema.py @@ -1,12 +1,48 @@ -from marshmallow import Schema, fields - - -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) +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 + } \ No newline at end of file diff --git a/cookie_api/types.py b/cookie_api/types.py index dd23fcc..9d5b13a 100644 --- a/cookie_api/types.py +++ b/cookie_api/types.py @@ -1,6 +1,8 @@ import datetime +import decimal + import dateutil -from apistar.typesystem import TypeSystemError +from apistar import typesystem class Datetime(datetime.datetime): @@ -13,7 +15,11 @@ class Datetime(datetime.datetime): try: return dateutil.parser.parse(args[0]) except ValueError: - raise TypeSystemError(cls=cls, code='type') from None + 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 + + diff --git a/tests/conftest.py b/tests/conftest.py index 55e7cb2..bdfb7f8 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,7 +5,7 @@ import pytest from cookie_api.models import Base from cookie_api.renders import JSONRenderer -from cookie_api.app import commands, routes, components +from cookie_api.app import commands, _routes, _components settings = { 'DATABASE': { @@ -49,5 +49,5 @@ def apistar_app_fixture(): """Returns a session scoped WSGIApp instance""" return WSGIApp(settings=settings, commands=commands, - components=components, - routes=routes) + components=_components, + routes=_routes)