mirror of
https://github.com/GSA/notifications-api.git
synced 2026-08-19 14:08:47 -04:00
Service and User API added, working with tests. Still need to polish the edges and add more tests.
This commit is contained in:
@@ -3,12 +3,14 @@ import os
|
||||
from flask._compat import string_types
|
||||
from flask import Flask, _request_ctx_stack
|
||||
from flask.ext.sqlalchemy import SQLAlchemy
|
||||
from flask_marshmallow import Marshmallow
|
||||
from werkzeug.local import LocalProxy
|
||||
from config import configs
|
||||
from utils import logging
|
||||
|
||||
|
||||
db = SQLAlchemy()
|
||||
ma = Marshmallow()
|
||||
|
||||
api_user = LocalProxy(lambda: _request_ctx_stack.top.api_user)
|
||||
|
||||
@@ -20,6 +22,7 @@ def create_app(config_name):
|
||||
application.config.from_object(configs[config_name])
|
||||
|
||||
db.init_app(application)
|
||||
ma.init_app(application)
|
||||
init_app(application)
|
||||
|
||||
logging.init_app(application)
|
||||
|
||||
@@ -1,31 +1,32 @@
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy.orm import load_only
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
|
||||
from app import db
|
||||
from app.models import Service
|
||||
|
||||
|
||||
def create_service(service_name,
|
||||
user,
|
||||
limit=1000,
|
||||
active=False,
|
||||
restricted=True):
|
||||
service = Service(name=service_name,
|
||||
created_at=datetime.now(),
|
||||
limit=limit,
|
||||
active=active,
|
||||
restricted=restricted)
|
||||
# Should I use SQLAlchemyError?
|
||||
class DAOException(SQLAlchemyError):
|
||||
pass
|
||||
|
||||
|
||||
def create_model_service(service):
|
||||
users_list = getattr(service, 'users', [])
|
||||
if not users_list:
|
||||
error_msg = {'users': 'Missing data for required attribute'}
|
||||
raise DAOException(json.dumps(error_msg))
|
||||
db.session.add(service)
|
||||
service.users.append(user)
|
||||
db.session.commit()
|
||||
return service.id
|
||||
|
||||
|
||||
def get_services(service_id=None, user_id=None):
|
||||
def get_model_services(service_id=None, user_id=None):
|
||||
# TODO need better mapping from function params to sql query.
|
||||
if user_id and service_id:
|
||||
return Service.query.filter(Service.users.any(id=user_id), id=service_id).one()
|
||||
return Service.query.filter(
|
||||
Service.users.any(id=user_id), id=service_id).one()
|
||||
elif service_id:
|
||||
return Service.query.filter_by(id=service_id).one()
|
||||
elif user_id:
|
||||
|
||||
@@ -6,15 +6,12 @@ from app import db
|
||||
from app.models import User
|
||||
|
||||
|
||||
def create_user(email_address):
|
||||
user = User(email_address=email_address,
|
||||
created_at=datetime.now())
|
||||
db.session.add(user)
|
||||
def create_model_user(usr):
|
||||
db.session.add(usr)
|
||||
db.session.commit()
|
||||
return user.id
|
||||
|
||||
|
||||
def get_users(user_id=None):
|
||||
def get_model_users(user_id=None):
|
||||
if user_id:
|
||||
return User.query.filter_by(id=user_id).one()
|
||||
return User.query.filter_by().all()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from . import db
|
||||
import datetime
|
||||
|
||||
|
||||
def filter_null_value_fields(obj):
|
||||
@@ -12,22 +13,18 @@ class User(db.Model):
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
email_address = db.Column(db.String(255), nullable=False, index=True, unique=True)
|
||||
created_at = db.Column(db.DateTime, index=False, unique=False, nullable=False)
|
||||
updated_at = db.Column(db.DateTime, index=False, unique=False, nullable=True)
|
||||
|
||||
# def serialize(self):
|
||||
# serialized = {
|
||||
# 'id': self.id,
|
||||
# 'name': self.name,
|
||||
# 'emailAddress': self.email_address,
|
||||
# 'locked': self.failed_login_count > current_app.config['MAX_FAILED_LOGIN_COUNT'],
|
||||
# 'createdAt': self.created_at.strftime(DATETIME_FORMAT),
|
||||
# 'updatedAt': self.updated_at.strftime(DATETIME_FORMAT),
|
||||
# 'role': self.role,
|
||||
# 'passwordChangedAt': self.password_changed_at.strftime(DATETIME_FORMAT),
|
||||
# 'failedLoginCount': self.failed_login_count
|
||||
# }
|
||||
# return filter_null_value_fields(serialized)
|
||||
created_at = db.Column(
|
||||
db.DateTime,
|
||||
index=False,
|
||||
unique=False,
|
||||
nullable=False,
|
||||
default=datetime.datetime.now)
|
||||
updated_at = db.Column(
|
||||
db.DateTime,
|
||||
index=False,
|
||||
unique=False,
|
||||
nullable=True,
|
||||
onupdate=datetime.datetime.now)
|
||||
|
||||
|
||||
user_to_service = db.Table(
|
||||
@@ -43,21 +40,22 @@ class Service(db.Model):
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
name = db.Column(db.String(255), nullable=False)
|
||||
created_at = db.Column(db.DateTime, index=False, unique=False, nullable=False)
|
||||
created_at = db.Column(
|
||||
db.DateTime,
|
||||
index=False,
|
||||
unique=False,
|
||||
nullable=False,
|
||||
default=datetime.datetime.now)
|
||||
updated_at = db.Column(
|
||||
db.DateTime,
|
||||
index=False,
|
||||
unique=False,
|
||||
nullable=True,
|
||||
onupdate=datetime.datetime.now)
|
||||
active = db.Column(db.Boolean, index=False, unique=False, nullable=False)
|
||||
limit = db.Column(db.BigInteger, index=False, unique=False, nullable=False)
|
||||
users = db.relationship('User', secondary=user_to_service, backref=db.backref('user_to_service', lazy='dynamic'))
|
||||
users = db.relationship(
|
||||
'User',
|
||||
secondary=user_to_service,
|
||||
backref=db.backref('user_to_service', lazy='dynamic'))
|
||||
restricted = db.Column(db.Boolean, index=False, unique=False, nullable=False)
|
||||
|
||||
# def serialize(self):
|
||||
# serialized = {
|
||||
# 'id': self.id,
|
||||
# 'name': self.name,
|
||||
# 'createdAt': self.created_at.strftime(DATETIME_FORMAT),
|
||||
# 'active': self.active,
|
||||
# 'restricted': self.restricted,
|
||||
# 'limit': self.limit,
|
||||
# 'user': self.users.serialize()
|
||||
# }
|
||||
|
||||
# return filter_null_value_fields(serialized)
|
||||
|
||||
@@ -1,20 +1,43 @@
|
||||
from marshmallow_sqlalchemy import ModelSchema
|
||||
from . import ma
|
||||
from . import models
|
||||
from marshmallow import post_load
|
||||
|
||||
# TODO I think marshmallow provides a better integration and error handling.
|
||||
# Would be better to replace functionality in dao with the marshmallow supported
|
||||
# functionality.
|
||||
# http://marshmallow.readthedocs.org/en/latest/api_reference.html
|
||||
|
||||
|
||||
class UserSchema(ModelSchema):
|
||||
class UserSchema(ma.ModelSchema):
|
||||
class Meta:
|
||||
model = models.User
|
||||
exclude = ("updated_at", "created_at", "user_to_service")
|
||||
|
||||
def make_object(self, data):
|
||||
# TODO possibly override to handle instance creation
|
||||
return super(UserSchema, self).make_object(data)
|
||||
|
||||
# def dump(self, obj, many=None, update_fields=True, **kwargs):
|
||||
# retval = super(UserSchema, self).dump(
|
||||
# obj, many=many, update_fields=update_fields, **kwargs)
|
||||
# if not many and 'email_address' not in retval.data:
|
||||
# retval.data['email_address'] = obj.email_address
|
||||
# return retval
|
||||
|
||||
|
||||
# TODO process users list, to return a list of user.id
|
||||
# Should that list be restricted??
|
||||
class ServiceSchema(ModelSchema):
|
||||
# Should that list be restricted by the auth parsed??
|
||||
class ServiceSchema(ma.ModelSchema):
|
||||
class Meta:
|
||||
model = models.Service
|
||||
exclude = ("updated_at", "created_at")
|
||||
|
||||
def make_object(self, data):
|
||||
# TODO possibly override to handle instance creation
|
||||
return super(ServiceSchema, self).make_object(data)
|
||||
|
||||
|
||||
user_schema = ServiceSchema()
|
||||
user_schema = UserSchema()
|
||||
users_schema = UserSchema(many=True)
|
||||
service_schema = ServiceSchema()
|
||||
services_schema = ServiceSchema(many=True)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
from flask import jsonify
|
||||
from flask import (jsonify, request)
|
||||
from sqlalchemy.exc import DataError
|
||||
from sqlalchemy.orm.exc import NoResultFound
|
||||
from app.dao.services_dao import (create_service, get_services)
|
||||
from app.dao.users_dao import (get_users)
|
||||
from app.dao.services_dao import (create_model_service, get_model_services)
|
||||
from app.dao.users_dao import get_model_users
|
||||
from .. import service
|
||||
from app.schemas import (services_schema, service_schema)
|
||||
|
||||
@@ -10,16 +10,19 @@ from app.schemas import (services_schema, service_schema)
|
||||
# TODO auth to be added.
|
||||
@service.route('/', methods=['POST'])
|
||||
def create_service():
|
||||
# Be lenient with args passed in
|
||||
parsed_data = service_schema(request.args)
|
||||
return jsonify(result="created"), 201
|
||||
# TODO what exceptions get passed from schema parsing?
|
||||
service = service_schema.load(request.get_json()).data
|
||||
print(service_schema.dump(service).data)
|
||||
# Some magic here, it automatically creates the service object.
|
||||
# Cool but need to understand how this works.
|
||||
return jsonify(data=service_schema.dump(service).data), 201
|
||||
|
||||
|
||||
# TODO auth to be added
|
||||
@service.route('/<int:service_id>', methods=['PUT'])
|
||||
def update_service(service_id):
|
||||
service = get_services(service_id=service_id)
|
||||
return jsonify(data=service_schema.dump(service))
|
||||
return jsonify(data=service_schema.dump(service).data)
|
||||
|
||||
|
||||
# TODO auth to be added.
|
||||
@@ -27,7 +30,7 @@ def update_service(service_id):
|
||||
@service.route('/', methods=['GET'])
|
||||
def get_service(service_id=None):
|
||||
try:
|
||||
services = get_services(service_id=service_id)
|
||||
services = get_model_services(service_id=service_id)
|
||||
except DataError:
|
||||
return jsonify(result="error", message="Invalid service id"), 400
|
||||
except NoResultFound:
|
||||
|
||||
@@ -1,27 +1,58 @@
|
||||
from flask import jsonify
|
||||
from flask import (jsonify, request)
|
||||
from sqlalchemy.exc import DataError
|
||||
from sqlalchemy.orm.exc import NoResultFound
|
||||
from app.dao.services_dao import get_services
|
||||
from app.dao.users_dao import get_users
|
||||
from app.dao.services_dao import get_model_services
|
||||
from app.dao.users_dao import (get_model_users, create_model_user)
|
||||
from app.schemas import (
|
||||
user_schema, users_schema, service_schema, services_schema)
|
||||
from .. import user
|
||||
|
||||
|
||||
# TODO auth to be added
|
||||
@user.route('/', methods=['POST'])
|
||||
def create_user():
|
||||
user = user_schema.load(request.get_json()).data
|
||||
create_model_user(user)
|
||||
return jsonify(data=user_schema.dump(user).data), 201
|
||||
|
||||
|
||||
# TODO auth to be added
|
||||
@user.route('/<int:user_id>', methods=['PUT'])
|
||||
def update_user(user_id):
|
||||
user = get_model_users(user_id=user_id)
|
||||
return jsonify(data=user_schema.dump(user).data)
|
||||
|
||||
|
||||
# TODO auth to be added.
|
||||
@user.route('/<int:user_id>', methods=['GET'])
|
||||
@user.route('/', methods=['GET'])
|
||||
def get_user(user_id=None):
|
||||
try:
|
||||
users = get_model_users(user_id=user_id)
|
||||
except DataError:
|
||||
return jsonify(result="error", message="Invalid user id"), 400
|
||||
except NoResultFound:
|
||||
return jsonify(result="error", message="User doesn't exist"), 404
|
||||
result = users_schema.dump(users) if isinstance(users, list) else user_schema.dump(users)
|
||||
return jsonify(data=result.data)
|
||||
|
||||
|
||||
# TODO auth to be added
|
||||
@user.route('/<int:user_id>/service', methods=['GET'])
|
||||
@user.route('/<int:user_id>/service/<int:service_id>', methods=['GET'])
|
||||
def get_service_by_user_id(user_id, service_id=None):
|
||||
try:
|
||||
user = get_users(user_id=user_id)
|
||||
user = get_model_users(user_id=user_id)
|
||||
except DataError:
|
||||
return jsonify(result="error", message="Invalid user id"), 400
|
||||
except NoResultFound:
|
||||
return jsonify(result="error", message="User doesn't exist"), 400
|
||||
|
||||
try:
|
||||
services = get_services(user_id=user.id, service_id=service_id)
|
||||
services = get_model_services(user_id=user.id, service_id=service_id)
|
||||
except DataError:
|
||||
return jsonify(result="error", message="Invalid service id"), 400
|
||||
except NoResultFound:
|
||||
return jsonify(result="error", message="Service doesn't exist"), 404
|
||||
|
||||
return jsonify(data=services)
|
||||
result = services_schema.dump(services) if isinstance(services, list) else service_schema.dump(services)
|
||||
return jsonify(data=result.data)
|
||||
|
||||
Reference in New Issue
Block a user