# coding: utf-8 """ This module contains the definition of the web app API routes. """ from __future__ import ( absolute_import, division, print_function, unicode_literals ) import json import bottle import flatisfy.data from flatisfy.models import flat as flat_model # TODO: Flat post-processing code should be factorized def index_v1(): """ API v1 index route: GET /api/v1/ """ return { "flats": "/api/v1/flats", "flat": "/api/v1/flat/:id", "search": "/api/v1/search", "time_to_places": "/api/v1/time_to/places" } def flats_v1(config, db): """ API v1 flats route: GET /api/v1/flats :return: The available flats objects in a JSON ``data`` dict. """ postal_codes = flatisfy.data.load_data("postal_codes", config) flats = [ flat.json_api_repr() for flat in db.query(flat_model.Flat).all() ] for flat in flats: if flat["flatisfy_postal_code"]: postal_code_data = postal_codes[flat["flatisfy_postal_code"]] flat["flatisfy_postal_code"] = { "postal_code": flat["flatisfy_postal_code"], "name": postal_code_data["nom"], "gps": postal_code_data["gps"] } else: flat["flatisfy_postal_code"] = {} return { "data": flats } def flats_by_status_v1(status, db): """ API v1 flats route with a specific status: GET /api/v1/flats/status/:status :return: The matching flats objects in a JSON ``data`` dict. """ try: flats = [ flat.json_api_repr() 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 } def flat_v1(flat_id, config, db): """ API v1 flat route: GET /api/v1/flat/:flat_id :return: The flat object in a JSON ``data`` dict. """ postal_codes = flatisfy.data.load_data("postal_codes", config) 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() if flat["flatisfy_postal_code"]: postal_code_data = postal_codes[flat["flatisfy_postal_code"]] flat["flatisfy_postal_code"] = { "postal_code": flat["flatisfy_postal_code"], "name": postal_code_data["nom"], "gps": postal_code_data["gps"] } else: flat["flatisfy_postal_code"] = {} return { "data": flat } def update_flat_status_v1(flat_id, db): """ API v1 route to update flat status: POST /api/v1/flat/:flat_id/status Data: { "status": "NEW_STATUS" } :return: The new flat object in a JSON ``data`` dict. """ 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)) try: flat.status = getattr( flat_model.FlatStatus, json.load(bottle.request.body)["status"] ) except (AttributeError, ValueError, KeyError): return bottle.HTTPError(400, "Invalid status provided.") json_flat = flat.json_api_repr() return { "data": json_flat } def update_flat_notes_v1(flat_id, db): """ API v1 route to update flat notes: POST /api/v1/flat/:flat_id/notes Data: { "notes": "NEW_NOTES" } :return: The new flat object in a JSON ``data`` dict. """ 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)) try: flat.notes = json.load(bottle.request.body)["notes"] except (ValueError, KeyError): return bottle.HTTPError(400, "Invalid notes provided.") json_flat = flat.json_api_repr() return { "data": json_flat } def update_flat_notation_v1(flat_id, db): """ API v1 route to update flat notation: POST /api/v1/flat/:flat_id/notation Data: { "notation": "NEW_NOTATION" } :return: The new flat object in a JSON ``data`` dict. """ 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)) try: flat.notation = json.load(bottle.request.body)["notation"] assert flat.notation >= 0 and flat.notation <= 5 except (AssertionError, ValueError, KeyError): return bottle.HTTPError(400, "Invalid notation provided.") json_flat = flat.json_api_repr() return { "data": json_flat } def time_to_places_v1(config): """ API v1 route to fetch the details of the places to compute time to. GET /api/v1/time_to/places :return: The JSON dump of the places to compute time to (dict of places names mapped to GPS coordinates). """ places = { k: v["gps"] for k, v in config["constraints"]["time_to"].items() } return { "data": places } def search_v1(db, config): """ API v1 route to perform a fulltext search on flats. POST /api/v1/search Data: { "query": "SOME_QUERY" } :return: The matching flat objects in a JSON ``data`` dict. """ postal_codes = flatisfy.data.load_data("postal_codes", config) try: query = json.load(bottle.request.body)["query"] except (ValueError, KeyError): return bottle.HTTPError(400, "Invalid query provided.") flats_db_query = flat_model.Flat.search_query(db, query) flats = [ flat.json_api_repr() for flat in flats_db_query ] for flat in flats: if flat["flatisfy_postal_code"]: postal_code_data = postal_codes[flat["flatisfy_postal_code"]] flat["flatisfy_postal_code"] = { "postal_code": flat["flatisfy_postal_code"], "name": postal_code_data["nom"], "gps": postal_code_data["gps"] } else: flat["flatisfy_postal_code"] = {} return { "data": flats }