zmiany ux i w panelu

This commit is contained in:
Mateusz Gruszczyński
2025-07-03 12:50:09 +02:00
parent 79301398dd
commit 5d5779c09e
9 changed files with 302 additions and 66 deletions

144
app.py
View File

@ -13,6 +13,8 @@ from config import Config
from PIL import Image
from werkzeug.utils import secure_filename
from werkzeug.middleware.proxy_fix import ProxyFix
from sqlalchemy import func
app = Flask(__name__)
app.config.from_object(Config)
@ -47,6 +49,7 @@ class ShoppingList(db.Model):
share_token = db.Column(db.String(64), unique=True, nullable=True)
expires_at = db.Column(db.DateTime, nullable=True)
owner = db.relationship('User', backref='lists', lazy=True)
is_archived = db.Column(db.Boolean, default=False)
class Item(db.Model):
id = db.Column(db.Integer, primary_key=True)
@ -77,6 +80,14 @@ app.register_blueprint(static_bp)
def allowed_file(filename):
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
def get_progress(list_id):
items = Item.query.filter_by(list_id=list_id).all()
total_count = len(items)
purchased_count = len([i for i in items if i.purchased])
percent = (purchased_count / total_count * 100) if total_count > 0 else 0
return purchased_count, total_count, percent
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
@ -195,12 +206,24 @@ def view_list(list_id):
shopping_list = ShoppingList.query.get_or_404(list_id)
items = Item.query.filter_by(list_id=list_id).all()
total_count = len(items)
purchased_count = len([i for i in items if i.purchased])
percent = (purchased_count / total_count * 100) if total_count > 0 else 0
receipt_pattern = f"list_{list_id}"
all_files = os.listdir(app.config['UPLOAD_FOLDER'])
receipt_files = [f for f in all_files if receipt_pattern in f]
return render_template('list.html', list=shopping_list, items=items, receipt_files=receipt_files)
return render_template(
'list.html',
list=shopping_list,
items=items,
receipt_files=receipt_files,
total_count=total_count,
purchased_count=purchased_count,
percent=percent
)
@app.route('/share/<token>')
def share_list(token):
@ -297,11 +320,56 @@ def update_note(item_id):
def admin_panel():
if not current_user.is_admin:
return redirect(url_for('index_guest'))
user_count = User.query.count()
list_count = ShoppingList.query.count()
item_count = Item.query.count()
all_lists = ShoppingList.query.options(db.joinedload(ShoppingList.owner)).all()
return render_template('admin/admin_panel.html', user_count=user_count, list_count=list_count, item_count=item_count, all_lists=all_lists)
# Pobierz folder uploadów
all_files = os.listdir(app.config['UPLOAD_FOLDER'])
enriched_lists = []
for l in all_lists:
items = Item.query.filter_by(list_id=l.id).all()
total_count = len(items)
purchased_count = len([i for i in items if i.purchased])
percent = (purchased_count / total_count * 100) if total_count > 0 else 0
comments_count = len([i for i in items if i.note and i.note.strip() != ''])
purchased_items_count = Item.query.filter_by(purchased=True).count()
receipt_pattern = f"list_{l.id}"
receipt_files = [f for f in all_files if receipt_pattern in f]
enriched_lists.append({
'list': l,
'total_count': total_count,
'purchased_count': purchased_count,
'percent': round(percent),
'comments_count': comments_count,
'receipts_count': len(receipt_files)
})
top_products = (
db.session.query(Item.name, func.count(Item.id).label('count'))
.filter(Item.purchased == True)
.group_by(Item.name)
.order_by(func.count(Item.id).desc())
.limit(5)
.all()
)
return render_template(
'admin/admin_panel.html',
user_count=user_count,
list_count=list_count,
item_count=item_count,
purchased_items_count=purchased_items_count,
enriched_lists=enriched_lists,
top_products=top_products,
)
@app.route('/admin/delete_list/<int:list_id>')
@login_required
@ -392,7 +460,6 @@ def admin_receipts():
upload_folder=app.config['UPLOAD_FOLDER']
)
@app.route('/admin/delete_receipt/<filename>')
@login_required
def delete_receipt(filename):
@ -406,6 +473,56 @@ def delete_receipt(filename):
flash('Plik nie istnieje', 'danger')
return redirect(url_for('admin_receipts'))
@app.route('/admin/edit_list/<int:list_id>', methods=['GET', 'POST'])
@login_required
def edit_list(list_id):
if not current_user.is_admin:
return redirect(url_for('index_guest'))
l = ShoppingList.query.get_or_404(list_id)
if request.method == 'POST':
new_title = request.form.get('title')
if new_title:
l.title = new_title
db.session.commit()
flash('Zaktualizowano tytuł listy', 'success')
return redirect(url_for('admin_panel'))
return render_template('admin/edit_list.html', list=l)
@app.route('/admin/delete_selected_lists', methods=['POST'])
@login_required
def delete_selected_lists():
if not current_user.is_admin:
return redirect(url_for('index_guest'))
ids = request.form.getlist('list_ids')
for list_id in ids:
lst = ShoppingList.query.get(int(list_id))
if lst:
Item.query.filter_by(list_id=lst.id).delete()
db.session.delete(lst)
db.session.commit()
flash('Usunięto wybrane listy', 'success')
return redirect(url_for('admin_panel'))
@app.route('/admin/archive_list/<int:list_id>')
@login_required
def archive_list(list_id):
if not current_user.is_admin:
return redirect(url_for('index_guest'))
l = ShoppingList.query.get_or_404(list_id)
l.is_archived = True
db.session.commit()
flash('Lista oznaczona jako archiwalna', 'success')
return redirect(url_for('admin_panel'))
@app.route('/admin/delete_all_items')
@login_required
def delete_all_items():
if not current_user.is_admin:
return redirect(url_for('index_guest'))
Item.query.delete()
db.session.commit()
flash('Usunięto wszystkie produkty', 'success')
return redirect(url_for('admin_panel'))
@socketio.on('delete_item')
def handle_delete_item(data):
@ -460,7 +577,16 @@ def handle_check_item(data):
item.purchased = True
item.purchased_at = datetime.utcnow()
db.session.commit()
purchased_count, total_count, percent = get_progress(item.list_id)
emit('item_checked', {'item_id': item.id}, to=str(item.list_id))
emit('progress_updated', {
'purchased_count': purchased_count,
'total_count': total_count,
'percent': percent
}, to=str(item.list_id))
@socketio.on('uncheck_item')
def handle_uncheck_item(data):
@ -469,7 +595,15 @@ def handle_uncheck_item(data):
item.purchased = False
item.purchased_at = None
db.session.commit()
purchased_count, total_count, percent = get_progress(item.list_id)
emit('item_unchecked', {'item_id': item.id}, to=str(item.list_id))
emit('progress_updated', {
'purchased_count': purchased_count,
'total_count': total_count,
'percent': percent
}, to=str(item.list_id))
@socketio.on('update_note')
def handle_update_note(data):
@ -481,6 +615,8 @@ def handle_update_note(data):
db.session.commit()
emit('note_updated', {'item_id': item_id, 'note': note}, to=str(item.list_id))
@app.cli.command('create_db')
def create_db():
db.create_all()