User setup added
This commit is contained in:
239
create_master_user.py
Normal file
239
create_master_user.py
Normal 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()
|
||||
Reference in New Issue
Block a user