diff --git a/app.py b/app.py index 01d37ff..b6ff207 100644 --- a/app.py +++ b/app.py @@ -1,6 +1,11 @@ from shopping_app import app, socketio, APP_PORT, DEBUG_MODE from shopping_app.app_setup import logging +from shopping_app.startup_info import print_startup_info + if __name__ == "__main__": logging.basicConfig(level=logging.DEBUG if DEBUG_MODE else logging.INFO) + + print_startup_info(app) + socketio.run(app, host="0.0.0.0", port=APP_PORT, debug=False) diff --git a/shopping_app.zip b/shopping_app.zip new file mode 100644 index 0000000..ee69d35 Binary files /dev/null and b/shopping_app.zip differ diff --git a/shopping_app/app_setup.py b/shopping_app/app_setup.py index b141970..a267e78 100644 --- a/shopping_app/app_setup.py +++ b/shopping_app/app_setup.py @@ -94,6 +94,18 @@ def read_commit(filename="version.txt", root_path=None): except Exception: return None + +def get_file_md5(path): + try: + digest = hashlib.md5() + with open(path, "rb") as f: + for chunk in iter(lambda: f.read(8192), b""): + digest.update(chunk) + return digest.hexdigest()[:12] + except Exception: + return "dev" + + commit = read_commit("version.txt", root_path=os.path.dirname(os.path.dirname(__file__))) or "dev" APP_VERSION = commit app.config["APP_VERSION"] = APP_VERSION diff --git a/shopping_app/startup_info.py b/shopping_app/startup_info.py new file mode 100644 index 0000000..44e02a4 --- /dev/null +++ b/shopping_app/startup_info.py @@ -0,0 +1,95 @@ +import os +import sys +import platform +import socket +from datetime import datetime + +import psutil + +try: + from sqlalchemy import text +except Exception: + text = None + +def mb(x): + return int(x / 1024 / 1024) + + +def get_db_type(app): + uri = app.config.get("SQLALCHEMY_DATABASE_URI") or app.config.get("DATABASE_URL", "") + + if not uri: + return "NONE" + + if uri.startswith("sqlite"): + return "SQLite" + if uri.startswith("mysql"): + return "MySQL" + if uri.startswith("postgresql"): + return "PostgreSQL" + + return "OTHER" + +def print_startup_info(app): + host = os.getenv("HOST", "127.0.0.1") + port = int(os.getenv("PORT", "8000")) + + rules = list(app.url_map.iter_rules()) + + cpu = psutil.cpu_percent(interval=0.2) + ram = psutil.virtual_memory() + proc = psutil.Process(os.getpid()) + + db_type = get_db_type(app) + + print("\n" + "="*52) + print(" APP START") + print("="*52) + + # SYSTEM + print("\n[ SYSTEM ]") + print(f"Time : {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") + print(f"OS : {platform.system()} {platform.release()} ({platform.machine()})") + print(f"Python : {sys.version.split()[0]}") + print(f"Host : {socket.gethostname()}") + + # SERVER + print("\n[ SERVER ]") + print(f"Bind : {host}:{port}") + print(f"URL : http://127.0.0.1:{port}") + + # APP + print("\n[ APP ]") + print(f"Name : {app.name}") + print(f"Mode : {'DEV' if app.debug else 'PROD'}") + print(f"Debug : {app.debug}") + + # RESOURCES + print("\n[ RESOURCES ]") + print(f"CPU : {cpu:>5.1f}%") + print(f"RAM : {ram.percent:>5.1f}% ({mb(ram.used)} / {mb(ram.total)} MB)") + print(f"PROC : {mb(proc.memory_info().rss)} MB") + + # DATABASE + print("\n[ DATABASE ]") + print(f"Type : {db_type}") + + # SECURITY + print("\n[ SECURITY ]") + print(f"Secret : {'OK' if app.config.get('SECRET_KEY') else 'MISSING'}") + print(f"Talis : {'OFF' if app.config.get('TALISMAN_DISABLED') else 'ON'}") + + # HEALTH + print("\n[ HEALTH ]") + print(f"Uploads: {'OK' if os.path.exists('uploads') else 'MISS'}") + print(f"Static : {'OK' if os.path.exists(app.static_folder) else 'MISS'}") + + # ROUTES + print("\n[ ROUTES ]") + print(f"Total : {len(rules)}") + + # STATUS + print("\n[ STATUS ]") + print("READY") + + print("="*52 + "\n") \ No newline at end of file diff --git a/shopping_app/static/css/style.css b/shopping_app/static/css/style.css index a2eeeee..78a32b9 100644 --- a/shopping_app/static/css/style.css +++ b/shopping_app/static/css/style.css @@ -5259,3 +5259,93 @@ body:not(.sorting-active) .drag-handle { min-width: 44px !important; } } + + +/* wyróżnienie pola dodawania produktu */ +.endpoint-list .shopping-entry-card, +.endpoint-list_share .shopping-entry-card, +.endpoint-shared_list .shopping-entry-card, +.endpoint-view_list .shopping-entry-card { + background: linear-gradient(180deg, rgba(25, 135, 84, 0.16), rgba(13, 17, 23, 0.92)); + border: 1px solid rgba(25, 135, 84, 0.42); + border-radius: 1rem; + padding: .9rem; + box-shadow: 0 .5rem 1.2rem rgba(0, 0, 0, 0.18); +} + +.endpoint-list .shopping-entry-card__label, +.endpoint-list_share .shopping-entry-card__label, +.endpoint-shared_list .shopping-entry-card__label, +.endpoint-view_list .shopping-entry-card__label { + display: inline-flex; + align-items: center; + gap: .4rem; + margin-bottom: .2rem; + font-size: .95rem; + font-weight: 700; + color: #d1f7df; +} + +.endpoint-list .shopping-entry-card__hint, +.endpoint-list_share .shopping-entry-card__hint, +.endpoint-shared_list .shopping-entry-card__hint, +.endpoint-view_list .shopping-entry-card__hint { + margin-bottom: .75rem; + color: rgba(255, 255, 255, 0.72); + font-size: .82rem; + line-height: 1.35; +} + +.endpoint-list .shopping-entry-card .shopping-product-input-group, +.endpoint-list_share .shopping-entry-card .shopping-product-input-group, +.endpoint-shared_list .shopping-entry-card .shopping-product-input-group, +.endpoint-view_list .shopping-entry-card .shopping-product-input-group { + margin-bottom: 0 !important; +} + +.endpoint-list .shopping-entry-card .shopping-product-input-group > .form-control, +.endpoint-list_share .shopping-entry-card .shopping-product-input-group > .form-control, +.endpoint-shared_list .shopping-entry-card .shopping-product-input-group > .form-control, +.endpoint-view_list .shopping-entry-card .shopping-product-input-group > .form-control { + border-color: rgba(25, 135, 84, 0.55) !important; + background: rgba(17, 24, 39, 0.95) !important; +} + +.endpoint-list .shopping-entry-card .shopping-product-input-group > .form-control::placeholder, +.endpoint-list_share .shopping-entry-card .shopping-product-input-group > .form-control::placeholder, +.endpoint-shared_list .shopping-entry-card .shopping-product-input-group > .form-control::placeholder, +.endpoint-view_list .shopping-entry-card .shopping-product-input-group > .form-control::placeholder { + color: rgba(255, 255, 255, 0.62); +} + +.endpoint-list .shopping-entry-card .shopping-product-input-group > .shopping-product-name-input:focus, +.endpoint-list_share .shopping-entry-card .shopping-product-input-group > .shopping-product-name-input:focus, +.endpoint-shared_list .shopping-entry-card .shopping-product-input-group > .shopping-product-name-input:focus, +.endpoint-view_list .shopping-entry-card .shopping-product-input-group > .shopping-product-name-input:focus { + box-shadow: inset 0 0 0 1px rgba(25, 135, 84, 0.25), 0 0 0 .2rem rgba(25, 135, 84, 0.18); +} + +@media (max-width: 767.98px) { + .endpoint-list .shopping-entry-card, + .endpoint-list_share .shopping-entry-card, + .endpoint-shared_list .shopping-entry-card, + .endpoint-view_list .shopping-entry-card { + padding: .8rem; + border-radius: .95rem; + } + + .endpoint-list .shopping-entry-card__label, + .endpoint-list_share .shopping-entry-card__label, + .endpoint-shared_list .shopping-entry-card__label, + .endpoint-view_list .shopping-entry-card__label { + font-size: .92rem; + } + + .endpoint-list .shopping-entry-card__hint, + .endpoint-list_share .shopping-entry-card__hint, + .endpoint-shared_list .shopping-entry-card__hint, + .endpoint-view_list .shopping-entry-card__hint { + font-size: .78rem; + margin-bottom: .65rem; + } +} diff --git a/shopping_app/static/js/live.js b/shopping_app/static/js/live.js index e134d5e..4538a12 100644 --- a/shopping_app/static/js/live.js +++ b/shopping_app/static/js/live.js @@ -13,7 +13,7 @@ function toggleEmptyPlaceholder() { const li = document.createElement('li'); li.id = 'empty-placeholder'; li.className = 'list-group-item bg-dark text-secondary text-center w-100'; - li.textContent = 'Brak produktów w tej liście.'; + li.textContent = 'Brak produktów w tej liście.'; list.appendChild(li); } else if (hasRealItems && placeholder) { placeholder.remove(); @@ -206,7 +206,7 @@ function setupList(listId, username) { const progressTitle = document.getElementById('progress-title'); if (progressTitle) { - progressTitle.textContent = `📊 Postęp listy — ${data.purchased_count}/${data.total_count} kupionych (${Math.round(data.percent)}%)`; + progressTitle.textContent = `Postęp listy — ${data.purchased_count}/${data.total_count} kupionych (${Math.round(data.percent)}%)`; } }); diff --git a/shopping_app/templates/admin/admin_panel.html b/shopping_app/templates/admin/admin_panel.html index f735f5f..441b36b 100644 --- a/shopping_app/templates/admin/admin_panel.html +++ b/shopping_app/templates/admin/admin_panel.html @@ -341,7 +341,7 @@ checkboxes.forEach(cb => cb.checked = this.checked); }); - + {% endblock %} {% endblock %} \ No newline at end of file diff --git a/shopping_app/templates/admin/edit_categories.html b/shopping_app/templates/admin/edit_categories.html index c9dfad7..5466d26 100644 --- a/shopping_app/templates/admin/edit_categories.html +++ b/shopping_app/templates/admin/edit_categories.html @@ -146,6 +146,6 @@ {% endblock %} {% block scripts %} - - + + {% endblock %} \ No newline at end of file diff --git a/shopping_app/templates/admin/edit_list.html b/shopping_app/templates/admin/edit_list.html index 7845906..ff8b1e8 100644 --- a/shopping_app/templates/admin/edit_list.html +++ b/shopping_app/templates/admin/edit_list.html @@ -303,5 +303,5 @@ {% endblock %} {% block scripts %} - + {% endblock %} \ No newline at end of file diff --git a/shopping_app/templates/admin/list_products.html b/shopping_app/templates/admin/list_products.html index b669026..89f2328 100644 --- a/shopping_app/templates/admin/list_products.html +++ b/shopping_app/templates/admin/list_products.html @@ -170,8 +170,8 @@ {% block scripts %} - - + + {% endblock %} {% endblock %} \ No newline at end of file diff --git a/shopping_app/templates/admin/lists_access.html b/shopping_app/templates/admin/lists_access.html index 3dd2198..c10326e 100644 --- a/shopping_app/templates/admin/lists_access.html +++ b/shopping_app/templates/admin/lists_access.html @@ -181,7 +181,7 @@ {% endblock %} {% block scripts %} - - + + {% endblock %} \ No newline at end of file diff --git a/shopping_app/templates/admin/receipts.html b/shopping_app/templates/admin/receipts.html index 1b4f5e2..a5ccd0a 100644 --- a/shopping_app/templates/admin/receipts.html +++ b/shopping_app/templates/admin/receipts.html @@ -224,8 +224,8 @@ endpoint: "/admin/crop_receipt" }; - - + + {% endblock %} {% endblock %} \ No newline at end of file diff --git a/shopping_app/templates/admin/settings.html b/shopping_app/templates/admin/settings.html index b9b7671..b9c7cba 100644 --- a/shopping_app/templates/admin/settings.html +++ b/shopping_app/templates/admin/settings.html @@ -153,6 +153,6 @@ {% endblock %} {% block scripts %} - - + + {% endblock %} diff --git a/shopping_app/templates/admin/user_management.html b/shopping_app/templates/admin/user_management.html index 4581550..8dc1265 100644 --- a/shopping_app/templates/admin/user_management.html +++ b/shopping_app/templates/admin/user_management.html @@ -121,7 +121,7 @@ {% block scripts %} - + {% endblock %} diff --git a/shopping_app/templates/base.html b/shopping_app/templates/base.html index 740e09a..5651049 100644 --- a/shopping_app/templates/base.html +++ b/shopping_app/templates/base.html @@ -6,25 +6,25 @@