Compare commits
No commits in common. "master" and "CICD" have entirely different histories.
13
.env
13
.env
@ -1,13 +0,0 @@
|
|||||||
# Environment Variables used to configure WMGZON
|
|
||||||
|
|
||||||
# ENVIRON: Used to incidicate the type of environment the app is running in.
|
|
||||||
# DEFAULT = prod
|
|
||||||
|
|
||||||
ENVIRON=prod
|
|
||||||
# ENVIRON=test
|
|
||||||
|
|
||||||
# App secret used to encrpy client-side cookies
|
|
||||||
APPSECRET=test
|
|
||||||
|
|
||||||
# Filestore for product photos
|
|
||||||
FILESTORE=static/assets/img/products/
|
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -17,6 +17,7 @@ cicd/runner-data
|
|||||||
instance/*
|
instance/*
|
||||||
!instance/.gitignore
|
!instance/.gitignore
|
||||||
.webassets-cache
|
.webassets-cache
|
||||||
|
.env
|
||||||
|
|
||||||
### Flask.Python Stack ###
|
### Flask.Python Stack ###
|
||||||
# Byte-compiled / optimized / DLL files
|
# Byte-compiled / optimized / DLL files
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
variables:
|
variables:
|
||||||
|
APPSECRET: "test"
|
||||||
|
ENVIRON: "test"
|
||||||
|
FILESTORE: "static/assets/img/products/"
|
||||||
DOCKER_HOST: tcp://docker:2375/
|
DOCKER_HOST: tcp://docker:2375/
|
||||||
DOCKER_DRIVER: overlay2
|
DOCKER_DRIVER: overlay2
|
||||||
DOCKER_TLS_CERTDIR: ""
|
DOCKER_TLS_CERTDIR: ""
|
||||||
@ -16,13 +19,13 @@ deploy:
|
|||||||
stage: deploy
|
stage: deploy
|
||||||
tags:
|
tags:
|
||||||
- docker
|
- docker
|
||||||
image: docker:latest
|
image: docker:20.10.16
|
||||||
services:
|
services:
|
||||||
- name: docker:dind
|
- name: docker:20.10.16-dind
|
||||||
alias: docker
|
alias: docker
|
||||||
script:
|
script:
|
||||||
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
|
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
|
||||||
- docker buildx build --platform linux/amd64 -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA .
|
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA .
|
||||||
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
|
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
|
||||||
- docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA $CI_REGISTRY_IMAGE:latest
|
- docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA $CI_REGISTRY_IMAGE:latest
|
||||||
- docker push $CI_REGISTRY_IMAGE:latest
|
- docker push $CI_REGISTRY_IMAGE:latest
|
||||||
|
21
README.md
21
README.md
@ -41,24 +41,3 @@ docker-compose up -d
|
|||||||
```
|
```
|
||||||
|
|
||||||
to run the container in a detatched mode.
|
to run the container in a detatched mode.
|
||||||
|
|
||||||
|
|
||||||
### Container
|
|
||||||
Alternatively, to deploy the app from the lastest published container:
|
|
||||||
|
|
||||||
```yml
|
|
||||||
version: '3.8'
|
|
||||||
|
|
||||||
services:
|
|
||||||
wmgzon:
|
|
||||||
container_name: "wmgzon"
|
|
||||||
image: lukeelse/wmgzon:latest
|
|
||||||
environment:
|
|
||||||
- FILESTORE=static/assets/img/products/
|
|
||||||
tty: true
|
|
||||||
ports:
|
|
||||||
- "8080:8080"
|
|
||||||
volumes:
|
|
||||||
- ./files:/app/$FILESTORE
|
|
||||||
restart: unless-stopped
|
|
||||||
```
|
|
2
app.py
2
app.py
@ -1,6 +1,5 @@
|
|||||||
from flask import Flask
|
from flask import Flask
|
||||||
from os import environ
|
from os import environ
|
||||||
from dotenv import load_dotenv
|
|
||||||
from controllers.web.endpoints import blueprint
|
from controllers.web.endpoints import blueprint
|
||||||
|
|
||||||
'''
|
'''
|
||||||
@ -12,7 +11,6 @@ from controllers.web.endpoints import blueprint
|
|||||||
app: Flask = Flask(__name__)
|
app: Flask = Flask(__name__)
|
||||||
|
|
||||||
# Set app secret key to sign session cookies
|
# Set app secret key to sign session cookies
|
||||||
load_dotenv()
|
|
||||||
secret_key = environ.get("APPSECRET")
|
secret_key = environ.get("APPSECRET")
|
||||||
if secret_key is None:
|
if secret_key is None:
|
||||||
# NO Secret Key set!
|
# NO Secret Key set!
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
version: '3.8'
|
|
||||||
|
|
||||||
services:
|
|
||||||
wmgzon:
|
|
||||||
container_name: "wmgzon"
|
|
||||||
image: lukeelse/wmgzon:latest
|
|
||||||
tty: true
|
|
||||||
ports:
|
|
||||||
- "8080:8080"
|
|
||||||
volumes:
|
|
||||||
- ./files:/app/static/assets/img/products/
|
|
||||||
- ./data:/app/data/
|
|
||||||
restart: unless-stopped
|
|
@ -12,7 +12,7 @@ class DatabaseController(ABC):
|
|||||||
__db_name = "wmgzon.db"
|
__db_name = "wmgzon.db"
|
||||||
|
|
||||||
# Use test file if necessary
|
# Use test file if necessary
|
||||||
if os.environ.get("ENVIRON", "test") == "test":
|
if os.environ.get("ENVIRON") == "test":
|
||||||
__db_name = "test_" + __db_name
|
__db_name = "test_" + __db_name
|
||||||
|
|
||||||
__sqlitefile = __data_dir + __db_name
|
__sqlitefile = __data_dir + __db_name
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
in the web app
|
in the web app
|
||||||
"""
|
"""
|
||||||
from flask import Blueprint
|
from flask import Blueprint
|
||||||
|
|
||||||
from flask import render_template, request, flash, session, redirect, url_for
|
from flask import render_template, request, flash, session, redirect, url_for
|
||||||
from controllers.database.stats import StatsController
|
from controllers.database.stats import StatsController
|
||||||
from controllers.database.product import ProductController
|
from controllers.database.product import ProductController
|
||||||
@ -47,8 +48,8 @@ def view_product_stats(id: int):
|
|||||||
|
|
||||||
# Recent Views
|
# Recent Views
|
||||||
product_view_frequency_data = dict(map(
|
product_view_frequency_data = dict(map(
|
||||||
# lambda k, v: (k, random.randint(70, 100)),
|
lambda k, v: (k, random.randint(70, 100)),
|
||||||
lambda k, v: (k, len(v)),
|
# lambda k, v: (k, len(v)),
|
||||||
data.keys(),
|
data.keys(),
|
||||||
data.values()
|
data.values()
|
||||||
))
|
))
|
||||||
|
@ -5,12 +5,14 @@ services:
|
|||||||
container_name: "wmgzon"
|
container_name: "wmgzon"
|
||||||
build: .
|
build: .
|
||||||
environment:
|
environment:
|
||||||
|
- APPSECRET=test
|
||||||
- ENVIRON=test
|
- ENVIRON=test
|
||||||
|
#- ENVIRON=prod
|
||||||
|
- FILESTORE=static/assets/img/products/
|
||||||
tty: true
|
tty: true
|
||||||
ports:
|
ports:
|
||||||
- "8080:8080"
|
- "8080:8080"
|
||||||
# Dev container -> Copies complete root directory with latest
|
|
||||||
# code into the container
|
|
||||||
volumes:
|
volumes:
|
||||||
- .:/app
|
- .:/app
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
@ -4,5 +4,4 @@ WORKDIR /app
|
|||||||
RUN pip install -r requirements.txt
|
RUN pip install -r requirements.txt
|
||||||
COPY . /app
|
COPY . /app
|
||||||
RUN chmod +x scripts/run.bash
|
RUN chmod +x scripts/run.bash
|
||||||
EXPOSE 8080
|
CMD ["bash", "scripts/run.bash"]
|
||||||
ENTRYPOINT ["scripts/run.bash"]
|
|
BIN
requirements.txt
BIN
requirements.txt
Binary file not shown.
@ -26,7 +26,7 @@ def create_connection(path: str, filename: str):
|
|||||||
print("Table creation complete")
|
print("Table creation complete")
|
||||||
|
|
||||||
# Populate with test data if we are in Test Mode
|
# Populate with test data if we are in Test Mode
|
||||||
if os.environ.get("ENVIRON", "test") == "test":
|
if os.environ.get("ENVIRON") == "test":
|
||||||
sql = open("scripts/test_data.sql", "r")
|
sql = open("scripts/test_data.sql", "r")
|
||||||
conn.executescript(sql.read())
|
conn.executescript(sql.read())
|
||||||
|
|
||||||
@ -37,21 +37,15 @@ def create_connection(path: str, filename: str):
|
|||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
def run():
|
# Ensure a directory is created given a path to it
|
||||||
""" Create the database for the application"""
|
|
||||||
dir = r"./data/"
|
dir = r"./data/"
|
||||||
db_name = r"wmgzon.db"
|
db_name = r"wmgzon.db"
|
||||||
|
|
||||||
# Check for test environ
|
# Check for test environ
|
||||||
if os.environ.get("ENVIRON", "test") == "test":
|
if os.environ.get("ENVIRON") == "test":
|
||||||
# Remove the original test database
|
# Remove the original test database
|
||||||
print("TEST ENVIRONMENT ACTIVE")
|
print("TEST ENVIRONMENT ACTIVE")
|
||||||
db_name = "test_" + db_name
|
db_name = "test_" + db_name
|
||||||
remove_file(dir + db_name)
|
remove_file(dir + db_name)
|
||||||
|
|
||||||
create_connection(dir, db_name)
|
create_connection(dir, db_name)
|
||||||
|
|
||||||
|
|
||||||
# Ensure a directory is created given a path to it
|
|
||||||
if __name__ == "__main__":
|
|
||||||
run()
|
|
||||||
|
@ -2,16 +2,11 @@
|
|||||||
pytest --disable-warnings
|
pytest --disable-warnings
|
||||||
python ./scripts/create_database.py
|
python ./scripts/create_database.py
|
||||||
|
|
||||||
|
|
||||||
EXPECTED_VALUE="test"
|
EXPECTED_VALUE="test"
|
||||||
|
|
||||||
if [ -z "$ENVIRON" ]; then
|
if [ -z "$ENVIRON" ]; then
|
||||||
echo "ENVIRON is not set."
|
echo "ENVIRON is not set."
|
||||||
echo "Using DEFAULT Environ Value: prod"
|
else
|
||||||
|
|
||||||
export ENVIRON=prod
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "ENVIRON is set to: $ENVIRON"
|
echo "ENVIRON is set to: $ENVIRON"
|
||||||
|
|
||||||
# Trim leading and trailing whitespaces
|
# Trim leading and trailing whitespaces
|
||||||
@ -24,3 +19,6 @@ else
|
|||||||
echo "Launching PROD Server"
|
echo "Launching PROD Server"
|
||||||
waitress-serve --host 0.0.0.0 app:app
|
waitress-serve --host 0.0.0.0 app:app
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,34 +8,34 @@ INSERT INTO Products (name, image, description, cost, sellerID, categoryID, quan
|
|||||||
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, quantityAvailable, postedDate) VALUES ("Exhaust Manifold", "manifold.bmp", "This is a super cool product that can be installed into your car to take the gasses from the inside all the way to the outside. Mad I know.", 20.99, 1, 2, 4, datetime());
|
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, quantityAvailable, postedDate) VALUES ("Exhaust Manifold", "manifold.bmp", "This is a super cool product that can be installed into your car to take the gasses from the inside all the way to the outside. Mad I know.", 20.99, 1, 2, 4, datetime());
|
||||||
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, quantityAvailable, postedDate) VALUES ("12' Brake Disks", "brake-disks.bmp", "this is a product", 20.99, 1, 2, 3, datetime());
|
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, quantityAvailable, postedDate) VALUES ("12' Brake Disks", "brake-disks.bmp", "this is a product", 20.99, 1, 2, 3, datetime());
|
||||||
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, quantityAvailable, postedDate) VALUES ("17' Alloy Wheels", "alloy.bmp", "These super stylish alloys offer a fresh trendy look for your car. Whether a brand new Mercedes or a niffty little banger, it will uplift the vehicle 10-fold", 20.99, 1, 3, 9, datetime());
|
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, quantityAvailable, postedDate) VALUES ("17' Alloy Wheels", "alloy.bmp", "These super stylish alloys offer a fresh trendy look for your car. Whether a brand new Mercedes or a niffty little banger, it will uplift the vehicle 10-fold", 20.99, 1, 3, 9, datetime());
|
||||||
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, quantityAvailable, postedDate) VALUES ("Single Turbo", "turbo.bmp", "this is a product", 129.99, 1, 4, 3, datetime());
|
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, quantityAvailable, postedDate) VALUES ("Single Turbo", "turbo.bmp", "this is a product", 20.99, 1, 4, 3, datetime());
|
||||||
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, quantityAvailable, postedDate) VALUES ("Exhaust Manifold", "manifold.bmp", "This is a super cool product that can be installed into your car to take the gasses from the inside all the way to the outside. Mad I know.", 129.99, 1, 4, 2, datetime());
|
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, quantityAvailable, postedDate) VALUES ("Exhaust Manifold", "manifold.bmp", "This is a super cool product that can be installed into your car to take the gasses from the inside all the way to the outside. Mad I know.", 20.99, 1, 4, 2, datetime());
|
||||||
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, quantityAvailable, postedDate) VALUES ("17' Alloy Wheels", "alloy.bmp", "These super stylish alloys offer a fresh trendy look for your car. Whether a brand new Mercedes or a niffty little banger, it will uplift the vehicle 10-fold", 129.99, 1, 4, 1, datetime());
|
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, quantityAvailable, postedDate) VALUES ("17' Alloy Wheels", "alloy.bmp", "These super stylish alloys offer a fresh trendy look for your car. Whether a brand new Mercedes or a niffty little banger, it will uplift the vehicle 10-fold", 20.99, 1, 4, 1, datetime());
|
||||||
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, quantityAvailable, postedDate) VALUES ("Exhaust Manifold", "manifold.bmp", "This is a super cool product that can be installed into your car to take the gasses from the inside all the way to the outside. Mad I know.", 20.99, 1, 6, 7, datetime());
|
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, quantityAvailable, postedDate) VALUES ("Exhaust Manifold", "manifold.bmp", "This is a super cool product that can be installed into your car to take the gasses from the inside all the way to the outside. Mad I know.", 20.99, 1, 6, 7, datetime());
|
||||||
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, quantityAvailable, postedDate) VALUES ("Single Turbo", "turbo.bmp", "this is a product", 20.99, 1, 6, 1232, datetime());
|
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, quantityAvailable, postedDate) VALUES ("Single Turbo", "turbo.bmp", "this is a product", 20.99, 1, 6, 1232, datetime());
|
||||||
|
|
||||||
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("17' Alloy Wheels", "alloy.bmp", "These super stylish alloys offer a fresh trendy look for your car. Whether a brand new Mercedes or a niffty little banger, it will uplift the vehicle 10-fold", 20.99, 1, 1, datetime());
|
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("17' Alloy Wheels", "alloy.bmp", "These super stylish alloys offer a fresh trendy look for your car. Whether a brand new Mercedes or a niffty little banger, it will uplift the vehicle 10-fold", 20.99, 1, 1, datetime());
|
||||||
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("Exhaust Manifold", "manifold.bmp", "This is a super cool product that can be installed into your car to take the gasses from the inside all the way to the outside. Mad I know.", 20.99, 1, 1, datetime());
|
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("Exhaust Manifold", "manifold.bmp", "This is a super cool product that can be installed into your car to take the gasses from the inside all the way to the outside. Mad I know.", 20.99, 1, 1, datetime());
|
||||||
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("Single Turbo", "turbo.bmp", "this is a product", 17.37, 1, 1, datetime());
|
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("Single Turbo", "turbo.bmp", "this is a product", 20.99, 1, 1, datetime());
|
||||||
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("17' Alloy Wheels", "alloy.bmp", "These super stylish alloys offer a fresh trendy look for your car. Whether a brand new Mercedes or a niffty little banger, it will uplift the vehicle 10-fold", 17.37, 1, 2, datetime());
|
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("17' Alloy Wheels", "alloy.bmp", "These super stylish alloys offer a fresh trendy look for your car. Whether a brand new Mercedes or a niffty little banger, it will uplift the vehicle 10-fold", 20.99, 1, 2, datetime());
|
||||||
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("12' Brake Disks", "brake-disks.bmp", "this is a product", 17.37, 1, 2, datetime());
|
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("12' Brake Disks", "brake-disks.bmp", "this is a product", 20.99, 1, 2, datetime());
|
||||||
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("17' Alloy Wheels", "alloy.bmp", "These super stylish alloys offer a fresh trendy look for your car. Whether a brand new Mercedes or a niffty little banger, it will uplift the vehicle 10-fold", 17.37, 1, 3, datetime());
|
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("17' Alloy Wheels", "alloy.bmp", "These super stylish alloys offer a fresh trendy look for your car. Whether a brand new Mercedes or a niffty little banger, it will uplift the vehicle 10-fold", 20.99, 1, 3, datetime());
|
||||||
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("Exhaust Manifold", "manifold.bmp", "This is a super cool product that can be installed into your car to take the gasses from the inside all the way to the outside. Mad I know.", 17.37, 1, 4, datetime());
|
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("Exhaust Manifold", "manifold.bmp", "This is a super cool product that can be installed into your car to take the gasses from the inside all the way to the outside. Mad I know.", 20.99, 1, 4, datetime());
|
||||||
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("Single Turbo", "turbo.bmp", "this is a product", 20.99, 1, 4, datetime());
|
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("Single Turbo", "turbo.bmp", "this is a product", 20.99, 1, 4, datetime());
|
||||||
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("12' Brake Disks", "brake-disks.bmp", "this is a product", 6.99, 1, 4, datetime());
|
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("12' Brake Disks", "brake-disks.bmp", "this is a product", 20.99, 1, 4, datetime());
|
||||||
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("12' Brake Disks", "brake-disks.bmp", "this is a product", 20.99, 1, 6, datetime());
|
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("12' Brake Disks", "brake-disks.bmp", "this is a product", 20.99, 1, 6, datetime());
|
||||||
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("12' Brake Disks", "brake-disks.bmp", "this is a product", 20.99, 1, 6, datetime());
|
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("12' Brake Disks", "brake-disks.bmp", "this is a product", 20.99, 1, 6, datetime());
|
||||||
|
|
||||||
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("17' Alloy Wheels", "alloy.bmp", "These super stylish alloys offer a fresh trendy look for your car. Whether a brand new Mercedes or a niffty little banger, it will uplift the vehicle 10-fold", 20.99, 1, 1, datetime());
|
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("17' Alloy Wheels", "alloy.bmp", "These super stylish alloys offer a fresh trendy look for your car. Whether a brand new Mercedes or a niffty little banger, it will uplift the vehicle 10-fold", 20.99, 1, 1, datetime());
|
||||||
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("Exhaust Manifold", "manifold.bmp", "This is a super cool product that can be installed into your car to take the gasses from the inside all the way to the outside. Mad I know.", 20.99, 1, 1, datetime());
|
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("Exhaust Manifold", "manifold.bmp", "This is a super cool product that can be installed into your car to take the gasses from the inside all the way to the outside. Mad I know.", 20.99, 1, 1, datetime());
|
||||||
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("12' Brake Disks", "brake-disks.bmp", "this is a product", 6.99, 1, 1, datetime());
|
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("12' Brake Disks", "brake-disks.bmp", "this is a product", 20.99, 1, 1, datetime());
|
||||||
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("Single Turbo", "turbo.bmp", "this is a product", 6.99, 1, 2, datetime());
|
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("Single Turbo", "turbo.bmp", "this is a product", 20.99, 1, 2, datetime());
|
||||||
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("Single Turbo", "turbo.bmp", "this is a product", 69.99, 1, 2, datetime());
|
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("Single Turbo", "turbo.bmp", "this is a product", 20.99, 1, 2, datetime());
|
||||||
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("17' Alloy Wheels", "alloy.bmp", "These super stylish alloys offer a fresh trendy look for your car. Whether a brand new Mercedes or a niffty little banger, it will uplift the vehicle 10-fold", 20.99, 1, 3, datetime());
|
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("17' Alloy Wheels", "alloy.bmp", "These super stylish alloys offer a fresh trendy look for your car. Whether a brand new Mercedes or a niffty little banger, it will uplift the vehicle 10-fold", 20.99, 1, 3, datetime());
|
||||||
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("12' Brake Disks", "brake-disks.bmp", "this is a product", 20.99, 1, 4, datetime());
|
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("12' Brake Disks", "brake-disks.bmp", "this is a product", 20.99, 1, 4, datetime());
|
||||||
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("17' Alloy Wheels", "alloy.bmp", "These super stylish alloys offer a fresh trendy look for your car. Whether a brand new Mercedes or a niffty little banger, it will uplift the vehicle 10-fold", 6.99, 1, 4, datetime());
|
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("17' Alloy Wheels", "alloy.bmp", "These super stylish alloys offer a fresh trendy look for your car. Whether a brand new Mercedes or a niffty little banger, it will uplift the vehicle 10-fold", 20.99, 1, 4, datetime());
|
||||||
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("Single Turbo", "turbo.bmp", "this is a product", 69.99, 1, 4, datetime());
|
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("Single Turbo", "turbo.bmp", "this is a product", 20.99, 1, 4, datetime());
|
||||||
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("Exhaust Manifold", "manifold.bmp", "This is a super cool product that can be installed into your car to take the gasses from the inside all the way to the outside. Mad I know.", 6.99, 1, 6, datetime());
|
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("Exhaust Manifold", "manifold.bmp", "This is a super cool product that can be installed into your car to take the gasses from the inside all the way to the outside. Mad I know.", 20.99, 1, 6, datetime());
|
||||||
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("17' Alloy Wheels", "alloy.bmp", "These super stylish alloys offer a fresh trendy look for your car. Whether a brand new Mercedes or a niffty little banger, it will uplift the vehicle 10-fold", 20.99, 1, 6, datetime());
|
INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("17' Alloy Wheels", "alloy.bmp", "These super stylish alloys offer a fresh trendy look for your car. Whether a brand new Mercedes or a niffty little banger, it will uplift the vehicle 10-fold", 20.99, 1, 6, datetime());
|
||||||
|
|
||||||
INSERT INTO Views (userID, productID, viewDate) VALUES (1, 1, datetime());
|
INSERT INTO Views (userID, productID, viewDate) VALUES (1, 1, datetime());
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<a href="{{ url_for('main.products.product', id=product.id) }}" class="product product-link">
|
<a href="{{ url_for('main.products.product', id=product.id) }}" class="product product-link">
|
||||||
<div class="product-title">{{product.name}}</div>
|
<div class="product-title">{{product.name}}</div>
|
||||||
<div class="product-content-container">
|
<div class="product-content-container">
|
||||||
<img class="product-image-preview" src="{{ url_for('static', filename='assets/img/products/' + product.image) }}" alt="Brake Disks" loading="lazy"/>
|
<img class="product-image-preview" src="{{ url_for('static', filename='assets/img/products/' + product.image) }}" alt="Brake Disks" />
|
||||||
|
|
||||||
<div class="product-details">
|
<div class="product-details">
|
||||||
<div class="product-price">£{{product.cost}}</div>
|
<div class="product-price">£{{product.cost}}</div>
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
# Setup test environment variables
|
||||||
|
|
||||||
|
# Capture environment variables at start of testing so we can
|
||||||
|
# Monitor current setting during tests
|
||||||
|
old_env = os.environ.get("ENVIRON")
|
||||||
|
os.environ["ENVIRON"] = "test"
|
@ -1,39 +0,0 @@
|
|||||||
import pytest
|
|
||||||
import os
|
|
||||||
from scripts.create_database import run
|
|
||||||
from app import app
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
from flask.testing import FlaskClient
|
|
||||||
|
|
||||||
|
|
||||||
class TestBase:
|
|
||||||
""" Base test class that ensures environment variables
|
|
||||||
and test setup is complete before any other unit tests are run
|
|
||||||
"""
|
|
||||||
|
|
||||||
def setup_class(self):
|
|
||||||
""" Setup class level resources or configurations
|
|
||||||
Setup test environment variables
|
|
||||||
"""
|
|
||||||
load_dotenv()
|
|
||||||
|
|
||||||
# Capture environment variables at start of testing so we can
|
|
||||||
# Monitor current setting during tests
|
|
||||||
self.old_env = os.environ.get("ENVIRON")
|
|
||||||
os.environ["ENVIRON"] = "test"
|
|
||||||
|
|
||||||
run()
|
|
||||||
|
|
||||||
def teardown_class(self):
|
|
||||||
""" Teardown class level resources or configurations """
|
|
||||||
os.environ["ENVIRON"] = self.old_env
|
|
||||||
|
|
||||||
@pytest.fixture(scope="class")
|
|
||||||
def test_client(self) -> FlaskClient:
|
|
||||||
""" Enables tests to create requests to the web app
|
|
||||||
"""
|
|
||||||
os.environ['CONFIG_TYPE'] = 'config.TestingConfig'
|
|
||||||
|
|
||||||
with app.test_client() as testing_client:
|
|
||||||
with app.app_context():
|
|
||||||
yield testing_client
|
|
@ -1,67 +0,0 @@
|
|||||||
from bs4 import BeautifulSoup
|
|
||||||
from flask.testing import FlaskClient
|
|
||||||
from tests.base_test import TestBase
|
|
||||||
|
|
||||||
|
|
||||||
class TestFunctionalRequirements(TestBase):
|
|
||||||
def test_product_filters(self, test_client: FlaskClient):
|
|
||||||
base_url = '/products/Car Part?filter={{FILTER}}'
|
|
||||||
|
|
||||||
# Make get request for all products in car parts
|
|
||||||
response = test_client.get(
|
|
||||||
base_url.replace("{{FILTER}}", "Price: High -> Low")
|
|
||||||
)
|
|
||||||
assert response.status_code == 200
|
|
||||||
|
|
||||||
# Extract first and last product
|
|
||||||
first, last = self.get_first_and_last_product(response.data)
|
|
||||||
|
|
||||||
# Get Prices of each
|
|
||||||
first_cost = float(self.get_tag_value(
|
|
||||||
str(first), "product-price").replace('£', '')
|
|
||||||
)
|
|
||||||
last_cost = float(self.get_tag_value(
|
|
||||||
str(last), "product-price").replace('£', '')
|
|
||||||
)
|
|
||||||
|
|
||||||
# Check filter is working
|
|
||||||
assert first_cost >= last_cost
|
|
||||||
|
|
||||||
# =============================================
|
|
||||||
# Test the reverse of the previous filter
|
|
||||||
# Get html data
|
|
||||||
response = test_client.get(
|
|
||||||
base_url.replace("{{FILTER}}", "Price: Low -> High")
|
|
||||||
)
|
|
||||||
assert response.status_code == 200
|
|
||||||
|
|
||||||
# Extract first and last product
|
|
||||||
first, last = self.get_first_and_last_product(response.data)
|
|
||||||
|
|
||||||
# Get Prices of each
|
|
||||||
first_cost = float(self.get_tag_value(
|
|
||||||
str(first), "product-price").replace('£', '')
|
|
||||||
)
|
|
||||||
last_cost = float(self.get_tag_value(
|
|
||||||
str(last), "product-price").replace('£', '')
|
|
||||||
)
|
|
||||||
|
|
||||||
# Check filter is working
|
|
||||||
assert first_cost <= last_cost
|
|
||||||
|
|
||||||
def get_tag_value(self, html: str, class_name: str) -> str:
|
|
||||||
""" Returns the value of a given tag in a html element """
|
|
||||||
soup = BeautifulSoup(html, features='html.parser')
|
|
||||||
return str(soup.find("div", {'class': class_name}).contents[0])
|
|
||||||
|
|
||||||
def get_first_and_last_product(self, html: str) -> (str, str):
|
|
||||||
""" Returns the first and last product on the page """
|
|
||||||
soup = BeautifulSoup(html, features='html.parser')
|
|
||||||
|
|
||||||
products = soup.findAll("a", {"class": "product"})
|
|
||||||
|
|
||||||
assert len(products) > 0
|
|
||||||
first = products[0]
|
|
||||||
last = products[-1]
|
|
||||||
|
|
||||||
return (first, last)
|
|
41
tests/functional/test_homepage.py
Normal file
41
tests/functional/test_homepage.py
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
from app import app
|
||||||
|
from flask.testing import FlaskClient
|
||||||
|
import pytest
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def test_client() -> FlaskClient:
|
||||||
|
""" Test that required environment variables are set
|
||||||
|
ahead of runtime
|
||||||
|
"""
|
||||||
|
os.environ['CONFIG_TYPE'] = 'config.TestingConfig'
|
||||||
|
|
||||||
|
with app.test_client() as testing_client:
|
||||||
|
with app.app_context():
|
||||||
|
yield testing_client
|
||||||
|
|
||||||
|
|
||||||
|
def test_homepage(test_client: FlaskClient):
|
||||||
|
""" Tests that the main homepage loads correctly
|
||||||
|
once the '/' endpoint is hit
|
||||||
|
"""
|
||||||
|
response = test_client.get('/')
|
||||||
|
assert response.status_code == 302
|
||||||
|
|
||||||
|
response = test_client.get('/products')
|
||||||
|
assert response.status_code == 308
|
||||||
|
|
||||||
|
|
||||||
|
def test_products(test_client: FlaskClient):
|
||||||
|
""" Tests that a product page is displayed when
|
||||||
|
hitting one of the product endpoints
|
||||||
|
"""
|
||||||
|
response = test_client.get('/products/2')
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
response = test_client.get('/products/50')
|
||||||
|
assert response.status_code == 302
|
||||||
|
|
||||||
|
response = test_client.get('/products/Books')
|
||||||
|
assert response.status_code == 200
|
@ -1,41 +0,0 @@
|
|||||||
from flask.testing import FlaskClient
|
|
||||||
from tests.base_test import TestBase
|
|
||||||
|
|
||||||
|
|
||||||
class TestPages(TestBase):
|
|
||||||
""" Test class that encapsulates tests for
|
|
||||||
the main pages on the site
|
|
||||||
"""
|
|
||||||
|
|
||||||
def test_homepage(self, test_client: FlaskClient):
|
|
||||||
""" Tests that the main homepage loads correctly
|
|
||||||
once the '/' endpoint is hit
|
|
||||||
"""
|
|
||||||
response = test_client.get('/')
|
|
||||||
assert response.status_code == 302
|
|
||||||
|
|
||||||
response = test_client.get('/products')
|
|
||||||
assert response.status_code == 308
|
|
||||||
|
|
||||||
def test_products(self, test_client: FlaskClient):
|
|
||||||
""" Tests that a product page is displayed when
|
|
||||||
hitting one of the product endpoints
|
|
||||||
"""
|
|
||||||
response = test_client.get('/products/2')
|
|
||||||
assert response.status_code == 200
|
|
||||||
|
|
||||||
response = test_client.get('/products/50')
|
|
||||||
assert response.status_code == 302
|
|
||||||
|
|
||||||
response = test_client.get('/products/Books')
|
|
||||||
assert response.status_code == 200
|
|
||||||
|
|
||||||
def test_admin(self, test_client: FlaskClient):
|
|
||||||
""" Tests that the admin pages can be reached and redirect
|
|
||||||
upon reaching
|
|
||||||
"""
|
|
||||||
response = test_client.get('/admin/users/')
|
|
||||||
assert response.status_code == 302
|
|
||||||
|
|
||||||
response = test_client.get('/admin/products/')
|
|
||||||
assert response.status_code == 302
|
|
@ -0,0 +1,3 @@
|
|||||||
|
# Ensure test environment is set before using
|
||||||
|
# Runs the database creation scripts
|
||||||
|
import scripts.create_database
|
@ -1,8 +0,0 @@
|
|||||||
from tests.base_test import TestBase
|
|
||||||
|
|
||||||
|
|
||||||
class TestDatabase(TestBase):
|
|
||||||
""" Class that controls the
|
|
||||||
testing of the WMGZON database
|
|
||||||
"""
|
|
||||||
pass
|
|
@ -1,4 +1,5 @@
|
|||||||
from tests.unit.database.database_test_class import TestDatabase
|
import pytest
|
||||||
|
import sqlite3
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from controllers.database.product import ProductController
|
from controllers.database.product import ProductController
|
||||||
from models.products.product import Product
|
from models.products.product import Product
|
||||||
@ -14,35 +15,34 @@ product = Product(
|
|||||||
1
|
1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Tests a new product can be created
|
||||||
|
|
||||||
class TestProduct(TestDatabase):
|
|
||||||
""" Class that controls the
|
|
||||||
testing of the WMGZON database
|
|
||||||
"""
|
|
||||||
|
|
||||||
def test_create_product(self):
|
def test_create_product():
|
||||||
"""Tests a new product can be created"""
|
|
||||||
db = ProductController()
|
db = ProductController()
|
||||||
db.create(product)
|
db.create(product)
|
||||||
|
|
||||||
def test_duplicate_product(self):
|
# Tests the database maintains integrity when we try
|
||||||
""" Tests the database maintains integrity when we try
|
# and add a product with the same details
|
||||||
and add a product with the same detail
|
|
||||||
"""
|
|
||||||
self.test_create_product()
|
|
||||||
|
|
||||||
def test_search_category(self):
|
|
||||||
""" Tests that products can be refined by category """
|
def test_duplicate_product():
|
||||||
|
test_create_product()
|
||||||
|
|
||||||
|
# Tests that products can be refined by category
|
||||||
|
|
||||||
|
|
||||||
|
def test_search_category():
|
||||||
db = ProductController()
|
db = ProductController()
|
||||||
|
|
||||||
# Check each category for correct amount of test products
|
# Check each category for correct amount of test products
|
||||||
assert len(db.read_all("Car Parts")) == 9 + \
|
assert len(db.read_all("Car Parts")) == 9 + 2 # Added in previous tests
|
||||||
2 # Added in previous tests
|
|
||||||
assert len(db.read_all("Books")) == 9
|
assert len(db.read_all("Books")) == 9
|
||||||
assert db.read_all("Phones") is None
|
assert db.read_all("Phones") is None
|
||||||
|
|
||||||
def test_search_term(self):
|
|
||||||
""" Tests that products can be refined by search term"""
|
# Tests that products can be refined by search term
|
||||||
|
def test_search_term():
|
||||||
db = ProductController()
|
db = ProductController()
|
||||||
|
|
||||||
# Check each search term for correct amount of test products
|
# Check each search term for correct amount of test products
|
||||||
@ -51,8 +51,10 @@ class TestProduct(TestDatabase):
|
|||||||
assert len(db.read_all(search_term="fold")) == 8
|
assert len(db.read_all(search_term="fold")) == 8
|
||||||
assert db.read_all(search_term="Twin") is None
|
assert db.read_all(search_term="Twin") is None
|
||||||
|
|
||||||
def test_read_product(self):
|
# Test we the same product details get returned from the database
|
||||||
""" Test we the same product details get returned from the database """
|
|
||||||
|
|
||||||
|
def test_read_product():
|
||||||
db = ProductController()
|
db = ProductController()
|
||||||
|
|
||||||
# Test the same product is returned
|
# Test the same product is returned
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import pytest
|
import pytest
|
||||||
import sqlite3
|
import sqlite3
|
||||||
from tests.unit.database.database_test_class import TestDatabase
|
|
||||||
from controllers.database.user import UserController
|
from controllers.database.user import UserController
|
||||||
from models.users.customer import Customer
|
from models.users.customer import Customer
|
||||||
from models.users.seller import Seller
|
from models.users.seller import Seller
|
||||||
@ -23,27 +22,26 @@ seller = Seller(
|
|||||||
"987654321"
|
"987654321"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Tests a new user can be created
|
||||||
|
|
||||||
class TestUsers(TestDatabase):
|
|
||||||
""" Class to encapsulate all of the user
|
|
||||||
datbase tests
|
|
||||||
"""
|
|
||||||
|
|
||||||
def test_create_user(self):
|
def test_create_user():
|
||||||
""" Tests a new user can be created """
|
|
||||||
db = UserController()
|
db = UserController()
|
||||||
db.create(customer)
|
db.create(customer)
|
||||||
|
|
||||||
def test_duplicate_user(self):
|
# Tests the database maintains integrity when we try
|
||||||
""" Tests the database maintains integrity when we try
|
# and add a user with the same details
|
||||||
and add a user with the same details
|
|
||||||
"""
|
|
||||||
|
def test_duplicate_user():
|
||||||
db = UserController()
|
db = UserController()
|
||||||
with pytest.raises(sqlite3.IntegrityError):
|
with pytest.raises(sqlite3.IntegrityError):
|
||||||
db.create(customer)
|
db.create(customer)
|
||||||
|
|
||||||
def test_read_user(self):
|
# Test we the same user details get returned from the database
|
||||||
""" Test we the same user details get returned from the database """
|
|
||||||
|
|
||||||
|
def test_read_user():
|
||||||
db = UserController()
|
db = UserController()
|
||||||
|
|
||||||
# Test the same user is returned
|
# Test the same user is returned
|
||||||
@ -54,15 +52,16 @@ class TestUsers(TestDatabase):
|
|||||||
customer.id = user.id
|
customer.id = user.id
|
||||||
assert user.__dict__ == customer.__dict__
|
assert user.__dict__ == customer.__dict__
|
||||||
|
|
||||||
def test_create_seller(self):
|
|
||||||
""" Tests a new seller can be created """
|
# Tests a new seller can be created
|
||||||
|
def test_create_seller():
|
||||||
db = UserController()
|
db = UserController()
|
||||||
db.create(seller)
|
db.create(seller)
|
||||||
|
|
||||||
def test_read_seller(self):
|
# Test that the same seller details get returned from the database
|
||||||
""" Test that the same seller details get
|
|
||||||
returned from the database
|
|
||||||
"""
|
def test_read_seller():
|
||||||
db = UserController()
|
db = UserController()
|
||||||
|
|
||||||
# Test the same user is returned
|
# Test the same user is returned
|
||||||
|
@ -1,31 +1,31 @@
|
|||||||
from tests.base_test import TestBase
|
|
||||||
from os import environ
|
from os import environ
|
||||||
from warnings import warn
|
from warnings import warn
|
||||||
|
from tests import old_env
|
||||||
|
|
||||||
|
# Tests environment variables used within the projects domain are
|
||||||
|
# set in the correct environment
|
||||||
|
|
||||||
class TestEnv(TestBase):
|
|
||||||
""" Tests environment variables used within the projects domain are
|
|
||||||
set in the correct environment
|
|
||||||
"""
|
|
||||||
VARS = ['ENVIRON', 'APPSECRET', 'FILESTORE']
|
VARS = ['ENVIRON', 'APPSECRET', 'FILESTORE']
|
||||||
|
|
||||||
ENV_STATES = ['test', 'prod']
|
ENV_STATES = ['test', 'prod']
|
||||||
|
|
||||||
def test_env_vars(self):
|
|
||||||
|
def test_env_vars():
|
||||||
""" Test that required environment variables are set
|
""" Test that required environment variables are set
|
||||||
ahead of runtime
|
ahead of runtime
|
||||||
"""
|
"""
|
||||||
for var in self.VARS:
|
for var in VARS:
|
||||||
env = environ.get(var)
|
env = environ.get(var)
|
||||||
|
|
||||||
# Check to see what variable we are comparing
|
# Check to see what variable we are comparing
|
||||||
if env is None:
|
if env is None:
|
||||||
warn(f"Variable {var} is not set!")
|
warn(f"Variable {var} is not set!")
|
||||||
|
|
||||||
def test_environment_var_state(self):
|
|
||||||
|
def test_environment_var_state():
|
||||||
""" Tests that the 'ENVIRON' Environment variable
|
""" Tests that the 'ENVIRON' Environment variable
|
||||||
is in a correct state
|
is in a correct state
|
||||||
"""
|
"""
|
||||||
var = self.old_env
|
var = old_env
|
||||||
assert var is not None
|
assert var is not None
|
||||||
assert (var in self.ENV_STATES)
|
assert (var in ENV_STATES)
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
import pycodestyle
|
import pycodestyle
|
||||||
from tests.base_test import TestBase
|
|
||||||
|
|
||||||
# Tests files to ensure they conform to pep8 standards
|
# Tests files to ensure they conform to pep8 standards
|
||||||
|
|
||||||
|
|
||||||
class TestPep8(TestBase):
|
def test_pep8_conformance():
|
||||||
def test_pep8_conformance(self):
|
|
||||||
"""Test that we conform to PEP8."""
|
"""Test that we conform to PEP8."""
|
||||||
pep8style = pycodestyle.StyleGuide()
|
pep8style = pycodestyle.StyleGuide()
|
||||||
dirs = ["./controllers", "./models", "./scripts", "./tests", "./utils"]
|
dirs = ["./controllers", "./models", "./scripts", "./tests", "./utils"]
|
||||||
|
Loading…
Reference in New Issue
Block a user