quick fix 2
This commit is contained in:
19
webserver/README.md
Normal file
19
webserver/README.md
Normal file
@ -0,0 +1,19 @@
|
||||
Simple Flask backend serving Access DB data for the web UI
|
||||
|
||||
Files added:
|
||||
- app.py - Flask app exposing /api/playcounts and static files under / (serves web/main.html and web/danebota.html)
|
||||
- web/data.js - fetches /api/playcounts and renders basic stats into the page
|
||||
- requirements.txt - minimal Python deps
|
||||
|
||||
Run (Windows PowerShell):
|
||||
|
||||
```powershell
|
||||
python -m venv .venv; .\.venv\Scripts\Activate.ps1
|
||||
pip install -r requirements.txt
|
||||
python app.py
|
||||
```
|
||||
|
||||
Notes:
|
||||
- This project expects the Access ODBC driver to be installed on Windows: "Microsoft Access Database Engine" or full Office with the Access components. If pyodbc fails to connect, install the Access Database Engine redistributable (search Microsoft Download Center for "AccessDatabaseEngine").
|
||||
- The Access file `playcount.accdb` must exist in the project root (next to `app.py`).
|
||||
- For production use, run behind a proper WSGI server and secure CORS instead of the permissive header used here for convenience.
|
||||
271
webserver/app.py
Normal file
271
webserver/app.py
Normal file
@ -0,0 +1,271 @@
|
||||
from flask import Flask, jsonify, send_from_directory, make_response, request
|
||||
import os
|
||||
import pyodbc
|
||||
|
||||
app = Flask(__name__, static_folder='web', static_url_path='')
|
||||
|
||||
|
||||
def get_access_db_path():
|
||||
# Database file next to this script
|
||||
base = os.path.dirname("C:/Users/marek_yrlsweo/Documents/furrystatus/bot/webserver")
|
||||
return os.path.join(base, 'playcount.accdb')
|
||||
|
||||
|
||||
def read_access_db(max_rows=1000):
|
||||
db_path = get_access_db_path()
|
||||
if not os.path.exists(db_path):
|
||||
return {'error': 'database file not found', 'path': db_path}
|
||||
|
||||
conn_str = (
|
||||
r'Driver={Microsoft Access Driver (*.mdb, *.accdb)};'
|
||||
f'DBQ={db_path};'
|
||||
)
|
||||
|
||||
try:
|
||||
conn = pyodbc.connect(conn_str, autocommit=True)
|
||||
cursor = conn.cursor()
|
||||
|
||||
# list user tables
|
||||
tables = []
|
||||
for row in cursor.tables():
|
||||
ttype = getattr(row, 'TABLE_TYPE', None) or row[3]
|
||||
tname = getattr(row, 'TABLE_NAME', None) or row[2]
|
||||
if ttype and ttype.upper() == 'TABLE':
|
||||
# skip system tables
|
||||
if tname.startswith('MSys'):
|
||||
continue
|
||||
tables.append(tname)
|
||||
|
||||
data = {}
|
||||
for table in tables:
|
||||
try:
|
||||
cursor.execute(f'SELECT * FROM [{table}]')
|
||||
cols = [column[0] for column in cursor.description] if cursor.description else []
|
||||
rows = []
|
||||
for i, r in enumerate(cursor.fetchmany(max_rows)):
|
||||
rows.append({cols[j]: r[j] for j in range(len(cols))})
|
||||
data[table] = rows
|
||||
except Exception as e:
|
||||
data[table] = {'error': str(e)}
|
||||
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
return {'tables': tables, 'data': data}
|
||||
except Exception as e:
|
||||
return {'error': 'pyodbc connection failed', 'detail': str(e)}
|
||||
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
return send_from_directory(app.static_folder, 'main.html')
|
||||
|
||||
|
||||
@app.route('/danebota.html')
|
||||
def danebota_html():
|
||||
return send_from_directory(app.static_folder, 'danebota.html')
|
||||
|
||||
|
||||
@app.route('/api/playcounts')
|
||||
def api_playcounts():
|
||||
result = read_access_db()
|
||||
resp = make_response(jsonify(result))
|
||||
# allow simple fetches from the same host or other origins during development
|
||||
resp.headers['Access-Control-Allow-Origin'] = '*'
|
||||
return resp
|
||||
|
||||
|
||||
def _coerce_int(v):
|
||||
try:
|
||||
if v is None:
|
||||
return 0
|
||||
if isinstance(v, (int,)):
|
||||
return v
|
||||
# handle Decimal, floats and numeric strings
|
||||
return int(float(v))
|
||||
except Exception:
|
||||
return 0
|
||||
|
||||
|
||||
def _find_key(keys, candidates):
|
||||
# keys: iterable of strings (actual column names)
|
||||
# candidates: list of substrings to search for (lowercase)
|
||||
low_map = {k.lower(): k for k in keys}
|
||||
for cand in candidates:
|
||||
for lk, orig in low_map.items():
|
||||
if cand in lk:
|
||||
return orig
|
||||
return None
|
||||
|
||||
|
||||
def compute_summary_from_readdata(read_result):
|
||||
# read_result expected to have 'data' mapping table->rows
|
||||
if not read_result or 'data' not in read_result:
|
||||
return {'error': 'no data available'}
|
||||
|
||||
data = read_result['data']
|
||||
servers = {} # server -> {'total': int, 'tracks': {track: int}}
|
||||
total_plays = 0
|
||||
|
||||
# candidate substrings to detect columns
|
||||
server_candidates = ['server', 'guild', 'serverid', 'guildid']
|
||||
track_candidates = ['track', 'song', 'file', 'title', 'name']
|
||||
playcount_candidates = ['playcount', 'plays', 'count', 'play_count', 'times']
|
||||
|
||||
for table, rows in (data.items() if isinstance(data, dict) else []):
|
||||
if not isinstance(rows, list):
|
||||
continue
|
||||
if len(rows) == 0:
|
||||
continue
|
||||
# determine column names from first row
|
||||
keys = list(rows[0].keys())
|
||||
k_server = _find_key(keys, server_candidates)
|
||||
k_track = _find_key(keys, track_candidates)
|
||||
k_play = _find_key(keys, playcount_candidates)
|
||||
|
||||
for r in rows:
|
||||
# fallback values
|
||||
server_val = r.get(k_server) if k_server else None
|
||||
track_val = r.get(k_track) if k_track else None
|
||||
play_val = r.get(k_play) if k_play else None
|
||||
|
||||
# If server not present, lump under 'unknown'
|
||||
server_key = str(server_val) if server_val is not None else 'unknown'
|
||||
track_key = str(track_val) if track_val is not None else '(unknown track)'
|
||||
plays = _coerce_int(play_val)
|
||||
|
||||
if server_key not in servers:
|
||||
servers[server_key] = {'total': 0, 'tracks': {}}
|
||||
servers[server_key]['total'] += plays
|
||||
servers[server_key]['tracks'][track_key] = servers[server_key]['tracks'].get(track_key, 0) + plays
|
||||
total_plays += plays
|
||||
|
||||
return {
|
||||
'total_servers': len(servers),
|
||||
'total_plays': total_plays,
|
||||
'servers': servers,
|
||||
}
|
||||
|
||||
|
||||
@app.route('/api/playcounts/summary')
|
||||
def api_playcounts_summary():
|
||||
read = read_access_db(max_rows=10000)
|
||||
if 'error' in read:
|
||||
resp = make_response(jsonify(read))
|
||||
resp.headers['Access-Control-Allow-Origin'] = '*'
|
||||
return resp
|
||||
|
||||
summary = compute_summary_from_readdata(read)
|
||||
# Try to read bot_status.json (written by bot.py) to get accurate guild count
|
||||
try:
|
||||
status_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'bot_status.json')
|
||||
if os.path.exists(status_path):
|
||||
import json
|
||||
with open(status_path, 'r', encoding='utf-8') as f:
|
||||
bot_status = json.load(f)
|
||||
# override total_servers if available
|
||||
if isinstance(bot_status, dict) and 'guild_count' in bot_status:
|
||||
summary['bot_status'] = bot_status
|
||||
summary['total_servers'] = bot_status.get('guild_count', summary.get('total_servers', 0))
|
||||
except Exception:
|
||||
# non-fatal; continue with original summary
|
||||
pass
|
||||
resp = make_response(jsonify(summary))
|
||||
resp.headers['Access-Control-Allow-Origin'] = '*'
|
||||
return resp
|
||||
|
||||
def write_to_db(table_name, column1_name, value1, column2_name, value2):
|
||||
db_path = get_access_db_path()
|
||||
if not os.path.exists(db_path):
|
||||
return {'success': False, 'error': f'Database file not found: {db_path}'}
|
||||
|
||||
conn_str = (
|
||||
r'Driver={Microsoft Access Driver (*.mdb, *.accdb)};'
|
||||
f'DBQ={db_path};'
|
||||
)
|
||||
|
||||
try:
|
||||
# Uwaga: Użycie parametrów zapytania (znak ?) jest kluczowe dla
|
||||
# bezpieczeństwa (ochrona przed SQL injection)
|
||||
conn = pyodbc.connect(conn_str)
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Budowanie zapytania INSERT
|
||||
# W Access należy użyć nawiasów kwadratowych dla nazw kolumn,
|
||||
# szczególnie jeśli zawierają spacje lub znaki specjalne
|
||||
sql_query = f"INSERT INTO [{table_name}] ([{column1_name}], [{column2_name}]) VALUES (?, ?)"
|
||||
|
||||
# Wykonanie zapytania z danymi
|
||||
cursor.execute(sql_query, value1, value2)
|
||||
|
||||
# Zatwierdzenie zmian
|
||||
conn.commit()
|
||||
|
||||
# Zamknięcie połączenia
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
return {'success': True, 'message': 'Data inserted successfully.'}
|
||||
|
||||
except Exception as e:
|
||||
return {'success': False, 'error': f'pyodbc write failed: {str(e)}'}
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
|
||||
# ... (funkcja read_access_db - bez zmian) ...
|
||||
# ... (trasy index, danebota_html, api_playcounts - bez zmian) ...
|
||||
# ... (funkcje _coerce_int, _find_key, compute_summary_from_readdata - bez zmian) ...
|
||||
# ... (trasa api_playcounts_summary - bez zmian) ...
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# NOWA TRASA: Strona HTML dla sugestii
|
||||
# ----------------------------------------------------------------------
|
||||
@app.route('/sugestie.html')
|
||||
def sugestie_html():
|
||||
# Zakładając, że plik sugestie.html znajduje się w folderze 'web'
|
||||
return send_from_directory(app.static_folder, 'sugestie.html')
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# NOWA TRASA API: Odbieranie danych z JavaScript
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
@app.route('/api/sugestie', methods=['POST'])
|
||||
def api_sugestie():
|
||||
# Wymagane jest, aby dane były przesyłane metodą POST w formacie JSON
|
||||
if not request.is_json:
|
||||
return make_response(jsonify({'success': False, 'error': 'Missing JSON in request'}), 400)
|
||||
|
||||
data = request.get_json()
|
||||
|
||||
# 1. Zmienna 1 jest nadal obowiązkowa
|
||||
zmienna1 = data.get('zmienna1')
|
||||
|
||||
# 2. Zmienna 2 jest teraz nieobowiązkowa (ustawiamy pusty ciąg, jeśli brak)
|
||||
zmienna2 = data.get('zmienna2', '') # <-- Zmiana: ustawiamy domyślną wartość
|
||||
|
||||
|
||||
# Sprawdzenie, czy obowiązkowa zmienna1 jest obecna
|
||||
if zmienna1 is None: # Zmieniono warunek na sprawdzenie tylko zmiennej1
|
||||
return make_response(jsonify({'success': False, 'error': 'Missing required variable: zmienna1'}), 400)
|
||||
|
||||
# UWAGA: Nazwy tabeli i kolumn muszą być zgodne z bazą Access!
|
||||
TABLE_NAME = "Sugestie" # Zmień na faktyczną nazwę tabeli
|
||||
COLUMN1_NAME = "NazwaUtworu" # Zmień na faktyczną nazwę kolumny
|
||||
COLUMN2_NAME = "Link" # Zmień na faktyczną nazwę kolumny
|
||||
|
||||
# Wywołanie funkcji zapisu do bazy danych
|
||||
# Wartość zmienna2 (pusty ciąg lub podana) zostanie przekazana
|
||||
result = write_to_db(TABLE_NAME, COLUMN1_NAME, zmienna1, COLUMN2_NAME, zmienna2)
|
||||
|
||||
resp = make_response(jsonify(result))
|
||||
resp.headers['Access-Control-Allow-Origin'] = '*'
|
||||
return resp
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Development server
|
||||
app.run(host='100.100.23.87', port=5000, debug=False)
|
||||
|
||||
|
||||
25
webserver/bot_status.json
Normal file
25
webserver/bot_status.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"guild_count": 5,
|
||||
"guilds": [
|
||||
{
|
||||
"id": 1016761768460156968,
|
||||
"name": "《🔒》Vip Server"
|
||||
},
|
||||
{
|
||||
"id": 1213542239893069824,
|
||||
"name": "Bot BDSM"
|
||||
},
|
||||
{
|
||||
"id": 1293641444195565580,
|
||||
"name": "♥←~Sea~Busters~→♥"
|
||||
},
|
||||
{
|
||||
"id": 1303446293485715477,
|
||||
"name": "server for softfrog emojis 𓆏"
|
||||
},
|
||||
{
|
||||
"id": 1340254368850772038,
|
||||
"name": "stalking fmbot"
|
||||
}
|
||||
]
|
||||
}
|
||||
5
webserver/pyvenv.cfg
Normal file
5
webserver/pyvenv.cfg
Normal file
@ -0,0 +1,5 @@
|
||||
home = C:\Program Files\Python313
|
||||
include-system-site-packages = false
|
||||
version = 3.13.7
|
||||
executable = C:\Program Files\Python313\python.exe
|
||||
command = C:\Program Files\Python313\python.exe -m venv C:\Users\marek_yrlsweo\Documents\furrystatus\bot
|
||||
3
webserver/startweb.bat
Normal file
3
webserver/startweb.bat
Normal file
@ -0,0 +1,3 @@
|
||||
@echo off
|
||||
cd "C:\Users\marek_yrlsweo\Documents\furrystatus\bot\webserver"
|
||||
python app.py
|
||||
25
webserver/web/Kontakt.html
Normal file
25
webserver/web/Kontakt.html
Normal file
@ -0,0 +1,25 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="./webcss/nav.css">
|
||||
<link rel="stylesheet" href="./webcss/main.css">
|
||||
<title>Kontakt</title>
|
||||
</head>
|
||||
<body>
|
||||
<nav>
|
||||
<ul>
|
||||
<li><a href="main.html">Strona główna</a></li>
|
||||
<li><a href="danebota.html">Dane Bota</a></li>
|
||||
<li><a href="sugestie.html">Sugestie</a></li>
|
||||
<li><a href="https://discord.com/oauth2/authorize?client_id=1379068224947093536">dodaj mojego bota!</a></li>
|
||||
<li><a href="Kontakt.html">Kontakt</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
<main>
|
||||
<h1>Kontakty</h1>
|
||||
<p>Możesz się ze mną skontaktować na Discordie: softfrog</p>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
35
webserver/web/danebota.html
Normal file
35
webserver/web/danebota.html
Normal file
@ -0,0 +1,35 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="./webcss/nav.css">
|
||||
<link rel="stylesheet" href="./webcss/bota.css">
|
||||
<link rel="stylesheet" href="./webcss/main.css">
|
||||
<!-- load the script at the end of body instead of link in head -->
|
||||
<title>Danebota</title>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<nav>
|
||||
<ul>
|
||||
<li><a href="main.html">Strona główna</a></li>
|
||||
<li><a href="danebota.html">Dane Bota</a></li>
|
||||
<li><a href="sugestie.html">Sugestie</a></li>
|
||||
<li><a href="https://discord.com/oauth2/authorize?client_id=1379068224947093536">dodaj mojego bota!</a></li>
|
||||
<li><a href="Kontakt.html">Kontakt</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
<main>
|
||||
<h1>Dane Bota</h1>
|
||||
<p>Tu znajdziesz informacje o bocie.</p>
|
||||
<section>
|
||||
<h2>Statystyki</h2>
|
||||
<div id="bot-stats">
|
||||
<p>Liczba serwerów: 56</p>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
<script src="./data.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
62
webserver/web/data.js
Normal file
62
webserver/web/data.js
Normal file
@ -0,0 +1,62 @@
|
||||
// Fetch playcount data from backend API and expose a helper to render it
|
||||
async function fetchPlaycounts() {
|
||||
try {
|
||||
const resp = await fetch('/api/playcounts');
|
||||
if (!resp.ok) throw new Error('Network response was not ok');
|
||||
return await resp.json();
|
||||
} catch (err) {
|
||||
return { error: err.message };
|
||||
}
|
||||
}
|
||||
|
||||
// Simple renderer for danebota.html - injects table counts
|
||||
async function renderStats() {
|
||||
const out = document.getElementById('bot-stats');
|
||||
if (!out) return;
|
||||
out.textContent = 'Ładowanie…';
|
||||
// prefer the summary endpoint which gives aggregated totals
|
||||
try {
|
||||
const resp = await fetch('/api/playcounts/summary');
|
||||
if (!resp.ok) throw new Error('Network response was not ok');
|
||||
const summary = await resp.json();
|
||||
if (summary.error) {
|
||||
out.textContent = 'Błąd: ' + (summary.detail || summary.error);
|
||||
return;
|
||||
}
|
||||
|
||||
let html = '';
|
||||
html += `<p>Liczba serwerów z discord: ${summary.total_servers}</p>`;
|
||||
html += `<p>Suma wszystkich odtworzeń: ${summary.total_plays}</p>`;
|
||||
|
||||
// Render each server and its top 5 tracks
|
||||
const servers = summary.servers || {};
|
||||
for (const [server, info] of Object.entries(servers)) {
|
||||
html += `<section class="server-block"><h3>Serwer: ${server}</h3>`;
|
||||
html += `<p>Łącznie odtworzeń: ${info.total}</p>`;
|
||||
const tracks = info.tracks || {};
|
||||
// sort tracks by plays desc
|
||||
const sorted = Object.entries(tracks).sort((a, b) => b[1] - a[1]).slice(0, 10000);
|
||||
if (sorted.length === 0) {
|
||||
html += `<p>Brak danych o utworach.</p>`;
|
||||
} else {
|
||||
html += `<ol>`;
|
||||
html += `<br>`;
|
||||
for (const [tname, plays] of sorted) {
|
||||
html += `<li style="margin-top: 10px;">${tname} — ${plays} odtworzeń</li>`;
|
||||
}
|
||||
html += `</ol>`;
|
||||
}
|
||||
html += `</section>`;
|
||||
}
|
||||
|
||||
out.innerHTML = html;
|
||||
} catch (err) {
|
||||
out.textContent = 'Błąd sieci: ' + err.message;
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-run when included from danebota.html
|
||||
if (typeof window !== 'undefined') {
|
||||
window.addEventListener('DOMContentLoaded', renderStats);
|
||||
}
|
||||
|
||||
33
webserver/web/main.html
Normal file
33
webserver/web/main.html
Normal file
@ -0,0 +1,33 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="./webcss/nav.css">
|
||||
<link rel="stylesheet" href="./webcss/main.css">
|
||||
<title>Główna Strona</title>
|
||||
</head>
|
||||
<body>
|
||||
<nav>
|
||||
<ul>
|
||||
<li><a href="main.html">Strona główna</a></li>
|
||||
<li><a href="danebota.html">Dane Bota</a></li>
|
||||
<li><a href="sugestie.html">Sugestie</a></li>
|
||||
<li><a href="https://discord.com/oauth2/authorize?client_id=1379068224947093536">dodaj mojego bota!</a></li>
|
||||
<li><a href="Kontakt.html">Kontakt</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
<main>
|
||||
<h1>Witamy na Stronie Głównej</h1>
|
||||
<p>To jest główna strona mojego bota.</p>
|
||||
<br><br>
|
||||
<section>
|
||||
<h1>Update</h1>
|
||||
<h2>General Update #1 19.10.2025</h2>
|
||||
<p>1. dodano statystyki bota na danebota</p>
|
||||
<p>2. </p>
|
||||
<p>3. </p>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
42
webserver/web/sugestie.html
Normal file
42
webserver/web/sugestie.html
Normal file
@ -0,0 +1,42 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="./webcss/nav.css">
|
||||
<link rel="stylesheet" href="./webcss/main.css">
|
||||
<title>sugestie</title>
|
||||
</head>
|
||||
<body>
|
||||
<nav>
|
||||
<ul>
|
||||
<li><a href="main.html">Strona główna</a></li>
|
||||
<li><a href="danebota.html">Dane Bota</a></li>
|
||||
<li><a href="sugestie.html">Sugestie</a></li>
|
||||
<li><a href="https://discord.com/oauth2/authorize?client_id=1379068224947093536">dodaj mojego bota!</a></li>
|
||||
<li><a href="Kontakt.html">Kontakt</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
<main>
|
||||
<h1>Podaj swoją sugestię muzyki</h1>
|
||||
<div id="dataContainer">
|
||||
<div class="input-group">
|
||||
<label for="var1">Nazwa Utworu: (OBOWIĄZKOWY)</label>
|
||||
<br>
|
||||
<input type="text" name="sugestia" id="sugestia" style="height: 30px; width: 400px;" placeholder="Twoja sugestia..." required>
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<label for="var2">Link:</label>
|
||||
<br>
|
||||
<input type="url" name="link" id="link" style="height: 30px; width: 400px;" placeholder="Link do utworu...">
|
||||
</div>
|
||||
|
||||
<button id="sendButton">Wyślij do Bazy</button>
|
||||
</div>
|
||||
|
||||
<div id="status"></div>
|
||||
</main>
|
||||
<script src="./sugestie.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
60
webserver/web/sugestie.js
Normal file
60
webserver/web/sugestie.js
Normal file
@ -0,0 +1,60 @@
|
||||
// Zmieniamy 'sugestionForm' i 'submit' na 'sendButton' i 'click'
|
||||
document.getElementById('sendButton').addEventListener('click', async function(event) {
|
||||
// Nie musimy już wywoływać event.preventDefault(), ponieważ to nie jest submit formularza
|
||||
|
||||
const statusDiv = document.getElementById('status');
|
||||
statusDiv.textContent = 'Wysyłanie danych...';
|
||||
statusDiv.style.color = 'orange';
|
||||
|
||||
// 1. Pobranie zmiennych z pól wejściowych
|
||||
const zmienna1 = document.getElementById('sugestia').value;
|
||||
const zmienna2 = document.getElementById('link').value;
|
||||
|
||||
// Weryfikacja obowiązkowej zmiennej 1
|
||||
if (!zmienna1.trim()) {
|
||||
statusDiv.textContent = 'BŁĄD: Zmienna 1 jest obowiązkowa!';
|
||||
statusDiv.style.color = 'red';
|
||||
return; // Zatrzymuje wysyłanie
|
||||
}
|
||||
|
||||
// 2. Przygotowanie danych jako obiekt JavaScript (JSON)
|
||||
const dataToSend = {
|
||||
zmienna1: zmienna1,
|
||||
zmienna2: zmienna2
|
||||
};
|
||||
|
||||
// 3. Wysłanie danych do API za pomocą Fetch API
|
||||
try {
|
||||
const response = await fetch('/api/sugestie', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(dataToSend)
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result.success) {
|
||||
// Sukces
|
||||
statusDiv.textContent = 'Sukces! Twoje dane nigdy nie będą przeczytane';
|
||||
statusDiv.style.color = 'green';
|
||||
|
||||
// Opcjonalne: Wyczyść pola po sukcesie
|
||||
document.getElementById('sugestia').value = '';
|
||||
document.getElementById('link').value = '';
|
||||
|
||||
} else {
|
||||
// Błąd
|
||||
const errorMessage = result.error || 'Nieznany błąd zapisu.';
|
||||
statusDiv.textContent = 'BŁĄD: ' + errorMessage;
|
||||
statusDiv.style.color = 'red';
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
// Błąd sieci
|
||||
statusDiv.textContent = 'BŁĄD POŁĄCZENIA: Nie można połączyć się z serwerem Flask.';
|
||||
statusDiv.style.color = 'red';
|
||||
console.error('Fetch error:', error);
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user