|
from flask import Blueprint, request, jsonify, current_app |
|
from flask_jwt_extended import jwt_required, get_jwt_identity |
|
from backend.services.schedule_service import ScheduleService |
|
from backend.celery_tasks.schedule_loader import load_schedules_task |
|
|
|
schedules_bp = Blueprint('schedules', __name__) |
|
|
|
@schedules_bp.route('/', methods=['OPTIONS']) |
|
@schedules_bp.route('', methods=['OPTIONS']) |
|
def handle_options(): |
|
"""Handle OPTIONS requests for preflight CORS checks.""" |
|
return '', 200 |
|
|
|
@schedules_bp.route('/', methods=['GET']) |
|
@schedules_bp.route('', methods=['GET']) |
|
@jwt_required() |
|
def get_schedules(): |
|
""" |
|
Get all schedules for the current user. |
|
|
|
Returns: |
|
JSON: List of schedules |
|
""" |
|
try: |
|
user_id = get_jwt_identity() |
|
print(f"[DEBUG] get_schedules called for user_id: {user_id}") |
|
|
|
|
|
if not hasattr(current_app, 'supabase') or current_app.supabase is None: |
|
print("[ERROR] Supabase client not initialized") |
|
|
|
response_data = jsonify({ |
|
'success': False, |
|
'message': 'Database connection not initialized' |
|
}) |
|
response_data.headers.add('Access-Control-Allow-Origin', 'http://localhost:3000') |
|
response_data.headers.add('Access-Control-Allow-Credentials', 'true') |
|
return response_data, 500 |
|
|
|
schedule_service = ScheduleService() |
|
schedules = schedule_service.get_user_schedules(user_id) |
|
print(f"[DEBUG] Found {len(schedules)} schedules for user {user_id}") |
|
|
|
|
|
response_data = jsonify({ |
|
'success': True, |
|
'schedules': schedules |
|
}) |
|
response_data.headers.add('Access-Control-Allow-Origin', 'http://localhost:3000') |
|
response_data.headers.add('Access-Control-Allow-Credentials', 'true') |
|
return response_data, 200 |
|
|
|
except Exception as e: |
|
print(f"[ERROR] Get schedules error: {str(e)}") |
|
import traceback |
|
print(f"[ERROR] Full traceback: {traceback.format_exc()}") |
|
current_app.logger.error(f"Get schedules error: {str(e)}") |
|
|
|
response_data = jsonify({ |
|
'success': False, |
|
'message': f'An error occurred while fetching schedules: {str(e)}', |
|
'schedules': [] |
|
}) |
|
response_data.headers.add('Access-Control-Allow-Origin', 'http://localhost:3000') |
|
response_data.headers.add('Access-Control-Allow-Credentials', 'true') |
|
return response_data, 500 |
|
|
|
@schedules_bp.route('/', methods=['POST']) |
|
@schedules_bp.route('', methods=['POST']) |
|
@jwt_required() |
|
def create_schedule(): |
|
""" |
|
Create a new schedule for the current user. |
|
|
|
Request Body: |
|
social_network (str): Social account ID |
|
schedule_time (str): Schedule time in format "HH:MM" |
|
days (List[str]): List of days to schedule |
|
|
|
Returns: |
|
JSON: Create schedule result |
|
""" |
|
try: |
|
user_id = get_jwt_identity() |
|
data = request.get_json() |
|
|
|
|
|
required_fields = ['social_network', 'schedule_time', 'days'] |
|
if not data or not all(k in data for k in required_fields): |
|
|
|
response_data = jsonify({ |
|
'success': False, |
|
'message': 'Social network, schedule time, and days are required' |
|
}) |
|
response_data.headers.add('Access-Control-Allow-Origin', 'http://localhost:3000') |
|
response_data.headers.add('Access-Control-Allow-Credentials', 'true') |
|
return response_data, 400 |
|
|
|
social_network = data['social_network'] |
|
schedule_time = data['schedule_time'] |
|
days = data['days'] |
|
|
|
|
|
valid_days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"] |
|
if not isinstance(days, list) or not all(day in valid_days for day in days): |
|
|
|
response_data = jsonify({ |
|
'success': False, |
|
'message': 'Days must be a list of valid day names' |
|
}) |
|
response_data.headers.add('Access-Control-Allow-Origin', 'http://localhost:3000') |
|
response_data.headers.add('Access-Control-Allow-Credentials', 'true') |
|
return response_data, 400 |
|
|
|
|
|
try: |
|
hour, minute = map(int, schedule_time.split(':')) |
|
if hour < 0 or hour > 23 or minute < 0 or minute > 59: |
|
raise ValueError |
|
except ValueError: |
|
|
|
response_data = jsonify({ |
|
'success': False, |
|
'message': 'Schedule time must be in format HH:MM (24-hour format)' |
|
}) |
|
response_data.headers.add('Access-Control-Allow-Origin', 'http://localhost:3000') |
|
response_data.headers.add('Access-Control-Allow-Credentials', 'true') |
|
return response_data, 400 |
|
|
|
|
|
schedule_service = ScheduleService() |
|
result = schedule_service.create_schedule(user_id, social_network, schedule_time, days) |
|
|
|
if result['success']: |
|
|
|
try: |
|
print("[INFO] Triggering immediate Celery Beat schedule update...") |
|
|
|
celery_result = load_schedules_task.delay() |
|
print(f"[INFO] Celery Beat update task queued: {celery_result.id}") |
|
|
|
|
|
result['celery_update_task_id'] = celery_result.id |
|
result['message'] += ' (Scheduler updated immediately)' |
|
except Exception as e: |
|
print(f"[WARNING] Failed to trigger immediate Celery update: {str(e)}") |
|
|
|
result['message'] += ' (Note: Scheduler update will occur in 5 minutes)' |
|
|
|
|
|
response_data = jsonify(result) |
|
response_data.headers.add('Access-Control-Allow-Origin', 'http://localhost:3000') |
|
response_data.headers.add('Access-Control-Allow-Credentials', 'true') |
|
return response_data, 201 |
|
else: |
|
|
|
response_data = jsonify(result) |
|
response_data.headers.add('Access-Control-Allow-Origin', 'http://localhost:3000') |
|
response_data.headers.add('Access-Control-Allow-Credentials', 'true') |
|
return response_data, 400 |
|
|
|
except Exception as e: |
|
current_app.logger.error(f"Create schedule error: {str(e)}") |
|
|
|
response_data = jsonify({ |
|
'success': False, |
|
'message': f'An error occurred while creating schedule: {str(e)}' |
|
}) |
|
response_data.headers.add('Access-Control-Allow-Origin', 'http://localhost:3000') |
|
response_data.headers.add('Access-Control-Allow-Credentials', 'true') |
|
return response_data, 500 |
|
|
|
@schedules_bp.route('/<schedule_id>', methods=['OPTIONS']) |
|
def handle_schedule_options(schedule_id): |
|
"""Handle OPTIONS requests for preflight CORS checks for specific schedule.""" |
|
return '', 200 |
|
|
|
@schedules_bp.route('/<schedule_id>', methods=['DELETE']) |
|
@jwt_required() |
|
def delete_schedule(schedule_id): |
|
""" |
|
Delete a schedule. |
|
|
|
Path Parameters: |
|
schedule_id (str): Schedule ID |
|
|
|
Returns: |
|
JSON: Delete schedule result |
|
""" |
|
try: |
|
user_id = get_jwt_identity() |
|
|
|
|
|
response = ( |
|
current_app.supabase |
|
.table("Scheduling") |
|
.select("Social_network(id_utilisateur)") |
|
.eq("id", schedule_id) |
|
.execute() |
|
) |
|
|
|
if not response.data: |
|
|
|
response_data = jsonify({ |
|
'success': False, |
|
'message': 'Schedule not found' |
|
}) |
|
response_data.headers.add('Access-Control-Allow-Origin', 'http://localhost:3000') |
|
response_data.headers.add('Access-Control-Allow-Credentials', 'true') |
|
return response_data, 404 |
|
|
|
schedule = response.data[0] |
|
if schedule.get('Social_network', {}).get('id_utilisateur') != user_id: |
|
|
|
response_data = jsonify({ |
|
'success': False, |
|
'message': 'Unauthorized to delete this schedule' |
|
}) |
|
response_data.headers.add('Access-Control-Allow-Origin', 'http://localhost:3000') |
|
response_data.headers.add('Access-Control-Allow-Credentials', 'true') |
|
return response_data, 403 |
|
|
|
|
|
schedule_service = ScheduleService() |
|
result = schedule_service.delete_schedule(schedule_id) |
|
|
|
if result['success']: |
|
|
|
try: |
|
print("[INFO] Triggering immediate Celery Beat schedule update after deletion...") |
|
|
|
celery_result = load_schedules_task.delay() |
|
print(f"[INFO] Celery Beat update task queued: {celery_result.id}") |
|
|
|
|
|
result['celery_update_task_id'] = celery_result.id |
|
result['message'] += ' (Scheduler updated immediately)' |
|
except Exception as e: |
|
print(f"[WARNING] Failed to trigger immediate Celery update: {str(e)}") |
|
|
|
result['message'] += ' (Note: Scheduler update will occur in 5 minutes)' |
|
|
|
|
|
response_data = jsonify(result) |
|
response_data.headers.add('Access-Control-Allow-Origin', 'http://localhost:3000') |
|
response_data.headers.add('Access-Control-Allow-Credentials', 'true') |
|
return response_data, 200 |
|
else: |
|
|
|
response_data = jsonify(result) |
|
response_data.headers.add('Access-Control-Allow-Origin', 'http://localhost:3000') |
|
response_data.headers.add('Access-Control-Allow-Credentials', 'true') |
|
return response_data, 404 |
|
|
|
except Exception as e: |
|
current_app.logger.error(f"Delete schedule error: {str(e)}") |
|
|
|
response_data = jsonify({ |
|
'success': False, |
|
'message': f'An error occurred while deleting schedule: {str(e)}' |
|
}) |
|
response_data.headers.add('Access-Control-Allow-Origin', 'http://localhost:3000') |
|
response_data.headers.add('Access-Control-Allow-Credentials', 'true') |
|
return response_data, 500 |