Seth commited on
Commit
0997ef3
·
1 Parent(s): 766e766
backend/app/auth_routes.py CHANGED
@@ -240,6 +240,13 @@ async def auth_me(request: Request, db: Session = Depends(get_db)):
240
  if cur_tid is not None and int(cur_tid) == tid:
241
  current_role = m.role
242
 
 
 
 
 
 
 
 
243
  return {
244
  **profile,
245
  "user_id": uid,
 
240
  if cur_tid is not None and int(cur_tid) == tid:
241
  current_role = m.role
242
 
243
+ # Keep session aligned with DB when current_tenant_id is missing or no longer valid.
244
+ if current_role is None and memberships:
245
+ m0, t0 = min(memberships, key=lambda mt: (int(mt[1].id), int(mt[0].id)))
246
+ request.session["current_tenant_id"] = int(t0.id)
247
+ cur_tid = int(t0.id)
248
+ current_role = m0.role
249
+
250
  return {
251
  **profile,
252
  "user_id": uid,
backend/app/tenant_deps.py CHANGED
@@ -22,20 +22,32 @@ async def get_tenant_context(request: Request, db: Session = Depends(get_db)) ->
22
  uid = request.session.get("user_id")
23
  if uid is None:
24
  raise HTTPException(status_code=401, detail="Sign in required")
25
- tid = request.session.get("current_tenant_id")
26
- if tid is None:
27
- raise HTTPException(status_code=400, detail="No workspace selected")
28
- m = (
29
  db.query(TenantMembership)
30
- .filter(
31
- TenantMembership.user_id == int(uid),
32
- TenantMembership.tenant_id == int(tid),
33
- )
34
- .first()
35
  )
36
- if not m:
37
- raise HTTPException(status_code=403, detail="You are not a member of this workspace")
38
- return TenantContext(tenant_id=int(tid), user_id=int(uid), role=m.role, db=db)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
 
40
 
41
  async def require_tenant_admin(tc: TenantContext = Depends(get_tenant_context)) -> TenantContext:
 
22
  uid = request.session.get("user_id")
23
  if uid is None:
24
  raise HTTPException(status_code=401, detail="Sign in required")
25
+ uid_i = int(uid)
26
+
27
+ memberships = (
 
28
  db.query(TenantMembership)
29
+ .filter(TenantMembership.user_id == uid_i)
30
+ .order_by(TenantMembership.id)
31
+ .all()
 
 
32
  )
33
+ if not memberships:
34
+ raise HTTPException(
35
+ status_code=400,
36
+ detail="No workspace membership. Sign out and sign in again, or use an invite link.",
37
+ )
38
+
39
+ tid_session = request.session.get("current_tenant_id")
40
+ m = None
41
+ if tid_session is not None:
42
+ tid_i = int(tid_session)
43
+ m = next((x for x in memberships if int(x.tenant_id) == tid_i), None)
44
+
45
+ # Session pointed at a tenant the user no longer belongs to (stale cookie / DB reset / HF volume).
46
+ if m is None:
47
+ m = memberships[0]
48
+ request.session["current_tenant_id"] = int(m.tenant_id)
49
+
50
+ return TenantContext(tenant_id=int(m.tenant_id), user_id=uid_i, role=m.role, db=db)
51
 
52
 
53
  async def require_tenant_admin(tc: TenantContext = Depends(get_tenant_context)) -> TenantContext:
frontend/src/components/layout/AppShell.jsx CHANGED
@@ -42,7 +42,7 @@ export default function AppShell({ title, subtitle, rightContent, children }) {
42
  };
43
  syncSettingsNav();
44
  window.addEventListener('emailout-auth-changed', syncSettingsNav);
45
- return () => window.removeEventListener('emailout-auth-changed', syncAdminNav);
46
  }, []);
47
 
48
  const navItems = useMemo(
 
42
  };
43
  syncSettingsNav();
44
  window.addEventListener('emailout-auth-changed', syncSettingsNav);
45
+ return () => window.removeEventListener('emailout-auth-changed', syncSettingsNav);
46
  }, []);
47
 
48
  const navItems = useMemo(