Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4def11d976 | ||
|
|
b2babfe382 | ||
|
|
4755393466 | ||
|
|
acc8c0658d | ||
|
|
3f459873fc | ||
|
|
1f4ec43974 | ||
|
|
fc922b6144 | ||
|
|
52ff0d153e |
@@ -46,14 +46,15 @@ TOP_K_SUMMARY=4
|
||||
MAX_CONTEXT_CHARS=4000
|
||||
MIN_SIMILARITY_SCORE=0.18
|
||||
LOG_LEVEL=INFO
|
||||
CORS_ORIGINS=https://docqube-test.maskantech.in,https://docqubeapp-test.maskantech.in,https://docqubeapi-test.maskantech.in
|
||||
CORS_ORIGINS=https://saas-test.maskantech.in,https://docqubeapp-test.maskantech.in,https://docqube-test.maskantech.in,http://localhost:5173,http://localhost:3000
|
||||
COOKIE_DOMAIN=.maskantech.in
|
||||
SMTP_HOST=smtp.gmail.com
|
||||
SMTP_PORT=465
|
||||
SMTP_USER=info.maskantech@gmail.com
|
||||
SMTP_PASSWORD=tuthpljtkrwchgxd
|
||||
MAIL_FROM=info.maskantech@gmail.com
|
||||
SMTP_SECURE=True
|
||||
FRONTEND_URL=https://docqube-test.maskantech.in,https://docqubeapp-test.maskantech.in,https://docqubeapi-test.maskantech.in
|
||||
FRONTEND_URL=https://docqubeapp-test.maskantech.in
|
||||
CHAT_REDIS_MAX_MESSAGES=10
|
||||
CHAT_REDIS_TTL_SECONDS=86400
|
||||
CHAT_DAILY_CREDITS_LIMIT=1000
|
||||
|
||||
@@ -42,13 +42,15 @@ def _validate_saas_subscription(subscription_details: Optional[dict]) -> None:
|
||||
except ValueError:
|
||||
end_date = None
|
||||
|
||||
if is_active is False or status_value in {"INACTIVE", "EXPIRED"}:
|
||||
can_sign_in = subscription_details.get("can_sign_in", True)
|
||||
if can_sign_in is False or is_active is False or status_value in {"INACTIVE", "EXPIRED"}:
|
||||
raise HTTPException(status_code=403, detail="Tenant subscription is inactive")
|
||||
|
||||
if start_date and today < start_date:
|
||||
raise HTTPException(status_code=403, detail="Tenant subscription is not active yet")
|
||||
if not (can_sign_in and is_active and status_value == "ACTIVE"):
|
||||
if start_date and today < start_date:
|
||||
raise HTTPException(status_code=403, detail="Tenant subscription is not active yet")
|
||||
|
||||
if end_date and today > end_date:
|
||||
if end_date and today > end_date and not subscription_details.get("can_write", True):
|
||||
raise HTTPException(status_code=403, detail="Tenant subscription has expired")
|
||||
|
||||
|
||||
|
||||
@@ -34,25 +34,27 @@ class CSRFMiddleware(BaseHTTPMiddleware):
|
||||
content={"detail": "CSRF verification failed"}
|
||||
)
|
||||
if not csrf_cookie:
|
||||
self._set_csrf_cookie(response)
|
||||
self._set_csrf_cookie(response, request)
|
||||
return response
|
||||
|
||||
response = await call_next(request)
|
||||
|
||||
if not csrf_cookie:
|
||||
self._set_csrf_cookie(response)
|
||||
self._set_csrf_cookie(response, request)
|
||||
|
||||
return response
|
||||
|
||||
def _set_csrf_cookie(self, response):
|
||||
def _set_csrf_cookie(self, response, request: Request = None):
|
||||
"""Helper to set the CSRF cookie with appropriate security flags."""
|
||||
is_prod = settings.APP_ENV == "production"
|
||||
is_secure = settings.APP_ENV in ["production", "test", "testing"] or (request and request.url.scheme == "https")
|
||||
samesite_mode = "none" if is_secure else "lax"
|
||||
cookie_domain = getattr(settings, "COOKIE_DOMAIN", None) or None
|
||||
response.set_cookie(
|
||||
key="csrf_token",
|
||||
value=str(uuid.uuid4()),
|
||||
httponly=False,
|
||||
samesite="none" if is_prod else "lax",
|
||||
secure=is_prod,
|
||||
domain=settings.COOKIE_DOMAIN if is_prod else None,
|
||||
samesite=samesite_mode,
|
||||
secure=is_secure,
|
||||
domain=cookie_domain,
|
||||
path="/"
|
||||
)
|
||||
@@ -45,13 +45,17 @@ def login(
|
||||
):
|
||||
token_data = AuthController.login_user(form_data, db, request)
|
||||
|
||||
is_secure = settings.APP_ENV in ["production", "test", "testing"] or request.url.scheme == "https"
|
||||
samesite_mode = "none" if is_secure else "lax"
|
||||
cookie_domain = getattr(settings, "COOKIE_DOMAIN", None) or None
|
||||
|
||||
response.set_cookie(
|
||||
key="docqube_access_token",
|
||||
value=token_data["access_token"],
|
||||
httponly=True,
|
||||
secure=settings.APP_ENV == "production",
|
||||
samesite="none" if settings.APP_ENV == "production" else "lax",
|
||||
domain=settings.COOKIE_DOMAIN if settings.APP_ENV == "production" else None,
|
||||
secure=is_secure,
|
||||
samesite=samesite_mode,
|
||||
domain=cookie_domain,
|
||||
max_age=3600,
|
||||
path="/",
|
||||
)
|
||||
@@ -60,9 +64,9 @@ def login(
|
||||
key="docqube_refresh_token",
|
||||
value=token_data["refresh_token"],
|
||||
httponly=True,
|
||||
secure=settings.APP_ENV == "production",
|
||||
samesite="none" if settings.APP_ENV == "production" else "lax",
|
||||
domain=settings.COOKIE_DOMAIN if settings.APP_ENV == "production" else None,
|
||||
secure=is_secure,
|
||||
samesite=samesite_mode,
|
||||
domain=cookie_domain,
|
||||
max_age=7 * 24 * 3600,
|
||||
path="/api/auth/refresh",
|
||||
)
|
||||
@@ -71,21 +75,31 @@ def login(
|
||||
key="docqube_has_session",
|
||||
value="true",
|
||||
httponly=False,
|
||||
secure=settings.APP_ENV == "production",
|
||||
samesite="none" if settings.APP_ENV == "production" else "lax",
|
||||
domain=settings.COOKIE_DOMAIN if settings.APP_ENV == "production" else None,
|
||||
secure=is_secure,
|
||||
samesite=samesite_mode,
|
||||
domain=cookie_domain,
|
||||
max_age=7 * 24 * 3600,
|
||||
path="/",
|
||||
)
|
||||
|
||||
response.set_cookie(
|
||||
key="csrf_token",
|
||||
value=str(uuid.uuid4()),
|
||||
httponly=False,
|
||||
secure=is_secure,
|
||||
samesite=samesite_mode,
|
||||
domain=cookie_domain,
|
||||
path="/"
|
||||
)
|
||||
|
||||
if hasattr(request.state, "new_device_id"):
|
||||
response.set_cookie(
|
||||
key="docqube_device_id",
|
||||
value=request.state.new_device_id,
|
||||
httponly=True,
|
||||
secure=settings.APP_ENV == "production",
|
||||
samesite="none" if settings.APP_ENV == "production" else "lax",
|
||||
domain=settings.COOKIE_DOMAIN if settings.APP_ENV == "production" else None,
|
||||
secure=is_secure,
|
||||
samesite=samesite_mode,
|
||||
domain=cookie_domain,
|
||||
max_age=365 * 24 * 3600,
|
||||
path="/",
|
||||
)
|
||||
@@ -97,14 +111,17 @@ def google_login(
|
||||
request: Request, response: Response, payload: GoogleLoginIn, db: Session = Depends(get_db)
|
||||
):
|
||||
token_data = AuthController.google_login(payload, db, request)
|
||||
is_secure = settings.APP_ENV in ["production", "test", "testing"] or request.url.scheme == "https"
|
||||
samesite_mode = "none" if is_secure else "lax"
|
||||
cookie_domain = getattr(settings, "COOKIE_DOMAIN", None) or None
|
||||
|
||||
response.set_cookie(
|
||||
key="docqube_access_token",
|
||||
value=token_data["access_token"],
|
||||
httponly=True,
|
||||
secure=settings.APP_ENV == "production",
|
||||
samesite="none" if settings.APP_ENV == "production" else "lax",
|
||||
domain=settings.COOKIE_DOMAIN if settings.APP_ENV == "production" else None,
|
||||
secure=is_secure,
|
||||
samesite=samesite_mode,
|
||||
domain=cookie_domain,
|
||||
max_age=3600,
|
||||
path="/",
|
||||
)
|
||||
@@ -113,9 +130,9 @@ def google_login(
|
||||
key="docqube_refresh_token",
|
||||
value=token_data["refresh_token"],
|
||||
httponly=True,
|
||||
secure=settings.APP_ENV == "production",
|
||||
samesite="none" if settings.APP_ENV == "production" else "lax",
|
||||
domain=settings.COOKIE_DOMAIN if settings.APP_ENV == "production" else None,
|
||||
secure=is_secure,
|
||||
samesite=samesite_mode,
|
||||
domain=cookie_domain,
|
||||
max_age=7 * 24 * 3600,
|
||||
path="/api/auth/refresh",
|
||||
)
|
||||
@@ -124,21 +141,31 @@ def google_login(
|
||||
key="docqube_has_session",
|
||||
value="true",
|
||||
httponly=False,
|
||||
secure=settings.APP_ENV == "production",
|
||||
samesite="none" if settings.APP_ENV == "production" else "lax",
|
||||
domain=settings.COOKIE_DOMAIN if settings.APP_ENV == "production" else None,
|
||||
secure=is_secure,
|
||||
samesite=samesite_mode,
|
||||
domain=cookie_domain,
|
||||
max_age=7 * 24 * 3600,
|
||||
path="/",
|
||||
)
|
||||
|
||||
response.set_cookie(
|
||||
key="csrf_token",
|
||||
value=str(uuid.uuid4()),
|
||||
httponly=False,
|
||||
secure=is_secure,
|
||||
samesite=samesite_mode,
|
||||
domain=cookie_domain,
|
||||
path="/"
|
||||
)
|
||||
|
||||
if hasattr(request.state, "new_device_id"):
|
||||
response.set_cookie(
|
||||
key="docqube_device_id",
|
||||
value=request.state.new_device_id,
|
||||
httponly=True,
|
||||
secure=settings.APP_ENV == "production",
|
||||
samesite="none" if settings.APP_ENV == "production" else "lax",
|
||||
domain=settings.COOKIE_DOMAIN if settings.APP_ENV == "production" else None,
|
||||
secure=is_secure,
|
||||
samesite=samesite_mode,
|
||||
domain=cookie_domain,
|
||||
max_age=365 * 24 * 3600,
|
||||
path="/",
|
||||
)
|
||||
@@ -225,13 +252,17 @@ def refresh_token(request: Request, response: Response, db: Session = Depends(ge
|
||||
|
||||
new_access_token = create_access_token(payload_access)
|
||||
|
||||
is_secure = settings.APP_ENV in ["production", "test", "testing"] or (request and request.url.scheme == "https")
|
||||
samesite_mode = "none" if is_secure else "lax"
|
||||
cookie_domain = getattr(settings, "COOKIE_DOMAIN", None) or None
|
||||
|
||||
response.set_cookie(
|
||||
key="docqube_access_token",
|
||||
value=new_access_token,
|
||||
httponly=True,
|
||||
secure=settings.APP_ENV == "production",
|
||||
samesite="none" if settings.APP_ENV == "production" else "lax",
|
||||
domain=settings.COOKIE_DOMAIN if settings.APP_ENV == "production" else None,
|
||||
secure=is_secure,
|
||||
samesite=samesite_mode,
|
||||
domain=cookie_domain,
|
||||
max_age=3600,
|
||||
path="/",
|
||||
)
|
||||
@@ -240,9 +271,9 @@ def refresh_token(request: Request, response: Response, db: Session = Depends(ge
|
||||
key="docqube_has_session",
|
||||
value="true",
|
||||
httponly=False,
|
||||
secure=settings.APP_ENV == "production",
|
||||
samesite="none" if settings.APP_ENV == "production" else "lax",
|
||||
domain=settings.COOKIE_DOMAIN if settings.APP_ENV == "production" else None,
|
||||
secure=is_secure,
|
||||
samesite=samesite_mode,
|
||||
domain=cookie_domain,
|
||||
max_age=7 * 24 * 3600,
|
||||
path="/",
|
||||
)
|
||||
@@ -304,26 +335,37 @@ def logout(
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
is_secure = settings.APP_ENV in ["production", "test", "testing"] or (request and request.url.scheme == "https")
|
||||
samesite_mode = "none" if is_secure else "lax"
|
||||
cookie_domain = getattr(settings, "COOKIE_DOMAIN", None) or None
|
||||
|
||||
response.delete_cookie(
|
||||
"docqube_access_token",
|
||||
path="/",
|
||||
samesite="none" if settings.APP_ENV == "production" else "lax",
|
||||
secure=settings.APP_ENV == "production",
|
||||
domain=settings.COOKIE_DOMAIN if settings.APP_ENV == "production" else None,
|
||||
samesite=samesite_mode,
|
||||
secure=is_secure,
|
||||
domain=cookie_domain,
|
||||
)
|
||||
response.delete_cookie(
|
||||
"docqube_refresh_token",
|
||||
path="/api/auth/refresh",
|
||||
samesite="none" if settings.APP_ENV == "production" else "lax",
|
||||
secure=settings.APP_ENV == "production",
|
||||
domain=settings.COOKIE_DOMAIN if settings.APP_ENV == "production" else None,
|
||||
samesite=samesite_mode,
|
||||
secure=is_secure,
|
||||
domain=cookie_domain,
|
||||
)
|
||||
response.delete_cookie(
|
||||
"docqube_has_session",
|
||||
path="/",
|
||||
samesite="none" if settings.APP_ENV == "production" else "lax",
|
||||
secure=settings.APP_ENV == "production",
|
||||
domain=settings.COOKIE_DOMAIN if settings.APP_ENV == "production" else None,
|
||||
samesite=samesite_mode,
|
||||
secure=is_secure,
|
||||
domain=cookie_domain,
|
||||
)
|
||||
response.delete_cookie(
|
||||
"csrf_token",
|
||||
path="/",
|
||||
samesite=samesite_mode,
|
||||
secure=is_secure,
|
||||
domain=cookie_domain,
|
||||
)
|
||||
return {"status": "success", "message": "Logged out"}
|
||||
|
||||
|
||||
@@ -54,19 +54,22 @@ def _assert_role_in_callers_tenant(role, current_user: User, db: Session = None,
|
||||
if role.tenant_id == current_user.tenant_id:
|
||||
return
|
||||
|
||||
if allow_system_roles and getattr(role, "is_system", False) and current_user.tenant_id and db:
|
||||
from app.modules.billing.models.plan_model import TenantSubscription, PlanRole
|
||||
sub = db.query(TenantSubscription).filter(
|
||||
TenantSubscription.tenant_id == current_user.tenant_id,
|
||||
TenantSubscription.status == 'active'
|
||||
).order_by(TenantSubscription.created_at.desc()).first()
|
||||
if sub and sub.plan_id:
|
||||
has_role = db.query(PlanRole).filter(
|
||||
PlanRole.plan_id == sub.plan_id,
|
||||
PlanRole.role_id == role.id
|
||||
).first()
|
||||
if has_role:
|
||||
return
|
||||
if allow_system_roles:
|
||||
if getattr(role, "tenant_id", None) is None and getattr(role, "name", "").lower() != "superadmin":
|
||||
return
|
||||
if getattr(role, "is_system", False) and current_user.tenant_id and db:
|
||||
from app.modules.billing.models.plan_model import TenantSubscription, PlanRole
|
||||
sub = db.query(TenantSubscription).filter(
|
||||
TenantSubscription.tenant_id == current_user.tenant_id,
|
||||
TenantSubscription.status == 'active'
|
||||
).order_by(TenantSubscription.created_at.desc()).first()
|
||||
if sub and sub.plan_id:
|
||||
has_role = db.query(PlanRole).filter(
|
||||
PlanRole.plan_id == sub.plan_id,
|
||||
PlanRole.role_id == role.id
|
||||
).first()
|
||||
if has_role:
|
||||
return
|
||||
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND, detail="Role not found"
|
||||
|
||||
@@ -63,6 +63,7 @@ class RoleService:
|
||||
query = db.query(Role)
|
||||
if tenant_id is not None:
|
||||
from app.modules.billing.models.plan_model import TenantSubscription, PlanRole
|
||||
from sqlalchemy import and_, func
|
||||
sub = db.query(TenantSubscription).filter(
|
||||
TenantSubscription.tenant_id == tenant_id,
|
||||
TenantSubscription.status == 'active'
|
||||
@@ -72,7 +73,16 @@ class RoleService:
|
||||
plan_role_ids = [pr.role_id for pr in plan_roles]
|
||||
query = query.filter(or_(Role.tenant_id == tenant_id, Role.id.in_(plan_role_ids)))
|
||||
else:
|
||||
query = query.filter(Role.tenant_id == tenant_id)
|
||||
# Include tenant roles AND tenant-accessible default/system roles (excluding superadmin)
|
||||
query = query.filter(
|
||||
or_(
|
||||
Role.tenant_id == tenant_id,
|
||||
and_(
|
||||
Role.tenant_id.is_(None),
|
||||
func.lower(Role.name) != 'superadmin'
|
||||
)
|
||||
)
|
||||
)
|
||||
return query.all()
|
||||
|
||||
@staticmethod
|
||||
@@ -135,6 +145,7 @@ class RoleService:
|
||||
query = db.query(Role)
|
||||
if tenant_id is not None:
|
||||
from app.modules.billing.models.plan_model import TenantSubscription, PlanRole
|
||||
from sqlalchemy import and_, func
|
||||
sub = db.query(TenantSubscription).filter(
|
||||
TenantSubscription.tenant_id == tenant_id,
|
||||
TenantSubscription.status == 'active'
|
||||
@@ -144,7 +155,16 @@ class RoleService:
|
||||
plan_role_ids = [pr.role_id for pr in plan_roles]
|
||||
query = query.filter(or_(Role.tenant_id == tenant_id, Role.id.in_(plan_role_ids)))
|
||||
else:
|
||||
query = query.filter(Role.tenant_id == tenant_id)
|
||||
# Include tenant roles AND tenant-accessible default/system roles (excluding superadmin)
|
||||
query = query.filter(
|
||||
or_(
|
||||
Role.tenant_id == tenant_id,
|
||||
and_(
|
||||
Role.tenant_id.is_(None),
|
||||
func.lower(Role.name) != 'superadmin'
|
||||
)
|
||||
)
|
||||
)
|
||||
if search and search.strip():
|
||||
search_term = search.strip()
|
||||
query = query.filter(Role.name.ilike(f"%{search_term}%"))
|
||||
|
||||
@@ -4,9 +4,12 @@ import time
|
||||
import logging
|
||||
import hmac
|
||||
import hashlib
|
||||
import uuid
|
||||
|
||||
from app.db.database import get_db
|
||||
from app.core.settings import settings
|
||||
from app.core.security import create_access_token, create_refresh_token
|
||||
from app.core.request_body import read_json_body
|
||||
from app.services.saas_service import SaaSService
|
||||
from app.modules.tenant.models.tenant_model import Tenant
|
||||
from app.modules.auth.models.saas_models import SaaSTenantMapping
|
||||
@@ -72,6 +75,13 @@ async def sso_login(
|
||||
"subscription": data.get("subscription"),
|
||||
}
|
||||
|
||||
subscription = data.get("subscription")
|
||||
if user.tenant and subscription:
|
||||
try:
|
||||
_sync_subscription(db, user.tenant, subscription.get("plan_code"), subscription)
|
||||
except Exception as e:
|
||||
logger.warning(f"Could not sync subscription for tenant {user.tenant_id}: {e}")
|
||||
|
||||
is_user_superadmin = bool(
|
||||
getattr(user, "is_superadmin", False)
|
||||
or data.get("is_superadmin")
|
||||
@@ -98,14 +108,17 @@ async def sso_login(
|
||||
}
|
||||
)
|
||||
|
||||
is_prod = settings.APP_ENV == "production"
|
||||
is_secure = settings.APP_ENV in ["production", "test", "testing"] or request.url.scheme == "https"
|
||||
samesite_mode = "none" if is_secure else "lax"
|
||||
cookie_domain = getattr(settings, "COOKIE_DOMAIN", None) or None
|
||||
|
||||
response.set_cookie(
|
||||
key="docqube_access_token",
|
||||
value=access_token,
|
||||
httponly=True,
|
||||
secure=is_prod,
|
||||
samesite="lax",
|
||||
secure=is_secure,
|
||||
samesite=samesite_mode,
|
||||
domain=cookie_domain,
|
||||
path="/",
|
||||
max_age=settings.ACCESS_TOKEN_EXPIRE_MINUTES * 60
|
||||
)
|
||||
@@ -114,12 +127,23 @@ async def sso_login(
|
||||
key="docqube_refresh_token",
|
||||
value=refresh_token,
|
||||
httponly=True,
|
||||
secure=is_prod,
|
||||
samesite="lax",
|
||||
secure=is_secure,
|
||||
samesite=samesite_mode,
|
||||
domain=cookie_domain,
|
||||
path="/",
|
||||
max_age=7 * 24 * 3600
|
||||
)
|
||||
|
||||
response.set_cookie(
|
||||
key="csrf_token",
|
||||
value=str(uuid.uuid4()),
|
||||
httponly=False,
|
||||
secure=is_secure,
|
||||
samesite=samesite_mode,
|
||||
domain=cookie_domain,
|
||||
path="/"
|
||||
)
|
||||
|
||||
return {
|
||||
"status": "success",
|
||||
"message": "SSO Login successful",
|
||||
@@ -129,6 +153,8 @@ async def sso_login(
|
||||
"id": user.id,
|
||||
"email": user.email,
|
||||
"name": user.name,
|
||||
"is_superadmin": is_user_superadmin,
|
||||
"role": "superadmin" if is_user_superadmin else (user.role.name if user.role else None),
|
||||
"permissions": permissions
|
||||
}
|
||||
}
|
||||
@@ -281,9 +307,6 @@ async def provision_tenant(request: Request, db: Session = Depends(get_db)):
|
||||
logger.exception("Provisioning webhook failed for event %s", event_type)
|
||||
raise HTTPException(status_code=500, detail=f"Provisioning error: {str(e)}")
|
||||
|
||||
from app.core.security import create_access_token, create_refresh_token
|
||||
from app.core.request_body import read_json_body
|
||||
|
||||
|
||||
def _sync_subscription(db, tenant, plan_code, subscription: dict) -> None:
|
||||
"""
|
||||
|
||||
@@ -41,10 +41,12 @@ class SaaSService:
|
||||
|
||||
@staticmethod
|
||||
def ensure_saas_user(db: Session, saas_data: Dict[str, Any]) -> Tuple[User, SaaSUserMapping]:
|
||||
"""
|
||||
Ensures a local user exists for the given SaaS user data.
|
||||
Maps the user if not already mapped.
|
||||
"""
|
||||
from sqlalchemy import text
|
||||
try:
|
||||
db.execute(text("SELECT set_config('docqube.bypass', 'on', true)"))
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
saas_user_id = str(saas_data.get("id"))
|
||||
email = saas_data.get("email")
|
||||
name = saas_data.get("name")
|
||||
@@ -94,6 +96,29 @@ class SaaSService:
|
||||
except Exception as e:
|
||||
logger.warning(f"Could not create role {role_name} for tenant {tenant.id}: {e}")
|
||||
|
||||
permissions = saas_data.get("metadata", {}).get("permissions", [])
|
||||
if target_role and permissions:
|
||||
try:
|
||||
access_rows = db.query(Access).filter(Access.access_code.in_(permissions)).all()
|
||||
existing_access_ids = {
|
||||
ra.access_id for ra in db.query(RoleAccess).filter(RoleAccess.role_id == target_role.id).all()
|
||||
}
|
||||
new_access_ids = {a.id for a in access_rows}
|
||||
|
||||
to_delete = existing_access_ids - new_access_ids
|
||||
if to_delete:
|
||||
db.query(RoleAccess).filter(
|
||||
RoleAccess.role_id == target_role.id,
|
||||
RoleAccess.access_id.in_(to_delete)
|
||||
).delete(synchronize_session=False)
|
||||
|
||||
to_add = new_access_ids - existing_access_ids
|
||||
for aid in to_add:
|
||||
db.add(RoleAccess(role_id=target_role.id, access_id=aid))
|
||||
db.flush()
|
||||
except Exception as e:
|
||||
logger.warning(f"Could not sync role accesses for {target_role.name}: {e}")
|
||||
|
||||
mapping = db.query(SaaSUserMapping).filter(SaaSUserMapping.saas_user_id == saas_user_id).first()
|
||||
if mapping:
|
||||
user = mapping.user
|
||||
|
||||
@@ -19,6 +19,7 @@ dependencies = [
|
||||
"python-jose==3.3.0",
|
||||
"passlib==1.7.4",
|
||||
"bcrypt==5.0.0",
|
||||
"cffi>=1.17.0",
|
||||
"cryptography==48.0.0",
|
||||
"google-auth==2.57.0",
|
||||
"sqlalchemy==2.0.36",
|
||||
|
||||
@@ -594,6 +594,7 @@ dependencies = [
|
||||
{ name = "beautifulsoup4" },
|
||||
{ name = "boto3" },
|
||||
{ name = "celery" },
|
||||
{ name = "cffi" },
|
||||
{ name = "cryptography" },
|
||||
{ name = "docx2txt" },
|
||||
{ name = "email-validator" },
|
||||
@@ -664,6 +665,7 @@ requires-dist = [
|
||||
{ name = "beautifulsoup4", specifier = "==4.13.5" },
|
||||
{ name = "boto3", specifier = "==1.36.23" },
|
||||
{ name = "celery", specifier = "==5.4.0" },
|
||||
{ name = "cffi", specifier = ">=1.17.0" },
|
||||
{ name = "cryptography", specifier = "==48.0.0" },
|
||||
{ name = "docx2txt", specifier = "==0.9" },
|
||||
{ name = "email-validator", specifier = "==2.3.0" },
|
||||
@@ -1443,8 +1445,8 @@ name = "mkl"
|
||||
version = "2021.4.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "intel-openmp", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" },
|
||||
{ name = "tbb", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" },
|
||||
{ name = "intel-openmp" },
|
||||
{ name = "tbb" },
|
||||
]
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ce/c6/892fe3bc91e811b78e4f85653864f2d92541d5e5c306b0cb3c2311e9ca64/mkl-2021.4.0-py2.py3-none-win32.whl", hash = "sha256:439c640b269a5668134e3dcbcea4350459c4a8bc46469669b2d67e07e3d330e8", size = 129048357, upload-time = "2021-09-28T17:08:58.256Z" },
|
||||
|
||||
Reference in New Issue
Block a user