Rework API code
Factor flat post-processing in API and fix for #83. Always return JSON even if an exception occurred.
This commit is contained in:
parent
aa0e1fd965
commit
9424f81959
@ -143,6 +143,8 @@ class Flat(BASE):
|
||||
flat_dict["date"] = arrow.get(flat_dict["date"]).naive
|
||||
|
||||
flat_object = Flat()
|
||||
# Using a __dict__.update() call to make it work even if there are
|
||||
# extra keys in flat_dict which are not valid kwargs for Flat model.
|
||||
flat_object.__dict__.update(flat_dict)
|
||||
return flat_object
|
||||
|
||||
|
@ -17,7 +17,42 @@ import flatisfy.data
|
||||
from flatisfy.models import flat as flat_model
|
||||
from flatisfy.models.postal_code import PostalCode
|
||||
|
||||
# TODO: Flat post-processing code should be factorized
|
||||
|
||||
def _serialize_flat(flat, config):
|
||||
"""
|
||||
Serialize a flat for JSON API.
|
||||
|
||||
Converts it to a JSON-representable dict and add postal code metadata.
|
||||
|
||||
:param flat: An SQLAlchemy Flat object.
|
||||
:param config: A config dict.
|
||||
:returns: A flat dict ready to be serialized.
|
||||
"""
|
||||
flat = flat.json_api_repr()
|
||||
|
||||
postal_codes = {}
|
||||
for constraint_name, constraint in config["constraints"].items():
|
||||
postal_codes[constraint_name] = flatisfy.data.load_data(
|
||||
PostalCode, constraint, config
|
||||
)
|
||||
|
||||
try:
|
||||
assert flat["flatisfy_postal_code"]
|
||||
|
||||
postal_code_data = next(
|
||||
x
|
||||
for x in postal_codes.get(flat["flatisfy_constraint"], [])
|
||||
if x.postal_code == flat["flatisfy_postal_code"]
|
||||
)
|
||||
flat["flatisfy_postal_code"] = {
|
||||
"postal_code": flat["flatisfy_postal_code"],
|
||||
"name": postal_code_data.name,
|
||||
"gps": (postal_code_data.lat, postal_code_data.lng)
|
||||
}
|
||||
except (AssertionError, StopIteration):
|
||||
flat["flatisfy_postal_code"] = {}
|
||||
|
||||
return flat
|
||||
|
||||
|
||||
def index_v1():
|
||||
@ -42,40 +77,22 @@ def flats_v1(config, db):
|
||||
|
||||
:return: The available flats objects in a JSON ``data`` dict.
|
||||
"""
|
||||
postal_codes = {}
|
||||
for constraint_name, constraint in config["constraints"].items():
|
||||
postal_codes[constraint_name] = flatisfy.data.load_data(
|
||||
PostalCode, constraint, config
|
||||
)
|
||||
|
||||
try:
|
||||
flats = [
|
||||
flat.json_api_repr()
|
||||
_serialize_flat(flat, config)
|
||||
for flat in db.query(flat_model.Flat).all()
|
||||
]
|
||||
|
||||
for flat in flats:
|
||||
try:
|
||||
assert flat["flatisfy_postal_code"]
|
||||
|
||||
postal_code_data = next(
|
||||
x
|
||||
for x in postal_codes.get(flat["flatisfy_constraint"], [])
|
||||
if x.postal_code == flat["flatisfy_postal_code"]
|
||||
)
|
||||
flat["flatisfy_postal_code"] = {
|
||||
"postal_code": flat["flatisfy_postal_code"],
|
||||
"name": postal_code_data.name,
|
||||
"gps": (postal_code_data.lat, postal_code_data.lng)
|
||||
}
|
||||
except (AssertionError, StopIteration):
|
||||
flat["flatisfy_postal_code"] = {}
|
||||
|
||||
return {
|
||||
"data": flats
|
||||
}
|
||||
except Exception as e:
|
||||
return {
|
||||
"error": str(e)
|
||||
}
|
||||
|
||||
|
||||
def flats_by_status_v1(status, db):
|
||||
def flats_by_status_v1(status, config, db):
|
||||
"""
|
||||
API v1 flats route with a specific status:
|
||||
|
||||
@ -85,19 +102,23 @@ def flats_by_status_v1(status, db):
|
||||
"""
|
||||
try:
|
||||
flats = [
|
||||
flat.json_api_repr()
|
||||
_serialize_flat(flat, config)
|
||||
for flat in (
|
||||
db.query(flat_model.Flat)
|
||||
.filter_by(status=getattr(flat_model.FlatStatus, status))
|
||||
.all()
|
||||
)
|
||||
]
|
||||
except AttributeError:
|
||||
return bottle.HTTPError(400, "Invalid status provided.")
|
||||
|
||||
return {
|
||||
"data": flats
|
||||
}
|
||||
except AttributeError:
|
||||
return bottle.HTTPError(400, "Invalid status provided.")
|
||||
except Exception as e:
|
||||
return {
|
||||
"error": str(e)
|
||||
}
|
||||
|
||||
|
||||
def flat_v1(flat_id, config, db):
|
||||
@ -108,40 +129,22 @@ def flat_v1(flat_id, config, db):
|
||||
|
||||
:return: The flat object in a JSON ``data`` dict.
|
||||
"""
|
||||
try:
|
||||
flat = db.query(flat_model.Flat).filter_by(id=flat_id).first()
|
||||
|
||||
if not flat:
|
||||
return bottle.HTTPError(404, "No flat with id {}.".format(flat_id))
|
||||
|
||||
flat = flat.json_api_repr()
|
||||
|
||||
try:
|
||||
assert flat["flatisfy_postal_code"]
|
||||
|
||||
constraint = config["constraints"].get(flat["flatisfy_constraint"],
|
||||
None)
|
||||
assert constraint is not None
|
||||
postal_codes = flatisfy.data.load_data(PostalCode, constraint, config)
|
||||
|
||||
postal_code_data = next(
|
||||
x
|
||||
for x in postal_codes
|
||||
if x.postal_code == flat["flatisfy_postal_code"]
|
||||
)
|
||||
flat["flatisfy_postal_code"] = {
|
||||
"postal_code": flat["flatisfy_postal_code"],
|
||||
"name": postal_code_data.name,
|
||||
"gps": (postal_code_data.lat, postal_code_data.lng)
|
||||
}
|
||||
except (AssertionError, StopIteration):
|
||||
flat["flatisfy_postal_code"] = {}
|
||||
|
||||
return {
|
||||
"data": flat
|
||||
"data": _serialize_flat(flat, config)
|
||||
}
|
||||
except Exception as e:
|
||||
return {
|
||||
"error": str(e)
|
||||
}
|
||||
|
||||
|
||||
def update_flat_status_v1(flat_id, db):
|
||||
def update_flat_status_v1(flat_id, config, db):
|
||||
"""
|
||||
API v1 route to update flat status:
|
||||
|
||||
@ -152,6 +155,7 @@ def update_flat_status_v1(flat_id, db):
|
||||
|
||||
:return: The new flat object in a JSON ``data`` dict.
|
||||
"""
|
||||
try:
|
||||
flat = db.query(flat_model.Flat).filter_by(id=flat_id).first()
|
||||
if not flat:
|
||||
return bottle.HTTPError(404, "No flat with id {}.".format(flat_id))
|
||||
@ -163,14 +167,16 @@ def update_flat_status_v1(flat_id, db):
|
||||
except (AttributeError, ValueError, KeyError):
|
||||
return bottle.HTTPError(400, "Invalid status provided.")
|
||||
|
||||
json_flat = flat.json_api_repr()
|
||||
|
||||
return {
|
||||
"data": json_flat
|
||||
"data": _serialize_flat(flat, config)
|
||||
}
|
||||
except Exception as e:
|
||||
return {
|
||||
"error": str(e)
|
||||
}
|
||||
|
||||
|
||||
def update_flat_notes_v1(flat_id, db):
|
||||
def update_flat_notes_v1(flat_id, config, db):
|
||||
"""
|
||||
API v1 route to update flat notes:
|
||||
|
||||
@ -181,6 +187,7 @@ def update_flat_notes_v1(flat_id, db):
|
||||
|
||||
:return: The new flat object in a JSON ``data`` dict.
|
||||
"""
|
||||
try:
|
||||
flat = db.query(flat_model.Flat).filter_by(id=flat_id).first()
|
||||
if not flat:
|
||||
return bottle.HTTPError(404, "No flat with id {}.".format(flat_id))
|
||||
@ -190,14 +197,16 @@ def update_flat_notes_v1(flat_id, db):
|
||||
except (ValueError, KeyError):
|
||||
return bottle.HTTPError(400, "Invalid notes provided.")
|
||||
|
||||
json_flat = flat.json_api_repr()
|
||||
|
||||
return {
|
||||
"data": json_flat
|
||||
"data": _serialize_flat(flat, config)
|
||||
}
|
||||
except Exception as e:
|
||||
return {
|
||||
"error": str(e)
|
||||
}
|
||||
|
||||
|
||||
def update_flat_notation_v1(flat_id, db):
|
||||
def update_flat_notation_v1(flat_id, config, db):
|
||||
"""
|
||||
API v1 route to update flat notation:
|
||||
|
||||
@ -208,6 +217,7 @@ def update_flat_notation_v1(flat_id, db):
|
||||
|
||||
:return: The new flat object in a JSON ``data`` dict.
|
||||
"""
|
||||
try:
|
||||
flat = db.query(flat_model.Flat).filter_by(id=flat_id).first()
|
||||
if not flat:
|
||||
return bottle.HTTPError(404, "No flat with id {}.".format(flat_id))
|
||||
@ -218,14 +228,16 @@ def update_flat_notation_v1(flat_id, db):
|
||||
except (AssertionError, ValueError, KeyError):
|
||||
return bottle.HTTPError(400, "Invalid notation provided.")
|
||||
|
||||
json_flat = flat.json_api_repr()
|
||||
|
||||
return {
|
||||
"data": json_flat
|
||||
"data": _serialize_flat(flat, config)
|
||||
}
|
||||
except Exception as e:
|
||||
return {
|
||||
"error": str(e)
|
||||
}
|
||||
|
||||
|
||||
def update_flat_visit_date_v1(flat_id, db):
|
||||
def update_flat_visit_date_v1(flat_id, config, db):
|
||||
"""
|
||||
API v1 route to update flat date of visit:
|
||||
|
||||
@ -236,6 +248,7 @@ def update_flat_visit_date_v1(flat_id, db):
|
||||
|
||||
:return: The new flat object in a JSON ``data`` dict.
|
||||
"""
|
||||
try:
|
||||
flat = db.query(flat_model.Flat).filter_by(id=flat_id).first()
|
||||
if not flat:
|
||||
return bottle.HTTPError(404, "No flat with id {}.".format(flat_id))
|
||||
@ -248,10 +261,12 @@ def update_flat_visit_date_v1(flat_id, db):
|
||||
except (arrow.parser.ParserError, ValueError, KeyError):
|
||||
return bottle.HTTPError(400, "Invalid visit date provided.")
|
||||
|
||||
json_flat = flat.json_api_repr()
|
||||
|
||||
return {
|
||||
"data": json_flat
|
||||
"data": _serialize_flat(flat, config)
|
||||
}
|
||||
except Exception as e:
|
||||
return {
|
||||
"error": str(e)
|
||||
}
|
||||
|
||||
|
||||
@ -264,6 +279,7 @@ def time_to_places_v1(config):
|
||||
:return: The JSON dump of the places to compute time to (dict of places
|
||||
names mapped to GPS coordinates).
|
||||
"""
|
||||
try:
|
||||
places = {}
|
||||
for constraint_name, constraint in config["constraints"].items():
|
||||
places[constraint_name] = {
|
||||
@ -273,6 +289,10 @@ def time_to_places_v1(config):
|
||||
return {
|
||||
"data": places
|
||||
}
|
||||
except Exception as e:
|
||||
return {
|
||||
"error": str(e)
|
||||
}
|
||||
|
||||
|
||||
def search_v1(db, config):
|
||||
@ -286,12 +306,7 @@ def search_v1(db, config):
|
||||
|
||||
:return: The matching flat objects in a JSON ``data`` dict.
|
||||
"""
|
||||
postal_codes = {}
|
||||
for constraint_name, constraint in config["constraints"].items():
|
||||
postal_codes[constraint_name] = flatisfy.data.load_data(
|
||||
PostalCode, constraint, config
|
||||
)
|
||||
|
||||
try:
|
||||
try:
|
||||
query = json.load(bottle.request.body)["query"]
|
||||
except (ValueError, KeyError):
|
||||
@ -299,30 +314,17 @@ def search_v1(db, config):
|
||||
|
||||
flats_db_query = flat_model.Flat.search_query(db, query)
|
||||
flats = [
|
||||
flat.json_api_repr()
|
||||
_serialize_flat(flat, config)
|
||||
for flat in flats_db_query
|
||||
]
|
||||
|
||||
for flat in flats:
|
||||
try:
|
||||
assert flat["flatisfy_postal_code"]
|
||||
|
||||
postal_code_data = next(
|
||||
x
|
||||
for x in postal_codes.get(flat["flatisfy_constraint"], [])
|
||||
if x.postal_code == flat["flatisfy_postal_code"]
|
||||
)
|
||||
flat["flatisfy_postal_code"] = {
|
||||
"postal_code": flat["flatisfy_postal_code"],
|
||||
"name": postal_code_data.name,
|
||||
"gps": (postal_code_data.lat, postal_code_data.lng)
|
||||
}
|
||||
except (AssertionError, StopIteration):
|
||||
flat["flatisfy_postal_code"] = {}
|
||||
|
||||
return {
|
||||
"data": flats
|
||||
}
|
||||
except Exception as e:
|
||||
return {
|
||||
"error": str(e)
|
||||
}
|
||||
|
||||
|
||||
def ics_feed_v1(config, db):
|
||||
@ -333,6 +335,7 @@ def ics_feed_v1(config, db):
|
||||
|
||||
:return: The ICS feed for the visits.
|
||||
"""
|
||||
try:
|
||||
flats_with_visits = db.query(flat_model.Flat).filter(
|
||||
flat_model.Flat.visit_date.isnot(None)
|
||||
).all()
|
||||
@ -359,3 +362,5 @@ def ics_feed_v1(config, db):
|
||||
vevent.add('description').value = description
|
||||
|
||||
return cal.serialize()
|
||||
except:
|
||||
return ''
|
||||
|
Loading…
Reference in New Issue
Block a user