import httpx from fastapi_async_sqlalchemy import db from sqlalchemy import and_, func, select from datetime import datetime from app.models import MapsetModel, OrganizationModel from app.core.config import settings class CountService: GEONETWORK_API_URL = settings.GEONETWORK_API_URL async def _get_metadata_count(self) -> int: """ Fetch metadata count from GeoNetwork API. Returns the total count from hits.total.value """ try: timeout = httpx.Timeout(30.0) request_body = { "size": 0, "track_total_hits": True, "query": { "bool": { "must": { "query_string": { "query": "+isTemplate:n" } } } }, "aggs": { "resourceType": { "terms": { "field": "resourceType", "size": 10 } } } } async with httpx.AsyncClient(timeout=timeout) as client: response = await client.post( self.GEONETWORK_API_URL, json=request_body, headers={ "Content-Type": "application/json", "Accept": "application/json", }, ) response.raise_for_status() data = response.json() return data.get("hits", {}).get("total", {}).get("value", 0) except Exception: # Return 0 if API call fails return 0 async def get_counts(self) -> dict: """ Return total counts for mapsets, organizations, and metadata from database and external API. Visitor count is set to 0 for now. """ # Count mapsets with filters: is_deleted=False, is_active=True, status_validation='approved' mapset_query = select(func.count()).select_from(MapsetModel).where( and_( MapsetModel.is_deleted.is_(False), MapsetModel.is_active.is_(True), MapsetModel.status_validation == "approved", ) ) # Sum download_count from mapsets with the same filters download_count_query = select(func.sum(MapsetModel.download_count)).select_from(MapsetModel).where( and_( MapsetModel.is_deleted.is_(False), MapsetModel.is_active.is_(True), MapsetModel.status_validation == "approved", ) ) # Sum view_count from mapsets with the same filters visitor_count_query = select(func.sum(MapsetModel.view_count)).select_from(MapsetModel).where( and_( MapsetModel.is_deleted.is_(False), MapsetModel.is_active.is_(True), MapsetModel.status_validation == "approved", ) ) # Count organizations that have mapsets # Only count organizations that have at least one mapset with the specified filters organization_query = ( select(func.count(func.distinct(OrganizationModel.id))) .select_from(OrganizationModel) .join(MapsetModel, OrganizationModel.id == MapsetModel.producer_id) .where( and_( OrganizationModel.is_deleted.is_(False), OrganizationModel.is_active.is_(True), MapsetModel.is_deleted.is_(False), MapsetModel.is_active.is_(True), MapsetModel.status_validation == "approved", ) ) ) mapset_count = await db.session.scalar(mapset_query) or 0 download_count = await db.session.scalar(download_count_query) or 0 organization_count = await db.session.scalar(organization_query) or 0 metadata_count = await self._get_metadata_count() visitor_count = await db.session.scalar(visitor_count_query) or 0 return { "mapset_count": int(mapset_count), "organization_count": int(organization_count), "visitor_count": visitor_count, "metadata_count": int(metadata_count), "download_count": int(download_count), }