Second revision

This commit is contained in:
ldy
2025-06-19 10:58:02 +08:00
parent 97c73b639d
commit 7baa3cea2a
50 changed files with 1310 additions and 129 deletions

View File

@@ -59,7 +59,7 @@ def create_app(config_name='default') -> Flask:
try:
# Configure CORS using settings from app.config
frontend_origin = "http://localhost:5173"
cors.init_app(app, resources={r"/api/*": {"origins": app.config.get('FRONTEND_ORIGIN', '*')}}, supports_credentials=True)
cors.init_app(app, resources={r"/api/*": {"origins": frontend_origin}}, supports_credentials=True)
print("CORS initialized successfully.")
except Exception as e:
print(f"Error initializing CORS: {e}")
@@ -84,12 +84,12 @@ def create_app(config_name='default') -> Flask:
from .urls import bp as urls_bp
# Register with potentially more specific prefixes
app.register_blueprint(auth_bp, url_prefix='/api')
app.register_blueprint(auth_bp, url_prefix='/api/auth')
app.register_blueprint(ai_services_bp, url_prefix="/api/ai") # Changed prefix
app.register_blueprint(activity_bp, url_prefix='/api/activity')
app.register_blueprint(projects_bp, url_prefix='/api/projects')
app.register_blueprint(dialog_bp, url_prefix="/api/dialog")
app.register_blueprint(urls_bp, url_prefix="/api/urls")
app.register_blueprint(urls_bp, url_prefix="/api") # FIXED: Changed from "/api/urls" to "/api" as urls_routes.py have /urls as default
print("Blueprints registered successfully.")
except (ModuleNotFoundError, ImportError) as e:

View File

@@ -4,8 +4,8 @@ from flask import Blueprint
# Define the Blueprint instance for the authentication module.
# 'auth' is the unique name for this blueprint.
# url_prefix='/api' so routes like '/register' become '/api/register'
bp = Blueprint('auth', __name__, url_prefix='/api')
# url_prefix='/api/auth' will be prepended to all routes defined in this blueprint.
bp = Blueprint('auth', __name__, url_prefix='/api/auth')
# Import the routes module.
# This connects the routes defined in routes.py to the 'bp' instance.

View File

@@ -5,7 +5,11 @@ import secrets
class Config:
# MongoDB Atlas connection string: set it in your environment variables
MONGO_URI: str = os.environ.get("MONGO_URI", "mongodb://localhost:27017/surfsmart")
MONGO_URI: str = os.environ.get(
"MONGO_URI",
"mongodb+srv://surfsmart_server:bmImHDsISZTeRNGN@projectdatacluster.ki0t3z8.mongodb.net/?retryWrites=true&w=majority&appName=ProjectDataCluster"
)
# Flask secret key for sessions and JWT (use a secure value in production)
SECRET_KEY: str = os.environ.get("SECRET_KEY", secrets.token_hex(32))

View File

@@ -142,7 +142,7 @@ def create_url(current_user, project_id):
# --- Prepare URL Document (using original data for optional fields) ---
# Optional fields are taken directly from original data, not schema output here
keywords_data = data.get("keywords", []) # Process keywords manually as before
keywords_data = json_data.get("keywords", []) # Process keywords manually as before
keywords_converted = []
if isinstance(keywords_data, list):
for kw in keywords_data:
@@ -153,20 +153,21 @@ def create_url(current_user, project_id):
percentage = float(kw.get("percentage", 0.0))
keywords_converted.append({"word": word, "percentage": percentage})
except (ValueError, TypeError):
logger.warning(f"Could not convert keyword percentage for word '{word}' during URL creation.")
logger.warning(
f"Could not convert keyword percentage for word '{word}' during URL creation.")
else:
logger.warning("Non-dict item found in keywords during URL creation.")
now = datetime.datetime.now(datetime.timezone.utc)
url_doc = {
"projectId": project_obj_id,
"url": user_url, # Use validated URL
"title": data.get("title", "").strip(),
"favicon": data.get("favicon", ""),
"starred": bool(data.get("starred", False)),
"note": data.get("note", "").strip(),
"url": user_url, # Use validated URL
"title": json_data.get("title", "").strip(), # FIX: Changed from data to json_data
"favicon": json_data.get("favicon", ""), # FIX: Changed from data to json_data
"starred": bool(json_data.get("starred", False)), # FIX: Changed from data to json_data
"note": json_data.get("note", "").strip(), # FIX: Changed from data to json_data
"keywords": keywords_converted,
"summary": data.get("summary", "").strip(),
"summary": json_data.get("summary", "").strip(), # FIX: Changed from data to json_data
"processingStatus": "pending",
"createdAt": now,
"updatedAt": now

View File

@@ -1,16 +1,10 @@
# utils/auth.py (or wherever token_required is defined)
# myapp/utils.py
from functools import wraps
import secrets
import jwt
from flask import request, jsonify, current_app # <-- Import current_app
# Config might still be needed for default algorithm if not in app.config
# from backend.config import Config # Keep if needed for defaults, but prefer current_app.config
# TODO Flask cannot find config inside the utils
from .config import Config # Example if config.py is in the same dir
from flask import request, jsonify, current_app
from bson.objectid import ObjectId
# Remove direct import of mongo
def token_required(f):
@@ -18,6 +12,7 @@ def token_required(f):
Decorator to ensure a valid JWT token is present in the request header
and injects the corresponding user document into the decorated function.
"""
@wraps(f)
def decorated(*args, **kwargs):
token = None
@@ -29,7 +24,7 @@ def token_required(f):
token = parts[1]
# Optional: Allow raw token directly (as in original code)
elif len(parts) == 1:
token = auth_header
token = auth_header
if not token:
return jsonify({"message": "Token is missing."}), 401
@@ -38,18 +33,20 @@ def token_required(f):
# Use current_app.config to access SECRET_KEY and JWT_ALGORITHM
secret_key = current_app.config['SECRET_KEY']
# Provide a default algorithm if not explicitly configured
algorithm = current_app.config.get('JWT_ALGORITHM', Config.JWT_ALGORITHM or 'HS256')
algorithm = current_app.config.get('JWT_ALGORITHM', 'HS256')
# Decode the token
data = jwt.decode(token, secret_key, algorithms=[algorithm])
# --- Use current_app to access mongo ---
# --- Use current_app to access extensions ---
from ..extensions import mongo # Import here to avoid circular dependency
user_id_str = data.get("user_id")
if not user_id_str:
return jsonify({"message": "Token payload missing user_id."}), 401
return jsonify({"message": "Token payload missing user_id."}), 401
# Access the 'users' collection via the mongo instance attached to current_app
current_user_doc = current_app.mongo.db.users.find_one({"_id": ObjectId(user_id_str)})
# Access the 'users' collection via the mongo instance
current_user_doc = mongo.db.users.find_one({"_id": ObjectId(user_id_str)})
# --- End database access change ---
if not current_user_doc:
@@ -65,7 +62,7 @@ def token_required(f):
return jsonify({"message": "Token has expired."}), 401
except jwt.InvalidTokenError as e:
# Specific error for other JWT validation issues
current_app.logger.warning(f"Invalid token encountered: {e}") # Log the specific error
current_app.logger.warning(f"Invalid token encountered: {e}") # Log the specific error
return jsonify({"message": "Token is invalid."}), 401
except Exception as e:
# Catch other potential errors (e.g., ObjectId conversion, DB connection issues)
@@ -90,4 +87,3 @@ def process_url(url_id):
# This function will generate a pass key for frontend-backend communication
def generate_passkey():
return secrets.token_hex(16)