app.py 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. #!/usr/bin/env python3
  2. import pickle
  3. import atexit
  4. import datetime
  5. from flask import Flask, Blueprint, jsonify, request, abort
  6. from flask_cors import CORS
  7. DB_FILE = "vacation.db"
  8. last_update = datetime.datetime.now()
  9. since_backup = 0
  10. try:
  11. with open(DB_FILE, "rb") as infile:
  12. db = pickle.load(infile)
  13. except FileNotFoundError:
  14. db = {}
  15. @atexit.register
  16. def save_db(prefix=""):
  17. with open(prefix + DB_FILE, "wb") as outfile:
  18. pickle.dump(db, outfile)
  19. def backup_db():
  20. save_db(f"backup-{datetime.datetime.now().isoformat()}-")
  21. bp = Blueprint("vacation", __name__)
  22. @bp.route("/")
  23. def health():
  24. return jsonify({"status": "healthy"})
  25. @bp.route("/availability", methods=["GET", "POST"])
  26. def status():
  27. global last_update, since_backup
  28. if request.method == "POST":
  29. body = request.get_json()
  30. if body is None:
  31. abort(400)
  32. name = body.get("name", None)
  33. availability = body.get("availability", None)
  34. if not isinstance(name, str) or not isinstance(availability, list):
  35. abort(400)
  36. transaction = []
  37. for a in availability:
  38. month = a.get("month", None)
  39. day = a.get("day", None)
  40. status = a.get("status", None)
  41. if (month, day) not in db or status not in ("yes", "no", "maybe", "unknown"):
  42. abort(400)
  43. transaction.append((month, day, status))
  44. last_update = datetime.datetime.now()
  45. for (month, day, status) in transaction:
  46. db[(month, day)][name] = status
  47. since_backup += 1
  48. if since_backup > 50:
  49. backup_db()
  50. return jsonify({
  51. "lastUpdated": last_update.isoformat(),
  52. "availability": [
  53. {
  54. "month": month,
  55. "day": day,
  56. "availability": [{
  57. "name": name,
  58. "status": status,
  59. } for (name, status) in avail.items()],
  60. } for (month, day), avail in db.items()
  61. ],
  62. })
  63. app = Flask(__name__)
  64. CORS(app)
  65. app.register_blueprint(bp, url_prefix="/vacation-planner/api")
  66. app.url_map.strict_slashes = False
  67. if __name__ == "__main__":
  68. app.run("0.0.0.0", 5000, debug=False, threaded=True)