zmiany w changlogach, alertach itp
This commit is contained in:
parent
85a37e4a78
commit
73a4e6149a
212
app.py
212
app.py
@ -26,6 +26,10 @@ try:
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
date_parser = None
|
date_parser = None
|
||||||
|
|
||||||
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
|
||||||
# Konfiguracja aplikacji
|
# Konfiguracja aplikacji
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.config['SECRET_KEY'] = 'twoj-sekret-klucz'
|
app.config['SECRET_KEY'] = 'twoj-sekret-klucz'
|
||||||
@ -444,73 +448,103 @@ def fetch_changelogs(force=False):
|
|||||||
changelog_url = "https://mikrotik.com/download/changelogs"
|
changelog_url = "https://mikrotik.com/download/changelogs"
|
||||||
current_date = datetime.utcnow()
|
current_date = datetime.utcnow()
|
||||||
|
|
||||||
|
def process_section(section):
|
||||||
|
a_tag = section.find("a")
|
||||||
|
if not a_tag:
|
||||||
|
return None
|
||||||
|
|
||||||
|
raw_text = a_tag.get_text(strip=True)
|
||||||
|
logging.info(f"raw_text: {raw_text}")
|
||||||
|
|
||||||
|
# Najpierw próbujemy znaleźć wersję za pomocą wzorca z "in"
|
||||||
|
match = re.search(r"in\s+(\d+\.\d+(?:\.\d+)?(?:beta|rc)?\d*)", raw_text)
|
||||||
|
if match:
|
||||||
|
version_text = match.group(1)
|
||||||
|
logging.info(f"Parsed version (pattern 1): {version_text}")
|
||||||
|
else:
|
||||||
|
# Jeśli nie znaleziono, próbujemy wychwycić wersję na początku łańcucha z dołączoną datą
|
||||||
|
match = re.match(r"^(\d+\.\d+(?:\.\d+)?(?:beta|rc)?\d*)(\d{4}-\d{2}-\d{2})", raw_text)
|
||||||
|
if match:
|
||||||
|
version_text = match.group(1)
|
||||||
|
logging.info(f"Parsed version (pattern 2): {version_text}")
|
||||||
|
else:
|
||||||
|
version_text = raw_text
|
||||||
|
logging.info("Brak dopasowania regex, używam raw_text jako wersji")
|
||||||
|
|
||||||
|
# Pomijamy wersje, które nie zaczynają się od "6." lub "7."
|
||||||
|
if not (version_text.startswith("6.") or version_text.startswith("7.")):
|
||||||
|
logging.info(f"Pomijam wersję {version_text} – nie jest 6.x ani 7.x")
|
||||||
|
return None
|
||||||
|
|
||||||
|
details_div = section.find("div", class_="content")
|
||||||
|
changelog_file_url = details_div.get("data-url") if details_div else None
|
||||||
|
if not changelog_file_url:
|
||||||
|
logging.warning(f"Brak URL changeloga dla wersji {version_text}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
changelog_response = requests.get(changelog_file_url, timeout=10)
|
||||||
|
changelog_response.raise_for_status()
|
||||||
|
changelog_lines = changelog_response.text.splitlines()
|
||||||
|
|
||||||
|
if not changelog_lines:
|
||||||
|
logging.warning(f"Pusty changelog dla wersji {version_text}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
first_line = changelog_lines[0].strip()
|
||||||
|
release_date_dt = parse_release_date(first_line)
|
||||||
|
if release_date_dt is None:
|
||||||
|
logging.warning(f"Nie udało się wyłuskać daty dla wersji {version_text}, pomijam ten changelog")
|
||||||
|
return None
|
||||||
|
|
||||||
|
changelog_text = "\n".join(changelog_lines).strip()
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"Błąd pobierania changeloga z {changelog_file_url}: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Filtrowanie według daty: dla 7.x pomijamy wersje starsze niż 1 rok, dla 6.x starsze niż 2 lata
|
||||||
|
if version_text.startswith("7.") and release_date_dt < (current_date - timedelta(days=365)):
|
||||||
|
logging.info(f"Pomijam wersję {version_text} - starsza niż 1 rok")
|
||||||
|
return None
|
||||||
|
if version_text.startswith("6.") and release_date_dt < (current_date - timedelta(days=730)):
|
||||||
|
logging.info(f"Pomijam wersję {version_text} - starsza niż 2 lata")
|
||||||
|
return None
|
||||||
|
|
||||||
|
release_type = get_release_type(version_text)
|
||||||
|
return {
|
||||||
|
"version": version_text,
|
||||||
|
"details": changelog_text,
|
||||||
|
"category": "6.x" if version_text.startswith("6.") else "7.x",
|
||||||
|
"timestamp": release_date_dt,
|
||||||
|
"release_type": release_type
|
||||||
|
}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
logging.info(f"Pobieranie changelogów z {changelog_url}...")
|
logging.info(f"Pobieranie changelogów z {changelog_url}...")
|
||||||
response = requests.get(changelog_url, timeout=10)
|
response = requests.get(changelog_url, timeout=30)
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
soup = BeautifulSoup(response.text, "html.parser")
|
soup = BeautifulSoup(response.text, "html.parser")
|
||||||
changelog_sections = soup.find_all("li", class_="accordion-navigation")
|
changelog_sections = soup.find_all("li", class_="accordion-navigation")
|
||||||
logging.info(f"Znaleziono {len(changelog_sections)} sekcji changelogów.")
|
logging.info(f"Znaleziono {len(changelog_sections)} sekcji changelogów.")
|
||||||
|
|
||||||
new_entries = 0
|
new_entries = 0
|
||||||
for section in changelog_sections:
|
results = []
|
||||||
a_tag = section.find("a")
|
# Używamy równoległego przetwarzania sekcji
|
||||||
if not a_tag:
|
with ThreadPoolExecutor(max_workers=8) as executor:
|
||||||
continue
|
futures = [executor.submit(process_section, section) for section in changelog_sections]
|
||||||
|
for future in as_completed(futures):
|
||||||
raw_text = a_tag.get_text(strip=True)
|
result = future.result()
|
||||||
match = re.match(r"([0-9.]+[a-zA-Z0-9]*)", raw_text)
|
if result is not None:
|
||||||
version_text = match.group(1) if match else raw_text
|
results.append(result)
|
||||||
|
|
||||||
# Pomijamy wersje, które nie zaczynają się od "6." lub "7."
|
|
||||||
if not (version_text.startswith("6.") or version_text.startswith("7.")):
|
|
||||||
logging.info(f"Pomijam wersję {version_text} – nie jest 6.x ani 7.x")
|
|
||||||
continue
|
|
||||||
|
|
||||||
details_div = section.find("div", class_="content")
|
|
||||||
changelog_file_url = details_div.get("data-url") if details_div else None
|
|
||||||
|
|
||||||
if not changelog_file_url:
|
|
||||||
logging.warning(f"Brak URL changeloga dla wersji {version_text}")
|
|
||||||
continue
|
|
||||||
|
|
||||||
try:
|
|
||||||
changelog_response = requests.get(changelog_file_url, timeout=10)
|
|
||||||
changelog_response.raise_for_status()
|
|
||||||
changelog_lines = changelog_response.text.splitlines()
|
|
||||||
|
|
||||||
if not changelog_lines:
|
|
||||||
logging.warning(f"Pusty changelog dla wersji {version_text}")
|
|
||||||
continue
|
|
||||||
|
|
||||||
first_line = changelog_lines[0].strip()
|
|
||||||
release_date_dt = parse_release_date(first_line)
|
|
||||||
if release_date_dt is None:
|
|
||||||
logging.warning(f"Nie udało się wyłuskać daty dla wersji {version_text}, pomijam ten changelog")
|
|
||||||
continue # Pomijamy wpis bez daty
|
|
||||||
|
|
||||||
changelog_text = "\n".join(changelog_lines).strip()
|
|
||||||
except Exception as e:
|
|
||||||
logging.error(f"Błąd pobierania changeloga z {changelog_file_url}: {e}")
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Filtrowanie: dla 7.x pomijamy wersje starsze niż 1 rok, dla 6.x starsze niż 2 lata
|
|
||||||
if version_text.startswith("7.") and release_date_dt < (current_date - timedelta(days=365)):
|
|
||||||
logging.info(f"Pomijam wersję {version_text} - starsza niż 1 rok")
|
|
||||||
continue
|
|
||||||
if version_text.startswith("6.") and release_date_dt < (current_date - timedelta(days=730)):
|
|
||||||
logging.info(f"Pomijam wersję {version_text} - starsza niż 2 lata")
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Określenie typu wydania (stable, rc, beta)
|
|
||||||
release_type = get_release_type(version_text)
|
|
||||||
|
|
||||||
|
# Dodajemy wyniki do bazy danych
|
||||||
|
for entry in results:
|
||||||
new_entry = ChangelogEntry(
|
new_entry = ChangelogEntry(
|
||||||
version=version_text,
|
version=entry["version"],
|
||||||
details=changelog_text,
|
details=entry["details"],
|
||||||
category="6.x" if version_text.startswith("6.") else "7.x",
|
category=entry["category"],
|
||||||
timestamp=release_date_dt,
|
timestamp=entry["timestamp"],
|
||||||
release_type=release_type
|
release_type=entry["release_type"]
|
||||||
)
|
)
|
||||||
db.session.add(new_entry)
|
db.session.add(new_entry)
|
||||||
new_entries += 1
|
new_entries += 1
|
||||||
@ -520,6 +554,8 @@ def fetch_changelogs(force=False):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(f"Błąd podczas pobierania changelogów: {e}")
|
logging.error(f"Błąd podczas pobierania changelogów: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def detect_anomalies():
|
def detect_anomalies():
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
# Ustal okres analizy, np. ostatnie 24 godziny
|
# Ustal okres analizy, np. ostatnie 24 godziny
|
||||||
@ -632,7 +668,7 @@ def register():
|
|||||||
password = request.form['password']
|
password = request.form['password']
|
||||||
# Prosta walidacja – warto rozszerzyć
|
# Prosta walidacja – warto rozszerzyć
|
||||||
if User.query.filter_by(username=username).first():
|
if User.query.filter_by(username=username).first():
|
||||||
flash("Użytkownik o tej nazwie już istnieje.")
|
flash("Użytkownik o tej nazwie już istnieje.", "error")
|
||||||
return redirect(url_for('register'))
|
return redirect(url_for('register'))
|
||||||
new_user = User(username=username, email=email)
|
new_user = User(username=username, email=email)
|
||||||
new_user.set_password(password)
|
new_user.set_password(password)
|
||||||
@ -642,7 +678,7 @@ def register():
|
|||||||
default_settings = Settings(user_id=new_user.id, check_interval=60)
|
default_settings = Settings(user_id=new_user.id, check_interval=60)
|
||||||
db.session.add(default_settings)
|
db.session.add(default_settings)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
flash("Rejestracja zakończona. Możesz się zalogować.")
|
flash("Rejestracja zakończona. Możesz się zalogować.", "success")
|
||||||
return redirect(url_for('login'))
|
return redirect(url_for('login'))
|
||||||
return render_template('register.html')
|
return render_template('register.html')
|
||||||
|
|
||||||
@ -655,10 +691,10 @@ def login():
|
|||||||
user = User.query.filter_by(username=username).first()
|
user = User.query.filter_by(username=username).first()
|
||||||
if user and user.check_password(password):
|
if user and user.check_password(password):
|
||||||
login_user(user)
|
login_user(user)
|
||||||
flash("Zalogowano pomyślnie.")
|
flash("Zalogowano pomyślnie.", "success")
|
||||||
return redirect(url_for('dashboard'))
|
return redirect(url_for('dashboard'))
|
||||||
else:
|
else:
|
||||||
flash("Nieprawidłowa nazwa użytkownika lub hasło.")
|
flash("Nieprawidłowa nazwa użytkownika lub hasło.", "error")
|
||||||
return render_template('login.html')
|
return render_template('login.html')
|
||||||
|
|
||||||
# Wylogowanie
|
# Wylogowanie
|
||||||
@ -666,7 +702,7 @@ def login():
|
|||||||
@login_required
|
@login_required
|
||||||
def logout():
|
def logout():
|
||||||
logout_user()
|
logout_user()
|
||||||
flash("Wylogowano.")
|
flash("Wylogowano.", "success")
|
||||||
return redirect(url_for('index'))
|
return redirect(url_for('index'))
|
||||||
|
|
||||||
# Lista urządzeń użytkownika
|
# Lista urządzeń użytkownika
|
||||||
@ -700,7 +736,7 @@ def add_device():
|
|||||||
)
|
)
|
||||||
db.session.add(new_device)
|
db.session.add(new_device)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
flash("Urządzenie dodane.")
|
flash("Urządzenie dodane.", "success")
|
||||||
return redirect(url_for('devices'))
|
return redirect(url_for('devices'))
|
||||||
return render_template('add_device.html')
|
return render_template('add_device.html')
|
||||||
|
|
||||||
@ -710,7 +746,7 @@ def add_device():
|
|||||||
def device_detail(device_id):
|
def device_detail(device_id):
|
||||||
device = Device.query.get_or_404(device_id)
|
device = Device.query.get_or_404(device_id)
|
||||||
if device.user_id != current_user.id:
|
if device.user_id != current_user.id:
|
||||||
flash("Brak dostępu.")
|
flash("Brak dostępu.", "error")
|
||||||
return redirect(url_for('devices'))
|
return redirect(url_for('devices'))
|
||||||
resource_data = {}
|
resource_data = {}
|
||||||
try:
|
try:
|
||||||
@ -774,7 +810,7 @@ def settings():
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
app.logger.error(f"Error rescheduling job: {e}")
|
app.logger.error(f"Error rescheduling job: {e}")
|
||||||
|
|
||||||
flash("Ustawienia zapisane.")
|
flash("Ustawienia zapisane.", "success")
|
||||||
return redirect(url_for('settings'))
|
return redirect(url_for('settings'))
|
||||||
return render_template('settings.html', settings=user_settings)
|
return render_template('settings.html', settings=user_settings)
|
||||||
|
|
||||||
@ -783,7 +819,7 @@ def settings():
|
|||||||
def edit_device(device_id):
|
def edit_device(device_id):
|
||||||
device = Device.query.get_or_404(device_id)
|
device = Device.query.get_or_404(device_id)
|
||||||
if device.user_id != current_user.id:
|
if device.user_id != current_user.id:
|
||||||
flash("Brak dostępu.")
|
flash("Brak dostępu.", "error")
|
||||||
return redirect(url_for('devices'))
|
return redirect(url_for('devices'))
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
device.name = request.form.get('name', device.name)
|
device.name = request.form.get('name', device.name)
|
||||||
@ -795,7 +831,7 @@ def edit_device(device_id):
|
|||||||
device.use_ssl = bool(request.form.get('use_ssl'))
|
device.use_ssl = bool(request.form.get('use_ssl'))
|
||||||
device.ssl_insecure = bool(request.form.get('ssl_insecure'))
|
device.ssl_insecure = bool(request.form.get('ssl_insecure'))
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
flash("Urządzenie zaktualizowane.")
|
flash("Urządzenie zaktualizowane.", "success")
|
||||||
return redirect(url_for('devices'))
|
return redirect(url_for('devices'))
|
||||||
return render_template('edit_device.html', device=device)
|
return render_template('edit_device.html', device=device)
|
||||||
|
|
||||||
@ -804,7 +840,7 @@ def edit_device(device_id):
|
|||||||
def force_check(device_id):
|
def force_check(device_id):
|
||||||
device = Device.query.get_or_404(device_id)
|
device = Device.query.get_or_404(device_id)
|
||||||
if device.user_id != current_user.id:
|
if device.user_id != current_user.id:
|
||||||
flash("Brak dostępu.")
|
flash("Brak dostępu.", "error")
|
||||||
return redirect(url_for('devices'))
|
return redirect(url_for('devices'))
|
||||||
result, update_available, current_version, current_firmware, upgrade_firmware = check_device_update(device)
|
result, update_available, current_version, current_firmware, upgrade_firmware = check_device_update(device)
|
||||||
device.last_log = result
|
device.last_log = result
|
||||||
@ -814,7 +850,7 @@ def force_check(device_id):
|
|||||||
device.current_firmware = current_firmware
|
device.current_firmware = current_firmware
|
||||||
device.upgrade_firmware = upgrade_firmware
|
device.upgrade_firmware = upgrade_firmware
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
flash("Sprawdzenie urządzenia zakończone.")
|
flash("Sprawdzenie urządzenia zakończone.", "success")
|
||||||
return redirect(url_for('devices'))
|
return redirect(url_for('devices'))
|
||||||
|
|
||||||
@app.route('/device/<int:device_id>/update', methods=['POST'])
|
@app.route('/device/<int:device_id>/update', methods=['POST'])
|
||||||
@ -822,7 +858,7 @@ def force_check(device_id):
|
|||||||
def update_device(device_id):
|
def update_device(device_id):
|
||||||
device = Device.query.get_or_404(device_id)
|
device = Device.query.get_or_404(device_id)
|
||||||
if device.user_id != current_user.id:
|
if device.user_id != current_user.id:
|
||||||
flash("Brak dostępu.")
|
flash("Brak dostępu.", "error")
|
||||||
return redirect(url_for('devices'))
|
return redirect(url_for('devices'))
|
||||||
try:
|
try:
|
||||||
app.logger.debug(f"Initiating system update for device {device.ip}")
|
app.logger.debug(f"Initiating system update for device {device.ip}")
|
||||||
@ -853,11 +889,11 @@ def update_device(device_id):
|
|||||||
db.session.add(history)
|
db.session.add(history)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
flash("Aktualizacja systemu została rozpoczęta.")
|
flash("Aktualizacja systemu została rozpoczęta.", "success")
|
||||||
app.logger.debug("System update command executed successfully")
|
app.logger.debug("System update command executed successfully")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
app.logger.error(f"Błąd podczas aktualizacji urządzenia {device.ip}: {e}", exc_info=True)
|
app.logger.error(f"Błąd podczas aktualizacji urządzenia {device.ip}: {e}", exc_info=True)
|
||||||
flash(f"Błąd podczas aktualizacji: {e}")
|
flash(f"Błąd podczas aktualizacji: {e}", "error")
|
||||||
return redirect(url_for('device_detail', device_id=device.id))
|
return redirect(url_for('device_detail', device_id=device.id))
|
||||||
|
|
||||||
@app.route('/device/<int:device_id>/update_firmware', methods=['POST'])
|
@app.route('/device/<int:device_id>/update_firmware', methods=['POST'])
|
||||||
@ -865,7 +901,7 @@ def update_device(device_id):
|
|||||||
def update_firmware(device_id):
|
def update_firmware(device_id):
|
||||||
device = Device.query.get_or_404(device_id)
|
device = Device.query.get_or_404(device_id)
|
||||||
if device.user_id != current_user.id:
|
if device.user_id != current_user.id:
|
||||||
flash("Brak dostępu.")
|
flash("Brak dostępu.", "error")
|
||||||
return redirect(url_for('devices'))
|
return redirect(url_for('devices'))
|
||||||
try:
|
try:
|
||||||
api = librouteros.connect(
|
api = librouteros.connect(
|
||||||
@ -886,9 +922,9 @@ def update_firmware(device_id):
|
|||||||
db.session.add(history)
|
db.session.add(history)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
flash("Aktualizacja firmware została rozpoczęta.")
|
flash("Aktualizacja firmware została rozpoczęta.", "success")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
flash(f"Błąd podczas aktualizacji firmware: {e}")
|
flash(f"Błąd podczas aktualizacji firmware: {e}", "error")
|
||||||
return redirect(url_for('device_detail', device_id=device.id))
|
return redirect(url_for('device_detail', device_id=device.id))
|
||||||
|
|
||||||
@app.route('/test_pushover', methods=['POST'])
|
@app.route('/test_pushover', methods=['POST'])
|
||||||
@ -896,7 +932,7 @@ def update_firmware(device_id):
|
|||||||
def test_pushover():
|
def test_pushover():
|
||||||
message = "To jest testowe powiadomienie Pushover z RouterOS Update."
|
message = "To jest testowe powiadomienie Pushover z RouterOS Update."
|
||||||
send_pushover_notification(current_user, message)
|
send_pushover_notification(current_user, message)
|
||||||
flash("Test powiadomienia Pushover wysłany.")
|
flash("Test powiadomienia Pushover wysłany.", "success")
|
||||||
return redirect(url_for('settings'))
|
return redirect(url_for('settings'))
|
||||||
|
|
||||||
@app.route('/test_email', methods=['POST'])
|
@app.route('/test_email', methods=['POST'])
|
||||||
@ -905,7 +941,7 @@ def test_email():
|
|||||||
subject = "Testowy E-mail z RouterOS Update"
|
subject = "Testowy E-mail z RouterOS Update"
|
||||||
message = "To jest testowa wiadomość e-mail wysłana z RouterOS Update."
|
message = "To jest testowa wiadomość e-mail wysłana z RouterOS Update."
|
||||||
send_email_notification(current_user, subject, message)
|
send_email_notification(current_user, subject, message)
|
||||||
flash("Testowy e-mail wysłany.")
|
flash("Testowy e-mail wysłany.", "success")
|
||||||
return redirect(url_for('settings'))
|
return redirect(url_for('settings'))
|
||||||
|
|
||||||
@app.route('/change_password', methods=['GET', 'POST'])
|
@app.route('/change_password', methods=['GET', 'POST'])
|
||||||
@ -916,14 +952,14 @@ def change_password():
|
|||||||
new_password = request.form.get('new_password')
|
new_password = request.form.get('new_password')
|
||||||
confirm_password = request.form.get('confirm_password')
|
confirm_password = request.form.get('confirm_password')
|
||||||
if not current_user.check_password(old_password):
|
if not current_user.check_password(old_password):
|
||||||
flash("Stare hasło jest nieprawidłowe.")
|
flash("Stare hasło jest nieprawidłowe.", "error")
|
||||||
return redirect(url_for('reset_password'))
|
return redirect(url_for('reset_password'))
|
||||||
if new_password != confirm_password:
|
if new_password != confirm_password:
|
||||||
flash("Nowe hasło i potwierdzenie nie są zgodne.")
|
flash("Nowe hasło i potwierdzenie nie są zgodne.", "warning")
|
||||||
return redirect(url_for('reset_password'))
|
return redirect(url_for('reset_password'))
|
||||||
current_user.set_password(new_password)
|
current_user.set_password(new_password)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
flash("Hasło zostało zresetowane.")
|
flash("Hasło zostało zresetowane.", "success")
|
||||||
return redirect(url_for('reset_password'))
|
return redirect(url_for('reset_password'))
|
||||||
return render_template('change_password.html')
|
return render_template('change_password.html')
|
||||||
|
|
||||||
@ -932,17 +968,17 @@ def change_password():
|
|||||||
def clean_logs():
|
def clean_logs():
|
||||||
days = request.form.get('days')
|
days = request.form.get('days')
|
||||||
if not days:
|
if not days:
|
||||||
flash("Podaj liczbę dni.")
|
flash("Podaj liczbę dni.", "warning")
|
||||||
return redirect(url_for('logs'))
|
return redirect(url_for('logs'))
|
||||||
try:
|
try:
|
||||||
days = int(days)
|
days = int(days)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
flash("Niepoprawna wartość dni.")
|
flash("Niepoprawna wartość dni.", "warning")
|
||||||
return redirect(url_for('logs'))
|
return redirect(url_for('logs'))
|
||||||
cutoff = datetime.utcnow() - timedelta(days=days)
|
cutoff = datetime.utcnow() - timedelta(days=days)
|
||||||
num_deleted = Log.query.filter(Log.user_id == current_user.id, Log.timestamp < cutoff).delete()
|
num_deleted = Log.query.filter(Log.user_id == current_user.id, Log.timestamp < cutoff).delete()
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
flash(f"Usunięto {num_deleted} logów starszych niż {days} dni.")
|
flash(f"Usunięto {num_deleted} logów starszych niż {days} dni.", "success")
|
||||||
return redirect(url_for('logs'))
|
return redirect(url_for('logs'))
|
||||||
|
|
||||||
@app.route('/update_history')
|
@app.route('/update_history')
|
||||||
@ -962,7 +998,7 @@ def anomalies():
|
|||||||
def update_selected_devices():
|
def update_selected_devices():
|
||||||
selected_ids = request.form.getlist('selected_devices')
|
selected_ids = request.form.getlist('selected_devices')
|
||||||
if not selected_ids:
|
if not selected_ids:
|
||||||
flash("Nie wybrano żadnych urządzeń.")
|
flash("Nie wybrano żadnych urządzeń.", "error")
|
||||||
return redirect(url_for('devices'))
|
return redirect(url_for('devices'))
|
||||||
for device_id in selected_ids:
|
for device_id in selected_ids:
|
||||||
device = Device.query.get(device_id)
|
device = Device.query.get(device_id)
|
||||||
@ -978,7 +1014,7 @@ def update_selected_devices():
|
|||||||
log_entry = Log(message=result, device_id=device.id, user_id=device.user_id)
|
log_entry = Log(message=result, device_id=device.id, user_id=device.user_id)
|
||||||
db.session.add(log_entry)
|
db.session.add(log_entry)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
flash("Wybrane urządzenia zostały zaktualizowane.")
|
flash("Wybrane urządzenia zostały zaktualizowane.", "success")
|
||||||
return redirect(url_for('devices'))
|
return redirect(url_for('devices'))
|
||||||
|
|
||||||
@app.route('/routeros_changelog')
|
@app.route('/routeros_changelog')
|
||||||
@ -1023,7 +1059,7 @@ def force_fetch_changelogs():
|
|||||||
def restart_device(device_id):
|
def restart_device(device_id):
|
||||||
device = Device.query.get_or_404(device_id)
|
device = Device.query.get_or_404(device_id)
|
||||||
if device.user_id != current_user.id:
|
if device.user_id != current_user.id:
|
||||||
flash("Brak dostępu.")
|
flash("Brak dostępu.", "error")
|
||||||
return redirect(url_for('devices'))
|
return redirect(url_for('devices'))
|
||||||
try:
|
try:
|
||||||
api = librouteros.connect(
|
api = librouteros.connect(
|
||||||
@ -1036,9 +1072,9 @@ def restart_device(device_id):
|
|||||||
# Wysyłamy komendę reboot
|
# Wysyłamy komendę reboot
|
||||||
list(api('/system/reboot'))
|
list(api('/system/reboot'))
|
||||||
|
|
||||||
flash("Komenda reboot została wysłana.")
|
flash("Komenda reboot została wysłana.", "success")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
flash(f"Błąd podczas wysyłania komendy reboot: {e}")
|
flash(f"Błąd podczas wysyłania komendy reboot: {e}", "error")
|
||||||
return ('', 204) # Zwracamy odpowiedź bez treści dla żądania AJAX
|
return ('', 204) # Zwracamy odpowiedź bez treści dla żądania AJAX
|
||||||
|
|
||||||
# Zamknięcie harmonogramu przy zatrzymaniu aplikacji
|
# Zamknięcie harmonogramu przy zatrzymaniu aplikacji
|
||||||
|
@ -145,6 +145,23 @@
|
|||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ========== Modal w trybie ciemny, ========== */
|
||||||
|
.dark-mode .modal-content {
|
||||||
|
background-color: #333;
|
||||||
|
color: #ddd;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
.dark-mode .modal-header,
|
||||||
|
.dark-mode .modal-footer {
|
||||||
|
border-color: #444;
|
||||||
|
}
|
||||||
|
.dark-mode .modal-title {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.dark-mode .btn-close {
|
||||||
|
filter: invert(1);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
{% block extra_head %}{% endblock %}
|
{% block extra_head %}{% endblock %}
|
||||||
</head>
|
</head>
|
||||||
|
@ -201,6 +201,11 @@ body.dark-mode .table-bordered > :not(caption) > * > * {
|
|||||||
<button id="mass-firmware-cancel-btn" class="btn btn-secondary ms-2">Anuluj</button>
|
<button id="mass-firmware-cancel-btn" class="btn btn-secondary ms-2">Anuluj</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Overlay informujący o zakończonym odświeżaniu -->
|
||||||
|
<div id="mass-update-overlay" style="display:none; position: fixed; top:0; left:0; width:100%; height:100%; background: rgba(0,0,0,0.7); z-index:1100; color:white; text-align:center; padding-top:200px;">
|
||||||
|
<h3>Polecnie odświeżenia urządzeń wykonane!</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Ten sam skrypt masowych akcji, przeniesiony bez zmian w logice
|
// Ten sam skrypt masowych akcji, przeniesiony bez zmian w logice
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
@ -241,12 +246,12 @@ body.dark-mode .table-bordered > :not(caption) > * > * {
|
|||||||
// Pokaż overlay z paskiem postępu (5 minut)
|
// Pokaż overlay z paskiem postępu (5 minut)
|
||||||
var overlay = document.getElementById('mass-system-update-overlay');
|
var overlay = document.getElementById('mass-system-update-overlay');
|
||||||
overlay.style.display = 'block';
|
overlay.style.display = 'block';
|
||||||
var timeLeft = 300; // 300 sekund
|
var timeLeft = 200; // 200 sekund
|
||||||
var progressBar = document.getElementById('mass-system-progress');
|
var progressBar = document.getElementById('mass-system-progress');
|
||||||
var timerDisplay = document.getElementById('mass-system-timer');
|
var timerDisplay = document.getElementById('mass-system-timer');
|
||||||
var interval = setInterval(function(){
|
var interval = setInterval(function(){
|
||||||
timeLeft--;
|
timeLeft--;
|
||||||
var percent = ((300 - timeLeft) / 300) * 100;
|
var percent = ((200 - timeLeft) / 200) * 100;
|
||||||
progressBar.style.width = percent + '%';
|
progressBar.style.width = percent + '%';
|
||||||
timerDisplay.textContent = timeLeft + ' sekund';
|
timerDisplay.textContent = timeLeft + ' sekund';
|
||||||
if(timeLeft <= 0){
|
if(timeLeft <= 0){
|
||||||
@ -298,12 +303,12 @@ body.dark-mode .table-bordered > :not(caption) > * > * {
|
|||||||
.then(function() {
|
.then(function() {
|
||||||
var overlay = document.getElementById('mass-firmware-update-overlay');
|
var overlay = document.getElementById('mass-firmware-update-overlay');
|
||||||
overlay.style.display = 'block';
|
overlay.style.display = 'block';
|
||||||
var timeLeft = 120; // 120 sekund
|
var timeLeft = 90; // 90 sekund
|
||||||
var progressBar = document.getElementById('mass-firmware-progress');
|
var progressBar = document.getElementById('mass-firmware-progress');
|
||||||
var timerDisplay = document.getElementById('mass-firmware-timer');
|
var timerDisplay = document.getElementById('mass-firmware-timer');
|
||||||
var interval = setInterval(function(){
|
var interval = setInterval(function(){
|
||||||
timeLeft--;
|
timeLeft--;
|
||||||
var percent = ((120 - timeLeft) / 120) * 100;
|
var percent = ((90 - timeLeft) / 90) * 100;
|
||||||
progressBar.style.width = percent + '%';
|
progressBar.style.width = percent + '%';
|
||||||
timerDisplay.textContent = timeLeft + ' sekund';
|
timerDisplay.textContent = timeLeft + ' sekund';
|
||||||
if(timeLeft <= 0){
|
if(timeLeft <= 0){
|
||||||
@ -319,19 +324,27 @@ body.dark-mode .table-bordered > :not(caption) > * > * {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Obsługa "Odśwież wybrane"
|
// Obsługa "Odśwież wybrane"
|
||||||
document.getElementById('mass-update-form').addEventListener('submit', function(e) {
|
document.getElementById('mass-update-form').addEventListener('submit', function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var selectedDevices = getSelectedDeviceIds();
|
var selectedDevices = getSelectedDeviceIds();
|
||||||
if(selectedDevices.length === 0) {
|
if (selectedDevices.length === 0) {
|
||||||
alert("Wybierz przynajmniej jedno urządzenie.");
|
alert("Wybierz przynajmniej jedno urządzenie.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Dla każdego wybranego urządzenia wykonaj force_check
|
||||||
selectedDevices.forEach(function(id) {
|
selectedDevices.forEach(function(id) {
|
||||||
fetch(`/device/${id}/force_check`, { method: 'GET' })
|
fetch(`/device/${id}/force_check`, { method: 'GET' })
|
||||||
.catch(function(error){ console.error('Błąd force check dla urządzenia ' + id, error); });
|
.catch(function(error) {
|
||||||
|
console.error('Błąd force check dla urządzenia ' + id, error);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
setTimeout(function(){ location.reload(); }, 2000);
|
// Pokaż overlay informujący o zakończonym odświeżaniu
|
||||||
|
document.getElementById('mass-update-overlay').style.display = 'block';
|
||||||
|
// Po 4 sekundach odśwież stronę
|
||||||
|
setTimeout(function() {
|
||||||
|
location.reload();
|
||||||
|
}, 4000);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -63,11 +63,10 @@
|
|||||||
<div class="card border-0 shadow">
|
<div class="card border-0 shadow">
|
||||||
<div class="card-header d-flex justify-content-between align-items-center">
|
<div class="card-header d-flex justify-content-between align-items-center">
|
||||||
<h4 class="mb-0">Changelog RouterOS</h4>
|
<h4 class="mb-0">Changelog RouterOS</h4>
|
||||||
<a href="{{ url_for('force_fetch_changelogs') }}"
|
<!-- Przycisk do wywołania aktualizacji changelogów -->
|
||||||
class="btn btn-danger btn-sm"
|
<a href="#" id="updateChangelog" class="btn btn-danger btn-sm">
|
||||||
onclick="return confirm('Czy na pewno chcesz ręcznie pobrać wszystkie changelogi? Operacja usunie wszystkie stare wpisy.');">
|
Aktualizuj changelogi
|
||||||
Aktualizuj changelogi
|
</a>
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
|
|
||||||
@ -151,4 +150,56 @@
|
|||||||
</div> <!-- /card-body -->
|
</div> <!-- /card-body -->
|
||||||
</div> <!-- /card -->
|
</div> <!-- /card -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Modal z progressem -->
|
||||||
|
<div class="modal fade" id="progressModal" tabindex="-1" role="dialog" aria-labelledby="progressModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="progressModalLabel">Pobieranie changelogów</h5>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="spinner-border" role="status">
|
||||||
|
<span class="visually-hidden">Ładowanie...</span>
|
||||||
|
</div>
|
||||||
|
<p>Proszę czekać, trwa pobieranie changelogów...</p>
|
||||||
|
<!-- Możesz dodać miejsce na logi, jeśli chcesz wyświetlać szczegóły postępu -->
|
||||||
|
<div id="progressLog" style="max-height:200px; overflow-y:auto;"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Upewnij się, że Bootstrap JS jest załadowany (np. przez CDN)
|
||||||
|
document.getElementById("updateChangelog").addEventListener("click", function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
// Pokaż modal
|
||||||
|
var progressModalEl = document.getElementById("progressModal");
|
||||||
|
var progressModal = new bootstrap.Modal(progressModalEl);
|
||||||
|
progressModal.show();
|
||||||
|
|
||||||
|
// Opcjonalnie wyczyść poprzednie logi
|
||||||
|
document.getElementById("progressLog").innerHTML = "";
|
||||||
|
|
||||||
|
// Wywołanie endpointu force_fetch_changelogs
|
||||||
|
fetch("{{ url_for('force_fetch_changelogs') }}")
|
||||||
|
.then(response => response.text())
|
||||||
|
.then(data => {
|
||||||
|
// Aktualizacja logu – możesz dodać otrzymane dane, jeśli są potrzebne
|
||||||
|
document.getElementById("progressLog").innerHTML += "<p>Pobieranie zakończone.</p>";
|
||||||
|
// Po krótkiej chwili zamknij modal i odśwież całą stronę
|
||||||
|
setTimeout(() => {
|
||||||
|
progressModal.hide();
|
||||||
|
location.reload();
|
||||||
|
}, 1000);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
document.getElementById("progressLog").innerHTML += "<p>Błąd: " + error + "</p>";
|
||||||
|
setTimeout(() => {
|
||||||
|
progressModal.hide();
|
||||||
|
}, 2000);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user