MemPrepMate / src /routes /profile.py
Christian Kniep
'back to single API on EC2'
2630788
"""
Profile management routes.
Feature: 012-profile-contact-ui
User Story 1: Profile Management
"""
import logging
from flask import Blueprint, render_template, request, redirect, url_for, flash, session, jsonify
from ..services.backend_client import backend_client, BackendAPIError
from ..services.storage_service import (
get_user_profile,
create_or_update_user,
)
logger = logging.getLogger(__name__)
bp = Blueprint("profile", __name__, url_prefix="/profile")
@bp.route("/")
def view_profile():
"""Display user profile with facts."""
# Check authentication
if "user_id" not in session:
flash("Please log in to view your profile.", "warning")
return redirect(url_for("auth.login"))
user_id = session["user_id"]
try:
# Get user profile from SQLite
user_profile = get_user_profile(user_id)
if not user_profile:
flash("Profile not found. Please log in again.", "error")
return redirect(url_for("auth.logout"))
# Get profile facts from backend (mode="memorize")
facts = backend_client.get_messages(user_profile.session_id, user_id, mode="memorize")
return render_template(
"profile/view.html",
user_profile=user_profile,
facts=facts,
)
except BackendAPIError as e:
flash(f"Error loading profile: {str(e)}", "error")
return render_template("profile/view.html", user_profile=None, facts=[])
@bp.route("/facts/add", methods=["POST"])
def add_fact():
"""Add a new fact to user profile."""
# Check authentication
if "user_id" not in session:
return {"error": "Unauthorized"}, 401
user_id = session["user_id"]
fact_content = request.form.get("content", "").strip()
# Validate input
if not fact_content:
flash("Fact content cannot be empty.", "error")
return redirect(url_for("profile.view_profile"))
if len(fact_content) > 500:
flash("Fact content exceeds 500 characters.", "error")
return redirect(url_for("profile.view_profile"))
try:
# Get user profile
user_profile = get_user_profile(user_id)
if not user_profile:
flash("Profile not found.", "error")
return redirect(url_for("auth.logout"))
# Send fact to backend with proper attribution (Feature: 001-refine-memory-producer-logic)
# Profile facts: producer=user_id, produced_for="prepmate"
logger.info(
f"Saving profile fact: user_id={user_id}, producer={user_id}, "
f"produced_for=prepmate, content_length={len(fact_content)}"
)
backend_client.send_message(
session_id=user_profile.session_id,
content=fact_content,
user_id=user_id,
mode="memorize",
producer=user_id, # User is the producer
produced_for="prepmate", # Produced for the prepmate system
)
# Fetch updated facts to ensure immediate visibility (T010)
facts = backend_client.get_messages(user_profile.session_id, user_id, mode="memorize")
logger.info(f"Profile fact saved successfully for user {user_id}")
# Feature: 012-realtime-message-display - Return JSON for AJAX requests
if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
# Find the newly added fact (last fact in the list)
new_fact = facts[-1] if facts else None
return jsonify({
'success': True,
'message': {
'id': new_fact.message_id if new_fact else None,
'content': fact_content,
'role': 'user',
'type': 'fact',
'created_at': new_fact.created_at if new_fact else None
}
})
# Re-render with updated facts instead of redirect
return render_template(
"profile/view.html",
user_profile=user_profile,
facts=facts,
)
except BackendAPIError as e:
flash(f"Error adding fact: {str(e)}", "error")
# Preserve input on error by passing it to template
user_profile = get_user_profile(user_id)
facts = backend_client.get_messages(user_profile.session_id, user_id, mode="memorize") if user_profile else []
return render_template(
"profile/view.html",
user_profile=user_profile,
facts=facts,
preserved_content=fact_content,
)
@bp.route("/facts/delete/<message_id>", methods=["POST"])
def delete_fact(message_id: str):
"""Delete a fact from user profile."""
# Check authentication
if "user_id" not in session:
return {"error": "Unauthorized"}, 401
# Note: Backend API does not support message deletion yet
# This is a placeholder for future implementation
flash("Fact deletion not yet implemented.", "warning")
return redirect(url_for("profile.view_profile"))