User setup added

This commit is contained in:
Sidharth Prabhu
2026-08-03 10:41:57 +05:30
parent 28a13d619c
commit 6b3714f2bc
8 changed files with 692 additions and 54 deletions

239
create_master_user.py Normal file
View File

@@ -0,0 +1,239 @@
#!/usr/bin/env python3
"""
Master User Creation Script for Positeasy Canteen Automation System.
This script creates or updates a master administrator user in the database
with username 'admin' and password 'admin', and synchronizes the application configuration.
"""
import sys
import os
import re
import argparse
import bcrypt
import psycopg2
# Default Configuration
DEFAULT_USERNAME = "admin"
DEFAULT_PASSWORD = "admin"
DEFAULT_NAME = "Admin Master"
DEFAULT_ROLE = "MASTER"
DEFAULT_DB_HOST = "localhost"
DEFAULT_DB_PORT = 5432
DEFAULT_DB_NAME = "positeasy"
DEFAULT_DB_USER = "postgres"
DEFAULT_DB_PASS = "sidharth"
ALL_PERMISSIONS = [
"dashboard",
"sale",
"customers",
"purchases",
"inventory",
"expense",
"reports",
"stores",
"table",
"wallet",
"promotions",
"feedback"
]
def hash_password(password: str) -> str:
"""Hash password using bcrypt compatible with Spring Security BCryptPasswordEncoder."""
salt = bcrypt.gensalt(rounds=10)
hashed = bcrypt.hashpw(password.encode('utf-8'), salt)
return hashed.decode('utf-8')
def parse_application_properties(prop_path: str) -> dict:
"""Parse db credentials from backend application.properties if available."""
config = {}
if not os.path.exists(prop_path):
return config
with open(prop_path, 'r', encoding='utf-8') as f:
for line in f:
line = line.strip()
if line and not line.startswith('#') and '=' in line:
key, value = line.split('=', 1)
config[key.strip()] = value.strip()
return config
def update_application_properties(prop_path: str, username: str, password: str) -> bool:
"""Update app.master.username and app.master.password in application.properties."""
if not os.path.exists(prop_path):
print(f"⚠️ [Config] File not found: {prop_path}")
return False
with open(prop_path, 'r', encoding='utf-8') as f:
content = f.read()
# Update or add app.master.username and app.master.password
new_user_line = f"app.master.username=${{MASTER_USER:{username}}}"
new_pass_line = f"app.master.password=${{MASTER_PASSWORD:{password}}}"
if re.search(r'^app\.master\.username=.*$', content, flags=re.MULTILINE):
content = re.sub(r'^app\.master\.username=.*$', new_user_line, content, flags=re.MULTILINE)
else:
content += f"\n{new_user_line}"
if re.search(r'^app\.master\.password=.*$', content, flags=re.MULTILINE):
content = re.sub(r'^app\.master\.password=.*$', new_pass_line, content, flags=re.MULTILINE)
else:
content += f"\n{new_pass_line}"
with open(prop_path, 'w', encoding='utf-8') as f:
f.write(content)
print(f"✅ [Config] Updated {prop_path} with default master credentials ({username}/{password}).")
return True
def update_frontend_demo_credentials(app_tsx_path: str, username: str, password: str) -> bool:
"""Update UI demo credentials displayed in api-dashboard if file exists."""
if not os.path.exists(app_tsx_path):
return False
with open(app_tsx_path, 'r', encoding='utf-8') as f:
content = f.read()
old_pattern = r'Default Admin:\s*<strong>[^<]*</strong>\s*/\s*Password:\s*<strong>[^<]*</strong>'
new_text = f'Default Admin: <strong>{username}</strong> / Password: <strong>{password}</strong>'
if re.search(old_pattern, content):
content = re.sub(old_pattern, new_text, content)
with open(app_tsx_path, 'w', encoding='utf-8') as f:
f.write(content)
print(f"✅ [UI] Updated demo credentials in {app_tsx_path}.")
return True
return False
def create_or_update_master_user(db_params: dict, username: str, password: str, name: str) -> bool:
"""Insert or update master user in PostgreSQL database."""
print(f"\n🔌 Connecting to PostgreSQL database '{db_params['dbname']}' on {db_params['host']}:{db_params['port']}...")
try:
conn = psycopg2.connect(**db_params)
conn.autocommit = False
cur = conn.cursor()
# Check if system_users table exists
cur.execute("""
SELECT EXISTS (
SELECT FROM information_schema.tables
WHERE table_name = 'system_users'
);
""")
table_exists = cur.fetchone()[0]
if not table_exists:
print("❌ Table 'system_users' does not exist in the database. Has backend schema initialized?")
conn.close()
return False
# Check if master user with this username (stored in email column) exists
cur.execute("SELECT id, name, role FROM system_users WHERE email = %s;", (username,))
row = cur.fetchone()
hashed_pass = hash_password(password)
if row:
user_id = row[0]
print(f"🔄 Existing master user found (ID: {user_id}). Updating credentials...")
cur.execute("""
UPDATE system_users
SET name = %s, password = %s, role = %s, view_only = false
WHERE id = %s;
""", (name, hashed_pass, DEFAULT_ROLE, user_id))
else:
print(f" Creating new master user '{username}'...")
cur.execute("""
INSERT INTO system_users (name, email, password, role, view_only)
VALUES (%s, %s, %s, %s, false)
RETURNING id;
""", (name, username, hashed_pass, DEFAULT_ROLE))
user_id = cur.fetchone()[0]
# Reset permissions for this user
cur.execute("DELETE FROM system_user_permissions WHERE user_id = %s;", (user_id,))
for perm in ALL_PERMISSIONS:
cur.execute("""
INSERT INTO system_user_permissions (user_id, permission)
VALUES (%s, %s);
""", (user_id, perm))
conn.commit()
# Verification query
cur.execute("""
SELECT u.id, u.name, u.email, u.role, count(p.permission)
FROM system_users u
LEFT JOIN system_user_permissions p ON u.id = p.user_id
WHERE u.id = %s
GROUP BY u.id, u.name, u.email, u.role;
""", (user_id,))
ver = cur.fetchone()
cur.close()
conn.close()
print("\n" + "=" * 50)
print("🎉 MASTER USER CREATED / UPDATED SUCCESSFULLY")
print("=" * 50)
print(f" User ID: {ver[0]}")
print(f" Name: {ver[1]}")
print(f" Username: {ver[2]}")
print(f" Password: {password}")
print(f" Role: {ver[3]}")
print(f" Permissions: {ver[4]} granted ({', '.join(ALL_PERMISSIONS[:4])}...)")
print("=" * 50 + "\n")
return True
except Exception as e:
print(f"❌ Database error: {e}")
return False
def main():
parser = argparse.ArgumentParser(description="Create or update master user for Positeasy Canteen Automation.")
parser.add_argument("-u", "--username", default=DEFAULT_USERNAME, help="Master username (default: admin)")
parser.add_argument("-p", "--password", default=DEFAULT_PASSWORD, help="Master password (default: admin)")
parser.add_argument("-n", "--name", default=DEFAULT_NAME, help="Display name for master user")
parser.add_argument("--host", default=DEFAULT_DB_HOST, help="PostgreSQL host (default: localhost)")
parser.add_argument("--port", type=int, default=DEFAULT_DB_PORT, help="PostgreSQL port (default: 5432)")
parser.add_argument("--dbname", default=DEFAULT_DB_NAME, help="PostgreSQL database name (default: positeasy)")
parser.add_argument("--dbuser", default=DEFAULT_DB_USER, help="PostgreSQL database user (default: postgres)")
parser.add_argument("--dbpass", default=DEFAULT_DB_PASS, help="PostgreSQL database password")
args = parser.parse_args()
project_root = os.path.dirname(os.path.abspath(__file__))
prop_path = os.path.join(project_root, "backend", "src", "main", "resources", "application.properties")
app_tsx_path = os.path.join(project_root, "api-dashboard", "src", "App.tsx")
db_params = {
"host": args.host,
"port": args.port,
"dbname": args.dbname,
"user": args.dbuser,
"password": args.dbpass
}
print("🚀 Starting Master User setup script...")
# 1. Database creation / update
db_success = create_or_update_master_user(db_params, args.username, args.password, args.name)
# 2. Sync application.properties
update_application_properties(prop_path, args.username, args.password)
# 3. Sync frontend dashboard UI
update_frontend_demo_credentials(app_tsx_path, args.username, args.password)
if db_success:
print("✨ All steps completed successfully! You can now log in with:")
print(f" Username: {args.username}")
print(f" Password: {args.password}")
else:
print("⚠️ Database operation failed or incomplete. Check database connectivity.")
if __name__ == "__main__":
main()