FIX: mandant wird erstellt wenn sich ein user mit microsoft oder google das erste mal registriert, damit er die app tatsächlich nutzen kann

This commit is contained in:
Ida 2026-06-12 09:28:11 +02:00
parent 66b44e5c78
commit 0438177934
5 changed files with 94 additions and 45 deletions

View file

@ -0,0 +1,55 @@
# Copyright (c) 2026 PowerOn AG
# All rights reserved.
"""Ensure new users receive a Home mandate on first login."""
import logging
logger = logging.getLogger(__name__)
def ensureHomeMandate(rootInterface, user) -> None:
"""Ensure user has a Home mandate, but only if they have no mandate memberships
AND no pending invitations.
Invited users should NOT get a Home mandate they join existing mandates via
invitation acceptance and can create their own later via onboarding.
"""
userId = str(user.id)
userMandates = rootInterface.getUserMandates(userId)
if userMandates:
for um in userMandates:
mandate = rootInterface.getMandate(um.mandateId)
if mandate and (mandate.name or "").startswith("Home ") and not mandate.isSystem:
return
logger.debug(
f"User {user.username} has {len(userMandates)} mandate(s) but no Home — skipping auto-creation"
)
return
try:
normalizedEmail = (user.email or "").strip().lower() if user.email else None
pendingByUsername = rootInterface.getInvitationsByTargetUsername(user.username)
pendingByEmail = (
rootInterface.getInvitationsByEmail(normalizedEmail) if normalizedEmail else []
)
seenIds = set()
for inv in pendingByUsername + pendingByEmail:
if inv.id in seenIds:
continue
seenIds.add(inv.id)
if not inv.revokedAt and (inv.currentUses or 0) < (inv.maxUses or 1):
logger.info(
f"User {user.username} has pending invitation(s) — skipping Home mandate creation"
)
return
except Exception as e:
logger.warning(f"Could not check pending invitations for {user.username}: {e}")
homeMandateLabel = f"Home {user.username}"
rootInterface._provisionMandateForUser(
userId=userId,
mandateLabel=homeMandateLabel,
planKey="TRIAL_14D",
)
logger.info(f"Created Home mandate '{homeMandateLabel}' for user {user.username}")

View file

@ -26,6 +26,7 @@ from modules.auth import (
setAccessTokenCookie,
setRefreshTokenCookie,
)
from modules.auth.homeMandateService import ensureHomeMandate
from modules.auth.mfaService import (
generateSetup,
confirmSetup,
@ -229,6 +230,20 @@ def mfaVerify(
)
userInterface.saveAccessToken(dbToken)
try:
ensureHomeMandate(rootInterface, user)
except Exception as homeErr:
logger.error(f"Error ensuring Home mandate for user {username}: {homeErr}")
try:
activatedCount = rootInterface._activatePendingSubscriptions(userId)
if activatedCount > 0:
logger.info(
f"Activated {activatedCount} pending subscription(s) for user {username} after MFA"
)
except Exception as subErr:
logger.error(f"Error activating subscriptions after MFA verify: {subErr}")
logger.info("MFA verify successful for user %s", username)
# Mark device as trusted so MFA is skipped on next login from this device

View file

@ -34,6 +34,7 @@ from modules.auth import (
)
from modules.auth.tokenManager import TokenManager
from modules.auth.oauthProviderConfig import googleAuthScopes, googleDataScopes
from modules.auth.homeMandateService import ensureHomeMandate
from modules.shared.timeUtils import createExpirationTimestamp, getUtcTimestamp, parseTimestamp
from modules.shared.i18nRegistry import apiRouteContext
routeApiMsg = apiRouteContext("routeSecurityGoogle")
@ -278,6 +279,11 @@ async def auth_login_callback(
)
# --- end MFA gate -----------------------------------------------------
try:
ensureHomeMandate(rootInterface, user)
except Exception as homeErr:
logger.error(f"Error ensuring Home mandate for user {user.username}: {homeErr}")
jwt_token_data = {
"sub": user.username,
"userId": str(user.id),

View file

@ -16,12 +16,13 @@ from jose import jwt
# Import auth modules
from modules.auth import getCurrentUser, limiter, SECRET_KEY, ALGORITHM, getRequestContext, RequestContext
from modules.auth import createAccessToken, createRefreshToken, setAccessTokenCookie, setRefreshTokenCookie, clearAccessTokenCookie, clearRefreshTokenCookie
from modules.interfaces.interfaceDbApp import getInterface, getRootInterface, getRootInterface as _getRootIf
from modules.interfaces.interfaceDbApp import getInterface, getRootInterface
from modules.datamodels.datamodelUam import User, UserInDB, AuthAuthority, Mandate
from modules.datamodels.datamodelSecurity import Token, TokenPurpose
from modules.shared.configuration import APP_CONFIG
from modules.shared.timeUtils import getUtcTimestamp
from modules.shared.i18nRegistry import apiRouteContext
from modules.auth.homeMandateService import ensureHomeMandate
routeApiMsg = apiRouteContext("routeSecurityLocal")
# Configure logger
@ -174,49 +175,6 @@ router = APIRouter(
}
)
def _ensureHomeMandate(rootInterface, user) -> None:
"""Ensure user has a Home mandate, but only if they have no mandate memberships
AND no pending invitations.
Invited users should NOT get a Home mandate they join existing mandates via
invitation acceptance and can create their own later via onboarding.
"""
userId = str(user.id)
userMandates = rootInterface.getUserMandates(userId)
if userMandates:
for um in userMandates:
mandate = rootInterface.getMandate(um.mandateId)
if mandate and (mandate.name or "").startswith("Home ") and not mandate.isSystem:
return
logger.debug(f"User {user.username} has {len(userMandates)} mandate(s) but no Home — skipping auto-creation")
return
try:
appIf = _getRootIf()
normalizedEmail = (user.email or "").strip().lower() if user.email else None
pendingByUsername = appIf.getInvitationsByTargetUsername(user.username)
pendingByEmail = appIf.getInvitationsByEmail(normalizedEmail) if normalizedEmail else []
seenIds = set()
for inv in pendingByUsername + pendingByEmail:
if inv.id in seenIds:
continue
seenIds.add(inv.id)
if not inv.revokedAt and (inv.currentUses or 0) < (inv.maxUses or 1):
logger.info(f"User {user.username} has pending invitation(s) — skipping Home mandate creation")
return
except Exception as e:
logger.warning(f"Could not check pending invitations for {user.username}: {e}")
homeMandateLabel = f"Home {user.username}"
rootInterface._provisionMandateForUser(
userId=userId,
mandateLabel=homeMandateLabel,
planKey="TRIAL_14D",
)
logger.info(f"Created Home mandate '{homeMandateLabel}' for user {user.username}")
@router.post("/login")
@limiter.limit("30/minute")
def login(
@ -364,7 +322,7 @@ def login(
# Ensure user has a Home mandate (created on first login if missing)
try:
_ensureHomeMandate(rootInterface, user)
ensureHomeMandate(rootInterface, user)
except Exception as homeErr:
logger.error(f"Error ensuring Home mandate for user {user.username}: {homeErr}")

View file

@ -35,6 +35,7 @@ from modules.auth import (
)
from modules.auth.tokenManager import TokenManager
from modules.auth.oauthProviderConfig import msftAuthScopes, msftDataScopes, msftDataScopesForRefresh
from modules.auth.homeMandateService import ensureHomeMandate
from modules.shared.timeUtils import createExpirationTimestamp, getUtcTimestamp, parseTimestamp
from modules.shared.i18nRegistry import apiRouteContext
routeApiMsg = apiRouteContext("routeSecurityMsft")
@ -251,6 +252,20 @@ async def auth_login_callback(
)
# --- end MFA gate -----------------------------------------------------
try:
ensureHomeMandate(rootInterface, user)
except Exception as homeErr:
logger.error(f"Error ensuring Home mandate for user {user.username}: {homeErr}")
try:
activatedCount = rootInterface._activatePendingSubscriptions(str(user.id))
if activatedCount > 0:
logger.info(
f"Activated {activatedCount} pending subscription(s) for user {user.username}"
)
except Exception as subErr:
logger.error(f"Error activating subscriptions on Microsoft login: {subErr}")
jwt_token_data = {
"sub": user.username,
"userId": str(user.id),