From 035867007122d044d6bbb87db823ef517c6885aa Mon Sep 17 00:00:00 2001 From: Luke Else Date: Thu, 25 Jan 2024 00:05:34 +0000 Subject: [PATCH] #4 #6 Completed functionlity to update products in place. Form still needs tidying up --- app.py | 1 + controllers/web/product.py | 28 +++++++++++++--------------- docker-compose.yml | 2 +- scripts/create_database.py | 23 +++++++---------------- utils/file_utils.py | 34 +++++++++++++++++++++++++++++++++- 5 files changed, 55 insertions(+), 33 deletions(-) diff --git a/app.py b/app.py index b1bf1b4..49c897c 100644 --- a/app.py +++ b/app.py @@ -10,6 +10,7 @@ from controllers.web.endpoints import blueprint def main(): + print(__package__) app = Flask(__name__) # Set app secret key to sign session cookies diff --git a/controllers/web/product.py b/controllers/web/product.py index 5b0b9e3..25f1800 100644 --- a/controllers/web/product.py +++ b/controllers/web/product.py @@ -11,12 +11,11 @@ from controllers.database.category import CategoryController from controllers.database.user import UserController from datetime import datetime -from utils.file_utils import allowed_file +from utils.file_utils import allowed_file, save_image, remove_file from utils.user_utils import is_role -import os -import uuid import pathlib +import os blueprint = Blueprint("products", __name__, url_prefix="/products") @@ -106,19 +105,11 @@ def add_product(): return redirect("/") file = request.files.get('image') - - # Ensure that the correct file type is uploaded - if file is None or not allowed_file(file.filename): - flash("Invalid File Uploaded") - return redirect("/add") - - # Create the product object and push to database - filename = str(uuid.uuid4()) + pathlib.Path(file.filename).suffix - file.save(os.path.join('static/assets/img/products/', filename)) + image_filename = save_image(file) product = Product( request.form.get('name'), - filename, + image_filename if image_filename is not None else "", request.form.get('description'), request.form.get('cost'), request.form.get('category'), @@ -151,17 +142,24 @@ def update_product(id: int): flash("This product does not belong to you!") return redirect("/ownproducts") + # 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.image = request.form.get('image') product.cost = request.form.get('cost') product.quantityAvailable = request.form.get('quantity') db.update(product) flash("Product successfully updated") - return redirect(f"/{product.id}") + return redirect(f"/products/{product.id}") @blueprint.route('/ownproducts') diff --git a/docker-compose.yml b/docker-compose.yml index 1946300..88c18a2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,7 +8,7 @@ services: - APPSECRET=test - ENVIRON=test # - ENVIRON=prod - - FILESTORE=static/assets/img/products + - FILESTORE=static/assets/img/products/ tty: true ports: - "5000:5000" diff --git a/scripts/create_database.py b/scripts/create_database.py index ba3e11e..209600f 100644 --- a/scripts/create_database.py +++ b/scripts/create_database.py @@ -1,5 +1,11 @@ import sqlite3 import os +import sys + +if __name__ == "__main__": + sys.path.append(os.getcwd()) + +from utils.file_utils import create_directory, remove_file def create_connection(path: str, filename: str): @@ -30,23 +36,8 @@ def create_connection(path: str, filename: str): if conn: conn.close() + # Ensure a directory is created given a path to it - - -def create_directory(dir: str): - try: - os.makedirs(dir) - except FileExistsError: - pass - - -def remove_file(dir: str): - try: - os.remove(dir) - except FileNotFoundError: - pass - - dir = r"./data/" db_name = r"wmgzon.db" diff --git a/utils/file_utils.py b/utils/file_utils.py index a457dd1..be1830e 100644 --- a/utils/file_utils.py +++ b/utils/file_utils.py @@ -1,7 +1,11 @@ +import os +import uuid +import pathlib + ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'} -def allowed_file(filename): +def allowed_file(filename) -> bool: """ Ensures only filenames ending with the correct extension are allowed. Note: This does not verify that the content inside of the file matches the type specified @@ -9,3 +13,31 @@ def allowed_file(filename): return '.' in filename and \ filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS +def save_image(file) -> str | None: + """ Saves a given file to disk with a random UUID4 generated + filename. Returns the filename as a string. + """ + # Ensure that the correct file type is uploaded + if file is None or not allowed_file(file.filename): + return None + + # Create the product object and push to database + filename = str(uuid.uuid4()) + pathlib.Path(file.filename).suffix + + path = os.environ.get('FILESTORE') + file.save(os.path.join(path, filename)) + return filename + +def create_directory(dir: str): + """ Creates the given directory string is not alreay made """ + try: + os.makedirs(dir) + except FileExistsError: + pass + +def remove_file(dir: str): + """ Removes a given file if it is present at the given dir """ + try: + os.remove(dir) + except FileNotFoundError: + pass