Files
moto-adv-website/run.py
SKE087 f8508a436a Fix Interactive Route Map: Create MapRoute records from GPX files
- Create MapRoute database records for all GPX files for map visualization
- Populate route statistics (distance, elevation, coordinates) from GPX parsing
- Update GPX file statistics to mirror MapRoute data for post detail pages
- Enable /community/api/routes endpoint to return proper route data for map iframe
- Fix post detail page GPX statistics display

This resolves the issue where the community map showed '2 routes discovered'
but routes weren't actually rendering on the Leaflet.js map visualization.

Changes:
- Dockerfile: Updated init script paths and added migrate-db call
- app/__init__.py: Added admin user auto-creation with error handling
- app/routes/community.py: Added debug logging and API route for map data
- docker-compose.yml: Simplified to use .env for environment variables
- run.py: Added comprehensive database schema migration command
2025-12-31 18:46:21 +02:00

186 lines
6.7 KiB
Python

import os
from app import create_app, db
from app.models import User, Post, PostImage, GPXFile, Comment, Like, PageView, MapRoute
app = create_app()
@app.shell_context_processor
def make_shell_context():
return {
'db': db,
'User': User,
'Post': Post,
'PostImage': PostImage,
'GPXFile': GPXFile,
'Comment': Comment,
'Like': Like,
'PageView': PageView,
'MapRoute': MapRoute
}
@app.cli.command()
def init_db():
"""Initialize the database with complete schema."""
print('Creating all database tables...')
db.create_all()
print('✓ Database schema created successfully')
@app.cli.command()
def migrate_db():
"""Apply all database schema migrations to ensure compatibility."""
from sqlalchemy import text, inspect
try:
# Get database inspector
inspector = inspect(db.engine)
print('Starting database schema migration...\n')
# 1. Check and migrate posts table
if 'posts' in inspector.get_table_names():
columns = [col['name'] for col in inspector.get_columns('posts')]
if 'media_folder' not in columns:
db.session.execute(text('ALTER TABLE posts ADD COLUMN media_folder VARCHAR(100)'))
db.session.commit()
print('✓ Added media_folder column to posts table')
# Check for other expected columns
expected = ['title', 'content', 'author_id', 'published', 'created_at']
for col in expected:
if col not in columns:
print(f'✗ WARNING: Expected column {col} not found in posts table')
# 2. Check and migrate post_images table
if 'post_images' in inspector.get_table_names():
columns = [col['name'] for col in inspector.get_columns('post_images')]
if 'is_cover' not in columns:
db.session.execute(text('ALTER TABLE post_images ADD COLUMN is_cover BOOLEAN DEFAULT 0'))
db.session.commit()
print('✓ Added is_cover column to post_images table')
# 3. Check and migrate chat_rooms table
if 'chat_rooms' in inspector.get_table_names():
columns = [col['name'] for col in inspector.get_columns('chat_rooms')]
if 'category' not in columns:
db.session.execute(text('ALTER TABLE chat_rooms ADD COLUMN category VARCHAR(50) DEFAULT "general"'))
db.session.commit()
print('✓ Added category column to chat_rooms table')
if 'last_activity' not in columns:
db.session.execute(text('ALTER TABLE chat_rooms ADD COLUMN last_activity DATETIME DEFAULT CURRENT_TIMESTAMP'))
db.session.commit()
print('✓ Added last_activity column to chat_rooms table')
# 4. Check and add GPX statistics columns
if 'gpx_files' in inspector.get_table_names():
columns = [col['name'] for col in inspector.get_columns('gpx_files')]
gpx_columns = {
'total_distance': 'REAL DEFAULT 0.0',
'elevation_gain': 'REAL DEFAULT 0.0',
'max_elevation': 'REAL DEFAULT 0.0',
'min_elevation': 'REAL DEFAULT 0.0',
'total_points': 'INTEGER DEFAULT 0'
}
for col_name, col_type in gpx_columns.items():
if col_name not in columns:
db.session.execute(text(f'ALTER TABLE gpx_files ADD COLUMN {col_name} {col_type}'))
db.session.commit()
print(f'✓ Added {col_name} column to gpx_files table')
# 5. Verify all required tables exist
required_tables = [
'users', 'posts', 'post_images', 'gpx_files',
'comments', 'likes', 'page_views', 'chat_rooms',
'chat_messages', 'map_routes', 'password_reset_requests'
]
existing_tables = inspector.get_table_names()
missing_tables = [t for t in required_tables if t not in existing_tables]
if missing_tables:
print(f'\n✗ WARNING: Missing tables: {missing_tables}')
print(' Running init-db to create missing tables...')
db.create_all()
print('✓ All missing tables created')
print('\n✓ Database migration completed successfully')
print(f'✓ Total tables: {len(existing_tables)}')
except Exception as e:
print(f'✗ Migration error: {e}')
db.session.rollback()
raise
print(f'Migration error: {e}')
db.session.rollback()
@app.cli.command()
def process_gpx_files():
"""Process existing GPX files to extract statistics."""
from app.utils.gpx_processor import process_gpx_file
gpx_files = GPXFile.query.all()
processed = 0
for gpx_file in gpx_files:
try:
if process_gpx_file(gpx_file):
processed += 1
print(f'Processed: {gpx_file.original_name}')
else:
print(f'Failed to process: {gpx_file.original_name}')
except Exception as e:
print(f'Error processing {gpx_file.original_name}: {e}')
db.session.commit()
print(f'Processed {processed}/{len(gpx_files)} GPX files')
@app.cli.command()
def set_cover_images():
"""Set cover images for posts that don't have them."""
posts = Post.query.all()
updated = 0
for post in posts:
# Check if post has a cover image
cover_image = post.images.filter_by(is_cover=True).first()
if not cover_image:
# Set the first image as cover if available
first_image = post.images.first()
if first_image:
first_image.is_cover = True
updated += 1
print(f'Set cover image for post: {post.title}')
db.session.commit()
print(f'Updated {updated} posts with cover images')
@app.cli.command()
def create_admin():
"""Create an admin user."""
admin_email = os.environ.get('ADMIN_EMAIL', 'admin@moto-adv.com')
admin_password = os.environ.get('ADMIN_PASSWORD', 'admin123')
admin = User.query.filter_by(email=admin_email).first()
if admin:
print(f'Admin user {admin_email} already exists.')
return
admin = User(
nickname='admin',
email=admin_email,
is_admin=True
)
admin.set_password(admin_password)
db.session.add(admin)
db.session.commit()
print(f'Admin user created: {admin_email}')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)