Publish first version

This commit is contained in:
Finn Christiansen 2021-01-24 13:58:29 +01:00
parent e167769041
commit bac59704db
18 changed files with 564 additions and 1 deletions

34
app/__init__.py Normal file
View file

@ -0,0 +1,34 @@
from flask import Flask
from flask_smorest import Api
from flask_marshmallow import Marshmallow
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
#from flask_jwt_extended import JWTManager
api = Api()
db = SQLAlchemy()
ma = Marshmallow()
#jwt = JWTManager()
def create_app(cfg='default'):
from config import config
app = Flask(__name__)
app.config.from_object(config[cfg])
app.url_map.strict_slashes = False
config[cfg].init_app(app)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
from . import resources
api.init_app(app)
db.init_app(app)
ma.init_app(app)
#jwt.init_app(app)
Migrate(app, db)
resources.register_blueprints(api)
return app

12
app/models/impulse.py Normal file
View file

@ -0,0 +1,12 @@
from .. import db
from datetime import datetime
class Impulse(db.Model):
id = db.Column(db.Integer, primary_key=True)
power = db.Column(db.Integer, nullable=False)
created_at = db.Column(db.DateTime, default=datetime.now, nullable=False)
def __repr__(self):
return 'Impulse {} with power of {} watts at {}'.format(self.name, self.power, self.created_at)

14
app/resources/__init__.py Normal file
View file

@ -0,0 +1,14 @@
def register_blueprints(api):
from . import impulses, consumption
resources = (impulses, consumption, )
for resource_blp in (res.bp for res in resources):
# Here we can register common handlers to all resources
#
# resource_blp.before_request(before_request_handler)
# resource_blp.after_request(after_request_handler)
api.register_blueprint(resource_blp,
url_prefix=f'/{resource_blp.url_prefix}')

View file

@ -0,0 +1,24 @@
from .. import db
import datetime
from flask.views import MethodView
from flask_smorest import Blueprint
from ..schemas.consumption import ConsumptionSchema, ConsumptionQuerySchema
from ..models.impulse import Impulse
from sqlalchemy.sql import func
bp = Blueprint('consumption', 'consumptions', url_prefix='consumption',
description='Operations on consumptions')
@bp.route('/')
class Consumptions(MethodView):
@bp.arguments(ConsumptionQuerySchema, location="query")
@bp.response(ConsumptionSchema(many=False))
def get(self, args):
if "timeperiod" in args:
timeperiod = int(args['timeperiod'])
filterdate = datetime.datetime.now() - datetime.timedelta(seconds=timeperiod)
consumption = db.session.query(func.sum(Impulse.power)).filter(Impulse.created_at >= filterdate).first()[0]
else:
consumption = db.session.query(func.sum(Impulse.power)).first()[0]
return {'consumption': consumption}

35
app/resources/impulses.py Normal file
View file

@ -0,0 +1,35 @@
from .. import db
from flask.views import MethodView
from flask_smorest import Blueprint
from ..schemas.impulse import ImpulseSchema, ImpulseQuerySchema
from ..models.impulse import Impulse
bp = Blueprint('impulse', 'impulses', url_prefix='impulses',
description='Operations on impulses')
@bp.route('/')
class Impulses(MethodView):
@bp.arguments(ImpulseQuerySchema, location="query")
@bp.response(ImpulseSchema(many=True))
def get(self, args):
impulses = Impulse.query.all()
return impulses
@bp.arguments(ImpulseSchema)
@bp.response(ImpulseSchema, code=201)
def post(self, new_impulse):
db.session.add(new_impulse)
db.session.commit()
return new_impulse
@bp.route('/<impulse_id>')
class ImpulseById(MethodView):
@bp.response(code=204)
def delete(self, impulse_id):
impulse = Impulse.query.filter_by(id=impulse_id).first()
db.session.delete(impulse)
db.session.commit()

View file

@ -0,0 +1,13 @@
from .. import ma
from marshmallow import fields
class ConsumptionQuerySchema(ma.Schema):
class Meta:
strict = True
timeperiod = fields.String()
class ConsumptionSchema(ma.Schema):
consumption = fields.Number()

20
app/schemas/impulse.py Normal file
View file

@ -0,0 +1,20 @@
from .. import ma
from ..models.impulse import Impulse
from marshmallow import fields
from .namespacedSchema import NamespacedSchema
class ImpulseQuerySchema(ma.Schema):
class Meta:
strict = True
timeperiod = fields.String()
class ImpulseSchema(NamespacedSchema):
class Meta:
strict = True
model = Impulse
name = "impulse"
plural_name = "impulses"

View file

@ -0,0 +1,45 @@
from marshmallow import SchemaOpts
from marshmallow import pre_load, post_dump
from marshmallow_sqlalchemy import ModelSchemaOpts, ModelConverter, ModelSchema
from .. import ma
from .. import db
class NamespaceOpts(ModelSchemaOpts):
"""Same as the default class Meta options, but adds "name" and
"plural_name" options for enveloping.
"""
def __init__(self, meta, **kwargs):
SchemaOpts.__init__(self, meta, **kwargs)
self.name = getattr(meta, "name", None)
self.plural_name = getattr(meta, "plural_name", self.name)
self.model = getattr(meta, "model", None)
self.model_converter = getattr(meta, "model_converter", ModelConverter)
self.include_fk = getattr(meta, "include_fk", False)
self.transient = getattr(meta, "transient", False)
self.sqla_session = db.session
self.load_instance = True
self.include_relationships = True
#class NamespacedSchema(ma.SQLAlchemySchema):
class NamespacedSchema(ModelSchema):
OPTIONS_CLASS = NamespaceOpts
@pre_load(pass_many=True)
def unwrap_envelope(self, data, many, **kwargs):
key = self.opts.plural_name if many else self.opts.name
if key in data:
return data[key]
else:
return data
@post_dump(pass_many=True)
def wrap_with_envelope(self, data, many, **kwargs):
if 'noenvelope' in self.context and self.context['noenvelope']:
return data
else:
key = self.opts.plural_name if many else self.opts.name
return {key: data}