feat(search): Add complete Search UI with API and web interface
Implements full search functionality for StarPunk v1.1.0. Search API Endpoint (/api/search): - GET endpoint with query parameter (q) validation - Pagination via limit (default 20, max 100) and offset parameters - JSON response with results count and formatted search results - Authentication-aware: anonymous users see published notes only - Graceful handling of FTS5 unavailability (503 error) - Proper error responses for missing/empty queries Search Web Interface (/search): - HTML search results page with Bootstrap-inspired styling - Search form with HTML5 validation (minlength=2, maxlength=100) - Results display with title, excerpt, date, and links - Empty state for no results - Error state for FTS5 unavailability - Simple pagination (Next/Previous navigation) Navigation Integration: - Added search box to site navigation in base.html - Preserves query parameter on results page - Responsive design with emoji search icon - Accessible with proper ARIA labels FTS Index Population: - Added startup check in __init__.py for empty FTS index - Automatic rebuild from existing notes on first run - Graceful degradation if population fails - Logging for troubleshooting Security Features: - XSS prevention: HTML in search results properly escaped - Safe highlighting: FTS5 <mark> tags preserved, user content escaped - Query validation: empty queries rejected, length limits enforced - SQL injection prevention via FTS5 query parser - Authentication filtering: unpublished notes hidden from anonymous users Testing: - Added 41 comprehensive tests across 3 test files - test_search_api.py: 12 tests for API endpoint validation - test_search_integration.py: 17 tests for UI rendering and integration - test_search_security.py: 12 tests for XSS, SQL injection, auth filtering - All tests passing with no regressions Implementation follows architect specifications from: - docs/architecture/v1.1.0-validation-report.md - docs/architecture/v1.1.0-feature-architecture.md - docs/decisions/ADR-034-full-text-search.md Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -76,6 +76,31 @@ def create_app(config=None):
|
||||
|
||||
init_db(app)
|
||||
|
||||
# Initialize FTS index if needed
|
||||
from pathlib import Path
|
||||
from starpunk.search import has_fts_table, rebuild_fts_index
|
||||
import sqlite3
|
||||
|
||||
db_path = Path(app.config["DATABASE_PATH"])
|
||||
data_path = Path(app.config["DATA_PATH"])
|
||||
|
||||
if has_fts_table(db_path):
|
||||
# Check if index is empty (fresh migration or first run)
|
||||
try:
|
||||
conn = sqlite3.connect(db_path)
|
||||
count = conn.execute("SELECT COUNT(*) FROM notes_fts").fetchone()[0]
|
||||
conn.close()
|
||||
|
||||
if count == 0:
|
||||
app.logger.info("FTS index is empty, populating from existing notes...")
|
||||
try:
|
||||
rebuild_fts_index(db_path, data_path)
|
||||
app.logger.info("FTS index successfully populated")
|
||||
except Exception as e:
|
||||
app.logger.error(f"Failed to populate FTS index: {e}")
|
||||
except Exception as e:
|
||||
app.logger.debug(f"FTS index check skipped: {e}")
|
||||
|
||||
# Register blueprints
|
||||
from starpunk.routes import register_routes
|
||||
|
||||
|
||||
Reference in New Issue
Block a user