first commit
This commit is contained in:
139
api/main.py
Normal file
139
api/main.py
Normal file
@@ -0,0 +1,139 @@
|
||||
"""
|
||||
main.py - Flask API with auth routes and module registry
|
||||
|
||||
Domain routes are registered via the routes registry.
|
||||
"""
|
||||
|
||||
import os
|
||||
import flask
|
||||
import core.auth as auth
|
||||
import core.users as users
|
||||
import core.postgres as postgres
|
||||
import api.routes.routines as routines_routes
|
||||
import api.routes.medications as medications_routes
|
||||
|
||||
app = flask.Flask(__name__)
|
||||
|
||||
ROUTE_MODULES = [routines_routes, medications_routes]
|
||||
|
||||
|
||||
def register_routes(module):
|
||||
"""Register a routes module. Module should have a register(app) function."""
|
||||
ROUTE_MODULES.append(module)
|
||||
|
||||
|
||||
# ── Auth Routes ────────────────────────────────────────────────────
|
||||
|
||||
|
||||
@app.route("/api/register", methods=["POST"])
|
||||
def api_register():
|
||||
data = flask.request.get_json()
|
||||
username = data.get("username")
|
||||
password = data.get("password")
|
||||
if not username or not password:
|
||||
return flask.jsonify({"error": "username and password required"}), 400
|
||||
result = users.registerUser(username, password, data)
|
||||
if result:
|
||||
return flask.jsonify({"success": True}), 201
|
||||
else:
|
||||
return flask.jsonify({"error": "username taken"}), 409
|
||||
|
||||
|
||||
@app.route("/api/login", methods=["POST"])
|
||||
def api_login():
|
||||
data = flask.request.get_json()
|
||||
username = data.get("username")
|
||||
password = data.get("password")
|
||||
if not username or not password:
|
||||
return flask.jsonify({"error": "username and password required"}), 400
|
||||
token = auth.getLoginToken(username, password)
|
||||
if token:
|
||||
return flask.jsonify({"token": token}), 200
|
||||
else:
|
||||
return flask.jsonify({"error": "invalid credentials"}), 401
|
||||
|
||||
|
||||
# ── User Routes ────────────────────────────────────────────────────
|
||||
|
||||
|
||||
@app.route("/api/getUserUUID/<username>", methods=["GET"])
|
||||
def api_getUserUUID(username):
|
||||
header = flask.request.headers.get("Authorization", "")
|
||||
if not header.startswith("Bearer "):
|
||||
return flask.jsonify({"error": "missing token"}), 401
|
||||
token = header[7:]
|
||||
if auth.verifyLoginToken(token, username):
|
||||
return flask.jsonify(users.getUserUUID(username)), 200
|
||||
else:
|
||||
return flask.jsonify({"error": "unauthorized"}), 401
|
||||
|
||||
|
||||
@app.route("/api/user/<userUUID>", methods=["GET"])
|
||||
def api_getUser(userUUID):
|
||||
header = flask.request.headers.get("Authorization", "")
|
||||
if not header.startswith("Bearer "):
|
||||
return flask.jsonify({"error": "missing token"}), 401
|
||||
token = header[7:]
|
||||
if auth.verifyLoginToken(token, userUUID=userUUID):
|
||||
user = postgres.select_one("users", {"id": userUUID})
|
||||
if user:
|
||||
user.pop("password_hashed", None)
|
||||
return flask.jsonify(user), 200
|
||||
else:
|
||||
return flask.jsonify({"error": "user not found"}), 404
|
||||
else:
|
||||
return flask.jsonify({"error": "unauthorized"}), 401
|
||||
|
||||
|
||||
@app.route("/api/user/<userUUID>", methods=["PUT"])
|
||||
def api_updateUser(userUUID):
|
||||
header = flask.request.headers.get("Authorization", "")
|
||||
if not header.startswith("Bearer "):
|
||||
return flask.jsonify({"error": "missing token"}), 401
|
||||
token = header[7:]
|
||||
if auth.verifyLoginToken(token, userUUID=userUUID):
|
||||
data = flask.request.get_json()
|
||||
result = users.updateUser(userUUID, data)
|
||||
if result:
|
||||
return flask.jsonify({"success": True}), 200
|
||||
else:
|
||||
return flask.jsonify({"error": "no valid fields to update"}), 400
|
||||
else:
|
||||
return flask.jsonify({"error": "unauthorized"}), 401
|
||||
|
||||
|
||||
@app.route("/api/user/<userUUID>", methods=["DELETE"])
|
||||
def api_deleteUser(userUUID):
|
||||
header = flask.request.headers.get("Authorization", "")
|
||||
if not header.startswith("Bearer "):
|
||||
return flask.jsonify({"error": "missing token"}), 401
|
||||
token = header[7:]
|
||||
if auth.verifyLoginToken(token, userUUID=userUUID):
|
||||
data = flask.request.get_json()
|
||||
password = data.get("password")
|
||||
if not password:
|
||||
return flask.jsonify(
|
||||
{"error": "password required for account deletion"}
|
||||
), 400
|
||||
result = auth.unregisterUser(userUUID, password)
|
||||
if result:
|
||||
return flask.jsonify({"success": True}), 200
|
||||
else:
|
||||
return flask.jsonify({"error": "invalid password"}), 401
|
||||
else:
|
||||
return flask.jsonify({"error": "unauthorized"}), 401
|
||||
|
||||
|
||||
# ── Health Check ───────────────────────────────────────────────────
|
||||
|
||||
|
||||
@app.route("/health", methods=["GET"])
|
||||
def health_check():
|
||||
return flask.jsonify({"status": "ok"}), 200
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
for module in ROUTE_MODULES:
|
||||
if hasattr(module, "register"):
|
||||
module.register(app)
|
||||
app.run(host="0.0.0.0", port=5000)
|
||||
Reference in New Issue
Block a user