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:
@@ -45,6 +45,7 @@ if TYPE_CHECKING:
|
||||
from pydantic import BaseModel
|
||||
|
||||
from app.modules.contracts.audit import AuditProviderProtocol
|
||||
from app.modules.contracts.cms import MediaUsageProviderProtocol
|
||||
from app.modules.contracts.features import FeatureProviderProtocol
|
||||
from app.modules.contracts.metrics import MetricsProviderProtocol
|
||||
from app.modules.contracts.widgets import DashboardWidgetProviderProtocol
|
||||
@@ -477,6 +478,14 @@ class ModuleDefinition:
|
||||
# The provider will be discovered by billing's FeatureAggregator service.
|
||||
feature_provider: "Callable[[], FeatureProviderProtocol] | None" = None
|
||||
|
||||
# =========================================================================
|
||||
# Media Usage Provider (Module-Driven Media Usage Tracking)
|
||||
# =========================================================================
|
||||
# Callable that returns a MediaUsageProviderProtocol implementation.
|
||||
# Modules that use media files (catalog, etc.) can register a provider
|
||||
# to report where media is being used.
|
||||
media_usage_provider: "Callable[[], MediaUsageProviderProtocol] | None" = None
|
||||
|
||||
# =========================================================================
|
||||
# Menu Item Methods (Legacy - uses menu_items dict of IDs)
|
||||
# =========================================================================
|
||||
@@ -929,6 +938,24 @@ class ModuleDefinition:
|
||||
return None
|
||||
return self.feature_provider()
|
||||
|
||||
# =========================================================================
|
||||
# Media Usage Provider Methods
|
||||
# =========================================================================
|
||||
|
||||
def has_media_usage_provider(self) -> bool:
|
||||
"""Check if this module has a media usage provider."""
|
||||
return self.media_usage_provider is not None
|
||||
|
||||
def get_media_usage_provider_instance(self) -> "MediaUsageProviderProtocol | None":
|
||||
"""Get the media usage provider instance for this module.
|
||||
|
||||
Returns:
|
||||
MediaUsageProviderProtocol instance, or None
|
||||
"""
|
||||
if self.media_usage_provider is None:
|
||||
return None
|
||||
return self.media_usage_provider()
|
||||
|
||||
# =========================================================================
|
||||
# Magic Methods
|
||||
# =========================================================================
|
||||
|
||||
Reference in New Issue
Block a user