diff --git a/.gitignore b/.gitignore index cafd598..099fcce 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ __pycache__/ -.venv/ \ No newline at end of file +.venv/ +.env \ No newline at end of file diff --git a/__init__.py b/__init__.py index 199ca67..6494705 100644 --- a/__init__.py +++ b/__init__.py @@ -1,37 +1,28 @@ from flask import Flask from flask_sqlalchemy import SQLAlchemy -from urllib.parse import quote_plus import logging db = SQLAlchemy() logger = logging.getLogger('sqlalchemy.engine') logger.setLevel(logging.INFO) -handler = logging.StreamHandler() -handler.setFormatter(logging.Formatter('%(asctime)s [%(levelname)s] %(message)s')) -logger.addHandler(handler) +if not logger.handlers: + handler = logging.StreamHandler() + handler.setFormatter(logging.Formatter('%(asctime)s [%(levelname)s] %(message)s')) + logger.addHandler(handler) def create_app(): + from config import Config app = Flask(__name__) - - params = quote_plus( - "DRIVER=ODBC Driver 17 for SQL Server;" - "SERVER=NDVASQLCR01;" - "DATABASE=conradTest;" - "Trusted_Connection=yes;" - ) - - app.config['SQLALCHEMY_DATABASE_URI'] = f"mssql+pyodbc:///?odbc_connect={params}" - app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False + app.config.from_object(Config) db.init_app(app) + with app.app_context(): + from . import models + db.create_all() + from .routes import main app.register_blueprint(main) - @app.route("/") - def index(): - return "Hello, you've reached the terrible but functional root of the site." - - return app diff --git a/config.py b/config.py new file mode 100644 index 0000000..012c37e --- /dev/null +++ b/config.py @@ -0,0 +1,60 @@ +import os +import urllib.parse +from dotenv import load_dotenv + +load_dotenv() + +def quote(value): + return urllib.parse.quote_plus(value) + +class Config: + SQLALCHEMY_TRACK_MODIFICATIONS = False + DEBUG = False + TESTING = False + + DB_BACKEND = os.getenv('DB_BACKEND', 'sqlite').lower() + DB_WINDOWS_AUTH = os.getenv('DB_WINDOWS_AUTH', 'false').strip().lower() in ['true', '1', 'yes'] + + DB_USER = os.getenv('DB_USER', '') + DB_PASSWORD = os.getenv('DB_PASSWORD', '') + DB_HOST = os.getenv('DB_HOST', 'localhost') + DB_PORT = os.getenv('DB_PORT', '') + DB_NAME = os.getenv('DB_NAME', 'app.db') # default file for sqlite + + SQLALCHEMY_DATABASE_URI = None # <-- initialize properly + + if DB_BACKEND == 'mssql': + driver = os.getenv('DB_DRIVER', 'ODBC Driver 17 for SQL Server') + quoted_driver = quote(driver) + + if DB_WINDOWS_AUTH: + SQLALCHEMY_DATABASE_URI = ( + f"mssql+pyodbc://@{DB_HOST}/{DB_NAME}?driver={quoted_driver}&Trusted_Connection=yes" + ) + else: + SQLALCHEMY_DATABASE_URI = ( + f"mssql+pyodbc://{quote(DB_USER)}:{quote(DB_PASSWORD)}@{DB_HOST}:{DB_PORT}/{DB_NAME}" + f"?driver={quoted_driver}" + ) + + elif DB_BACKEND == 'postgres': + SQLALCHEMY_DATABASE_URI = ( + f"postgresql://{quote(DB_USER)}:{quote(DB_PASSWORD)}@{DB_HOST}:{DB_PORT or '5432'}/{DB_NAME}" + ) + + elif DB_BACKEND in ['mariadb', 'mysql']: + SQLALCHEMY_DATABASE_URI = ( + f"mysql+pymysql://{quote(DB_USER)}:{quote(DB_PASSWORD)}@{DB_HOST}:{DB_PORT or '3306'}/{DB_NAME}" + ) + + elif DB_BACKEND == 'sqlite': + if DB_NAME == ':memory:': + SQLALCHEMY_DATABASE_URI = 'sqlite:///:memory:' + else: + SQLALCHEMY_DATABASE_URI = f"sqlite:///{DB_NAME}" + + else: + raise ValueError( + f"Unsupported DB_BACKEND: {DB_BACKEND}. " + "Supported backends: mssql, postgres, mariadb, mysql, sqlite." + ) diff --git a/models/__pycache__/work_log.cpython-313.pyc b/models/__pycache__/work_log.cpython-313.pyc index 11854dc..85fa3ee 100644 Binary files a/models/__pycache__/work_log.cpython-313.pyc and b/models/__pycache__/work_log.cpython-313.pyc differ diff --git a/models/work_log.py b/models/work_log.py index fbea696..bec28c6 100644 --- a/models/work_log.py +++ b/models/work_log.py @@ -3,8 +3,7 @@ if TYPE_CHECKING: from .inventory import Inventory from .inventory import User -from sqlalchemy import Boolean, ForeignKeyConstraint, Identity, Integer, ForeignKey, Unicode, text -from sqlalchemy.dialects.mssql import DATETIME2 +from sqlalchemy import Boolean, ForeignKeyConstraint, Identity, Integer, ForeignKey, Unicode, DateTime, text from sqlalchemy.orm import Mapped, mapped_column, relationship import datetime @@ -17,8 +16,8 @@ class WorkLog(db.Model): ) id: Mapped[int] = mapped_column("ID", Integer, Identity(start=1, increment=1), primary_key=True) - start_time: Mapped[Optional[datetime.datetime]] = mapped_column('Start Timestamp', DATETIME2) - end_time: Mapped[Optional[datetime.datetime]] = mapped_column('End Timestamp', DATETIME2) + start_time: Mapped[Optional[datetime.datetime]] = mapped_column('Start Timestamp', DateTime) + end_time: Mapped[Optional[datetime.datetime]] = mapped_column('End Timestamp', DateTime) notes: Mapped[Optional[str]] = mapped_column('Description & Notes', Unicode()) complete: Mapped[Optional[bool]] = mapped_column("Complete", Boolean, server_default=text('((0))')) followup: Mapped[Optional[bool]] = mapped_column('Needs Follow-Up', Boolean, server_default=text('((0))')) diff --git a/requirements.txt b/requirements.txt index d12b286..b7cb7bb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ +dotenv flask flask_sqlalchemy -pyodbc pandas +pyodbc \ No newline at end of file diff --git a/routes.py b/routes.py index 6bc10ee..ed51a34 100644 --- a/routes.py +++ b/routes.py @@ -165,7 +165,12 @@ def index(): 'Deployed','Inoperable', 'Partially Inoperable', 'Unverified', 'Working' ] - pivot = df['condition'].value_counts().reindex(expected_conditions, fill_value=0) + print(df) + if 'condition' in df.columns: + pivot = df['condition'].value_counts().reindex(expected_conditions, fill_value=0) + else: + pivot = pd.Series([0] * len(expected_conditions), index=expected_conditions) + # Convert pandas/numpy int64s to plain old Python ints pivot = pivot.astype(int) @@ -376,7 +381,7 @@ def search(): query = request.args.get('q', '').strip() if not query: - return redirect(url_for('index')) + return redirect(url_for('main.index')) InventoryAlias = aliased(Inventory) UserAlias = aliased(User) diff --git a/templates/fragments/_breadcrumb_fragment.html b/templates/fragments/_breadcrumb_fragment.html index aed2779..dbb9922 100644 --- a/templates/fragments/_breadcrumb_fragment.html +++ b/templates/fragments/_breadcrumb_fragment.html @@ -5,7 +5,7 @@
{% endif %} + {% if (datasets[0]['values'] | sum) > 0 %}
@@ -33,6 +34,7 @@
+ {% endif %} {% endblock %} diff --git a/templates/layout.html b/templates/layout.html index 5eec65d..c6758f7 100644 --- a/templates/layout.html +++ b/templates/layout.html @@ -30,7 +30,7 @@