samarth upadhyay commited on
Commit
3b9735e
·
verified ·
1 Parent(s): 402371f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +124 -76
app.py CHANGED
@@ -1,105 +1,153 @@
1
- import subprocess
 
2
  import sys
3
- import uuid
4
  from flask import Flask, request, jsonify
5
  from flask_cors import CORS
6
 
7
  app = Flask(__name__)
8
  CORS(app)
9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  @app.route('/')
11
  def home():
12
- return jsonify({"status": "ok", "message": "API Running (Isolated Sessions Enabled)"})
13
 
14
- def run_command(command, input_text=None, timeout=15):
15
- """Helper to run shell commands safely"""
16
- try:
17
- run_process = subprocess.run(
18
- command,
19
- input=input_text,
20
- capture_output=True,
21
- text=True,
22
- timeout=timeout
23
- )
24
- output = run_process.stdout
25
- if run_process.stderr:
26
- output += "\n--- Error Log ---\n" + run_process.stderr
27
- return output
28
- except subprocess.TimeoutExpired:
29
- return "Error: Execution timed out (15s limit)."
30
- except Exception as e:
31
- return f"System Error: {str(e)}"
32
-
33
- @app.route('/api/run-python', methods=['POST'])
34
- def run_python():
35
- code = request.json.get('code', '')
36
- user_input = request.json.get('input', '')
37
 
38
- if not code: return jsonify({'output': 'No code provided'}), 400
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
 
40
- cmd = [sys.executable, "-c", code]
41
- output = run_command(cmd, input_text=user_input)
42
- return jsonify({'output': output})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
 
44
  @app.route('/api/run-sql', methods=['POST'])
45
  def run_sql():
46
  data = request.json
47
- sql_code = data.get('code', '')
48
- db_type = data.get('type', 'sqlite').lower()
49
 
50
- if not sql_code: return jsonify({'output': 'No SQL code provided'}), 400
 
51
 
52
- output = ""
53
- session_id = uuid.uuid4().hex[:8] # Random 8-char ID for isolation
 
 
 
54
 
 
55
  try:
56
- # 1. SQLITE (Already Isolated by :memory:)
57
- if db_type == 'sqlite':
58
- cmd = ["sqlite3", ":memory:"]
59
- output = run_command(cmd, input_text=sql_code)
60
-
61
- # 2. POSTGRESQL (Schema Isolation)
62
- elif db_type in ['postgres', 'postgresql']:
63
- schema_name = f"sess_{session_id}"
 
 
64
 
65
- # A. Create Temp Schema
66
- setup_cmd = ["psql", "-h", "localhost", "-U", "playground", "-d", "playground", "-c", f"CREATE SCHEMA {schema_name};"]
67
- run_command(setup_cmd)
68
-
69
- # B. Run User Code (Wrapped in search_path to use the schema)
70
- # We modify the SQL to force it into the new schema
71
- isolated_sql = f"SET search_path TO {schema_name};\n{sql_code}"
72
 
73
- main_cmd = ["psql", "-h", "localhost", "-U", "playground", "-d", "playground"]
74
- output = run_command(main_cmd, input_text=isolated_sql)
75
-
76
- # C. Cleanup (Drop Schema)
77
- cleanup_cmd = ["psql", "-h", "localhost", "-U", "playground", "-d", "playground", "-c", f"DROP SCHEMA {schema_name} CASCADE;"]
78
- run_command(cleanup_cmd)
79
-
80
- # 3. MYSQL (Database Isolation)
81
- elif db_type == 'mysql':
82
- db_name = f"sess_{session_id}"
83
-
84
- # A. Create Temp Database
85
- setup_cmd = ["mysql", "-h", "localhost", "-u", "playground", "-e", f"CREATE DATABASE {db_name};"]
86
- run_command(setup_cmd)
87
-
88
- # B. Run User Code (Against the new DB)
89
- main_cmd = ["mysql", "-h", "localhost", "-u", "playground", "-D", db_name, "-t"]
90
- output = run_command(main_cmd, input_text=sql_code)
91
-
92
- # C. Cleanup (Drop Database)
93
- cleanup_cmd = ["mysql", "-h", "localhost", "-u", "playground", "-e", f"DROP DATABASE {db_name};"]
94
- run_command(cleanup_cmd)
95
-
96
  else:
97
- return jsonify({'output': 'Unsupported database type.'}), 400
98
 
 
 
 
 
 
99
  except Exception as e:
100
- output = f"Server Error: {str(e)}"
101
 
102
- return jsonify({'output': output})
103
 
104
  if __name__ == '__main__':
 
 
 
105
  app.run(host="0.0.0.0", port=7860)
 
1
+ import sqlite3
2
+ import os
3
  import sys
 
4
  from flask import Flask, request, jsonify
5
  from flask_cors import CORS
6
 
7
  app = Flask(__name__)
8
  CORS(app)
9
 
10
+ # Store databases in a temporary directory
11
+ DB_STORAGE_PATH = "/tmp"
12
+
13
+ def get_db_path(session_id):
14
+ # Security: Ensure session_id is alphanumeric only to prevent path traversal
15
+ safe_id = "".join(x for x in session_id if x.isalnum())
16
+ return os.path.join(DB_STORAGE_PATH, f"{safe_id}.db")
17
+
18
+ def create_sample_db(path):
19
+ """Creates a dummy database with Employees and Departments"""
20
+ if os.path.exists(path):
21
+ os.remove(path)
22
+
23
+ conn = sqlite3.connect(path)
24
+ cursor = conn.cursor()
25
+
26
+ # Create Tables
27
+ cursor.execute('''CREATE TABLE Departments (id INTEGER PRIMARY KEY, name TEXT, budget INTEGER)''')
28
+ cursor.execute('''CREATE TABLE Employees (id INTEGER PRIMARY KEY, name TEXT, role TEXT, salary INTEGER, dept_id INTEGER, FOREIGN KEY(dept_id) REFERENCES Departments(id))''')
29
+
30
+ # Insert Data
31
+ cursor.executemany('INSERT INTO Departments VALUES (?,?,?)', [
32
+ (1, 'Engineering', 150000),
33
+ (2, 'Marketing', 80000),
34
+ (3, 'HR', 50000)
35
+ ])
36
+ cursor.executemany('INSERT INTO Employees VALUES (?,?,?,?,?)', [
37
+ (101, 'Alice', 'Engineer', 90000, 1),
38
+ (102, 'Bob', 'Manager', 95000, 2),
39
+ (103, 'Charlie', 'Analyst', 60000, 2),
40
+ (104, 'David', 'Engineer', 88000, 1),
41
+ (105, 'Eve', 'Recruiter', 55000, 3)
42
+ ])
43
+ conn.commit()
44
+ conn.close()
45
+
46
  @app.route('/')
47
  def home():
48
+ return jsonify({"status": "ok", "message": "SQL Compiler with File Persistence Ready"})
49
 
50
+ @app.route('/api/session/init', methods=['POST'])
51
+ def init_session():
52
+ # Allows user to request a fresh sample DB
53
+ session_id = request.json.get('session_id')
54
+ if not session_id: return jsonify({'error': 'Missing session_id'}), 400
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
+ db_path = get_db_path(session_id)
57
+ create_sample_db(db_path)
58
+ return jsonify({'status': 'initialized', 'message': 'Sample Database Loaded'})
59
+
60
+ @app.route('/api/session/upload', methods=['POST'])
61
+ def upload_db():
62
+ session_id = request.form.get('session_id')
63
+ file = request.files.get('file')
64
+
65
+ if not session_id or not file:
66
+ return jsonify({'error': 'Missing session_id or file'}), 400
67
+
68
+ db_path = get_db_path(session_id)
69
+ file.save(db_path)
70
+ return jsonify({'status': 'uploaded', 'message': 'Database Uploaded Successfully'})
71
+
72
+ @app.route('/api/schema', methods=['POST'])
73
+ def get_schema():
74
+ """Returns list of tables and columns for the sidebar"""
75
+ session_id = request.json.get('session_id')
76
+ db_path = get_db_path(session_id)
77
+
78
+ if not os.path.exists(db_path):
79
+ return jsonify({'error': 'No database found for this session'}), 404
80
 
81
+ try:
82
+ conn = sqlite3.connect(db_path)
83
+ cursor = conn.cursor()
84
+
85
+ # Get all tables
86
+ cursor.execute("SELECT name FROM sqlite_master WHERE type='table';")
87
+ tables = [row[0] for row in cursor.fetchall()]
88
+
89
+ schema = {}
90
+ for table in tables:
91
+ cursor.execute(f"PRAGMA table_info({table})")
92
+ # Returns (cid, name, type, notnull, dflt_value, pk)
93
+ columns = [{"name": col[1], "type": col[2]} for col in cursor.fetchall()]
94
+ schema[table] = columns
95
+
96
+ conn.close()
97
+ return jsonify({'schema': schema})
98
+ except Exception as e:
99
+ return jsonify({'error': str(e)}), 500
100
 
101
  @app.route('/api/run-sql', methods=['POST'])
102
  def run_sql():
103
  data = request.json
104
+ session_id = data.get('session_id')
105
+ sql_code = data.get('code')
106
 
107
+ if not session_id or not sql_code:
108
+ return jsonify({'output': 'Missing session_id or SQL code'}), 400
109
 
110
+ db_path = get_db_path(session_id)
111
+
112
+ # If DB doesn't exist yet, create sample
113
+ if not os.path.exists(db_path):
114
+ create_sample_db(db_path)
115
 
116
+ output = []
117
  try:
118
+ conn = sqlite3.connect(db_path)
119
+ cursor = conn.cursor()
120
+
121
+ # Execute script allows multiple statements
122
+ cursor.executescript(sql_code)
123
+
124
+ # Check if the last query returned data (SELECT)
125
+ if cursor.description:
126
+ columns = [desc[0] for desc in cursor.description]
127
+ rows = cursor.fetchall()
128
 
129
+ # ASCII Table Formatting
130
+ output.append(f"| {' | '.join(columns)} |")
131
+ output.append("-" * len(output[-1]))
132
+ for row in rows:
133
+ output.append(f"| {' | '.join(map(str, row))} |")
 
 
134
 
135
+ output.append(f"\n({len(rows)} rows returned)")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
  else:
137
+ output.append(f"Query executed successfully. (Rows affected: {conn.total_changes})")
138
 
139
+ conn.commit()
140
+ conn.close()
141
+
142
+ except sqlite3.Error as e:
143
+ return jsonify({'error': str(e)})
144
  except Exception as e:
145
+ return jsonify({'error': f"System Error: {str(e)}"})
146
 
147
+ return jsonify({'output': "\n".join(output)})
148
 
149
  if __name__ == '__main__':
150
+ # Ensure tmp dir exists
151
+ if not os.path.exists(DB_STORAGE_PATH):
152
+ os.makedirs(DB_STORAGE_PATH)
153
  app.run(host="0.0.0.0", port=7860)