from flask import Blueprint, request, jsonify, session from sqlalchemy import or_, func from extensions import db from models.note import Note from models.notepad import Notepad from models.favorite import Favorite from models.collaborator import Collaborator from .api import check_pad_write_permission import urllib.request import urllib.parse import json search_bp = Blueprint('search', __name__) @search_bp.route('/api/search') def search_notes(): query = request.args.get('q', '') if not query: return jsonify([]) # Join Note and Notepad to filter by permissions # Explicitly join on the foreign key to ensure correct results sql_query = db.session.query(Note, Notepad).join(Notepad, Note.notepad_id == Notepad.id).filter( or_( Note.title.ilike(f'%{query}%'), Note.content.ilike(f'%{query}%') ) ) user_id = session.get('user_id') if user_id: sql_query = sql_query.filter( or_( Notepad.is_public == True, Notepad.user_id == user_id ) ) else: sql_query = sql_query.filter(Notepad.is_public == True) results = sql_query.all() # Get user favorites if logged in fav_ids = set() if user_id: favs = Favorite.query.filter_by(user_id=user_id).all() fav_ids = {f.notepad_id for f in favs} # Eagerly fetch note counts and permissions to prevent N+1 queries note_counts = dict(db.session.query(Note.notepad_id, func.count(Note.id)).filter(Note.is_hidden == False).group_by(Note.notepad_id).all()) collab_write_pad_ids = set() if user_id: collab_write_pad_ids = {c.notepad_id for c in Collaborator.query.filter_by(user_id=user_id, permission='write').all()} # Construct response with extra info for frontend (owner_id, is_public) output = [] for note, pad in results: n_dict = note.to_dict() p_dict = pad.to_dict(note_count=note_counts.get(pad.id, 0)) p_dict['is_favorite'] = pad.id in fav_ids p_dict['can_write'] = (pad.user_id == user_id) or (pad.id in collab_write_pad_ids) n_dict['notepad'] = p_dict n_dict['owner_id'] = pad.user_id # Keep for map marker compatibility n_dict['is_public'] = pad.is_public # Keep for map marker compatibility output.append(n_dict) return jsonify(output) @search_bp.route('/api/geocode') def geocode(): q = request.args.get('q', '') if not q: return jsonify([]) try: # Proxy request to Nominatim with required User-Agent url = f"https://nominatim.openstreetmap.org/search?format=json&q={urllib.parse.quote(q)}" req = urllib.request.Request(url, headers={'User-Agent': 'SpotNotesApp/1.0'}) with urllib.request.urlopen(req) as response: data = json.loads(response.read().decode()) return jsonify(data) except Exception as e: print(f"Geocode error: {e}") return jsonify({'error': str(e)}), 500