Cleaner API
This commit is contained in:
parent
9424f81959
commit
b285c270aa
@ -13,6 +13,7 @@ import arrow
|
|||||||
from sqlalchemy import (
|
from sqlalchemy import (
|
||||||
Column, DateTime, Enum, Float, SmallInteger, String, Text
|
Column, DateTime, Enum, Float, SmallInteger, String, Text
|
||||||
)
|
)
|
||||||
|
from sqlalchemy.orm import validates
|
||||||
|
|
||||||
from flatisfy.database.base import BASE
|
from flatisfy.database.base import BASE
|
||||||
from flatisfy.database.types import MagicJSON
|
from flatisfy.database.types import MagicJSON
|
||||||
@ -96,6 +97,62 @@ class Flat(BASE):
|
|||||||
# Date for visit
|
# Date for visit
|
||||||
visit_date = Column(DateTime)
|
visit_date = Column(DateTime)
|
||||||
|
|
||||||
|
@validates('utilities')
|
||||||
|
def validate_utilities(self, _, utilities):
|
||||||
|
"""
|
||||||
|
Utilities validation method
|
||||||
|
"""
|
||||||
|
if isinstance(utilities, FlatUtilities):
|
||||||
|
return utilities
|
||||||
|
|
||||||
|
if utilities == "C.C.":
|
||||||
|
return FlatUtilities.included
|
||||||
|
elif utilities == "H.C.":
|
||||||
|
return FlatUtilities.excluded
|
||||||
|
else:
|
||||||
|
return FlatUtilities.unknown
|
||||||
|
|
||||||
|
@validates("status")
|
||||||
|
def validate_status(self, _, status):
|
||||||
|
"""
|
||||||
|
Status validation method
|
||||||
|
"""
|
||||||
|
if isinstance(status, FlatStatus):
|
||||||
|
return status
|
||||||
|
|
||||||
|
try:
|
||||||
|
return getattr(FlatStatus, status)
|
||||||
|
except (AttributeError, TypeError):
|
||||||
|
LOGGER.warn("Unkown flat status %s, ignoring it.",
|
||||||
|
status)
|
||||||
|
return self.status.default.arg
|
||||||
|
|
||||||
|
@validates("notation")
|
||||||
|
def validate_status(self, _, notation):
|
||||||
|
"""
|
||||||
|
Notation validation method
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
notation = int(notation)
|
||||||
|
assert notation >= 0 and notation <= 5
|
||||||
|
except (ValueError, AssertionError):
|
||||||
|
raise ValueError('notation should be an integer between 0 and 5')
|
||||||
|
return notation
|
||||||
|
|
||||||
|
@validates("date")
|
||||||
|
def validate_date(self, _, date):
|
||||||
|
"""
|
||||||
|
Date validation method
|
||||||
|
"""
|
||||||
|
return arrow.get(date).naive
|
||||||
|
|
||||||
|
@validates("visit_date")
|
||||||
|
def validate_visit_date(self, _, visit_date):
|
||||||
|
"""
|
||||||
|
Visit date validation method
|
||||||
|
"""
|
||||||
|
return arrow.get(visit_date).naive
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_dict(flat_dict):
|
def from_dict(flat_dict):
|
||||||
"""
|
"""
|
||||||
@ -119,29 +176,6 @@ class Flat(BASE):
|
|||||||
)
|
)
|
||||||
del flat_dict["flatisfy"]
|
del flat_dict["flatisfy"]
|
||||||
|
|
||||||
# Handle utilities field
|
|
||||||
if not isinstance(flat_dict["utilities"], FlatUtilities):
|
|
||||||
if flat_dict["utilities"] == "C.C.":
|
|
||||||
flat_dict["utilities"] = FlatUtilities.included
|
|
||||||
elif flat_dict["utilities"] == "H.C.":
|
|
||||||
flat_dict["utilities"] = FlatUtilities.excluded
|
|
||||||
else:
|
|
||||||
flat_dict["utilities"] = FlatUtilities.unknown
|
|
||||||
|
|
||||||
# Handle status field
|
|
||||||
flat_status = flat_dict.get("status", "new")
|
|
||||||
if not isinstance(flat_status, FlatStatus):
|
|
||||||
try:
|
|
||||||
flat_dict["status"] = getattr(FlatStatus, flat_status)
|
|
||||||
except AttributeError:
|
|
||||||
if "status" in flat_dict:
|
|
||||||
del flat_dict["status"]
|
|
||||||
LOGGER.warn("Unkown flat status %s, ignoring it.",
|
|
||||||
flat_status)
|
|
||||||
|
|
||||||
# Handle date field
|
|
||||||
flat_dict["date"] = arrow.get(flat_dict["date"]).naive
|
|
||||||
|
|
||||||
flat_object = Flat()
|
flat_object = Flat()
|
||||||
# Using a __dict__.update() call to make it work even if there are
|
# 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.
|
# extra keys in flat_dict which are not valid kwargs for Flat model.
|
||||||
@ -151,7 +185,6 @@ class Flat(BASE):
|
|||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<Flat(id=%s, urls=%s)>" % (self.id, self.urls)
|
return "<Flat(id=%s, urls=%s)>" % (self.id, self.urls)
|
||||||
|
|
||||||
|
|
||||||
def json_api_repr(self):
|
def json_api_repr(self):
|
||||||
"""
|
"""
|
||||||
Return a dict representation of this flat object that is JSON
|
Return a dict representation of this flat object that is JSON
|
||||||
|
@ -73,20 +73,11 @@ def get_app(config):
|
|||||||
api_routes.time_to_places_v1)
|
api_routes.time_to_places_v1)
|
||||||
|
|
||||||
app.route("/api/v1/flats", "GET", api_routes.flats_v1)
|
app.route("/api/v1/flats", "GET", api_routes.flats_v1)
|
||||||
app.route("/api/v1/flats/status/:status", "GET",
|
app.route("/api/v1/flats/:flat_id", "GET", api_routes.flat_v1)
|
||||||
api_routes.flats_by_status_v1)
|
app.route("/api/v1/flats/:flat_id", "PATCH",
|
||||||
|
api_routes.update_flat_v1)
|
||||||
|
|
||||||
app.route("/api/v1/flat/:flat_id", "GET", api_routes.flat_v1)
|
app.route("/api/v1/ics/visits.ics", "GET",
|
||||||
app.route("/api/v1/flat/:flat_id/status", "POST",
|
|
||||||
api_routes.update_flat_status_v1)
|
|
||||||
app.route("/api/v1/flat/:flat_id/notes", "POST",
|
|
||||||
api_routes.update_flat_notes_v1)
|
|
||||||
app.route("/api/v1/flat/:flat_id/notation", "POST",
|
|
||||||
api_routes.update_flat_notation_v1)
|
|
||||||
app.route("/api/v1/flat/:flat_id/visit_date", "POST",
|
|
||||||
api_routes.update_flat_visit_date_v1)
|
|
||||||
|
|
||||||
app.route("/api/v1/visits.ics", "GET",
|
|
||||||
api_routes.ics_feed_v1)
|
api_routes.ics_feed_v1)
|
||||||
|
|
||||||
app.route("/api/v1/search", "POST", api_routes.search_v1)
|
app.route("/api/v1/search", "POST", api_routes.search_v1)
|
||||||
|
@ -46,7 +46,7 @@ export const getFlats = function (callback) {
|
|||||||
|
|
||||||
export const getFlat = function (flatId, callback) {
|
export const getFlat = function (flatId, callback) {
|
||||||
fetch(
|
fetch(
|
||||||
'/api/v1/flat/' + encodeURIComponent(flatId),
|
'/api/v1/flats/' + encodeURIComponent(flatId),
|
||||||
{ credentials: 'same-origin' }
|
{ credentials: 'same-origin' }
|
||||||
)
|
)
|
||||||
.then(function (response) {
|
.then(function (response) {
|
||||||
@ -61,10 +61,10 @@ export const getFlat = function (flatId, callback) {
|
|||||||
|
|
||||||
export const updateFlatStatus = function (flatId, newStatus, callback) {
|
export const updateFlatStatus = function (flatId, newStatus, callback) {
|
||||||
fetch(
|
fetch(
|
||||||
'/api/v1/flat/' + encodeURIComponent(flatId) + '/status',
|
'/api/v1/flats/' + encodeURIComponent(flatId),
|
||||||
{
|
{
|
||||||
credentials: 'same-origin',
|
credentials: 'same-origin',
|
||||||
method: 'POST',
|
method: 'PATCH',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
@ -79,10 +79,10 @@ export const updateFlatStatus = function (flatId, newStatus, callback) {
|
|||||||
|
|
||||||
export const updateFlatNotes = function (flatId, newNotes, callback) {
|
export const updateFlatNotes = function (flatId, newNotes, callback) {
|
||||||
fetch(
|
fetch(
|
||||||
'/api/v1/flat/' + encodeURIComponent(flatId) + '/notes',
|
'/api/v1/flats/' + encodeURIComponent(flatId),
|
||||||
{
|
{
|
||||||
credentials: 'same-origin',
|
credentials: 'same-origin',
|
||||||
method: 'POST',
|
method: 'PATCH',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
@ -97,10 +97,10 @@ export const updateFlatNotes = function (flatId, newNotes, callback) {
|
|||||||
|
|
||||||
export const updateFlatNotation = function (flatId, newNotation, callback) {
|
export const updateFlatNotation = function (flatId, newNotation, callback) {
|
||||||
fetch(
|
fetch(
|
||||||
'/api/v1/flat/' + encodeURIComponent(flatId) + '/notation',
|
'/api/v1/flats/' + encodeURIComponent(flatId),
|
||||||
{
|
{
|
||||||
credentials: 'same-origin',
|
credentials: 'same-origin',
|
||||||
method: 'POST',
|
method: 'PATCH',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
@ -115,10 +115,10 @@ export const updateFlatNotation = function (flatId, newNotation, callback) {
|
|||||||
|
|
||||||
export const updateFlatVisitDate = function (flatId, newVisitDate, callback) {
|
export const updateFlatVisitDate = function (flatId, newVisitDate, callback) {
|
||||||
fetch(
|
fetch(
|
||||||
'/api/v1/flat/' + encodeURIComponent(flatId) + '/visit_date',
|
'/api/v1/flats/' + encodeURIComponent(flatId),
|
||||||
{
|
{
|
||||||
credentials: 'same-origin',
|
credentials: 'same-origin',
|
||||||
method: 'POST',
|
method: 'PATCH',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
|
@ -8,8 +8,8 @@ from __future__ import (
|
|||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
import json
|
import json
|
||||||
|
import re
|
||||||
|
|
||||||
import arrow
|
|
||||||
import bottle
|
import bottle
|
||||||
import vobject
|
import vobject
|
||||||
|
|
||||||
@ -18,6 +18,12 @@ from flatisfy.models import flat as flat_model
|
|||||||
from flatisfy.models.postal_code import PostalCode
|
from flatisfy.models.postal_code import PostalCode
|
||||||
|
|
||||||
|
|
||||||
|
def JSONError(error_code, error_str):
|
||||||
|
bottle.response.status = error_code
|
||||||
|
bottle.response.content_type = "application/json"
|
||||||
|
return json.dumps(dict(error=error_str, status_code=error_code))
|
||||||
|
|
||||||
|
|
||||||
def _serialize_flat(flat, config):
|
def _serialize_flat(flat, config):
|
||||||
"""
|
"""
|
||||||
Serialize a flat for JSON API.
|
Serialize a flat for JSON API.
|
||||||
@ -65,7 +71,8 @@ def index_v1():
|
|||||||
"flats": "/api/v1/flats",
|
"flats": "/api/v1/flats",
|
||||||
"flat": "/api/v1/flat/:id",
|
"flat": "/api/v1/flat/:id",
|
||||||
"search": "/api/v1/search",
|
"search": "/api/v1/search",
|
||||||
"time_to_places": "/api/v1/time_to/places"
|
"ics": "/api/v1/ics/visits.ics",
|
||||||
|
"time_to_places": "/api/v1/time_to_places"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -75,57 +82,43 @@ def flats_v1(config, db):
|
|||||||
|
|
||||||
GET /api/v1/flats
|
GET /api/v1/flats
|
||||||
|
|
||||||
|
.. note:: Filtering can be done through the ``filter`` GET param, according
|
||||||
|
to JSON API spec (http://jsonapi.org/recommendations/#filtering).
|
||||||
|
|
||||||
:return: The available flats objects in a JSON ``data`` dict.
|
:return: The available flats objects in a JSON ``data`` dict.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
|
db_query = db.query(flat_model.Flat)
|
||||||
|
|
||||||
|
# Handle filtering according to JSON API spec
|
||||||
|
FILTER_RE = re.compile(r"filter\[([A-z0-9_]+)\]")
|
||||||
|
filters = {}
|
||||||
|
for param in bottle.request.query:
|
||||||
|
filter_match = FILTER_RE.match(param)
|
||||||
|
if not filter:
|
||||||
|
continue
|
||||||
|
field = filter_match.group(1)
|
||||||
|
value = bottle.request.query[filter_match.group(0)]
|
||||||
|
filters[field] = value
|
||||||
|
db_query = db_query.filter_by(**filters)
|
||||||
|
|
||||||
|
# Build flat list
|
||||||
flats = [
|
flats = [
|
||||||
_serialize_flat(flat, config)
|
_serialize_flat(flat, config)
|
||||||
for flat in db.query(flat_model.Flat).all()
|
for flat in db_query
|
||||||
]
|
]
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"data": flats
|
"data": flats
|
||||||
}
|
}
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
return {
|
return JSONError(500, str(exc))
|
||||||
"error": str(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def flats_by_status_v1(status, config, 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 = [
|
|
||||||
_serialize_flat(flat, config)
|
|
||||||
for flat in (
|
|
||||||
db.query(flat_model.Flat)
|
|
||||||
.filter_by(status=getattr(flat_model.FlatStatus, status))
|
|
||||||
.all()
|
|
||||||
)
|
|
||||||
]
|
|
||||||
|
|
||||||
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):
|
def flat_v1(flat_id, config, db):
|
||||||
"""
|
"""
|
||||||
API v1 flat route:
|
API v1 flat route:
|
||||||
|
|
||||||
GET /api/v1/flat/:flat_id
|
GET /api/v1/flats/:flat_id
|
||||||
|
|
||||||
:return: The flat object in a JSON ``data`` dict.
|
:return: The flat object in a JSON ``data`` dict.
|
||||||
"""
|
"""
|
||||||
@ -133,141 +126,50 @@ def flat_v1(flat_id, config, db):
|
|||||||
flat = db.query(flat_model.Flat).filter_by(id=flat_id).first()
|
flat = db.query(flat_model.Flat).filter_by(id=flat_id).first()
|
||||||
|
|
||||||
if not flat:
|
if not flat:
|
||||||
return bottle.HTTPError(404, "No flat with id {}.".format(flat_id))
|
return JSONError(404, "No flat with id {}.".format(flat_id))
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"data": _serialize_flat(flat, config)
|
"data": _serialize_flat(flat, config)
|
||||||
}
|
}
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
return {
|
return JSONError(500, str(exc))
|
||||||
"error": str(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def update_flat_status_v1(flat_id, config, db):
|
def update_flat_v1(flat_id, config, db):
|
||||||
"""
|
"""
|
||||||
API v1 route to update flat status:
|
API v1 route to update flat status:
|
||||||
|
|
||||||
POST /api/v1/flat/:flat_id/status
|
PATCH /api/v1/flat/:flat_id
|
||||||
Data: {
|
|
||||||
"status": "NEW_STATUS"
|
|
||||||
}
|
|
||||||
|
|
||||||
: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))
|
|
||||||
|
|
||||||
try:
|
|
||||||
flat.status = getattr(
|
|
||||||
flat_model.FlatStatus, json.load(bottle.request.body)["status"]
|
|
||||||
)
|
|
||||||
except (AttributeError, ValueError, KeyError):
|
|
||||||
return bottle.HTTPError(400, "Invalid status provided.")
|
|
||||||
|
|
||||||
return {
|
|
||||||
"data": _serialize_flat(flat, config)
|
|
||||||
}
|
|
||||||
except Exception as e:
|
|
||||||
return {
|
|
||||||
"error": str(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def update_flat_notes_v1(flat_id, config, 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.
|
|
||||||
"""
|
|
||||||
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))
|
|
||||||
|
|
||||||
try:
|
|
||||||
flat.notes = json.load(bottle.request.body)["notes"]
|
|
||||||
except (ValueError, KeyError):
|
|
||||||
return bottle.HTTPError(400, "Invalid notes provided.")
|
|
||||||
|
|
||||||
return {
|
|
||||||
"data": _serialize_flat(flat, config)
|
|
||||||
}
|
|
||||||
except Exception as e:
|
|
||||||
return {
|
|
||||||
"error": str(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def update_flat_notation_v1(flat_id, config, 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.
|
|
||||||
"""
|
|
||||||
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))
|
|
||||||
|
|
||||||
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.")
|
|
||||||
|
|
||||||
return {
|
|
||||||
"data": _serialize_flat(flat, config)
|
|
||||||
}
|
|
||||||
except Exception as e:
|
|
||||||
return {
|
|
||||||
"error": str(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def update_flat_visit_date_v1(flat_id, config, db):
|
|
||||||
"""
|
|
||||||
API v1 route to update flat date of visit:
|
|
||||||
|
|
||||||
POST /api/v1/flat/:flat_id/visit_date
|
|
||||||
Data: {
|
Data: {
|
||||||
|
"status": "NEW_STATUS",
|
||||||
"visit_date": "ISO8601 DATETIME"
|
"visit_date": "ISO8601 DATETIME"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.. note:: The keys in the data sent are same keys as in ``Flat`` model. You
|
||||||
|
can provide any subset of them to update part of the flat infos.
|
||||||
|
|
||||||
:return: The new flat object in a JSON ``data`` dict.
|
:return: The new flat object in a JSON ``data`` dict.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
flat = db.query(flat_model.Flat).filter_by(id=flat_id).first()
|
flat = db.query(flat_model.Flat).filter_by(id=flat_id).first()
|
||||||
if not flat:
|
if not flat:
|
||||||
return bottle.HTTPError(404, "No flat with id {}.".format(flat_id))
|
return JSONError(404, "No flat with id {}.".format(flat_id))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
visit_date = json.load(bottle.request.body)["visit_date"]
|
json_body = json.load(bottle.request.body)
|
||||||
if visit_date:
|
for k, v in json_body.items():
|
||||||
visit_date = arrow.get(visit_date).naive
|
setattr(flat, k, v)
|
||||||
flat.visit_date = visit_date
|
except ValueError as exc:
|
||||||
except (arrow.parser.ParserError, ValueError, KeyError):
|
return JSONError(
|
||||||
return bottle.HTTPError(400, "Invalid visit date provided.")
|
400,
|
||||||
|
"Invalid payload provided: {}.".format(str(exc))
|
||||||
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"data": _serialize_flat(flat, config)
|
"data": _serialize_flat(flat, config)
|
||||||
}
|
}
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
return {
|
return JSONError(500, str(exc))
|
||||||
"error": str(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def time_to_places_v1(config):
|
def time_to_places_v1(config):
|
||||||
@ -289,10 +191,8 @@ def time_to_places_v1(config):
|
|||||||
return {
|
return {
|
||||||
"data": places
|
"data": places
|
||||||
}
|
}
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
return {
|
return JSONError(500, str(exc))
|
||||||
"error": str(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def search_v1(db, config):
|
def search_v1(db, config):
|
||||||
@ -310,7 +210,7 @@ def search_v1(db, config):
|
|||||||
try:
|
try:
|
||||||
query = json.load(bottle.request.body)["query"]
|
query = json.load(bottle.request.body)["query"]
|
||||||
except (ValueError, KeyError):
|
except (ValueError, KeyError):
|
||||||
return bottle.HTTPError(400, "Invalid query provided.")
|
return JSONError(400, "Invalid query provided.")
|
||||||
|
|
||||||
flats_db_query = flat_model.Flat.search_query(db, query)
|
flats_db_query = flat_model.Flat.search_query(db, query)
|
||||||
flats = [
|
flats = [
|
||||||
@ -321,26 +221,24 @@ def search_v1(db, config):
|
|||||||
return {
|
return {
|
||||||
"data": flats
|
"data": flats
|
||||||
}
|
}
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
return {
|
return JSONError(500, str(exc))
|
||||||
"error": str(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def ics_feed_v1(config, db):
|
def ics_feed_v1(config, db):
|
||||||
"""
|
"""
|
||||||
API v1 ICS feed of visits route:
|
API v1 ICS feed of visits route:
|
||||||
|
|
||||||
GET /api/v1/visits.ics
|
GET /api/v1/ics/visits.ics
|
||||||
|
|
||||||
:return: The ICS feed for the visits.
|
:return: The ICS feed for the visits.
|
||||||
"""
|
"""
|
||||||
|
cal = vobject.iCalendar()
|
||||||
try:
|
try:
|
||||||
flats_with_visits = db.query(flat_model.Flat).filter(
|
flats_with_visits = db.query(flat_model.Flat).filter(
|
||||||
flat_model.Flat.visit_date.isnot(None)
|
flat_model.Flat.visit_date.isnot(None)
|
||||||
).all()
|
)
|
||||||
|
|
||||||
cal = vobject.iCalendar()
|
|
||||||
for flat in flats_with_visits:
|
for flat in flats_with_visits:
|
||||||
vevent = cal.add('vevent')
|
vevent = cal.add('vevent')
|
||||||
vevent.add('dtstart').value = flat.visit_date
|
vevent.add('dtstart').value = flat.visit_date
|
||||||
@ -360,7 +258,7 @@ def ics_feed_v1(config, db):
|
|||||||
description += '\n{}\n'.format(flat.notes)
|
description += '\n{}\n'.format(flat.notes)
|
||||||
|
|
||||||
vevent.add('description').value = description
|
vevent.add('description').value = description
|
||||||
|
|
||||||
return cal.serialize()
|
|
||||||
except:
|
except:
|
||||||
return ''
|
pass
|
||||||
|
|
||||||
|
return cal.serialize()
|
||||||
|
Loading…
Reference in New Issue
Block a user