Lin / backend /services /schedule_service.py
Zelyanoth's picture
fff
25f22bf
raw
history blame
8.32 kB
from flask import current_app
from datetime import datetime, timedelta
from typing import List, Dict
import pandas as pd
from models.schedule import Schedule
class ScheduleService:
"""Service for managing post scheduling."""
def __init__(self):
self.supabase = current_app.supabase
def get_user_schedules(self, user_id: str) -> List[Dict]:
"""
Get all schedules for a user.
Args:
user_id (str): User ID
Returns:
List[Dict]: List of schedules
"""
try:
response = (
self.supabase
.table("Scheduling")
.select("*, Social_network(id_utilisateur, social_network, account_name)")
.execute()
)
# Filter schedules for the user
schedules = []
for item in response.data:
if item.get('Social_network', {}).get('id_utilisateur') == user_id:
schedule = Schedule.from_dict({
'id': item['id'],
'social_account_id': item['id_social'],
'schedule_time': item['schedule_time'],
'adjusted_time': item['adjusted_time'],
'created_at': item['created_at']
})
schedules.append(schedule.to_dict())
return schedules
except Exception as e:
# Log the error for debugging
print(f"[ERROR] Failed to fetch schedules: {str(e)}")
# Return empty list instead of raising exception
return []
def create_schedule(self, user_id: str, social_network: str, schedule_time: str, days: List[str]) -> Dict:
"""
Create a new schedule.
Args:
user_id (str): User ID
social_network (str): Social account ID (as string)
schedule_time (str): Schedule time in format "HH:MM"
days (List[str]): List of days to schedule
Returns:
Dict: Created schedule
"""
try:
# Validate that social_network is a valid ID
if not social_network or not isinstance(social_network, str):
raise Exception("Invalid social account ID provided")
# Try to convert social_network to int for database query
try:
social_account_id = int(social_network)
except ValueError:
raise Exception(f"Invalid social account ID format: {social_network}. Expected a numeric ID.")
# Get social account - verify it belongs to the current user
account_response = (
self.supabase
.table("Social_network")
.select("id, id_utilisateur")
.eq("id", social_account_id)
.execute()
)
if not account_response.data:
raise Exception("Social account not found")
# Verify the account belongs to the current user
account = account_response.data[0]
if str(account.get('id_utilisateur')) != str(user_id):
raise Exception("Social account not found or unauthorized")
social_account_id = account['id']
# Create schedules for each day
created_schedules = []
for day in days:
# Format schedule time
formatted_schedule = f"{day} {schedule_time}"
# Calculate adjusted time (5 minutes before for content generation)
adjusted_time = self._calculate_adjusted_time(formatted_schedule)
# Insert schedule
response = (
self.supabase
.table("Scheduling")
.insert({
"id_social": social_account_id,
"schedule_time": formatted_schedule,
"adjusted_time": adjusted_time
})
.execute()
)
if response.data:
schedule = Schedule.from_dict({
'id': response.data[0]['id'],
'social_account_id': response.data[0]['id_social'],
'schedule_time': response.data[0]['schedule_time'],
'adjusted_time': response.data[0]['adjusted_time'],
'created_at': response.data[0]['created_at']
})
created_schedules.append(schedule.to_dict())
return {
'success': True,
'schedules': created_schedules,
'message': f'Schedule created successfully for {len(created_schedules)} day(s)'
}
except Exception as e:
raise Exception(f"Failed to create schedule: {str(e)}")
def delete_schedule(self, schedule_id: str) -> Dict:
"""
Delete a schedule.
Args:
schedule_id (str): Schedule ID
Returns:
Dict: Deletion result
"""
try:
response = (
self.supabase
.table("Scheduling")
.delete()
.eq("id", schedule_id)
.execute()
)
if response.data:
return {
'success': True,
'message': 'Schedule deleted successfully'
}
else:
return {
'success': False,
'message': 'Schedule not found'
}
except Exception as e:
raise Exception(f"Failed to delete schedule: {str(e)}")
def _calculate_adjusted_time(self, schedule_time: str) -> str:
"""
Calculate adjusted time for content generation (5 minutes before schedule).
Args:
schedule_time (str): Original schedule time
Returns:
str: Adjusted time
"""
# Parse schedule time
parts = schedule_time.strip().split()
if len(parts) != 2 or ':' not in parts[1]:
return schedule_time
day, time_part = parts
try:
hour, minute = map(int, time_part.split(':'))
# Subtract 5 minutes for content generation
adjusted_minute = minute - 5
adjusted_hour = hour
if adjusted_minute < 0:
adjusted_minute += 60
adjusted_hour -= 1
if adjusted_hour < 0:
adjusted_hour += 24
return f"{day} {adjusted_hour:02d}:{adjusted_minute:02d}"
except ValueError:
return schedule_time
def get_all_schedules(self) -> pd.DataFrame:
"""
Get all schedules for the scheduler.
Returns:
pd.DataFrame: DataFrame with all schedules
"""
try:
response = (
self.supabase
.table("Scheduling")
.select("*, Social_network(id_utilisateur, account_name)")
.execute()
)
# Normalize the data
data = response.data
df = pd.json_normalize(data)
if not df.empty:
df = df.rename(columns={
"Social_network.id_utilisateur": "user_id",
"Social_network.account_name": "social_network"
})
# Select relevant columns
cols = ["id", "id_social", "user_id", "schedule_time", "social_network", "adjusted_time", "created_at"]
df = df[[c for c in cols if c in df.columns]]
return df
except Exception as e:
raise Exception(f"Failed to fetch all schedules: {str(e)}")