From 04c1e6d49acd4f2f0bb8db62faf16d137677f754 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Gruszczy=C5=84ski?= Date: Mon, 24 Feb 2025 10:18:52 +0100 Subject: [PATCH] new options --- __pycache__/app.cpython-313.pyc | Bin 0 -> 40308 bytes app.py | 53 +++++++++++++++++++++----------- instance/database.db | Bin 0 -> 90112 bytes requirements.txt | 3 +- routeros_update.service | 14 +++++++++ run_waitress.py | 9 ++++++ templates/logs.html | 13 ++++++++ templates/settings.html | 12 ++++++-- 8 files changed, 81 insertions(+), 23 deletions(-) create mode 100644 __pycache__/app.cpython-313.pyc create mode 100644 instance/database.db create mode 100644 routeros_update.service create mode 100644 run_waitress.py diff --git a/__pycache__/app.cpython-313.pyc b/__pycache__/app.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..911c414b2cddd61b247cdcb62e0635ba597e2cad GIT binary patch literal 40308 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 literal 0 HcmV?d00001 diff --git a/app.py b/app.py index 46f6810..0203a95 100644 --- a/app.py +++ b/app.py @@ -31,7 +31,6 @@ login_manager = LoginManager(app) login_manager.login_view = 'login' # MODELE BAZY DANYCH - class User(UserMixin, db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(80), unique=True, nullable=False) @@ -45,7 +44,6 @@ class User(UserMixin, db.Model): def check_password(self, password): return check_password_hash(self.password_hash, password) - class Device(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(120)) @@ -62,7 +60,6 @@ class Device(db.Model): use_ssl = db.Column(db.Boolean, default=False) # Czy używać SSL? ssl_insecure = db.Column(db.Boolean, default=False) # Jeśli True – nie weryfikować certyfikatu SSL user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) - class Settings(db.Model): id = db.Column(db.Integer, primary_key=True) pushover_user_key = db.Column(db.String(255)) @@ -73,16 +70,17 @@ class Settings(db.Model): smtp_username = db.Column(db.String(255)) smtp_password = db.Column(db.String(255)) email_notifications_enabled = db.Column(db.Boolean, default=False) - check_interval = db.Column(db.Integer, default=60) # interwał sprawdzania w sekundach - log_retention_days = db.Column(db.Integer, default=30) # nowe pole – retencja logów w dniach + check_interval = db.Column(db.Integer, default=60) + log_retention_days = db.Column(db.Integer, default=30) + recipient_email = db.Column(db.String(120)) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False, unique=True) - class Log(db.Model): id = db.Column(db.Integer, primary_key=True) timestamp = db.Column(db.DateTime, default=datetime.utcnow) message = db.Column(db.Text) device_id = db.Column(db.Integer, db.ForeignKey('device.id')) user_id = db.Column(db.Integer, db.ForeignKey('user.id')) + device = db.relationship('Device', backref='logs') # Inicjalizacja bazy (utworzyć bazę przy pierwszym uruchomieniu) with app.app_context(): @@ -110,21 +108,21 @@ def send_pushover_notification(user, message): print("Błąd przy wysyłaniu powiadomienia Pushover:", e) def send_email_notification(user, subject, message): - # Sprawdzamy, czy ustawienia e-mail są poprawnie skonfigurowane if not user.settings or not user.settings.email_notifications_enabled or not user.settings.smtp_server: return try: - # Uzyskujemy sformatowaną treść e-maila html_body = get_email_template(subject, message) msg = MIMEText(html_body, 'html') msg["Subject"] = subject msg["From"] = user.settings.smtp_username - msg["To"] = user.email + # Używamy adresu z ustawień, jeśli został podany, lub domyślnie adresu z profilu użytkownika + to_email = user.settings.recipient_email if user.settings.recipient_email else user.email + msg["To"] = to_email s = smtplib.SMTP(user.settings.smtp_server, user.settings.smtp_port) s.starttls() s.login(user.settings.smtp_username, user.settings.smtp_password) - s.sendmail(user.settings.smtp_username, [user.email], msg.as_string()) + s.sendmail(user.settings.smtp_username, [to_email], msg.as_string()) s.quit() app.logger.debug("E-mail wysłany pomyślnie") except Exception as e: @@ -271,7 +269,9 @@ def check_all_devices(): device.current_firmware = current_firmware db.session.commit() # Zapis do tabeli logów - 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) + log_message = f"Urządzenie {device.name or device.ip} - {result}" + log_entry = Log(message=log_message, device_id=device.id, user_id=device.user_id) db.session.add(log_entry) db.session.commit() # Powiadomienia, jeśli dostępna aktualizacja @@ -487,27 +487,29 @@ def settings(): user_settings.smtp_username = request.form.get('smtp_username') user_settings.smtp_password = request.form.get('smtp_password') user_settings.email_notifications_enabled = bool(request.form.get('email_notifications_enabled')) + # Aktualizacja adresu e-mail odbiorcy (może być inny niż email z profilu) + user_settings.recipient_email = request.form.get('recipient_email') # Aktualizacja interwału sprawdzania interval = request.form.get('check_interval') user_settings.check_interval = int(interval) if interval else 60 # Aktualizacja retencji logów retention = request.form.get('log_retention_days') user_settings.log_retention_days = int(retention) if retention else 30 - + db.session.commit() - - # Aktualizacja interwału zadania scheduler'a, jeśli masz takie zadanie + try: scheduler.reschedule_job("check_all_devices", trigger="interval", seconds=user_settings.check_interval) app.logger.debug(f"Scheduler rescheduled with new interval: {user_settings.check_interval} seconds") except Exception as e: app.logger.error(f"Error rescheduling job: {e}") - + flash("Ustawienia zapisane.") return redirect(url_for('settings')) return render_template('settings.html', settings=user_settings) + @app.route('/device//edit', methods=['GET', 'POST']) @login_required def edit_device(device_id): @@ -529,7 +531,6 @@ def edit_device(device_id): return redirect(url_for('devices')) return render_template('edit_device.html', device=device) - @app.route('/device//force_check') @login_required def force_check(device_id): @@ -581,8 +582,6 @@ def update_device(device_id): flash(f"Błąd podczas aktualizacji: {e}") return redirect(url_for('device_detail', device_id=device.id)) - - @app.route('/device//update_firmware', methods=['POST']) @login_required def update_firmware(device_id): @@ -641,6 +640,24 @@ def reset_password(): return redirect(url_for('reset_password')) return render_template('reset_password.html') +@app.route('/logs/clean', methods=['POST']) +@login_required +def clean_logs(): + days = request.form.get('days') + if not days: + flash("Podaj liczbę dni.") + return redirect(url_for('logs')) + try: + days = int(days) + except ValueError: + flash("Niepoprawna wartość dni.") + return redirect(url_for('logs')) + cutoff = datetime.utcnow() - timedelta(days=days) + num_deleted = Log.query.filter(Log.user_id == current_user.id, Log.timestamp < cutoff).delete() + db.session.commit() + flash(f"Usunięto {num_deleted} logów starszych niż {days} dni.") + return redirect(url_for('logs')) + # Zamknięcie harmonogramu przy zatrzymaniu aplikacji atexit.register(lambda: scheduler.shutdown()) diff --git a/instance/database.db b/instance/database.db new file mode 100644 index 0000000000000000000000000000000000000000..6c69bc2850b87fa56f824a63b27b1e7c13a7e687 GIT binary patch literal 90112 zcmeI)?Qh%09l&wQPAp4_tz=p11w$}mXb~HYRX&KKVXr3yiROCUfJe$pUj=a3KUb$1L%4_%5<+Y8Km78)l)9w4) zon5zA>-*wm$32igUaH>uaH%@08OGeu9&S6V(UIT3cW^dQT1rt7=;<_l!d<-{0%>oENsbEz4`x+MU2_c(xUIowi>~Xp_C|+B-F`9f)RG z&C``fAtpMUC=LT*&tg_}<2mYW?`Gd;srHz$!Syyh#J=gZSp4h7v zHT0wqRZ}9zkE+Y7OVv&JZe>%R^_(bgV{Q5VMn#@IZdsIf`(CxOd}l4(?<8NYR&H0S zm9<-y2XeS?R6us_vmc*J&s@8f`rYMdFgWh6XS?z1`JsUj=Y7jC80wBei@okp5X0l< zxsHu%h(^&1Wepv8ykqzIUJffA+OcW*K`rV``2#Ve*Oyl-;RuSdMVH9ym51wL#@W4E z?^$ho`y__2fx0g@Z-MMdp5dH_7pv9_j|ptU&Sc*#Sl0t&#1F0V2=0w%il{;|_iHxk~7iFzdUbIVorE^k|QBPd+d& z5&l#?^{3IE>))8xzc(>4bL)Ca^4gBO?>}yetEZaP4?5BB;`|by<7(>Qr*!T=sZZY+ zomUX(k(El%T)mol`c5=;gi~yo#)c-3Fy~ulk8tzQsi5@S1pne`a%lb^oFQu4mj7%L zSGCgcX(DM_Iel6Un=o{)jjEl?&fOTFnEBb&vj$z*`kEHLp1U#joja=Gj^m=ECd1AO zFX~gdMM*q)Ab<)W!7Zb2lyY*+XvRcw4zhj6su?$nxofURd=moLp5E^v|P1rXGL78+`lF9mHv=1I0?v{5SZIrg|?yi=9ZZ)jo|i}I2A-pOE;-0z zctes{1+-i?UV|W~lY=y(AjJZv<W=IX`d zc#JTfLc!3B`e?;-AvqpBipMA@=7`0UO^!#6`$tiX(rEQhCNZ8uIqn}3jyhWLOeV(@ z%?AZT+=Z%*Ry^tCcn0%A;+aT}C!P<);@ifEjkoj3@x=3iURLxGo8QhQ#-kt4 z2YSgUjMjJ?PmU*^5A>2*98eO?iIfp3TsnXU0tg_000IagfB*srAbVxmnE(I) literal 0 HcmV?d00001 diff --git a/requirements.txt b/requirements.txt index 77bdbf0..c4a8411 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,5 +4,4 @@ Flask-Login APScheduler librouteros requests -gunicorn -requests \ No newline at end of file +waitress \ No newline at end of file diff --git a/routeros_update.service b/routeros_update.service new file mode 100644 index 0000000..c546e3f --- /dev/null +++ b/routeros_update.service @@ -0,0 +1,14 @@ +[Unit] +Description=RouterOS Update Waitress Service +After=network.target + +[Service] +#User=routeros +#Group=routeros +WorkingDirectory=/opt/routeros_update +ExecStart=/opt/routeros_update/venv/bin/python3 /opt/routeros_update/run_waitress.py +Restart=always +Environment=PYTHONUNBUFFERED=1 + +[Install] +WantedBy=multi-user.target diff --git a/run_waitress.py b/run_waitress.py new file mode 100644 index 0000000..130f934 --- /dev/null +++ b/run_waitress.py @@ -0,0 +1,9 @@ +from waitress import serve +from app import app, scheduler, clean_old_logs +import atexit + +with app.app_context(): + scheduler.add_job(func=clean_old_logs, trigger="interval", days=1) + atexit.register(lambda: scheduler.shutdown()) + +serve(app, host='0.0.0.0', port=5582, ident='', threads=4) diff --git a/templates/logs.html b/templates/logs.html index 0c55026..06b695f 100644 --- a/templates/logs.html +++ b/templates/logs.html @@ -2,6 +2,18 @@ {% block title %}Logi - Aplikacja Updatera{% endblock %} {% block content %}

Logi

+ +
+

Usuń logi starsze niż podana liczba dni

+
+
+ + +
+ +
+
+
@@ -30,4 +42,5 @@ {% endfor %}
+ {% endblock %} diff --git a/templates/settings.html b/templates/settings.html index eeab883..d500a5d 100644 --- a/templates/settings.html +++ b/templates/settings.html @@ -46,12 +46,18 @@ - +
+ E-mail odbiorcy powiadomień +
+ + +
+
Interwał sprawdzania
- - + +