diff --git a/README.md b/README.md index 624765f..6da4e75 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ It will install the SystemGuard app and its dependencies in the crontab and it w ```bash # install miniconda3 if not installed already wget https://raw.githubusercontent.com/codeperfectplus/HackScripts/main/setup/install_miniconda.sh -chmod +x install_miniconda.sh && ./install_miniconda.sh +chmod +x install_miniconda.sh && sudo ./install_miniconda.sh ``` ## Features 🚀 @@ -84,6 +84,12 @@ chmod +x install_miniconda.sh && ./install_miniconda.sh A Docker image has not been created for this project because it requires access to the host machine in order to retrieve server stats. Therefore, it is not possible to obtain server stats from within a Docker container. +## Upcoming Features 📅 + +- Threshold notifications +- Customizable dashboards +- Plugin support to make SystemGuard even more powerful. + ## Acknowledgments | Project | License | Repository | diff --git a/src/models.py b/src/models.py index c0ac68a..64f96af 100644 --- a/src/models.py +++ b/src/models.py @@ -22,9 +22,36 @@ def __repr__(self): class DashboardSettings(db.Model): __tablename__ = "DashboardSettings" id = db.Column(db.Integer, primary_key=True) + + # speedtest setting speedtest_cooldown = db.Column(db.Integer, default=1) number_of_speedtests = db.Column(db.Integer, default=1) + + # general settings timezone = db.Column(db.String(50), default="Asia/Kolkata") + enable_cache = db.Column(db.Boolean, default=True) + + # page enable/disable + is_cpu_info_enabled = db.Column(db.Boolean, default=True) + is_memory_info_enabled = db.Column(db.Boolean, default=True) + is_disk_info_enabled = db.Column(db.Boolean, default=True) + is_network_info_enabled = db.Column(db.Boolean, default=True) + is_process_info_enabled = db.Column(db.Boolean, default=False) + + + # card enable/disable + is_user_card_enabled = db.Column(db.Boolean, default=True) + is_server_card_enabled = db.Column(db.Boolean, default=True) + is_battery_card_enabled = db.Column(db.Boolean, default=True) + is_cpu_core_card_enabled = db.Column(db.Boolean, default=True) + is_cpu_usage_card_enabled = db.Column(db.Boolean, default=True) + is_cpu_temp_card_enabled = db.Column(db.Boolean, default=True) + is_dashboard_memory_card_enabled = db.Column(db.Boolean, default=True) + is_memory_usage_card_enabled = db.Column(db.Boolean, default=True) + is_disk_usage_card_enabled = db.Column(db.Boolean, default=True) + is_system_uptime_card_enabled = db.Column(db.Boolean, default=True) + is_network_statistic_card_enabled = db.Column(db.Boolean, default=True) + is_speedtest_enabled = db.Column(db.Boolean, default=False) def __repr__(self): return f"" @@ -76,4 +103,10 @@ class User(db.Model, UserMixin): hashed_password = generate_password_hash('adminpassword') admin_user = User(username='admin', password=hashed_password, user_level='admin') db.session.add(admin_user) - db.session.commit() \ No newline at end of file + db.session.commit() + +# ibject for all templates +@app.context_processor +def inject_settings(): + settings = DashboardSettings.query.first() + return dict(settings=settings) diff --git a/src/routes/cpu_info.py b/src/routes/cpu_info.py index dde796d..d60c585 100644 --- a/src/routes/cpu_info.py +++ b/src/routes/cpu_info.py @@ -2,15 +2,21 @@ from flask import render_template, blueprints from src.config import app -from src.utils import get_cpu_core_count, get_cpu_frequency, cpu_usage_percent, get_cpu_temp +from src.utils import get_cpu_core_count, get_cpu_frequency, cpu_usage_percent, get_cpu_temp, get_cached_value +from src.models import DashboardSettings cpu_info_bp = blueprints.Blueprint("cpu_usage", __name__) @app.route("/cpu_usage") def cpu_usage(): + settings = DashboardSettings.query.first() + if not settings.is_cpu_info_enabled: + return render_template("error/404.html") + current_temp, high_temp, critical_temp = get_cpu_temp() + cpu_core = get_cached_value("cpu_core", get_cpu_core_count) system_info = { - "cpu_core": get_cpu_core_count(), + "cpu_core": cpu_core, "cpu_frequency": get_cpu_frequency(), "cpu_percent": cpu_usage_percent(), "current_temp": current_temp, diff --git a/src/routes/disk_info.py b/src/routes/disk_info.py index 39bce50..5841965 100644 --- a/src/routes/disk_info.py +++ b/src/routes/disk_info.py @@ -3,16 +3,22 @@ from flask import render_template, blueprints from src.config import app +from src.utils import get_cached_value, get_disk_free, get_disk_total, get_disk_used, get_disk_usage_percent +from src.models import DashboardSettings disk_info_bp = blueprints.Blueprint("disk_usage", __name__) @app.route("/disk_usage") def disk_usage(): + settings = DashboardSettings.query.first() + if not settings.is_disk_info_enabled: + return render_template("error/404.html") + disk_total = get_cached_value("disk_total", get_disk_total) system_info = { - "disk_usage": psutil.disk_usage("/").percent, - "disk_total": round(psutil.disk_usage("/").total / (1024**3), 2), # In GB - "disk_used": round(psutil.disk_usage("/").used / (1024**3), 2), # In GB - "disk_free": round(psutil.disk_usage("/").free / (1024**3), 2), # In GB + "disk_usage": get_disk_usage_percent(), + "disk_total": disk_total, + "disk_used": get_disk_used(), + "disk_free": get_disk_free(), } return render_template("disk_info.html", system_info=system_info) diff --git a/src/routes/homepage.py b/src/routes/homepage.py index 811ee25..2933e2d 100644 --- a/src/routes/homepage.py +++ b/src/routes/homepage.py @@ -1,5 +1,5 @@ import datetime -from flask import render_template, blueprints +from flask import render_template, blueprints, session from src.config import app from src.models import SpeedTestResult, DashboardSettings, SystemInfo diff --git a/src/routes/memory_info.py b/src/routes/memory_info.py index bd58f1c..d58216e 100644 --- a/src/routes/memory_info.py +++ b/src/routes/memory_info.py @@ -1,23 +1,26 @@ import psutil from flask import render_template, blueprints -from src.utils import swap_memory_info - from src.config import app +from src.utils import get_cached_value, get_memory_percent, get_memory_available, get_memory_used, get_swap_memory_info +from src.models import DashboardSettings memory_info_bp = blueprints.Blueprint("memory_usage", __name__) + @app.route("/memory_usage") def memory_usage(): - total_swap, used_swap, free_swap = swap_memory_info() + settings = DashboardSettings.query.first() + if not settings.is_memory_info_enabled: + return render_template("error/404.html") + memory_available = get_cached_value("memory_available", get_memory_available) system_info = { - "memory_percent": psutil.virtual_memory().percent, - "memory_available": round( - psutil.virtual_memory().available / (1024**3), 2 - ), # In GB - "memory_used": round(psutil.virtual_memory().used / (1024**3), 2), # In GB, - "total_swap": round(total_swap / (1024**3), 2), # In GB - "used_swap": round(used_swap / (1024**3), 2), # In GB - "free_swap": round(free_swap / (1024**3), 2), # In GB + "memory_percent": get_memory_percent(), + "memory_available": memory_available, + "memory_used": get_memory_used(), } + + swap_info = get_swap_memory_info() + system_info.update(swap_info) + return render_template("memory_info.html", system_info=system_info) diff --git a/src/routes/network_info.py b/src/routes/network_info.py index 8b37da4..0070f24 100644 --- a/src/routes/network_info.py +++ b/src/routes/network_info.py @@ -3,10 +3,15 @@ from src.config import app from src.utils import get_established_connections +from src.models import DashboardSettings + network_info_bp = blueprints.Blueprint("network_stats", __name__) @app.route("/network_stats") def network_stats(): + settings = DashboardSettings.query.first() + if not settings.is_network_info_enabled: + return render_template("error/404.html") net_io = psutil.net_io_counters() ipv4_ip, ipv6_ip = get_established_connections() system_info = { diff --git a/src/routes/process.py b/src/routes/process.py index f1b5cb1..0f9ff02 100644 --- a/src/routes/process.py +++ b/src/routes/process.py @@ -3,12 +3,16 @@ from flask_login import login_required, current_user from src.config import app from src.utils import get_top_processes +from src.models import DashboardSettings process_bp = blueprints.Blueprint("process", __name__) @app.route("/process", methods=["GET", "POST"]) @login_required def process(): + settings = DashboardSettings.query.first() + if not settings.is_process_info_enabled: + return render_template("error/404.html") if current_user.user_level != "admin": flash("You do not have permission to view this page.", "danger") return redirect(url_for("dashboard")) diff --git a/src/routes/settings.py b/src/routes/settings.py index 7a4b34b..27153c1 100644 --- a/src/routes/settings.py +++ b/src/routes/settings.py @@ -1,5 +1,4 @@ from flask import render_template, request, flash, blueprints - from src.config import app, db from src.models import DashboardSettings @@ -7,14 +6,37 @@ @app.route("/settings", methods=["GET", "POST"]) def settings(): - # Fetch the settings from the database and update them + # Fetch the settings from the database settings = DashboardSettings.query.first() if settings: if request.method == "POST": + # Update settings from the form inputs settings.speedtest_cooldown = int(request.form["speedtest_cooldown"]) settings.number_of_speedtests = int(request.form["number_of_speedtests"]) settings.timezone = request.form["timezone"] + settings.is_cpu_info_enabled = "is_cpu_info_enabled" in request.form + settings.is_memory_info_enabled = "is_memory_info_enabled" in request.form + settings.is_disk_info_enabled = "is_disk_info_enabled" in request.form + settings.is_network_info_enabled = "is_network_info_enabled" in request.form + settings.is_process_info_enabled = "is_process_info_enabled" in request.form + settings.enable_cache = "enable_cache" in request.form + + # + settings.is_user_card_enabled = "is_user_card_enabled" in request.form + settings.is_server_card_enabled = "is_server_card_enabled" in request.form + settings.is_battery_card_enabled = "is_battery_card_enabled" in request.form + settings.is_cpu_core_card_enabled = "is_cpu_core_card_enabled" in request.form + settings.is_cpu_usage_card_enabled = "is_cpu_usage_card_enabled" in request.form + settings.is_cpu_temp_card_enabled = "is_cpu_temp_card_enabled" in request.form + settings.is_dashboard_memory_card_enabled = "is_dashboard_memory_card_enabled" in request.form + settings.is_memory_usage_card_enabled = "is_memory_usage_card_enabled" in request.form + settings.is_disk_usage_card_enabled = "is_disk_usage_card_enabled" in request.form + settings.is_system_uptime_card_enabled = "is_system_uptime_card_enabled" in request.form + settings.is_network_statistic_card_enabled = "is_network_statistic_card_enabled" in request.form + settings.is_speedtest_enabled = "is_speedtest_enabled" in request.form + + # Commit the changes to the database db.session.commit() flash("Settings updated successfully!", "success") + return render_template("settings.html", settings=settings) - diff --git a/src/scripts/locustfile.py b/src/scripts/locustfile.py index 085e8cc..e1192b2 100644 --- a/src/scripts/locustfile.py +++ b/src/scripts/locustfile.py @@ -1,3 +1,5 @@ +import os + from locust import HttpUser, TaskSet, task, between from locust.exception import StopUser @@ -44,5 +46,4 @@ class WebsiteUser(HttpUser): wait_time = between(1, 5) # Time to wait between tasks if __name__ == "__main__": - import os - # os.system("locust -f locustfile.py --host=http://localhost:5000") + os.system("locust -f locustfile.py --host=http://localhost:5000") diff --git a/src/static/css/404.css b/src/static/css/404.css new file mode 100644 index 0000000..1ea0de0 --- /dev/null +++ b/src/static/css/404.css @@ -0,0 +1,35 @@ +.container { + text-align: center; + background-color: #ffffff; + padding: 30px 50px; + border-radius: 8px; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); +} + +h1 { + font-size: 100px; + margin: 0; + color: #dc3545; +} + +p { + font-size: 20px; + margin: 20px 0; + color: #6c757d; +} + +.btn { + display: inline-block; + padding: 10px 20px; + font-size: 16px; + color: #ffffff; + background-color: #007bff; + border: none; + border-radius: 4px; + text-decoration: none; + transition: background-color 0.3s ease; +} + +.btn:hover { + background-color: #0056b3; +} diff --git a/src/static/css/settings.css b/src/static/css/settings.css index b83761a..36ae2da 100644 --- a/src/static/css/settings.css +++ b/src/static/css/settings.css @@ -1,44 +1,94 @@ -.container { - max-width: 600px; - margin: auto; - background: white; +.settings-container { + max-width: 800px; + margin: 0 auto; padding: 20px; + background-color: #f8f9fa; border-radius: 8px; - box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); - margin-bottom: 10px; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); } -h1 { - margin-bottom: 20px; +.settings-title { + font-size: 32px; + color: #343a40; + margin-bottom: 30px; + text-align: center; +} + +.settings-form { + display: flex; + flex-direction: column; + gap: 20px; +} + +.settings-section { + border: 1px solid #dee2e6; + border-radius: 8px; + padding: 15px; + background-color: #ffffff; +} + +.section-title { font-size: 24px; + color: #495057; + margin-bottom: 15px; } .form-group { + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; margin-bottom: 15px; } .form-group label { - display: block; - margin-bottom: 5px; - font-weight: bold; + font-weight: 600; + color: #495057; } -.form-group input, +.form-group input[type="checkbox"] { + width: 20px; + height: 20px; + cursor: pointer; + margin: 0; +} + +.form-group input[type="number"], .form-group select { - width: 100%; padding: 8px; - box-sizing: border-box; + border: 1px solid #ced4da; + border-radius: 4px; + background-color: #ffffff; + font-size: 16px; + width: 100%; } -.btn { +.btn-primary { + padding: 12px 25px; background-color: #007bff; - color: white; - padding: 10px 15px; + color: #ffffff; border: none; - border-radius: 5px; + border-radius: 4px; cursor: pointer; + font-size: 16px; + text-align: center; + transition: background-color 0.3s ease; } -.btn:hover { +.btn-primary:hover { background-color: #0056b3; } + +@media (max-width: 768px) { + .settings-container { + padding: 15px; + } + + .settings-title { + font-size: 28px; + } + + .btn-primary { + width: 100%; + } +} diff --git a/src/static/css/style.css b/src/static/css/style.css index 7936fb4..22b2ad9 100644 --- a/src/static/css/style.css +++ b/src/static/css/style.css @@ -58,63 +58,67 @@ body { font-size: 2.5rem; } +/* Navbar Styles */ /* Navbar Styles */ .navbar { - background-color: #0056b3; /* Dark blue background */ - padding: 0.75rem 1rem; /* Increased padding for a more substantial navbar */ - box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); /* Soft shadow for depth */ - border-radius: 0.5rem; /* Slightly rounded corners */ + background-color: #ffffff; + border-bottom: 1px solid #dee2e6; + padding: 0.5rem 1rem; } .navbar-brand { - font-size: 1.75rem; /* Slightly larger and bolder for prominence */ - color: #000000; /* White text color for contrast */ - font-weight: bold; /* Added weight for emphasis */ + font-size: 1.5rem; + font-weight: bold; + color: #007bff; +} + +.navbar-nav { + display: flex; + align-items: center; } -.navbar-nav .nav-link { - color: #000000; /* White text color */ - font-size: 1.125rem; /* Slightly larger font for readability */ - padding: 0.5rem 1rem; /* More padding for clickable area */ - transition: color 0.3s ease, background-color 0.3s ease; /* Smooth transition */ +.nav-item { + margin-left: 1rem; } -.navbar-nav .nav-link:hover { - color: #0056b3; /* Blue text on hover */ - background-color: #f8f9fa; /* Light gray background on hover */ - border-radius: 0.25rem; +.nav-link { + color: #495057; + font-size: 1rem; + padding: 0.5rem 1rem; + border-radius: 4px; + transition: background-color 0.3s, color 0.3s; +} + +.nav-link:hover, .nav-link.active { + color: #ffffff; + background-color: #007bff; + text-decoration: none; } -/* Active Page Styling */ -.navbar-nav .nav-link.active { - background-color: #003d80; /* Darker blue for the active page */ - color: #ffffff; /* Keep the text white */ - border-radius: 0.25rem; /* Match the hover effect */ +.nav-link i { + font-size: 1.2rem; } .navbar-toggler { - border: none; /* Remove default border */ - outline: none; /* Remove focus outline */ - padding: 0.25rem 0.5rem; /* Smaller padding for a sleek look */ + border: none; } .navbar-toggler-icon { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24'%3E%3Cpath stroke='%23ffffff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' d='M4 6h16M4 12h16M4 18h16'/%3E%3C/svg%3E"); - filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.2)); /* Add subtle shadow */ + background-image: url('data:image/svg+xml;charset=utf8,...'); /* Include your own icon URL or SVG here */ } -/* Responsive Styles */ -@media (max-width: 767.98px) { - .navbar-nav .nav-link { - padding-right: 1rem; - padding-left: 1rem; - text-align: center; /* Center-align links on smaller screens */ - } +/* Add margin-right to space out authentication links */ +.navbar-nav.ml-auto .nav-item { + margin-left: 1rem; +} - .navbar-brand { - font-size: 1.5rem; /* Adjust brand size on smaller screens */ +/* Responsive adjustments */ +@media (max-width: 992px) { + .navbar-nav { + margin-top: 0.5rem; } } +/* end of navbar styles */ .btn-primary { margin-top: 1rem; /* Adds space above buttons */ diff --git a/src/templates/dasbhboard_comp/battery/percentage.html b/src/templates/dasbhboard_comp/battery/percentage.html index d4e5e84..6b98d8c 100644 --- a/src/templates/dasbhboard_comp/battery/percentage.html +++ b/src/templates/dasbhboard_comp/battery/percentage.html @@ -1 +1,10 @@ -
Battery Percentage

{{ system_info['battery_percent']}}%

\ No newline at end of file +{% if settings.is_battery_card_enabled %} +
+
+
+
Battery Percentage
+

{{ system_info['battery_percent']}}%

+
+
+
+{% endif %} \ No newline at end of file diff --git a/src/templates/dasbhboard_comp/cpu/core.html b/src/templates/dasbhboard_comp/cpu/core.html index 22ac313..bb9e620 100644 --- a/src/templates/dasbhboard_comp/cpu/core.html +++ b/src/templates/dasbhboard_comp/cpu/core.html @@ -1 +1,12 @@ -
CPU Cores

{{ system_info['cpu_core']}}

{% for i in range(system_info['cpu_core']) %}
{% endfor %}
\ No newline at end of file +{% if settings.is_cpu_core_card_enabled %} +
+
+
+
CPU Cores
+

{{ system_info['cpu_core']}}

+
{% for i in range(system_info['cpu_core']) %}
+
{% endfor %}
+
+
+
+{% endif %} \ No newline at end of file diff --git a/src/templates/dasbhboard_comp/cpu/current_temp.html b/src/templates/dasbhboard_comp/cpu/current_temp.html index 87f294c..dbc894d 100644 --- a/src/templates/dasbhboard_comp/cpu/current_temp.html +++ b/src/templates/dasbhboard_comp/cpu/current_temp.html @@ -1 +1,10 @@ -
CPU Temperature

{{ system_info['current_temp']}}%

\ No newline at end of file +{% if settings.is_cpu_temp_card_enabled %} +
+
+
+
CPU Temperature
+

{{ system_info['current_temp']}}%

+
+
+
+{% endif %} \ No newline at end of file diff --git a/src/templates/dasbhboard_comp/cpu/usages.html b/src/templates/dasbhboard_comp/cpu/usages.html index c8fa76b..de8fd7c 100644 --- a/src/templates/dasbhboard_comp/cpu/usages.html +++ b/src/templates/dasbhboard_comp/cpu/usages.html @@ -1 +1,10 @@ -
CPU Usage

{{ system_info['cpu_percent']}}%

\ No newline at end of file +{% if settings.is_cpu_usage_card_enabled %} +
+
+
+
CPU Usage
+

{{ system_info['cpu_percent']}}%

+
+
+
+{% endif %} \ No newline at end of file diff --git a/src/templates/dasbhboard_comp/disk/usage.html b/src/templates/dasbhboard_comp/disk/usage.html index f458d1f..2457c9e 100644 --- a/src/templates/dasbhboard_comp/disk/usage.html +++ b/src/templates/dasbhboard_comp/disk/usage.html @@ -1 +1,10 @@ -
Disk Usage

{{ system_info['disk_usage']}}%

\ No newline at end of file +{% if settings.is_disk_usage_card_enabled %} +
+
+
+
Disk Usage
+

{{ system_info['disk_usage']}}%

+
+
+
+{% endif %} \ No newline at end of file diff --git a/src/templates/dasbhboard_comp/memory/dashboard_memory.html b/src/templates/dasbhboard_comp/memory/dashboard_memory.html index 10b4282..bdb4a1b 100644 --- a/src/templates/dasbhboard_comp/memory/dashboard_memory.html +++ b/src/templates/dasbhboard_comp/memory/dashboard_memory.html @@ -1 +1,10 @@ -
Memory Usages(Dashboard)

{{ system_info['dashboard_memory_usage']}}

\ No newline at end of file +{% if settings.is_dashboard_memory_card_enabled %} +
+
+
+
Memory Usages(Dashboard)
+

{{ system_info['dashboard_memory_usage']}} MB

+
+
+
+{% endif %} \ No newline at end of file diff --git a/src/templates/dasbhboard_comp/memory/usage.html b/src/templates/dasbhboard_comp/memory/usage.html index cf7d4d9..3faf869 100644 --- a/src/templates/dasbhboard_comp/memory/usage.html +++ b/src/templates/dasbhboard_comp/memory/usage.html @@ -1 +1,10 @@ -
Memory Usage

{{ system_info['memory_percent']}}%

\ No newline at end of file +{% if settings.is_memory_usage_card_enabled %} +
+
+
+
Memory Usage
+

{{ system_info['memory_percent']}}%

+
+
+
+{% endif %} \ No newline at end of file diff --git a/src/templates/dasbhboard_comp/network/stats.html b/src/templates/dasbhboard_comp/network/stats.html index 47d9a5a..0b5d61e 100644 --- a/src/templates/dasbhboard_comp/network/stats.html +++ b/src/templates/dasbhboard_comp/network/stats.html @@ -1 +1,3 @@ -
Network Statistics

D:{{ system_info['network_sent']}} MB / U:{{ system_info['network_received']}} MB

\ No newline at end of file +{% if settings.is_network_statistic_card_enabled %} +
Network Statistics

D:{{ system_info['network_sent']}} MB / U:{{ system_info['network_received']}} MB

+{% endif %} \ No newline at end of file diff --git a/src/templates/dasbhboard_comp/other/boot_time.html b/src/templates/dasbhboard_comp/other/boot_time.html index 03eb341..49e482f 100644 --- a/src/templates/dasbhboard_comp/other/boot_time.html +++ b/src/templates/dasbhboard_comp/other/boot_time.html @@ -1,3 +1,4 @@ +{% if settings.is_server_card_enabled %}
@@ -6,15 +7,21 @@
Server Time
+{% endif %}