import os import secrets import sys import logging import time from pathlib import Path from flask import Flask from flask_bootstrap import Bootstrap5 from flask_login import LoginManager from flask_wtf.csrf import CSRFProtect from flask_mail import Mail from sqlalchemy.orm import joinedload from dotenv import load_dotenv # Carregar .env antes de importar módulos load_dotenv(Path(__file__).resolve().parent / ".env") from functions.database import get_db_session, Usuario from functions.rbac import Role from functions.template_helpers import permission_context_processor, init_template_filters, safe_render_helper from logging.handlers import RotatingFileHandler # Importar blueprints from controllers.auth_controller import auth_bp from controllers.home_controller import home_bp from controllers.militante_controller import militante_bp from controllers.pagamento_controller import pagamento_bp from controllers.cota_controller import cota_bp from controllers.usuario_controller import usuario_bp from controllers.material_controller import material_bp from routes.admin import admin_bp # Import cache service from services.cache_service import cache_service def setup_logging(app): """Configure logging for the application""" if not app.debug and not app.testing: # Create logs directory if it doesn't exist if not os.path.exists('logs'): os.mkdir('logs') # File handler for general logs file_handler = RotatingFileHandler('logs/controles.log', maxBytes=10240000, backupCount=10) file_handler.setFormatter(logging.Formatter( '%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]' )) file_handler.setLevel(logging.INFO) app.logger.addHandler(file_handler) # File handler for cache logs cache_handler = RotatingFileHandler('logs/cache.log', maxBytes=10240000, backupCount=5) cache_handler.setFormatter(logging.Formatter( '%(asctime)s %(levelname)s: %(message)s' )) cache_handler.setLevel(logging.DEBUG) # Create cache logger cache_logger = logging.getLogger('services.cache_service') cache_logger.addHandler(cache_handler) cache_logger.setLevel(logging.DEBUG) app.logger.setLevel(logging.INFO) app.logger.info('Controles startup') def create_app(): """Cria e configura a aplicação Flask""" app = Flask(__name__) app.secret_key = os.getenv('SECRET_KEY', secrets.token_hex(16)) # Setup logging setup_logging(app) # Configurar Bootstrap bootstrap = Bootstrap5(app) # Configurar CSRF Protection (desabilitado temporariamente) # csrf = CSRFProtect() # csrf.init_app(app) # Configurar cabeçalhos CSRF personalizados app.config['WTF_CSRF_CHECK_DEFAULT'] = False app.config['WTF_CSRF_HEADERS'] = ['X-CSRFToken'] # Configurar Flask-Login login_manager = LoginManager() login_manager.init_app(app) login_manager.login_view = 'auth.login' # Configurar context processors e template helpers app.context_processor(permission_context_processor) app.context_processor(safe_render_helper) # Inicializar filtros de template personalizados init_template_filters(app) # Adicionar filtros Jinja2 @app.template_filter('bitwise_and') def bitwise_and(value1, value2): """Filtro para operação bit a bit AND""" return value1 & value2 @login_manager.user_loader def load_user(user_id): """Carrega o usuário pelo ID com roles e permissions (eager).""" db = get_db_session() try: user = db.query(Usuario).options( joinedload(Usuario.roles).joinedload(Role.permissions) ).get(user_id) return user finally: db.close() # Configurar Flask-Mail app.config['MAIL_SERVER'] = os.getenv('MAIL_SERVER', 'smtp.gmail.com') app.config['MAIL_PORT'] = int(os.getenv('MAIL_PORT', 587)) app.config['MAIL_USE_TLS'] = os.getenv('MAIL_USE_TLS', 'True').lower() == 'true' app.config['MAIL_USERNAME'] = os.getenv('MAIL_USERNAME') app.config['MAIL_PASSWORD'] = os.getenv('MAIL_PASSWORD') app.config['MAIL_DEFAULT_SENDER'] = os.getenv('MAIL_DEFAULT_SENDER') mail = Mail(app) # Initialize Redis cache try: redis_url = os.getenv('REDIS_URL', 'redis://localhost:6379/0') app.logger.info(f"Initializing Redis cache with URL: {redis_url}") # Test cache connection with retry max_retries = 5 retry_delay = 2 for attempt in range(max_retries): try: if cache_service._is_connected(): app.logger.info("Redis cache connection successful") break else: app.logger.warning(f"Redis cache connection attempt {attempt + 1} failed") if attempt < max_retries - 1: time.sleep(retry_delay) retry_delay *= 2 # Exponential backoff except Exception as e: app.logger.warning(f"Redis cache connection attempt {attempt + 1} failed: {e}") if attempt < max_retries - 1: time.sleep(retry_delay) retry_delay *= 2 else: app.logger.warning("Redis cache connection failed after all retries - continuing without cache") except Exception as e: app.logger.error(f"Error initializing Redis cache: {e}") app.logger.info("Application will continue without Redis cache") # Registrar blueprints app.register_blueprint(auth_bp) app.register_blueprint(home_bp) app.register_blueprint(militante_bp) app.register_blueprint(pagamento_bp) app.register_blueprint(cota_bp) app.register_blueprint(usuario_bp) app.register_blueprint(material_bp) app.register_blueprint(admin_bp) return app def main(): """Função principal""" # Criar a aplicação app = create_app() return app # Criar a aplicação usando a função main app = main() if __name__ == '__main__': if len(sys.argv) > 1: print("app.py não aceita argumentos.") print("Use 'python scripts/manage.py --help' para comandos administrativos.") raise SystemExit(2) app.run( host='0.0.0.0', port=5000, debug=os.getenv('FLASK_ENV') == 'development' )