Initial commit.
This commit is contained in:
4
.babelrc
Normal file
4
.babelrc
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"presets": ["@babel/preset-env"],
|
||||
"plugins": ["@babel/plugin-syntax-dynamic-import"]
|
||||
}
|
||||
77
.gitignore
vendored
Normal file
77
.gitignore
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
|
||||
# Ignore Git files
|
||||
git-filter-repo/
|
||||
|
||||
# Ignore compiled files
|
||||
*.class
|
||||
*.o
|
||||
*.pyc
|
||||
.VSCodeCounter/
|
||||
__pycache__/
|
||||
|
||||
# Ignore logs and databases
|
||||
*.log
|
||||
*.log.*
|
||||
|
||||
# Ignore logs and databases
|
||||
# *.sql
|
||||
# *.sqlite
|
||||
|
||||
# Ignore OS generated files
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
|
||||
# Ignore IDE and editor files
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
*.sublime-workspace
|
||||
|
||||
# Ignore package management directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
bower_components/
|
||||
|
||||
# Ignore build directories
|
||||
build/
|
||||
dist/
|
||||
out/
|
||||
|
||||
# Ignore environment and config files
|
||||
.env
|
||||
config.js
|
||||
secrets.yaml
|
||||
|
||||
# Ignore dependency lock files (uncomment if you want to ignore)
|
||||
# package-lock.json
|
||||
# yarn.lock
|
||||
|
||||
# Ignore personal TODO lists
|
||||
TODO.md
|
||||
|
||||
# Ignore all files in a directory
|
||||
tmp/
|
||||
|
||||
# Ignore all .txt files in the doc/ directory
|
||||
doc/*.txt
|
||||
|
||||
# But don't ignore doc/important.txt, even though we're ignoring .txt files above
|
||||
!doc/important.txt
|
||||
|
||||
# Ignore all .pdf files in the doc/ directory and any of its subdirectories
|
||||
doc/**/*.pdf
|
||||
|
||||
# Ignore deprecated files
|
||||
DEPRECATED/
|
||||
|
||||
# Ignore virtual environments
|
||||
bot_env/
|
||||
bot_web/
|
||||
env_test/
|
||||
env_web/
|
||||
7
.htaccess
Normal file
7
.htaccess
Normal file
@@ -0,0 +1,7 @@
|
||||
PassengerEnabled On
|
||||
PassengerAppRoot parts_website
|
||||
PassengerAppType wsgi
|
||||
PassengerStartupFile passenger_wsgi.py
|
||||
|
||||
# Optional: Set the Python interpreter if required
|
||||
PassengerPython /home/partsltd/virtualenv/public_html/parts_website/3.11/bin/python
|
||||
41
README.md
Normal file
41
README.md
Normal file
@@ -0,0 +1,41 @@
|
||||
Precision and Research Technology Systems Limited
|
||||
Website with online store
|
||||
|
||||
Powered by flask
|
||||
|
||||
enter virtual environment:
|
||||
python -m venv VIRTUAL_ENVIRONMENT_NAME
|
||||
|
||||
run module bundler:
|
||||
npm run build
|
||||
|
||||
host for machine:
|
||||
python -m flask run
|
||||
|
||||
host for local network:
|
||||
python -m flask run --host=0.0.0.0
|
||||
|
||||
|
||||
files dedicated to each page:
|
||||
CSS
|
||||
page
|
||||
HTML
|
||||
page
|
||||
row
|
||||
JavaScript
|
||||
page
|
||||
api
|
||||
router
|
||||
base - navigation buttons
|
||||
MySQL
|
||||
get
|
||||
save
|
||||
table
|
||||
staging table
|
||||
audit table
|
||||
Python
|
||||
business object
|
||||
controller
|
||||
datastore
|
||||
form
|
||||
model
|
||||
20
__init__.py
Normal file
20
__init__.py
Normal file
@@ -0,0 +1,20 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Backend
|
||||
Feature: Initialisation
|
||||
|
||||
Description:
|
||||
Initializes the Flask application.
|
||||
Initializes any extensions used in the project.
|
||||
"""
|
||||
|
||||
from flask import Flask
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config.from_object('config')
|
||||
|
||||
# from app import routes
|
||||
# import business_objects, lib, models
|
||||
129
app.py
Normal file
129
app.py
Normal file
@@ -0,0 +1,129 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: App General
|
||||
Feature: App
|
||||
|
||||
Description:
|
||||
Initializes the Flask application, sets the configuration based on the environment, and defines two routes (/ and /about) that render templates with the specified titles.
|
||||
"""
|
||||
|
||||
# IMPORTS
|
||||
# VARIABLE INSTANTIATION
|
||||
# METHODS
|
||||
|
||||
# IMPORTS
|
||||
# internal
|
||||
from config import app_config, Config
|
||||
from controllers.core.contact import routes_core_contact
|
||||
from controllers.core.home import routes_core_home
|
||||
from controllers.legal.legal import routes_legal
|
||||
from extensions import db, csrf, mail, oauth
|
||||
from helpers.helper_app import Helper_App
|
||||
# external
|
||||
from flask import Flask, render_template, jsonify, request, render_template_string, send_from_directory, redirect, url_for, session
|
||||
# from flask_appconfig import AppConfig
|
||||
from flask_cors import CORS
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from flask_mail import Mail, Message
|
||||
from flask_wtf.csrf import CSRFProtect
|
||||
from werkzeug.exceptions import HTTPException
|
||||
from authlib.integrations.flask_client import OAuth
|
||||
import os
|
||||
import sys
|
||||
from logging.handlers import RotatingFileHandler
|
||||
import traceback
|
||||
import logging
|
||||
|
||||
sys.path.insert(0, os.path.dirname(__file__)) # Todo: why?
|
||||
|
||||
|
||||
app = Flask(__name__)
|
||||
app.secret_key = os.getenv('KEY_SECRET_FLASK')
|
||||
|
||||
# AppConfig(app)
|
||||
app.config.from_object(app_config) # for db init with required keys
|
||||
app.app_config = app_config
|
||||
# app.config["config"] = app_config()
|
||||
|
||||
# logging
|
||||
handler = RotatingFileHandler('app.log', maxBytes=10000, backupCount=3)
|
||||
handler.setLevel(logging.DEBUG)
|
||||
app.logger.addHandler(handler)
|
||||
|
||||
@app.errorhandler(Exception)
|
||||
def internal_server_error(error):
|
||||
if isinstance(error, HTTPException) and error.code == 404:
|
||||
return "Not Found", 404
|
||||
|
||||
app.logger.error('Server Error: %s', (error))
|
||||
app.logger.error('Request: %s %s %s %s %s',
|
||||
request.remote_addr,
|
||||
request.method,
|
||||
request.scheme,
|
||||
request.full_path,
|
||||
request.headers)
|
||||
app.logger.error('Request data: %s', request.get_data())
|
||||
app.logger.error('Traceback: %s', traceback.format_exc())
|
||||
return "Internal Server Error", 500
|
||||
|
||||
@app.before_request
|
||||
def make_session_permanent():
|
||||
session.permanent = True
|
||||
|
||||
csrf = CSRFProtect()
|
||||
cors = CORS(app, resources={
|
||||
r"/static/*": {
|
||||
"origins": [app.config["URL_HOST"]],
|
||||
"methods": ["GET"],
|
||||
"max_age": 3600
|
||||
}
|
||||
})
|
||||
|
||||
csrf.init_app(app)
|
||||
cors.init_app(app)
|
||||
db.init_app(app)
|
||||
mail.init_app(app)
|
||||
oauth.init_app(app)
|
||||
|
||||
with app.app_context():
|
||||
# config = app.config["config"]
|
||||
db.create_all()
|
||||
db.engine.url = app.config['SQLALCHEMY_DATABASE_URI']
|
||||
|
||||
oauth.register(
|
||||
"auth0",
|
||||
client_id = app.config['ID_AUTH0_CLIENT'],
|
||||
client_secret = app.config['ID_AUTH0_CLIENT_SECRET'],
|
||||
client_kwargs={
|
||||
"scope": "openid profile email",
|
||||
},
|
||||
server_metadata_url=f'https://{app.config["DOMAIN_AUTH0"]}/.well-known/openid-configuration',
|
||||
api_base_url = f'https://{app.config["DOMAIN_AUTH0"]}',
|
||||
authorize_url = f'https://{app.config["DOMAIN_AUTH0"]}/authorize',
|
||||
access_token_url = f'https://{app.config["DOMAIN_AUTH0"]}/oauth/token',
|
||||
)
|
||||
|
||||
|
||||
app.register_blueprint(routes_core_home)
|
||||
app.register_blueprint(routes_core_contact)
|
||||
app.register_blueprint(routes_legal)
|
||||
|
||||
|
||||
|
||||
@app.template_filter('console_log')
|
||||
def console_log(value):
|
||||
Helper_App.console_log(value)
|
||||
return value
|
||||
|
||||
@app.after_request
|
||||
def add_cache_headers(response):
|
||||
if request.path.startswith('/static/'):
|
||||
# Cache static assets
|
||||
response.headers['Cache-Control'] = 'public, max-age=31536000'
|
||||
else:
|
||||
# No caching for dynamic content
|
||||
response.headers['Cache-Control'] = 'no-store, no-cache, must-revalidate, max-age=0'
|
||||
return response
|
||||
11
business_objects/__init__.py
Normal file
11
business_objects/__init__.py
Normal file
@@ -0,0 +1,11 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Module Initialisation
|
||||
Feature: Business Objects
|
||||
|
||||
Description:
|
||||
Initialises business objects module.
|
||||
"""
|
||||
32
business_objects/api.py
Normal file
32
business_objects/api.py
Normal file
@@ -0,0 +1,32 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Business Objects
|
||||
Feature: Base Business Object
|
||||
|
||||
Description:
|
||||
Abstract business object
|
||||
"""
|
||||
|
||||
# internal
|
||||
from extensions import db
|
||||
import lib.argument_validation as av
|
||||
# external
|
||||
from typing import ClassVar
|
||||
from flask import jsonify
|
||||
|
||||
|
||||
class API():
|
||||
|
||||
@staticmethod
|
||||
def get_standard_response(success: bool, status_code: int, message: str, data: any, errors: list, meta: dict):
|
||||
return jsonify({
|
||||
"success": success,
|
||||
"status_code": status_code,
|
||||
"message": message,
|
||||
"data": data,
|
||||
"errors": errors,
|
||||
"meta": meta
|
||||
})
|
||||
90
business_objects/base.py
Normal file
90
business_objects/base.py
Normal file
@@ -0,0 +1,90 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Business Objects
|
||||
Feature: Base Business Object
|
||||
|
||||
Description:
|
||||
Abstract base class for all business objects in app
|
||||
"""
|
||||
|
||||
# internal
|
||||
from extensions import db
|
||||
import lib.argument_validation as av
|
||||
# external
|
||||
from typing import ClassVar
|
||||
|
||||
|
||||
class Base():
|
||||
ATTR_ID_ACCESS_LEVEL: ClassVar[str] = 'id_access_level'
|
||||
ATTR_ID_ADDRESS: ClassVar[str] = 'id_address'
|
||||
ATTR_ID_CURRENCY: ClassVar[str] = 'id_currency'
|
||||
ATTR_ID_MSG_ERROR_TYPE: ClassVar[str] = 'id_type'
|
||||
ATTR_ID_REGION: ClassVar[str] = 'id_region'
|
||||
ATTR_ID_USER: ClassVar[str] = 'id_user'
|
||||
ATTR_ID_USER_MANAGER: ClassVar[str] = 'id_user_manager'
|
||||
FLAG_ACCESS_LEVEL_REQUIRED: ClassVar[str] = 'access_level_required'
|
||||
FLAG_ACTIVE: ClassVar[str] = 'active'
|
||||
FLAG_ADDRESS: ClassVar[str] = 'address'
|
||||
FLAG_ADDRESS_LINE_1: ClassVar[str] = 'address_line_1'
|
||||
FLAG_ADDRESS_LINE_2: ClassVar[str] = 'address_line_2'
|
||||
FLAG_CAN_ADMIN: ClassVar[str] = 'can_admin'
|
||||
FLAG_CAN_EDIT: ClassVar[str] = 'can_edit'
|
||||
FLAG_CAN_VIEW: ClassVar[str] = 'can_view'
|
||||
FLAG_CITY: ClassVar[str] = 'city'
|
||||
FLAG_CODE: ClassVar[str] = 'code'
|
||||
FLAG_COUNTY: ClassVar[str] = 'county'
|
||||
FLAG_CREATED_BY: ClassVar[str] = 'created_by'
|
||||
FLAG_CREATED_ON: ClassVar[str] = 'created_on'
|
||||
FLAG_CURRENCY: ClassVar[str] = 'currency'
|
||||
FLAG_CURRENCY_COST: ClassVar[str] = 'currency_cost'
|
||||
FLAG_DATE_FROM: ClassVar[str] = 'date_from'
|
||||
FLAG_DATE_TO: ClassVar[str] = 'date_to'
|
||||
FLAG_DESCRIPTION: ClassVar[str] = 'description'
|
||||
FLAG_DISPLAY_ORDER: ClassVar[str] = 'display_order'
|
||||
FLAG_EDIT: ClassVar[str] = 'edit'
|
||||
FLAG_EMAIL: ClassVar[str] = 'email'
|
||||
FLAG_FAX: ClassVar[str] = 'fax'
|
||||
FLAG_GUID: ClassVar[str] = 'guid'
|
||||
FLAG_IS_NOT_EMPTY: ClassVar[str] = 'is_not_empty'
|
||||
# FLAG_KEY_PRIMARY: ClassVar[str] = 'key_primary'
|
||||
FLAG_MESSAGE: ClassVar[str] = 'message'
|
||||
FLAG_NAME: ClassVar[str] = 'name'
|
||||
FLAG_NAME_ATTR_OPTION_TEXT: ClassVar[str] = 'NAME_ATTR_OPTION_TEXT'
|
||||
FLAG_NAME_ATTR_OPTION_VALUE: ClassVar[str] = 'NAME_ATTR_OPTION_VALUE'
|
||||
FLAG_NAME_SINGULAR: ClassVar[str] = 'name_singular'
|
||||
FLAG_NAME_PLURAL: ClassVar[str] = 'name_plural'
|
||||
FLAG_PHONE_NUMBER: ClassVar[str] = 'phone_number'
|
||||
FLAG_POSTCODE: ClassVar[str] = 'postcode'
|
||||
FLAG_PRIORITY: ClassVar[str] = 'priority'
|
||||
FLAG_REGION: ClassVar[str] = 'region'
|
||||
FLAG_ROWS: ClassVar[str] = 'rows'
|
||||
FLAG_SYMBOL: ClassVar[str] = 'symbol'
|
||||
FLAG_URL: ClassVar[str] = 'url'
|
||||
FLAG_USER: ClassVar[str] = 'authorisedUser' # 'user' already used
|
||||
FLAG_VALUE_LOCAL_VAT_EXCL: ClassVar[str] = 'value_local_vat_excl'
|
||||
FLAG_VALUE_LOCAL_VAT_INCL: ClassVar[str] = 'value_local_vat_incl'
|
||||
FLAG_WEBSITE: ClassVar[str] = 'website'
|
||||
ID_USER_GUEST: ClassVar[int] = 3
|
||||
"""
|
||||
NAME_ATTR_OPTION_TEXT: ClassVar[str] = 'name-attribute-option-text'
|
||||
NAME_ATTR_OPTION_VALUE: ClassVar[str] = 'name-attribute-option-value'
|
||||
"""
|
||||
def __repr__(self):
|
||||
attrs = '\n'.join(f'{k}={v!r}' for k, v in self.__dict__.items())
|
||||
return f'<{self.__class__.__name__}(\n{attrs}\n)>'
|
||||
|
||||
@classmethod
|
||||
def output_bool(cls, value):
|
||||
return av.input_bool(value, f'{cls.__name__} bool attribute', f'{cls.__name__}.output_bool')
|
||||
@staticmethod
|
||||
def convert_list_objects_to_list_options(objects):
|
||||
return [object.to_json_option() for object in objects]
|
||||
@classmethod
|
||||
def get_shared_json_attributes(cls, object):
|
||||
return {
|
||||
cls.FLAG_NAME_ATTR_OPTION_TEXT: object.NAME_ATTR_OPTION_TEXT,
|
||||
cls.FLAG_NAME_ATTR_OPTION_VALUE: object.NAME_ATTR_OPTION_VALUE
|
||||
}
|
||||
48
business_objects/db_base.py
Normal file
48
business_objects/db_base.py
Normal file
@@ -0,0 +1,48 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Business Objects
|
||||
Feature: Database Base Business Objects
|
||||
|
||||
Description:
|
||||
Abstract base class for database objects
|
||||
"""
|
||||
|
||||
# internal
|
||||
# from helpers.DEPRECATED.helper_abc import Interface_ABC
|
||||
from extensions import db
|
||||
import lib.argument_validation as av
|
||||
# external
|
||||
from typing import ClassVar
|
||||
from abc import abstractmethod, ABCMeta
|
||||
from pydantic import BaseModel
|
||||
from sqlalchemy.ext.declarative import DeclarativeMeta
|
||||
# from flask_sqlalchemy import SQLAlchemy
|
||||
|
||||
|
||||
|
||||
class SQLAlchemy_ABCMeta(db.Model.__class__, ABCMeta):
|
||||
pass
|
||||
|
||||
class SQLAlchemy_ABC(db.Model, metaclass=SQLAlchemy_ABCMeta):
|
||||
__abstract__ = True
|
||||
# id = db.Column(db.Integer, primary_key=True)
|
||||
def __init__(self):
|
||||
pass
|
||||
def __repr__(self):
|
||||
pass
|
||||
def to_json(self):
|
||||
pass
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
pass
|
||||
def to_temporary_record(self):
|
||||
pass
|
||||
def to_object_with_missing_attributes(self, excluded_attributes):
|
||||
return {
|
||||
column.name: getattr(self, column.name)
|
||||
for column in self.__table__.columns
|
||||
if column.name not in excluded_attributes
|
||||
}
|
||||
82
business_objects/dog/DEPRECATED - access_level.py
Normal file
82
business_objects/dog/DEPRECATED - access_level.py
Normal file
@@ -0,0 +1,82 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Business Objects
|
||||
Feature: Product Category Business Object
|
||||
|
||||
Description:
|
||||
Business object for product
|
||||
"""
|
||||
|
||||
# internal
|
||||
import lib.argument_validation as av
|
||||
from business_objects.base import Base
|
||||
from extensions import db
|
||||
from helpers.helper_app import Helper_App
|
||||
# external
|
||||
from pydantic import BaseModel
|
||||
from typing import ClassVar
|
||||
|
||||
|
||||
class Access_Level(db.Model, Base):
|
||||
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Base.ATTR_ID_ACCESS_LEVEL
|
||||
NAME_ATTR_OPTION_TEXT: ClassVar[str] = Base.FLAG_NAME
|
||||
__tablename__ = 'PH_Access_Level_Temp'
|
||||
id_access_level = db.Column(db.Integer, primary_key=True)
|
||||
code = db.Column(db.String(50))
|
||||
name = db.Column(db.String(250))
|
||||
priority = db.Column(db.Integer)
|
||||
display_order = db.Column(db.Integer)
|
||||
active = db.Column(db.Boolean)
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
Base.__init__(self)
|
||||
@classmethod
|
||||
def from_DB_access_level(cls, query_row):
|
||||
access_level = cls()
|
||||
access_level.id_access_level = query_row[0]
|
||||
access_level.code = query_row[1]
|
||||
access_level.name = query_row[2]
|
||||
access_level.priority = query_row[3]
|
||||
access_level.display_order = query_row[4]
|
||||
access_level.active = query_row[5]
|
||||
return access_level
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
id: {self.id_access_level[0] if isinstance(self.id_access_level, tuple) else self.id_access_level}
|
||||
code: {self.code[0] if isinstance(self.code, tuple) else self.code}
|
||||
name: {self.name[0] if isinstance(self.name, tuple) else self.name}
|
||||
description: {self.description[0] if isinstance(self.description, tuple) else self.description}
|
||||
priority: {self.priority[0] if isinstance(self.priority, tuple) else self.priority}
|
||||
display_order: {self.display_order}
|
||||
active: {self.active}
|
||||
'''
|
||||
def to_json(self):
|
||||
return {
|
||||
**self.get_shared_json_attributes(self),
|
||||
self.ATTR_ID_ACCESS_LEVEL: self.id_access_level[0] if isinstance(self.id_access_level, tuple) else self.id_access_level,
|
||||
self.FLAG_CODE: self.code[0] if isinstance(self.code, tuple) else self.code,
|
||||
self.FLAG_NAME: self.name[0] if isinstance(self.name, tuple) else self.name,
|
||||
self.FLAG_DESCRIPTION: self.description[0] if isinstance(self.description, tuple) else self.description,
|
||||
self.FLAG_PRIORITY: self.priority[0] if isinstance(self.priority, tuple) else self.priority,
|
||||
self.FLAG_DISPLAY_ORDER: self.display_order,
|
||||
self.FLAG_ACTIVE: av.input_bool(self.active, self.FLAG_ACTIVE, f'{self.__class__.__name__}.to_json')
|
||||
}
|
||||
def to_json_option(self):
|
||||
return {
|
||||
'value': self.id_access_level,
|
||||
'text': self.name
|
||||
}
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
access_level = cls()
|
||||
access_level.id_access_level = json[cls.ATTR_ID_ACCESS_LEVEL],
|
||||
access_level.code = json[cls.FLAG_CODE],
|
||||
access_level.name = json[cls.FLAG_NAME],
|
||||
access_level.priority = json[cls.FLAG_PRIORITY],
|
||||
access_level.description = json[cls.FLAG_DESCRIPTION],
|
||||
access_level.display_order = json[cls.FLAG_DISPLAY_ORDER]
|
||||
access_level.active = json[cls.FLAG_ACTIVE]
|
||||
return access_level
|
||||
0
business_objects/dog/__init__.py
Normal file
0
business_objects/dog/__init__.py
Normal file
136
business_objects/dog/command.py
Normal file
136
business_objects/dog/command.py
Normal file
@@ -0,0 +1,136 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Business Objects
|
||||
Feature: Command Business Object
|
||||
"""
|
||||
|
||||
# internal
|
||||
from business_objects.base import Base
|
||||
from business_objects.db_base import SQLAlchemy_ABC
|
||||
import lib.argument_validation as av
|
||||
from extensions import db
|
||||
from helpers.helper_app import Helper_App
|
||||
# external
|
||||
from dataclasses import dataclass
|
||||
from typing import ClassVar
|
||||
|
||||
|
||||
class Command(SQLAlchemy_ABC, Base):
|
||||
FLAG_ALTCHA: ClassVar[str] = 'altcha'
|
||||
FLAG_COMMAND: ClassVar[str] = 'command'
|
||||
FLAG_NAME_COMPANY: ClassVar[str] = 'name-company'
|
||||
FLAG_NAME_CONTACT: ClassVar[str] = 'name-contact'
|
||||
FLAG_MESSAGE: ClassVar[str] = 'message'
|
||||
FLAG_RECEIVE_MARKETING_COMMUNICATIONS: ClassVar[str] = 'receive-marketing-communications'
|
||||
NAME_ATTR_OPTION_VALUE: ClassVar[str] = FLAG_COMMAND
|
||||
NAME_ATTR_OPTION_TEXT: ClassVar[str] = Base.FLAG_EMAIL
|
||||
|
||||
__tablename__ = 'PH_Command'
|
||||
__table_args__ = { 'extend_existing': True }
|
||||
|
||||
id_command = db.Column(db.Integer, primary_key=True)
|
||||
email = db.Column(db.String(250))
|
||||
name_contact = db.Column(db.String(250))
|
||||
name_company = db.Column(db.String(250))
|
||||
message = db.Column(db.Text)
|
||||
receive_marketing_communications = db.Column(db.Boolean)
|
||||
active = db.Column(db.Boolean)
|
||||
created_on = db.Column(db.DateTime)
|
||||
|
||||
def __init__(self):
|
||||
self.id_command = 0
|
||||
self.is_new = False
|
||||
super().__init__()
|
||||
|
||||
def from_DB_Command(query_row):
|
||||
_m = 'Command.from_DB_Command'
|
||||
command = Command()
|
||||
command.id_command = query_row[0]
|
||||
command.email = query_row[1]
|
||||
command.name_contact = query_row[2]
|
||||
command.name_company = query_row[3]
|
||||
command.message = query_row[4]
|
||||
command.receive_marketing_communications = av.input_bool(query_row[5], 'receive_marketing_communications', _m)
|
||||
command.active = av.input_bool(query_row[6], 'active', _m)
|
||||
command.created_on = query_row[7]
|
||||
return command
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
_m = 'Command.from_json'
|
||||
command = cls()
|
||||
if json is None: return Command
|
||||
Helper_App.console_log(f'{_m}\njson: {json}')
|
||||
command.id_command = -1
|
||||
command.email = json[cls.FLAG_EMAIL]
|
||||
command.name_contact = json[cls.FLAG_NAME_CONTACT]
|
||||
command.name_company = json[cls.FLAG_NAME_COMPANY]
|
||||
command.message = json[cls.FLAG_MESSAGE]
|
||||
command.receive_marketing_communications = json[cls.FLAG_RECEIVE_MARKETING_COMMUNICATIONS]
|
||||
command.active = json[cls.FLAG_ACTIVE]
|
||||
command.created_on = json.get(cls.FLAG_CREATED_ON, None)
|
||||
Helper_App.console_log(f'Command: {command}')
|
||||
return command
|
||||
|
||||
|
||||
def to_json(self):
|
||||
as_json = {
|
||||
self.FLAG_COMMAND: self.id_command
|
||||
, self.FLAG_EMAIL: self.email
|
||||
, self.FLAG_NAME_CONTACT: self.name_contact
|
||||
, self.FLAG_NAME_COMPANY: self.name_company
|
||||
, self.FLAG_MESSAGE: self.message
|
||||
, self.FLAG_RECEIVE_MARKETING_COMMUNICATIONS: self.receive_marketing_communications
|
||||
, self.FLAG_ACTIVE: self.active
|
||||
, self.FLAG_CREATED_ON: self.created_on
|
||||
}
|
||||
Helper_App.console_log(f'as_json: {as_json}')
|
||||
return as_json
|
||||
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
{self.__class__.__name__}(
|
||||
{self.FLAG_COMMAND}: {self.id_command}
|
||||
{self.FLAG_EMAIL}: {self.email}
|
||||
{self.FLAG_NAME_CONTACT}: {self.name_contact}
|
||||
{self.FLAG_NAME_COMPANY}: {self.name_company}
|
||||
{self.FLAG_MESSAGE}: {self.message}
|
||||
{self.FLAG_RECEIVE_MARKETING_COMMUNICATIONS}: {self.receive_marketing_communications}
|
||||
{self.FLAG_ACTIVE}: {self.active}
|
||||
{self.FLAG_CREATED_ON}: {self.created_on}
|
||||
)
|
||||
'''
|
||||
|
||||
class Command_Temp(db.Model, Base):
|
||||
__tablename__ = 'PH_Command_Temp'
|
||||
__table_args__ = { 'extend_existing': True }
|
||||
id_temp = db.Column(db.Integer, primary_key=True)
|
||||
id_command = db.Column(db.Integer)
|
||||
email = db.Column(db.String(250))
|
||||
name_contact = db.Column(db.String(250))
|
||||
name_company = db.Column(db.String(250))
|
||||
message = db.Column(db.Text)
|
||||
receive_marketing_communications = db.Column(db.Boolean)
|
||||
active = db.Column(db.Boolean)
|
||||
created_on = db.Column(db.DateTime)
|
||||
guid: str = db.Column(db.String(36))
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
@classmethod
|
||||
def from_command(cls, command):
|
||||
_m = 'Command_Temp.from_Command'
|
||||
temp = cls()
|
||||
temp.id_command = command.id_command
|
||||
temp.email = command.email
|
||||
temp.name_contact = command.name_contact
|
||||
temp.name_company = command.name_company
|
||||
temp.message = command.message
|
||||
temp.receive_marketing_communications = command.receive_marketing_communications
|
||||
temp.active = command.active
|
||||
temp.created_on = command.created_on
|
||||
return temp
|
||||
126
business_objects/dog/dog.py
Normal file
126
business_objects/dog/dog.py
Normal file
@@ -0,0 +1,126 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Business Objects
|
||||
Feature: Dog Business Object
|
||||
"""
|
||||
|
||||
# internal
|
||||
from business_objects.base import Base
|
||||
from business_objects.db_base import SQLAlchemy_ABC
|
||||
import lib.argument_validation as av
|
||||
from extensions import db
|
||||
from helpers.helper_app import Helper_App
|
||||
# external
|
||||
from dataclasses import dataclass
|
||||
from typing import ClassVar
|
||||
|
||||
|
||||
class Dog(SQLAlchemy_ABC, Base):
|
||||
FLAG_DOG: ClassVar[str] = 'dog'
|
||||
FLAG_APPEARANCE: ClassVar[str] = 'appearance'
|
||||
FLAG_MASS_KG: ClassVar[str] = 'mass-kg'
|
||||
FLAG_NOTES: ClassVar[str] = 'notes'
|
||||
NAME_ATTR_OPTION_VALUE: ClassVar[str] = FLAG_DOG
|
||||
NAME_ATTR_OPTION_TEXT: ClassVar[str] = Base.FLAG_EMAIL
|
||||
|
||||
__tablename__ = 'PH_Dog'
|
||||
__table_args__ = { 'extend_existing': True }
|
||||
|
||||
id_dog = db.Column(db.Integer, primary_key=True)
|
||||
name = db.Column(db.String(250))
|
||||
appearance = db.Column(db.String(1000))
|
||||
mass_kg = db.Column(db.Numeric(precision=7, scale=3))
|
||||
notes = db.Column(db.Text)
|
||||
active = db.Column(db.Boolean)
|
||||
|
||||
def __init__(self):
|
||||
self.id_dog = 0
|
||||
self.is_new = False
|
||||
super().__init__()
|
||||
|
||||
def from_DB_Dog(query_row):
|
||||
_m = 'Dog.from_DB_Dog'
|
||||
dog = Dog()
|
||||
dog.id_dog = query_row[0]
|
||||
dog.name = query_row[1]
|
||||
dog.appearance = query_row[2]
|
||||
dog.mass_kg = query_row[3]
|
||||
dog.notes = query_row[4]
|
||||
dog.active = av.input_bool(query_row[5], 'active', _m)
|
||||
return dog
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
_m = 'Dog.from_json'
|
||||
dog = cls()
|
||||
if json is None: return Dog
|
||||
Helper_App.console_log(f'{_m}\njson: {json}')
|
||||
dog.id_dog = -1
|
||||
dog.name = json[cls.FLAG_NAME]
|
||||
dog.appearance = json[cls.FLAG_APPEARANCE]
|
||||
dog.mass_kg = json[cls.FLAG_MASS_KG]
|
||||
dog.notes = json[cls.FLAG_NOTES]
|
||||
dog.active = json[cls.FLAG_ACTIVE]
|
||||
Helper_App.console_log(f'Dog: {dog}')
|
||||
return dog
|
||||
|
||||
|
||||
def to_json(self):
|
||||
as_json = {
|
||||
self.FLAG_DOG: self.id_dog
|
||||
, self.FLAG_NAME: self.name
|
||||
, self.FLAG_APPEARANCE: self.appearance
|
||||
, self.FLAG_MASS_KG: self.mass_kg
|
||||
, self.FLAG_NOTES: self.notes
|
||||
, self.FLAG_ACTIVE: self.active
|
||||
}
|
||||
Helper_App.console_log(f'as_json: {as_json}')
|
||||
return as_json
|
||||
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
{self.__class__.__name__}(
|
||||
{self.FLAG_DOG}: {self.id_dog}
|
||||
{self.FLAG_NAME}: {self.name}
|
||||
{self.FLAG_APPEARANCE}: {self.appearance}
|
||||
{self.FLAG_MASS_KG}: {self.mass_kg}
|
||||
{self.FLAG_NOTES}: {self.notes}
|
||||
{self.FLAG_ACTIVE}: {self.active}
|
||||
)
|
||||
'''
|
||||
|
||||
"""
|
||||
class Dog_Temp(db.Model, Base):
|
||||
__tablename__ = 'PH_Dog_Temp'
|
||||
__table_args__ = { 'extend_existing': True }
|
||||
id_temp = db.Column(db.Integer, primary_key=True)
|
||||
id_dog = db.Column(db.Integer)
|
||||
email = db.Column(db.String(250))
|
||||
name_contact = db.Column(db.String(250))
|
||||
name_company = db.Column(db.String(250))
|
||||
message = db.Column(db.Text)
|
||||
receive_marketing_communications = db.Column(db.Boolean)
|
||||
active = db.Column(db.Boolean)
|
||||
created_on = db.Column(db.DateTime)
|
||||
guid: str = db.Column(db.String(36))
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
@classmethod
|
||||
def from_dog(cls, dog):
|
||||
_m = 'Dog_Temp.from_Dog'
|
||||
temp = cls()
|
||||
temp.id_dog = dog.id_dog
|
||||
temp.email = dog.email
|
||||
temp.name_contact = dog.name_contact
|
||||
temp.name_company = dog.name_company
|
||||
temp.message = dog.message
|
||||
temp.receive_marketing_communications = dog.receive_marketing_communications
|
||||
temp.active = dog.active
|
||||
temp.created_on = dog.created_on
|
||||
return temp
|
||||
"""
|
||||
133
business_objects/dog/user.py
Normal file
133
business_objects/dog/user.py
Normal file
@@ -0,0 +1,133 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Business Objects
|
||||
Feature: User Business Object
|
||||
"""
|
||||
|
||||
# internal
|
||||
from business_objects.base import Base
|
||||
from business_objects.db_base import SQLAlchemy_ABC
|
||||
import lib.argument_validation as av
|
||||
from forms.forms import Form_Contact
|
||||
from extensions import db
|
||||
from helpers.helper_app import Helper_App
|
||||
# external
|
||||
from dataclasses import dataclass
|
||||
from typing import ClassVar
|
||||
|
||||
|
||||
class User(SQLAlchemy_ABC, Base):
|
||||
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Base.ATTR_ID_USER
|
||||
NAME_ATTR_OPTION_TEXT: ClassVar[str] = 'email'
|
||||
|
||||
__tablename__ = 'PH_User'
|
||||
__table_args__ = { 'extend_existing': True }
|
||||
|
||||
id_user = db.Column(db.Integer, primary_key=True)
|
||||
id_user_auth0 = db.Column(db.String(250))
|
||||
firstname = db.Column(db.String(250))
|
||||
surname = db.Column(db.String(250))
|
||||
email = db.Column(db.String(250))
|
||||
is_email_verified = db.Column(db.Boolean)
|
||||
is_super_user = db.Column(db.Boolean)
|
||||
is_new = db.Column(db.Boolean)
|
||||
|
||||
def __init__(self):
|
||||
self.id_user = 0
|
||||
self.is_new = False
|
||||
super().__init__()
|
||||
|
||||
def from_DB_user(query_row):
|
||||
_m = 'User.from_DB_user'
|
||||
user = User()
|
||||
user.id_user = query_row[0]
|
||||
user.id_user_auth0 = query_row[1]
|
||||
user.firstname = query_row[2]
|
||||
user.surname = query_row[3]
|
||||
user.email = query_row[4]
|
||||
user.is_email_verified = av.input_bool(query_row[5], 'is_email_verified', _m)
|
||||
user.is_super_user = av.input_bool(query_row[9], 'is_super_user', _m)
|
||||
user.is_new = av.input_bool(query_row[12], 'is_new', _m)
|
||||
return user
|
||||
|
||||
@staticmethod
|
||||
def from_json(json):
|
||||
_m = 'User.from_json'
|
||||
user = User()
|
||||
if json is None: return user
|
||||
Helper_App.console_log(f'{_m}\njson: {json}')
|
||||
user.id_user = json['id_user']
|
||||
user.id_user_auth0 = json['id_user_auth0']
|
||||
user.firstname = json['firstname']
|
||||
user.surname = json['surname']
|
||||
user.email = json['email']
|
||||
user.is_email_verified = av.input_bool(json['is_email_verified'], 'is_email_verified', _m)
|
||||
user.is_super_user = av.input_bool(json['is_super_user'], 'is_super_user', _m)
|
||||
Helper_App.console_log(f'user: {user}')
|
||||
return user
|
||||
|
||||
@staticmethod
|
||||
def from_json_auth0(json):
|
||||
_m = 'User.from_json_auth0'
|
||||
user = User()
|
||||
if json is None: return user
|
||||
Helper_App.console_log(f'{_m}\njson: {json}')
|
||||
user_info = json['userinfo']
|
||||
user.id_user = None
|
||||
user.id_user_auth0 = user_info['sub']
|
||||
user.firstname = None
|
||||
user.surname = None
|
||||
user.email = user_info['email']
|
||||
user.is_email_verified = av.input_bool(user_info['email_verified'], 'is_email_verified', _m)
|
||||
user.is_super_user = None
|
||||
Helper_App.console_log(f'user: {user}')
|
||||
return user
|
||||
|
||||
def to_json(self):
|
||||
as_json = {
|
||||
'id_user': self.id_user,
|
||||
'id_user_auth0': self.id_user_auth0,
|
||||
'firstname': self.firstname,
|
||||
'surname': self.surname,
|
||||
'email': self.email,
|
||||
'is_email_verified': self.is_email_verified,
|
||||
'is_super_user': self.is_super_user
|
||||
}
|
||||
Helper_App.console_log(f'as_json: {as_json}')
|
||||
return as_json
|
||||
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
id_user: {self.id_user}
|
||||
id_user_auth0: {self.id_user_auth0}
|
||||
firstname: {self.firstname}
|
||||
surname: {self.surname}
|
||||
email: {self.email}
|
||||
is_email_verified: {self.is_email_verified}
|
||||
is_super_user: {self.is_super_user}
|
||||
'''
|
||||
|
||||
def get_is_logged_in(self):
|
||||
return (self.id_user > 0 and self.id_user != Base.ID_USER_GUEST)
|
||||
|
||||
class User_Temp(db.Model, Base):
|
||||
__tablename__ = 'Shop_User_Temp'
|
||||
__table_args__ = { 'extend_existing': True }
|
||||
id_user = db.Column(db.Integer, primary_key=True)
|
||||
id_user_auth0 = db.Column(db.String(250))
|
||||
firstname = db.Column(db.String(250))
|
||||
surname = db.Column(db.String(250))
|
||||
email = db.Column(db.String(250))
|
||||
is_email_verified = db.Column(db.Boolean)
|
||||
is_super_user = db.Column(db.Boolean)
|
||||
id_currency_default = db.Column(db.Integer)
|
||||
id_region_default = db.Column(db.Integer)
|
||||
is_included_VAT_default = db.Column(db.Boolean)
|
||||
# is_logged_in: bool
|
||||
|
||||
def __init__(self):
|
||||
self.id_user = 0
|
||||
super().__init__()
|
||||
69
business_objects/sql_error.py
Normal file
69
business_objects/sql_error.py
Normal file
@@ -0,0 +1,69 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Business Objects
|
||||
Feature: SQL Error Business Object
|
||||
|
||||
Description:
|
||||
Business object for SQL errors returned by Get Many Stored Procedures
|
||||
"""
|
||||
|
||||
# internal
|
||||
from business_objects.base import Base
|
||||
import lib.argument_validation as av
|
||||
from lib import data_types
|
||||
from forms.forms import Form_Basket_Add, Form_Basket_Edit # Form_Product
|
||||
# external
|
||||
from enum import Enum
|
||||
from datetime import datetime, timedelta
|
||||
import locale
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
|
||||
|
||||
db = SQLAlchemy()
|
||||
|
||||
|
||||
class SQL_Error(db.Model):
|
||||
display_order = db.Column(db.Integer, primary_key=True)
|
||||
id_type = db.Column(db.Integer)
|
||||
code = db.Column(db.String(50))
|
||||
msg = db.Column(db.String(4000))
|
||||
name = db.Column(db.String(500))
|
||||
description = db.Column(db.String(4000))
|
||||
|
||||
"""
|
||||
def __new__(cls, display_order, code, msg):
|
||||
_m = 'SQL_Error.__new__'
|
||||
v_arg_type = 'class attribute'
|
||||
av.val_int(display_order, 'display_order', _m)
|
||||
av.val_str(code, 'code', _m, max_len=50, v_arg_type=v_arg_type)
|
||||
av.val_str(msg, 'msg', _m, max_len=4000, v_arg_type=v_arg_type)
|
||||
return super(SQL_Error, cls).__new__(cls)
|
||||
|
||||
def __init__(self, display_order, code, msg):
|
||||
self.display_order = display_order
|
||||
self.code = code
|
||||
self.msg = msg
|
||||
super().__init__()
|
||||
"""
|
||||
|
||||
def from_DB_record(record):
|
||||
error = SQL_Error()
|
||||
error.display_order = record[0]
|
||||
error.id_type = record[1]
|
||||
error.code = record[2]
|
||||
error.msg = record[3]
|
||||
error.name = record[4]
|
||||
error.description = record[5]
|
||||
return error
|
||||
def to_json(self):
|
||||
return {
|
||||
Base.FLAG_DISPLAY_ORDER: self.display_order,
|
||||
Base.ATTR_ID_MSG_ERROR_TYPE: self.id_type,
|
||||
Base.FLAG_CODE: self.code,
|
||||
Base.FLAG_MESSAGE: self.msg,
|
||||
Base.FLAG_NAME: self.name,
|
||||
Base.FLAG_DESCRIPTION: self.description,
|
||||
}
|
||||
131
config.py
Normal file
131
config.py
Normal file
@@ -0,0 +1,131 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Backend
|
||||
Feature: Configuration
|
||||
|
||||
Description:
|
||||
Configuration variables
|
||||
"""
|
||||
|
||||
# IMPORTS
|
||||
import os
|
||||
from dotenv import load_dotenv, find_dotenv
|
||||
from flask import current_app
|
||||
|
||||
load_dotenv(find_dotenv())
|
||||
|
||||
# CLASSES
|
||||
class Config:
|
||||
is_development = False
|
||||
is_production = False
|
||||
# Miscellaneous
|
||||
DEBUG = False # av.input_bool(os.getenv('DEBUG'), 'DEBUG', 'Config')
|
||||
TESTING = False
|
||||
URL_HOST = os.getenv('URL_HOST')
|
||||
SECRET_KEY = os.getenv('KEY_SECRET_FLASK') # gen cmd: openssl rand -hex 32
|
||||
# Add other configuration variables as needed
|
||||
# MySQL
|
||||
SQLALCHEMY_DATABASE_URI = os.getenv('SQLALCHEMY_DATABASE_URI')
|
||||
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
||||
SQLALCHEMY_ENGINE_OPTIONS = {
|
||||
'pool_size': 10,
|
||||
'pool_recycle': 280,
|
||||
'pool_pre_ping': True,
|
||||
'pool_timeout': 30,
|
||||
}
|
||||
# Auth0
|
||||
SESSION_COOKIE_SECURE = True
|
||||
SESSION_COOKIE_HTTPONLY = True
|
||||
SESSION_COOKIE_SAMESITE = 'Strict'
|
||||
REMEMBER_COOKIE_SECURE = True
|
||||
WTF_CSRF_ENABLED = True
|
||||
# WTF_CSRF_CHECK_DEFAULT = False # We'll check it manually for API routes
|
||||
# WTF_CSRF_HEADERS = ['X-CSRFToken'] # Accept CSRF token from this header
|
||||
WTF_CSRF_TIME_LIMIT = None
|
||||
WTF_CSRF_SSL_STRICT = False # Allows testing without HTTPS
|
||||
ID_AUTH0_CLIENT = os.getenv('ID_AUTH0_CLIENT')
|
||||
ID_AUTH0_CLIENT_SECRET = os.getenv('ID_AUTH0_CLIENT_SECRET')
|
||||
DOMAIN_AUTH0 = os.getenv('DOMAIN_AUTH0')
|
||||
ID_TOKEN_USER = 'user'
|
||||
# PostgreSQL
|
||||
DB_NAME = os.getenv('parts')
|
||||
DB_USER = os.getenv('DB_USER')
|
||||
DB_PASSWORD = os.getenv('DB_PASSWORD')
|
||||
DB_HOST = os.getenv('DB_HOST')
|
||||
# DB_PORT = os.getenv('DB_PORT')
|
||||
# Store
|
||||
# is_included_VAT = True
|
||||
"""
|
||||
KEY_IS_INCLUDED_VAT = 'is_included_VAT'
|
||||
code_currency = 1
|
||||
KEY_CODE_CURRENCY = 'id_currency'
|
||||
code_region_delivery = 1
|
||||
KEY_CODE_REGION_DELIVERY = 'id_region_delivery'
|
||||
KEY_ID_CURRENCY = 'id_currency'
|
||||
KEY_ID_REGION_DELIVERY = 'id_region_delivery'
|
||||
"""
|
||||
# id_currency = 1
|
||||
# id_region_delivery = 1
|
||||
# Mail
|
||||
MAIL_DEBUG = False # av.input_bool(os.getenv('DEBUG'), 'DEBUG', 'Config')
|
||||
MAIL_SERVER = 'mail.partsltd.co.uk' # 'smtp.gmail.com'
|
||||
MAIL_PORT = 465 # 587
|
||||
MAIL_USE_TLS = False
|
||||
MAIL_USE_SSL = True
|
||||
MAIL_USERNAME = os.getenv('MAIL_DEFAULT_SENDER')
|
||||
MAIL_PASSWORD = os.getenv('MAIL_PASSWORD')
|
||||
MAIL_DEFAULT_SENDER = os.getenv('MAIL_DEFAULT_SENDER')
|
||||
MAIL_CONTACT_PUBLIC = os.getenv('MAIL_CONTACT_PUBLIC')
|
||||
"""
|
||||
# Recaptcha
|
||||
RECAPTCHA_PUBLIC_KEY = os.getenv('RECAPTCHA_PUBLIC_KEY')
|
||||
RECAPTCHA_PRIVATE_KEY = os.getenv('RECAPTCHA_PRIVATE_KEY')
|
||||
"""
|
||||
# ALTCHA
|
||||
ALTCHA_API_KEY = os.getenv('ALTCHA_API_KEY')
|
||||
ALTCHA_SECRET_KEY = os.getenv('ALTCHA_SECRET_KEY')
|
||||
ALTCHA_REGION = 'eu'
|
||||
|
||||
class DevelopmentConfig(Config):
|
||||
is_development = True
|
||||
# Add development-specific configuration variables
|
||||
DEBUG = True
|
||||
MAIL_DEBUG = True
|
||||
SESSION_COOKIE_SECURE = False
|
||||
|
||||
class ProductionConfig(Config):
|
||||
is_production = True
|
||||
# Add production-specific configuration variables
|
||||
pass
|
||||
|
||||
# Set the configuration class based on the environment
|
||||
# You can change 'development' to 'production' when deploying
|
||||
config_env = os.getenv('FLASK_ENV', "development")
|
||||
with open('app.log', 'a') as f:
|
||||
print(f'config_env: {config_env}')
|
||||
f.write(f'config_env: {config_env}\n')
|
||||
# current_app.logger.error(f'config_env: {config_env}') # logger not yet initialised
|
||||
if config_env == 'development':
|
||||
app_config = DevelopmentConfig
|
||||
elif config_env == 'production':
|
||||
app_config = ProductionConfig
|
||||
else:
|
||||
raise ValueError("Invalid configuration environment")
|
||||
|
||||
# environment variables
|
||||
"""
|
||||
SET KEY_SECRET_FLASK=nips
|
||||
SET ID_AUTH0_CLIENT=
|
||||
SET ID_AUTH0_CLIENT_SECRET=
|
||||
SET DOMAIN_AUTH0=
|
||||
SET MAIL_PASSWORD=
|
||||
SET RECAPTCHA_PUBLIC_KEY=
|
||||
SET RECAPTCHA_PRIVATE_KEY=
|
||||
SET SQLALCHEMY_DATABASE_URI=
|
||||
SET URL_HOST=
|
||||
"""
|
||||
# SET SQLALCHEMY_DATABASE_URI = mysql://username:password@localhost/dbname
|
||||
# Replace 'username', 'password', 'localhost', and 'dbname' with your actual database credentials
|
||||
0
controllers/__init__.py
Normal file
0
controllers/__init__.py
Normal file
0
controllers/core/__init__.py
Normal file
0
controllers/core/__init__.py
Normal file
143
controllers/core/contact.py
Normal file
143
controllers/core/contact.py
Normal file
@@ -0,0 +1,143 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: App Routing
|
||||
Feature: Core - Contact Routes
|
||||
|
||||
Description:
|
||||
Contact Page Controller.
|
||||
"""
|
||||
|
||||
# IMPORTS
|
||||
# internal
|
||||
from business_objects.api import API
|
||||
from business_objects.project_hub.command import Command
|
||||
from datastores.project_hub.datastore_command import DataStore_Command
|
||||
from forms.contact import Form_Contact
|
||||
from helpers.helper_app import Helper_App
|
||||
from models.model_view_contact import Model_View_Contact
|
||||
from models.model_view_contact_success import Model_View_Contact_Success
|
||||
from models.model_view_home import Model_View_Home
|
||||
import lib.argument_validation as av
|
||||
# external
|
||||
from flask import Flask, render_template, jsonify, request, render_template_string, send_from_directory, redirect, url_for, session, Blueprint, current_app, flash
|
||||
from flask_mail import Mail, Message
|
||||
from extensions import db, oauth, mail
|
||||
from urllib.parse import quote_plus, urlencode
|
||||
from authlib.integrations.flask_client import OAuth
|
||||
from authlib.integrations.base_client import OAuthError
|
||||
from urllib.parse import quote, urlparse, parse_qs
|
||||
import json
|
||||
import base64
|
||||
import hmac
|
||||
import hashlib
|
||||
import datetime
|
||||
from altcha import ChallengeOptions, create_challenge, verify_solution
|
||||
|
||||
routes_core_contact = Blueprint('routes_core_contact', __name__)
|
||||
|
||||
|
||||
@routes_core_contact.route(Model_View_Contact.HASH_PAGE_CONTACT, methods=['GET'])
|
||||
def contact():
|
||||
try:
|
||||
form = Form_Contact()
|
||||
model = Model_View_Contact(form)
|
||||
html_body = render_template('pages/core/_contact.html', model = model)
|
||||
return html_body
|
||||
except Exception as e:
|
||||
return API.get_standard_response(
|
||||
success = False,
|
||||
status_code = 500,
|
||||
message = f"Error: {e}",
|
||||
data = None,
|
||||
errors = [str(e)],
|
||||
meta = None
|
||||
)
|
||||
|
||||
@routes_core_contact.route(Model_View_Contact.HASH_GET_ALTCHA_CHALLENGE, methods=['GET'])
|
||||
def create_altcha_challenge():
|
||||
options = ChallengeOptions(
|
||||
expires = datetime.datetime.now() + datetime.timedelta(hours=1),
|
||||
max_number = 100000, # The maximum random number
|
||||
hmac_key = current_app.app_config.ALTCHA_SECRET_KEY,
|
||||
)
|
||||
challenge = create_challenge(options)
|
||||
Helper_App.console_log(f"Challenge created: {challenge}")
|
||||
# return jsonify({"challenge": challenge})
|
||||
return jsonify({
|
||||
"algorithm": challenge.algorithm,
|
||||
"challenge": challenge.challenge,
|
||||
"salt": challenge.salt,
|
||||
"signature": challenge.signature,
|
||||
})
|
||||
|
||||
@routes_core_contact.route(Model_View_Contact.HASH_PAGE_CONTACT, methods=['POST'])
|
||||
def contact_post():
|
||||
try:
|
||||
form = Form_Contact()
|
||||
if form.validate_on_submit():
|
||||
try:
|
||||
email = form.email.data
|
||||
# CC = form.CC.data # not in use
|
||||
contact_name = form.contact_name.data
|
||||
company_name = form.company_name.data
|
||||
message = form.message.data
|
||||
receive_marketing = form.receive_marketing.data
|
||||
receive_marketing_text = "I would like to receive marketing emails.\n" if receive_marketing else ""
|
||||
# send email
|
||||
mailItem = Message("PARTS Website Contact Us Message", recipients=[current_app.config['MAIL_CONTACT_PUBLIC']])
|
||||
mailItem.body = f"Dear Lord Edward Middleton-Smith,\n\n{message}\n{receive_marketing_text}\nKind regards,\n{contact_name}\n{company_name}\n{email}"
|
||||
mail.send(mailItem)
|
||||
# save to database
|
||||
datastore = DataStore_Command()
|
||||
command = Command.from_json(form.to_json())
|
||||
datastore.save_commands(
|
||||
comment = command.message
|
||||
, commands = [command]
|
||||
)
|
||||
return redirect(url_for(Model_View_Contact.ENDPOINT_PAGE_CONTACT_SUCCESS))
|
||||
except Exception as e:
|
||||
return API.get_standard_response(
|
||||
success = False,
|
||||
status_code = 500,
|
||||
message = f"Error: {e}",
|
||||
data = None,
|
||||
errors = [str(e)],
|
||||
meta = None
|
||||
)
|
||||
return API.get_standard_response(
|
||||
success = False,
|
||||
status_code = 500,
|
||||
message = f"Error: {form.errors}",
|
||||
data = None,
|
||||
errors = [str(form.errors)],
|
||||
meta = None
|
||||
)
|
||||
# html_body = render_template('pages/core/_contact.html', model = model)
|
||||
except Exception as e:
|
||||
return API.get_standard_response(
|
||||
success = False,
|
||||
status_code = 500,
|
||||
message = f"Error: {e}",
|
||||
data = None,
|
||||
errors = [str(e)],
|
||||
meta = None
|
||||
)
|
||||
|
||||
@routes_core_contact.route(Model_View_Contact.HASH_PAGE_CONTACT_SUCCESS, methods=['GET'])
|
||||
def contact_success():
|
||||
try:
|
||||
model = Model_View_Contact_Success()
|
||||
html_body = render_template('pages/core/_contact_success.html', model = model)
|
||||
return html_body
|
||||
except Exception as e:
|
||||
return API.get_standard_response(
|
||||
success = False,
|
||||
status_code = 500,
|
||||
message = f"Error: {e}",
|
||||
data = None,
|
||||
errors = [str(e)],
|
||||
meta = None
|
||||
)
|
||||
31
controllers/core/home.py
Normal file
31
controllers/core/home.py
Normal file
@@ -0,0 +1,31 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: App Routing
|
||||
Feature: Core - Home Routes
|
||||
|
||||
Description:
|
||||
Home Page Controller.
|
||||
"""
|
||||
|
||||
# internal
|
||||
from business_objects.api import API
|
||||
from models.model_view_home import Model_View_Home
|
||||
# external
|
||||
from flask import render_template, jsonify, Blueprint
|
||||
|
||||
|
||||
routes_core_home = Blueprint('routes_core_home', __name__)
|
||||
|
||||
|
||||
@routes_core_home.route(Model_View_Home.HASH_PAGE_HOME, methods=['GET'])
|
||||
def home():
|
||||
try:
|
||||
model = Model_View_Home()
|
||||
html_body = render_template('pages/core/_home.html', model = model)
|
||||
except Exception as e:
|
||||
return jsonify(error=str(e)), 403
|
||||
return html_body
|
||||
|
||||
0
controllers/legal/__init__.py
Normal file
0
controllers/legal/__init__.py
Normal file
70
controllers/legal/legal.py
Normal file
70
controllers/legal/legal.py
Normal file
@@ -0,0 +1,70 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: App Routing
|
||||
Feature: Legal Routes
|
||||
|
||||
Description:
|
||||
Legal Section Controller.
|
||||
"""
|
||||
|
||||
# IMPORTS
|
||||
# internal
|
||||
# from models.model_view_home import Model_View_Home
|
||||
from models.model_view_license import Model_View_License
|
||||
from models.model_view_privacy_policy import Model_View_Privacy_Policy
|
||||
from models.model_view_accessibility_report import Model_View_Accessibility_Report
|
||||
from models.model_view_accessibility_statement import Model_View_Accessibility_Statement
|
||||
from models.model_view_retention_schedule import Model_View_Retention_Schedule
|
||||
import lib.argument_validation as av
|
||||
# external
|
||||
from flask import render_template, Blueprint
|
||||
|
||||
|
||||
routes_legal = Blueprint('routes_legal', __name__)
|
||||
|
||||
|
||||
# snore
|
||||
@routes_legal.route('/license', methods=['GET'])
|
||||
def license():
|
||||
try:
|
||||
model = Model_View_License()
|
||||
html_body = render_template('pages/legal/_license.html', model = model)
|
||||
except Exception as e:
|
||||
return str(e)
|
||||
return html_body
|
||||
@routes_legal.route('/accessibility-statement', methods=['GET'])
|
||||
def accessibility_statement():
|
||||
try:
|
||||
model = Model_View_Accessibility_Statement()
|
||||
html_body = render_template('pages/legal/_accessibility_statement.html', model = model)
|
||||
except Exception as e:
|
||||
return str(e)
|
||||
return html_body
|
||||
@routes_legal.route('/accessibility-report', methods=['GET'])
|
||||
def accessibility_report():
|
||||
try:
|
||||
model = Model_View_Accessibility_Report()
|
||||
html_body = render_template('pages/legal/_accessibility_report.html', model = model)
|
||||
except Exception as e:
|
||||
return str(e)
|
||||
return html_body
|
||||
@routes_legal.route('/retention-schedule', methods=['GET'])
|
||||
def retention_schedule():
|
||||
try:
|
||||
model = Model_View_Retention_Schedule()
|
||||
html_body = render_template('pages/legal/_retention_schedule.html', model = model)
|
||||
except Exception as e:
|
||||
return str(e)
|
||||
return html_body
|
||||
@routes_legal.route('/privacy-policy', methods=['GET'])
|
||||
def privacy_policy():
|
||||
try:
|
||||
model = Model_View_Privacy_Policy()
|
||||
html_body = render_template('pages/legal/_privacy_policy.html', model = model)
|
||||
except Exception as e:
|
||||
return str(e)
|
||||
return html_body
|
||||
|
||||
11
datastores/__init__.py
Normal file
11
datastores/__init__.py
Normal file
@@ -0,0 +1,11 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Module Initialisation
|
||||
Feature: DataStores
|
||||
|
||||
Description:
|
||||
Initialises datastores module.
|
||||
"""
|
||||
114
datastores/datastore_base.py
Normal file
114
datastores/datastore_base.py
Normal file
@@ -0,0 +1,114 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: DataStores
|
||||
Feature: Base DataStore
|
||||
|
||||
Description:
|
||||
Datastore for Store
|
||||
"""
|
||||
|
||||
# internal
|
||||
# from routes import bp_home
|
||||
import lib.argument_validation as av
|
||||
from business_objects.sql_error import SQL_Error
|
||||
from business_objects.project_hub.user import User
|
||||
# from helpers.helper_db_mysql import Helper_DB_MySQL
|
||||
# from models.model_view_store_checkout import Model_View_Store_Checkout # circular!
|
||||
from extensions import db
|
||||
from forms.access_level import Filters_Access_Level
|
||||
from forms.unit_measurement import Filters_Unit_Measurement
|
||||
from helpers.helper_app import Helper_App
|
||||
# external
|
||||
from sqlalchemy import text
|
||||
from flask import Flask, session, current_app
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
import time
|
||||
from sqlalchemy.exc import OperationalError
|
||||
|
||||
|
||||
|
||||
class DataStore_Base(BaseModel):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
@staticmethod
|
||||
def db_procedure_execute(proc_name, argument_dict_list = None):
|
||||
# Argument validation
|
||||
_m = 'DataStore_Base.db_procedure_execute'
|
||||
av.val_str(proc_name, 'proc_name', _m)
|
||||
proc_string = f'CALL {proc_name}('
|
||||
has_arguments = not str(type(argument_dict_list)) == "<class 'NoneType'>"
|
||||
if has_arguments:
|
||||
arg_keys = list(argument_dict_list.keys())
|
||||
for i in range(len(arg_keys)):
|
||||
proc_string += f'{"" if i == 0 else ", "}:{arg_keys[i]}'
|
||||
proc_string += ')'
|
||||
proc_string = text(proc_string)
|
||||
Helper_App.console_log(f'{_m}\nproc_string: {proc_string}\nargs: {argument_dict_list}')
|
||||
|
||||
if has_arguments:
|
||||
result = db.session.execute(proc_string, argument_dict_list)
|
||||
else:
|
||||
result = db.session.execute(proc_string)
|
||||
Helper_App.console_log(f'result: {result}')
|
||||
# conn.session.remove()
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def db_cursor_clear(cursor):
|
||||
while cursor.nextset():
|
||||
Helper_App.console_log(f'new result set: {cursor.fetchall()}')
|
||||
|
||||
@staticmethod
|
||||
def get_user_session():
|
||||
Helper_App.console_log('DataStore_Base.get_user_session')
|
||||
user = User.from_json(session.get(User.FLAG_USER))
|
||||
if user.id_user <= 0:
|
||||
user.id_user = 3
|
||||
return user
|
||||
|
||||
@staticmethod
|
||||
def upload_bulk(permanent_table_name, records, batch_size):
|
||||
_m = 'DataStore_Base.upload_bulk'
|
||||
Helper_App.console_log(f'{_m}\nstarting...')
|
||||
Helper_App.console_log(f'permanent_table_name: {permanent_table_name}')
|
||||
if db.session.dirty or db.session.new or db.session.deleted:
|
||||
Helper_App.console_log("Session is not clean")
|
||||
return
|
||||
# Assuming `permanent_table_name` is a string representing the table name
|
||||
table_object = db.metadata.tables.get(permanent_table_name)
|
||||
if table_object is None:
|
||||
Helper_App.console_log(f"Table {permanent_table_name} not found in metadata.")
|
||||
return
|
||||
else:
|
||||
expected_columns = set(column.name for column in db.inspect(table_object).columns)
|
||||
Helper_App.console_log(f'expected_columns: {expected_columns}')
|
||||
max_retries = 3
|
||||
initial_backoff = 1
|
||||
for i in range(0, len(records), batch_size):
|
||||
batch = records[i:i + batch_size]
|
||||
try:
|
||||
retries = 0
|
||||
while retries < max_retries:
|
||||
try:
|
||||
db.session.bulk_save_objects(batch)
|
||||
db.session.commit()
|
||||
break
|
||||
except OperationalError as e:
|
||||
if "Lock wait timeout exceeded" not in str(e) or retries == max_retries - 1:
|
||||
raise
|
||||
|
||||
wait_time = initial_backoff * (2 ** retries)
|
||||
current_app.logger.warning(f"Lock timeout encountered. Retrying in {wait_time} seconds... (Attempt {retries + 1}/{max_retries})")
|
||||
time.sleep(wait_time)
|
||||
retries += 1
|
||||
|
||||
# Ensure the session is clean for the retry
|
||||
db.session.rollback()
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
raise e
|
||||
113
datastores/project_hub/datastore_contact_form.py
Normal file
113
datastores/project_hub/datastore_contact_form.py
Normal file
@@ -0,0 +1,113 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: DataStores
|
||||
Feature: User DataStore
|
||||
|
||||
Description:
|
||||
Datastore for Users
|
||||
"""
|
||||
|
||||
# internal
|
||||
# from routes import bp_home
|
||||
import lib.argument_validation as av
|
||||
from business_objects.sql_error import SQL_Error
|
||||
from business_objects.project_hub.command import Command, Command_Temp
|
||||
from datastores.datastore_base import DataStore_Base
|
||||
from helpers.helper_app import Helper_App
|
||||
from helpers.helper_db_mysql import Helper_DB_MySQL
|
||||
# from models.model_view_store_checkout import Model_View_Store_Checkout # circular!
|
||||
from extensions import db
|
||||
# external
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from datetime import datetime
|
||||
|
||||
db = SQLAlchemy()
|
||||
|
||||
|
||||
class DataStore_Command(DataStore_Base):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
@classmethod
|
||||
def get_many_command(cls):
|
||||
_m = f'{cls.__qualname__}.get_many_command'
|
||||
user = cls.get_user_session()
|
||||
argument_dict = {
|
||||
'a_id_user': user.id_user
|
||||
, 'a_debug': 0
|
||||
}
|
||||
Helper_App.console_log(f'argument_dict: {argument_dict}')
|
||||
result = cls.db_procedure_execute('p_ph_get_many_command', argument_dict)
|
||||
cursor = result.cursor
|
||||
|
||||
# Commands
|
||||
result_set_1 = cursor.fetchall()
|
||||
Helper_App.console_log(f'raw commands: {result_set_1}')
|
||||
commands = []
|
||||
command_indexes = {}
|
||||
for row in result_set_1:
|
||||
new_command = Command.from_DB_command(row)
|
||||
command_indexes[new_command.id_command] = len(commands)
|
||||
commands.append(new_command)
|
||||
|
||||
# Errors
|
||||
cursor.nextset()
|
||||
result_set_e = cursor.fetchall()
|
||||
Helper_App.console_log(f'raw errors: {result_set_e}')
|
||||
errors = []
|
||||
if len(result_set_e) > 0:
|
||||
errors = [SQL_Error.from_DB_record(row) for row in result_set_e]
|
||||
for error in errors:
|
||||
Helper_App.console_log(f"Error [{error.code}]: {error.msg}")
|
||||
|
||||
cls.db_cursor_clear(cursor)
|
||||
|
||||
return commands, errors
|
||||
|
||||
@classmethod
|
||||
def save_commands(cls, comment, commands):
|
||||
_m = f'{cls}.save_commands'
|
||||
av.val_str(comment, 'comment', _m)
|
||||
|
||||
guid = Helper_DB_MySQL.create_guid_str()
|
||||
now = datetime.now()
|
||||
user = cls.get_user_session()
|
||||
|
||||
Helper_App.console_log(f'saving commands: {commands}')
|
||||
|
||||
rows = []
|
||||
for command in commands:
|
||||
row = Command_Temp.from_command(command)
|
||||
row.guid = guid
|
||||
rows.append(row)
|
||||
|
||||
cls.upload_bulk(Command_Temp.__tablename__, rows, 1000)
|
||||
|
||||
Helper_App.console_log('Commands uploaded')
|
||||
|
||||
argument_dict_list = {
|
||||
'a_comment': comment,
|
||||
'a_guid': guid,
|
||||
'a_id_user': user.id_user,
|
||||
'a_debug': 0
|
||||
}
|
||||
result = cls.db_procedure_execute('p_ph_save_command', argument_dict_list)
|
||||
|
||||
Helper_App.console_log('Commands saved')
|
||||
|
||||
# Errors
|
||||
cursor = result.cursor
|
||||
cursor.nextset()
|
||||
result_set_e = cursor.fetchall()
|
||||
errors = []
|
||||
if len(result_set_e) > 0:
|
||||
errors = [SQL_Error.from_DB_record(row) for row in result_set_e]
|
||||
for error in errors:
|
||||
Helper_App.console_log(f"Error [{error.code}]: {error.msg}")
|
||||
|
||||
cls.db_cursor_clear(cursor)
|
||||
return errors
|
||||
14
extensions.py
Normal file
14
extensions.py
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
from flask import Flask, render_template, jsonify, request, render_template_string, send_from_directory, redirect, url_for, session, current_app
|
||||
from flask_cors import CORS
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from flask_mail import Mail, Message
|
||||
from flask_wtf.csrf import CSRFProtect
|
||||
from authlib.integrations.flask_client import OAuth
|
||||
|
||||
|
||||
csrf = CSRFProtect()
|
||||
# cors = CORS()
|
||||
db = SQLAlchemy()
|
||||
mail = Mail()
|
||||
oauth = OAuth()
|
||||
0
forms/__init__.py
Normal file
0
forms/__init__.py
Normal file
37
forms/access_level.py
Normal file
37
forms/access_level.py
Normal file
@@ -0,0 +1,37 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Backend
|
||||
Feature: Forms - Access Level Filters data input
|
||||
|
||||
Description:
|
||||
Defines Flask-WTF forms for handling access level filter input.
|
||||
"""
|
||||
|
||||
# internal
|
||||
from business_objects.base import Base
|
||||
from forms.base import Form_Base
|
||||
import lib.argument_validation as av
|
||||
# external
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField, TextAreaField, SubmitField, BooleanField, IntegerField, SelectField, FloatField
|
||||
from wtforms.validators import InputRequired, NumberRange, Regexp, DataRequired, Optional
|
||||
from flask_wtf.recaptcha import RecaptchaField
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
|
||||
class Filters_Access_Level(Form_Base):
|
||||
active = BooleanField("Active only?", default = True)
|
||||
def __repr__(self):
|
||||
return f'{self.__class__.__name__}(active={self.active.data})'
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
form = Filters_Access_Level()
|
||||
form.active.data = av.input_bool(json[Base.FLAG_ACTIVE], Base.FLAG_ACTIVE, f'{cls.__name__}.from_json')
|
||||
return form
|
||||
def to_json(self):
|
||||
return {
|
||||
Base.FLAG_ACTIVE: 1 if av.input_bool(self.active.data, Base.FLAG_ACTIVE, f'{self.__class__.__name__}.to_json') else 0,
|
||||
}
|
||||
78
forms/base.py
Normal file
78
forms/base.py
Normal file
@@ -0,0 +1,78 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Backend
|
||||
Feature: Form Base and Meta Classes - data input
|
||||
|
||||
Description:
|
||||
Defines Flask-WTF base forms for handling user input.
|
||||
"""
|
||||
|
||||
# internal
|
||||
# external
|
||||
from flask_wtf import FlaskForm
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
|
||||
class Form_Base_Meta(type(FlaskForm), ABCMeta):
|
||||
pass
|
||||
|
||||
|
||||
class Form_Base(FlaskForm, metaclass=Form_Base_Meta):
|
||||
"""
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def from_filters(cls, filters):
|
||||
pass
|
||||
@abstractmethod
|
||||
def __repr__(self):
|
||||
pass
|
||||
"""
|
||||
def __repr__(self):
|
||||
fields = ', '.join(
|
||||
f"{name}={field.data}" for name, field in self._fields.items()
|
||||
)
|
||||
return f"{self.__class__.__name__}({fields})"
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def from_json(cls, json):
|
||||
pass
|
||||
@classmethod
|
||||
def get_default(cls):
|
||||
return cls()
|
||||
"""
|
||||
@abstractmethod
|
||||
def test_69(self):
|
||||
pass
|
||||
|
||||
def get_Filters_Product_Category(data_request):
|
||||
data_form = data_request[Model_View_Store_Product_Category.FLAG_FORM]
|
||||
form_filters = Filters_Product_Category(**data_form)
|
||||
form_filters.is_not_empty.data = av.input_bool(data_form['is_not_empty'], 'is_not_empty', 'filter_category')
|
||||
form_filters.active.data = av.input_bool(data_form['active'], 'active', 'filter_category')
|
||||
return form_filters
|
||||
"""
|
||||
@classmethod
|
||||
def get_choices_blank(cls):
|
||||
return [('', 'Select')]
|
||||
@classmethod
|
||||
def get_choice_all(cls):
|
||||
return ('', 'All')
|
||||
|
||||
'''
|
||||
class Filters_Stored_Procedure_Base(Form_Base):
|
||||
"""
|
||||
@abstractmethod
|
||||
def __repr__(self):
|
||||
pass
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def from_json(cls, json):
|
||||
pass
|
||||
"""
|
||||
@abstractmethod
|
||||
def to_json(self):
|
||||
pass
|
||||
'''
|
||||
100
forms/contact.py
Normal file
100
forms/contact.py
Normal file
@@ -0,0 +1,100 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Backend
|
||||
Feature: Contact Us Form
|
||||
|
||||
Description:
|
||||
Defines Flask-WTF form for handling user input on Contact Us page.
|
||||
"""
|
||||
|
||||
# IMPORTS
|
||||
# internal
|
||||
from business_objects.base import Base
|
||||
from business_objects.project_hub.command import Command
|
||||
# from models.model_view_store import Model_View_Store # circular
|
||||
from models.model_view_base import Model_View_Base
|
||||
from forms.base import Form_Base
|
||||
# external
|
||||
from flask import Flask, render_template, request, flash, redirect, url_for, current_app
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField, TextAreaField, SubmitField, HiddenField, BooleanField, Field, EmailField
|
||||
from wtforms.validators import DataRequired, Email, ValidationError
|
||||
import markupsafe
|
||||
from flask_wtf.recaptcha import RecaptchaField
|
||||
from abc import ABCMeta, abstractmethod
|
||||
import json
|
||||
from altcha import verify_solution
|
||||
import base64
|
||||
|
||||
class ALTCHAValidator:
|
||||
def __init__(self, message=None):
|
||||
self.message = message or 'ALTCHA verification failed'
|
||||
|
||||
def __call__(self, form, field):
|
||||
altcha_data = field.data
|
||||
|
||||
if not altcha_data:
|
||||
raise ValidationError(self.message)
|
||||
|
||||
try:
|
||||
# The data is base64 encoded JSON
|
||||
try:
|
||||
# First try to decode it as JSON directly (if it's not base64 encoded)
|
||||
altcha_payload = json.loads(altcha_data)
|
||||
except json.JSONDecodeError:
|
||||
# If direct JSON decoding fails, try base64 decoding first
|
||||
decoded_data = base64.b64decode(altcha_data).decode('utf-8')
|
||||
altcha_payload = json.loads(decoded_data)
|
||||
|
||||
ok, err = verify_solution(altcha_payload, current_app.app_config.ALTCHA_SECRET_KEY, check_expires=True)
|
||||
|
||||
if err or not ok:
|
||||
raise ValidationError(self.message + ': ' + (err or 'Invalid solution'))
|
||||
|
||||
except Exception as e:
|
||||
raise ValidationError(f'Invalid ALTCHA data: {str(e)}')
|
||||
|
||||
class ALTCHAField(Field):
|
||||
def __init__(self, label='', validators=None, **kwargs):
|
||||
validators = validators or []
|
||||
validators.append(ALTCHAValidator())
|
||||
|
||||
super(ALTCHAField, self).__init__(label, validators, **kwargs)
|
||||
|
||||
def __call__(self, **kwargs):
|
||||
html = f"""
|
||||
<altcha-widget
|
||||
challengeurl="/get-challenge"
|
||||
auto="onload"
|
||||
id="{self.id}"
|
||||
name="{self.name}">
|
||||
</altcha-widget>
|
||||
"""
|
||||
return markupsafe.Markup(html)
|
||||
|
||||
|
||||
class Form_Contact(FlaskForm):
|
||||
email = EmailField('Email')
|
||||
contact_name = StringField('Name')
|
||||
company_name = StringField('Company')
|
||||
message = TextAreaField('Message')
|
||||
receive_marketing = BooleanField('I would like to receive marketing emails.')
|
||||
# recaptcha = RecaptchaField()
|
||||
# altcha = HiddenField('ALTCHA') # , validators=[validate_altcha]
|
||||
altcha = ALTCHAField('Verify you are human')
|
||||
submit = SubmitField('Send Message')
|
||||
|
||||
def to_json(self):
|
||||
return {
|
||||
Base.FLAG_EMAIL: self.email.data
|
||||
, Command.FLAG_NAME_CONTACT: self.contact_name.data
|
||||
, Command.FLAG_NAME_COMPANY: self.company_name.data
|
||||
, Command.FLAG_MESSAGE: self.message.data
|
||||
, Command.FLAG_RECEIVE_MARKETING_COMMUNICATIONS: self.receive_marketing.data
|
||||
, Command.FLAG_ALTCHA: self.altcha.data
|
||||
, Base.FLAG_ACTIVE: True
|
||||
, Base.FLAG_CREATED_ON: None
|
||||
}
|
||||
134
forms/forms.py
Normal file
134
forms/forms.py
Normal file
@@ -0,0 +1,134 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Backend
|
||||
Feature: Forms - User data input
|
||||
|
||||
Description:
|
||||
Defines Flask-WTF forms for handling user input.
|
||||
"""
|
||||
|
||||
# IMPORTS
|
||||
# internal
|
||||
# from business_objects.store.product_category import Filters_Product_Category # circular
|
||||
# from models.model_view_store import Model_View_Store # circular
|
||||
from forms.base import Form_Base
|
||||
# external
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField, TextAreaField, SubmitField, BooleanField, IntegerField, SelectField, FloatField
|
||||
from wtforms.validators import InputRequired, NumberRange, Regexp, DataRequired, Optional
|
||||
from flask_wtf.recaptcha import RecaptchaField
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
|
||||
|
||||
class Form_Contact(FlaskForm):
|
||||
email = StringField('Email address')
|
||||
CC = BooleanField('Would you like to receive a copy of this email request?') # not in use
|
||||
name = StringField('Name')
|
||||
message = TextAreaField('Message')
|
||||
recaptcha = RecaptchaField()
|
||||
submit = SubmitField('Submit')
|
||||
|
||||
class Form_Register(FlaskForm):
|
||||
email = StringField('Email address')
|
||||
CC = BooleanField('Would you like to receive a copy of this email request?') # not in use
|
||||
name = StringField('Name')
|
||||
message = TextAreaField('Message')
|
||||
submit = SubmitField('Submit')
|
||||
|
||||
|
||||
"""
|
||||
class Form_Product(FlaskForm): # for basket, product tiles, product add
|
||||
# PositiveIntegerField with validation constraints
|
||||
quantity = IntegerField(
|
||||
'Quantity',
|
||||
validators=[
|
||||
# InputRequired(message='Quantity'),
|
||||
NumberRange(min=1, message='Please enter a positive integer')
|
||||
],
|
||||
default=1
|
||||
)
|
||||
"""
|
||||
|
||||
class Form_Basket_Add(FlaskForm): # for basket, product tiles, product add
|
||||
# PositiveIntegerField with validation constraints
|
||||
quantity = IntegerField(
|
||||
'Quantity',
|
||||
validators=[
|
||||
# InputRequired(message='Quantity'),
|
||||
NumberRange(min=1, message='Please enter a positive integer')
|
||||
],
|
||||
default=1
|
||||
# render_kw={'id-product': ''} # {Model_View_Store.attr_id_product: ''}
|
||||
)
|
||||
submit = SubmitField('Add')
|
||||
form_type = 'Form_Basket_Add'
|
||||
|
||||
class Form_Basket_Edit(FlaskForm): # for basket, product tiles, product add
|
||||
# PositiveIntegerField with validation constraints
|
||||
quantity = IntegerField(
|
||||
'Quantity',
|
||||
validators=[
|
||||
# InputRequired(message='Quantity'),
|
||||
NumberRange(min=1, message='Please enter a positive integer')
|
||||
],
|
||||
default=1
|
||||
# render_kw={'id-product': ''} # {Model_View_Store.attr_id_product: ''}
|
||||
)
|
||||
submit = SubmitField('Update')
|
||||
form_type = 'Form_Basket_Edit'
|
||||
|
||||
class Form_Billing(FlaskForm):
|
||||
identical = BooleanField('Use delivery address')
|
||||
region = SelectField('Country / region', choices=[('uk', 'UK'), ('international', 'International')], validators=[DataRequired()])
|
||||
name_full = StringField('Full name')
|
||||
phone_number = StringField('Phone number', validators=[Regexp(r'^\+?[0-9\s]{5,20}$', message='Only numbers, plus symbol, and space are allowed.'), DataRequired()])
|
||||
postcode = StringField('Post code', validators=[DataRequired()])
|
||||
address_1 = StringField('Address line 1', validators=[DataRequired()])
|
||||
address_2 = StringField('Address line 2 (optional)')
|
||||
city = StringField('City', validators=[DataRequired()])
|
||||
county = StringField('County', validators=[DataRequired()])
|
||||
submit = SubmitField('Submit')
|
||||
form_type_billing_not_delivery = False
|
||||
|
||||
def output_id(self):
|
||||
return 'formBilling' if self.form_type_billing_not_delivery else 'formDeliver'
|
||||
|
||||
class Form_Is_Included_VAT(FlaskForm):
|
||||
is_included = BooleanField('Include VAT')
|
||||
|
||||
class Form_Delivery_Region(FlaskForm):
|
||||
id_id_region_delivery = 'id_region_delivery'
|
||||
id_region_delivery = SelectField('Region', id='id_region_delivery')
|
||||
|
||||
class Form_Currency(FlaskForm):
|
||||
id_id_currency = 'id_currency'
|
||||
id_currency = SelectField('Currency', id='id_currency')
|
||||
|
||||
|
||||
# Store
|
||||
class Form_Supplier(FlaskForm):
|
||||
id_id_supplier = 'id_supplier'
|
||||
id_supplier = SelectField('Supplier', id='id_supplier')
|
||||
name_company = StringField('Company name')
|
||||
name_contact = StringField('Contact name')
|
||||
department_contact = StringField('Contact department')
|
||||
id_address = SelectField('Address ID')
|
||||
phone_number = StringField('Phone number')
|
||||
email = StringField('Email address')
|
||||
fax = StringField('Fax number')
|
||||
website = StringField('Website')
|
||||
id_currency = SelectField('Currency ID')
|
||||
is_active = BooleanField('Active', default = True)
|
||||
|
||||
# class Form_Supplier_Purchase_Order(FlaskForm):
|
||||
|
||||
|
||||
|
||||
# User
|
||||
class Form_Filters_User(FlaskForm):
|
||||
active = BooleanField('Active only?', default = True)
|
||||
id_user = SelectField('User ID', validators=[Optional()], choices=[])
|
||||
42
forms/unit_measurement.py
Normal file
42
forms/unit_measurement.py
Normal file
@@ -0,0 +1,42 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Backend
|
||||
Feature: Forms - Unit of Measurement Filters data input
|
||||
|
||||
Description:
|
||||
Defines Flask-WTF forms for handling unit of measurement filter input.
|
||||
"""
|
||||
|
||||
# internal
|
||||
from business_objects.base import Base
|
||||
from forms.base import Form_Base
|
||||
import lib.argument_validation as av
|
||||
# external
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField, TextAreaField, SubmitField, BooleanField, IntegerField, SelectField, FloatField
|
||||
from wtforms.validators import InputRequired, NumberRange, Regexp, DataRequired, Optional
|
||||
from flask_wtf.recaptcha import RecaptchaField
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
|
||||
class Filters_Unit_Measurement(Form_Base):
|
||||
active = BooleanField("Active only?", default = True)
|
||||
@classmethod
|
||||
def from_filters(cls, filters):
|
||||
form = Filters_Unit_Measurement()
|
||||
form.active.data = filters.active
|
||||
return form
|
||||
def __repr__(self):
|
||||
return f'Filters_Unit_Measurement(active={self.active.data})'
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
form = Filters_Unit_Measurement()
|
||||
form.active.data = av.input_bool(json[Base.FLAG_ACTIVE], 'active', 'Filters_Unit_Measurement')
|
||||
return form
|
||||
def to_json(self):
|
||||
return {
|
||||
Base.FLAG_ACTIVE: av.input_bool(self.active.data, Base.FLAG_ACTIVE, f'{self.__class__.__name__}.to_json'),
|
||||
}
|
||||
11
helpers/__init__.py
Normal file
11
helpers/__init__.py
Normal file
@@ -0,0 +1,11 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Module Initialisation
|
||||
Feature: Helpers
|
||||
|
||||
Description:
|
||||
Initialises helpers module.
|
||||
"""
|
||||
43
helpers/helper_app.py
Normal file
43
helpers/helper_app.py
Normal file
@@ -0,0 +1,43 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Helpers
|
||||
Feature: App Helper
|
||||
"""
|
||||
|
||||
# internal
|
||||
|
||||
# external
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
from flask import current_app
|
||||
# from flask_sqlalchemy import SQLAlchemy
|
||||
|
||||
|
||||
class Helper_App(BaseModel):
|
||||
|
||||
@staticmethod
|
||||
def get_request_data(request):
|
||||
Helper_App.console_log(f'request={request}')
|
||||
data = {}
|
||||
try:
|
||||
data = request.json
|
||||
except:
|
||||
try:
|
||||
data = request.data
|
||||
except:
|
||||
try:
|
||||
data = request.form
|
||||
except:
|
||||
pass
|
||||
Helper_App.console_log(f'data={data}')
|
||||
return data
|
||||
|
||||
@staticmethod
|
||||
def console_log(message):
|
||||
if current_app.app_config.is_development:
|
||||
print(message)
|
||||
elif current_app.app_config.is_production:
|
||||
pass
|
||||
current_app.logger.info(message)
|
||||
42
helpers/helper_db_mysql.py
Normal file
42
helpers/helper_db_mysql.py
Normal file
@@ -0,0 +1,42 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Helpers
|
||||
Feature: MySQL Database Helper
|
||||
|
||||
Notes: This architecture does not work with Flask-SQLAlchemy - db connection must be initialised with Flask app initialisation
|
||||
"""
|
||||
|
||||
# internal
|
||||
|
||||
# external
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
from flask import Flask, render_template, jsonify, request, render_template_string, send_from_directory, redirect, url_for, session
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
import uuid
|
||||
|
||||
class Helper_DB_MySQL(BaseModel):
|
||||
app: Flask
|
||||
|
||||
model_config = ConfigDict(arbitrary_types_allowed=True)
|
||||
|
||||
def __init__(self, app):
|
||||
super().__init__(app=app)
|
||||
# self.app = app
|
||||
|
||||
def get_db_connection(self):
|
||||
db = SQLAlchemy()
|
||||
db.init_app(self.app)
|
||||
with self.app.app_context():
|
||||
db.create_all()
|
||||
db.engine.url = self.app.config['SQLALCHEMY_DATABASE_URI']
|
||||
return db
|
||||
|
||||
@staticmethod
|
||||
def create_guid_str():
|
||||
return str(uuid.uuid4())
|
||||
@staticmethod
|
||||
def create_guid():
|
||||
return uuid.uuid4().bytes
|
||||
11
lib/__init__.py
Normal file
11
lib/__init__.py
Normal file
@@ -0,0 +1,11 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Module Initialisation
|
||||
Feature: Library
|
||||
|
||||
Description:
|
||||
Initialises library module.
|
||||
"""
|
||||
1301
lib/argument_validation.py
Normal file
1301
lib/argument_validation.py
Normal file
File diff suppressed because it is too large
Load Diff
37
lib/data_types.py
Normal file
37
lib/data_types.py
Normal file
@@ -0,0 +1,37 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on Thu Apr 27 12:33:59 2023
|
||||
|
||||
@author: Edward Middleton-Smith
|
||||
|
||||
Argument Validation
|
||||
"""
|
||||
|
||||
# CLASSES
|
||||
# ATTRIBUTE DECLARATION
|
||||
# METHODS
|
||||
# FUNCTION
|
||||
# ARGUMENTS
|
||||
# ARGUMENT VALIDATION
|
||||
# ATTRIBUTE + VARIABLE INSTANTIATION
|
||||
# METHODS
|
||||
# RETURNS
|
||||
|
||||
# NORMAL METHODS
|
||||
# FUNCTION
|
||||
# ARGUMENTS
|
||||
# ARGUMENT VALIDATION
|
||||
# VARIABLE INSTANTIATION
|
||||
# METHODS
|
||||
# RETURNS
|
||||
|
||||
# IMPORTS
|
||||
|
||||
# CLASSES
|
||||
|
||||
# METHODS
|
||||
def get_enum_member_by_text(enum_class, text):
|
||||
for member in enum_class.__members__.values():
|
||||
if member.name == text:
|
||||
return member
|
||||
raise ValueError(f'{text} is not in {enum_class}')
|
||||
11
models/__init__.py
Normal file
11
models/__init__.py
Normal file
@@ -0,0 +1,11 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Module Initialisation
|
||||
Feature: Models
|
||||
|
||||
Description:
|
||||
Initialises view data models module.
|
||||
"""
|
||||
24
models/model_view_accessibility_report.py
Normal file
24
models/model_view_accessibility_report.py
Normal file
@@ -0,0 +1,24 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Legal View Models
|
||||
Feature: Accessibility Report View Model
|
||||
|
||||
Description:
|
||||
Data model for accessibility report view
|
||||
"""
|
||||
|
||||
# internal
|
||||
from models.model_view_base import Model_View_Base
|
||||
# from routes import bp_home
|
||||
# external
|
||||
|
||||
class Model_View_Accessibility_Report(Model_View_Base):
|
||||
@property
|
||||
def title(self):
|
||||
return 'Accessibility Report'
|
||||
def __init__(self, hash_page_current=Model_View_Base.HASH_PAGE_ACCESSIBILITY_REPORT):
|
||||
super().__init__(hash_page_current=hash_page_current)
|
||||
|
||||
24
models/model_view_accessibility_statement.py
Normal file
24
models/model_view_accessibility_statement.py
Normal file
@@ -0,0 +1,24 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Legal View Models
|
||||
Feature: Accessibility Statement View Model
|
||||
|
||||
Description:
|
||||
Data model for accessibility statement view
|
||||
"""
|
||||
|
||||
# internal
|
||||
from models.model_view_base import Model_View_Base
|
||||
# from routes import bp_home
|
||||
# external
|
||||
|
||||
class Model_View_Accessibility_Statement(Model_View_Base):
|
||||
@property
|
||||
def title(self):
|
||||
return 'Accessibility Statement'
|
||||
def __init__(self, hash_page_current=Model_View_Base.HASH_PAGE_ACCESSIBILITY_STATEMENT):
|
||||
super().__init__(hash_page_current=hash_page_current)
|
||||
|
||||
263
models/model_view_base.py
Normal file
263
models/model_view_base.py
Normal file
@@ -0,0 +1,263 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: View Models
|
||||
Feature: Base View Model
|
||||
|
||||
Description:
|
||||
Base data model for views
|
||||
"""
|
||||
|
||||
# IMPORTS
|
||||
# VARIABLE INSTANTIATION
|
||||
# METHODS
|
||||
|
||||
# IMPORTS
|
||||
# internal
|
||||
# from routes import bp_home
|
||||
from business_objects.base import Base
|
||||
from business_objects.project_hub.user import User
|
||||
from business_objects.project_hub.command import Command
|
||||
from datastores.datastore_base import DataStore_Base
|
||||
from datastores.project_hub.datastore_command import DataStore_Command
|
||||
from forms.access_level import Filters_Access_Level
|
||||
from forms.forms import Form_Is_Included_VAT, Form_Delivery_Region, Form_Currency
|
||||
from forms.unit_measurement import Filters_Unit_Measurement
|
||||
from helpers.helper_app import Helper_App
|
||||
import lib.argument_validation as av
|
||||
# external
|
||||
from abc import ABC, abstractmethod
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from flask import Flask, session, current_app, jsonify
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
from typing import ClassVar
|
||||
|
||||
|
||||
class Model_View_Base(BaseModel, ABC):
|
||||
ATTR_TEXT_COLLAPSED: ClassVar[str] = 'textCollapsed'
|
||||
ATTR_TEXT_EXPANDED: ClassVar[str] = 'textExpanded'
|
||||
ATTR_VALUE_CURRENT: ClassVar[str] = 'current-value'
|
||||
ATTR_VALUE_PREVIOUS: ClassVar[str] = 'previous-value'
|
||||
COMPANY_ADDRESS_SHORT: ClassVar[str] = '53 Alfred Green Close, Rugby, United Kingdom, CV22 6DN'
|
||||
COMPANY_NUMBER: ClassVar[str] = '13587499'
|
||||
ENDPOINT_GET_ALTCHA_CHALLENGE: ClassVar[str] = 'routes_core_contact.create_altcha_challenge'
|
||||
ENDPOINT_PAGE_ACCESSIBILITY_REPORT: ClassVar[str] = 'routes_legal.accessibility_report'
|
||||
ENDPOINT_PAGE_ACCESSIBILITY_STATEMENT: ClassVar[str] = 'routes_legal.accessibility_statement'
|
||||
ENDPOINT_PAGE_CONTACT: ClassVar[str] = 'routes_core_contact.contact'
|
||||
ENDPOINT_PAGE_CONTACT_SUCCESS: ClassVar[str] = 'routes_core_contact.contact_success'
|
||||
ENDPOINT_PAGE_DATA_RETENTION_SCHEDULE: ClassVar[str] = 'routes_legal.retention_schedule'
|
||||
ENDPOINT_PAGE_ERROR_NO_PERMISSION: ClassVar[str] = 'routes_core.error_no_permission'
|
||||
ENDPOINT_PAGE_HOME: ClassVar[str] = 'routes_core_home.home'
|
||||
ENDPOINT_PAGE_LICENSE: ClassVar[str] = 'routes_legal.license'
|
||||
ENDPOINT_PAGE_PRIVACY_POLICY: ClassVar[str] = 'routes_legal.privacy_policy'
|
||||
ENDPOINT_POST_COMMAND: ClassVar[str] = 'routes_core_contact.contact_post'
|
||||
FLAG_ACTIVE: ClassVar[str] = Base.FLAG_ACTIVE
|
||||
FLAG_ADD: ClassVar[str] = 'add'
|
||||
# FLAG_ADD_DELETE: ClassVar[str] = 'add-delete'
|
||||
FLAG_BOOL_FALSE: ClassVar[str] = 'false'
|
||||
FLAG_BOOL_TRUE: ClassVar[str] = 'true'
|
||||
FLAG_BUTTON: ClassVar[str] = 'button'
|
||||
FLAG_BUTTON_LIGHT: ClassVar[str] = 'button-light'
|
||||
FLAG_BUTTON_PRIMARY: ClassVar[str] = 'button-primary'
|
||||
FLAG_CANCEL: ClassVar[str] = 'button-cancel'
|
||||
FLAG_CALLBACK: ClassVar[str] = 'callback'
|
||||
FLAG_CAPTCHA: ClassVar[str] = 'captcha'
|
||||
FLAG_CARD: ClassVar[str] = 'card'
|
||||
FLAG_CLOSE_TEMPORARY_ELEMENT: ClassVar[str] = 'button-temporary-element-close'
|
||||
FLAG_CODE: ClassVar[str] = Base.FLAG_CODE
|
||||
FLAG_COLLAPSED: ClassVar[str] = 'collapsed'
|
||||
FLAG_COLLAPSIBLE: ClassVar[str] = 'collapsible'
|
||||
FLAG_COLUMN: ClassVar[str] = 'column'
|
||||
FLAG_COMMENT: ClassVar[str] = 'comment'
|
||||
FLAG_CONTAINER: ClassVar[str] = 'container'
|
||||
FLAG_CONTAINER_CHECKBOX: ClassVar[str] = 'container-checkbox'
|
||||
FLAG_CONTAINER_ICON_AND_LABEL: ClassVar[str] = 'container-icon-label'
|
||||
FLAG_CONTAINER_INPUT: ClassVar[str] = 'container-input'
|
||||
FLAG_CSRF_TOKEN: ClassVar[str] = 'X-CSRFToken'
|
||||
FLAG_DATA: ClassVar[str] = 'data'
|
||||
FLAG_DATE_FROM: ClassVar[str] = Base.FLAG_DATE_FROM
|
||||
FLAG_DATE_TO: ClassVar[str] = Base.FLAG_DATE_TO
|
||||
FLAG_DELETE: ClassVar[str] = 'delete'
|
||||
FLAG_DESCRIPTION: ClassVar[str] = Base.FLAG_DESCRIPTION
|
||||
FLAG_DETAIL: ClassVar[str] = 'detail'
|
||||
FLAG_DIALOG: ClassVar[str] = 'dialog'
|
||||
FLAG_DIRTY: ClassVar[str] = 'dirty'
|
||||
FLAG_DISPLAY_ORDER: ClassVar[str] = Base.FLAG_DISPLAY_ORDER
|
||||
FLAG_EDIT: ClassVar[str] = 'edit'
|
||||
FLAG_EMAIL: ClassVar[str] = Base.FLAG_EMAIL
|
||||
FLAG_ERROR: ClassVar[str] = 'error'
|
||||
FLAG_EXPANDED: ClassVar[str] = 'expanded'
|
||||
FLAG_FAILURE: ClassVar[str] = 'failure'
|
||||
FLAG_FILTER: ClassVar[str] = 'filter'
|
||||
FLAG_FORM: ClassVar[str] = 'form'
|
||||
FLAG_FORM_FILTERS: ClassVar[str] = 'form-filters'
|
||||
FLAG_HAMBURGER: ClassVar[str] = 'hamburger'
|
||||
FLAG_IMAGE_LOGO: ClassVar[str] = 'image-logo'
|
||||
FLAG_INITIALISED: ClassVar[str] = 'initialised'
|
||||
FLAG_LEFT_HAND_STUB: ClassVar[str] = 'lhs'
|
||||
FLAG_LOGO: ClassVar[str] = 'logo'
|
||||
FLAG_MESSAGE: ClassVar[str] = Command.FLAG_MESSAGE
|
||||
FLAG_MODAL: ClassVar[str] = 'modal'
|
||||
FLAG_NAME: ClassVar[str] = Base.FLAG_NAME
|
||||
FLAG_NAME_ATTR_OPTION_TEXT: ClassVar[str] = Base.FLAG_NAME_ATTR_OPTION_TEXT
|
||||
FLAG_NAME_ATTR_OPTION_VALUE: ClassVar[str] = Base.FLAG_NAME_ATTR_OPTION_VALUE
|
||||
FLAG_NAME_PLURAL: ClassVar[str] = Base.FLAG_NAME_PLURAL
|
||||
# FLAG_NAME_SINGULAR: ClassVar[str] = Base.FLAG_NAME_SINGULAR
|
||||
FLAG_NAV_CONTACT: ClassVar[str] = 'navContact'
|
||||
FLAG_NAV_HOME: ClassVar[str] = 'navHome'
|
||||
FLAG_OVERLAY: ClassVar[str] = 'overlay'
|
||||
FLAG_PAGE_BODY: ClassVar[str] = 'page-body'
|
||||
FLAG_RIGHT_HAND_SIDE: ClassVar[str] = 'rhs'
|
||||
FLAG_ROW: ClassVar[str] = 'row'
|
||||
FLAG_ROW_NEW: ClassVar[str] = 'row-new'
|
||||
FLAG_ROWS: ClassVar[str] = Base.FLAG_ROWS
|
||||
FLAG_SAVE: ClassVar[str] = 'save'
|
||||
FLAG_SCROLLABLE: ClassVar[str] = 'scrollable'
|
||||
FLAG_SLIDER: ClassVar[str] = 'slider'
|
||||
FLAG_STATUS: ClassVar[str] = 'status'
|
||||
FLAG_SUBMIT: ClassVar[str] = 'submit'
|
||||
FLAG_SUCCESS: ClassVar[str] = 'success'
|
||||
FLAG_TEMPORARY_ELEMENT: ClassVar[str] = 'temporary-element'
|
||||
FLAG_USER: ClassVar[str] = User.FLAG_USER
|
||||
FLAG_WEBSITE: ClassVar[str] = Base.FLAG_WEBSITE
|
||||
HASH_GET_ALTCHA_CHALLENGE: ClassVar[str] = '/altcha/create-challenge'
|
||||
HASH_PAGE_ACCESSIBILITY_REPORT: ClassVar[str] = '/accessibility-report'
|
||||
HASH_PAGE_ACCESSIBILITY_STATEMENT: ClassVar[str] = '/accessibility-statement'
|
||||
HASH_PAGE_CONTACT: ClassVar[str] = '/contact'
|
||||
HASH_PAGE_CONTACT_SUCCESS: ClassVar[str] = '/contact-success'
|
||||
HASH_PAGE_DATA_RETENTION_SCHEDULE: ClassVar[str] = '/retention-schedule'
|
||||
HASH_PAGE_ERROR_NO_PERMISSION: ClassVar[str] = '/error'
|
||||
HASH_PAGE_HOME: ClassVar[str] = '/'
|
||||
HASH_PAGE_LICENSE: ClassVar[str] = '/license'
|
||||
HASH_PAGE_PRIVACY_POLICY: ClassVar[str] = '/privacy-policy'
|
||||
ID_BUTTON_ADD: ClassVar[str] = 'buttonAdd'
|
||||
ID_BUTTON_APPLY_FILTERS: ClassVar[str] = 'buttonApplyFilters'
|
||||
ID_BUTTON_CANCEL: ClassVar[str] = 'buttonCancel'
|
||||
ID_BUTTON_HAMBURGER: ClassVar[str] = 'buttonHamburger'
|
||||
ID_BUTTON_SAVE: ClassVar[str] = 'buttonSave'
|
||||
ID_CSRF_TOKEN: ClassVar[str] = 'X-CSRFToken'
|
||||
ID_FORM_CONTACT: ClassVar[str] = 'formContact'
|
||||
ID_FORM_FILTERS: ClassVar[str] = 'formFilters'
|
||||
ID_LABEL_ERROR: ClassVar[str] = 'labelError'
|
||||
ID_OVERLAY_CONFIRM: ClassVar[str] = 'overlayConfirm'
|
||||
ID_OVERLAY_ERROR: ClassVar[str] = 'overlayError'
|
||||
ID_OVERLAY_HAMBURGER: ClassVar[str] = 'overlayHamburger'
|
||||
ID_PAGE_BODY: ClassVar[str] = 'pageBody'
|
||||
ID_TABLE_MAIN: ClassVar[str] = 'tableMain'
|
||||
ID_TEXTAREA_CONFIRM: ClassVar[str] = 'textareaConfirm'
|
||||
NAME_COMPANY: ClassVar[str] = 'Precision And Research Technology Systems Limited'
|
||||
NAME_COMPANY_SHORT: ClassVar[str] = 'PARTS Ltd'
|
||||
NAME_CSRF_TOKEN: ClassVar[str] = 'csrf-token'
|
||||
URL_GITHUB: ClassVar[str] = 'https://github.com/Teddy-1024'
|
||||
URL_LINKEDIN: ClassVar[str] = 'https://uk.linkedin.com/in/teddyms'
|
||||
|
||||
hash_page_current: str
|
||||
app: Flask = None
|
||||
session: None = None
|
||||
is_page_store: bool = None
|
||||
is_user_logged_in: bool = None
|
||||
user: User = None
|
||||
access_levels: list = None
|
||||
|
||||
model_config = ConfigDict(arbitrary_types_allowed=True)
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def title(self):
|
||||
pass
|
||||
|
||||
def __init__(self, hash_page_current, **kwargs):
|
||||
BaseModel.__init__(self, hash_page_current=hash_page_current, **kwargs)
|
||||
self.app = current_app
|
||||
with self.app.app_context():
|
||||
self.session = session
|
||||
self.is_page_store = False
|
||||
Helper_App.console_log(f'session: {self.session}')
|
||||
|
||||
datastore_base = DataStore_Base()
|
||||
self.user = datastore_base.get_user_session()
|
||||
self.is_user_logged_in = self.user.get_is_logged_in()
|
||||
# Helper_App.console_log(f'model_view_base init end - model.user: {self.user}')
|
||||
|
||||
def output_bool(self, boolean):
|
||||
return str(boolean).lower()
|
||||
|
||||
def get_url_host(self):
|
||||
return self.app.config['URL_HOST']
|
||||
|
||||
def get_user_session(self):
|
||||
datastore_user = DataStore_User()
|
||||
return datastore_user.get_user_session()
|
||||
|
||||
def get_many_access_level(self, filters=None):
|
||||
_m = 'Model_View_Store.get_many_access_level'
|
||||
# av.val_instance(filters, 'filters', _m, Filters_Access_Level)
|
||||
access_levels, errors = DataStore_Base.get_many_access_level(filters)
|
||||
return access_levels
|
||||
def get_many_unit_measurement(self, filters=None):
|
||||
_m = 'Model_View_Store.get_many_unit_measurement'
|
||||
# av.val_instance(filters, 'filters', _m, Filters_Unit_Measurement)
|
||||
units_measurement, errors = DataStore_Base.get_many_unit_measurement(filters)
|
||||
return units_measurement
|
||||
|
||||
@staticmethod
|
||||
def convert_list_objects_to_json(list_objects):
|
||||
return [obj.to_json() for obj in list_objects]
|
||||
@staticmethod
|
||||
def convert_list_objects_to_list_options(list_objects):
|
||||
return Base.convert_list_objects_to_list_options(list_objects)
|
||||
@staticmethod
|
||||
def convert_list_objects_to_dict_by_attribute_key(list_objects, key):
|
||||
return {getattr(obj, key): obj for obj in list_objects}
|
||||
@staticmethod
|
||||
def convert_list_objects_to_dict_json_by_attribute_key(list_objects, key):
|
||||
return {getattr(obj, key): obj.to_json() for obj in list_objects}
|
||||
@staticmethod
|
||||
def convert_list_objects_to_dict_by_attribute_key_default(list_objects):
|
||||
if list_objects is None or len(list_objects) == 0:
|
||||
return {}
|
||||
obj_class = list_objects[0].__class__
|
||||
return Model_View_Base.convert_list_objects_to_dict_by_attribute_key(list_objects, getattr(obj_class, obj_class.FLAG_NAME_ATTR_OPTION_VALUE))
|
||||
@staticmethod
|
||||
def convert_list_objects_to_dict_json_by_attribute_key_default(list_objects):
|
||||
if list_objects is None or len(list_objects) == 0:
|
||||
return {}
|
||||
obj_class = list_objects[0].__class__
|
||||
return Model_View_Base.convert_list_objects_to_dict_json_by_attribute_key(list_objects, getattr(obj_class, obj_class.FLAG_NAME_ATTR_OPTION_VALUE))
|
||||
@staticmethod
|
||||
def convert_dict_values_to_json(dict):
|
||||
return {key: dict[key].to_json() for key in dict.keys()}
|
||||
@staticmethod
|
||||
def convert_list_objects_to_preview_str(list_objects):
|
||||
preview_str = ''
|
||||
for obj in list_objects:
|
||||
if preview_str != '':
|
||||
preview_str += '\n'
|
||||
obj_json = obj.to_json()
|
||||
preview_str += obj_json[obj_json[Base.FLAG_NAME_ATTR_OPTION_TEXT]]
|
||||
return preview_str
|
||||
@staticmethod
|
||||
def join_with_linebreaks(strs):
|
||||
str_multiline = ''
|
||||
for str in strs:
|
||||
if str_multiline != '':
|
||||
str_multiline += '\n'
|
||||
str_multiline += str
|
||||
return str_multiline
|
||||
@staticmethod
|
||||
def format_date(date):
|
||||
if date is None:
|
||||
return ''
|
||||
return date.strftime('%Y-%m-%d')
|
||||
@staticmethod
|
||||
def format_datetime(date_time):
|
||||
if date_time is None:
|
||||
return ''
|
||||
return date_time.strftime('%Y-%m-%dT%H:%M')
|
||||
@staticmethod
|
||||
def jsonify(data):
|
||||
return jsonify(data)
|
||||
def get_mail_contact_public(self):
|
||||
return self.app.config['MAIL_CONTACT_PUBLIC']
|
||||
35
models/model_view_contact.py
Normal file
35
models/model_view_contact.py
Normal file
@@ -0,0 +1,35 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: View Models
|
||||
Feature: Contact View Model
|
||||
|
||||
Description:
|
||||
Data model for contact view
|
||||
"""
|
||||
|
||||
# internal
|
||||
from business_objects.project_hub.command import Command
|
||||
from models.model_view_base import Model_View_Base
|
||||
# from routes import bp_home
|
||||
from lib import argument_validation as av
|
||||
from forms.contact import Form_Contact
|
||||
# external
|
||||
from flask_wtf import FlaskForm
|
||||
from abc import abstractproperty
|
||||
from pydantic import BaseModel
|
||||
from typing import ClassVar
|
||||
|
||||
class Model_View_Contact(Model_View_Base):
|
||||
|
||||
form_contact: Form_Contact
|
||||
|
||||
@property
|
||||
def title(self):
|
||||
return 'Contact'
|
||||
|
||||
def __init__(self, form_contact, hash_page_current=Model_View_Base.HASH_PAGE_CONTACT, **kwargs):
|
||||
super().__init__(hash_page_current=hash_page_current, form_contact=form_contact, **kwargs)
|
||||
# self.form = form
|
||||
31
models/model_view_contact_success.py
Normal file
31
models/model_view_contact_success.py
Normal file
@@ -0,0 +1,31 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: View Models
|
||||
Feature: Contact View Model
|
||||
|
||||
Description:
|
||||
Data model for contact view
|
||||
"""
|
||||
|
||||
# internal
|
||||
from models.model_view_base import Model_View_Base
|
||||
# from routes import bp_home
|
||||
from lib import argument_validation as av
|
||||
# from forms.contact import Form_Contact
|
||||
# external
|
||||
from flask_wtf import FlaskForm
|
||||
from abc import abstractproperty
|
||||
from pydantic import BaseModel
|
||||
from typing import ClassVar
|
||||
|
||||
class Model_View_Contact_Success(Model_View_Base):
|
||||
|
||||
@property
|
||||
def title(self):
|
||||
return 'Contact Success'
|
||||
|
||||
def __init__(self, hash_page_current=Model_View_Base.HASH_PAGE_CONTACT_SUCCESS, **kwargs):
|
||||
super().__init__(hash_page_current=hash_page_current, **kwargs)
|
||||
24
models/model_view_home.py
Normal file
24
models/model_view_home.py
Normal file
@@ -0,0 +1,24 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Core View Models
|
||||
Feature: Home View Model
|
||||
|
||||
Description:
|
||||
Data model for home view
|
||||
"""
|
||||
|
||||
# internal
|
||||
from models.model_view_base import Model_View_Base
|
||||
# from routes import bp_home
|
||||
# external
|
||||
|
||||
class Model_View_Home(Model_View_Base):
|
||||
@property
|
||||
def title(self):
|
||||
return 'Home'
|
||||
def __init__(self, hash_page_current=Model_View_Base.HASH_PAGE_HOME):
|
||||
super().__init__(hash_page_current=hash_page_current)
|
||||
|
||||
24
models/model_view_license.py
Normal file
24
models/model_view_license.py
Normal file
@@ -0,0 +1,24 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Legal View Models
|
||||
Feature: License View Model
|
||||
|
||||
Description:
|
||||
Data model for license view
|
||||
"""
|
||||
|
||||
# internal
|
||||
from models.model_view_base import Model_View_Base
|
||||
# from routes import bp_home
|
||||
# external
|
||||
|
||||
class Model_View_License(Model_View_Base):
|
||||
@property
|
||||
def title(self):
|
||||
return 'License'
|
||||
def __init__(self, hash_page_current=Model_View_Base.HASH_PAGE_LICENSE):
|
||||
super().__init__(hash_page_current=hash_page_current)
|
||||
|
||||
24
models/model_view_privacy_policy.py
Normal file
24
models/model_view_privacy_policy.py
Normal file
@@ -0,0 +1,24 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Legal View Models
|
||||
Feature: Privacy Policy View Model
|
||||
|
||||
Description:
|
||||
Data model for privacy policy view
|
||||
"""
|
||||
|
||||
# internal
|
||||
from models.model_view_base import Model_View_Base
|
||||
# from routes import bp_home
|
||||
# external
|
||||
|
||||
class Model_View_Privacy_Policy(Model_View_Base):
|
||||
@property
|
||||
def title(self):
|
||||
return 'Privacy Policy'
|
||||
def __init__(self, hash_page_current=Model_View_Base.HASH_PAGE_PRIVACY_POLICY):
|
||||
super().__init__(hash_page_current=hash_page_current)
|
||||
|
||||
24
models/model_view_retention_schedule.py
Normal file
24
models/model_view_retention_schedule.py
Normal file
@@ -0,0 +1,24 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Legal View Models
|
||||
Feature: Retention Schedule View Model
|
||||
|
||||
Description:
|
||||
Data model for retention schedule view
|
||||
"""
|
||||
|
||||
# internal
|
||||
from models.model_view_base import Model_View_Base
|
||||
# from routes import bp_home
|
||||
# external
|
||||
|
||||
class Model_View_Retention_Schedule(Model_View_Base):
|
||||
@property
|
||||
def title(self):
|
||||
return 'Retention Schedule'
|
||||
def __init__(self, hash_page_current=Model_View_Base.HASH_PAGE_DATA_RETENTION_SCHEDULE):
|
||||
super().__init__(hash_page_current=hash_page_current)
|
||||
|
||||
4296
package-lock.json
generated
Normal file
4296
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
40
package.json
Normal file
40
package.json
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "app",
|
||||
"version": "1.0.0",
|
||||
"description": "Precision and Research Technology Systems Limited\r Website with online store",
|
||||
"main": "webpack.config.js",
|
||||
"directories": {
|
||||
"lib": "lib"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"build": "webpack --mode production",
|
||||
"watch": "webpack --mode development --watch"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/Teddy-1024/parts_website.git"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"bugs": {
|
||||
"url": "https://github.com/Teddy-1024/parts_website/issues"
|
||||
},
|
||||
"homepage": "https://github.com/Teddy-1024/parts_website#readme",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.25.2",
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
||||
"@babel/preset-env": "^7.25.4",
|
||||
"babel-loader": "^9.1.3",
|
||||
"css-loader": "^7.1.2",
|
||||
"glob": "^11.0.0",
|
||||
"mini-css-extract-plugin": "^2.9.1",
|
||||
"style-loader": "^4.0.0",
|
||||
"webpack": "^5.94.0",
|
||||
"webpack-cli": "^5.1.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"aos": "^2.3.4"
|
||||
}
|
||||
}
|
||||
BIN
packages-microsoft-prod.deb
Normal file
BIN
packages-microsoft-prod.deb
Normal file
Binary file not shown.
15
passenger_wsgi.py
Normal file
15
passenger_wsgi.py
Normal file
@@ -0,0 +1,15 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
sys.path.insert(0, os.path.dirname(__file__))
|
||||
|
||||
|
||||
def application(environ, start_response):
|
||||
start_response('200 OK', [('Content-Type', 'text/plain')])
|
||||
message = 'It works!\n'
|
||||
version = 'Python %s\n' % sys.version.split()[0]
|
||||
response = '\n'.join([message, version])
|
||||
return [response.encode()]
|
||||
|
||||
from app import app as application # Import the Flask application from app.py
|
||||
18
requirements.txt
Normal file
18
requirements.txt
Normal file
@@ -0,0 +1,18 @@
|
||||
|
||||
Flask==3.0.3
|
||||
gunicorn==23.0.0
|
||||
flask_wtf
|
||||
flask_sqlalchemy
|
||||
flask_cors
|
||||
flask_mail
|
||||
authlib
|
||||
jwt
|
||||
mysqlclient
|
||||
stripe
|
||||
python_dotenv
|
||||
authlib
|
||||
pydantic
|
||||
# psycopg2
|
||||
requests
|
||||
cryptography
|
||||
altcha
|
||||
3
robots.txt
Normal file
3
robots.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
User-agent: *
|
||||
Disallow: /qa
|
||||
Disallow: /dev
|
||||
54
routes.py
Normal file
54
routes.py
Normal file
@@ -0,0 +1,54 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Backend
|
||||
Feature: Controller - Webpage routing
|
||||
|
||||
Description:
|
||||
Defines the routes and view functions for each page.
|
||||
Manages the interaction between the frontend and backend.
|
||||
"""
|
||||
|
||||
from flask import render_template, url_for, Blueprint
|
||||
from app import app
|
||||
from app.forms import Form_Contact
|
||||
# from forms import MyForm
|
||||
# from app import MyForm
|
||||
from model_view_contact import Model_View_Contact
|
||||
|
||||
"""
|
||||
@app.route('/', methods=['GET'])
|
||||
def home():
|
||||
return render_template('_home.html', title='Home')
|
||||
|
||||
@app.route('/store', methods=['GET'])
|
||||
def store_home():
|
||||
return render_template('_store_home.html', title='Store Home')
|
||||
|
||||
@app.route('/contact', methods=['GET', 'POST'])
|
||||
def contact():
|
||||
form = Form_Contact()
|
||||
if form.validate_on_submit():
|
||||
# Handle form submission
|
||||
email = form.sender_email.data
|
||||
CC = form.sender_CC.data
|
||||
name = form.sender_name.data
|
||||
msg = form.sender_message.data
|
||||
# return render_template('contact.html', form=form)
|
||||
# return render_template('_contact.html', title='Contact Us')
|
||||
return render_template('contact.html', model=Model_View_Contact(form))
|
||||
|
||||
@app.route('/about')
|
||||
def about():
|
||||
return render_template('about.html')
|
||||
|
||||
@app.route('/contact', methods=['GET', 'POST'])
|
||||
def contact():
|
||||
form = MyForm()
|
||||
if form.validate_on_submit():
|
||||
# Handle form submission
|
||||
pass
|
||||
return render_template('contact.html', form=form)
|
||||
"""
|
||||
17
run.py
Normal file
17
run.py
Normal file
@@ -0,0 +1,17 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Backend
|
||||
Feature: Launcher
|
||||
|
||||
Description:
|
||||
Runs project.
|
||||
"""
|
||||
|
||||
from app import app
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=True)
|
||||
# app.run(debug=True, host="0.0.0.0", port=5000)
|
||||
5769
static/MySQL/0000_combined.sql
Normal file
5769
static/MySQL/0000_combined.sql
Normal file
File diff suppressed because it is too large
Load Diff
153
static/MySQL/0001_destroy.sql
Normal file
153
static/MySQL/0001_destroy.sql
Normal file
@@ -0,0 +1,153 @@
|
||||
|
||||
CREATE DATABASE IF NOT EXISTS parts;
|
||||
|
||||
GRANT ALL PRIVILEGES ON parts.* TO 'teddy'@'%';
|
||||
FLUSH PRIVILEGES;
|
||||
|
||||
USE parts;
|
||||
|
||||
-- Permanent Temp Tables
|
||||
DROP TABLE IF EXISTS parts.tmp_DOG_Calc_User;
|
||||
-- DROP TABLE IF EXISTS parts.tmp_core_Msg_Error;
|
||||
DROP TABLE IF EXISTS parts.tmp_DOG_User;
|
||||
DROP TABLE IF EXISTS parts.tmp_DOG_User_Role_Link;
|
||||
|
||||
|
||||
-- Permanent Tables
|
||||
DROP TABLE IF EXISTS parts.DOG_Dog_Drive_Link_Temp;
|
||||
DROP TABLE IF EXISTS parts.DOG_Dog_Drive_Link_Audit;
|
||||
DROP TABLE IF EXISTS parts.DOG_Dog_Drive_Link;
|
||||
|
||||
DROP TABLE IF EXISTS parts.DOG_Drive_Temp;
|
||||
DROP TABLE IF EXISTS parts.DOG_Drive_Audit;
|
||||
DROP TABLE IF EXISTS parts.DOG_Drive;
|
||||
|
||||
DROP TABLE IF EXISTS parts.DOG_Command_Button_Link_Temp;
|
||||
DROP TABLE IF EXISTS parts.DOG_Command_Button_Link_Audit;
|
||||
DROP TABLE IF EXISTS parts.DOG_Command_Button_Link;
|
||||
|
||||
DROP TABLE IF EXISTS parts.DOG_Button_Icon_Temp;
|
||||
DROP TABLE IF EXISTS parts.DOG_Button_Icon_Audit;
|
||||
DROP TABLE IF EXISTS parts.DOG_Button_Icon;
|
||||
|
||||
DROP TABLE IF EXISTS parts.DOG_Image_Temp;
|
||||
DROP TABLE IF EXISTS parts.DOG_Image_Audit;
|
||||
DROP TABLE IF EXISTS parts.DOG_Image;
|
||||
|
||||
DROP TABLE IF EXISTS parts.DOG_Button_Shape_Temp;
|
||||
DROP TABLE IF EXISTS parts.DOG_Button_Shape_Audit;
|
||||
DROP TABLE IF EXISTS parts.DOG_Button_Shape;
|
||||
|
||||
DROP TABLE IF EXISTS parts.DOG_Colour_Temp;
|
||||
DROP TABLE IF EXISTS parts.DOG_Colour_Audit;
|
||||
DROP TABLE IF EXISTS parts.DOG_Colour;
|
||||
|
||||
DROP TABLE IF EXISTS parts.DOG_Location_Link_Temp;
|
||||
DROP TABLE IF EXISTS parts.DOG_Location_Link_Audit;
|
||||
DROP TABLE IF EXISTS parts.DOG_Location_Link;
|
||||
|
||||
DROP TABLE IF EXISTS parts.DOG_Location_Temp;
|
||||
DROP TABLE IF EXISTS parts.DOG_Location_Audit;
|
||||
DROP TABLE IF EXISTS parts.DOG_Location;
|
||||
|
||||
DROP TABLE IF EXISTS parts.DOG_Personal_Best_Temp;
|
||||
DROP TABLE IF EXISTS parts.DOG_Personal_Best_Audit;
|
||||
DROP TABLE IF EXISTS parts.DOG_Personal_Best;
|
||||
|
||||
DROP TABLE IF EXISTS parts.DOG_Dog_Command_Link_Temp;
|
||||
DROP TABLE IF EXISTS parts.DOG_Dog_Command_Link_Audit;
|
||||
DROP TABLE IF EXISTS parts.DOG_Dog_Command_Link;
|
||||
|
||||
DROP TABLE IF EXISTS parts.DOG_Command_Temp;
|
||||
DROP TABLE IF EXISTS parts.DOG_Command_Audit;
|
||||
DROP TABLE IF EXISTS parts.DOG_Command;
|
||||
|
||||
DROP TABLE IF EXISTS parts.DOG_Command_Category_Temp;
|
||||
DROP TABLE IF EXISTS parts.DOG_Command_Category_Audit;
|
||||
DROP TABLE IF EXISTS parts.DOG_Command_Category;
|
||||
|
||||
DROP TABLE IF EXISTS parts.DOG_Obedience_Level_Temp;
|
||||
DROP TABLE IF EXISTS parts.DOG_Obedience_Level_Audit;
|
||||
DROP TABLE IF EXISTS parts.DOG_Obedience_Level;
|
||||
|
||||
DROP TABLE IF EXISTS parts.DOG_Understanding_Level_Temp;
|
||||
DROP TABLE IF EXISTS parts.DOG_Understanding_Level_Audit;
|
||||
DROP TABLE IF EXISTS parts.DOG_Understanding_Level;
|
||||
|
||||
DROP TABLE IF EXISTS parts.DOG_Competency_Level_Temp;
|
||||
DROP TABLE IF EXISTS parts.DOG_Competency_Level_Audit;
|
||||
DROP TABLE IF EXISTS parts.DOG_Competency_Level;
|
||||
|
||||
DROP TABLE IF EXISTS parts.DOG_Dog_Breed_Link_Temp;
|
||||
DROP TABLE IF EXISTS parts.DOG_Dog_Breed_Link_Audit;
|
||||
DROP TABLE IF EXISTS parts.DOG_Dog_Breed_Link;
|
||||
|
||||
DROP TABLE IF EXISTS parts.DOG_Breed_Temp;
|
||||
DROP TABLE IF EXISTS parts.DOG_Breed_Audit;
|
||||
DROP TABLE IF EXISTS parts.DOG_Breed;
|
||||
|
||||
DROP TABLE IF EXISTS parts.DOG_Dog_Temp;
|
||||
DROP TABLE IF EXISTS parts.DOG_Dog_Audit;
|
||||
DROP TABLE IF EXISTS parts.DOG_Dog;
|
||||
|
||||
DROP TABLE IF EXISTS parts.DOG_Dog_Change_Set;
|
||||
|
||||
DROP TABLE IF EXISTS parts.DOG_Calc_User_Temp;
|
||||
|
||||
DROP TABLE IF EXISTS parts.DOG_User_Role_Link_Audit;
|
||||
DROP TABLE IF EXISTS parts.DOG_User_Role_Link;
|
||||
|
||||
DROP TABLE IF EXISTS parts.DOG_Role_Permission_Link_Audit;
|
||||
DROP TABLE IF EXISTS parts.DOG_Role_Permission_Link;
|
||||
|
||||
DROP TABLE IF EXISTS parts.DOG_Role_Audit;
|
||||
DROP TABLE IF EXISTS parts.DOG_Role;
|
||||
|
||||
DROP TABLE IF EXISTS parts.DOG_User_Temp;
|
||||
DROP TABLE IF EXISTS parts.DOG_User_Audit;
|
||||
DROP TABLE IF EXISTS parts.DOG_User;
|
||||
|
||||
DROP TABLE IF EXISTS parts.DOG_Permission_Audit;
|
||||
DROP TABLE IF EXISTS parts.DOG_Permission;
|
||||
|
||||
DROP TABLE IF EXISTS parts.DOG_Permission_Group_Audit;
|
||||
DROP TABLE IF EXISTS parts.DOG_Permission_Group;
|
||||
|
||||
DROP TABLE IF EXISTS parts.DOG_Access_Level_Audit;
|
||||
DROP TABLE IF EXISTS parts.DOG_Access_Level;
|
||||
|
||||
DROP TABLE IF EXISTS parts.DOG_User_Change_Set;
|
||||
|
||||
/*
|
||||
DROP TABLE IF EXISTS parts.CORE_Split_Key_Value_Pair_Csv_Temp;
|
||||
DROP TABLE IF EXISTS parts.CORE_Split_Temp;
|
||||
|
||||
*/
|
||||
DROP TABLE IF EXISTS parts.CORE_File_Type;
|
||||
DROP TABLE IF EXISTS parts.CORE_Msg_Error_Type;
|
||||
|
||||
-- Stored Procedures
|
||||
DROP PROCEDURE IF EXISTS parts.p_DOG_test_get_many_dog_command;
|
||||
DROP PROCEDURE IF EXISTS parts.p_DOG_test_get_many_command;
|
||||
DROP PROCEDURE IF EXISTS parts.p_DOG_get_many_command;
|
||||
DROP PROCEDURE IF EXISTS parts.p_DOG_test_save_command;
|
||||
DROP PROCEDURE IF EXISTS parts.p_DOG_save_command;
|
||||
|
||||
DROP PROCEDURE IF EXISTS parts.p_DOG_clear_calc_user;
|
||||
DROP PROCEDURE IF EXISTS parts.p_DOG_calc_user;
|
||||
|
||||
/*
|
||||
DROP PROCEDURE IF EXISTS parts.p_core_clear_split_key_value_pair_csv;
|
||||
DROP PROCEDURE IF EXISTS parts.p_core_split_key_value_pair_csv;
|
||||
DROP PROCEDURE IF EXISTS parts.p_core_clear_split;
|
||||
DROP PROCEDURE IF EXISTS parts.p_core_split;
|
||||
DROP PROCEDURE IF EXISTS parts.p_clear_split_key_value_pair_csv;
|
||||
DROP PROCEDURE IF EXISTS parts.p_split_key_value_pair_csv;
|
||||
DROP PROCEDURE IF EXISTS parts.p_clear_split;
|
||||
DROP PROCEDURE IF EXISTS parts.p_split;
|
||||
|
||||
DROP PROCEDURE IF EXISTS parts.p_core_debug_timing_reporting;
|
||||
DROP PROCEDURE IF EXISTS parts.p_debug_timing_reporting;
|
||||
DROP PROCEDURE IF EXISTS parts.p_core_validate_guid;
|
||||
DROP PROCEDURE IF EXISTS parts.p_core_validate_guid_test;
|
||||
*/
|
||||
19
static/MySQL/1000_tbl_CORE_Msg_Error_Type.sql
Normal file
19
static/MySQL/1000_tbl_CORE_Msg_Error_Type.sql
Normal file
@@ -0,0 +1,19 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'CORE_Msg_Error_Type'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.CORE_Msg_Error_Type (
|
||||
id_type INT NOT NULL AUTO_INCREMENT PRIMARY KEY
|
||||
, code VARCHAR(100) NOT NULL
|
||||
, name VARCHAR(500) NOT NULL
|
||||
, description VARCHAR(1000)
|
||||
, is_breaking_error BIT NOT NULL
|
||||
, background_colour VARCHAR(32) NOT NULL DEFAULT '#111111'
|
||||
, text_colour VARCHAR(32) NOT NULL DEFAULT '#110000'
|
||||
);
|
||||
17
static/MySQL/1020_tbl_CORE_File_Type.sql
Normal file
17
static/MySQL/1020_tbl_CORE_File_Type.sql
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'CORE_File_Type'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.CORE_File_Type (
|
||||
id_file_type INT NOT NULL AUTO_INCREMENT PRIMARY KEY
|
||||
, code VARCHAR(100) NOT NULL
|
||||
, name VARCHAR(250) NOT NULL
|
||||
, is_image BIT NOT NULL DEFAULT 0
|
||||
, active BIT NOT NULL DEFAULT 1
|
||||
);
|
||||
15
static/MySQL/1090_tbl_CORE_Split_Temp.sql
Normal file
15
static/MySQL/1090_tbl_CORE_Split_Temp.sql
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'CORE_Split_Temp'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.CORE_Split_Temp (
|
||||
guid BINARY(36) NOT NULL
|
||||
, display_order INT NOT NULL
|
||||
, substring VARCHAR(4000) NOT NULL
|
||||
);
|
||||
16
static/MySQL/1091_tbl_CORE_Split_Key_Value_Pair_Csv_Temp.sql
Normal file
16
static/MySQL/1091_tbl_CORE_Split_Key_Value_Pair_Csv_Temp.sql
Normal file
@@ -0,0 +1,16 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'CORE_Split_Key_Value_Pair_Csv_Temp'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.CORE_Split_Key_Value_Pair_Csv_Temp (
|
||||
guid BINARY(36) NOT NULL
|
||||
, id INT NOT NULL
|
||||
, key_column VARCHAR(4000) NULL
|
||||
, value_column VARCHAR(4000) NULL
|
||||
);
|
||||
16
static/MySQL/1100_tbl_DOG_User_Change_Set.sql
Normal file
16
static/MySQL/1100_tbl_DOG_User_Change_Set.sql
Normal file
@@ -0,0 +1,16 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'DOG_User_Change_Set'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.DOG_User_Change_Set (
|
||||
id_change_set INT NOT NULL AUTO_INCREMENT PRIMARY KEY
|
||||
, comment VARCHAR(500)
|
||||
, updated_last_on DATETIME
|
||||
, id_user_updated_last_by INT
|
||||
);
|
||||
20
static/MySQL/1104_tbl_DOG_Access_Level.sql
Normal file
20
static/MySQL/1104_tbl_DOG_Access_Level.sql
Normal file
@@ -0,0 +1,20 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'DOG_Access_Level'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.DOG_Access_Level (
|
||||
id_access_level INT NOT NULL AUTO_INCREMENT PRIMARY KEY
|
||||
, code VARCHAR(100)
|
||||
, name VARCHAR(250)
|
||||
, priority INT NOT NULL
|
||||
, display_order INT NOT NULL
|
||||
, active BIT NOT NULL DEFAULT 1
|
||||
);
|
||||
|
||||
|
||||
17
static/MySQL/1108_tbl_DOG_Permission_Group.sql
Normal file
17
static/MySQL/1108_tbl_DOG_Permission_Group.sql
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'DOG_Permission_Group'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.DOG_Permission_Group (
|
||||
id_group INT NOT NULL AUTO_INCREMENT PRIMARY KEY
|
||||
, code VARCHAR(100)
|
||||
, name VARCHAR(250)
|
||||
, display_order INT NOT NULL
|
||||
, active BIT NOT NULL DEFAULT 1
|
||||
);
|
||||
25
static/MySQL/1112_tbl_DOG_Permission.sql
Normal file
25
static/MySQL/1112_tbl_DOG_Permission.sql
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'DOG_Permission'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.DOG_Permission (
|
||||
id_permission INT NOT NULL AUTO_INCREMENT PRIMARY KEY
|
||||
, code VARCHAR(100)
|
||||
, name VARCHAR(250)
|
||||
, id_permission_group INT NOT NULL
|
||||
, CONSTRAINT FK_DOG_Permission_id_permission_group
|
||||
FOREIGN KEY (id_permission_group)
|
||||
REFERENCES parts.DOG_Permission_Group(id_group)
|
||||
, id_access_level_required INT NOT NULL
|
||||
, CONSTRAINT FK_DOG_Permission_id_access_level_required
|
||||
FOREIGN KEY (id_access_level_required)
|
||||
REFERENCES parts.DOG_Access_Level(id_access_level)
|
||||
, display_order INT NOT NULL
|
||||
, active BIT NOT NULL DEFAULT 1
|
||||
);
|
||||
29
static/MySQL/1116_tbl_DOG_User.sql
Normal file
29
static/MySQL/1116_tbl_DOG_User.sql
Normal file
@@ -0,0 +1,29 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'DOG_User'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.DOG_User (
|
||||
id_user INT NOT NULL AUTO_INCREMENT PRIMARY KEY
|
||||
, id_user_auth0 VARCHAR(200)
|
||||
, firstname VARCHAR(250)
|
||||
, surname VARCHAR(250)
|
||||
, email VARCHAR(254)
|
||||
, is_email_verified BIT NOT NULL DEFAULT 0
|
||||
, is_super_user BIT NOT NULL DEFAULT 0
|
||||
, active BIT NOT NULL DEFAULT 1
|
||||
, created_on DATETIME
|
||||
, id_user_created_by INT
|
||||
, CONSTRAINT FK_DOG_User_id_user_created_by
|
||||
FOREIGN KEY (id_user_created_by)
|
||||
REFERENCES parts.DOG_User(id_user)
|
||||
, id_change_set INT
|
||||
, CONSTRAINT FK_DOG_User_id_change_set
|
||||
FOREIGN KEY (id_change_set)
|
||||
REFERENCES parts.DOG_User_Change_Set(id_change_set)
|
||||
);
|
||||
24
static/MySQL/1118_tbl_DOG_User_Audit.sql
Normal file
24
static/MySQL/1118_tbl_DOG_User_Audit.sql
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'DOG_User_Audit'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.DOG_User_Audit (
|
||||
id_audit INT NOT NULL AUTO_INCREMENT PRIMARY KEY
|
||||
, id_user INT NOT NULL
|
||||
, CONSTRAINT FK_DOG_User_Audit_id_user
|
||||
FOREIGN KEY (id_user)
|
||||
REFERENCES parts.DOG_User(id_user)
|
||||
, name_field VARCHAR(100) NOT NULL
|
||||
, value_prev VARCHAR(500)
|
||||
, value_new VARCHAR(500)
|
||||
, id_change_set INT NOT NULL
|
||||
, CONSTRAINT FK_DOG_User_Audit_id_change_set
|
||||
FOREIGN KEY (id_change_set)
|
||||
REFERENCES parts.DOG_User_Change_Set(id_change_set)
|
||||
);
|
||||
22
static/MySQL/1119_tbl_DOG_User_Temp.sql
Normal file
22
static/MySQL/1119_tbl_DOG_User_Temp.sql
Normal file
@@ -0,0 +1,22 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'DOG_User_Temp'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.DOG_User_Temp (
|
||||
id_temp INT NOT NULL AUTO_INCREMENT PRIMARY KEY
|
||||
, id_user INT NOT NULL
|
||||
, id_user_auth0 VARCHAR(200)
|
||||
, firstname VARCHAR(250)
|
||||
, surname VARCHAR(250)
|
||||
, email VARCHAR(254)
|
||||
, is_email_verified BIT
|
||||
, is_super_user BIT
|
||||
, active BIT
|
||||
, guid BINARY(36) NOT NULL
|
||||
);
|
||||
26
static/MySQL/1120_tbl_DOG_Role.sql
Normal file
26
static/MySQL/1120_tbl_DOG_Role.sql
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'DOG_Role'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.DOG_Role (
|
||||
id_role INT NOT NULL AUTO_INCREMENT PRIMARY KEY
|
||||
, code VARCHAR(100)
|
||||
, name VARCHAR(250)
|
||||
, display_order INT NOT NULL
|
||||
, active BIT NOT NULL DEFAULT 1
|
||||
, created_on DATETIME
|
||||
, id_user_created_by INT
|
||||
, CONSTRAINT FK_DOG_Role_id_user_created_by
|
||||
FOREIGN KEY (id_user_created_by)
|
||||
REFERENCES parts.DOG_User(id_user)
|
||||
, id_change_set INT
|
||||
, CONSTRAINT FK_DOG_Role_id_change_set
|
||||
FOREIGN KEY (id_change_set)
|
||||
REFERENCES parts.DOG_User_Change_Set(id_change_set)
|
||||
);
|
||||
24
static/MySQL/1121_tbl_DOG_Role_Audit.sql
Normal file
24
static/MySQL/1121_tbl_DOG_Role_Audit.sql
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'DOG_Role_Audit'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.DOG_Role_Audit (
|
||||
id_audit INT NOT NULL AUTO_INCREMENT PRIMARY KEY
|
||||
, id_role INT NOT NULL
|
||||
, CONSTRAINT FK_DOG_Role_Audit_id_role
|
||||
FOREIGN KEY (id_role)
|
||||
REFERENCES parts.DOG_Role(id_role)
|
||||
, name_field VARCHAR(100) NOT NULL
|
||||
, value_prev VARCHAR(500)
|
||||
, value_new VARCHAR(500)
|
||||
, id_change_set INT NOT NULL
|
||||
, CONSTRAINT FK_DOG_Role_Audit_id_change_set
|
||||
FOREIGN KEY (id_change_set)
|
||||
REFERENCES parts.DOG_User_Change_Set(id_change_set)
|
||||
);
|
||||
35
static/MySQL/1124_tbl_DOG_Role_Permission_Link.sql
Normal file
35
static/MySQL/1124_tbl_DOG_Role_Permission_Link.sql
Normal file
@@ -0,0 +1,35 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'DOG_Role_Permission_Link'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.DOG_Role_Permission_Link (
|
||||
id_link INT NOT NULL AUTO_INCREMENT PRIMARY KEY
|
||||
, id_role INT NOT NULL
|
||||
, CONSTRAINT FK_DOG_Role_Permission_Link_id_role
|
||||
FOREIGN KEY (id_role)
|
||||
REFERENCES parts.DOG_Role(id_role)
|
||||
, id_permission INT NOT NULL
|
||||
, CONSTRAINT FK_DOG_Role_Permission_Link_id_permission
|
||||
FOREIGN KEY (id_permission)
|
||||
REFERENCES parts.DOG_Permission(id_permission)
|
||||
, id_access_level INT NOT NULL
|
||||
, CONSTRAINT FK_DOG_Role_Permission_Link_id_access_level
|
||||
FOREIGN KEY (id_access_level)
|
||||
REFERENCES parts.DOG_Access_Level(id_access_level)
|
||||
, active BIT NOT NULL DEFAULT 1
|
||||
, created_on DATETIME
|
||||
, id_user_created_by INT
|
||||
, CONSTRAINT FK_DOG_Role_Permission_Link_id_user_created_by
|
||||
FOREIGN KEY (id_user_created_by)
|
||||
REFERENCES parts.DOG_User(id_user)
|
||||
, id_change_set INT
|
||||
, CONSTRAINT FK_DOG_Role_Permission_Link_id_change_set
|
||||
FOREIGN KEY (id_change_set)
|
||||
REFERENCES parts.DOG_User_Change_Set(id_change_set)
|
||||
);
|
||||
23
static/MySQL/1125_tbl_DOG_Role_Permission_Link_Audit.sql
Normal file
23
static/MySQL/1125_tbl_DOG_Role_Permission_Link_Audit.sql
Normal file
@@ -0,0 +1,23 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'DOG_Role_Permission_Link_Audit';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.DOG_Role_Permission_Link_Audit (
|
||||
id_audit INT NOT NULL AUTO_INCREMENT PRIMARY KEY
|
||||
, id_link INT NOT NULL
|
||||
, CONSTRAINT FK_DOG_Role_Permission_Link_Audit_id_link
|
||||
FOREIGN KEY (id_link)
|
||||
REFERENCES parts.DOG_Role_Permission_Link(id_link)
|
||||
, name_field VARCHAR(100) NOT NULL
|
||||
, value_prev VARCHAR(500)
|
||||
, value_new VARCHAR(500)
|
||||
, id_change_set INT NOT NULL
|
||||
, CONSTRAINT FK_DOG_Role_Permission_Link_Audit_id_change_set
|
||||
FOREIGN KEY (id_change_set)
|
||||
REFERENCES parts.DOG_User_Change_Set(id_change_set)
|
||||
);
|
||||
31
static/MySQL/1128_tbl_DOG_User_Role_Link.sql
Normal file
31
static/MySQL/1128_tbl_DOG_User_Role_Link.sql
Normal file
@@ -0,0 +1,31 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'DOG_User_Role_Link'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.DOG_User_Role_Link (
|
||||
id_link INT NOT NULL AUTO_INCREMENT PRIMARY KEY
|
||||
, id_user INT NOT NULL
|
||||
, CONSTRAINT FK_DOG_User_Role_Link_id_user
|
||||
FOREIGN KEY (id_user)
|
||||
REFERENCES parts.DOG_User(id_user)
|
||||
, id_role INT NOT NULL
|
||||
, CONSTRAINT FK_DOG_User_Role_Link_id_role
|
||||
FOREIGN KEY (id_role)
|
||||
REFERENCES parts.DOG_Role(id_role)
|
||||
, active BIT NOT NULL DEFAULT 1
|
||||
, created_on DATETIME
|
||||
, id_user_created_by INT
|
||||
, CONSTRAINT FK_DOG_User_Role_Link_id_user_created_by
|
||||
FOREIGN KEY (id_user_created_by)
|
||||
REFERENCES parts.DOG_User(id_user)
|
||||
, id_change_set INT
|
||||
, CONSTRAINT FK_DOG_User_Role_Link_id_change_set
|
||||
FOREIGN KEY (id_change_set)
|
||||
REFERENCES parts.DOG_User_Change_Set(id_change_set)
|
||||
);
|
||||
24
static/MySQL/1129_tbl_DOG_User_Role_Link_Audit.sql
Normal file
24
static/MySQL/1129_tbl_DOG_User_Role_Link_Audit.sql
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'DOG_User_Role_Link_Audit'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.DOG_User_Role_Link_Audit (
|
||||
id_audit INT NOT NULL AUTO_INCREMENT PRIMARY KEY
|
||||
, id_link INT NOT NULL
|
||||
, CONSTRAINT FK_DOG_User_Role_Link_Audit_id_link
|
||||
FOREIGN KEY (id_link)
|
||||
REFERENCES parts.DOG_User_Role_Link(id_link)
|
||||
, name_field VARCHAR(100) NOT NULL
|
||||
, value_prev VARCHAR(500)
|
||||
, value_new VARCHAR(500)
|
||||
, id_change_set INT NOT NULL
|
||||
, CONSTRAINT FK_DOG_User_Role_Link_Audit_id_change_set
|
||||
FOREIGN KEY (id_change_set)
|
||||
REFERENCES parts.DOG_User_Change_Set(id_change_set)
|
||||
);
|
||||
22
static/MySQL/1130_tbl_DOG_Calc_User_Temp.sql
Normal file
22
static/MySQL/1130_tbl_DOG_Calc_User_Temp.sql
Normal file
@@ -0,0 +1,22 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'DOG_Calc_User_Temp'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.DOG_Calc_User_Temp (
|
||||
guid BINARY(36) NOT NULL
|
||||
, id_user INT
|
||||
, id_permission_required INT NOT NULL
|
||||
, CONSTRAINT FK_DOG_Calc_User_Temp_id_permission_required
|
||||
FOREIGN KEY (id_permission_required)
|
||||
REFERENCES parts.DOG_Permission (id_permission)
|
||||
, priority_access_level_required INT NOT NULL
|
||||
, is_super_user BIT
|
||||
, priority_access_level_user INT
|
||||
, has_access BIT
|
||||
);
|
||||
19
static/MySQL/1200_tbl_DOG_Dog_Change_Set.sql
Normal file
19
static/MySQL/1200_tbl_DOG_Dog_Change_Set.sql
Normal file
@@ -0,0 +1,19 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'DOG_Dog_Change_Set'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.DOG_Dog_Change_Set (
|
||||
id_change_set INT NOT NULL AUTO_INCREMENT PRIMARY KEY
|
||||
, comment VARCHAR(500)
|
||||
, updated_last_on DATETIME
|
||||
, id_user_updated_last_by INT
|
||||
, CONSTRAINT FK_DOG_Role_id_user_updated_last_by
|
||||
FOREIGN KEY (id_user_updated_last_by)
|
||||
REFERENCES parts.DOG_User(id_user)
|
||||
);
|
||||
27
static/MySQL/1201_tbl_DOG_Dog.sql
Normal file
27
static/MySQL/1201_tbl_DOG_Dog.sql
Normal file
@@ -0,0 +1,27 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'DOG_Dog'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.DOG_Dog (
|
||||
id_dog INT NOT NULL AUTO_INCREMENT PRIMARY KEY
|
||||
, name VARCHAR(250) NOT NULL
|
||||
, appearance VARCHAR(1000)
|
||||
, mass_kg DECIMAL(7, 3)
|
||||
, notes TEXT
|
||||
, active BIT NOT NULL DEFAULT 1
|
||||
, created_on DATETIME
|
||||
, id_user_created_by INT
|
||||
, CONSTRAINT FK_DOG_Dog_id_user_created_by
|
||||
FOREIGN KEY (id_user_created_by)
|
||||
REFERENCES parts.DOG_User(id_user)
|
||||
, id_change_set INT
|
||||
, CONSTRAINT FK_DOG_Dog_id_change_set
|
||||
FOREIGN KEY (id_change_set)
|
||||
REFERENCES parts.DOG_Dog_Change_Set(id_change_set)
|
||||
);
|
||||
24
static/MySQL/1202_tbl_DOG_Dog_Audit.sql
Normal file
24
static/MySQL/1202_tbl_DOG_Dog_Audit.sql
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'DOG_Dog_Audit'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.DOG_Dog_Audit (
|
||||
id_audit INT NOT NULL AUTO_INCREMENT PRIMARY KEY
|
||||
, id_dog INT NOT NULL
|
||||
, CONSTRAINT FK_DOG_Dog_Audit_id_dog
|
||||
FOREIGN KEY (id_dog)
|
||||
REFERENCES parts.DOG_Dog(id_dog)
|
||||
, name_field VARCHAR(100) NOT NULL
|
||||
, value_prev TEXT
|
||||
, value_new TEXT
|
||||
, id_change_set INT NOT NULL
|
||||
, CONSTRAINT FK_DOG_Dog_Audit_id_change_set
|
||||
FOREIGN KEY (id_change_set)
|
||||
REFERENCES parts.DOG_Dog_Change_Set(id_change_set)
|
||||
);
|
||||
20
static/MySQL/1203_tbl_DOG_Dog_Temp.sql
Normal file
20
static/MySQL/1203_tbl_DOG_Dog_Temp.sql
Normal file
@@ -0,0 +1,20 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'DOG_Dog_Temp'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.DOG_Dog_Temp (
|
||||
id_temp INT NOT NULL PRIMARY KEY AUTO_INCREMENT
|
||||
, id_dog INT
|
||||
, name VARCHAR(250)
|
||||
, appearance VARCHAR(1000)
|
||||
, mass_kg DECIMAL(7, 3)
|
||||
, notes TEXT
|
||||
, active BIT
|
||||
, guid BINARY(36)
|
||||
);
|
||||
25
static/MySQL/1205_tbl_DOG_Breed.sql
Normal file
25
static/MySQL/1205_tbl_DOG_Breed.sql
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'DOG_Breed'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.DOG_Breed (
|
||||
id_breed INT NOT NULL AUTO_INCREMENT PRIMARY KEY
|
||||
, code VARCHAR(100) NOT NULL
|
||||
, name VARCHAR(250) NOT NULL
|
||||
, active BIT NOT NULL DEFAULT 1
|
||||
, created_on DATETIME
|
||||
, id_user_created_by INT
|
||||
, CONSTRAINT FK_DOG_Breed_id_user_created_by
|
||||
FOREIGN KEY (id_user_created_by)
|
||||
REFERENCES parts.DOG_User(id_user)
|
||||
, id_change_set INT
|
||||
, CONSTRAINT FK_DOG_Breed_id_change_set
|
||||
FOREIGN KEY (id_change_set)
|
||||
REFERENCES parts.DOG_Dog_Change_Set(id_change_set)
|
||||
);
|
||||
24
static/MySQL/1206_tbl_DOG_Breed_Audit.sql
Normal file
24
static/MySQL/1206_tbl_DOG_Breed_Audit.sql
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'DOG_Breed_Audit'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.DOG_Breed_Audit (
|
||||
id_audit INT NOT NULL AUTO_INCREMENT PRIMARY KEY
|
||||
, id_breed INT NOT NULL
|
||||
, CONSTRAINT FK_DOG_Breed_Audit_id_breed
|
||||
FOREIGN KEY (id_breed)
|
||||
REFERENCES parts.DOG_Breed(id_breed)
|
||||
, name_field VARCHAR(100) NOT NULL
|
||||
, value_prev TEXT
|
||||
, value_new TEXT
|
||||
, id_change_set INT NOT NULL
|
||||
, CONSTRAINT FK_DOG_Breed_Audit_id_change_set
|
||||
FOREIGN KEY (id_change_set)
|
||||
REFERENCES parts.DOG_Dog_Change_Set(id_change_set)
|
||||
);
|
||||
18
static/MySQL/1207_tbl_DOG_Breed_Temp.sql
Normal file
18
static/MySQL/1207_tbl_DOG_Breed_Temp.sql
Normal file
@@ -0,0 +1,18 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'DOG_Breed_Temp'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.DOG_Breed_Temp (
|
||||
id_temp INT NOT NULL PRIMARY KEY AUTO_INCREMENT
|
||||
, id_breed INT
|
||||
, code VARCHAR(100)
|
||||
, name VARCHAR(250)
|
||||
, active BIT
|
||||
, guid BINARY(36)
|
||||
);
|
||||
32
static/MySQL/1209_tbl_DOG_Dog_Breed_Link.sql
Normal file
32
static/MySQL/1209_tbl_DOG_Dog_Breed_Link.sql
Normal file
@@ -0,0 +1,32 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'DOG_Dog_Breed_Link'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.DOG_Dog_Breed_Link (
|
||||
id_link INT NOT NULL AUTO_INCREMENT PRIMARY KEY
|
||||
, id_dog INT NOT NULL
|
||||
, CONSTRAINT FK_DOG_Dog_Breed_Link_id_dog
|
||||
FOREIGN KEY (id_dog)
|
||||
REFERENCES parts.DOG_Dog(id_dog)
|
||||
, id_breed INT NOT NULL
|
||||
, CONSTRAINT FK_DOG_Dog_Breed_Link_id_breed
|
||||
FOREIGN KEY (id_breed)
|
||||
REFERENCES parts.DOG_Breed(id_breed)
|
||||
, lineage_ratio DECIMAL(5, 4) NOT NULL
|
||||
, active BIT NOT NULL DEFAULT 1
|
||||
, created_on DATETIME
|
||||
, id_user_created_by INT
|
||||
, CONSTRAINT FK_DOG_Dog_Breed_Link_id_user_created_by
|
||||
FOREIGN KEY (id_user_created_by)
|
||||
REFERENCES parts.DOG_User(id_user)
|
||||
, id_change_set INT
|
||||
, CONSTRAINT FK_DOG_Dog_Breed_Link_id_change_set
|
||||
FOREIGN KEY (id_change_set)
|
||||
REFERENCES parts.DOG_Dog_Change_Set(id_change_set)
|
||||
);
|
||||
24
static/MySQL/1210_tbl_DOG_Dog_Breed_Link_Audit.sql
Normal file
24
static/MySQL/1210_tbl_DOG_Dog_Breed_Link_Audit.sql
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'DOG_Dog_Breed_Link_Audit'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.DOG_Dog_Breed_Link_Audit (
|
||||
id_audit INT NOT NULL AUTO_INCREMENT PRIMARY KEY
|
||||
, id_link INT NOT NULL
|
||||
, CONSTRAINT FK_DOG_Dog_Breed_Link_Audit_id_link
|
||||
FOREIGN KEY (id_link)
|
||||
REFERENCES parts.DOG_Dog_Breed_Link(id_link)
|
||||
, name_field VARCHAR(100) NOT NULL
|
||||
, value_prev TEXT
|
||||
, value_new TEXT
|
||||
, id_change_set INT NOT NULL
|
||||
, CONSTRAINT FK_DOG_Dog_Breed_Link_Audit_id_change_set
|
||||
FOREIGN KEY (id_change_set)
|
||||
REFERENCES parts.DOG_Dog_Change_Set(id_change_set)
|
||||
);
|
||||
19
static/MySQL/1211_tbl_DOG_Dog_Breed_Link_Temp.sql
Normal file
19
static/MySQL/1211_tbl_DOG_Dog_Breed_Link_Temp.sql
Normal file
@@ -0,0 +1,19 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'DOG_Dog_Breed_Link_Temp'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.DOG_Dog_Breed_Link_Temp (
|
||||
id_temp INT NOT NULL PRIMARY KEY AUTO_INCREMENT
|
||||
, id_link INT
|
||||
, id_dog INT
|
||||
, id_breed INT
|
||||
, lineage_ratio DECIMAL(5, 4)
|
||||
, active BIT
|
||||
, guid BINARY(36)
|
||||
);
|
||||
25
static/MySQL/1213_0_tbl_DOG_Understanding_Level.sql
Normal file
25
static/MySQL/1213_0_tbl_DOG_Understanding_Level.sql
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'DOG_Understanding_Level'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.DOG_Understanding_Level (
|
||||
id_understanding_level INT NOT NULL AUTO_INCREMENT PRIMARY KEY
|
||||
, code VARCHAR(100) NOT NULL
|
||||
, name VARCHAR(250) NOT NULL
|
||||
, active BIT NOT NULL DEFAULT 1
|
||||
, created_on DATETIME
|
||||
, id_user_created_by INT
|
||||
, CONSTRAINT FK_DOG_Understanding_Level_id_user_created_by
|
||||
FOREIGN KEY (id_user_created_by)
|
||||
REFERENCES parts.DOG_User(id_user)
|
||||
, id_change_set INT
|
||||
, CONSTRAINT FK_DOG_Understanding_Level_id_change_set
|
||||
FOREIGN KEY (id_change_set)
|
||||
REFERENCES parts.DOG_Dog_Change_Set(id_change_set)
|
||||
);
|
||||
24
static/MySQL/1213_1_tbl_DOG_Understanding_Level_Audit.sql
Normal file
24
static/MySQL/1213_1_tbl_DOG_Understanding_Level_Audit.sql
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'DOG_Understanding_Level_Audit'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.DOG_Understanding_Level_Audit (
|
||||
id_audit INT NOT NULL AUTO_INCREMENT PRIMARY KEY
|
||||
, id_understanding_level INT NOT NULL
|
||||
, CONSTRAINT FK_DOG_Understanding_Level_Audit_id_understanding_level
|
||||
FOREIGN KEY (id_understanding_level)
|
||||
REFERENCES parts.DOG_Understanding_Level(id_understanding_level)
|
||||
, name_field VARCHAR(100) NOT NULL
|
||||
, value_prev TEXT
|
||||
, value_new TEXT
|
||||
, id_change_set INT NOT NULL
|
||||
, CONSTRAINT FK_DOG_Understanding_Level_Audit_id_change_set
|
||||
FOREIGN KEY (id_change_set)
|
||||
REFERENCES parts.DOG_Dog_Change_Set(id_change_set)
|
||||
);
|
||||
18
static/MySQL/1213_2_tbl_DOG_Understanding_Level_Temp.sql
Normal file
18
static/MySQL/1213_2_tbl_DOG_Understanding_Level_Temp.sql
Normal file
@@ -0,0 +1,18 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'DOG_Understanding_Level_Temp'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.DOG_Understanding_Level_Temp (
|
||||
id_temp INT NOT NULL PRIMARY KEY AUTO_INCREMENT
|
||||
, id_understanding_level INT
|
||||
, code VARCHAR(100)
|
||||
, name VARCHAR(250)
|
||||
, active BIT
|
||||
, guid BINARY(36)
|
||||
);
|
||||
25
static/MySQL/1213_tbl_DOG_Obedience_Level.sql
Normal file
25
static/MySQL/1213_tbl_DOG_Obedience_Level.sql
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'DOG_Obedience_Level'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.DOG_Obedience_Level (
|
||||
id_obedience_level INT NOT NULL AUTO_INCREMENT PRIMARY KEY
|
||||
, code VARCHAR(100) NOT NULL
|
||||
, name VARCHAR(250) NOT NULL
|
||||
, active BIT NOT NULL DEFAULT 1
|
||||
, created_on DATETIME
|
||||
, id_user_created_by INT
|
||||
, CONSTRAINT FK_DOG_Obedience_Level_id_user_created_by
|
||||
FOREIGN KEY (id_user_created_by)
|
||||
REFERENCES parts.DOG_User(id_user)
|
||||
, id_change_set INT
|
||||
, CONSTRAINT FK_DOG_Obedience_Level_id_change_set
|
||||
FOREIGN KEY (id_change_set)
|
||||
REFERENCES parts.DOG_Dog_Change_Set(id_change_set)
|
||||
);
|
||||
24
static/MySQL/1214_tbl_DOG_Obedience_Level_Audit.sql
Normal file
24
static/MySQL/1214_tbl_DOG_Obedience_Level_Audit.sql
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'DOG_Obedience_Level_Audit'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.DOG_Obedience_Level_Audit (
|
||||
id_audit INT NOT NULL AUTO_INCREMENT PRIMARY KEY
|
||||
, id_obedience_level INT NOT NULL
|
||||
, CONSTRAINT FK_DOG_Obedience_Level_Audit_id_obedience_level
|
||||
FOREIGN KEY (id_obedience_level)
|
||||
REFERENCES parts.DOG_Obedience_Level(id_obedience_level)
|
||||
, name_field VARCHAR(100) NOT NULL
|
||||
, value_prev TEXT
|
||||
, value_new TEXT
|
||||
, id_change_set INT NOT NULL
|
||||
, CONSTRAINT FK_DOG_Obedience_Level_Audit_id_change_set
|
||||
FOREIGN KEY (id_change_set)
|
||||
REFERENCES parts.DOG_Dog_Change_Set(id_change_set)
|
||||
);
|
||||
18
static/MySQL/1215_tbl_DOG_Obedience_Level_Temp.sql
Normal file
18
static/MySQL/1215_tbl_DOG_Obedience_Level_Temp.sql
Normal file
@@ -0,0 +1,18 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'DOG_Obedience_Level_Temp'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.DOG_Obedience_Level_Temp (
|
||||
id_temp INT NOT NULL PRIMARY KEY AUTO_INCREMENT
|
||||
, id_obedience_level INT
|
||||
, code VARCHAR(100)
|
||||
, name VARCHAR(250)
|
||||
, active BIT
|
||||
, guid BINARY(36)
|
||||
);
|
||||
25
static/MySQL/1217_tbl_DOG_Command_Category.sql
Normal file
25
static/MySQL/1217_tbl_DOG_Command_Category.sql
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'DOG_Command_Category'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.DOG_Command_Category (
|
||||
id_command_category INT NOT NULL AUTO_INCREMENT PRIMARY KEY
|
||||
, code VARCHAR(100) NOT NULL
|
||||
, name VARCHAR(250) NOT NULL
|
||||
, active BIT NOT NULL DEFAULT 1
|
||||
, created_on DATETIME
|
||||
, id_user_created_by INT
|
||||
, CONSTRAINT FK_DOG_Command_Category_id_user_created_by
|
||||
FOREIGN KEY (id_user_created_by)
|
||||
REFERENCES parts.DOG_User(id_user)
|
||||
, id_change_set INT
|
||||
, CONSTRAINT FK_DOG_Command_Category_id_change_set
|
||||
FOREIGN KEY (id_change_set)
|
||||
REFERENCES parts.DOG_Dog_Change_Set(id_change_set)
|
||||
);
|
||||
24
static/MySQL/1218_tbl_DOG_Command_Category_Audit.sql
Normal file
24
static/MySQL/1218_tbl_DOG_Command_Category_Audit.sql
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'DOG_Command_Category_Audit'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.DOG_Command_Category_Audit (
|
||||
id_audit INT NOT NULL AUTO_INCREMENT PRIMARY KEY
|
||||
, id_command_category INT NOT NULL
|
||||
, CONSTRAINT FK_DOG_Command_Category_Audit_id_command_category
|
||||
FOREIGN KEY (id_command_category)
|
||||
REFERENCES parts.DOG_Command_Category(id_command_category)
|
||||
, name_field VARCHAR(100) NOT NULL
|
||||
, value_prev TEXT
|
||||
, value_new TEXT
|
||||
, id_change_set INT NOT NULL
|
||||
, CONSTRAINT FK_DOG_Command_Category_Audit_id_change_set
|
||||
FOREIGN KEY (id_change_set)
|
||||
REFERENCES parts.DOG_Dog_Change_Set(id_change_set)
|
||||
);
|
||||
18
static/MySQL/1219_tbl_DOG_Command_Category_Temp.sql
Normal file
18
static/MySQL/1219_tbl_DOG_Command_Category_Temp.sql
Normal file
@@ -0,0 +1,18 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'DOG_Command_Category_Temp'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.DOG_Command_Category_Temp (
|
||||
id_temp INT NOT NULL PRIMARY KEY AUTO_INCREMENT
|
||||
, id_command_category INT
|
||||
, code VARCHAR(100)
|
||||
, name VARCHAR(250)
|
||||
, active BIT
|
||||
, guid BINARY(36)
|
||||
);
|
||||
31
static/MySQL/1221_tbl_DOG_Command.sql
Normal file
31
static/MySQL/1221_tbl_DOG_Command.sql
Normal file
@@ -0,0 +1,31 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'DOG_Command'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.DOG_Command (
|
||||
id_command INT NOT NULL AUTO_INCREMENT PRIMARY KEY
|
||||
, id_command_category INT NOT NULL
|
||||
, CONSTRAINT FK_DOG_Command_id_command_category
|
||||
FOREIGN KEY (id_command_category)
|
||||
REFERENCES parts.DOG_Command_Category(id_command_category)
|
||||
, name VARCHAR(250) NOT NULL
|
||||
, hand_signal_default_description TEXT
|
||||
, can_have_button BIT NOT NULL DEFAULT 0
|
||||
, notes TEXT
|
||||
, active BIT NOT NULL DEFAULT 1
|
||||
, created_on DATETIME
|
||||
, id_user_created_by INT
|
||||
, CONSTRAINT FK_DOG_Command_id_user_created_by
|
||||
FOREIGN KEY (id_user_created_by)
|
||||
REFERENCES parts.DOG_User(id_user)
|
||||
, id_change_set INT
|
||||
, CONSTRAINT FK_DOG_Command_id_change_set
|
||||
FOREIGN KEY (id_change_set)
|
||||
REFERENCES parts.DOG_Dog_Change_Set(id_change_set)
|
||||
);
|
||||
24
static/MySQL/1222_tbl_DOG_Command_Audit.sql
Normal file
24
static/MySQL/1222_tbl_DOG_Command_Audit.sql
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'DOG_Command_Audit'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.DOG_Command_Audit (
|
||||
id_audit INT NOT NULL AUTO_INCREMENT PRIMARY KEY
|
||||
, id_command INT NOT NULL
|
||||
, CONSTRAINT FK_DOG_Command_Audit_id_command
|
||||
FOREIGN KEY (id_command)
|
||||
REFERENCES parts.DOG_Command(id_command)
|
||||
, name_field VARCHAR(100) NOT NULL
|
||||
, value_prev TEXT
|
||||
, value_new TEXT
|
||||
, id_change_set INT NOT NULL
|
||||
, CONSTRAINT FK_DOG_Command_Audit_id_change_set
|
||||
FOREIGN KEY (id_change_set)
|
||||
REFERENCES parts.DOG_Dog_Change_Set(id_change_set)
|
||||
);
|
||||
23
static/MySQL/1223_tbl_DOG_Command_Temp.sql
Normal file
23
static/MySQL/1223_tbl_DOG_Command_Temp.sql
Normal file
@@ -0,0 +1,23 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'DOG_Command_Temp'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.DOG_Command_Temp (
|
||||
id_temp INT NOT NULL PRIMARY KEY AUTO_INCREMENT
|
||||
, id_command INT
|
||||
, id_command_category INT
|
||||
, name VARCHAR(250)
|
||||
, hand_signal_default_description TEXT
|
||||
, can_have_button BIT
|
||||
, notes TEXT
|
||||
, active BIT
|
||||
, guid BINARY(36)
|
||||
|
||||
, name_command_category VARCHAR(250)
|
||||
);
|
||||
42
static/MySQL/1225_tbl_DOG_Dog_Command_Link.sql
Normal file
42
static/MySQL/1225_tbl_DOG_Dog_Command_Link.sql
Normal file
@@ -0,0 +1,42 @@
|
||||
|
||||
USE parts;
|
||||
|
||||
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE
|
||||
TABLE_SCHEMA = 'parts'
|
||||
AND TABLE_NAME = 'DOG_Dog_Command_Link'
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parts.DOG_Dog_Command_Link (
|
||||
id_link INT NOT NULL AUTO_INCREMENT PRIMARY KEY
|
||||
, id_dog INT NOT NULL
|
||||
, CONSTRAINT FK_DOG_Dog_Command_Link_id_dog
|
||||
FOREIGN KEY (id_dog)
|
||||
REFERENCES parts.DOG_Dog(id_dog)
|
||||
, id_command INT NOT NULL
|
||||
, CONSTRAINT FK_DOG_Dog_Command_Link_id_command
|
||||
FOREIGN KEY (id_command)
|
||||
REFERENCES parts.DOG_Command(id_command)
|
||||
, id_understanding_level INT NOT NULL
|
||||
, CONSTRAINT FK_DOG_Dog_Command_Link_id_understanding_level
|
||||
FOREIGN KEY (id_understanding_level)
|
||||
REFERENCES parts.DOG_Understanding_Level(id_understanding_level)
|
||||
, id_obedience_level INT NOT NULL
|
||||
, CONSTRAINT FK_DOG_Dog_Command_Link_id_obedience_level
|
||||
FOREIGN KEY (id_obedience_level)
|
||||
REFERENCES parts.DOG_Obedience_Level(id_obedience_level)
|
||||
, hand_signal_description TEXT
|
||||
, notes TEXT
|
||||
-- , has_button BIT NOT NULL DEFAULT 0
|
||||
, active BIT NOT NULL DEFAULT 1
|
||||
, created_on DATETIME
|
||||
, id_user_created_by INT
|
||||
, CONSTRAINT FK_DOG_Dog_Command_Link_id_user_created_by
|
||||
FOREIGN KEY (id_user_created_by)
|
||||
REFERENCES parts.DOG_User(id_user)
|
||||
, id_change_set INT
|
||||
, CONSTRAINT FK_DOG_Dog_Command_Link_id_change_set
|
||||
FOREIGN KEY (id_change_set)
|
||||
REFERENCES parts.DOG_Dog_Change_Set(id_change_set)
|
||||
);
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user