diff --git a/controllers/database/category.py b/controllers/database/category.py new file mode 100644 index 0000000..3c183e8 --- /dev/null +++ b/controllers/database/category.py @@ -0,0 +1,64 @@ +from .database import DatabaseController +from models.category import Category + +class CategoryController(DatabaseController): + FIELDS = ['id', 'name'] + + def __init__(self): + super().__init__() + + def create(self, category: Category): + params = [ + category.name, + ] + + self._conn.execute( + "INSERT INTO Categories (name) VALUES (?)", + params + ) + self._conn.commit() + + + def read(self, id: int = 0) -> Category | None: + params = [ + id + ] + + cursor = self._conn.execute( + "SELECT * FROM Categories WHERE id = ?", + params + ) + row = cursor.fetchone() + + if row == None: + return None + + params = dict(zip(self.FIELDS, row)) + obj = self.new_instance(Category, params) + + return obj + + + def read_all(self) -> list[Category] | None: + cursor = self._conn.execute( + "SELECT * FROM Categories", + ) + rows = cursor.fetchall() + + if rows == None: + return None + + categories = list() + + for category in rows: + params = dict(zip(self.FIELDS, category)) + obj = self.new_instance(Category, params) + categories.append(obj) + + return categories + + def update(self): + print("Doing work") + + def delete(self): + print("Doing work") \ No newline at end of file diff --git a/controllers/database/product.py b/controllers/database/product.py index aa714f4..81cd436 100644 --- a/controllers/database/product.py +++ b/controllers/database/product.py @@ -46,15 +46,21 @@ class ProductController(DatabaseController): for product in rows: params = dict(zip(self.FIELDS, product)) obj = self.new_instance(Product, params) - print(obj.__dict__) products.push(obj) return products - def read_all(self) -> list[Product] | None: + def read_all(self, category: str = "") -> list[Product] | None: + params = [ + "%" + category + "%" + ] + cursor = self._conn.execute( - "SELECT * FROM Products", + """SELECT * FROM Products + INNER JOIN Categories ON Products.categoryID = Categories.id + WHERE Categories.name LIKE ? """, + params ) rows = cursor.fetchall() @@ -67,7 +73,6 @@ class ProductController(DatabaseController): for product in rows: params = dict(zip(self.FIELDS, product)) obj = self.new_instance(Product, params) - print(obj.__dict__) products.append(obj) return products diff --git a/controllers/database/user.py b/controllers/database/user.py index 2a73b7d..87d93d4 100644 --- a/controllers/database/user.py +++ b/controllers/database/user.py @@ -39,7 +39,6 @@ class UserController(DatabaseController): if row != None: params = dict(zip(self.FIELDS, row)) obj = self.new_instance(Customer, params) - print(obj.__dict__) return obj return None diff --git a/controllers/web/product.py b/controllers/web/product.py index c545ee0..7a89c9c 100644 --- a/controllers/web/product.py +++ b/controllers/web/product.py @@ -2,9 +2,16 @@ from flask import Blueprint from flask import render_template, session, flash from controllers.database.product import ProductController +from controllers.database.category import CategoryController blueprint = Blueprint("products", __name__, url_prefix="/products") +@blueprint.context_processor +def category_list(): + database = CategoryController() + categories = database.read_all() + return dict(categories=categories) + # Loads the front product page @blueprint.route('/') def index(): @@ -20,7 +27,15 @@ def index(): # Loads a given product category page @blueprint.route('/') def category(category: str): - return "Category: " + category + print(category) + database = ProductController() + products = database.read_all(category) + + # No Products visible + if products == None: + flash("No Products available in " + category) + + return render_template('index.html', content="content.html", user = session.get('user'), products = products, category = category) # Loads a given product based on ID @blueprint.route('/') diff --git a/models/category.py b/models/category.py new file mode 100644 index 0000000..91c0360 --- /dev/null +++ b/models/category.py @@ -0,0 +1,7 @@ +class Category: + ''' + Constructor for a category object + ''' + def __init__(self): + self.id = 0 + self.name = "" \ No newline at end of file diff --git a/scripts/create_tables.sql b/scripts/create_tables.sql index 8200b6b..1d0eb10 100644 --- a/scripts/create_tables.sql +++ b/scripts/create_tables.sql @@ -11,6 +11,21 @@ CREATE TABLE IF NOT EXISTS Users ( INSERT INTO Users (first_name, last_name, username, email, phone, password, role) VALUES ("Luke", "Else", "lukejelse04", "test@test.com", "07498 289321", "test213", "Customer"); +CREATE TABLE IF NOT EXISTS Categories ( + id INTEGER PRIMARY KEY, + name TEXT NOT NULL UNIQUE +); + +INSERT INTO Categories (name) VALUES ("Car Parts"); +INSERT INTO Categories (name) VALUES ("Animals"); +INSERT INTO Categories (name) VALUES ("Sports"); +INSERT INTO Categories (name) VALUES ("Books"); +INSERT INTO Categories (name) VALUES ("Phones"); +INSERT INTO Categories (name) VALUES ("Music"); + + + + CREATE TABLE IF NOT EXISTS Products ( id INTEGER PRIMARY KEY, name TEXT NOT NULL, @@ -21,20 +36,23 @@ CREATE TABLE IF NOT EXISTS Products ( REFERENCES Users (id) ON DELETE CASCADE ON UPDATE NO ACTION, - category TEXT NOT NULL + categoryID INTEGER NOT NULL + REFERENCES Categories (id) + ON DELETE CASCADE + ON UPDATE NO ACTION ); -INSERT INTO Products (name, image, description, cost, sellerID, category) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, "CarParts"); -INSERT INTO Products (name, image, description, cost, sellerID, category) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, "CarParts"); -INSERT INTO Products (name, image, description, cost, sellerID, category) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, "CarParts"); -INSERT INTO Products (name, image, description, cost, sellerID, category) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, "CarParts"); -INSERT INTO Products (name, image, description, cost, sellerID, category) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, "CarParts"); -INSERT INTO Products (name, image, description, cost, sellerID, category) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, "CarParts"); -INSERT INTO Products (name, image, description, cost, sellerID, category) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, "CarParts"); -INSERT INTO Products (name, image, description, cost, sellerID, category) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, "CarParts"); -INSERT INTO Products (name, image, description, cost, sellerID, category) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, "CarParts"); -INSERT INTO Products (name, image, description, cost, sellerID, category) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, "CarParts"); -INSERT INTO Products (name, image, description, cost, sellerID, category) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, "CarParts"); +INSERT INTO Products (name, image, description, cost, sellerID, categoryID) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, 1); +INSERT INTO Products (name, image, description, cost, sellerID, categoryID) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, 1); +INSERT INTO Products (name, image, description, cost, sellerID, categoryID) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, 1); +INSERT INTO Products (name, image, description, cost, sellerID, categoryID) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, 1); +INSERT INTO Products (name, image, description, cost, sellerID, categoryID) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, 1); +INSERT INTO Products (name, image, description, cost, sellerID, categoryID) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, 1); +INSERT INTO Products (name, image, description, cost, sellerID, categoryID) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, 1); +INSERT INTO Products (name, image, description, cost, sellerID, categoryID) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, 1); +INSERT INTO Products (name, image, description, cost, sellerID, categoryID) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, 1); +INSERT INTO Products (name, image, description, cost, sellerID, categoryID) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, 1); +INSERT INTO Products (name, image, description, cost, sellerID, categoryID) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, 1); CREATE TABLE IF NOT EXISTS Orders ( id INTEGER PRIMARY KEY, diff --git a/static/css/carparts.css b/static/css/carparts.css new file mode 100644 index 0000000..b1cdf92 --- /dev/null +++ b/static/css/carparts.css @@ -0,0 +1,69 @@ +.filter-pane { + flex: 0 1 auto; + width: 60%; + padding: .5rem 2rem; + background-color: var(--bg-grad-3); + border-radius: 1rem; +} + +.filter-items { + display: flex; + align-items: center; + justify-content: space-between; + gap: 2rem; +} + +.product-filter { + width: 100%; + padding: 16px 20px; + border: none; + border-radius: 4px; + background-color: var(--bg-grad-2); + color: var(--fg); + font-size: .75rem; +} + + + + +/* Number Plate*/ +.number-plate { + display: flex; + align-items: center; +} + +.country-identifier { + width: auto; + display: flex; + flex-direction: column; + align-items: center; + color: #ffffff; + font-weight: bold; + height: 60px; + justify-content: center; +} +.country-identifier img { + border-radius: 8px 0 0 8px; +} +.vrn { + width: 10rem; + height: 63px; + border: 1px solid #ead809; + background-color: #ead809; + border-radius: 0 8px 8px 0; +} +.vrn .vrn-text { + width: -webkit-fill-available; + height: -webkit-fill-available; + border-radius: 0; + border: 0; + font-family: "UKNumberPlate", sans-serif; + font-size: 180%; + text-transform: uppercase; + text-align: center; + outline: 0; + background-color: transparent; +} +.vrn .vrn-text:focus { + outline: 0; +} \ No newline at end of file diff --git a/static/css/products.css b/static/css/products.css new file mode 100644 index 0000000..4aeb158 --- /dev/null +++ b/static/css/products.css @@ -0,0 +1,43 @@ +/* Product Information*/ + +.product-container { + width: 95%; + background-color: var(--bg-grad-3); + border-radius: 1rem 1rem 0rem 0rem; + display: flex; + flex-wrap: wrap; + flex-direction: row; + gap: 2rem 1.5rem; + padding: 1rem; + transition: all 0.2s; + overflow-y: scroll; +} + +.product { + display: flex; + flex-direction: column; + justify-content: space-between; + flex-wrap: wrap; + flex: 4 0 1rem; + padding: .5rem 1rem 2rem 2rem; + background: var(--bg-secondary); + border-radius: .5rem .5rem; + transition: all 0.2s; +} + +.product-information { + display: flex; + flex-direction: row; + gap: 1rem 1rem; +} + +.product-details { + display: flex; + flex-direction: column; + align-items: center; + gap: 1rem 1rem; +} + +.product-description { + font-size: 70%; +} \ No newline at end of file diff --git a/static/css/style.css b/static/css/style.css index 358e5e4..09a3b9e 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -172,122 +172,3 @@ a:active { flex-grow: 1; height: 1%; } - -.filter-pane { - padding: .5rem 2rem; - background-color: var(--bg-grad-3); - border-radius: 1rem; -} - -.filter-items { - display: flex; - align-items: center; - justify-content: space-between; - gap: 2rem; -} - -.product-filter { - width: 100%; - padding: 16px 20px; - border: none; - border-radius: 4px; - background-color: var(--bg-grad-2); - color: var(--fg); - font-size: .75rem; -} - - - - - - - -/* Number Plate*/ -.number-plate { - display: flex; - align-items: center; -} - -.country-identifier { - width: auto; - display: flex; - flex-direction: column; - align-items: center; - color: #ffffff; - font-weight: bold; - height: 60px; - justify-content: center; -} -.country-identifier img { - border-radius: 8px 0 0 8px; -} -.vrn { - width: 10rem; - height: 63px; - border: 1px solid #ead809; - background-color: #ead809; - border-radius: 0 8px 8px 0; -} -.vrn .vrn-text { - width: -webkit-fill-available; - height: -webkit-fill-available; - border-radius: 0; - border: 0; - font-family: "UKNumberPlate", sans-serif; - font-size: 180%; - text-transform: uppercase; - text-align: center; - outline: 0; - background-color: transparent; -} -.vrn .vrn-text:focus { - outline: 0; -} - - - - - -/* Product Information*/ - -.product-container { - width: 95%; - background-color: var(--bg-grad-3); - border-radius: 1rem 1rem 0rem 0rem; - display: flex; - flex-wrap: wrap; - flex-direction: row; - gap: 2rem 1.5rem; - padding: 1rem; - transition: all 0.2s; - overflow-y: scroll; -} - -.product { - display: flex; - flex-direction: column; - justify-content: space-between; - flex-wrap: wrap; - flex: 4 0 1rem; - padding: .5rem 1rem 2rem 2rem; - background: var(--bg-secondary); - border-radius: .5rem .5rem; - transition: all 0.2s; -} - -.product-information { - display: flex; - flex-direction: row; - gap: 1rem 1rem; -} - -.product-details { - display: flex; - flex-direction: column; - align-items: center; - gap: 1rem 1rem; -} - -.product-description { - font-size: 70%; -} \ No newline at end of file diff --git a/templates/Car Parts.html b/templates/Car Parts.html new file mode 100644 index 0000000..e586cd2 --- /dev/null +++ b/templates/Car Parts.html @@ -0,0 +1,22 @@ + + +
+
+
+ + + + + + +
+ + + + +
+
diff --git a/templates/car_parts.html b/templates/car_parts.html deleted file mode 100644 index f57a6ca..0000000 --- a/templates/car_parts.html +++ /dev/null @@ -1,39 +0,0 @@ - -
-
-
- - - - - - -
- - -
-
- -
- {% if products != None %} - {% for product in products %} -
-
{{product.name}}
-
-
- Brake Disks -
-
-
£{{product.cost}}
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
-
-
-
-
- {% endfor %} - {% endif %} -
diff --git a/templates/content.html b/templates/content.html index 5fd24d3..7032fe8 100644 --- a/templates/content.html +++ b/templates/content.html @@ -1,3 +1,5 @@ + +
{% if products != None %} {% for product in products %} @@ -9,7 +11,7 @@
£{{product.cost}}
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
+
{{product.description}}
diff --git a/templates/header.html b/templates/header.html index 5826d71..57eff9f 100644 --- a/templates/header.html +++ b/templates/header.html @@ -14,12 +14,14 @@
- Car Parts - Animals - Sports - Books - Phones - Music + {# List all categories and ensure the selected one is highlighted #} + {% for c in categories %} + {% if category == c.name %} + {{c.name}} + {% else %} + {{c.name}} + {% endif %} + {% endfor %}
diff --git a/templates/index.html b/templates/index.html index 81f990e..e68507c 100644 --- a/templates/index.html +++ b/templates/index.html @@ -11,7 +11,14 @@ {% include 'header.html' %} + +
+ {% if category is defined %} + {% set include_file = category+".html" %} + {% include include_file ignore missing %} + {% endif %} + {% include content %}