211 lines
6.9 KiB
Python
211 lines
6.9 KiB
Python
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()
|