Resolved merge conflict

This commit is contained in:
Luke Else 2024-01-15 17:45:47 +00:00
commit 7b12c29319
21 changed files with 217 additions and 48 deletions

7
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,7 @@
pytest:
stage: test
script:
- python -m venv .venv
- source ./.venv/scripts/activate
- pip install -r requirements.txt
- pytest

View File

@ -18,6 +18,13 @@ python -m venv .venv
pip install -r requirements.txt
```
## Testing
To run the full suite of unit tests for the webapp simply run the following command in the venv
```sh
pytest
```
## Running
### Pre-Requisites

View File

@ -1,14 +1,25 @@
from abc import ABC, abstractmethod
from typing import Mapping, Any
import sqlite3
import os
class DatabaseController(ABC):
__sqlitefile = "./data/wmgzon.db"
__data_dir = "./data/"
__db_name = "wmgzon.db"
# Use test file if necessary
if os.environ.get("ENVIRON") == "test":
__db_name = "test_" + __db_name
__sqlitefile = __data_dir + __db_name
def __init__(self):
self._conn = None
try:
self._conn = sqlite3.connect(self.__sqlitefile)
# Creates a connection and specifies a flag to parse all types back down into
# Python declared types e.g. date & time
self._conn = sqlite3.connect(self.__sqlitefile, detect_types=sqlite3.PARSE_DECLTYPES)
except sqlite3.Error as e:
# Close the connection if still open
if self._conn:

View File

@ -2,7 +2,7 @@ from .database import DatabaseController
from models.products.product import Product
class ProductController(DatabaseController):
FIELDS = ['id', 'name', 'image', 'description', 'cost', 'category', 'sellerID', 'postedDate', 'quantity']
FIELDS = ['id', 'name', 'image', 'description', 'cost', 'category', 'sellerID', 'postedDate', 'quantityAvailable']
def __init__(self):
super().__init__()
@ -20,7 +20,7 @@ class ProductController(DatabaseController):
]
self._conn.execute(
"INSERT INTO Products (name, cost, image, description, category, sellerID, postedDate, quantityAvailable) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
"INSERT INTO Products (name, image, description, cost, categoryID, sellerID, postedDate, quantityAvailable) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
params
)
self._conn.commit()
@ -46,7 +46,7 @@ class ProductController(DatabaseController):
for product in rows:
params = dict(zip(self.FIELDS, product))
obj = self.new_instance(Product, params)
products.push(obj)
products.append(obj)
return products

View File

@ -55,14 +55,12 @@ def signup():
return redirect("/signup")
database.create(Customer(
0,
request.form['username'],
sha512(request.form['password'].encode()).hexdigest(), # Hashed as soon as it is recieved on the backend
request.form['firstname'],
request.form['lastname'],
request.form['email'],
"123",
"Customer"
"123"
))
# Code 307 Preserves the original request (POST)

View File

@ -6,6 +6,9 @@ services:
build: .
environment:
- APPSECRET=test
- ENVIRON=test
# - ENVIRON=prod
tty: true
ports:
- "5000:5000"
volumes:

View File

@ -3,5 +3,5 @@ COPY ./requirements.txt /app/requirements.txt
WORKDIR /app
RUN pip install -r requirements.txt
COPY . /app
RUN chmod +x scripts/run.sh
CMD ["sh", "scripts/run.sh"]
RUN chmod +x scripts/run.bash
CMD ["bash", "scripts/run.bash"]

View File

@ -10,8 +10,25 @@ class Product:
self.image = "/static/assets/wmgzon.png"
self.description = ""
self.cost = 0.0
self.category = ""
self.category = 0
self.sellerID = 0
self.postedDate = datetime.now()
self.quantityAvailable = 0
'''
Class constructor to instatiate a customer object
No additional properties are assigned to the customer
'''
def __init__(self, name: str, image: str, description: str, cost: float, category: int,
seller_id: int, posted_date: datetime, quantity_available: int):
self.id = 0
self.name = name
self.image = image
self.description = description
self.cost = cost
self.category = category
self.sellerID = seller_id
self.postedDate = posted_date
self.quantityAvailable = quantity_available

View File

@ -6,8 +6,8 @@ class Admin(User):
No additional properties are assigned to the admin
'''
def __init__(self, id: int, username: str, password: str, firstname: str,
lastname: str, email: str, phone: str, role: str):
def __init__(self, username: str, password: str, firstname: str,
lastname: str, email: str, phone: str):
super().__init__(
id, username, password, firstname, lastname, email, phone, role
username, password, firstname, lastname, email, phone, "Admin"
)

View File

@ -6,9 +6,9 @@ class Customer(User):
No additional properties are assigned to the customer
'''
def __init__(self, id: int, username: str, password: str, firstname: str,
lastname: str, email: str, phone: str, role: str):
def __init__(self, username: str, password: str, firstname: str,
lastname: str, email: str, phone: str):
super().__init__(
id, username, password, firstname, lastname, email, phone, role
username, password, firstname, lastname, email, phone, "Customer"
)

View File

@ -6,9 +6,9 @@ class Seller(User):
No additional properties are assigned to the customer
'''
def __init__(self, id: int, username: str, password: str, firstname: str,
lastname: str, email: str, phone: str, role: str):
def __init__(self, username: str, password: str, firstname: str,
lastname: str, email: str, phone: str):
super().__init__(
id, username, password, firstname, lastname, email, phone, role
id, username, password, firstname, lastname, email, phone, "Seller"
)
self.store = ""

View File

@ -3,9 +3,9 @@ from abc import ABC
class User(ABC):
""" Functional Class constructor to initialise all properties in the base object
with a value """
def __init__(self, id: int, username: str, password: str, firstname: str,
def __init__(self, username: str, password: str, firstname: str,
lastname: str, email: str, phone: str, role: str):
self.id = id
self.id = 0
self.username = username
self.password = password
self.firstName = firstname

0
scripts/__init__.py Normal file
View File

View File

@ -17,8 +17,13 @@ def create_connection(path: str, filename: str):
sql = open("scripts/create_tables.sql", "r");
conn.executescript(sql.read())
print("SQLite Version: " + sqlite3.version)
print("Table creation complete")
# Populate with test data if we are in Test Mode
if os.environ.get("ENVIRON") == "test":
sql = open("scripts/test_data.sql", "r");
conn.executescript(sql.read())
except sqlite3.Error as e:
print(e)
finally:
@ -32,5 +37,22 @@ def create_directory(dir: str):
except FileExistsError:
pass
if __name__ == '__main__':
create_connection(r"./data/", r"wmgzon.db")
def remove_file(dir: str):
try:
os.remove(dir)
except FileNotFoundError:
pass
dir = r"./data/"
db_name = r"wmgzon.db"
# Check for test environ
if os.environ.get("ENVIRON") == "test":
# Remove the original test database
print("TEST ENVIRONMENT ACTIVE")
db_name = "test_" + db_name
remove_file(dir + db_name)
create_connection(dir, db_name)

View File

@ -9,8 +9,6 @@ CREATE TABLE IF NOT EXISTS Users (
role TEXT NOT NULL
);
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
@ -23,9 +21,6 @@ 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,
@ -39,21 +34,11 @@ CREATE TABLE IF NOT EXISTS Products (
categoryID INTEGER NOT NULL
REFERENCES Categories (id)
ON DELETE CASCADE
ON UPDATE NO ACTION
ON UPDATE NO ACTION,
postedDate TIMESTAMP,
quantityAvailable INTEGER DEFAULT 0
);
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, 2, 2);
INSERT INTO Products (name, image, description, cost, sellerID, categoryID) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 3, 3);
INSERT INTO Products (name, image, description, cost, sellerID, categoryID) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 3, 3);
INSERT INTO Products (name, image, description, cost, sellerID, categoryID) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 3, 3);
INSERT INTO Products (name, image, description, cost, sellerID, categoryID) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 6, 6);
INSERT INTO Products (name, image, description, cost, sellerID, categoryID) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 6, 6);
INSERT INTO Products (name, image, description, cost, sellerID, categoryID) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 5, 5);
CREATE TABLE IF NOT EXISTS Orders (
id INTEGER PRIMARY KEY,
sellerID TEXT NOT NULL

2
scripts/run.bash Normal file
View File

@ -0,0 +1,2 @@
#! /bin/bash
pytest --disable-warnings && python ./scripts/create_database.py && python ./app.py

View File

@ -1,4 +0,0 @@
#! /bin/sh
python ./scripts/create_database.py
python ./app.py

37
scripts/test_data.sql Normal file
View File

@ -0,0 +1,37 @@
INSERT INTO Users (first_name, last_name, username, email, phone, password, role) VALUES ("Luke", "Else", "lukejelse04", "test@test.com", "07498 289321", "test213", "Customer");
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, 2);
INSERT INTO Products (name, image, description, cost, sellerID, categoryID) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, 2);
INSERT INTO Products (name, image, description, cost, sellerID, categoryID) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, 3);
INSERT INTO Products (name, image, description, cost, sellerID, categoryID) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, 4);
INSERT INTO Products (name, image, description, cost, sellerID, categoryID) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, 4);
INSERT INTO Products (name, image, description, cost, sellerID, categoryID) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, 4);
INSERT INTO Products (name, image, description, cost, sellerID, categoryID) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, 6);
INSERT INTO Products (name, image, description, cost, sellerID, categoryID) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, 6);
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, 2);
INSERT INTO Products (name, image, description, cost, sellerID, categoryID) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, 2);
INSERT INTO Products (name, image, description, cost, sellerID, categoryID) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, 3);
INSERT INTO Products (name, image, description, cost, sellerID, categoryID) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, 4);
INSERT INTO Products (name, image, description, cost, sellerID, categoryID) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, 4);
INSERT INTO Products (name, image, description, cost, sellerID, categoryID) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, 4);
INSERT INTO Products (name, image, description, cost, sellerID, categoryID) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, 6);
INSERT INTO Products (name, image, description, cost, sellerID, categoryID) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, 6);
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, 2);
INSERT INTO Products (name, image, description, cost, sellerID, categoryID) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, 2);
INSERT INTO Products (name, image, description, cost, sellerID, categoryID) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, 3);
INSERT INTO Products (name, image, description, cost, sellerID, categoryID) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, 4);
INSERT INTO Products (name, image, description, cost, sellerID, categoryID) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, 4);
INSERT INTO Products (name, image, description, cost, sellerID, categoryID) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, 4);
INSERT INTO Products (name, image, description, cost, sellerID, categoryID) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, 6);
INSERT INTO Products (name, image, description, cost, sellerID, categoryID) VALUES ("test", "assets/img/wmgzon.png", "this is a product", 20.99, 1, 6);

View File

@ -0,0 +1,8 @@
# Ensure test environment is set before using
import os
# Setup test environment variables
os.environ["ENVIRON"] = "test"
# Runs the database creation scripts
import scripts.create_database

View File

@ -0,0 +1,40 @@
import pytest
import sqlite3
from datetime import datetime
from controllers.database.product import ProductController
from models.products.product import Product
product = Product(
"product",
"image.png",
"description",
10.00,
1,
1,
datetime.now(),
1
)
# Tests a new product can be created
def test_create_product():
db = ProductController()
db.create(product)
# Tests the database maintains integrity when we try and add a product with the same details
def test_duplicate_product():
db = ProductController()
with pytest.raises(sqlite3.IntegrityError):
db.create(product)
# Test we the same product details get returned from the database
def test_read_product():
db = ProductController()
# Test the same product is returned
new_product = db.read("product")
assert isinstance(new_product, list)
assert isinstance(new_product[0], Product)
# Update the ID on the item as database assigns new id
product.id = new_product[0].id
assert new_product[0].__dict__ == product.__dict__

View File

@ -0,0 +1,36 @@
import pytest
import sqlite3
from controllers.database.user import UserController
from models.users.customer import Customer
customer = Customer(
"testuser",
"Password1",
"firstname",
"lastname",
"test@test",
"123456789"
)
# Tests a new user can be created
def test_create_user():
db = UserController()
db.create(customer)
# Tests the database maintains integrity when we try and add a user with the same details
def test_duplicate_user():
db = UserController()
with pytest.raises(sqlite3.IntegrityError):
db.create(customer)
# Test we the same user details get returned from the database
def test_read_user():
db = UserController()
# Test the same user is returned
user = db.read("testuser")
assert isinstance(user, Customer)
# Update the ID on the item as database assigns new id
customer.id = user.id
assert user.__dict__ == customer.__dict__