# app/services/admin_service.py """Summary description .... This module provides classes and functions for: - .... - .... - .... """ import logging from datetime import datetime from typing import List, Optional, Tuple from fastapi import HTTPException from sqlalchemy.orm import Session from models.api_models import MarketplaceImportJobResponse from models.database_models import MarketplaceImportJob, Shop, User logger = logging.getLogger(__name__) class AdminService: """Service class for admin operations following the application's service pattern.""" def get_all_users(self, db: Session, skip: int = 0, limit: int = 100) -> List[User]: """Get paginated list of all users.""" return db.query(User).offset(skip).limit(limit).all() def toggle_user_status( self, db: Session, user_id: int, current_admin_id: int ) -> Tuple[User, str]: """ Toggle user active status. Args: db: Database session user_id: ID of user to toggle current_admin_id: ID of the admin performing the action Returns: Tuple of (updated_user, status_message) Raises: HTTPException: If user not found or trying to deactivate own account """ user = db.query(User).filter(User.id == user_id).first() if not user: raise HTTPException(status_code=404, detail="User not found") if user.id == current_admin_id: raise HTTPException( status_code=400, detail="Cannot deactivate your own account" ) user.is_active = not user.is_active user.updated_at = datetime.utcnow() db.commit() db.refresh(user) status = "activated" if user.is_active else "deactivated" logger.info( f"User {user.username} has been {status} by admin {current_admin_id}" ) return user, f"User {user.username} has been {status}" def get_all_shops( self, db: Session, skip: int = 0, limit: int = 100 ) -> Tuple[List[Shop], int]: """ Get paginated list of all shops with total count. Args: db: Database session skip: Number of records to skip limit: Maximum number of records to return Returns: Tuple of (shops_list, total_count) """ total = db.query(Shop).count() shops = db.query(Shop).offset(skip).limit(limit).all() return shops, total def verify_shop(self, db: Session, shop_id: int) -> Tuple[Shop, str]: """ Toggle shop verification status. Args: db: Database session shop_id: ID of shop to verify/unverify Returns: Tuple of (updated_shop, status_message) Raises: HTTPException: If shop not found """ shop = db.query(Shop).filter(Shop.id == shop_id).first() if not shop: raise HTTPException(status_code=404, detail="Shop not found") shop.is_verified = not shop.is_verified shop.updated_at = datetime.utcnow() db.commit() db.refresh(shop) status = "verified" if shop.is_verified else "unverified" logger.info(f"Shop {shop.shop_code} has been {status}") return shop, f"Shop {shop.shop_code} has been {status}" def toggle_shop_status(self, db: Session, shop_id: int) -> Tuple[Shop, str]: """ Toggle shop active status. Args: db: Database session shop_id: ID of shop to activate/deactivate Returns: Tuple of (updated_shop, status_message) Raises: HTTPException: If shop not found """ shop = db.query(Shop).filter(Shop.id == shop_id).first() if not shop: raise HTTPException(status_code=404, detail="Shop not found") shop.is_active = not shop.is_active shop.updated_at = datetime.utcnow() db.commit() db.refresh(shop) status = "activated" if shop.is_active else "deactivated" logger.info(f"Shop {shop.shop_code} has been {status}") return shop, f"Shop {shop.shop_code} has been {status}" def get_marketplace_import_jobs( self, db: Session, marketplace: Optional[str] = None, shop_name: Optional[str] = None, status: Optional[str] = None, skip: int = 0, limit: int = 100, ) -> List[MarketplaceImportJobResponse]: """ Get filtered and paginated marketplace import jobs. Args: db: Database session marketplace: Filter by marketplace name (case-insensitive partial match) shop_name: Filter by shop name (case-insensitive partial match) status: Filter by exact status skip: Number of records to skip limit: Maximum number of records to return Returns: List of MarketplaceImportJobResponse objects """ query = db.query(MarketplaceImportJob) # Apply filters if marketplace: query = query.filter( MarketplaceImportJob.marketplace.ilike(f"%{marketplace}%") ) if shop_name: query = query.filter(MarketplaceImportJob.shop_name.ilike(f"%{shop_name}%")) if status: query = query.filter(MarketplaceImportJob.status == status) # Order by creation date and apply pagination jobs = ( query.order_by(MarketplaceImportJob.created_at.desc()) .offset(skip) .limit(limit) .all() ) return [ MarketplaceImportJobResponse( job_id=job.id, status=job.status, marketplace=job.marketplace, shop_id=job.shop.id, shop_name=job.shop_name, imported=job.imported_count or 0, updated=job.updated_count or 0, total_processed=job.total_processed or 0, error_count=job.error_count or 0, error_message=job.error_message, created_at=job.created_at, started_at=job.started_at, completed_at=job.completed_at, ) for job in jobs ] def get_user_by_id(self, db: Session, user_id: int) -> Optional[User]: """Get user by ID.""" return db.query(User).filter(User.id == user_id).first() def get_shop_by_id(self, db: Session, shop_id: int) -> Optional[Shop]: """Get shop by ID.""" return db.query(Shop).filter(Shop.id == shop_id).first() def user_exists(self, db: Session, user_id: int) -> bool: """Check if user exists by ID.""" return db.query(User).filter(User.id == user_id).first() is not None def shop_exists(self, db: Session, shop_id: int) -> bool: """Check if shop exists by ID.""" return db.query(Shop).filter(Shop.id == shop_id).first() is not None # Create service instance following the same pattern as product_service admin_service = AdminService()