diff --git a/app/main.py b/app/main.py index 657ea4d..6c67924 100644 --- a/app/main.py +++ b/app/main.py @@ -415,6 +415,11 @@ async def cloudron_create_user(email: str, name: str) -> str: r.raise_for_status() for u in r.json().get("users", []): if u.get("email") == email: + # If the existing user has no display name (e.g. created with a + # placeholder), fill it in. Otherwise leave it alone — the user + # may have set their own name during account setup. + if not u.get("displayName"): + await cloudron_update_profile(u["id"], email, name) return u["id"] # Create user (role "user" = regular member). Only email is required; @@ -458,6 +463,22 @@ async def cloudron_set_active(user_id: str, active: bool) -> None: r.raise_for_status() +async def cloudron_update_profile(user_id: str, email: str, display_name: str, fallback_email: str = "") -> None: + """Update a user's profile (display name, email) after creation. + + Uses POST /api/v1/users/:userId/profile (the Cloudron "Update user" route). + Needed because cloudron_create_user() only sets displayName at creation and + returns early if the user already exists — so corrections require this. + """ + async with httpx.AsyncClient() as client: + r = await client.post( + f"{CLOUDRON_API}/api/v1/users/{user_id}/profile", + headers=cloudron_headers(), + json={"email": email, "displayName": display_name, "fallbackEmail": fallback_email}, + ) + r.raise_for_status() + + async def cloudron_get_invite_link(user_id: str) -> str: """Return the account-setup link WITHOUT sending Cloudron's own email.