import os os.environ["NUMBA_CACHE_DIR"] = "/tmp/numba_cache" os.environ["NUMBA_DISABLE_JIT"] = "1" from apscheduler.schedulers.background import BackgroundScheduler import requests import time import logging from flask import Flask, request, jsonify, send_file from flask_cors import CORS from predict import handle_predict from database import ( init_db, save_prediction, get_history, register_user, authenticate_user, get_user_profile, update_user_profile, get_farm_details_from_db, update_farm_details_in_db, get_farm_detailss_from_db, get_hives_from_db, get_hive_detail_from_db, add_hive_to_db, delete_hive_from_db, update_hive_health_in_db, add_task_to_db, get_user_tasks_from_db, get_task_detail_from_db, delete_task_from_db, update_task_status_to_completed, update_hive_in_db, generate_reset_code, verify_reset_code, update_user_password, change_user_password, get_all_notifications, add_notification, mark_notification_as_read, get_user_cities ) from forget import forgot_password, verify_reset_code_endpoint, reset_password from report import generate_report from datetime import datetime # Configure logging logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) app = Flask(__name__) app.secret_key = os.urandom(24) CORS(app) # Forgot password endpoint @app.route('/forgot_password', methods=['POST']) def forgot_password_endpoint(): return forgot_password(request) # Verify reset code endpoint @app.route('/verify_reset_code', methods=['POST']) def verify_reset_code_route(): return verify_reset_code_endpoint(request) # Reset password endpoint @app.route('/reset_password', methods=['POST']) def reset_password_endpoint(): return reset_password(request) @app.route('/change_password', methods=['POST']) def change_password(): data = request.json user_id = data.get('user_id') current_password = data.get('password') new_password = data.get('new_password') if not all([user_id, current_password, new_password]): return jsonify({"error": "Missing required fields"}), 400 result = change_user_password(user_id, current_password, new_password) if result: return jsonify({"message": "Password changed successfully"}), 200 return jsonify({"error": "Current password incorrect"}), 401 # Existing endpoints (unchanged) @app.route('/predict', methods=['POST']) def predict(): return handle_predict(request, save_prediction) @app.route('/signup', methods=['POST']) def signup(): data = request.json result = register_user(data['fullName'], data['email'], data['password']) if result == "email already exist": return jsonify({"message": result}), 215 return jsonify({"message": result}), 200 @app.route('/login', methods=['POST']) def login(): data = request.json result = authenticate_user(data['email'], data['password']) if "error" in result: return jsonify(result), 415 return jsonify(result), 200 @app.route('/profile', methods=['GET']) def profile(): user_id = request.args.get('user_id') return jsonify(get_user_profile(user_id)) @app.route('/profile/update', methods=['POST']) def update_profile(): data = request.json return jsonify(update_user_profile( data['user_id'], data['fullname'], data['country'], data['city'], data['gender'], data['phone_number'] )) @app.route('/history', methods=['GET']) def history(): user_id = request.args.get('user_id') return jsonify({"history": get_history(user_id)}) @app.route('/farm', methods=['GET']) def get_farm_details(): user_id = request.args.get('user_id') if not user_id: return jsonify({"error": "User ID is required"}), 400 farm = get_farm_details_from_db(user_id) return jsonify(farm) if farm else jsonify({"error": "Farm details not found"}), 404 @app.route('/farm/update', methods=['POST']) def update_farm(): data = request.json return jsonify(update_farm_details_in_db( data['user_id'], data['fullname'], data['country'], data['city'], data['zip'] )) @app.route('/farms', methods=['GET']) def get_farm(): user_id = request.args.get('user_id') if not user_id: return jsonify({"error": "User ID is required"}), 400 farm = get_farm_details_from_db(user_id) return jsonify(farm) if farm else jsonify({"error": "No farm registered"}), 404 @app.route('/hives', methods=['GET']) def get_hives(): farm_id = request.args.get('farm_id') if not farm_id: return jsonify({"error": "Farm ID is required"}), 400 hives = get_hives_from_db(farm_id) return jsonify(hives) @app.route('/hives', methods=['POST']) def add_hive(): data = request.json if not all(key in data for key in ['farm_id', 'hive_number', 'bee_type', 'number_of_frames', 'health_status']): return jsonify({"error": "Missing required fields"}), 400 try: hive_id = add_hive_to_db( data['farm_id'], data['hive_number'], data['bee_type'], data['number_of_frames'], data['health_status'], data.get('notes', '') ) return jsonify({"success": True, "hive_id": hive_id}), 201 except Exception as e: return jsonify({"error": str(e)}), 500 @app.route('/hives', methods=['DELETE']) def delete_hive(): hive_id = request.args.get('hive_id') if not hive_id: return jsonify({"error": "Hive ID is required"}), 400 try: deleted = delete_hive_from_db(hive_id) if deleted: return jsonify({"success": True}), 200 else: return jsonify({"error": "Hive not found"}), 404 except Exception as e: return jsonify({"error": str(e)}), 500 @app.route('/hive_detail', methods=['GET']) def get_hives_detail(): hive_id = request.args.get('hive_id') if not hive_id: return jsonify({"error": "Hive Id is required"}), 400 hivess = get_hive_detail_from_db(hive_id) return jsonify(hivess) @app.route('/manual_health_update', methods=['POST']) def update_hive_health(): data = request.json if not all(key in data for key in ['hive_id', 'health_status']): return jsonify({"error": "Missing required fields"}), 400 try: update_hive_health_in_db(data['hive_id'], data['health_status']) return jsonify({"success": True, "message": "Health status updated"}), 200 except Exception as e: return jsonify({"error": str(e)}), 500 @app.route('/edit_hive', methods=['POST']) def update_hive(): data = request.json if 'hive_id' not in data: return jsonify({"error": "hive_id is required"}), 400 update_data = {k: v for k, v in data.items() if k in {'hive_id', 'number_of_frames', 'bee_type', 'notes'}} if len(update_data) <= 1: return jsonify({"error": "No valid fields provided"}), 400 try: result = update_hive_in_db( update_data['hive_id'], update_data.get('number_of_frames'), update_data.get('bee_type'), update_data.get('notes') ) if not result: return jsonify({"error": "Hive not found"}), 404 return jsonify({"success": True, "hive_id": update_data['hive_id']}), 200 except Exception as e: return jsonify({"error": str(e)}), 500 @app.route('/report', methods=['GET']) def get_report(): user_id = request.args.get('user_id') if not user_id: return jsonify({"error": "User ID is required"}), 400 try: buffer = generate_report(user_id) buffer.seek(0) return send_file( buffer, as_attachment=True, download_name=f"bee_hive_report_{user_id}_{datetime.now().strftime('%Y%m%d')}.pdf", mimetype='application/pdf' ) except Exception as e: return jsonify({"error": str(e)}), 500 @app.route('/addtask', methods=['POST']) def add_task(): data = request.json required_fields = ['user_id', 'task_name', 'description', 'deadline_date', 'status'] if not all(key in data for key in required_fields): return jsonify({"error": "Missing required fields"}), 400 try: task_id = add_task_to_db( data['user_id'], data['task_name'], data.get('hive_id'), data['description'], data['deadline_date'], data['status'] ) return jsonify({"success": True, "task_id": task_id}), 201 except Exception as e: return jsonify({"error": str(e)}), 500 @app.route('/showtasks', methods=['GET']) def get_user_tasks(): user_id = request.args.get('user_id') if not user_id: return jsonify({"error": "User ID is required"}), 400 try: tasks = get_user_tasks_from_db(user_id) return jsonify({"tasks": tasks}), 200 except Exception as e: return jsonify({"error": str(e)}), 500 @app.route('/task_detail', methods=['GET']) def get_task_detail(): task_id = request.args.get('task_id') if not task_id: return jsonify({"error": "Task ID is required"}), 400 try: task = get_task_detail_from_db(task_id) if task: return jsonify(task), 200 return jsonify({"error": "Task not found"}), 404 except Exception as e: return jsonify({"error": str(e)}), 500 @app.route('/task_complete', methods=['POST']) def mark_task_complete(): data = request.json task_id = data.get('task_id') if not task_id: return jsonify({"error": "Task ID is required"}), 400 try: updated = update_task_status_to_completed(task_id) if updated: return jsonify({"success": True, "message": "Task marked as completed"}), 200 return jsonify({"error": "Task not found"}), 404 except Exception as e: return jsonify({"error": str(e)}), 500 @app.route('/delete_task', methods=['DELETE']) def delete_task(): data = request.get_json() task_id = data.get("task_id") if data else None if not task_id: return jsonify({"error": "Task ID is required"}), 400 try: deleted = delete_task_from_db(task_id) if deleted: return jsonify({"success": True}), 200 else: return jsonify({"error": "Task not found"}), 404 except Exception as e: return jsonify({"error": str(e)}), 500 @app.route('/notifications', methods=['GET']) def get_notifications(): user_id = request.args.get('user_id') if not user_id: return jsonify({"error": "User ID is required"}), 400 try: notifications = get_all_notifications(user_id) return jsonify({"notifications": notifications}), 200 except TypeError as e: return jsonify({"error": str(e)}), 500 @app.route('/notifications/mark_read', methods=['POST']) def mark_notifications_read(): data = request.json notification_id = data.get('notification_id') if not notification_id: return jsonify({"error": "Notification ID is required"}), 400 try: mark_notification_as_read(notification_id) return jsonify({"message": "Notification marked as read"}), 200 except Exception as e: return jsonify({"error)": str(e)}), 500 @app.route('/add_notifications', methods=['POST']) def create_notification(): data = request.json required_fields = ['user_id', 'textt'] if not all(key in data for key in required_fields): return jsonify({"error": "Missing required fields"}), 400 try: notification_id = add_notification( data['user_id'], data['textt'] ) return jsonify({"success": True, "notification_id": notification_id}), 201 except Exception as e: return jsonify({"error": str(e)}), 500 @app.route('/check_weather', methods=['POST']) def trigger_weather_check(): try: check_weather_conditions() return jsonify({"message": "Weather check triggered successfully"}), 200 except Exception as e: logger.error(f"Error triggering weather check: {str(e)}") return jsonify({"error": str(e)}), 500 def check_weather_conditions(): logger.info("Checking weather conditions for users") # Wake up the database try: response = requests.get("https://bilalhasanniazi-bee-notbee.hf.space/profile?user_id=0") if response.status_code == 200: logger.info("Database wake-up API called successfully") else: logger.warning(f"Database wake-up API failed with status {response.status_code}") except Exception as e: logger.error(f"Error calling database wake-up API: {str(e)}") # Wait for 10 seconds time.sleep(10) user_cities = get_user_cities() weather_api_key = "9fb23a5a66764b61a43163911251605" base_url = "http://api.weatherapi.com/v1/forecast.json" for user_id, city in user_cities.items(): try: # Fetch weather data response = requests.get(f"{base_url}?key={weather_api_key}&q={city}") if response.status_code != 200: logger.warning(f"Failed to fetch weather for city {city}: {response.status_code}") continue data = response.json() if "error" in data: logger.warning(f"Invalid city {city} for user {user_id}: {data['error']['message']}") continue temp_c = data["current"]["temp_c"] if temp_c > 45: notification_text = "Temperature is too hot, take safety precautions to protect bees" add_notification(user_id, notification_text) logger.info(f"Notification added for user {user_id} in {city}: {notification_text}") except Exception as e: logger.error(f"Error processing weather for user {user_id}, city {city}: {str(e)}") # Initialize scheduler scheduler = BackgroundScheduler() scheduler.add_job(check_weather_conditions, 'interval', hours=24) scheduler.start() if __name__ == '__main__': logger.info("Starting Flask application") app.run(debug=False, host='0.0.0.0', port=7860)