| |
| import os |
| import sqlite3 |
| import json |
| import requests |
| from flask import Flask, request, jsonify, g |
|
|
| app = Flask(__name__) |
|
|
| @app.after_request |
| def add_cors_headers(response): |
| response.headers['Access-Control-Allow-Origin'] = '*' |
| response.headers['Access-Control-Allow-Methods'] = 'GET,POST,PUT,DELETE,OPTIONS' |
| response.headers['Access-Control-Allow-Headers'] = 'Content-Type,Authorization' |
| return response |
|
|
| |
| |
| |
| DATABASE = os.path.join(os.path.dirname(__file__), "tasks.db") |
|
|
| def get_db(): |
| db = getattr(g, "_database", None) |
| if db is None: |
| db = g._database = sqlite3.connect(DATABASE, check_same_thread=False) |
| db.row_factory = sqlite3.Row |
| return db |
|
|
| def init_db(): |
| conn = sqlite3.connect(DATABASE) |
| cursor = conn.cursor() |
| cursor.execute( |
| """ |
| CREATE TABLE IF NOT EXISTS tasks ( |
| id INTEGER PRIMARY KEY AUTOINCREMENT, |
| title TEXT NOT NULL, |
| completed INTEGER NOT NULL DEFAULT 0 |
| ) |
| """ |
| ) |
| conn.commit() |
| conn.close() |
|
|
| @app.teardown_appcontext |
| def close_connection(exception): |
| db = getattr(g, "_database", None) |
| if db is not None: |
| db.close() |
|
|
| |
| |
| |
| @app.route("/tasks", methods=["GET"]) |
| def list_tasks(): |
| db = get_db() |
| cursor = db.execute("SELECT id, title, completed FROM tasks") |
| tasks = [ |
| {"id": row["id"], "title": row["title"], "completed": bool(row["completed"])} |
| for row in cursor.fetchall() |
| ] |
| return jsonify(tasks) |
|
|
| @app.route("/tasks", methods=["POST"]) |
| def create_task(): |
| data = request.get_json() |
| title = data.get("title") |
| if not title: |
| return jsonify({"error": "title is required"}), 400 |
| db = get_db() |
| cursor = db.execute( |
| "INSERT INTO tasks (title, completed) VALUES (?, ?)", |
| (title, 0), |
| ) |
| db.commit() |
| task_id = cursor.lastrowid |
| return jsonify({"id": task_id, "title": title, "completed": False}), 201 |
|
|
| @app.route("/tasks/<int:task_id>", methods=["PUT"]) |
| def update_task(task_id): |
| data = request.get_json() |
| title = data.get("title") |
| completed = data.get("completed") |
| if title is None and completed is None: |
| return jsonify({"error": "nothing to update"}), 400 |
| db = get_db() |
| if title is not None: |
| db.execute("UPDATE tasks SET title = ? WHERE id = ?", (title, task_id)) |
| if completed is not None: |
| db.execute( |
| "UPDATE tasks SET completed = ? WHERE id = ?", |
| (1 if completed else 0, task_id), |
| ) |
| db.commit() |
| return jsonify({"id": task_id, "title": title, "completed": completed}) |
|
|
| @app.route("/tasks/<int:task_id>", methods=["DELETE"]) |
| def delete_task(task_id): |
| db = get_db() |
| db.execute("DELETE FROM tasks WHERE id = ?", (task_id,)) |
| db.commit() |
| return "", 204 |
|
|
| |
| |
| |
| @app.route("/", methods=["GET"]) |
| @app.route("/test", methods=["GET"]) |
| def index(): |
| return "Task API is running." |
|
|
| @app.route("/ping", methods=["GET"]) |
| def ping(): |
| return "pong", 200 |
|
|
| |
| |
| |
| @app.route("/api/connector", methods=["GET", "POST"]) |
| def api_connector(): |
| """ |
| Expects a JSON payload with the following fields: |
| { |
| "url": "https://example.com/endpoint", |
| "method": "GET|POST|PUT|DELETE|PATCH", |
| "headers": {"Authorization": "Bearer ...", ...}, # optional |
| "params": {"q": "search"}, # optional, for query string |
| "json": {"key": "value"} # optional, for JSON body |
| } |
| The endpoint forwards the request to the target API and returns |
| the raw response (status code, headers and JSON body if possible). |
| """ |
| payload = request.get_json() |
| if not payload: |
| return jsonify({"error": "invalid json payload"}), 400 |
|
|
| url = payload.get("url") |
| |
| method = payload.get("method", "GET").upper() |
| headers = payload.get("headers", {}) |
| params = payload.get("params", {}) |
| json_body = payload.get("json", None) |
|
|
| if not url: |
| return jsonify({"error": "url is required"}), 400 |
|
|
| |
| default_key = os.environ.get("DEFAULT_API_KEY") |
| if default_key and "Authorization" not in headers: |
| headers["Authorization"] = f"Bearer {default_key}" |
|
|
| try: |
| response = requests.request( |
| method=method, |
| url=url, |
| headers=headers, |
| params=params, |
| json=json_body, |
| timeout=30 |
| ) |
| |
| except requests.RequestException as e: |
| return jsonify({"error": "request failed", "details": str(e)}), 502 |
|
|
| |
| try: |
| resp_content = response.json() |
| except ValueError: |
| resp_content = response.text |
|
|
| result = { |
| "status_code": response.status_code, |
| "headers": dict(response.headers), |
| "content": resp_content |
| } |
| return jsonify(result), response.status_code |
|
|
| |
| |
| |
| @app.errorhandler(404) |
| def not_found(e): |
| return jsonify({"error": "not found"}), 404 |
|
|
| |
| |
| |
| if __name__ == "__main__": |
| if not os.path.isfile(DATABASE): |
| init_db() |
| app.run(host="0.0.0.0", port=7860) |