218 lines
6.9 KiB
Python
218 lines
6.9 KiB
Python
"""
|
|
RSS Feed management routes
|
|
"""
|
|
from flask import Blueprint, request, jsonify
|
|
from datetime import datetime
|
|
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"""
|
|
try:
|
|
feeds = list(rss_feeds_collection.find(
|
|
{},
|
|
{'_id': 0}
|
|
).sort('name', 1))
|
|
|
|
# Convert datetime to ISO format
|
|
for feed in feeds:
|
|
if 'created_at' in feed:
|
|
feed['created_at'] = feed['created_at'].isoformat()
|
|
|
|
return jsonify({
|
|
'feeds': feeds,
|
|
'total': len(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"""
|
|
try:
|
|
data = request.get_json()
|
|
|
|
# Validate required fields
|
|
if not data.get('name'):
|
|
return jsonify({'error': 'Feed name is required'}), 400
|
|
if not data.get('url'):
|
|
return jsonify({'error': 'Feed URL is required'}), 400
|
|
if not data.get('category'):
|
|
return jsonify({'error': 'Category is required'}), 400
|
|
|
|
# Category validation - accept any string, but recommend common ones
|
|
category = data['category'].strip().lower()
|
|
if not category:
|
|
return jsonify({'error': 'Category cannot be empty'}), 400
|
|
|
|
data['category'] = category # Normalize to lowercase
|
|
|
|
# Check if feed already exists
|
|
existing = rss_feeds_collection.find_one({'url': data['url']})
|
|
if existing:
|
|
return jsonify({'error': 'Feed URL already exists'}), 400
|
|
|
|
# Create feed document
|
|
feed_doc = {
|
|
'name': data['name'].strip(),
|
|
'url': data['url'].strip(),
|
|
'category': data['category'],
|
|
'active': data.get('active', True),
|
|
'created_at': datetime.utcnow()
|
|
}
|
|
|
|
rss_feeds_collection.insert_one(feed_doc)
|
|
|
|
return jsonify({
|
|
'message': 'RSS feed added successfully',
|
|
'feed': {
|
|
'name': feed_doc['name'],
|
|
'url': feed_doc['url'],
|
|
'category': feed_doc['category'],
|
|
'active': feed_doc['active']
|
|
}
|
|
}), 201
|
|
|
|
except Exception as e:
|
|
return jsonify({'error': str(e)}), 500
|
|
|
|
|
|
@rss_bp.route('/api/rss-feeds/<feed_name>', methods=['PUT'])
|
|
def update_rss_feed(feed_name):
|
|
"""Update an RSS feed"""
|
|
try:
|
|
data = request.get_json()
|
|
|
|
# Build update document
|
|
update_doc = {}
|
|
if 'url' in data:
|
|
update_doc['url'] = data['url'].strip()
|
|
if 'category' in data:
|
|
category = data['category'].strip().lower()
|
|
if not category:
|
|
return jsonify({'error': 'Category cannot be empty'}), 400
|
|
update_doc['category'] = category
|
|
if 'active' in data:
|
|
update_doc['active'] = bool(data['active'])
|
|
|
|
if not update_doc:
|
|
return jsonify({'error': 'No fields to update'}), 400
|
|
|
|
result = rss_feeds_collection.update_one(
|
|
{'name': feed_name},
|
|
{'$set': update_doc}
|
|
)
|
|
|
|
if result.matched_count > 0:
|
|
return jsonify({'message': 'RSS feed updated successfully'}), 200
|
|
else:
|
|
return jsonify({'error': 'Feed not found'}), 404
|
|
|
|
except Exception as e:
|
|
return jsonify({'error': str(e)}), 500
|
|
|
|
|
|
@rss_bp.route('/api/rss-feeds/<feed_name>', methods=['DELETE'])
|
|
def delete_rss_feed(feed_name):
|
|
"""Delete an RSS feed"""
|
|
try:
|
|
result = rss_feeds_collection.delete_one({'name': feed_name})
|
|
|
|
if result.deleted_count > 0:
|
|
return jsonify({'message': f'RSS feed "{feed_name}" deleted successfully'}), 200
|
|
else:
|
|
return jsonify({'error': 'Feed not found'}), 404
|
|
|
|
except Exception as e:
|
|
return jsonify({'error': str(e)}), 500
|
|
|
|
|
|
|
|
@rss_bp.route('/api/rss-feeds/export', methods=['GET'])
|
|
def export_rss_feeds():
|
|
"""Export all RSS feeds as JSON"""
|
|
try:
|
|
feeds = list(rss_feeds_collection.find(
|
|
{},
|
|
{'_id': 0}
|
|
).sort('name', 1))
|
|
|
|
# Convert datetime to ISO format
|
|
for feed in feeds:
|
|
if 'created_at' in feed:
|
|
feed['created_at'] = feed['created_at'].isoformat()
|
|
|
|
return jsonify({
|
|
'feeds': feeds,
|
|
'total': len(feeds),
|
|
'exported_at': datetime.utcnow().isoformat()
|
|
}), 200
|
|
|
|
except Exception as e:
|
|
return jsonify({'error': str(e)}), 500
|
|
|
|
|
|
@rss_bp.route('/api/rss-feeds/import', methods=['POST'])
|
|
def import_rss_feeds():
|
|
"""Import RSS feeds from JSON"""
|
|
try:
|
|
data = request.get_json()
|
|
|
|
if not data or 'feeds' not in data:
|
|
return jsonify({'error': 'Invalid import data. Expected {feeds: [...]}'}), 400
|
|
|
|
feeds = data['feeds']
|
|
|
|
if not isinstance(feeds, list):
|
|
return jsonify({'error': 'feeds must be an array'}), 400
|
|
|
|
imported = 0
|
|
skipped = 0
|
|
errors = []
|
|
|
|
for feed in feeds:
|
|
try:
|
|
# Validate required fields
|
|
if not feed.get('name') or not feed.get('url') or not feed.get('category'):
|
|
errors.append(f"Skipped invalid feed: {feed.get('name', 'unknown')}")
|
|
skipped += 1
|
|
continue
|
|
|
|
# Check if feed already exists
|
|
existing = rss_feeds_collection.find_one({'url': feed['url']})
|
|
if existing:
|
|
errors.append(f"Skipped duplicate: {feed['name']}")
|
|
skipped += 1
|
|
continue
|
|
|
|
# Create feed document
|
|
feed_doc = {
|
|
'name': feed['name'].strip(),
|
|
'url': feed['url'].strip(),
|
|
'category': feed['category'].strip().lower(),
|
|
'active': feed.get('active', True),
|
|
'created_at': datetime.utcnow()
|
|
}
|
|
|
|
rss_feeds_collection.insert_one(feed_doc)
|
|
imported += 1
|
|
|
|
except Exception as e:
|
|
errors.append(f"Error importing {feed.get('name', 'unknown')}: {str(e)}")
|
|
skipped += 1
|
|
|
|
return jsonify({
|
|
'message': f'Import complete: {imported} imported, {skipped} skipped',
|
|
'imported': imported,
|
|
'skipped': skipped,
|
|
'errors': errors if errors else None
|
|
}), 200
|
|
|
|
except Exception as e:
|
|
return jsonify({'error': str(e)}), 500
|