from flask import Blueprint, request, jsonify from datetime import datetime from pymongo.errors import DuplicateKeyError from bson.objectid import ObjectId import feedparser from database import rss_feeds_collection rss_bp = Blueprint('rss', __name__) @rss_bp.route('/api/rss-feeds', methods=['GET']) def get_rss_feeds(): """Get all RSS feeds, optionally filtered by category""" try: # Get optional category filter category = request.args.get('category') # Build query query = {} if category: query['category'] = category cursor = rss_feeds_collection.find(query).sort('created_at', -1) feeds = [] for feed in cursor: feeds.append({ 'id': str(feed['_id']), 'name': feed.get('name', ''), 'url': feed.get('url', ''), 'category': feed.get('category', 'general'), 'active': feed.get('active', True), 'created_at': feed.get('created_at', '').isoformat() if feed.get('created_at') else '' }) return jsonify({'feeds': feeds}), 200 except Exception as e: return jsonify({'error': str(e)}), 500 @rss_bp.route('/api/rss-feeds', methods=['POST']) def add_rss_feed(): """Add a new RSS feed with optional category""" data = request.json name = data.get('name', '').strip() url = data.get('url', '').strip() category = data.get('category', 'general').strip().lower() if not name or not url: return jsonify({'error': 'Name and URL are required'}), 400 if not url.startswith('http://') and not url.startswith('https://'): return jsonify({'error': 'URL must start with http:// or https://'}), 400 # Validate category (optional, but if provided should be reasonable) valid_categories = ['general', 'local', 'politics', 'sports', 'culture', 'business', 'technology', 'entertainment'] if category and category not in valid_categories: # Allow custom categories but warn pass try: # Test if the RSS feed is valid try: feed = feedparser.parse(url) if not feed.entries: return jsonify({'error': 'Invalid RSS feed or no entries found'}), 400 except Exception as e: return jsonify({'error': f'Failed to parse RSS feed: {str(e)}'}), 400 feed_doc = { 'name': name, 'url': url, 'category': category, 'active': True, 'created_at': datetime.utcnow() } try: result = rss_feeds_collection.insert_one(feed_doc) return jsonify({ 'message': 'RSS feed added successfully', 'id': str(result.inserted_id), 'category': category }), 201 except DuplicateKeyError: return jsonify({'error': 'RSS feed URL already exists'}), 409 except Exception as e: return jsonify({'error': str(e)}), 500 @rss_bp.route('/api/rss-feeds/', methods=['DELETE']) def remove_rss_feed(feed_id): """Remove an RSS feed""" try: # Validate ObjectId try: obj_id = ObjectId(feed_id) except Exception: return jsonify({'error': 'Invalid feed ID'}), 400 result = rss_feeds_collection.delete_one({'_id': obj_id}) if result.deleted_count > 0: return jsonify({'message': 'RSS feed removed successfully'}), 200 else: return jsonify({'error': 'RSS feed not found'}), 404 except Exception as e: return jsonify({'error': str(e)}), 500 @rss_bp.route('/api/rss-feeds//toggle', methods=['PATCH']) def toggle_rss_feed(feed_id): """Toggle RSS feed active status""" try: # Validate ObjectId try: obj_id = ObjectId(feed_id) except Exception: return jsonify({'error': 'Invalid feed ID'}), 400 # Get current status feed = rss_feeds_collection.find_one({'_id': obj_id}) if not feed: return jsonify({'error': 'RSS feed not found'}), 404 # Toggle status new_status = not feed.get('active', True) result = rss_feeds_collection.update_one( {'_id': obj_id}, {'$set': {'active': new_status}} ) if result.modified_count > 0: return jsonify({ 'message': f'RSS feed {"activated" if new_status else "deactivated"} successfully', 'active': new_status }), 200 else: return jsonify({'error': 'Failed to update RSS feed'}), 500 except Exception as e: return jsonify({'error': str(e)}), 500 @rss_bp.route('/api/rss-feeds/categories', methods=['GET']) def get_categories(): """Get all unique categories from RSS feeds""" try: categories = rss_feeds_collection.distinct('category') # Filter out None/empty and sort categories = sorted([c for c in categories if c]) return jsonify({'categories': categories}), 200 except Exception as e: return jsonify({'error': str(e)}), 500