Add authentication improvements and search functionality
- Implement anonymous access control with ALLOW_ANONYMOUS_ACCESS env var - Add complete password reset workflow with token-based validation - Add username recovery functionality for better UX - Implement full-text search API with relevance scoring and highlighting - Add Docker compatibility improvements with permission handling and fallback storage - Add quick stats API for real-time dashboard updates - Improve security with proper token expiration and input validation - Add search result pagination and navigation - Enhance error handling and logging throughout the application 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -16,7 +16,10 @@ from data_collection_lib import data_methods
|
||||
# ===== STORAGE FUNCTIONS =====
|
||||
|
||||
def ensure_directories(storage_dir: str) -> Dict[str, Path]:
|
||||
"""Create and return directory paths"""
|
||||
"""Create and return directory paths with proper error handling"""
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
base = Path(storage_dir)
|
||||
|
||||
dirs = {
|
||||
@@ -27,7 +30,40 @@ def ensure_directories(storage_dir: str) -> Dict[str, Path]:
|
||||
}
|
||||
|
||||
for path in dirs.values():
|
||||
path.mkdir(parents=True, exist_ok=True)
|
||||
try:
|
||||
path.mkdir(parents=True, exist_ok=True)
|
||||
# Set proper permissions for Docker compatibility
|
||||
try:
|
||||
path.chmod(0o755)
|
||||
except (OSError, PermissionError):
|
||||
logger.warning(f"Could not set permissions for directory: {path}")
|
||||
except PermissionError as e:
|
||||
logger.error(f"Permission denied creating directory {path}: {e}")
|
||||
# For Docker compatibility, try using a temporary directory
|
||||
import tempfile
|
||||
temp_dir = Path(tempfile.gettempdir()) / 'balanceboard_data'
|
||||
temp_dir.mkdir(parents=True, exist_ok=True)
|
||||
temp_dir.chmod(0o755)
|
||||
logger.info(f"Using temporary directory: {temp_dir}")
|
||||
|
||||
# Update paths to use temp directory
|
||||
dirs['base'] = temp_dir
|
||||
dirs['posts'] = temp_dir / 'posts'
|
||||
dirs['comments'] = temp_dir / 'comments'
|
||||
dirs['moderation'] = temp_dir / 'moderation'
|
||||
|
||||
# Create temp directories
|
||||
for temp_path in dirs.values():
|
||||
temp_path.mkdir(parents=True, exist_ok=True)
|
||||
try:
|
||||
temp_path.chmod(0o755)
|
||||
except (OSError, PermissionError):
|
||||
pass # Ignore permission errors on temp files
|
||||
|
||||
except OSError as e:
|
||||
logger.error(f"Error creating directory {path}: {e}")
|
||||
# Continue with other directories
|
||||
continue
|
||||
|
||||
return dirs
|
||||
|
||||
@@ -46,10 +82,40 @@ def load_index(storage_dir: str) -> Dict:
|
||||
|
||||
|
||||
def save_index(index: Dict, storage_dir: str):
|
||||
"""Save post index to disk"""
|
||||
"""Save post index to disk with error handling"""
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
index_file = Path(storage_dir) / 'post_index.json'
|
||||
with open(index_file, 'w') as f:
|
||||
json.dump(index, f, indent=2)
|
||||
try:
|
||||
# Create backup of existing index
|
||||
if index_file.exists():
|
||||
backup_file = index_file.with_suffix('.json.backup')
|
||||
try:
|
||||
import shutil
|
||||
shutil.copy2(index_file, backup_file)
|
||||
except (OSError, PermissionError):
|
||||
logger.warning(f"Could not create backup of index file: {index_file}")
|
||||
|
||||
with open(index_file, 'w') as f:
|
||||
json.dump(index, f, indent=2)
|
||||
|
||||
except PermissionError as e:
|
||||
logger.error(f"Permission denied saving index to {index_file}: {e}")
|
||||
# Try to save to temp directory as fallback
|
||||
try:
|
||||
import tempfile
|
||||
temp_dir = Path(tempfile.gettempdir()) / 'balanceboard_data'
|
||||
temp_index_file = temp_dir / 'post_index.json'
|
||||
temp_dir.mkdir(parents=True, exist_ok=True)
|
||||
with open(temp_index_file, 'w') as f:
|
||||
json.dump(index, f, indent=2)
|
||||
logger.info(f"Index saved to temporary location: {temp_index_file}")
|
||||
except Exception as temp_e:
|
||||
logger.error(f"Failed to save index to temp location: {temp_e}")
|
||||
|
||||
except OSError as e:
|
||||
logger.error(f"Error saving index to {index_file}: {e}")
|
||||
|
||||
|
||||
def load_state(storage_dir: str) -> Dict:
|
||||
@@ -66,10 +132,29 @@ def load_state(storage_dir: str) -> Dict:
|
||||
|
||||
|
||||
def save_state(state: Dict, storage_dir: str):
|
||||
"""Save collection state to disk"""
|
||||
"""Save collection state to disk with error handling"""
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
state_file = Path(storage_dir) / 'collection_state.json'
|
||||
with open(state_file, 'w') as f:
|
||||
json.dump(state, f, indent=2)
|
||||
try:
|
||||
with open(state_file, 'w') as f:
|
||||
json.dump(state, f, indent=2)
|
||||
except PermissionError as e:
|
||||
logger.error(f"Permission denied saving state to {state_file}: {e}")
|
||||
# Try to save to temp directory as fallback
|
||||
try:
|
||||
import tempfile
|
||||
temp_dir = Path(tempfile.gettempdir()) / 'balanceboard_data'
|
||||
temp_state_file = temp_dir / 'collection_state.json'
|
||||
temp_dir.mkdir(parents=True, exist_ok=True)
|
||||
with open(temp_state_file, 'w') as f:
|
||||
json.dump(state, f, indent=2)
|
||||
logger.info(f"State saved to temporary location: {temp_state_file}")
|
||||
except Exception as temp_e:
|
||||
logger.error(f"Failed to save state to temp location: {temp_e}")
|
||||
except OSError as e:
|
||||
logger.error(f"Error saving state to {state_file}: {e}")
|
||||
|
||||
|
||||
def generate_uuid() -> str:
|
||||
|
||||
Reference in New Issue
Block a user