86 lines
No EOL
3 KiB
Python
86 lines
No EOL
3 KiB
Python
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 |