feat: Implement auth user management API and UI for admin users
This commit introduces a new Auth User management feature, allowing admins to create, update, delete, and list users in the auth database. A dedicated API has been implemented with endpoints for managing auth users, including validation for unique email addresses. The frontend has been updated to include a Manage Users page with tabs for backend and frontend users, enhancing the user experience. Additionally, modals for creating and editing auth users have been added, along with appropriate error handling and loading states. Documentation has been updated to reflect these changes.
This commit is contained in:
Executable
+64
@@ -0,0 +1,64 @@
|
||||
#!/bin/bash
|
||||
# Grant DELETE permission on auth database users table
|
||||
|
||||
set -e
|
||||
|
||||
echo "🔧 Granting DELETE permission on auth database users table..."
|
||||
|
||||
# Check if .env file exists
|
||||
ENV_FILE=".env"
|
||||
if [ ! -f "$ENV_FILE" ]; then
|
||||
echo "❌ Error: .env file not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Extract DATABASE_URL_AUTH from .env file
|
||||
AUTH_DB_URL=$(grep "^DATABASE_URL_AUTH=" "$ENV_FILE" | cut -d '=' -f2- | tr -d '"' | tr -d "'")
|
||||
|
||||
if [ -z "$AUTH_DB_URL" ]; then
|
||||
echo "❌ Error: DATABASE_URL_AUTH not found in .env file"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Parse the database URL
|
||||
# Format: postgresql+psycopg2://user:password@host:port/database
|
||||
# or: postgresql://user:password@host:port/database
|
||||
|
||||
# Remove postgresql+psycopg2:// prefix if present
|
||||
AUTH_DB_URL=${AUTH_DB_URL#postgresql+psycopg2://}
|
||||
AUTH_DB_URL=${AUTH_DB_URL#postgresql://}
|
||||
|
||||
# Extract components
|
||||
# Split by @ to get user:pass and host:port/db
|
||||
IFS='@' read -r CREDENTIALS REST <<< "$AUTH_DB_URL"
|
||||
IFS=':' read -r DB_USER DB_PASS <<< "$CREDENTIALS"
|
||||
|
||||
# Extract host, port, and database
|
||||
IFS='/' read -r HOST_PORT DB_NAME <<< "$REST"
|
||||
IFS=':' read -r DB_HOST DB_PORT <<< "$HOST_PORT"
|
||||
|
||||
# Set defaults
|
||||
DB_PORT=${DB_PORT:-5432}
|
||||
DB_HOST=${DB_HOST:-localhost}
|
||||
|
||||
echo "📋 Database information:"
|
||||
echo " Host: $DB_HOST"
|
||||
echo " Port: $DB_PORT"
|
||||
echo " Database: $DB_NAME"
|
||||
echo " User: $DB_USER"
|
||||
echo ""
|
||||
|
||||
# Grant DELETE permission using psql as postgres superuser
|
||||
echo "🔐 Granting DELETE permission (requires sudo)..."
|
||||
sudo -u postgres psql -d "$DB_NAME" << EOF
|
||||
GRANT DELETE ON TABLE users TO "$DB_USER";
|
||||
\q
|
||||
EOF
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "✅ Successfully granted DELETE permission to user '$DB_USER'"
|
||||
else
|
||||
echo "❌ Failed to grant permission"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
Executable
+99
@@ -0,0 +1,99 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Grant DELETE permission on auth database users table.
|
||||
|
||||
This script grants DELETE permission to the database user specified in DATABASE_URL_AUTH.
|
||||
It requires superuser access (postgres user) to grant permissions.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from dotenv import load_dotenv
|
||||
from sqlalchemy import create_engine, text
|
||||
|
||||
# Load environment variables
|
||||
env_path = Path(__file__).parent.parent.parent / ".env"
|
||||
load_dotenv(dotenv_path=env_path)
|
||||
|
||||
|
||||
def parse_database_url(db_url: str) -> dict:
|
||||
"""Parse database URL into components."""
|
||||
# Handle postgresql+psycopg2:// format
|
||||
if db_url.startswith("postgresql+psycopg2://"):
|
||||
db_url = db_url.replace("postgresql+psycopg2://", "postgresql://")
|
||||
|
||||
parsed = urlparse(db_url)
|
||||
return {
|
||||
"user": parsed.username,
|
||||
"password": parsed.password,
|
||||
"host": parsed.hostname or "localhost",
|
||||
"port": parsed.port or 5432,
|
||||
"database": parsed.path.lstrip("/"),
|
||||
}
|
||||
|
||||
|
||||
def grant_delete_permission() -> None:
|
||||
"""Grant DELETE permission on users table in auth database."""
|
||||
auth_db_url = os.getenv("DATABASE_URL_AUTH")
|
||||
if not auth_db_url:
|
||||
print("❌ Error: DATABASE_URL_AUTH environment variable not set")
|
||||
sys.exit(1)
|
||||
|
||||
if not auth_db_url.startswith("postgresql"):
|
||||
print("ℹ️ Auth database is not PostgreSQL. No permissions to grant.")
|
||||
return
|
||||
|
||||
db_info = parse_database_url(auth_db_url)
|
||||
db_user = db_info["user"]
|
||||
db_name = db_info["database"]
|
||||
|
||||
print(f"📋 Granting DELETE permission on users table...")
|
||||
print(f" Database: {db_name}")
|
||||
print(f" User: {db_user}")
|
||||
|
||||
# Connect as postgres superuser to grant permissions
|
||||
# Try to connect as postgres user (superuser)
|
||||
try:
|
||||
# Try to get postgres password from environment or use peer authentication
|
||||
postgres_url = f"postgresql://postgres@{db_info['host']}:{db_info['port']}/{db_name}"
|
||||
engine = create_engine(postgres_url)
|
||||
|
||||
with engine.connect() as conn:
|
||||
# Grant DELETE permission
|
||||
conn.execute(text(f"""
|
||||
GRANT DELETE ON TABLE users TO {db_user}
|
||||
"""))
|
||||
conn.commit()
|
||||
|
||||
print(f"✅ Successfully granted DELETE permission to user '{db_user}'")
|
||||
return
|
||||
except Exception as e:
|
||||
# If connecting as postgres fails, try with the same user (might have grant privileges)
|
||||
print(f"⚠️ Could not connect as postgres user: {e}")
|
||||
print(f" Trying with current database user...")
|
||||
|
||||
try:
|
||||
engine = create_engine(auth_db_url)
|
||||
with engine.connect() as conn:
|
||||
# Try to grant permission
|
||||
conn.execute(text(f"""
|
||||
GRANT DELETE ON TABLE users TO {db_user}
|
||||
"""))
|
||||
conn.commit()
|
||||
|
||||
print(f"✅ Successfully granted DELETE permission to user '{db_user}'")
|
||||
return
|
||||
except Exception as e2:
|
||||
print(f"❌ Failed to grant permission: {e2}")
|
||||
print(f"\n💡 To grant permission manually, run as postgres superuser:")
|
||||
print(f" sudo -u postgres psql -d {db_name} -c \"GRANT DELETE ON TABLE users TO {db_user};\"")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
grant_delete_permission()
|
||||
|
||||
@@ -21,21 +21,6 @@ def recreate_tables():
|
||||
Base.metadata.create_all(bind=engine)
|
||||
|
||||
print("✅ All tables created successfully!")
|
||||
|
||||
# Stamp Alembic to latest migration
|
||||
print("\nMarking database as up-to-date with migrations...")
|
||||
from alembic.config import Config
|
||||
from alembic import command
|
||||
from alembic.script import ScriptDirectory
|
||||
|
||||
alembic_cfg = Config("alembic.ini")
|
||||
script = ScriptDirectory.from_config(alembic_cfg)
|
||||
|
||||
# Get the latest revision
|
||||
head = script.get_current_head()
|
||||
print(f"Stamping database to revision: {head}")
|
||||
command.stamp(alembic_cfg, head)
|
||||
|
||||
print("✅ Database is now fresh and ready to use!")
|
||||
|
||||
|
||||
|
||||
@@ -59,3 +59,4 @@ echo "3. Run your application - it will connect to PostgreSQL automatically"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user