Second revision
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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))
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user