Refactoring code for modular approach
This commit is contained in:
202
app/services/marketplace_service.py
Normal file
202
app/services/marketplace_service.py
Normal file
@@ -0,0 +1,202 @@
|
||||
from sqlalchemy.orm import Session
|
||||
from models.database_models import MarketplaceImportJob, Shop, User
|
||||
from models.api_models import MarketplaceImportRequest, MarketplaceImportJobResponse
|
||||
from typing import Optional, List
|
||||
from datetime import datetime
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class MarketplaceService:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def validate_shop_access(self, db: Session, shop_code: str, user: User) -> Shop:
|
||||
"""Validate that the shop exists and user has access to it"""
|
||||
shop = db.query(Shop).filter(Shop.shop_code == shop_code).first()
|
||||
if not shop:
|
||||
raise ValueError("Shop not found")
|
||||
|
||||
# Check permissions: admin can import for any shop, others only for their own
|
||||
if user.role != "admin" and shop.owner_id != user.id:
|
||||
raise PermissionError("Access denied to this shop")
|
||||
|
||||
return shop
|
||||
|
||||
def create_import_job(
|
||||
self,
|
||||
db: Session,
|
||||
request: MarketplaceImportRequest,
|
||||
user: User
|
||||
) -> MarketplaceImportJob:
|
||||
"""Create a new marketplace import job"""
|
||||
# Validate shop access first
|
||||
shop = self.validate_shop_access(db, request.shop_code, user)
|
||||
|
||||
# Create marketplace import job record
|
||||
import_job = MarketplaceImportJob(
|
||||
status="pending",
|
||||
source_url=request.url,
|
||||
marketplace=request.marketplace,
|
||||
shop_code=request.shop_code,
|
||||
user_id=user.id,
|
||||
created_at=datetime.utcnow()
|
||||
)
|
||||
|
||||
db.add(import_job)
|
||||
db.commit()
|
||||
db.refresh(import_job)
|
||||
|
||||
logger.info(
|
||||
f"Created marketplace import job {import_job.id}: {request.marketplace} -> {request.shop_code} by user {user.username}")
|
||||
|
||||
return import_job
|
||||
|
||||
def get_import_job_by_id(self, db: Session, job_id: int, user: User) -> MarketplaceImportJob:
|
||||
"""Get a marketplace import job by ID with access control"""
|
||||
job = db.query(MarketplaceImportJob).filter(MarketplaceImportJob.id == job_id).first()
|
||||
if not job:
|
||||
raise ValueError("Marketplace import job not found")
|
||||
|
||||
# Users can only see their own jobs, admins can see all
|
||||
if user.role != "admin" and job.user_id != user.id:
|
||||
raise PermissionError("Access denied to this import job")
|
||||
|
||||
return job
|
||||
|
||||
def get_import_jobs(
|
||||
self,
|
||||
db: Session,
|
||||
user: User,
|
||||
marketplace: Optional[str] = None,
|
||||
shop_name: Optional[str] = None,
|
||||
skip: int = 0,
|
||||
limit: int = 50
|
||||
) -> List[MarketplaceImportJob]:
|
||||
"""Get marketplace import jobs with filtering and access control"""
|
||||
query = db.query(MarketplaceImportJob)
|
||||
|
||||
# Users can only see their own jobs, admins can see all
|
||||
if user.role != "admin":
|
||||
query = query.filter(MarketplaceImportJob.user_id == user.id)
|
||||
|
||||
# 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}%"))
|
||||
|
||||
# Order by creation date (newest first) and apply pagination
|
||||
jobs = query.order_by(MarketplaceImportJob.created_at.desc()).offset(skip).limit(limit).all()
|
||||
|
||||
return jobs
|
||||
|
||||
def update_job_status(
|
||||
self,
|
||||
db: Session,
|
||||
job_id: int,
|
||||
status: str,
|
||||
**kwargs
|
||||
) -> MarketplaceImportJob:
|
||||
"""Update marketplace import job status and other fields"""
|
||||
job = db.query(MarketplaceImportJob).filter(MarketplaceImportJob.id == job_id).first()
|
||||
if not job:
|
||||
raise ValueError("Marketplace import job not found")
|
||||
|
||||
job.status = status
|
||||
|
||||
# Update optional fields if provided
|
||||
if 'imported_count' in kwargs:
|
||||
job.imported_count = kwargs['imported_count']
|
||||
if 'updated_count' in kwargs:
|
||||
job.updated_count = kwargs['updated_count']
|
||||
if 'total_processed' in kwargs:
|
||||
job.total_processed = kwargs['total_processed']
|
||||
if 'error_count' in kwargs:
|
||||
job.error_count = kwargs['error_count']
|
||||
if 'error_message' in kwargs:
|
||||
job.error_message = kwargs['error_message']
|
||||
if 'started_at' in kwargs:
|
||||
job.started_at = kwargs['started_at']
|
||||
if 'completed_at' in kwargs:
|
||||
job.completed_at = kwargs['completed_at']
|
||||
|
||||
db.commit()
|
||||
db.refresh(job)
|
||||
|
||||
logger.info(f"Updated marketplace import job {job_id} status to {status}")
|
||||
return job
|
||||
|
||||
def get_job_stats(self, db: Session, user: User) -> dict:
|
||||
"""Get statistics about marketplace import jobs for a user"""
|
||||
query = db.query(MarketplaceImportJob)
|
||||
|
||||
# Users can only see their own jobs, admins can see all
|
||||
if user.role != "admin":
|
||||
query = query.filter(MarketplaceImportJob.user_id == user.id)
|
||||
|
||||
total_jobs = query.count()
|
||||
pending_jobs = query.filter(MarketplaceImportJob.status == "pending").count()
|
||||
running_jobs = query.filter(MarketplaceImportJob.status == "running").count()
|
||||
completed_jobs = query.filter(MarketplaceImportJob.status == "completed").count()
|
||||
failed_jobs = query.filter(MarketplaceImportJob.status == "failed").count()
|
||||
|
||||
return {
|
||||
"total_jobs": total_jobs,
|
||||
"pending_jobs": pending_jobs,
|
||||
"running_jobs": running_jobs,
|
||||
"completed_jobs": completed_jobs,
|
||||
"failed_jobs": failed_jobs
|
||||
}
|
||||
|
||||
def convert_to_response_model(self, job: MarketplaceImportJob) -> MarketplaceImportJobResponse:
|
||||
"""Convert database model to API response model"""
|
||||
return MarketplaceImportJobResponse(
|
||||
job_id=job.id,
|
||||
status=job.status,
|
||||
marketplace=job.marketplace,
|
||||
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
|
||||
)
|
||||
|
||||
def cancel_import_job(self, db: Session, job_id: int, user: User) -> MarketplaceImportJob:
|
||||
"""Cancel a pending or running import job"""
|
||||
job = self.get_import_job_by_id(db, job_id, user)
|
||||
|
||||
if job.status not in ["pending", "running"]:
|
||||
raise ValueError(f"Cannot cancel job with status: {job.status}")
|
||||
|
||||
job.status = "cancelled"
|
||||
job.completed_at = datetime.utcnow()
|
||||
|
||||
db.commit()
|
||||
db.refresh(job)
|
||||
|
||||
logger.info(f"Cancelled marketplace import job {job_id}")
|
||||
return job
|
||||
|
||||
def delete_import_job(self, db: Session, job_id: int, user: User) -> bool:
|
||||
"""Delete a marketplace import job"""
|
||||
job = self.get_import_job_by_id(db, job_id, user)
|
||||
|
||||
# Only allow deletion of completed, failed, or cancelled jobs
|
||||
if job.status in ["pending", "running"]:
|
||||
raise ValueError(f"Cannot delete job with status: {job.status}. Cancel it first.")
|
||||
|
||||
db.delete(job)
|
||||
db.commit()
|
||||
|
||||
logger.info(f"Deleted marketplace import job {job_id}")
|
||||
return True
|
||||
|
||||
|
||||
# Create service instance
|
||||
marketplace_service = MarketplaceService()
|
||||
Reference in New Issue
Block a user