174 lines
5.7 KiB
Python
174 lines
5.7 KiB
Python
from flask import Flask, request, jsonify, render_template
|
|
from influxdb import InfluxDBClient
|
|
from flask_cors import CORS
|
|
from config import get_influx_client
|
|
|
|
app = Flask(__name__)
|
|
CORS(app)
|
|
|
|
client = get_influx_client()
|
|
|
|
def escape_identifier(identifier):
|
|
"""Escapuje identyfikatory dla InfluxDB."""
|
|
return f'"{identifier.replace("\\", "\\\\").replace("\"", "\\\"")}"'
|
|
|
|
def escape_value(value):
|
|
"""Escapuje wartości dla zapytań InfluxDB."""
|
|
if isinstance(value, str):
|
|
escaped = value.replace("'", "''")
|
|
return f"'{escaped}'"
|
|
return str(value)
|
|
|
|
@app.route('/')
|
|
def index():
|
|
return render_template("index.html")
|
|
|
|
@app.route('/databases', methods=['GET'])
|
|
def get_databases():
|
|
databases = client.get_list_database()
|
|
return jsonify([db['name'] for db in databases])
|
|
|
|
@app.route('/series', methods=['GET'])
|
|
def get_series():
|
|
db = request.args.get('db')
|
|
if not db:
|
|
return jsonify({'error': 'Baza danych nie została wybrana'}), 400
|
|
|
|
client.switch_database(db)
|
|
series_info = []
|
|
|
|
#print("DEBUG: Pobieram listę measurementów...")
|
|
measurements = client.query("SHOW MEASUREMENTS")
|
|
measurement_names = [m['name'] for m in measurements.get_points()]
|
|
#print("DEBUG: Measurementy:", measurement_names)
|
|
|
|
for measurement in measurement_names:
|
|
if measurement == "results":
|
|
print("DEBUG: Pomijam 'results'")
|
|
continue
|
|
|
|
#print(f"DEBUG: SHOW SERIES FROM \"{measurement}\"")
|
|
try:
|
|
result = client.query(f'SHOW SERIES FROM "{measurement}"')
|
|
for s in result.get_points():
|
|
tags = {k: v for k, v in s.items() if k != 'time'}
|
|
if not tags:
|
|
continue
|
|
series_id = f"{measurement},{','.join([f'{k}={v}' for k, v in tags.items()])}"
|
|
#print(f"DEBUG: Series = {series_id}")
|
|
series_info.append({
|
|
'series': series_id,
|
|
'measurement': measurement,
|
|
'tags': tags
|
|
})
|
|
except Exception as e:
|
|
print(f"DEBUG: Błąd w {measurement}: {str(e)}")
|
|
|
|
print(f"DEBUG: Zwracam do frontu {len(series_info)} serii")
|
|
return jsonify(series_info)
|
|
|
|
|
|
@app.route('/delete', methods=['POST'])
|
|
def delete_series():
|
|
data = request.json
|
|
db = data.get('db')
|
|
if not db:
|
|
return jsonify({'error': 'Baza danych nie została wybrana'}), 400
|
|
|
|
client.switch_database(db)
|
|
deleted_count = 0
|
|
|
|
for series in data['series']:
|
|
try:
|
|
parts = series.split(',', 1)
|
|
measurement = parts[0].strip()
|
|
tags_part = parts[1] if len(parts) > 1 else ''
|
|
|
|
# Raw tag parsing
|
|
tags = {}
|
|
for tag in tags_part.split(','):
|
|
if '=' in tag:
|
|
k, v = tag.split('=', 1)
|
|
tags[k.strip()] = v.strip()
|
|
|
|
# Pobierz tylko tagi dostępne w measurement
|
|
tag_keys_query = client.query(f'SHOW TAG KEYS FROM "{measurement}"')
|
|
tag_keys = {row['tagKey'] for row in tag_keys_query.get_points()}
|
|
|
|
# Build WHERE clause tylko z tagów
|
|
where_parts = []
|
|
for k, v in tags.items():
|
|
if k not in tag_keys:
|
|
print(f"Pomijam '{k}', bo nie jest tagiem w '{measurement}'")
|
|
continue
|
|
v_escaped = v.replace("'", "\\'")
|
|
where_parts.append(f'"{k}" = \'{v_escaped}\'')
|
|
|
|
# Escape measurement for InfluxQL
|
|
measurement_escaped = measurement.replace('"', '\\"')
|
|
|
|
query = f'DROP SERIES FROM "{measurement_escaped}" WHERE {" AND ".join(where_parts)}'
|
|
print(f"DEBUG: Final query to run: {query}")
|
|
|
|
client.query(query)
|
|
deleted_count += 1
|
|
|
|
except Exception as e:
|
|
print(f"Błąd usuwania serii {series}: {str(e)}")
|
|
continue
|
|
|
|
return jsonify({'status': 'success', 'deleted': deleted_count})
|
|
|
|
|
|
@app.route('/delete_range', methods=['POST'])
|
|
def delete_range():
|
|
data = request.json
|
|
db = data.get('db')
|
|
series = data.get('series')
|
|
time_from = data.get('from')
|
|
time_to = data.get('to')
|
|
|
|
if not all([db, series, time_from, time_to]):
|
|
return jsonify({'error': 'Brakuje wymaganych parametrów'}), 400
|
|
|
|
client.switch_database(db)
|
|
|
|
try:
|
|
# Parsowanie measurementu i tagów z serii
|
|
parts = series.split(',', 1)
|
|
measurement = parts[0].strip()
|
|
tags_part = parts[1] if len(parts) > 1 else ''
|
|
|
|
tags = {}
|
|
for tag in tags_part.split(','):
|
|
if '=' in tag:
|
|
k, v = tag.split('=', 1)
|
|
tags[k.strip()] = v.strip()
|
|
|
|
# Pobierz dozwolone tagi z InfluxDB
|
|
tag_keys_query = client.query(f'SHOW TAG KEYS FROM "{measurement}"')
|
|
tag_keys = {row['tagKey'] for row in tag_keys_query.get_points()}
|
|
|
|
# Buduj WHERE tylko z tagów i czasu
|
|
where_parts = [f"time >= '{time_from}'", f"time <= '{time_to}'"]
|
|
for k, v in tags.items():
|
|
if k not in tag_keys:
|
|
print(f"Pomijam '{k}', bo nie jest tagiem w '{measurement}'")
|
|
continue
|
|
v_escaped = v.replace("'", "\\'")
|
|
where_parts.append(f'"{k}" = \'{v_escaped}\'')
|
|
|
|
measurement_escaped = measurement.replace('"', '\\"')
|
|
query = f'DELETE FROM "{measurement_escaped}" WHERE {" AND ".join(where_parts)}'
|
|
|
|
print(f"DEBUG: DELETE query: {query}")
|
|
client.query(query)
|
|
return jsonify({'status': 'success'})
|
|
|
|
except Exception as e:
|
|
return jsonify({'error': str(e)}), 500
|
|
|
|
|
|
if __name__ == '__main__':
|
|
app.run(host='0.0.0.0', port=9999, debug=True)
|