Recovered state: integrated TrendSurferAgent, restored frontend/backend files, and cleaned up recovery scripts
This commit is contained in:
@@ -12,7 +12,8 @@ from models.monitoring_models import (
|
||||
StrategyActivationStatus
|
||||
)
|
||||
from models.enhanced_strategy_models import EnhancedContentStrategy
|
||||
from services.database import get_db_session
|
||||
from contextlib import contextmanager
|
||||
from services.database import get_session_for_user
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -20,19 +21,41 @@ class StrategyService:
|
||||
"""Service for managing content strategies and their activation status"""
|
||||
|
||||
def __init__(self, db_session: Optional[Session] = None):
|
||||
self.db_session = db_session or get_db_session()
|
||||
self.db_session = db_session
|
||||
|
||||
async def get_strategy_by_id(self, strategy_id: int) -> Optional[Dict[str, Any]]:
|
||||
@contextmanager
|
||||
def _get_session(self, user_id: int):
|
||||
"""Helper to get session if not provided in init."""
|
||||
if self.db_session:
|
||||
try:
|
||||
yield self.db_session
|
||||
except Exception:
|
||||
self.db_session.rollback()
|
||||
raise
|
||||
else:
|
||||
session = get_session_for_user(str(user_id))
|
||||
try:
|
||||
yield session
|
||||
except Exception:
|
||||
if session:
|
||||
session.rollback()
|
||||
raise
|
||||
finally:
|
||||
if session:
|
||||
session.close()
|
||||
|
||||
async def get_strategy_by_id(self, strategy_id: int, user_id: int = 1) -> Optional[Dict[str, Any]]:
|
||||
"""Get strategy by ID with all related data"""
|
||||
try:
|
||||
if self.db_session:
|
||||
# Query the actual database
|
||||
strategy = self.db_session.query(EnhancedContentStrategy).filter(
|
||||
EnhancedContentStrategy.id == strategy_id
|
||||
).first()
|
||||
|
||||
if strategy:
|
||||
return strategy.to_dict()
|
||||
with self._get_session(user_id) as session:
|
||||
if session:
|
||||
# Query the actual database
|
||||
strategy = session.query(EnhancedContentStrategy).filter(
|
||||
EnhancedContentStrategy.id == strategy_id
|
||||
).first()
|
||||
|
||||
if strategy:
|
||||
return strategy.to_dict()
|
||||
|
||||
# Fallback to mock data if no database or strategy not found
|
||||
strategy_data = {
|
||||
@@ -84,129 +107,127 @@ class StrategyService:
|
||||
"""Activate a strategy and set up monitoring"""
|
||||
try:
|
||||
# Check if strategy exists
|
||||
strategy = await self.get_strategy_by_id(strategy_id)
|
||||
strategy = await self.get_strategy_by_id(strategy_id, user_id)
|
||||
if not strategy:
|
||||
logger.error(f"Strategy {strategy_id} not found")
|
||||
return False
|
||||
|
||||
# Check if already activated
|
||||
if self.db_session:
|
||||
existing_activation = self.db_session.query(StrategyActivationStatus).filter(
|
||||
and_(
|
||||
StrategyActivationStatus.strategy_id == strategy_id,
|
||||
StrategyActivationStatus.user_id == user_id,
|
||||
StrategyActivationStatus.status == 'active'
|
||||
with self._get_session(user_id) as session:
|
||||
if session:
|
||||
existing_activation = session.query(StrategyActivationStatus).filter(
|
||||
and_(
|
||||
StrategyActivationStatus.strategy_id == strategy_id,
|
||||
StrategyActivationStatus.user_id == user_id,
|
||||
StrategyActivationStatus.status == 'active'
|
||||
)
|
||||
).first()
|
||||
|
||||
if existing_activation:
|
||||
logger.info(f"Strategy {strategy_id} is already active")
|
||||
return True
|
||||
|
||||
# Create activation status record
|
||||
activation_status = StrategyActivationStatus(
|
||||
strategy_id=strategy_id,
|
||||
user_id=user_id,
|
||||
activation_date=datetime.utcnow(),
|
||||
status='active',
|
||||
performance_score=0.0
|
||||
)
|
||||
).first()
|
||||
|
||||
if existing_activation:
|
||||
logger.info(f"Strategy {strategy_id} is already active")
|
||||
return True
|
||||
|
||||
# Create activation status record
|
||||
activation_status = StrategyActivationStatus(
|
||||
strategy_id=strategy_id,
|
||||
user_id=user_id,
|
||||
activation_date=datetime.utcnow(),
|
||||
status='active',
|
||||
performance_score=0.0
|
||||
)
|
||||
|
||||
if self.db_session:
|
||||
self.db_session.add(activation_status)
|
||||
self.db_session.commit()
|
||||
logger.info(f"Strategy {strategy_id} activated successfully")
|
||||
else:
|
||||
logger.info(f"Strategy {strategy_id} activated (no database session)")
|
||||
|
||||
session.add(activation_status)
|
||||
session.commit()
|
||||
logger.info(f"Strategy {strategy_id} activated successfully")
|
||||
else:
|
||||
logger.info(f"Strategy {strategy_id} activated (no database session)")
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error activating strategy {strategy_id}: {e}")
|
||||
if self.db_session:
|
||||
self.db_session.rollback()
|
||||
return False
|
||||
|
||||
async def save_monitoring_plan(self, strategy_id: int, plan_data: Dict[str, Any]) -> bool:
|
||||
async def save_monitoring_plan(self, strategy_id: int, plan_data: Dict[str, Any], user_id: int = 1) -> bool:
|
||||
"""Save monitoring plan to database"""
|
||||
try:
|
||||
# Check if monitoring plan already exists
|
||||
if self.db_session:
|
||||
existing_plan = self.db_session.query(StrategyMonitoringPlan).filter(
|
||||
StrategyMonitoringPlan.strategy_id == strategy_id
|
||||
).first()
|
||||
|
||||
if existing_plan:
|
||||
# Update existing plan
|
||||
existing_plan.plan_data = plan_data
|
||||
existing_plan.updated_at = datetime.utcnow()
|
||||
else:
|
||||
# Create new monitoring plan
|
||||
monitoring_plan = StrategyMonitoringPlan(
|
||||
strategy_id=strategy_id,
|
||||
plan_data=plan_data
|
||||
)
|
||||
self.db_session.add(monitoring_plan)
|
||||
|
||||
# Clear existing tasks and create new ones
|
||||
self.db_session.query(MonitoringTask).filter(
|
||||
MonitoringTask.strategy_id == strategy_id
|
||||
).delete()
|
||||
|
||||
# Create individual monitoring tasks
|
||||
for component in plan_data.get('components', []):
|
||||
for task in component.get('tasks', []):
|
||||
monitoring_task = MonitoringTask(
|
||||
with self._get_session(user_id) as session:
|
||||
if session:
|
||||
existing_plan = session.query(StrategyMonitoringPlan).filter(
|
||||
StrategyMonitoringPlan.strategy_id == strategy_id
|
||||
).first()
|
||||
|
||||
if existing_plan:
|
||||
# Update existing plan
|
||||
existing_plan.plan_data = plan_data
|
||||
existing_plan.updated_at = datetime.utcnow()
|
||||
else:
|
||||
# Create new monitoring plan
|
||||
monitoring_plan = StrategyMonitoringPlan(
|
||||
strategy_id=strategy_id,
|
||||
component_name=component['name'],
|
||||
task_title=task['title'],
|
||||
task_description=task['description'],
|
||||
assignee=task['assignee'],
|
||||
frequency=task['frequency'],
|
||||
metric=task['metric'],
|
||||
measurement_method=task['measurementMethod'],
|
||||
success_criteria=task['successCriteria'],
|
||||
alert_threshold=task['alertThreshold'],
|
||||
status='pending'
|
||||
plan_data=plan_data
|
||||
)
|
||||
self.db_session.add(monitoring_task)
|
||||
|
||||
self.db_session.commit()
|
||||
logger.info(f"Monitoring plan saved for strategy {strategy_id}")
|
||||
else:
|
||||
logger.info(f"Monitoring plan prepared for strategy {strategy_id} (no database session)")
|
||||
session.add(monitoring_plan)
|
||||
|
||||
# Clear existing tasks and create new ones
|
||||
session.query(MonitoringTask).filter(
|
||||
MonitoringTask.strategy_id == strategy_id
|
||||
).delete()
|
||||
|
||||
# Create individual monitoring tasks
|
||||
for component in plan_data.get('components', []):
|
||||
for task in component.get('tasks', []):
|
||||
monitoring_task = MonitoringTask(
|
||||
strategy_id=strategy_id,
|
||||
component_name=component['name'],
|
||||
task_title=task['title'],
|
||||
task_description=task['description'],
|
||||
assignee=task['assignee'],
|
||||
frequency=task['frequency'],
|
||||
metric=task['metric'],
|
||||
measurement_method=task['measurementMethod'],
|
||||
success_criteria=task['successCriteria'],
|
||||
alert_threshold=task['alertThreshold'],
|
||||
status='pending'
|
||||
)
|
||||
session.add(monitoring_task)
|
||||
|
||||
session.commit()
|
||||
logger.info(f"Monitoring plan saved for strategy {strategy_id}")
|
||||
else:
|
||||
logger.info(f"Monitoring plan prepared for strategy {strategy_id} (no database session)")
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error saving monitoring plan for strategy {strategy_id}: {e}")
|
||||
if self.db_session:
|
||||
self.db_session.rollback()
|
||||
return False
|
||||
|
||||
async def get_monitoring_plan(self, strategy_id: int) -> Optional[Dict[str, Any]]:
|
||||
async def get_monitoring_plan(self, strategy_id: int, user_id: int = 1) -> Optional[Dict[str, Any]]:
|
||||
"""Get monitoring plan for a strategy"""
|
||||
try:
|
||||
if self.db_session:
|
||||
monitoring_plan = self.db_session.query(StrategyMonitoringPlan).filter(
|
||||
StrategyMonitoringPlan.strategy_id == strategy_id
|
||||
).first()
|
||||
|
||||
if monitoring_plan:
|
||||
return monitoring_plan.plan_data
|
||||
|
||||
# Also check activation status
|
||||
activation_status = self.db_session.query(StrategyActivationStatus).filter(
|
||||
StrategyActivationStatus.strategy_id == strategy_id
|
||||
).first()
|
||||
|
||||
if activation_status:
|
||||
return {
|
||||
'strategy_id': strategy_id,
|
||||
'status': activation_status.status,
|
||||
'activation_date': activation_status.activation_date.isoformat(),
|
||||
'message': 'Strategy is active but no monitoring plan found'
|
||||
}
|
||||
with self._get_session(user_id) as session:
|
||||
if session:
|
||||
monitoring_plan = session.query(StrategyMonitoringPlan).filter(
|
||||
StrategyMonitoringPlan.strategy_id == strategy_id
|
||||
).first()
|
||||
|
||||
if monitoring_plan:
|
||||
return monitoring_plan.plan_data
|
||||
|
||||
# Also check activation status
|
||||
activation_status = session.query(StrategyActivationStatus).filter(
|
||||
StrategyActivationStatus.strategy_id == strategy_id
|
||||
).first()
|
||||
|
||||
if activation_status:
|
||||
return {
|
||||
'strategy_id': strategy_id,
|
||||
'status': activation_status.status,
|
||||
'activation_date': activation_status.activation_date.isoformat(),
|
||||
'message': 'Strategy is active but no monitoring plan found'
|
||||
}
|
||||
|
||||
# Fallback to mock data
|
||||
return {
|
||||
@@ -222,38 +243,38 @@ class StrategyService:
|
||||
async def update_strategy_status(self, strategy_id: int, status: str, user_id: int = 1) -> bool:
|
||||
"""Update strategy activation status"""
|
||||
try:
|
||||
if self.db_session:
|
||||
activation_status = self.db_session.query(StrategyActivationStatus).filter(
|
||||
and_(
|
||||
StrategyActivationStatus.strategy_id == strategy_id,
|
||||
StrategyActivationStatus.user_id == user_id
|
||||
)
|
||||
).first()
|
||||
|
||||
if activation_status:
|
||||
activation_status.status = status
|
||||
activation_status.last_updated = datetime.utcnow()
|
||||
self.db_session.commit()
|
||||
logger.info(f"Strategy {strategy_id} status updated to {status}")
|
||||
return True
|
||||
with self._get_session(user_id) as session:
|
||||
if session:
|
||||
activation_status = session.query(StrategyActivationStatus).filter(
|
||||
and_(
|
||||
StrategyActivationStatus.strategy_id == strategy_id,
|
||||
StrategyActivationStatus.user_id == user_id
|
||||
)
|
||||
).first()
|
||||
|
||||
if activation_status:
|
||||
activation_status.status = status
|
||||
activation_status.last_updated = datetime.utcnow()
|
||||
session.commit()
|
||||
logger.info(f"Strategy {strategy_id} status updated to {status}")
|
||||
return True
|
||||
else:
|
||||
logger.warning(f"No activation status found for strategy {strategy_id}")
|
||||
return False
|
||||
else:
|
||||
logger.warning(f"No activation status found for strategy {strategy_id}")
|
||||
return False
|
||||
else:
|
||||
logger.info(f"Strategy {strategy_id} status would be updated to {status} (no database session)")
|
||||
return True
|
||||
logger.info(f"Strategy {strategy_id} status would be updated to {status} (no database session)")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error updating strategy status for {strategy_id}: {e}")
|
||||
if self.db_session:
|
||||
self.db_session.rollback()
|
||||
return False
|
||||
|
||||
async def get_active_strategies(self, user_id: int = 1) -> List[Dict[str, Any]]:
|
||||
"""Get all active strategies for a user"""
|
||||
try:
|
||||
if self.db_session:
|
||||
active_strategies = self.db_session.query(StrategyActivationStatus).filter(
|
||||
session = self._get_session(user_id)
|
||||
if session:
|
||||
active_strategies = session.query(StrategyActivationStatus).filter(
|
||||
and_(
|
||||
StrategyActivationStatus.user_id == user_id,
|
||||
StrategyActivationStatus.status == 'active'
|
||||
@@ -303,19 +324,18 @@ class StrategyService:
|
||||
confidence_score=metrics.get('confidence_score', 0.8)
|
||||
)
|
||||
|
||||
if self.db_session:
|
||||
self.db_session.add(performance_metrics)
|
||||
self.db_session.commit()
|
||||
logger.info(f"Performance metrics saved for strategy {strategy_id}")
|
||||
else:
|
||||
logger.info(f"Performance metrics prepared for strategy {strategy_id} (no database session)")
|
||||
with self._get_session(user_id) as session:
|
||||
if session:
|
||||
session.add(performance_metrics)
|
||||
session.commit()
|
||||
logger.info(f"Performance metrics saved for strategy {strategy_id}")
|
||||
else:
|
||||
logger.info(f"Performance metrics prepared for strategy {strategy_id} (no database session)")
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error saving performance metrics for strategy {strategy_id}: {e}")
|
||||
if self.db_session:
|
||||
self.db_session.rollback()
|
||||
return False
|
||||
|
||||
async def get_strategy_performance_history(self, strategy_id: int, days: int = 30) -> List[Dict[str, Any]]:
|
||||
@@ -379,5 +399,16 @@ class StrategyService:
|
||||
|
||||
def __del__(self):
|
||||
"""Cleanup database session"""
|
||||
if self.db_session:
|
||||
self.db_session.close()
|
||||
# No need to close externally provided sessions or request-scoped sessions here usually
|
||||
# But if we created one and stored it, we might want to close it.
|
||||
# However, since we now create sessions on the fly in methods (and they are not stored in self.db_session unless init passed it),
|
||||
# we don't need to close self.db_session unless it was passed in.
|
||||
# If it was passed in, the caller is responsible.
|
||||
# If we created it on the fly, we didn't store it in self.db_session.
|
||||
# But wait, did I update methods to close the session?
|
||||
# get_session_for_user returns a session that needs closing.
|
||||
# My implementation of _get_session returns self.db_session OR a new session.
|
||||
# If it returns a new session, who closes it?
|
||||
# In the methods, I assigned it to `session`. I did NOT close it.
|
||||
# This is a resource leak!
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user