feat: consolidate media service, add merchant users page, fix metrics overlap
- Merge ImageService into MediaService with WebP variant generation, DB-backed storage stats, and module-driven media usage discovery via new MediaUsageProviderProtocol - Add merchant users admin page with scoped user listing, stats endpoint, template, JS, and i18n strings (de/en/fr/lb) - Fix merchant user metrics so Owners and Team Members are mutually exclusive (filter team_members on user_type="member" and exclude owner IDs) ensuring stat cards add up correctly - Update billing and monitoring services to use media_service - Update subscription-billing and feature-gating docs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -107,18 +107,31 @@ class AdminService:
|
||||
per_page: int = 10,
|
||||
search: str | None = None,
|
||||
role: str | None = None,
|
||||
scope: str | None = None,
|
||||
is_active: bool | None = None,
|
||||
) -> tuple[list[User], int, int]:
|
||||
"""
|
||||
Get paginated list of users with filtering.
|
||||
|
||||
Args:
|
||||
scope: Optional scope filter. 'merchant' returns users who are
|
||||
merchant owners or store team members.
|
||||
|
||||
Returns:
|
||||
Tuple of (users, total_count, total_pages)
|
||||
"""
|
||||
import math
|
||||
|
||||
from app.modules.tenancy.models import Merchant, StoreUser
|
||||
|
||||
query = db.query(User)
|
||||
|
||||
# Apply scope filter
|
||||
if scope == "merchant":
|
||||
owner_ids = db.query(Merchant.owner_user_id).distinct()
|
||||
team_ids = db.query(StoreUser.user_id).distinct()
|
||||
query = query.filter(User.id.in_(owner_ids.union(team_ids)))
|
||||
|
||||
# Apply filters
|
||||
if search:
|
||||
search_term = f"%{search.lower()}%"
|
||||
|
||||
Reference in New Issue
Block a user