Files
natureinpots_community/plugins/utility/search/search.py

64 lines
2.1 KiB
Python

# plugins/utility/search/routes.py
from flask import Blueprint, render_template, request, jsonify
from flask_login import login_required, current_user
from app import db
from sqlalchemy import or_
from plugins.plant.models import Plant, PlantCommonName, PlantScientificName, Tag
from flask_wtf import FlaskForm
from wtforms import StringField, SelectMultipleField, SubmitField
from wtforms.validators import Optional, Length, Regexp
bp = Blueprint(
'search',
__name__,
url_prefix='/search',
template_folder='templates/search'
)
class SearchForm(FlaskForm):
query = StringField(
'Search',
validators=[
Optional(),
Length(min=2, max=100, message="Search term must be between 2 and 100 characters."),
Regexp(r'^[\w\s\-]+$', message="Search can only include letters, numbers, spaces, and dashes.")
]
)
tags = SelectMultipleField('Tags', coerce=int)
submit = SubmitField('Search')
@bp.route('', methods=['GET', 'POST'])
@login_required
def search():
form = SearchForm()
# populate tag choices
form.tags.choices = [(t.id, t.name) for t in Tag.query.order_by(Tag.name).all()]
results = []
if form.validate_on_submit():
q = form.query.data or ''
db_query = db.session.query(Plant).join(PlantScientific).join(PlantCommon)
if q:
like_term = f"%{q}%"
db_query = db_query.filter(
or_(
Plant.common_name.ilike(like_term),
Plant.scientific_name.ilike(like_term),
Plant.current_status.ilike(like_term)
)
)
if form.tags.data:
db_query = db_query.filter(Plant.tags.any(Tag.id.in_(form.tags.data)))
db_query = db_query.filter(Plant.owner_id == current_user.id)
results = db_query.all()
return render_template('search/search.html', form=form, results=results)
@bp.route('/tags')
@login_required
def search_tags():
term = request.args.get('term', '')
matches = Tag.query.filter(Tag.name.ilike(f"%{term}%")).limit(10).all()
return jsonify([t.name for t in matches])