From a89e51e02623d4cb24c15ae5cb650d70d2d587bb Mon Sep 17 00:00:00 2001 From: Rishabh Shah Date: Fri, 21 Feb 2025 14:02:27 -0500 Subject: [PATCH 1/7] Added Bookmark add and delete endpoints --- backend/api_gateway/api_gateway.py | 63 +++++++++++++++++++++++++++ backend/microservices/news_storage.py | 17 +++++++- 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/backend/api_gateway/api_gateway.py b/backend/api_gateway/api_gateway.py index 4e5c85d..a190546 100644 --- a/backend/api_gateway/api_gateway.py +++ b/backend/api_gateway/api_gateway.py @@ -45,6 +45,7 @@ summarize_ns = api.namespace('summarize', description='Text summarization operations') user_ns = api.namespace('api/user', description='User operations') auth_ns = api.namespace('api/auth', description='Authentication operations') +bookmark_ns = api.namespace('api/bookmarks', description='Bookmark operations') def token_required(f): @wraps(f) @@ -263,6 +264,68 @@ def get(self): return {k: user[k] for k in user if k != 'password'}, 200 +@bookmark_ns.route('/') +class Bookmark(Resource): + @token_required + def post(self): + """Add a bookmark for a news article""" + try: + # Get the user ID from the token + auth_header = request.headers.get('Authorization') + token = auth_header.split()[1] + payload = jwt.decode(token, app.config['SECRET_KEY'], algorithms=['HS256']) + user_id = payload.get('id') + + # Get the news article ID from the request body + data = request.get_json() + news_id = data.get('news_id') + + if not news_id: + return {'error': 'News article ID is required'}, 400 + + # Add the bookmark using the news_storage service + bookmark = add_bookmark(user_id, news_id) + + return { + 'status': 'success', + 'message': 'Bookmark added successfully', + 'data': bookmark + }, 201 + + except Exception as e: + logger.error(f"Error adding bookmark: {str(e)}") + return { + 'status': 'error', + 'message': str(e) + }, 500 + +@bookmark_ns.route('/') +class BookmarkDelete(Resource): + @token_required + def delete(self, bookmark_id): + """Remove a bookmark for a news article""" + try: + # Get the user ID from the token + auth_header = request.headers.get('Authorization') + token = auth_header.split()[1] + payload = jwt.decode(token, app.config['SECRET_KEY'], algorithms=['HS256']) + user_id = payload.get('id') + + # Delete the bookmark using the news_storage service + result = delete_bookmark(user_id, bookmark_id) + + return { + 'status': 'success', + 'message': 'Bookmark removed successfully' + }, 200 + + except Exception as e: + logger.error(f"Error removing bookmark: {str(e)}") + return { + 'status': 'error', + 'message': str(e) + }, 500 + if __name__ == '__main__': port = int(sys.argv[1]) if len(sys.argv) > 1 else Config.API_PORT app.run(host=Config.API_HOST, port=port, debug=True) diff --git a/backend/microservices/news_storage.py b/backend/microservices/news_storage.py index 35861a5..8642b70 100644 --- a/backend/microservices/news_storage.py +++ b/backend/microservices/news_storage.py @@ -46,4 +46,19 @@ def log_user_search(user_id, news_id, session_id): "searched_at": datetime.datetime.utcnow().isoformat(), "session_id": session_id, }).execute() - return result \ No newline at end of file + return result + +def add_bookmark(user_id, news_id): + """ + Adds a bookmark by inserting a record into the user_bookmarks table. + Returns the created bookmark record if successful. + """ + try: + result = supabase.table("user_bookmarks").insert({ + "user_id": user_id, + "news_id": news_id, + }).execute() + return result.data[0] if result.data else None + except Exception as e: + print(f"Error adding bookmark: {str(e)}") + raise e \ No newline at end of file From cdbcbf6c1626ed8a1436a6c2411d0f3746e654e3 Mon Sep 17 00:00:00 2001 From: Rishabh Shah Date: Fri, 21 Feb 2025 14:13:39 -0500 Subject: [PATCH 2/7] Changed booksave reponse, add list bookmark endpoint --- backend/api_gateway/api_gateway.py | 31 +++++++++++++++++++++++++-- backend/microservices/news_storage.py | 27 +++++++++++++++++++++++ 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/backend/api_gateway/api_gateway.py b/backend/api_gateway/api_gateway.py index a190546..bb96ee8 100644 --- a/backend/api_gateway/api_gateway.py +++ b/backend/api_gateway/api_gateway.py @@ -26,7 +26,7 @@ from backend.core.config import Config from backend.core.utils import setup_logger, log_exception from backend.microservices.auth_service import load_users -from backend.microservices.news_storage import store_article_in_supabase, log_user_search +from backend.microservices.news_storage import store_article_in_supabase, log_user_search, add_bookmark # Initialize logger logger = setup_logger(__name__) @@ -266,6 +266,31 @@ def get(self): @bookmark_ns.route('/') class Bookmark(Resource): + @token_required + def get(self): + """Get all bookmarked articles for the authenticated user""" + try: + # Get the user ID from the token + auth_header = request.headers.get('Authorization') + token = auth_header.split()[1] + payload = jwt.decode(token, app.config['SECRET_KEY'], algorithms=['HS256']) + user_id = payload.get('id') + + # Get bookmarks using the news_storage service + bookmarks = get_user_bookmarks(user_id) + + return { + 'status': 'success', + 'data': bookmarks + }, 200 + + except Exception as e: + logger.error(f"Error fetching bookmarks: {str(e)}") + return { + 'status': 'error', + 'message': str(e) + }, 500 + @token_required def post(self): """Add a bookmark for a news article""" @@ -289,7 +314,9 @@ def post(self): return { 'status': 'success', 'message': 'Bookmark added successfully', - 'data': bookmark + 'data': { + 'bookmark_id': bookmark['id'] if isinstance(bookmark, dict) else bookmark + } }, 201 except Exception as e: diff --git a/backend/microservices/news_storage.py b/backend/microservices/news_storage.py index 8642b70..c75d807 100644 --- a/backend/microservices/news_storage.py +++ b/backend/microservices/news_storage.py @@ -61,4 +61,31 @@ def add_bookmark(user_id, news_id): return result.data[0] if result.data else None except Exception as e: print(f"Error adding bookmark: {str(e)}") + raise e + +def get_user_bookmarks(user_id): + """ + Retrieves all bookmarked articles for a user with full article details. + Returns a list of bookmarked articles with their details. + """ + try: + # Query user_bookmarks and join with news_articles to get full article details + result = supabase.table("user_bookmarks") \ + .select( + "id," + "news_articles(id,title,summary,content,source,published_at,url,image)" + ) \ + .eq("user_id", user_id) \ + .execute() + + # Transform the result to a more friendly format + bookmarks = [] + for item in result.data: + article = item["news_articles"] + article["bookmark_id"] = item["id"] + bookmarks.append(article) + + return bookmarks + except Exception as e: + print(f"Error fetching bookmarks: {str(e)}") raise e \ No newline at end of file From 3cb45acb422a4427ed6a42eb071ab7a042ff84db Mon Sep 17 00:00:00 2001 From: Rishabh Shah Date: Fri, 21 Feb 2025 21:29:53 -0500 Subject: [PATCH 3/7] Changes --- backend/microservices/auth_service.py | 51 --------------------------- 1 file changed, 51 deletions(-) diff --git a/backend/microservices/auth_service.py b/backend/microservices/auth_service.py index bf233e6..9f065e3 100644 --- a/backend/microservices/auth_service.py +++ b/backend/microservices/auth_service.py @@ -42,54 +42,3 @@ def load_users(): except Exception as e: print(f"Error loading users: {e}") return [] - -# @app.route('/api/auth/login', methods=['POST']) -# def login(): -# data = request.get_json() -# username = data.get('username') -# password = data.get('password') - -# if not username or not password: -# return jsonify({'error': 'Username and password are required'}), 400 - -# users = load_users() -# user = next((u for u in users if u.get('username') == username and u.get('password') == password), None) - -# if not user: -# return jsonify({'error': 'Invalid credentials'}), 401 - -# token = jwt.encode({ -# 'id': user['id'], -# 'username': user['username'], -# 'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=1) -# }, app.config['SECRET_KEY'], algorithm='HS256') - -# user_data = {k: user[k] for k in user if k != 'password'} -# return jsonify({'token': token, 'user': user_data}) - -# @app.route('/api/user/profile', methods=['GET']) -# def profile(): -# auth_header = request.headers.get('Authorization') -# if not auth_header: -# return jsonify({'error': 'Authorization header missing'}), 401 - -# try: -# token = auth_header.split()[1] -# payload = jwt.decode(token, app.config['SECRET_KEY'], algorithms=['HS256']) -# except Exception as e: -# return jsonify({'error': 'Invalid token', 'message': str(e)}), 401 - -# users = load_users() -# user = next((u for u in users if u.get('id') == payload.get('id')), None) -# if not user: -# return jsonify({'error': 'User not found'}), 404 - -# user_data = {k: user[k] for k in user if k != 'password'} -# return jsonify(user_data) - -# @app.route('/health', methods=['GET']) -# def health(): -# return jsonify({'status': 'Authentication service is healthy'}), 200 - -# if __name__ == '__main__': -# app.run(host='0.0.0.0', port=5003, debug=True) \ No newline at end of file From f36d0600ff7f31202a991616c94b332d7b4d2531 Mon Sep 17 00:00:00 2001 From: Rishabh Shah Date: Fri, 21 Feb 2025 23:01:46 -0500 Subject: [PATCH 4/7] working bookmark service, get article ID next --- backend/api_gateway/api_gateway.py | 31 +++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/backend/api_gateway/api_gateway.py b/backend/api_gateway/api_gateway.py index bb96ee8..2fb1949 100644 --- a/backend/api_gateway/api_gateway.py +++ b/backend/api_gateway/api_gateway.py @@ -51,11 +51,21 @@ def token_required(f): @wraps(f) def decorated(*args, **kwargs): auth_header = request.headers.get('Authorization') + + print(auth_header) + + if not auth_header: return {'error': 'Authorization header missing'}, 401 try: token = auth_header.split()[1] - payload = jwt.decode(token, app.config['SECRET_KEY'], algorithms=['HS256']) + print("eomthigs") + print(app.config['SECRET_KEY']) + # payload = jwt.decode(token, "xpOvQQ2OG/xmVaPNoiPr5wzRMJQ1+vOH0QsGroxtFqHOr8MSM6JPNQmCZz9pKfBNOGohGj31xHnqgm5OXlBDvg==", algorithms=['HS256']) + payload = jwt.decode(token, app.config['SECRET_KEY'], algorithms=['HS256'],audience='authenticated') + print(payload) + print('\n\n\n') + return f(*args, **kwargs) except Exception as e: return {'error': 'Invalid token', 'message': str(e)}, 401 @@ -140,8 +150,6 @@ def get(self): 'message': str(e) }), 500) - - # News processing endpoint @news_ns.route('/process') @@ -273,7 +281,7 @@ def get(self): # Get the user ID from the token auth_header = request.headers.get('Authorization') token = auth_header.split()[1] - payload = jwt.decode(token, app.config['SECRET_KEY'], algorithms=['HS256']) + payload = jwt.decode(token, app.config['SECRET_KEY'], algorithms=['HS256'],audience='authenticated') user_id = payload.get('id') # Get bookmarks using the news_storage service @@ -295,20 +303,29 @@ def get(self): def post(self): """Add a bookmark for a news article""" try: + print("asdfsjdknbdsjkb") + print("asdfsjdknbdsjkb") + print("asdfsjdknbdsjkb") + print("asdfsjdknbdsjkb") # Get the user ID from the token auth_header = request.headers.get('Authorization') token = auth_header.split()[1] - payload = jwt.decode(token, app.config['SECRET_KEY'], algorithms=['HS256']) - user_id = payload.get('id') + payload = jwt.decode(token, app.config['SECRET_KEY'], algorithms=['HS256'],audience='authenticated') + user_id = payload.get('sub') # Get the news article ID from the request body data = request.get_json() news_id = data.get('news_id') + print(data['user_id']) + print() + print(data) + if not news_id: return {'error': 'News article ID is required'}, 400 # Add the bookmark using the news_storage service + # bookmark = add_bookmark(user_id, '054c021a-f6f3-44b2-a43f-1ca0d211eb15') bookmark = add_bookmark(user_id, news_id) return { @@ -335,7 +352,7 @@ def delete(self, bookmark_id): # Get the user ID from the token auth_header = request.headers.get('Authorization') token = auth_header.split()[1] - payload = jwt.decode(token, app.config['SECRET_KEY'], algorithms=['HS256']) + payload = jwt.decode(token, app.config['SECRET_KEY'], algorithms=['HS256'],audience='authenticated') user_id = payload.get('id') # Delete the bookmark using the news_storage service From 77769abbc882bb140393adf088aae1d77891f7f6 Mon Sep 17 00:00:00 2001 From: Rishabh Shah Date: Sat, 22 Feb 2025 00:27:04 -0500 Subject: [PATCH 5/7] Add bookmark working now --- backend/api_gateway/api_gateway.py | 30 ++++--------------- .../microservices/summarization_service.py | 1 + 2 files changed, 7 insertions(+), 24 deletions(-) diff --git a/backend/api_gateway/api_gateway.py b/backend/api_gateway/api_gateway.py index 2fb1949..a3e02f2 100644 --- a/backend/api_gateway/api_gateway.py +++ b/backend/api_gateway/api_gateway.py @@ -26,7 +26,7 @@ from backend.core.config import Config from backend.core.utils import setup_logger, log_exception from backend.microservices.auth_service import load_users -from backend.microservices.news_storage import store_article_in_supabase, log_user_search, add_bookmark +from backend.microservices.news_storage import store_article_in_supabase, log_user_search, add_bookmark, get_user_bookmarks # Initialize logger logger = setup_logger(__name__) @@ -51,20 +51,12 @@ def token_required(f): @wraps(f) def decorated(*args, **kwargs): auth_header = request.headers.get('Authorization') - - print(auth_header) - - + print("here") if not auth_header: return {'error': 'Authorization header missing'}, 401 try: token = auth_header.split()[1] - print("eomthigs") - print(app.config['SECRET_KEY']) - # payload = jwt.decode(token, "xpOvQQ2OG/xmVaPNoiPr5wzRMJQ1+vOH0QsGroxtFqHOr8MSM6JPNQmCZz9pKfBNOGohGj31xHnqgm5OXlBDvg==", algorithms=['HS256']) payload = jwt.decode(token, app.config['SECRET_KEY'], algorithms=['HS256'],audience='authenticated') - print(payload) - print('\n\n\n') return f(*args, **kwargs) except Exception as e: @@ -178,7 +170,6 @@ def post(self): class Signup(Resource): @auth_ns.expect(signup_model) def post(self): - print('signup') """Register a new user""" data = request.get_json() username = data.get('username') @@ -205,8 +196,6 @@ def post(self): 'firstName': firstName, 'lastName': lastName } - - print(new_user) users.append(new_user) @@ -232,7 +221,6 @@ def post(self): class Login(Resource): def post(self): """Login and get authentication token""" - print('login in') data = request.get_json() username = data.get('username') password = data.get('password') @@ -278,15 +266,16 @@ class Bookmark(Resource): def get(self): """Get all bookmarked articles for the authenticated user""" try: + print('here') # Get the user ID from the token auth_header = request.headers.get('Authorization') token = auth_header.split()[1] payload = jwt.decode(token, app.config['SECRET_KEY'], algorithms=['HS256'],audience='authenticated') - user_id = payload.get('id') + user_id = payload.get('sub') # Get bookmarks using the news_storage service bookmarks = get_user_bookmarks(user_id) - + print(bookmarks) return { 'status': 'success', 'data': bookmarks @@ -303,10 +292,7 @@ def get(self): def post(self): """Add a bookmark for a news article""" try: - print("asdfsjdknbdsjkb") - print("asdfsjdknbdsjkb") - print("asdfsjdknbdsjkb") - print("asdfsjdknbdsjkb") + # Get the user ID from the token auth_header = request.headers.get('Authorization') token = auth_header.split()[1] @@ -317,10 +303,6 @@ def post(self): data = request.get_json() news_id = data.get('news_id') - print(data['user_id']) - print() - print(data) - if not news_id: return {'error': 'News article ID is required'}, 400 diff --git a/backend/microservices/summarization_service.py b/backend/microservices/summarization_service.py index f2a5547..52c123b 100755 --- a/backend/microservices/summarization_service.py +++ b/backend/microservices/summarization_service.py @@ -128,6 +128,7 @@ def process_articles(session_id): summary = run_summarization(article.get('content', '')) summarized_articles.append({ + 'id': article['id'], 'title': article['title'], 'author': article.get('author', 'Unknown Author'), 'source': article.get('source'), From 3c8cccfaf360dc27e1cf6215e9c925623d52ff2a Mon Sep 17 00:00:00 2001 From: Rishabh Shah Date: Sat, 22 Feb 2025 12:59:59 -0500 Subject: [PATCH 6/7] List bookmark working now --- backend/api_gateway/api_gateway.py | 7 ++----- backend/microservices/news_storage.py | 12 ++++++++++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/backend/api_gateway/api_gateway.py b/backend/api_gateway/api_gateway.py index a3e02f2..c25cdd3 100644 --- a/backend/api_gateway/api_gateway.py +++ b/backend/api_gateway/api_gateway.py @@ -26,14 +26,14 @@ from backend.core.config import Config from backend.core.utils import setup_logger, log_exception from backend.microservices.auth_service import load_users -from backend.microservices.news_storage import store_article_in_supabase, log_user_search, add_bookmark, get_user_bookmarks +from backend.microservices.news_storage import store_article_in_supabase, log_user_search, add_bookmark, get_user_bookmarks, delete_bookmark # Initialize logger logger = setup_logger(__name__) # Initialize Flask app with CORS support app = Flask(__name__) app.config['SECRET_KEY'] = os.getenv('JWT_SECRET_KEY', 'your-secret-key') # Change this in production -CORS(app, origins=Config.CORS_ORIGINS, supports_credentials=True, allow_headers=['Content-Type', 'Authorization']) +CORS(app, origins=Config.CORS_ORIGINS, supports_credentials=True, allow_headers=['Content-Type', 'Authorization', 'Access-Control-Allow-Origin'], methods=['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], expose_headers=['Access-Control-Allow-Origin']) # Initialize Flask-RestX api = Api(app, version='1.0', title='News Aggregator API', @@ -51,7 +51,6 @@ def token_required(f): @wraps(f) def decorated(*args, **kwargs): auth_header = request.headers.get('Authorization') - print("here") if not auth_header: return {'error': 'Authorization header missing'}, 401 try: @@ -266,7 +265,6 @@ class Bookmark(Resource): def get(self): """Get all bookmarked articles for the authenticated user""" try: - print('here') # Get the user ID from the token auth_header = request.headers.get('Authorization') token = auth_header.split()[1] @@ -292,7 +290,6 @@ def get(self): def post(self): """Add a bookmark for a news article""" try: - # Get the user ID from the token auth_header = request.headers.get('Authorization') token = auth_header.split()[1] diff --git a/backend/microservices/news_storage.py b/backend/microservices/news_storage.py index c75d807..a8ae7e9 100644 --- a/backend/microservices/news_storage.py +++ b/backend/microservices/news_storage.py @@ -88,4 +88,16 @@ def get_user_bookmarks(user_id): return bookmarks except Exception as e: print(f"Error fetching bookmarks: {str(e)}") + raise e + +def delete_bookmark(user_id, bookmark_id): + """ + Deletes a bookmark from the user_bookmarks table. + Returns True if successful, False otherwise. + """ + try: + result = supabase.table("user_bookmarks").delete().eq("id", bookmark_id).eq("user_id", user_id).execute() + return len(result.data) > 0 + except Exception as e: + print(f"Error deleting bookmark: {str(e)}") raise e \ No newline at end of file From 88f80ce1b36d625ae96da2d63b60919bc088881b Mon Sep 17 00:00:00 2001 From: Rishabh Shah Date: Sat, 22 Feb 2025 13:39:55 -0500 Subject: [PATCH 7/7] Bookmark remove working now --- backend/api_gateway/api_gateway.py | 4 ++-- backend/microservices/news_fetcher.py | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/backend/api_gateway/api_gateway.py b/backend/api_gateway/api_gateway.py index c25cdd3..5b69660 100644 --- a/backend/api_gateway/api_gateway.py +++ b/backend/api_gateway/api_gateway.py @@ -273,7 +273,7 @@ def get(self): # Get bookmarks using the news_storage service bookmarks = get_user_bookmarks(user_id) - print(bookmarks) + return { 'status': 'success', 'data': bookmarks @@ -332,7 +332,7 @@ def delete(self, bookmark_id): auth_header = request.headers.get('Authorization') token = auth_header.split()[1] payload = jwt.decode(token, app.config['SECRET_KEY'], algorithms=['HS256'],audience='authenticated') - user_id = payload.get('id') + user_id = payload.get('sub') # Delete the bookmark using the news_storage service result = delete_bookmark(user_id, bookmark_id) diff --git a/backend/microservices/news_fetcher.py b/backend/microservices/news_fetcher.py index 6fa336c..818c52a 100644 --- a/backend/microservices/news_fetcher.py +++ b/backend/microservices/news_fetcher.py @@ -67,4 +67,9 @@ def write_to_file(articles, session_id=None): print(f"Error writing to file: {e}") if __name__ == '__main__': - fetch_news() \ No newline at end of file + fetch_news() + + + + +