""" Product related endpoints. Included contexts for principles such as categories and image processing. """ from flask import render_template, session, flash, request, redirect, Blueprint, url_for from models.products.product import Product from models.stats import Stats from controllers.database.product import ProductController from controllers.database.category import CategoryController from controllers.database.stats import StatsController from datetime import datetime from utils.file_utils import save_image, remove_file from utils.user_utils import is_role import os blueprint = Blueprint("products", __name__, url_prefix="/products") # List of available filters for the user to select FILTERS = { # ANY INFOMRATION PUT INTO THE VALUES HERE WILL BE INTERPRETED AS SQL!!! 'Relevance': 'ORDER BY quantityAvailable DESC', 'Price: High -> Low': 'ORDER BY cost DESC', 'Price: Low -> High': 'ORDER BY cost' } @blueprint.context_processor def filter_list(): """ Places a list of all the available filters in the products context """ return dict(filters=FILTERS) def get_filter(): """ Return any filters that are currently active on the page """ filter = request.args.get('filter') if filter is None: filter = 'Relevance' if filter in FILTERS: return FILTERS[filter] return FILTERS['Relevance'] @blueprint.context_processor def category_list(): """ Places a list of all categories in the products context """ database = CategoryController() categories = database.read_all() return dict(categories=categories) @blueprint.route('/') def index(): """ The front product page """ # Returning an empty category acts the same # as a generic home page return category("") @blueprint.route('/') def category(category: str): """ Loads a given categories page """ database = ProductController() # Check to see if there is a custome search term search_term = request.args.get("search", type=str) if search_term is not None: products = database.read_all(category, search_term, get_filter()) else: products = database.read_all(category, "", get_filter()) # No Products visible if products is None: flash( f"No Products available. Try expanding your search criteria.", "warning" ) return render_template( 'index.html', content="content.html", products=products, category=category ) @blueprint.route('/') def product(id: int): """ Loads a given product based on ID """ db = ProductController() product = db.read_id(id) # Check that a valid product was returned if product is None: flash(f"No Product available with id {id}", "warning") return redirect(url_for('main.index')) # Record a view on the product db = StatsController() user_id = session.get('user_id') db.create(Stats(product.id, user_id)) return render_template( 'index.html', content='product.html', product=product ) @blueprint.route('/add') def display_add(): """ Launches the page to add a new product to the site """ # User needs to be logged in as a seller to view this page if not is_role("Seller"): flash("You must be logged in as a seller to view this page!", "error") return redirect(url_for('main.index')) return render_template('index.html', content='new_product.html') @blueprint.post('/add') def add(): """ Server site processing to handle a request to add a new product to the site """ user_id = session.get('user_id') # User needs to be logged in as a seller to view this page if not is_role("Seller"): flash("You must be logged in as a seller to view this page!", "error") return redirect(url_for('main.index')) file = request.files.get('image') image_filename = save_image(file) product = Product( request.form.get('name'), image_filename if image_filename is not None else "", request.form.get('description'), request.form.get('cost'), request.form.get('category'), user_id, datetime.now(), request.form.get('quantity') ) db = ProductController() db.create(product) return redirect('/products/ownproducts') @blueprint.post('/update/') def update(id: int): """ Processes a request to update a product in place on the site """ # Ensure that the product belongs to the current user user_id = session.get('user_id') # User needs to be logged in as a seller to view this page if not is_role("Seller"): flash("You must be logged in as a seller to view this page!", "error") return redirect(url_for('main.index')) db = ProductController() product = db.read_id(id) if product.sellerID != user_id: flash("This product does not belong to you!", "error") return redirect(url_for('main.products.own')) # Save new image file file = request.files.get('image') new_image = save_image(file) if new_image is not None: remove_file(os.path.join(os.environ.get('FILESTORE'), product.image)) product.image = new_image # Update product details product.name = request.form.get('name') product.description = request.form.get('description') product.category = request.form.get('category') product.cost = request.form.get('cost') product.quantityAvailable = request.form.get('quantity') db.update(product) flash("Product successfully updated", 'notice') return redirect(url_for('main.products.product', id=product.id)) @blueprint.post('/delete/') def delete(id: int): """ Processes a request to delete a product in place on the site """ # Ensure that the product belongs to the current user user_id = session.get('user_id') # User needs to be logged in as a seller to view this page if not is_role("Seller"): flash("You must be logged in as a seller to view this page!", "error") return redirect(url_for('main.index')) db = ProductController() product = db.read_id(id) if product.sellerID != user_id: flash("This product does not belong to you!", "error") return redirect(url_for('main.products.display_own')) db.delete(id) flash("Product Removed!", "success") return redirect(url_for('main.products.display_own')) @blueprint.route('/ownproducts') def display_own(): """ Display products owned by the currently logged in seller """ user_id = session.get('user_id') # User must be logged in as seller to view page if not is_role("Seller"): flash("You must be logged in as a seller to view this page!", "error") return redirect(url_for('main.index')) db = ProductController() products = db.read_user(user_id) if products is None: flash("You don't currently have any products for sale.", "info") return render_template( 'index.html', content='content.html', products=products )