pgsql_mysql_docker #4
48
app.py
48
app.py
@@ -45,7 +45,7 @@ from config import Config
|
||||
from PIL import Image, ExifTags, ImageFilter, ImageOps
|
||||
from werkzeug.utils import secure_filename
|
||||
from werkzeug.middleware.proxy_fix import ProxyFix
|
||||
from sqlalchemy import func, extract
|
||||
from sqlalchemy import func, extract, inspect
|
||||
from collections import defaultdict, deque
|
||||
from functools import wraps
|
||||
|
||||
@@ -99,6 +99,7 @@ active_users = {}
|
||||
def utcnow():
|
||||
return datetime.now(timezone.utc)
|
||||
|
||||
app_start_time = utcnow()
|
||||
|
||||
class User(UserMixin, db.Model):
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
@@ -1386,6 +1387,30 @@ def admin_panel():
|
||||
process = psutil.Process(os.getpid())
|
||||
app_mem = process.memory_info().rss // (1024 * 1024) # MB
|
||||
|
||||
# Engine info
|
||||
db_engine = db.engine
|
||||
db_info = {
|
||||
"engine": db_engine.name,
|
||||
"version": getattr(db_engine.dialect, "server_version_info", None),
|
||||
"url": str(db_engine.url).split("?")[0],
|
||||
}
|
||||
|
||||
# Tabele
|
||||
inspector = inspect(db_engine)
|
||||
table_count = len(inspector.get_table_names())
|
||||
|
||||
# Rekordy (szybkie zliczenie)
|
||||
record_total = (
|
||||
db.session.query(func.count(User.id)).scalar()
|
||||
+ db.session.query(func.count(ShoppingList.id)).scalar()
|
||||
+ db.session.query(func.count(Item.id)).scalar()
|
||||
+ db.session.query(func.count(Receipt.id)).scalar()
|
||||
+ db.session.query(func.count(Expense.id)).scalar()
|
||||
)
|
||||
|
||||
# Uptime
|
||||
uptime_minutes = int((datetime.now(timezone.utc) - app_start_time).total_seconds() // 60)
|
||||
|
||||
return render_template(
|
||||
"admin/admin_panel.html",
|
||||
user_count=user_count,
|
||||
@@ -1401,6 +1426,11 @@ def admin_panel():
|
||||
python_version=sys.version,
|
||||
system_info=platform.platform(),
|
||||
app_memory=f"{app_mem} MB",
|
||||
|
||||
db_info=db_info,
|
||||
table_count=table_count,
|
||||
record_total=record_total,
|
||||
uptime_minutes=uptime_minutes,
|
||||
)
|
||||
|
||||
|
||||
@@ -1778,6 +1808,22 @@ def edit_list(list_id):
|
||||
flash("Nie znaleziono produktu", "danger")
|
||||
return redirect(url_for("edit_list", list_id=list_id))
|
||||
|
||||
elif action == "edit_quantity":
|
||||
item = db.session.get(Item, request.form.get("item_id"))
|
||||
if item and item.list_id == list_id:
|
||||
try:
|
||||
new_quantity = int(request.form.get("quantity"))
|
||||
if new_quantity > 0:
|
||||
item.quantity = new_quantity
|
||||
db.session.commit()
|
||||
flash("Zmieniono ilość produktu", "success")
|
||||
except ValueError:
|
||||
flash("Nieprawidłowa ilość", "danger")
|
||||
else:
|
||||
flash("Nie znaleziono produktu", "danger")
|
||||
return redirect(url_for("edit_list", list_id=list_id))
|
||||
|
||||
|
||||
return render_template(
|
||||
"admin/edit_list.html",
|
||||
list=l,
|
||||
|
@@ -1,11 +1,12 @@
|
||||
import os
|
||||
basedir = os.path.abspath(os.path.dirname(__file__))
|
||||
|
||||
class Config:
|
||||
SECRET_KEY = os.environ.get("SECRET_KEY", "D8pceNZ8q%YR7^7F&9wAC2")
|
||||
|
||||
DB_ENGINE = os.environ.get("DB_ENGINE", "sqlite").lower()
|
||||
if DB_ENGINE == "sqlite":
|
||||
SQLALCHEMY_DATABASE_URI = "sqlite:///instance/shopping.db"
|
||||
SQLALCHEMY_DATABASE_URI = f"sqlite:///{os.path.join(basedir, 'instance', 'shopping.db')}"
|
||||
elif DB_ENGINE == "pgsql":
|
||||
SQLALCHEMY_DATABASE_URI = f"postgresql://{os.environ['DB_USER']}:{os.environ['DB_PASSWORD']}@{os.environ['DB_HOST']}:{os.environ.get('DB_PORT', 5432)}/{os.environ['DB_NAME']}"
|
||||
elif DB_ENGINE == "mysql":
|
||||
|
@@ -198,6 +198,9 @@
|
||||
{% endblock %}
|
||||
|
||||
<div class="info-bar-fixed">
|
||||
Python: {{ python_version.split()[0] }} | {{ system_info }} | RAM app: {{ app_memory }}
|
||||
Python: {{ python_version.split()[0] }} | {{ system_info }} | RAM app: {{ app_memory }} |
|
||||
DB: {{ db_info.engine|upper }}{% if db_info.version %} v{{ db_info.version[0] }}{% endif %} |
|
||||
Tabele: {{ table_count }} | Rekordy: {{ record_total }} |
|
||||
Uptime: {{ uptime_minutes }} min
|
||||
</div>
|
||||
{% endblock %}
|
@@ -65,8 +65,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="mb-4">
|
||||
<label class="form-label">Link do udostępnienia</label>
|
||||
<input type="text" class="form-control bg-dark text-white border-secondary rounded" readonly
|
||||
@@ -111,7 +109,30 @@
|
||||
<tr>
|
||||
<td>
|
||||
<strong>{{ item.name }}</strong>
|
||||
<small class="text-muted">(x{{ item.quantity }})</small>
|
||||
<small class="text-small text-success">(x{{ item.quantity }})</small>
|
||||
|
||||
{% if item.note %}
|
||||
<div class="text-info small mt-1">
|
||||
<strong>Notatka:</strong> {{ item.note }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if item.not_purchased_reason %}
|
||||
<div class="text-warning small mt-1">
|
||||
<strong>Powód:</strong> {{ item.not_purchased_reason }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<form method="post" action="{{ url_for('edit_list', list_id=list.id) }}" class="mt-2">
|
||||
<input type="hidden" name="action" value="edit_quantity">
|
||||
<input type="hidden" name="item_id" value="{{ item.id }}">
|
||||
<div class="input-group input-group-sm ">
|
||||
<input type="number" name="quantity"
|
||||
class="form-control bg-dark text-white border-secondary rounded-left" min="1"
|
||||
value="{{ item.quantity }}">
|
||||
<button type="submit" class="btn btn-outline-light">💾</button>
|
||||
</div>
|
||||
</form>
|
||||
</td>
|
||||
<td>
|
||||
{% if item.purchased %}
|
||||
|
Reference in New Issue
Block a user