filter functionality added on all modules.
This commit is contained in:
@@ -89,6 +89,10 @@ class RoleController:
|
||||
page: int = 1,
|
||||
page_size: int = 10,
|
||||
search: Optional[str] = None,
|
||||
filter_role_names: Optional[List[str]] = None,
|
||||
filter_tenant_ids: Optional[List[uuid.UUID]] = None,
|
||||
sort_by: Optional[str] = None,
|
||||
sort_order: Optional[str] = None,
|
||||
) -> RolePaginatedResponse:
|
||||
tenant_id = None if current_user_tenant_id is None else current_user_tenant_id
|
||||
return RoleService.get_roles_paginated(
|
||||
@@ -97,4 +101,8 @@ class RoleController:
|
||||
page=page,
|
||||
page_size=page_size,
|
||||
search=search,
|
||||
filter_role_names=filter_role_names,
|
||||
filter_tenant_ids=filter_tenant_ids,
|
||||
sort_by=sort_by,
|
||||
sort_order=sort_order,
|
||||
)
|
||||
@@ -1,5 +1,5 @@
|
||||
import uuid
|
||||
from typing import Optional
|
||||
from typing import List, Optional
|
||||
from sqlalchemy.orm import Session
|
||||
from app.schemas.auth.subscription_plan_schema import SubscriptionPlanCreate, SubscriptionPlanUpdate
|
||||
from app.services.auth.subscription_plan_service import SubscriptionPlanService
|
||||
@@ -23,8 +23,28 @@ class SubscriptionPlanController:
|
||||
return SubscriptionPlanService.get_all_plans(db, is_public, status)
|
||||
|
||||
@staticmethod
|
||||
def get_paginated_plans(db: Session, page: int, page_size: int, search: Optional[str]):
|
||||
return SubscriptionPlanService.get_paginated_plans(db, page, page_size, search)
|
||||
def get_paginated_plans(
|
||||
db: Session,
|
||||
page: int,
|
||||
page_size: int,
|
||||
search: Optional[str],
|
||||
filter_names: Optional[List[str]] = None,
|
||||
statuses: Optional[List[str]] = None,
|
||||
visibility: Optional[List[bool]] = None,
|
||||
sort_by: Optional[str] = None,
|
||||
sort_order: Optional[str] = None,
|
||||
):
|
||||
return SubscriptionPlanService.get_paginated_plans(
|
||||
db,
|
||||
page,
|
||||
page_size,
|
||||
search,
|
||||
filter_names=filter_names,
|
||||
statuses=statuses,
|
||||
visibility=visibility,
|
||||
sort_by=sort_by,
|
||||
sort_order=sort_order,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def delete_plan(db: Session, plan_id: uuid.UUID):
|
||||
|
||||
@@ -2,7 +2,7 @@ from sqlalchemy.orm import Session
|
||||
from app.schemas.auth.tenant_schema import TenantCreate, TenantUpdate
|
||||
from app.services.auth.tenant_service import TenantService
|
||||
import uuid
|
||||
from typing import Optional
|
||||
from typing import List, Optional
|
||||
|
||||
class TenantController:
|
||||
|
||||
@@ -33,6 +33,12 @@ class TenantController:
|
||||
page_size: int,
|
||||
search: Optional[str],
|
||||
is_active: Optional[bool],
|
||||
filter_tenant_names: Optional[List[str]] = None,
|
||||
filter_tenant_domains: Optional[List[str]] = None,
|
||||
filter_plan_ids: Optional[List[uuid.UUID]] = None,
|
||||
statuses: Optional[List[bool]] = None,
|
||||
sort_by: Optional[str] = None,
|
||||
sort_order: Optional[str] = None,
|
||||
):
|
||||
return TenantService.get_tenants_paginated(
|
||||
db=db,
|
||||
@@ -40,4 +46,10 @@ class TenantController:
|
||||
page_size=page_size,
|
||||
search=search,
|
||||
is_active=is_active,
|
||||
filter_tenant_names=filter_tenant_names,
|
||||
filter_tenant_domains=filter_tenant_domains,
|
||||
filter_plan_ids=filter_plan_ids,
|
||||
statuses=statuses,
|
||||
sort_by=sort_by,
|
||||
sort_order=sort_order,
|
||||
)
|
||||
@@ -55,7 +55,13 @@ class UserController:
|
||||
page: int = 1,
|
||||
page_size: int = 10,
|
||||
search: Optional[str] = None,
|
||||
status: Optional[str] = None,
|
||||
filter_names: Optional[List[str]] = None,
|
||||
filter_emails: Optional[List[str]] = None,
|
||||
statuses: Optional[List[str]] = None,
|
||||
filter_tenant_ids: Optional[List[uuid.UUID]] = None,
|
||||
filter_role_ids: Optional[List[uuid.UUID]] = None,
|
||||
sort_by: Optional[str] = None,
|
||||
sort_order: Optional[str] = None,
|
||||
):
|
||||
tenant_id = current_user.tenant_id
|
||||
return UserService.get_users_paginated(
|
||||
@@ -64,5 +70,11 @@ class UserController:
|
||||
page=page,
|
||||
page_size=page_size,
|
||||
search=search,
|
||||
status=status,
|
||||
filter_names=filter_names,
|
||||
filter_emails=filter_emails,
|
||||
statuses=statuses,
|
||||
filter_tenant_ids=filter_tenant_ids,
|
||||
filter_role_ids=filter_role_ids,
|
||||
sort_by=sort_by,
|
||||
sort_order=sort_order,
|
||||
)
|
||||
@@ -1,6 +1,7 @@
|
||||
from typing import Optional
|
||||
from typing import List, Optional
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy import asc, desc, or_, cast, String
|
||||
|
||||
from app.config.database import get_db
|
||||
from app.middleware.auth_middleware import get_current_user, User
|
||||
@@ -16,6 +17,12 @@ def get_audit_logs(
|
||||
module_name: Optional[str] = Query(None, description="Filter by module name"),
|
||||
action_type: Optional[str] = Query(None, description="CREATE | UPDATE | DELETE"),
|
||||
performed_by_email: Optional[str] = Query(None, description="Filter by actor email"),
|
||||
search: Optional[str] = Query(None, description="Search audit logs"),
|
||||
module_names: Optional[List[str]] = Query(None, description="Filter by module names"),
|
||||
action_types: Optional[List[str]] = Query(None, description="Filter by action types"),
|
||||
performed_by_emails: Optional[List[str]] = Query(None, description="Filter by actor emails"),
|
||||
sort_by: Optional[str] = Query("created_at", description="Sort by created_at, module_name, action_type, or performed_by_email"),
|
||||
sort_order: Optional[str] = Query("desc", description="Sort order: asc or desc"),
|
||||
limit: int = Query(50, ge=1, le=500),
|
||||
offset: int = Query(0, ge=0),
|
||||
):
|
||||
@@ -27,16 +34,44 @@ def get_audit_logs(
|
||||
|
||||
if module_name:
|
||||
query = query.filter(AuditLog.module_name == module_name)
|
||||
if module_names:
|
||||
query = query.filter(AuditLog.module_name.in_(module_names))
|
||||
if action_type:
|
||||
query = query.filter(AuditLog.action_type == action_type.upper())
|
||||
if action_types:
|
||||
normalized_action_types = [item.upper() for item in action_types]
|
||||
query = query.filter(AuditLog.action_type.in_(normalized_action_types))
|
||||
if performed_by_email:
|
||||
query = query.filter(
|
||||
AuditLog.performed_by_email.ilike(f"%{performed_by_email}%")
|
||||
)
|
||||
if performed_by_emails:
|
||||
query = query.filter(AuditLog.performed_by_email.in_(performed_by_emails))
|
||||
if search:
|
||||
search_term = search.strip()
|
||||
query = query.filter(
|
||||
or_(
|
||||
AuditLog.module_name.ilike(f"%{search_term}%"),
|
||||
AuditLog.action_type.ilike(f"%{search_term}%"),
|
||||
AuditLog.entity_name.ilike(f"%{search_term}%"),
|
||||
AuditLog.description.ilike(f"%{search_term}%"),
|
||||
AuditLog.performed_by_email.ilike(f"%{search_term}%"),
|
||||
AuditLog.ip_address.ilike(f"%{search_term}%"),
|
||||
cast(AuditLog.entity_id, String).ilike(f"%{search_term}%"),
|
||||
)
|
||||
)
|
||||
|
||||
total = query.count()
|
||||
sort_column_map = {
|
||||
"created_at": AuditLog.created_at,
|
||||
"module_name": AuditLog.module_name,
|
||||
"action_type": AuditLog.action_type,
|
||||
"performed_by_email": AuditLog.performed_by_email,
|
||||
}
|
||||
sort_column = sort_column_map.get(sort_by or "created_at", AuditLog.created_at)
|
||||
order_fn = asc if (sort_order or "").lower() == "asc" else desc
|
||||
items = (
|
||||
query.order_by(AuditLog.created_at.desc())
|
||||
query.order_by(order_fn(sort_column))
|
||||
.offset(offset)
|
||||
.limit(limit)
|
||||
.all()
|
||||
|
||||
@@ -135,6 +135,10 @@ def list_roles(
|
||||
page: int = Query(1, ge=1, description="Page number"),
|
||||
page_size: int = Query(10, ge=1, le=100, description="Items per page"),
|
||||
search: Optional[str] = Query(None, description="Search in role name or ID"),
|
||||
filter_role_names: Optional[List[str]] = Query(None, description="Filter by role names"),
|
||||
filter_tenant_ids: Optional[List[uuid.UUID]] = Query(None, description="Filter by tenant IDs"),
|
||||
sort_by: Optional[str] = Query(None, description="Sort by role name or tenant"),
|
||||
sort_order: Optional[str] = Query(None, description="Sort order: asc or desc"),
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user),
|
||||
_=Depends(require_access("admin.role.read")),
|
||||
@@ -145,4 +149,8 @@ def list_roles(
|
||||
page=page,
|
||||
page_size=page_size,
|
||||
search=search,
|
||||
filter_role_names=filter_role_names,
|
||||
filter_tenant_ids=filter_tenant_ids,
|
||||
sort_by=sort_by,
|
||||
sort_order=sort_order,
|
||||
)
|
||||
@@ -93,11 +93,26 @@ def list_plans(
|
||||
page: int = Query(1, ge=1),
|
||||
page_size: int = Query(10, ge=1, le=100),
|
||||
search: Optional[str] = Query(None),
|
||||
filter_names: Optional[List[str]] = Query(None),
|
||||
statuses: Optional[List[str]] = Query(None),
|
||||
visibility: Optional[List[bool]] = Query(None, description="Filter by public/private visibility"),
|
||||
sort_by: Optional[str] = Query(None, description="Sort by name, status, visibility, or price"),
|
||||
sort_order: Optional[str] = Query(None, description="Sort order: asc or desc"),
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user),
|
||||
_ = Depends(require_access("superadmin.plan.read"))
|
||||
):
|
||||
return SubscriptionPlanController.get_paginated_plans(db, page, page_size, search)
|
||||
return SubscriptionPlanController.get_paginated_plans(
|
||||
db,
|
||||
page,
|
||||
page_size,
|
||||
search,
|
||||
filter_names=filter_names,
|
||||
statuses=statuses,
|
||||
visibility=visibility,
|
||||
sort_by=sort_by,
|
||||
sort_order=sort_order,
|
||||
)
|
||||
|
||||
@router.get("/all", response_model=List[SubscriptionPlanResponse])
|
||||
def all_plans(
|
||||
|
||||
@@ -133,6 +133,12 @@ def list_tenants(
|
||||
page_size: int = Query(10, ge=1, le=100, description="Items per page"),
|
||||
search: Optional[str] = Query(None, description="Search in name, domain, or ID"),
|
||||
is_active: Optional[bool] = Query(None, description="Filter by active status"),
|
||||
filter_tenant_names: Optional[List[str]] = Query(None, description="Filter by tenant names"),
|
||||
filter_tenant_domains: Optional[List[str]] = Query(None, description="Filter by tenant domains"),
|
||||
filter_plan_ids: Optional[List[uuid.UUID]] = Query(None, description="Filter by plan IDs"),
|
||||
statuses: Optional[List[bool]] = Query(None, description="Filter by tenant statuses"),
|
||||
sort_by: Optional[str] = Query(None, description="Sort by name, domain, status, or plan"),
|
||||
sort_order: Optional[str] = Query(None, description="Sort order: asc or desc"),
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user),
|
||||
_ = Depends(require_access("superadmin.tenant.read")),
|
||||
@@ -143,4 +149,10 @@ def list_tenants(
|
||||
page_size=page_size,
|
||||
search=search,
|
||||
is_active=is_active,
|
||||
filter_tenant_names=filter_tenant_names,
|
||||
filter_tenant_domains=filter_tenant_domains,
|
||||
filter_plan_ids=filter_plan_ids,
|
||||
statuses=statuses,
|
||||
sort_by=sort_by,
|
||||
sort_order=sort_order,
|
||||
)
|
||||
+15
-3
@@ -121,7 +121,13 @@ def list_users(
|
||||
page: int = Query(1, ge=1, description="Page number"),
|
||||
page_size: int = Query(10, ge=1, le=100, description="Items per page"),
|
||||
search: Optional[str] = Query(None, description="Search in email, name, phone, or ID"),
|
||||
status: Optional[str] = Query(None, description="Filter by user status (e.g. active, inactive)"),
|
||||
filter_names: Optional[List[str]] = Query(None, description="Filter by full names"),
|
||||
filter_emails: Optional[List[str]] = Query(None, description="Filter by emails"),
|
||||
statuses: Optional[List[str]] = Query(None, description="Filter by user statuses"),
|
||||
filter_tenant_ids: Optional[List[uuid.UUID]] = Query(None, description="Filter by tenant IDs"),
|
||||
filter_role_ids: Optional[List[uuid.UUID]] = Query(None, description="Filter by role IDs"),
|
||||
sort_by: Optional[str] = Query(None, description="Sort by name, email, status, tenant, or role"),
|
||||
sort_order: Optional[str] = Query(None, description="Sort order: asc or desc"),
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user),
|
||||
_ = Depends(require_access("admin.user.read")),
|
||||
@@ -132,5 +138,11 @@ def list_users(
|
||||
page=page,
|
||||
page_size=page_size,
|
||||
search=search,
|
||||
status=status,
|
||||
)
|
||||
filter_names=filter_names,
|
||||
filter_emails=filter_emails,
|
||||
statuses=statuses,
|
||||
filter_tenant_ids=filter_tenant_ids,
|
||||
filter_role_ids=filter_role_ids,
|
||||
sort_by=sort_by,
|
||||
sort_order=sort_order,
|
||||
)
|
||||
|
||||
@@ -3,7 +3,7 @@ import json
|
||||
import logging
|
||||
from typing import List, Optional
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy import or_, cast, String
|
||||
from sqlalchemy import or_, cast, String, asc, desc
|
||||
from fastapi import HTTPException, status
|
||||
from app.models.auth.role_model import Role
|
||||
from app.models.auth.role_access_model import RoleAccess
|
||||
@@ -313,6 +313,10 @@ class RoleService:
|
||||
page: int = 1,
|
||||
page_size: int = 10,
|
||||
search: Optional[str] = None,
|
||||
filter_role_names: Optional[List[str]] = None,
|
||||
filter_tenant_ids: Optional[List[uuid.UUID]] = None,
|
||||
sort_by: Optional[str] = None,
|
||||
sort_order: Optional[str] = None,
|
||||
) -> RolePaginatedResponse:
|
||||
|
||||
query = db.query(Role)
|
||||
@@ -320,6 +324,12 @@ class RoleService:
|
||||
if tenant_id is not None:
|
||||
query = query.filter(Role.tenant_id == tenant_id)
|
||||
|
||||
if filter_role_names:
|
||||
query = query.filter(Role.role_name.in_(filter_role_names))
|
||||
|
||||
if filter_tenant_ids:
|
||||
query = query.filter(Role.tenant_id.in_(filter_tenant_ids))
|
||||
|
||||
if search and search.strip():
|
||||
search_term = search.strip()
|
||||
query = query.filter(
|
||||
@@ -329,6 +339,15 @@ class RoleService:
|
||||
)
|
||||
)
|
||||
|
||||
sort_column_map = {
|
||||
"name": Role.role_name,
|
||||
"tenant": Role.tenant_id,
|
||||
}
|
||||
sort_column = sort_column_map.get(sort_by or "")
|
||||
if sort_column is not None:
|
||||
order_fn = desc if (sort_order or "").lower() == "desc" else asc
|
||||
query = query.order_by(order_fn(sort_column))
|
||||
|
||||
total = query.count()
|
||||
|
||||
offset = (page - 1) * page_size
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import uuid
|
||||
from typing import Optional
|
||||
from typing import List, Optional
|
||||
from sqlalchemy.orm import Session, joinedload
|
||||
from sqlalchemy import or_, cast, String
|
||||
from sqlalchemy import or_, cast, String, asc, desc
|
||||
from fastapi import HTTPException, status
|
||||
|
||||
from app.models.auth.subscription_plan_model import SubscriptionPlan
|
||||
@@ -103,8 +103,28 @@ class SubscriptionPlanService:
|
||||
return query.all()
|
||||
|
||||
@staticmethod
|
||||
def get_paginated_plans(db: Session, page: int = 1, page_size: int = 10, search: Optional[str] = None) -> SubscriptionPlanPaginatedResponse:
|
||||
def get_paginated_plans(
|
||||
db: Session,
|
||||
page: int = 1,
|
||||
page_size: int = 10,
|
||||
search: Optional[str] = None,
|
||||
filter_names: Optional[List[str]] = None,
|
||||
statuses: Optional[List[str]] = None,
|
||||
visibility: Optional[List[bool]] = None,
|
||||
sort_by: Optional[str] = None,
|
||||
sort_order: Optional[str] = None,
|
||||
) -> SubscriptionPlanPaginatedResponse:
|
||||
query = db.query(SubscriptionPlan)
|
||||
|
||||
if filter_names:
|
||||
query = query.filter(SubscriptionPlan.name.in_(filter_names))
|
||||
|
||||
if statuses:
|
||||
query = query.filter(SubscriptionPlan.status.in_(statuses))
|
||||
|
||||
if visibility is not None and len(visibility) > 0:
|
||||
query = query.filter(SubscriptionPlan.is_public.in_(visibility))
|
||||
|
||||
if search:
|
||||
query = query.filter(
|
||||
or_(
|
||||
@@ -112,6 +132,18 @@ class SubscriptionPlanService:
|
||||
cast(SubscriptionPlan.id, String).ilike(f"%{search}%")
|
||||
)
|
||||
)
|
||||
|
||||
sort_column_map = {
|
||||
"name": SubscriptionPlan.name,
|
||||
"price": SubscriptionPlan.price,
|
||||
"status": SubscriptionPlan.status,
|
||||
"visibility": SubscriptionPlan.is_public,
|
||||
}
|
||||
sort_column = sort_column_map.get(sort_by or "")
|
||||
if sort_column is not None:
|
||||
order_fn = desc if (sort_order or "").lower() == "desc" else asc
|
||||
query = query.order_by(order_fn(sort_column))
|
||||
|
||||
total = query.count()
|
||||
offset = (page - 1) * page_size
|
||||
plans = query.offset(offset).limit(page_size).all()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy import or_, cast, String
|
||||
from sqlalchemy import or_, cast, String, asc, desc
|
||||
from fastapi import HTTPException, status
|
||||
from app.models.auth.tenant_model import Tenant
|
||||
from app.models.auth.tenant_module_model import TenantModule
|
||||
@@ -13,7 +13,7 @@ from app.schemas.auth.tenant_schema import TenantCreate, TenantUpdate, TenantPag
|
||||
from app.schemas.auth.role_schema import RoleCreate, RoleUpdate
|
||||
from app.services.auth.role_service import RoleService
|
||||
import uuid
|
||||
from typing import Optional
|
||||
from typing import List, Optional
|
||||
from app.services.auth.event_service import EventService
|
||||
import logging
|
||||
|
||||
@@ -411,10 +411,25 @@ class TenantService:
|
||||
page_size: int = 10,
|
||||
search: Optional[str] = None,
|
||||
is_active: Optional[bool] = None,
|
||||
filter_tenant_names: Optional[List[str]] = None,
|
||||
filter_tenant_domains: Optional[List[str]] = None,
|
||||
filter_plan_ids: Optional[List[uuid.UUID]] = None,
|
||||
statuses: Optional[List[bool]] = None,
|
||||
sort_by: Optional[str] = None,
|
||||
sort_order: Optional[str] = None,
|
||||
) -> TenantPaginatedResponse:
|
||||
|
||||
query = db.query(Tenant)
|
||||
|
||||
if filter_tenant_names:
|
||||
query = query.filter(Tenant.tenant_name.in_(filter_tenant_names))
|
||||
|
||||
if filter_tenant_domains:
|
||||
query = query.filter(Tenant.tenant_domain.in_(filter_tenant_domains))
|
||||
|
||||
if filter_plan_ids:
|
||||
query = query.filter(Tenant.plan_id.in_(filter_plan_ids))
|
||||
|
||||
if search and search.strip():
|
||||
search_term = search.strip()
|
||||
query = query.filter(
|
||||
@@ -428,6 +443,20 @@ class TenantService:
|
||||
if is_active is not None:
|
||||
query = query.filter(Tenant.is_active == is_active)
|
||||
|
||||
if statuses is not None and len(statuses) > 0:
|
||||
query = query.filter(Tenant.is_active.in_(statuses))
|
||||
|
||||
sort_column_map = {
|
||||
"name": Tenant.tenant_name,
|
||||
"domain": Tenant.tenant_domain,
|
||||
"status": Tenant.is_active,
|
||||
"plan": Tenant.plan_id,
|
||||
}
|
||||
sort_column = sort_column_map.get(sort_by or "")
|
||||
if sort_column is not None:
|
||||
order_fn = desc if (sort_order or "").lower() == "desc" else asc
|
||||
query = query.order_by(order_fn(sort_column))
|
||||
|
||||
total = query.count()
|
||||
|
||||
offset = (page - 1) * page_size
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy import or_, cast, String
|
||||
from sqlalchemy import or_, cast, String, asc, desc, func
|
||||
from fastapi import HTTPException, status, BackgroundTasks
|
||||
from datetime import datetime
|
||||
import uuid
|
||||
@@ -14,6 +14,7 @@ from app.models.auth.role_module_access_model import RoleModuleAccess
|
||||
from app.models.auth.module_access_model import ModuleAccess
|
||||
from app.models.auth.tenant_module_model import TenantModule
|
||||
from app.models.auth.role_model import Role
|
||||
from app.models.auth.tenant_model import Tenant
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -235,11 +236,17 @@ class UserService:
|
||||
page: int = 1,
|
||||
page_size: int = 10,
|
||||
search: Optional[str] = None,
|
||||
status: Optional[str] = None,
|
||||
filter_names: Optional[List[str]] = None,
|
||||
filter_emails: Optional[List[str]] = None,
|
||||
statuses: Optional[List[str]] = None,
|
||||
filter_tenant_ids: Optional[List[uuid.UUID]] = None,
|
||||
filter_role_ids: Optional[List[uuid.UUID]] = None,
|
||||
sort_by: Optional[str] = None,
|
||||
sort_order: Optional[str] = None,
|
||||
) -> UserPaginatedResponse:
|
||||
|
||||
query = db.query(User)
|
||||
query = db.query(User).outerjoin(Tenant, User.tenant_id == Tenant.id).outerjoin(Role, User.role_id == Role.id)
|
||||
|
||||
# Scope to tenant if not superadmin
|
||||
if tenant_id:
|
||||
query = query.filter(User.tenant_id == tenant_id)
|
||||
|
||||
@@ -256,8 +263,73 @@ class UserService:
|
||||
)
|
||||
)
|
||||
|
||||
if status is not None:
|
||||
query = query.filter(User.status == status)
|
||||
if filter_names:
|
||||
normalized_names = [name.strip() for name in filter_names if isinstance(name, str) and name.strip()]
|
||||
if normalized_names:
|
||||
query = query.filter(
|
||||
func.trim(
|
||||
func.concat(
|
||||
User.first_name,
|
||||
" ",
|
||||
func.coalesce(User.last_name, ""),
|
||||
)
|
||||
).in_(normalized_names)
|
||||
)
|
||||
|
||||
if filter_emails:
|
||||
normalized_emails = [email.strip() for email in filter_emails if isinstance(email, str) and email.strip()]
|
||||
if normalized_emails:
|
||||
query = query.filter(User.email.in_(normalized_emails))
|
||||
|
||||
if statuses:
|
||||
normalized_statuses = [status for status in statuses if status]
|
||||
if normalized_statuses:
|
||||
query = query.filter(User.status.in_(normalized_statuses))
|
||||
|
||||
if filter_tenant_ids:
|
||||
tenant_ids: List[uuid.UUID] = []
|
||||
for tenant_value in filter_tenant_ids:
|
||||
try:
|
||||
tenant_ids.append(
|
||||
tenant_value if isinstance(tenant_value, uuid.UUID) else uuid.UUID(str(tenant_value))
|
||||
)
|
||||
except (ValueError, AttributeError, TypeError):
|
||||
continue
|
||||
if tenant_ids:
|
||||
query = query.filter(User.tenant_id.in_(tenant_ids))
|
||||
|
||||
if filter_role_ids:
|
||||
role_ids: List[uuid.UUID] = []
|
||||
for role_value in filter_role_ids:
|
||||
try:
|
||||
role_ids.append(
|
||||
role_value if isinstance(role_value, uuid.UUID) else uuid.UUID(str(role_value))
|
||||
)
|
||||
except (ValueError, AttributeError, TypeError):
|
||||
continue
|
||||
if role_ids:
|
||||
query = query.filter(User.role_id.in_(role_ids))
|
||||
|
||||
normalized_sort_by = (sort_by or "").strip().lower()
|
||||
normalized_sort_order = (sort_order or "asc").strip().lower()
|
||||
sort_fn = desc if normalized_sort_order == "desc" else asc
|
||||
|
||||
if normalized_sort_by == "name":
|
||||
query = query.order_by(
|
||||
sort_fn(func.lower(User.first_name)),
|
||||
sort_fn(func.lower(func.coalesce(User.last_name, ""))),
|
||||
asc(User.email),
|
||||
)
|
||||
elif normalized_sort_by == "email":
|
||||
query = query.order_by(sort_fn(func.lower(User.email)))
|
||||
elif normalized_sort_by == "status":
|
||||
query = query.order_by(sort_fn(func.lower(User.status)), asc(User.email))
|
||||
elif normalized_sort_by == "tenant":
|
||||
query = query.order_by(sort_fn(func.lower(func.coalesce(Tenant.tenant_name, ""))), asc(User.email))
|
||||
elif normalized_sort_by == "role":
|
||||
query = query.order_by(sort_fn(func.lower(func.coalesce(Role.role_name, ""))), asc(User.email))
|
||||
else:
|
||||
query = query.order_by(desc(User.created_at))
|
||||
|
||||
total = query.count()
|
||||
|
||||
@@ -276,10 +348,6 @@ class UserService:
|
||||
|
||||
@staticmethod
|
||||
def _resolve_targets_for_role(db: Session, role_id: uuid.UUID, tenant_id: uuid.UUID = None) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
Helper to resolve which modules/envs a role targets.
|
||||
Mirrors logic in RoleService.
|
||||
"""
|
||||
active_modules = (
|
||||
db.query(ModuleAccess.module_id)
|
||||
.join(RoleModuleAccess, RoleModuleAccess.module_access_id == ModuleAccess.id)
|
||||
@@ -298,7 +366,7 @@ class UserService:
|
||||
tm_assignments = db.query(TenantModule).filter(
|
||||
TenantModule.tenant_id == tenant_id,
|
||||
TenantModule.module_id.in_(module_ids),
|
||||
TenantModule.is_active == True
|
||||
TenantModule.is_active == True
|
||||
).all()
|
||||
for tm in tm_assignments:
|
||||
env_map[str(tm.module_id)] = tm.assigned_environment_slug or "prod"
|
||||
|
||||
Reference in New Issue
Block a user