64 lines
2.1 KiB
Python
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])
|