-
-
Notifications
You must be signed in to change notification settings - Fork 78
创建书签功能 #227
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
创建书签功能 #227
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,134 @@ | ||
| """ | ||
| Bookmark routes for handling post bookmarks | ||
| """ | ||
|
|
||
| from flask import Blueprint, jsonify, session, request | ||
| from database import db | ||
| from models import Bookmark, Post, User | ||
| from utils.log import Log | ||
|
|
||
| bookmark_blueprint = Blueprint("bookmark", __name__) | ||
|
|
||
|
|
||
| @bookmark_blueprint.route("/api/bookmark/<int:post_id>", methods=["POST"]) | ||
| def toggle_bookmark(post_id): | ||
| """Toggle bookmark status for a post""" | ||
| try: | ||
| # Check if user is logged in | ||
| if "username" not in session: | ||
| return jsonify({"error": "User not logged in"}), 401 | ||
|
|
||
| # Get user ID | ||
| user = User.query.filter_by(username=session["username"]).first() | ||
| if not user: | ||
| return jsonify({"error": "User not found"}), 404 | ||
|
|
||
| # Check if post exists | ||
| post = Post.query.get(post_id) | ||
| if not post: | ||
| return jsonify({"error": "Post not found"}), 404 | ||
|
|
||
| # Check if bookmark already exists | ||
| existing_bookmark = Bookmark.query.filter_by( | ||
| user_id=user.user_id, | ||
| post_id=post_id | ||
| ).first() | ||
|
|
||
| if existing_bookmark: | ||
| # Remove bookmark | ||
| db.session.delete(existing_bookmark) | ||
| db.session.commit() | ||
| Log.info(f"Bookmark removed for user {user.username} on post {post_id}") | ||
| return jsonify({"bookmarked": False, "message": "Bookmark removed"}), 200 | ||
| else: | ||
| # Add bookmark | ||
| new_bookmark = Bookmark( | ||
| user_id=user.user_id, | ||
| post_id=post_id | ||
| ) | ||
| db.session.add(new_bookmark) | ||
| db.session.commit() | ||
| Log.info(f"Bookmark added for user {user.username} on post {post_id}") | ||
| return jsonify({"bookmarked": True, "message": "Bookmark added"}), 201 | ||
|
|
||
| except Exception as e: | ||
| db.session.rollback() | ||
| Log.error(f"Error toggling bookmark: {e}") | ||
| return jsonify({"error": "Internal server error"}), 500 | ||
|
|
||
|
|
||
| @bookmark_blueprint.route("/api/bookmark/status/<int:post_id>", methods=["GET"]) | ||
| def get_bookmark_status(post_id): | ||
| """Get bookmark status for a specific post""" | ||
| try: | ||
| # Check if user is logged in | ||
| if "username" not in session: | ||
| return jsonify({"bookmarked": False}), 200 | ||
|
|
||
| # Get user ID | ||
| user = User.query.filter_by(username=session["username"]).first() | ||
| if not user: | ||
| return jsonify({"bookmarked": False}), 200 | ||
|
|
||
| # Check if bookmark exists | ||
| bookmark = Bookmark.query.filter_by( | ||
| user_id=user.user_id, | ||
| post_id=post_id | ||
| ).first() | ||
|
|
||
| return jsonify({"bookmarked": bookmark is not None}), 200 | ||
|
|
||
| except Exception as e: | ||
| Log.error(f"Error getting bookmark status: {e}") | ||
| return jsonify({"error": "Internal server error"}), 500 | ||
|
|
||
|
|
||
| @bookmark_blueprint.route("/my-bookmarks") | ||
| def my_bookmarks(): | ||
| """Display user's bookmarked posts""" | ||
| try: | ||
| # Check if user is logged in | ||
| if "username" not in session: | ||
| return jsonify({"error": "User not logged in"}), 401 | ||
|
|
||
| # Get user ID | ||
| user = User.query.filter_by(username=session["username"]).first() | ||
| if not user: | ||
| return jsonify({"error": "User not found"}), 404 | ||
|
|
||
| # Get user's bookmarks with post details | ||
| bookmarks = db.session.query(Bookmark, Post).join( | ||
| Post, Bookmark.post_id == Post.id | ||
| ).filter( | ||
| Bookmark.user_id == user.user_id | ||
| ).order_by( | ||
| Bookmark.time_stamp.desc() | ||
| ).all() | ||
|
|
||
| # Format data for template | ||
| bookmarked_posts = [] | ||
| for bookmark, post in bookmarks: | ||
| bookmarked_posts.append({ | ||
| 'id': post.id, | ||
| 'title': post.title, | ||
| 'tags': post.tags, | ||
| 'content': post.content, | ||
| 'banner': post.banner, | ||
| 'author': post.author, | ||
| 'views': post.views, | ||
| 'time_stamp': post.time_stamp, | ||
| 'last_edit_time_stamp': post.last_edit_time_stamp, | ||
| 'category': post.category, | ||
| 'url_id': post.url_id, | ||
| 'abstract': post.abstract, | ||
| 'bookmark_time': bookmark.time_stamp | ||
| }) | ||
|
|
||
| return jsonify({ | ||
| "bookmarked_posts": bookmarked_posts, | ||
| "username": user.username | ||
| }), 200 | ||
|
|
||
| except Exception as e: | ||
| Log.error(f"Error getting user bookmarks: {e}") | ||
| return jsonify({"error": "Internal server error"}), 500 | ||
|
Comment on lines
+86
to
+134
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Resolve /my-bookmarks route conflict and JSON serialization risk. ✅ Suggested fix (example)-@bookmark_blueprint.route("/my-bookmarks")
+@bookmark_blueprint.route("/api/my-bookmarks")
def my_bookmarks():
@@
- 'banner': post.banner,
- 'content': post.content,
+ # Consider returning banner_url instead of raw binary,
+ # and omit large content if not needed by the client.
'author': post.author,
@@
- 'abstract': post.abstract,
+ 'abstract': post.abstract,🤖 Prompt for AI Agents |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| """ | ||
| My Bookmarks page route | ||
| """ | ||
|
|
||
| from flask import Blueprint, render_template, session, redirect, url_for | ||
| from database import db | ||
| from models import Bookmark, Post, User | ||
| from utils.log import Log | ||
| from utils.get_profile_picture import get_profile_picture | ||
|
|
||
| my_bookmarks_blueprint = Blueprint("my_bookmarks", __name__) | ||
|
|
||
|
|
||
| @my_bookmarks_blueprint.route("/my-bookmarks") | ||
| def my_bookmarks(): | ||
| """Display user's bookmarked posts page""" | ||
| try: | ||
| # Check if user is logged in | ||
| if "username" not in session: | ||
| return redirect("/login/redirect=&my-bookmarks") | ||
|
|
||
| # Get user ID | ||
| user = User.query.filter_by(username=session["username"]).first() | ||
| if not user: | ||
| return redirect("/login/redirect=&my-bookmarks") | ||
|
|
||
| # Get user's bookmarks with post details | ||
| bookmarks = db.session.query(Bookmark, Post).join( | ||
| Post, Bookmark.post_id == Post.id | ||
| ).filter( | ||
| Bookmark.user_id == user.user_id | ||
| ).order_by( | ||
| Bookmark.time_stamp.desc() | ||
| ).all() | ||
|
|
||
| # Format data for template (match the expected tuple format) | ||
| bookmarked_posts = [] | ||
| for bookmark, post in bookmarks: | ||
| bookmarked_posts.append([ | ||
| post.id, | ||
| post.title, | ||
| post.tags, | ||
| post.content, | ||
| post.banner, | ||
| post.author, | ||
| post.views, | ||
| post.time_stamp, | ||
| post.last_edit_time_stamp, | ||
| post.category, | ||
| post.url_id, | ||
| post.abstract, | ||
| ]) | ||
|
|
||
| return render_template( | ||
| "my_bookmarks.html", | ||
| bookmarked_posts=bookmarked_posts, | ||
| username=user.username, | ||
| get_profile_picture=get_profile_picture | ||
| ) | ||
|
|
||
| except Exception as e: | ||
| Log.error(f"Error loading my bookmarks page: {e}") | ||
| return redirect(url_for("index.index")) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| """ | ||
| Database migration script for adding bookmarks table | ||
| Run this script to create the bookmarks table in the database | ||
| """ | ||
|
|
||
| import os | ||
| import sys | ||
|
|
||
| # Add the parent directory to the path so we can import our modules | ||
| sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) | ||
|
|
||
| from database import db, init_db | ||
| from models import Bookmark | ||
| from app import create_app | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Same issue as in 🐛 Proposed fix-from app import create_app
+from app import appThen update line 20: - app = create_app()
- with app.app_context():
+ with app.app_context():🤖 Prompt for AI Agents |
||
| from utils.log import Log | ||
|
|
||
| def migrate_bookmarks(): | ||
| """Create the bookmarks table""" | ||
| try: | ||
| app = create_app() | ||
| with app.app_context(): | ||
| # Create all tables (this will only create the new bookmarks table) | ||
| db.create_all() | ||
| Log.success("Bookmarks table created successfully!") | ||
| return True | ||
| except Exception as e: | ||
| Log.error(f"Error creating bookmarks table: {e}") | ||
| return False | ||
|
|
||
| if __name__ == "__main__": | ||
| migrate_bookmarks() | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| """ | ||
| Test script for bookmark functionality | ||
| Tests both logged in and logged out scenarios | ||
| """ | ||
|
|
||
| import requests | ||
| import json | ||
|
|
||
| # Test configuration | ||
| BASE_URL = "http://localhost:1283" | ||
|
|
||
| def test_bookmark_functionality(): | ||
| """Test bookmark functionality""" | ||
| print("🧪 Testing Bookmark Functionality") | ||
| print("=" * 50) | ||
|
|
||
| # Test 1: Check if server is running | ||
| print("1. Testing server connection...") | ||
| try: | ||
| response = requests.get(BASE_URL) | ||
| if response.status_code == 200: | ||
| print("✅ Server is running") | ||
| else: | ||
| print(f"❌ Server returned status {response.status_code}") | ||
| return False | ||
| except Exception as e: | ||
| print(f"❌ Server connection failed: {e}") | ||
| return False | ||
|
|
||
| # Test 2: Test bookmark API without login | ||
| print("\n2. Testing bookmark API without login...") | ||
| try: | ||
| response = requests.post(f"{BASE_URL}/api/bookmark/1") | ||
| if response.status_code == 401: | ||
| print("✅ Correctly rejected unauthenticated request") | ||
| else: | ||
| print(f"❌ Unexpected status code: {response.status_code}") | ||
| print(f"Response: {response.text}") | ||
| except Exception as e: | ||
| print(f"❌ API test failed: {e}") | ||
|
|
||
| # Test 3: Test bookmark status API without login | ||
| print("\n3. Testing bookmark status API without login...") | ||
| try: | ||
| response = requests.get(f"{BASE_URL}/api/bookmark/status/1") | ||
| if response.status_code == 200: | ||
| data = response.json() | ||
| if data.get("bookmarked") == False: | ||
| print("✅ Correctly returned False for unauthenticated user") | ||
| else: | ||
| print(f"❌ Unexpected response: {data}") | ||
| else: | ||
| print(f"❌ Unexpected status code: {response.status_code}") | ||
| except Exception as e: | ||
| print(f"❌ API test failed: {e}") | ||
|
|
||
| # Test 4: Test my-bookmarks page without login | ||
| print("\n4. Testing my-bookmarks page without login...") | ||
| try: | ||
| response = requests.get(f"{BASE_URL}/my-bookmarks", allow_redirects=False) | ||
| if response.status_code == 302: | ||
| print("✅ Correctly redirected to login page") | ||
| print(f"Redirect location: {response.headers.get('Location')}") | ||
| else: | ||
| print(f"❌ Unexpected status code: {response.status_code}") | ||
| except Exception as e: | ||
| print(f"❌ Page test failed: {e}") | ||
|
|
||
| print("\n🎯 Bookmark functionality tests completed!") | ||
| return True | ||
|
Comment on lines
+12
to
+70
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fail the script when any test step fails. ✅ Suggested fix def test_bookmark_functionality():
"""Test bookmark functionality"""
+ success = True
@@
- else:
+ else:
print(f"❌ Unexpected status code: {response.status_code}")
print(f"Response: {response.text}")
+ success = False
@@
- else:
+ else:
print(f"❌ Unexpected status code: {response.status_code}")
+ success = False
@@
- else:
+ else:
print(f"❌ Unexpected status code: {response.status_code}")
+ success = False
@@
- return True
+ return success🤖 Prompt for AI Agents |
||
|
|
||
| if __name__ == "__main__": | ||
| test_bookmark_functionality() | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: DogukanUrker/FlaskBlog
Length of output: 479
🏁 Script executed:
Repository: DogukanUrker/FlaskBlog
Length of output: 574
🏁 Script executed:
Repository: DogukanUrker/FlaskBlog
Length of output: 973
🏁 Script executed:
Repository: DogukanUrker/FlaskBlog
Length of output: 735
Enforce NOT NULL for bookmark foreign keys.
The
user_idandpost_idcolumns are nullable by default. In SQL, multiple NULL values satisfy unique constraints (NULL ≠ NULL), allowing multiple bookmarks with missing user or post references. This defeats the uniqueness constraint intent (ensuring each user can bookmark each post only once). Addnullable=Falseto both foreign key columns.Suggested fix
🤖 Prompt for AI Agents