diff --git a/SETUP_IMPROVEMENTS.md b/SETUP_IMPROVEMENTS.md index 3bc65a9..5ea3857 100644 --- a/SETUP_IMPROVEMENTS.md +++ b/SETUP_IMPROVEMENTS.md @@ -43,10 +43,28 @@ volumes: 3. If `config.toml` doesn't exist in the config directory, the example config is copied 4. Application-managed directories (like images) are created automatically 5. Database migrations run -6. Application starts successfully +6. **Default admin user is created if no users exist** (see Login Information below) +7. Application starts successfully Note: Media directories are NOT created by the application - they should be mounted from your host system. +## Login Information + +### Default Admin User +- If no users exist in the database, a default admin user is automatically created +- **Email**: First email from `admin_emails` in config.toml (default: `admin@example.com`) +- **Password**: `admin` +- **⚠️ IMPORTANT**: Change this password immediately after first login! + +### Creating Additional Admin Users +- Register a new user with an email address listed in the `admin_emails` array in your config.toml +- Users with admin emails automatically become administrators upon registration + +### Manual User Registration +- Access the web UI at `http://localhost:8000/` +- Look for registration/signup options in the interface +- Or use the API directly at `/api/v1/auth/register` + ## User Experience Improvements - **No pre-setup required**: Users can now run `docker-compose up` immediately diff --git a/config.example.toml b/config.example.toml index 5ca15ba..959edca 100644 --- a/config.example.toml +++ b/config.example.toml @@ -36,6 +36,9 @@ email_password_resets = false # if true, you also need to set up SMTP (notificat token_secret = "CHANGE_ME_GENERATE_RANDOM_STRING" # generate a random string with "openssl rand -hex 32", e.g. here https://www.cryptool.org/en/cto/openssl/ session_lifetime = 86400 # this is how long you will be logged in after loggin in, in seconds + +# Admin users: Users who register with these email addresses will automatically become administrators +# If no users exist in the database, a default admin user will be created with the first email in this list admin_emails = ["admin@example.com", "admin2@example.com"] # OpenID Connect settings diff --git a/media_manager/main.py b/media_manager/main.py index edb0b84..42abb18 100644 --- a/media_manager/main.py +++ b/media_manager/main.py @@ -85,7 +85,7 @@ from media_manager.exceptions import ( # noqa: E402 ) from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore # noqa: E402 -from starlette.responses import FileResponse # noqa: E402 +from starlette.responses import FileResponse, RedirectResponse # noqa: E402 import media_manager.database # noqa: E402 import shutil # noqa: E402 @@ -147,10 +147,62 @@ scheduler.start() @asynccontextmanager async def lifespan(app: FastAPI): + # Startup: Create default admin user if needed + await create_default_admin_user() yield + # Shutdown scheduler.shutdown() +async def create_default_admin_user(): + """Create a default admin user if no users exist in the database""" + try: + from media_manager.auth.db import get_user_db + from media_manager.auth.users import get_user_manager + from media_manager.auth.schemas import UserCreate + from media_manager.database import get_session + from sqlalchemy import select, func + from media_manager.auth.db import User + + async for session in get_session(): + async for user_db in get_user_db(session): + async for user_manager in get_user_manager(user_db): + # Check if any users exist + result = await session.execute(select(func.count(User.id))) + user_count = result.scalar() + + if user_count == 0: + log.info("No users found in database. Creating default admin user...") + + # Use the first admin email from config, or default + admin_email = config.auth.admin_emails[0] if config.auth.admin_emails else "admin@mediamanager.local" + default_password = "admin" # Simple default password + + user_create = UserCreate( + email=admin_email, + password=default_password, + is_superuser=True, + is_verified=True + ) + + user = await user_manager.create(user_create) + log.info("=" * 60) + log.info("✅ DEFAULT ADMIN USER CREATED!") + log.info(f" 📧 Email: {admin_email}") + log.info(f" 🔑 Password: {default_password}") + log.info(" ⚠️ IMPORTANT: Please change this password after first login!") + log.info("=" * 60) + + else: + log.info(f"Found {user_count} existing users. Skipping default user creation.") + break + break + break + except Exception as e: + log.error(f"Failed to create default admin user: {e}") + log.info("You can create an admin user manually by registering with an email from the admin_emails list in your config.") + + BASE_PATH = os.getenv("BASE_PATH", "") FRONTEND_FILES_DIR = os.getenv("FRONTEND_FILES_DIR") @@ -262,6 +314,20 @@ app.mount( app.include_router(api_app) app.mount("/web", StaticFiles(directory=FRONTEND_FILES_DIR, html=True), name="frontend") +# Add root route to redirect to web UI +@app.get("/") +async def root(): + return RedirectResponse(url="/web/") + +# Add common routes that users might try +@app.get("/dashboard") +async def dashboard(): + return RedirectResponse(url="/web/") + +@app.get("/login") +async def login(): + return RedirectResponse(url="/web/") + # ---------------------------- # Custom Exception Handlers # ---------------------------- diff --git a/mediamanager-backend-startup.sh b/mediamanager-backend-startup.sh index 708ce26..63eb9a7 100644 --- a/mediamanager-backend-startup.sh +++ b/mediamanager-backend-startup.sh @@ -47,4 +47,11 @@ echo "Running DB migrations..." uv run alembic upgrade head echo "Starting MediaManager backend service..." +echo "" +echo "🔐 LOGIN INFORMATION:" +echo " If this is a fresh installation, a default admin user will be created automatically." +echo " Check the application logs for the login credentials." +echo " You can also register a new user and it will become admin if the email" +echo " matches one of the admin_emails in your config.toml" +echo "" uv run fastapi run /app/media_manager/main.py --port 8000