From 4ffc68d5f25b7d2648aa058e1029f090fdca9907 Mon Sep 17 00:00:00 2001
From: candifloss <candifloss@candifloss.cc>
Date: Thu, 3 Apr 2025 11:33:57 +0530
Subject: [PATCH] Add: Branding config

- App name
- Tagline
- Large Logo (for Login page)
- Small Logo (for header)
---
 config.sample.py             |  10 +++++++++-
 routes/create.py             |  11 ++++++-----
 routes/delete.py             |   4 +++-
 routes/homepage.py           |   3 ++-
 routes/update.py             |  11 ++++++-----
 routes/upload.py             |   7 +++++--
 routes/viewall.py            |   4 +++-
 static/images/logo_large.png | Bin 0 -> 4863 bytes
 static/images/logo_small.png | Bin 0 -> 8975 bytes
 templates/header.html        |   7 ++++++-
 templates/login.html         |  10 ++++++----
 11 files changed, 46 insertions(+), 21 deletions(-)
 create mode 100644 static/images/logo_large.png
 create mode 100644 static/images/logo_small.png

diff --git a/config.sample.py b/config.sample.py
index fcbcf6f..b13cf30 100644
--- a/config.sample.py
+++ b/config.sample.py
@@ -1,6 +1,14 @@
 from definitions.attributes import *
 
-
+# Branding Configuration
+class BrandingConfig:
+    APP_NAME = "Inventory Manager"
+    TAGLINE = "Inventory management system"
+    
+    # Logo paths (relative to static folder)
+    LOGIN_LOGO = "images/logo_large.png"  # ~400x200px recommended
+    HEADER_LOGO = "images/logo_small.png"  # ~100x50px recommended
+    
 # MySQL information
 class sql_conf:
     SQL_USER = "assetadmin"
diff --git a/routes/create.py b/routes/create.py
index e939956..21fab5f 100644
--- a/routes/create.py
+++ b/routes/create.py
@@ -4,6 +4,7 @@ from config import item_attributes
 from sqlalchemy import exc  # Import exc for database exceptions
 from functions.validate_values import validate_values  # Form validation
 from functions.auth import login_required
+from config import BrandingConfig
 
 addasset_bp = Blueprint('addasset', __name__)
 
@@ -12,7 +13,7 @@ addasset_bp = Blueprint('addasset', __name__)
 def create():
     if request.method == 'GET':
         # Render the "add item" form
-        return render_template('item_form.html', item_attributes=item_attributes, item=None)
+        return render_template('item_form.html', item_attributes=item_attributes, item=None, brandingconfig=BrandingConfig)
 
     # Process submitted form
     if request.method == 'POST':
@@ -22,7 +23,7 @@ def create():
         # Form validation
         error = validate_values(form_data)
         if error:
-            return render_template('item_form.html', item_attributes=item_attributes, item=None, error=error)
+            return render_template('item_form.html', item_attributes=item_attributes, item=None, error=error, brandingconfig=BrandingConfig)
 
         # Create the Asset object
         item = Asset(**form_data)
@@ -37,15 +38,15 @@ def create():
                 error = f"An entry with {primary_attrib.display_name} '{form_data[primary_attrib.attrib_name]}' already exists."
             else:
                 error = "An entry with the same primary key already exists."
-            return render_template('item_form.html', item_attributes=item_attributes, item=None, error=error)
+            return render_template('item_form.html', item_attributes=item_attributes, item=None, error=error, brandingconfig=BrandingConfig)
         except exc.StatementError as e:
             # Handle other database errors
             error = f"Database error: {str(e)}"
-            return render_template('item_form.html', item_attributes=item_attributes, item=None, error=error)
+            return render_template('item_form.html', item_attributes=item_attributes, item=None, error=error, brandingconfig=BrandingConfig)
         except Exception as e:
             # Handle unexpected errors
             error = f"An unexpected error occurred: {str(e)}"
-            return render_template('item_form.html', item_attributes=item_attributes, item=None, error=error)
+            return render_template('item_form.html', item_attributes=item_attributes, item=None, error=error, brandingconfig=BrandingConfig)
 
         # Redirect to /viewall on success
         return redirect('/viewall')
\ No newline at end of file
diff --git a/routes/delete.py b/routes/delete.py
index 374d022..fc8404d 100644
--- a/routes/delete.py
+++ b/routes/delete.py
@@ -2,6 +2,7 @@ from flask import Blueprint, request, render_template, redirect, flash
 from definitions.models import Asset, db
 from config import item_attributes
 from functions.auth import login_required
+from config import BrandingConfig
 
 delete_bp = Blueprint('deleteasset', __name__)
 
@@ -34,5 +35,6 @@ def delete(primary_value):
     return render_template(
         'delete.html',
         item=item,
-        item_attributes=item_attributes
+        item_attributes=item_attributes,
+        brandingconfig=BrandingConfig
     )
\ No newline at end of file
diff --git a/routes/homepage.py b/routes/homepage.py
index fb89d01..d258f9a 100644
--- a/routes/homepage.py
+++ b/routes/homepage.py
@@ -1,5 +1,6 @@
 from flask import Blueprint, render_template, redirect, url_for, session, request, flash
 from definitions.models import db, User
+from config import BrandingConfig
 
 homepage_bp = Blueprint('homepage', __name__)
 
@@ -31,7 +32,7 @@ def login():
         else:
             flash('Invalid username or password', 'error')
 
-    return render_template('login.html')
+    return render_template('login.html', brandingconfig=BrandingConfig)
 
 @homepage_bp.route('/logout/')
 def logout():
diff --git a/routes/update.py b/routes/update.py
index b41b3e6..bd04e59 100644
--- a/routes/update.py
+++ b/routes/update.py
@@ -4,6 +4,7 @@ from config import item_attributes
 from sqlalchemy import exc  # Import exc for database exceptions
 from functions.validate_values import validate_values  # Form validation
 from functions.auth import login_required
+from config import BrandingConfig
 
 update_bp = Blueprint('editasset', __name__)
 
@@ -22,7 +23,7 @@ def update(primary_value):
 
     if request.method == 'GET':
         # Render the update form with the current item data
-        return render_template('item_form.html', item=item, item_attributes=item_attributes)
+        return render_template('item_form.html', item=item, item_attributes=item_attributes, brandingconfig=BrandingConfig)
 
     if request.method == 'POST':
         # Get data from form
@@ -31,7 +32,7 @@ def update(primary_value):
         # Form validation
         error = validate_values(form_data)
         if error:
-            return render_template('item_form.html', item=item, item_attributes=item_attributes, error=error)
+            return render_template('item_form.html', item=item, item_attributes=item_attributes, error=error, brandingconfig=BrandingConfig)
 
         # Update the item with the new data
         for attrib in item_attributes:
@@ -42,15 +43,15 @@ def update(primary_value):
         except exc.IntegrityError:
             # Handle duplicate primary key or unique constraint errors
             error = f"An entry with {primary_attrib.display_name} '{form_data[primary_attrib.attrib_name]}' already exists."
-            return render_template('item_form.html', item=item, item_attributes=item_attributes, error=error)
+            return render_template('item_form.html', item=item, item_attributes=item_attributes, error=error, brandingconfig=BrandingConfig)
         except exc.StatementError as e:
             # Handle other database errors
             error = f"Database error: {str(e)}"
-            return render_template('item_form.html', item=item, item_attributes=item_attributes, error=error)
+            return render_template('item_form.html', item=item, item_attributes=item_attributes, error=error, brandingconfig=BrandingConfig)
         except Exception as e:
             # Handle unexpected errors
             error = f"An unexpected error occurred: {str(e)}"
-            return render_template('item_form.html', item=item, item_attributes=item_attributes, error=error)
+            return render_template('item_form.html', item=item, item_attributes=item_attributes, error=error, brandingconfig=BrandingConfig)
 
         # Redirect to /viewall on success
         return redirect('/viewall')
\ No newline at end of file
diff --git a/routes/upload.py b/routes/upload.py
index a60929f..dd9416f 100644
--- a/routes/upload.py
+++ b/routes/upload.py
@@ -4,6 +4,7 @@ from functions.process_csv import get_csv_data
 from functions.validate_values import validate_values
 from config import item_attributes
 from functions.auth import login_required
+from config import BrandingConfig
 
 upload_bp = Blueprint('uploadcsv', __name__)
 
@@ -89,7 +90,8 @@ def import_from_csv():
             mode='import',
             new_entries=result['new_entries'],
             invalid_entries=result['invalid_entries'],
-            item_attributes=item_attributes
+            item_attributes=item_attributes,
+            brandingconfig=BrandingConfig
         )
 
     # Render the upload page for GET requests
@@ -129,7 +131,8 @@ def edit_using_csv():
             mode='edit',
             existing_entries=result['existing_entries'],
             invalid_entries=result['invalid_entries'],
-            item_attributes=item_attributes
+            item_attributes=item_attributes,
+            brandingconfig=BrandingConfig
         )
 
     # Render the upload page for GET requests
diff --git a/routes/viewall.py b/routes/viewall.py
index 9f97a39..5477110 100644
--- a/routes/viewall.py
+++ b/routes/viewall.py
@@ -2,6 +2,7 @@ from flask import Blueprint, render_template
 from definitions.models import Asset
 from config import item_attributes
 from functions.auth import login_required
+from config import BrandingConfig
 
 viewall_bp = Blueprint('viewall', __name__)
 
@@ -21,5 +22,6 @@ def view_list():
         'viewList.html',
         items=items,
         item_attributes=item_attributes,
-        primary_attrib=primary_attrib.attrib_name
+        primary_attrib=primary_attrib.attrib_name,
+        brandingconfig=BrandingConfig
     )
\ No newline at end of file
diff --git a/static/images/logo_large.png b/static/images/logo_large.png
new file mode 100644
index 0000000000000000000000000000000000000000..a513dda08d1e3ec732012db657b89b6a29c48bd2
GIT binary patch
literal 4863
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

literal 0
HcmV?d00001

diff --git a/static/images/logo_small.png b/static/images/logo_small.png
new file mode 100644
index 0000000000000000000000000000000000000000..d8dd1376b2ae55e9efc5019803eee92c7b4978a2
GIT binary patch
literal 8975
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

literal 0
HcmV?d00001

diff --git a/templates/header.html b/templates/header.html
index 29f2c22..f9e006a 100644
--- a/templates/header.html
+++ b/templates/header.html
@@ -1,6 +1,11 @@
 <!-- Header bar -->
 <div class="header">
-    <h1 class="appname">Inventory Manager</h1>
+    <div class="branding">
+        <img src="{{ url_for('static', filename=brandingconfig.HEADER_LOGO) }}" 
+             alt="{{ brandingconfig.APP_NAME }} Logo"
+             class="header-logo">
+        <h1 class="appname">{{ brandingconfig.APP_NAME }}</h1>
+    </div>
     <div class="buttons">
         <form action="/create" method="get">
             <button type="submit">Add New Item</button>
diff --git a/templates/login.html b/templates/login.html
index 2af868c..f3c0369 100644
--- a/templates/login.html
+++ b/templates/login.html
@@ -3,14 +3,16 @@
 	<head>
 		<meta charset="UTF-8">
 		<meta name="viewport" content="width=device-width, initial-scale=1.0">
-		<title>Login Page</title>
+		<title>{{ brandingconfig.APP_NAME }} - Login</title>
 	</head>
 	<body>
 
 		<div class="left-container">
-			<img src="../images/logo2.png" alt="Company Logo" class="logo">
-			<h1>Inventory Manager</h1>
-			<p>Inventory management system</p>
+			<img src="{{ url_for('static', filename=brandingconfig.LOGIN_LOGO) }}" 
+             alt="{{ brandingconfig.APP_NAME }} Logo" 
+             class="logo">
+			<h1>{{ brandingconfig.APP_NAME }}</h1>
+			<p>{{ brandingconfig.TAGLINE }}</p>
 		</div>
 
 		{% with messages = get_flashed_messages(with_categories=true) %}