- atualizando requirements - gitignore com as extensoes de database - garantindo admin com role associada
187 lines
6.4 KiB
Python
187 lines
6.4 KiB
Python
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'
|
|
)
|