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)