Files
digital-garage-sale/app/admin/routes.py
2025-04-29 13:54:11 -07:00

257 lines
9.7 KiB
Python

import os
import uuid
from functools import wraps
from datetime import datetime
from flask import render_template, redirect, url_for, request, flash, session, current_app, send_file
from werkzeug.utils import secure_filename
from app.admin import bp
from app.models import Category, Item, ContactInfo
from app import db
import pdfkit
def admin_required(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if 'admin_authenticated' not in session:
return redirect(url_for('admin.login'))
return f(*args, **kwargs)
return decorated_function
def allowed_file(filename):
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
@bp.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
password = request.form.get('password')
if password == current_app.config['ADMIN_PASSWORD']:
session['admin_authenticated'] = True
return redirect(url_for('admin.dashboard'))
else:
flash('Invalid password', 'danger')
return render_template('admin/login.html', title='Admin Login')
@bp.route('/')
@admin_required
def dashboard():
return render_template('admin/dashboard.html', title='Admin Dashboard')
@bp.route('/categories')
@admin_required
def categories():
categories = Category.query.all()
return render_template('admin/categories.html',
title='Manage Categories',
categories=categories)
@bp.route('/category/add', methods=['GET', 'POST'])
@admin_required
def add_category():
if request.method == 'POST':
name = request.form.get('name')
if name:
# Check if category already exists
existing = Category.query.filter_by(name=name).first()
if existing:
flash(f'Category "{name}" already exists', 'warning')
else:
category = Category(name=name)
db.session.add(category)
db.session.commit()
flash(f'Category "{name}" added successfully', 'success')
return redirect(url_for('admin.categories'))
else:
flash('Category name is required', 'danger')
return render_template('admin/add_category.html', title='Add Category')
@bp.route('/category/<int:id>/delete', methods=['POST'])
@admin_required
def delete_category(id):
category = Category.query.get_or_404(id)
if category:
db.session.delete(category)
db.session.commit()
flash(f'Category "{category.name}" deleted successfully', 'success')
return redirect(url_for('admin.categories'))
@bp.route('/items')
@admin_required
def items():
items = Item.query.order_by(Item.created_at.desc()).all()
return render_template('admin/items.html',
title='Manage Items',
items=items)
@bp.route('/item/add', methods=['GET', 'POST'])
@admin_required
def add_item():
categories = Category.query.all()
if request.method == 'POST':
title = request.form.get('title')
description = request.form.get('description')
price = request.form.get('price')
category_id = request.form.get('category_id')
status = request.form.get('status', 'For Sale')
if title and description and price and category_id:
try:
price = float(price)
item = Item(
title=title,
description=description,
price=price,
category_id=category_id,
status=status
)
# Handle image upload
if 'image' in request.files:
file = request.files['image']
if file and file.filename and allowed_file(file.filename):
# Create a unique filename
filename = secure_filename(file.filename)
unique_filename = f"{uuid.uuid4().hex}_{filename}"
file.save(os.path.join(current_app.config['UPLOAD_FOLDER'], unique_filename))
item.image_filename = unique_filename
db.session.add(item)
db.session.commit()
flash(f'Item "{title}" added successfully', 'success')
return redirect(url_for('admin.items'))
except ValueError:
flash('Price must be a number', 'danger')
else:
flash('All fields are required', 'danger')
return render_template('admin/add_item.html',
title='Add Item',
categories=categories)
@bp.route('/item/<int:id>/edit', methods=['GET', 'POST'])
@admin_required
def edit_item(id):
item = Item.query.get_or_404(id)
categories = Category.query.all()
if request.method == 'POST':
title = request.form.get('title')
description = request.form.get('description')
price = request.form.get('price')
category_id = request.form.get('category_id')
status = request.form.get('status')
if title and description and price and category_id and status:
try:
price = float(price)
item.title = title
item.description = description
item.price = price
item.category_id = category_id
item.status = status
item.updated_at = datetime.utcnow()
# Handle image upload
if 'image' in request.files:
file = request.files['image']
if file and file.filename and allowed_file(file.filename):
# Delete old image if it exists
if item.image_filename:
old_image_path = os.path.join(current_app.config['UPLOAD_FOLDER'], item.image_filename)
if os.path.exists(old_image_path):
os.remove(old_image_path)
# Create a unique filename
filename = secure_filename(file.filename)
unique_filename = f"{uuid.uuid4().hex}_{filename}"
file.save(os.path.join(current_app.config['UPLOAD_FOLDER'], unique_filename))
item.image_filename = unique_filename
db.session.commit()
flash(f'Item "{title}" updated successfully', 'success')
return redirect(url_for('admin.items'))
except ValueError:
flash('Price must be a number', 'danger')
else:
flash('All fields are required', 'danger')
return render_template('admin/edit_item.html',
title='Edit Item',
item=item,
categories=categories)
@bp.route('/item/<int:id>/delete', methods=['POST'])
@admin_required
def delete_item(id):
item = Item.query.get_or_404(id)
if item:
# Delete image file if exists
if item.image_filename:
image_path = os.path.join(current_app.config['UPLOAD_FOLDER'], item.image_filename)
if os.path.exists(image_path):
os.remove(image_path)
db.session.delete(item)
db.session.commit()
flash(f'Item "{item.title}" deleted successfully', 'success')
return redirect(url_for('admin.items'))
@bp.route('/information', methods=['GET', 'POST'])
@admin_required
def edit_contact():
contact_info = ContactInfo.query.first()
# Create default contact info if it doesn't exist
if not contact_info:
contact_info = ContactInfo(
information="Welcome to our Digital Garage Sale! This is a place to find unique pre-owned items at great prices.",
email="example@example.com",
signal="Signal Username or Number",
donation_link="https://example.com/donate"
)
db.session.add(contact_info)
db.session.commit()
if request.method == 'POST':
information = request.form.get('information')
email = request.form.get('email')
signal = request.form.get('signal')
donation_link = request.form.get('donation_link')
if email:
contact_info.information = information
contact_info.email = email
contact_info.signal = signal
contact_info.donation_link = donation_link
db.session.commit()
flash('Contact information updated successfully', 'success')
return redirect(url_for('admin.dashboard'))
else:
flash('Email is required', 'danger')
return render_template('admin/edit_contact.html',
title='Edit Contact Information',
contact_info=contact_info)
@bp.route('/catalog/generate')
@admin_required
def generate_catalog():
items = Item.query.order_by(Item.created_at.desc()).all()
categories = Category.query.all()
contact_info = ContactInfo.query.first()
# Create HTML to convert to PDF
html = render_template('admin/catalog_pdf.html',
items=items,
categories=categories,
contact_info=contact_info)
# Generate PDF
pdf_path = os.path.join(current_app.root_path, 'static', 'catalog.pdf')
pdfkit.from_string(html, pdf_path)
# Return PDF for download
return send_file(pdf_path, as_attachment=True, download_name='garage_sale_catalog.pdf')