Added Repository

This commit is contained in:
2026-01-30 14:02:35 +03:30
parent 8917e625a5
commit dbc8f70b4a
53 changed files with 7758 additions and 2 deletions

7
routes/__init__.py Normal file
View File

@@ -0,0 +1,7 @@
from .main import main_bp
from .cart import cart_bp
from .auth import auth_bp
from .admin import admin_bp
from .user import user_bp
__all__ = ['main_bp', 'cart_bp', 'auth_bp', 'admin_bp', 'user_bp']

526
routes/admin.py Normal file
View File

@@ -0,0 +1,526 @@
from flask import Blueprint, render_template, redirect, url_for, flash, request, jsonify, current_app
from flask_login import login_required, current_user
from models import db, Product, Category, ProductImage, Review, SizeEnum, User, Order, OrderItem
import os
from werkzeug.utils import secure_filename
import json
from functools import wraps
from datetime import datetime
from sqlalchemy import func
admin_bp = Blueprint('admin', __name__, url_prefix='/admin')
def admin_required(func):
@wraps(func)
def wrapper(*args, **kwargs):
if not current_user.is_authenticated:
flash("Please login to access admin area", "danger")
return redirect(url_for('auth.login'))
if not current_user.is_admin:
flash("Admin access only!", "danger")
return redirect(url_for('main.home'))
return func(*args, **kwargs)
return wrapper
def allowed_file(filename):
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif', 'webp'}
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
def get_or_create_default_category():
default = Category.query.filter_by(name='Uncategorized').first()
if not default:
default = Category(name='Uncategorized')
db.session.add(default)
db.session.commit()
return default
def get_categories():
categories = Category.query.all()
if not categories:
default_cat = get_or_create_default_category()
categories = [default_cat]
return categories
def get_admin_stats():
try:
total_revenue_result = db.session.query(
func.sum(OrderItem.price_at_purchase * OrderItem.quantity)
).join(Order).filter(Order.status.in_(['delivered', 'completed'])).scalar()
total_revenue = float(
total_revenue_result) if total_revenue_result else 0.0
except:
total_revenue = 0.0
stats = {
'total_products': Product.query.count(),
'total_categories': Category.query.count(),
'total_reviews': Review.query.count(),
'total_orders': Order.query.count() if hasattr(Order, 'query') else 0,
'total_users': User.query.count() if hasattr(User, 'query') else 1,
'total_revenue': total_revenue,
'low_stock': Product.query.filter(Product.stock > 0, Product.stock <= 5).count(),
'out_of_stock': Product.query.filter(Product.stock == 0).count(),
'total_value': db.session.query(func.sum(Product.price * Product.stock)).scalar() or 0,
}
return stats
@admin_bp.route('/')
@login_required
@admin_required
def dashboard():
page = request.args.get('page', 1, type=int)
per_page = 20
products = Product.query.order_by(
Product.id.desc()).paginate(page=page, per_page=per_page)
stats = get_admin_stats()
return render_template('admin/dashboard.html',
products=products,
stats=stats,
SizeEnum=SizeEnum)
@admin_bp.route('/add', methods=['GET', 'POST'])
@login_required
@admin_required
def add_product():
if request.method == 'POST':
try:
name = request.form['name']
description = request.form.get('description', '')
price = float(request.form['price'])
stock = int(request.form.get('stock', 0))
sku = request.form.get('sku', '')
color = request.form.get('color', '')
size = request.form.get('size', '')
product_type = request.form.get('product_type', '')
material = request.form.get('material', '')
company = request.form.get('company', '')
weight = request.form.get('weight')
dimensions = request.form.get('dimensions', '')
if weight:
try:
weight = float(weight)
except ValueError:
weight = None
else:
weight = None
category_id = request.form.get('category_id')
if not category_id:
category = get_or_create_default_category()
category_id = category.id
product = Product(
name=name,
description=description,
price=price,
stock=stock,
sku=sku,
color=color,
size=size,
material=material,
company=company,
weight=weight,
dimensions=dimensions,
category_id=category_id
)
db.session.add(product)
db.session.flush()
if 'images[]' in request.files:
files = request.files.getlist('images[]')
for i, file in enumerate(files):
if file and file.filename and allowed_file(file.filename):
upload_dir = 'static/uploads/products'
os.makedirs(upload_dir, exist_ok=True)
filename = secure_filename(file.filename)
name_part, ext = os.path.splitext(filename)
unique_filename = f"{name_part}_{product.id}_{i}{ext}"
file_path = os.path.join(upload_dir, unique_filename)
file.save(file_path)
product_image = ProductImage(
product_id=product.id,
filename=unique_filename,
is_primary=(i == 0),
display_order=i
)
db.session.add(product_image)
db.session.commit()
flash(f"Product '{name}' added successfully!", "success")
return redirect(url_for('admin.dashboard'))
except Exception as e:
db.session.rollback()
flash(f"Error adding product: {str(e)}", "danger")
import traceback
traceback.print_exc()
categories = get_categories()
return render_template('admin/add_product.html',
categories=categories,
sizes=SizeEnum.ALL)
@admin_bp.route('/edit/<int:id>', methods=['GET', 'POST'])
@login_required
@admin_required
def edit_product(id):
product = Product.query.get_or_404(id)
if request.method == 'POST':
try:
product.name = request.form['name']
product.description = request.form.get('description', '')
product.price = float(request.form['price'])
product.stock = int(request.form.get('stock', 0))
product.sku = request.form.get('sku', '')
product.color = request.form.get('color', '')
product.size = request.form.get('size', '')
product.material = request.form.get('material', '')
product.company = request.form.get('company', '')
weight = request.form.get('weight')
if weight:
try:
product.weight = float(weight)
except ValueError:
product.weight = None
else:
product.weight = None
product.dimensions = request.form.get('dimensions', '')
category_id = request.form.get('category_id')
if category_id:
product.category_id = category_id
if 'images[]' in request.files:
files = request.files.getlist('images[]')
for i, file in enumerate(files):
if file and file.filename and allowed_file(file.filename):
upload_dir = 'static/uploads/products'
os.makedirs(upload_dir, exist_ok=True)
filename = secure_filename(file.filename)
name_part, ext = os.path.splitext(filename)
unique_filename = f"{name_part}_{product.id}_{len(product.images) + i}{ext}"
file_path = os.path.join(upload_dir, unique_filename)
file.save(file_path)
product_image = ProductImage(
product_id=product.id,
filename=unique_filename,
display_order=len(product.images) + i
)
db.session.add(product_image)
if 'deleted_images' in request.form:
deleted_images_str = request.form['deleted_images']
if deleted_images_str:
try:
deleted_ids = json.loads(deleted_images_str)
for img_id in deleted_ids:
image = ProductImage.query.get(img_id)
if image and image.product_id == product.id:
file_path = os.path.join(
'static/uploads/products', image.filename)
if os.path.exists(file_path):
os.remove(file_path)
db.session.delete(image)
except json.JSONDecodeError:
pass
if 'primary_image' in request.form:
primary_id = request.form['primary_image']
if primary_id:
try:
primary_id = int(primary_id)
for img in product.images:
img.is_primary = (img.id == primary_id)
except ValueError:
pass
db.session.commit()
flash("Product updated successfully!", "success")
return redirect(url_for('admin.dashboard'))
except Exception as e:
db.session.rollback()
flash(f"Error updating product: {str(e)}", "danger")
import traceback
traceback.print_exc()
categories = get_categories()
return render_template('admin/edit_product.html',
product=product,
categories=categories,
sizes=SizeEnum.ALL)
@admin_bp.route('/delete/<int:id>', methods=['POST'])
@login_required
@admin_required
def delete_product(id):
product = Product.query.get_or_404(id)
try:
for image in product.images:
file_path = os.path.join('static/uploads/products', image.filename)
if os.path.exists(file_path):
os.remove(file_path)
db.session.delete(product)
db.session.commit()
flash("Product deleted successfully!", "info")
except Exception as e:
flash(f"Error deleting product: {str(e)}", "danger")
return redirect(url_for('admin.dashboard'))
@admin_bp.route('/image/delete/<int:id>', methods=['POST'])
@login_required
@admin_required
def delete_image(id):
try:
image = ProductImage.query.get_or_404(id)
file_path = os.path.join('static/uploads/products', image.filename)
if os.path.exists(file_path):
os.remove(file_path)
db.session.delete(image)
db.session.commit()
return jsonify({'success': True})
except Exception as e:
return jsonify({'success': False, 'error': str(e)}), 500
@admin_bp.route('/reviews')
@login_required
@admin_required
def manage_reviews():
reviews = Review.query.order_by(Review.created_at.desc()).all()
return render_template('admin/reviews.html', reviews=reviews)
@admin_bp.route('/review/delete/<int:id>', methods=['POST'])
@login_required
@admin_required
def delete_review(id):
review = Review.query.get_or_404(id)
try:
db.session.delete(review)
db.session.commit()
flash("Review deleted successfully!", "info")
except Exception as e:
flash(f"Error deleting review: {str(e)}", "danger")
return redirect(url_for('admin.manage_reviews'))
@admin_bp.route('/categories')
@login_required
@admin_required
def manage_categories():
categories = Category.query.order_by(Category.name.asc()).all()
return render_template('admin/categories.html', categories=categories)
@admin_bp.route('/category/add', methods=['POST'])
@login_required
@admin_required
def add_category():
name = request.form.get('name', '').strip()
if not name:
flash("Category name cannot be empty", "danger")
return redirect(url_for('admin.manage_categories'))
existing = Category.query.filter_by(name=name).first()
if existing:
flash(f"Category '{name}' already exists", "warning")
return redirect(url_for('admin.manage_categories'))
try:
category = Category(name=name)
db.session.add(category)
db.session.commit()
flash(f"Category '{name}' added successfully!", "success")
except Exception as e:
flash(f"Error adding category: {str(e)}", "danger")
return redirect(url_for('admin.manage_categories'))
@admin_bp.route('/category/delete/<int:id>', methods=['POST'])
@login_required
@admin_required
def delete_category(id):
category = Category.query.get_or_404(id)
if category.products:
flash(
f"Cannot delete category '{category.name}' because it has {len(category.products)} product(s)", "danger")
return redirect(url_for('admin.manage_categories'))
try:
db.session.delete(category)
db.session.commit()
flash(f"Category '{category.name}' deleted successfully!", "info")
except Exception as e:
flash(f"Error deleting category: {str(e)}", "danger")
return redirect(url_for('admin.manage_categories'))
@admin_bp.route('/stats')
@login_required
@admin_required
def stats():
stats_data = get_admin_stats()
return render_template('admin/stats.html', stats=stats_data)
@admin_bp.route('/users')
@login_required
@admin_required
def manage_users():
users = User.query.order_by(User.id.desc()).all()
return render_template('admin/users.html', users=users)
@admin_bp.route('/user/toggle_admin/<int:id>', methods=['POST'])
@login_required
@admin_required
def toggle_user_admin(id):
user = User.query.get_or_404(id)
if user.id == current_user.id:
flash("You cannot remove admin privileges from yourself", "warning")
return redirect(url_for('admin.manage_users'))
try:
user.is_admin = not user.is_admin
db.session.commit()
status = "granted" if user.is_admin else "removed"
flash(f"Admin privileges {status} for {user.email}", "success")
except Exception as e:
flash(f"Error updating user: {str(e)}", "danger")
return redirect(url_for('admin.manage_users'))
@admin_bp.route('/user/delete/<int:id>', methods=['POST'])
@login_required
@admin_required
def delete_user(id):
user = User.query.get_or_404(id)
if user.id == current_user.id:
flash("You cannot delete your own account", "warning")
return redirect(url_for('admin.manage_users'))
try:
db.session.delete(user)
db.session.commit()
flash(f"User {user.email} deleted successfully", "info")
except Exception as e:
flash(f"Error deleting user: {str(e)}", "danger")
return redirect(url_for('admin.manage_users'))
@admin_bp.route('/orders')
@login_required
@admin_required
def manage_orders():
orders = Order.query.order_by(Order.created_at.desc()).all()
return render_template('admin/orders.html', orders=orders)
@admin_bp.route('/order/<int:id>')
@login_required
@admin_required
def order_detail(id):
order = Order.query.get_or_404(id)
return render_template('admin/order_detail.html', order=order)
@admin_bp.route('/order/update_status/<int:id>', methods=['POST'])
@login_required
@admin_required
def update_order_status(id):
order = Order.query.get_or_404(id)
new_status = request.form.get('status')
if new_status in ['pending', 'processing', 'shipped', 'delivered', 'cancelled']:
try:
order.status = new_status
db.session.commit()
flash(f"Order #{order.id} status updated to {new_status}", "success")
except Exception as e:
flash(f"Error updating order: {str(e)}", "danger")
else:
flash("Invalid status", "danger")
return redirect(url_for('admin.order_detail', id=id))
@admin_bp.route('/quick/restock_low')
@login_required
@admin_required
def quick_restock_low():
"""Quick action to restock low inventory items"""
try:
low_stock_products = Product.query.filter(
Product.stock > 0,
Product.stock <= 5
).all()
count = 0
for product in low_stock_products:
product.stock += 10
count += 1
if count > 0:
db.session.commit()
flash(f"Restocked {count} low inventory products", "success")
else:
flash("No low inventory products found", "info")
except Exception as e:
flash(f"Error restocking products: {str(e)}", "danger")
return redirect(url_for('admin.dashboard'))
@admin_bp.route('/quick/update_prices', methods=['POST'])
@login_required
@admin_required
def quick_update_prices():
"""Quick action to update prices by percentage"""
try:
percentage = float(request.form.get('percentage', 0))
if percentage != 0:
multiplier = 1 + (percentage / 100)
products = Product.query.all()
for product in products:
product.price = round(product.price * multiplier, 2)
db.session.commit()
action = "increased" if percentage > 0 else "decreased"
flash(
f"Prices {action} by {abs(percentage)}% for all products", "success")
else:
flash("No price change specified", "warning")
except Exception as e:
flash(f"Error updating prices: {str(e)}", "danger")
return redirect(url_for('admin.dashboard'))

43
routes/auth.py Normal file
View File

@@ -0,0 +1,43 @@
from flask import Blueprint, render_template, redirect, url_for, flash, request
from flask_login import login_user, logout_user, login_required, current_user
from models import db, User
from werkzeug.security import generate_password_hash, check_password_hash
auth_bp = Blueprint('auth', __name__)
@auth_bp.route('/register', methods=['GET', 'POST'])
def register():
if request.method == 'POST':
email = request.form['email']
password = request.form['password']
if User.query.filter_by(email=email).first():
flash("Email already registered", "danger")
return redirect(url_for('auth.register'))
user = User(email=email)
user.set_password(password)
db.session.add(user)
db.session.commit()
flash("Registered successfully!", "success")
return redirect(url_for('auth.login'))
return render_template('register.html')
@auth_bp.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
email = request.form['email']
password = request.form['password']
user = User.query.filter_by(email=email).first()
if user and user.check_password(password):
login_user(user)
flash("Logged in successfully!", "success")
next_page = request.args.get('next')
return redirect(next_page or url_for('main.home'))
flash("Invalid credentials", "danger")
return render_template('login.html')
@auth_bp.route('/logout')
@login_required
def logout():
logout_user()
flash("Logged out successfully!", "info")
return redirect(url_for('main.home'))

218
routes/cart.py Normal file
View File

@@ -0,0 +1,218 @@
from flask import Blueprint, render_template, redirect, url_for, flash, request
from flask_login import login_required, current_user
from models import db, Cart, CartItem, Product
cart_bp = Blueprint('cart', __name__)
@cart_bp.route('/cart')
@login_required
def view_cart():
cart = Cart.query.filter_by(user_id=current_user.id).first()
if not cart:
cart = Cart(user_id=current_user.id)
db.session.add(cart)
db.session.commit()
items = cart.items
total = 0
item_details = []
for item in items:
product = Product.query.get(item.product_id)
if product:
subtotal = product.price * item.quantity
total += subtotal
item_details.append({
'id': item.id,
'product': product,
'quantity': item.quantity,
'subtotal': subtotal,
'max_quantity': product.stock
})
return render_template('cart.html', items=item_details, total=total)
@cart_bp.route('/add/<int:product_id>')
@login_required
def add_to_cart(product_id):
cart = Cart.query.filter_by(user_id=current_user.id).first()
if not cart:
cart = Cart(user_id=current_user.id)
db.session.add(cart)
db.session.commit()
product = Product.query.get(product_id)
if not product:
flash("Product not found", "danger")
return redirect(url_for('main.products'))
if product.stock <= 0:
flash(f"Sorry, {product.name} is out of stock", "danger")
return redirect(url_for('main.products'))
cart_item = CartItem.query.filter_by(
cart_id=cart.id, product_id=product_id).first()
if cart_item:
if cart_item.quantity + 1 > product.stock:
flash(f"Only {product.stock} items available in stock", "warning")
return redirect(url_for('main.products'))
cart_item.quantity += 1
else:
cart_item = CartItem(cart_id=cart.id, product_id=product_id, quantity=1)
db.session.add(cart_item)
db.session.commit()
flash(f"Added {product.name} to cart!", "success")
referrer = request.referrer
if referrer and ('/product/' in referrer or '/products' in referrer):
return redirect(referrer)
return redirect(url_for('main.products'))
@cart_bp.route('/remove/<int:item_id>', methods=['POST'])
@login_required
def remove_from_cart(item_id):
cart_item = CartItem.query.get_or_404(item_id)
if cart_item.cart.user_id != current_user.id:
flash("You don't have permission to remove this item", "danger")
return redirect(url_for('cart.view_cart'))
product_name = cart_item.product.name
db.session.delete(cart_item)
db.session.commit()
flash(f"{product_name} removed from cart", "info")
return redirect(url_for('cart.view_cart'))
@cart_bp.route('/update/<int:item_id>', methods=['POST'])
@login_required
def update_cart(item_id):
cart_item = CartItem.query.get_or_404(item_id)
if cart_item.cart.user_id != current_user.id:
flash("You don't have permission to update this item", "danger")
return redirect(url_for('cart.view_cart'))
new_quantity = request.form.get('quantity')
product = Product.query.get(cart_item.product_id)
try:
new_quantity = int(new_quantity)
if new_quantity > 0:
if new_quantity > product.stock:
flash(
f"Only {product.stock} items available in stock. Quantity adjusted.", "warning")
new_quantity = product.stock
cart_item.quantity = new_quantity
db.session.commit()
flash("Cart updated", "success")
elif new_quantity == 0:
db.session.delete(cart_item)
db.session.commit()
flash("Item removed from cart", "info")
else:
flash("Quantity must be at least 0", "danger")
except ValueError:
flash("Invalid quantity", "danger")
return redirect(url_for('cart.view_cart'))
@cart_bp.route('/clear', methods=['POST'])
@login_required
def clear_cart():
cart = Cart.query.filter_by(user_id=current_user.id).first()
if cart:
items = cart.items
if items:
item_count = len(items)
CartItem.query.filter_by(cart_id=cart.id).delete()
db.session.commit()
flash(f"Cart cleared ({item_count} items removed)", "info")
else:
flash("Your cart is already empty", "info")
return redirect(url_for('cart.view_cart'))
@cart_bp.route('/checkout', methods=['GET', 'POST'])
@login_required
def checkout():
cart = Cart.query.filter_by(user_id=current_user.id).first()
if not cart or not cart.items:
flash("Your cart is empty", "warning")
return redirect(url_for('cart.view_cart'))
for item in cart.items:
product = Product.query.get(item.product_id)
if product.stock < item.quantity:
flash(
f"Sorry, {product.name} only has {product.stock} items in stock (you have {item.quantity} in cart)", "danger")
return redirect(url_for('cart.view_cart'))
if request.method == 'POST':
try:
total = 0
order_items = []
for item in cart.items:
product = Product.query.get(item.product_id)
product.stock -= item.quantity
total += product.price * item.quantity
order_items.append({
'product_id': product.id,
'quantity': item.quantity,
'price': product.price
})
from models import Order, OrderItem
from datetime import datetime
order = Order(user_id=current_user.id, created_at=datetime.utcnow())
db.session.add(order)
db.session.flush()
for item_data in order_items:
order_item = OrderItem(
order_id=order.id,
product_id=item_data['product_id'],
quantity=item_data['quantity']
)
db.session.add(order_item)
CartItem.query.filter_by(cart_id=cart.id).delete()
db.session.commit()
flash(f"Order placed successfully! Total: ${total:.2f}", "success")
return redirect(url_for('user.profile'))
except Exception as e:
db.session.rollback()
flash(f"Checkout failed: {str(e)}", "danger")
return redirect(url_for('cart.view_cart'))
total = sum(item.product.price * item.quantity for item in cart.items)
return render_template('checkout.html', cart=cart, total=total)
@cart_bp.route('/count')
@login_required
def cart_count():
cart = Cart.query.filter_by(user_id=current_user.id).first()
if cart:
count = sum(item.quantity for item in cart.items)
else:
count = 0
return str(count)

149
routes/main.py Normal file
View File

@@ -0,0 +1,149 @@
from flask import Blueprint, render_template, request
from flask_login import login_required, current_user
from models import Product, Category, SizeEnum, db
from sqlalchemy import or_, and_
from extensions import db
main_bp = Blueprint('main', __name__)
@main_bp.route('/')
def home():
featured_products = Product.query.order_by(Product.id.desc()).limit(8).all()
best_sellers = Product.query.order_by(
Product.stock.desc(),
Product.price.desc()
).limit(4).all()
categories = Category.query.all()
return render_template('home.html',
featured_products=featured_products,
best_sellers=best_sellers,
categories=categories)
@main_bp.route('/products')
def products():
search_query = request.args.get('q', '').strip()
category_id = request.args.get('category', '')
size = request.args.get('size', '')
color = request.args.get('color', '')
material = request.args.get('material', '')
company = request.args.get('company', '')
min_price = request.args.get('min_price', '')
max_price = request.args.get('max_price', '')
in_stock_only = request.args.get('in_stock') == '1'
sort_by = request.args.get('sort', 'newest')
query = Product.query
if search_query:
search_term = f"%{search_query}%"
query = query.filter(
or_(
Product.name.ilike(search_term),
Product.description.ilike(search_term),
Product.color.ilike(search_term),
Product.material.ilike(search_term),
Product.company.ilike(search_term),
Product.category.has(Category.name.ilike(search_term))
)
)
if category_id:
try:
query = query.filter(Product.category_id == int(category_id))
selected_category_name = Category.query.get(int(category_id)).name
except (ValueError, TypeError):
selected_category_name = None
else:
selected_category_name = None
if size:
query = query.filter(Product.size == size)
if color:
query = query.filter(Product.color.ilike(f"%{color}%"))
if material:
query = query.filter(Product.material.ilike(f"%{material}%"))
if company:
query = query.filter(Product.company.ilike(f"%{company}%"))
if min_price:
try:
query = query.filter(Product.price >= float(min_price))
except ValueError:
pass
if max_price:
try:
query = query.filter(Product.price <= float(max_price))
except ValueError:
pass
if in_stock_only:
query = query.filter(Product.stock > 0)
if sort_by == 'price_low':
query = query.order_by(Product.price.asc())
elif sort_by == 'price_high':
query = query.order_by(Product.price.desc())
elif sort_by == 'name':
query = query.order_by(Product.name.asc())
elif sort_by == 'rating':
query = query.order_by(Product.id.desc())
else:
query = query.order_by(Product.id.desc())
colors = db.session.query(Product.color).distinct().filter(
Product.color != None, Product.color != '').all()
colors = [c[0] for c in colors if c[0]]
materials = db.session.query(Product.material).distinct().filter(
Product.material != None, Product.material != '').all()
materials = [m[0] for m in materials if m[0]]
companies = db.session.query(Product.company).distinct().filter(
Product.company != None, Product.company != '').all()
companies = [c[0] for c in companies if c[0]]
products = query.all()
categories = Category.query.order_by(Category.name.asc()).all()
return render_template('products.html',
products=products,
categories=categories,
sizes=SizeEnum.ALL,
colors=colors,
materials=materials,
companies=companies,
search_query=search_query,
selected_category=category_id,
selected_category_name=selected_category_name,
selected_size=size,
selected_color=color,
selected_material=material,
selected_company=company,
min_price=min_price,
max_price=max_price,
sort_by=sort_by,
in_stock_only=in_stock_only)
@main_bp.route('/product/<int:id>')
def product_detail(id):
product = Product.query.get_or_404(id)
related_products = Product.query.filter(
Product.category_id == product.category_id,
Product.id != product.id
).limit(4).all()
return render_template('product_detail.html',
product=product,
related_products=related_products)

22
routes/user.py Normal file
View File

@@ -0,0 +1,22 @@
from flask import Blueprint, render_template, redirect, url_for, flash
from flask_login import login_required, current_user
from models import Order
user_bp = Blueprint('user', __name__)
@user_bp.route('/profile')
@login_required
def profile():
orders = Order.query.filter_by(user_id=current_user.id).all()
return render_template('user_profile.html', orders=orders)
@user_bp.route('/orders/<int:order_id>')
@login_required
def order_details(order_id):
order = Order.query.get_or_404(order_id)
if order.user_id != current_user.id:
flash("Access denied", "danger")
return redirect(url_for('user.profile'))
return render_template('order_details.html', order=order)