From 1c47aad05e988150c5c74d0e19d10c165e652f8d Mon Sep 17 00:00:00 2001 From: Benjamin Bertrand <benjamin.bertrand@esss.se> Date: Thu, 20 Jul 2017 10:46:06 +0200 Subject: [PATCH] Add method to create an item via the API --- app/api/items.py | 40 +++++++++++++++++++++++++++++----------- app/models.py | 22 ++++++++++++++++++---- app/utils.py | 18 ++++++++++++++++++ 3 files changed, 65 insertions(+), 15 deletions(-) diff --git a/app/api/items.py b/app/api/items.py index 7caa5cf..1eb8471 100644 --- a/app/api/items.py +++ b/app/api/items.py @@ -9,11 +9,13 @@ This module implements the items API. :license: BSD 2-Clause, see LICENSE for more details. """ +import sqlalchemy as sa from flask import (current_app, Blueprint, jsonify, request) from flask_jwt_extended import create_access_token, jwt_required from flask_ldap3_login import AuthenticationResponseStatus from ..extensions import ldap_manager, db -from ..models import User +from ..models import User, Item +from .. import utils bp = Blueprint('api', __name__) @@ -42,13 +44,29 @@ def login(): @bp.route('/items') @jwt_required def get_items(): - sql = """SELECT item.id, item.name, manufacturer.name, model.name, location.name, status.name - FROM item - INNER JOIN manufacturer ON manufacturer.id = item.manufacturer_id - INNER JOIN model ON model.id = item.model_id - INNER JOIN location ON location.id = item.location_id - INNER JOIN status ON status.id = item.status_id - """ - result = db.engine.execute(sql) - data = [[item for item in row] for row in result] - return jsonify(data=data) + # TODO: add pagination + items = Item.query.order_by(Item._created) + data = [item.to_dict() for item in items] + return jsonify({'items': data}) + + +@bp.route('/items', methods=['POST']) +@jwt_required +def create_item(): + data = request.get_json() + if data is None: + raise utils.InventoryError('Body should be a JSON object') + if 'serial_number' not in data: + raise utils.InventoryError('serial_number is mandatory') + try: + item = Item(**data) + except TypeError as e: + message = str(e).replace('__init__() got an ', '') + raise utils.InventoryError(message) + db.session.add(item) + try: + db.session.commit() + except sa.exc.IntegrityError as e: + db.session.rollback() + raise utils.InventoryError('IntegrityError', status_code=409) + return jsonify(item.to_dict()), 201 diff --git a/app/models.py b/app/models.py index 02f3173..055de44 100644 --- a/app/models.py +++ b/app/models.py @@ -184,11 +184,25 @@ class Item(db.Model): # All arguments must be optional for this class to work with flask-admin! self.serial_number = serial_number self.name = name - self.manufacturer = manufacturer - self.model = model - self.location = location - self.status = status + self.manufacturer = utils.convert_to_model(manufacturer, Manufacturer) + self.model = utils.convert_to_model(model, Model) + self.location = utils.convert_to_model(location, Location) + self.status = utils.convert_to_model(status, Status) self.hash = utils.compute_hash(serial_number) def __str__(self): return self.serial_number + + def to_dict(self): + return { + 'id': self.id, + 'serial_number': self.serial_number, + 'name': self.name, + 'hash': self.hash, + 'manufacturer': utils.format_field(self.manufacturer), + 'model': utils.format_field(self.model), + 'location': utils.format_field(self.location), + 'status': utils.format_field(self.status), + 'updated': utils.format_field(self._updated), + 'created': utils.format_field(self._created), + } diff --git a/app/utils.py b/app/utils.py index dddef7b..f67893d 100644 --- a/app/utils.py +++ b/app/utils.py @@ -65,3 +65,21 @@ def format_field(field): if isinstance(field, datetime.datetime): return field.strftime('%Y-%m-%d %H:%M') return str(field) + + +def convert_to_model(item, model): + """Convert item to an instance of model + + Allow to convert a string to an instance of model + Raise an exception if the given name is not found + + :returns: an instance of model + """ + if item is None: + return None + if not isinstance(item, model): + instance = model.query.filter_by(name=item).first() + if instance is None: + raise InventoryError(f'{item} is not a valid {model.__name__.lower()}') + return instance + return item -- GitLab