File size: 6,337 Bytes
d81bb6a
 
 
f1364d9
e9194d7
097cbf3
d81bb6a
097cbf3
d81bb6a
01ac14b
 
 
 
 
 
 
f1364d9
 
 
097cbf3
 
 
 
 
9f255f9
097cbf3
 
d81bb6a
 
097cbf3
 
 
d81bb6a
 
 
 
 
 
 
 
 
 
 
097cbf3
 
 
 
 
 
f1364d9
 
 
097cbf3
 
 
 
 
 
 
 
 
 
 
 
 
 
d81bb6a
097cbf3
 
 
 
 
4831f3a
097cbf3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4831f3a
097cbf3
 
4831f3a
097cbf3
 
 
 
 
 
 
f1364d9
 
 
097cbf3
efb2d13
097cbf3
 
 
1f44040
 
 
 
f1364d9
 
 
e7ff015
f1364d9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e849906
f1364d9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6398b8e
f1364d9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
09341e0
 
 
 
f1364d9
 
 
097cbf3
 
 
c39b33d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# -*- coding: utf-8 -*-
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 utilities (unchanged)
# ----------------------------------------------------------------------
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()

# ----------------------------------------------------------------------
# Existing task endpoints (unchanged)
# ----------------------------------------------------------------------
@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

# ----------------------------------------------------------------------
# Health endpoints (unchanged)
# ----------------------------------------------------------------------
@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

# ----------------------------------------------------------------------
# New: Generic API connector
# ----------------------------------------------------------------------
@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")
    # placeholder replacement removed
    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

    # Optional: inject a default API key from environment if not provided
    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
        )
        # Do not raise for HTTP errors; return the response as is
    except requests.RequestException as e:
        return jsonify({"error": "request failed", "details": str(e)}), 502

    # Try to parse JSON, fallback to raw text
    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

# ----------------------------------------------------------------------
# Error handling (unchanged)
# ----------------------------------------------------------------------
@app.errorhandler(404)
def not_found(e):
    return jsonify({"error": "not found"}), 404

# ----------------------------------------------------------------------
# Main entry point (unchanged)
# ----------------------------------------------------------------------
if __name__ == "__main__":
    if not os.path.isfile(DATABASE):
        init_db()
    app.run(host="0.0.0.0", port=7860)