| | from flask import Blueprint, request, jsonify, current_app |
| | from flask_jwt_extended import jwt_required, get_jwt_identity |
| | from backend.services.content_service import ContentService |
| | import pandas as pd |
| |
|
| | sources_bp = Blueprint('sources', __name__) |
| |
|
| | @sources_bp.route('/', methods=['OPTIONS']) |
| | @sources_bp.route('', methods=['OPTIONS']) |
| | def handle_options(): |
| | """Handle OPTIONS requests for preflight CORS checks.""" |
| | return '', 200 |
| |
|
| | @sources_bp.route('/', methods=['GET']) |
| | @sources_bp.route('', methods=['GET']) |
| | @jwt_required() |
| | def get_sources(): |
| | """ |
| | Get all sources for the current user. |
| | |
| | Returns: |
| | JSON: List of sources |
| | """ |
| | try: |
| | user_id = get_jwt_identity() |
| | |
| | |
| | if not hasattr(current_app, 'supabase') or current_app.supabase is None: |
| | |
| | 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 |
| | |
| | |
| | response = ( |
| | current_app.supabase |
| | .table("Source") |
| | .select("*") |
| | .eq("user_id", user_id) |
| | .execute() |
| | ) |
| | |
| | sources = response.data if response.data else [] |
| | |
| | |
| | response_data = jsonify({ |
| | 'success': True, |
| | 'sources': sources |
| | }) |
| | 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: |
| | current_app.logger.error(f"Get sources error: {str(e)}") |
| | |
| | response_data = jsonify({ |
| | 'success': False, |
| | 'message': 'An error occurred while fetching sources' |
| | }) |
| | response_data.headers.add('Access-Control-Allow-Origin', 'http://localhost:3000') |
| | response_data.headers.add('Access-Control-Allow-Credentials', 'true') |
| | return response_data, 500 |
| |
|
| | @sources_bp.route('/', methods=['POST']) |
| | @sources_bp.route('', methods=['POST']) |
| | @jwt_required() |
| | def add_source(): |
| | """ |
| | Add a new source for the current user. |
| | |
| | Request Body: |
| | source (str): Source URL |
| | |
| | Returns: |
| | JSON: Add source result |
| | """ |
| | try: |
| | user_id = get_jwt_identity() |
| | data = request.get_json() |
| | |
| | |
| | if not data or 'source' not in data: |
| | return jsonify({ |
| | 'success': False, |
| | 'message': 'Source URL is required' |
| | }), 400 |
| | |
| | source_url = data['source'] |
| | |
| | |
| | try: |
| | content_service = ContentService() |
| | result = content_service.add_rss_source(source_url, user_id) |
| | |
| | return jsonify({ |
| | 'success': True, |
| | 'message': result |
| | }), 201 |
| | except Exception as e: |
| | |
| | current_app.logger.warning(f"Content service failed, storing in database directly: {str(e)}") |
| | |
| | |
| | |
| | response = ( |
| | current_app.supabase |
| | .table("Source") |
| | .insert({ |
| | "source": source_url, |
| | "user_id": user_id, |
| | "created_at": "now()" |
| | }) |
| | .execute() |
| | ) |
| | |
| | if response.data: |
| | |
| | return jsonify({ |
| | 'success': True, |
| | 'source': response.data[0] |
| | }), 201 |
| | else: |
| | raise Exception("Failed to store source in database") |
| | |
| | except Exception as e: |
| | current_app.logger.error(f"Add source error: {str(e)}") |
| | return jsonify({ |
| | 'success': False, |
| | 'message': f'An error occurred while adding source: {str(e)}' |
| | }), 500 |
| |
|
| | @sources_bp.route('/<source_id>', methods=['OPTIONS']) |
| | def handle_source_options(source_id): |
| | """Handle OPTIONS requests for preflight CORS checks for specific source.""" |
| | return '', 200 |
| |
|
| | @sources_bp.route('/keyword-analysis', methods=['OPTIONS']) |
| | def handle_keyword_analysis_options(): |
| | """Handle OPTIONS requests for preflight CORS checks for keyword analysis.""" |
| | return '', 200 |
| |
|
| |
|
| | @sources_bp.route('/keyword-analysis', methods=['POST']) |
| | @jwt_required() |
| | def analyze_keyword(): |
| | """ |
| | Analyze keyword frequency in RSS feeds and posts. |
| | |
| | Request Body: |
| | keyword (str): The keyword to analyze |
| | date_range (str): The date range to analyze ('daily', 'weekly', 'monthly'), default is 'monthly' |
| | |
| | Returns: |
| | JSON: Keyword frequency analysis data |
| | """ |
| | try: |
| | user_id = get_jwt_identity() |
| | data = request.get_json() |
| | |
| | |
| | if not data or 'keyword' not in data: |
| | return jsonify({ |
| | 'success': False, |
| | 'message': 'Keyword is required' |
| | }), 400 |
| | |
| | keyword = data['keyword'] |
| | date_range = data.get('date_range', 'monthly') |
| | |
| | |
| | valid_date_ranges = ['daily', 'weekly', 'monthly'] |
| | if date_range not in valid_date_ranges: |
| | return jsonify({ |
| | 'success': False, |
| | 'message': f'Invalid date_range. Must be one of: {valid_date_ranges}' |
| | }), 400 |
| | |
| | |
| | try: |
| | content_service = ContentService() |
| | analysis_data = content_service.analyze_keyword_frequency(keyword, user_id, date_range) |
| | |
| | return jsonify({ |
| | 'success': True, |
| | 'data': analysis_data, |
| | 'keyword': keyword, |
| | 'date_range': date_range |
| | }), 200 |
| | except Exception as e: |
| | current_app.logger.error(f"Keyword analysis error: {str(e)}") |
| | return jsonify({ |
| | 'success': False, |
| | 'message': f'An error occurred during keyword analysis: {str(e)}' |
| | }), 500 |
| | |
| | except Exception as e: |
| | current_app.logger.error(f"Analyze keyword error: {str(e)}") |
| | return jsonify({ |
| | 'success': False, |
| | 'message': f'An error occurred while analyzing keyword: {str(e)}' |
| | }), 500 |
| |
|
| |
|
| | @sources_bp.route('/keyword-frequency-pattern', methods=['POST']) |
| | @jwt_required() |
| | def analyze_keyword_frequency_pattern(): |
| | """ |
| | Analyze keyword frequency pattern in RSS feeds and posts. |
| | Determines if keyword follows a daily, weekly, monthly, or rare pattern based on recency and frequency. |
| | |
| | Request Body: |
| | keyword (str): The keyword to analyze |
| | |
| | Returns: |
| | JSON: Keyword frequency pattern analysis data |
| | """ |
| | try: |
| | user_id = get_jwt_identity() |
| | data = request.get_json() |
| | |
| | |
| | if not data or 'keyword' not in data: |
| | return jsonify({ |
| | 'success': False, |
| | 'message': 'Keyword is required' |
| | }), 400 |
| | |
| | keyword = data['keyword'] |
| | |
| | |
| | try: |
| | content_service = ContentService() |
| | analysis_result = content_service.analyze_keyword_frequency_pattern(keyword, user_id) |
| | |
| | return jsonify({ |
| | 'success': True, |
| | 'data': analysis_result, |
| | 'keyword': keyword |
| | }), 200 |
| | except Exception as e: |
| | current_app.logger.error(f"Keyword frequency pattern analysis error: {str(e)}") |
| | return jsonify({ |
| | 'success': False, |
| | 'message': f'An error occurred during keyword frequency pattern analysis: {str(e)}' |
| | }), 500 |
| | |
| | except Exception as e: |
| | current_app.logger.error(f"Analyze keyword frequency pattern error: {str(e)}") |
| | return jsonify({ |
| | 'success': False, |
| | 'message': f'An error occurred while analyzing keyword frequency pattern: {str(e)}' |
| | }), 500 |
| |
|
| |
|
| | @sources_bp.route('/<source_id>', methods=['DELETE']) |
| | @jwt_required() |
| | def delete_source(source_id): |
| | """ |
| | Delete a source. |
| | |
| | Path Parameters: |
| | source_id (str): Source ID |
| | |
| | Returns: |
| | JSON: Delete source result |
| | """ |
| | try: |
| | user_id = get_jwt_identity() |
| | |
| | |
| | response = ( |
| | current_app.supabase |
| | .table("Source") |
| | .delete() |
| | .eq("id", source_id) |
| | .eq("user_id", user_id) |
| | .execute() |
| | ) |
| | |
| | if response.data: |
| | return jsonify({ |
| | 'success': True, |
| | 'message': 'Source deleted successfully' |
| | }), 200 |
| | else: |
| | return jsonify({ |
| | 'success': False, |
| | 'message': 'Source not found or unauthorized' |
| | }), 404 |
| | |
| | except Exception as e: |
| | current_app.logger.error(f"Delete source error: {str(e)}") |
| | return jsonify({ |
| | 'success': False, |
| | 'message': 'An error occurred while deleting source' |
| | }), 500 |