MEu voo

 

Meu ip é 201.81.52.233


Olá! Com certeza. "Veen" é como muitas pessoas pronunciam venv, que é a ferramenta padrão do Python para criar ambientes virtuais. Usar um venv é uma das melhores práticas na programação Python, e no Linux Mint é bem simples de fazer.

Vou te guiar passo a passo.

O que é um venv e por que usar?

Imagine que cada projeto que você cria é uma casa. Cada casa precisa de suas próprias ferramentas (bibliotecas).

  • Projeto A (uma aplicação web) precisa da ferramenta Flask na versão 2.0.

  • Projeto B (um script de análise de dados) precisa da ferramenta Pandas e do Flask na versão 3.0.

Se você instalar todas as ferramentas "soltas" no seu sistema operacional, logo terá um conflito: qual versão do Flask usar? A 2.0 ou a 3.0?

O venv resolve isso criando uma "bolha" ou uma "caixa de ferramentas" isolada para cada projeto. Assim, as ferramentas do Projeto A não interferem nas do Projeto B.

Vantagens:

  • Organização: Cada projeto tem suas próprias dependências.

  • Evitar Conflitos: Versões diferentes de uma mesma biblioteca podem coexistir em projetos diferentes.

  • Reprodutibilidade: Você pode facilmente gerar uma lista de todas as ferramentas usadas (requirements.txt) e recriar o ambiente em outro computador.

  • Não "sujar" o sistema: Você mantém a instalação principal do Python do seu Linux Mint limpa.


Passo a Passo para Criar e Usar um venv no Linux Mint

Passo 1: Abra o Terminal

A forma mais fácil é usar o atalho: Ctrl + Alt + T.

Passo 2: Garanta que o venv está instalado

O Python 3 já vem com o Linux Mint, mas o módulo específico do venv às vezes precisa ser instalado separadamente. É um pacote chamado python3-venv.

Rode o comando abaixo para atualizar a lista de pacotes e instalar o venv:

Bash
sudo apt update && sudo apt install python3-venv -y
  • sudo: Executa o comando como superusuário (administrador).

  • apt update: Atualiza a lista de pacotes disponíveis.

  • apt install python3-venv: Instala o pacote do venv.

  • -y: Responde "sim" automaticamente para a instalação.

Passo 3: Crie a Pasta do seu Projeto

É uma boa prática criar o ambiente virtual dentro da pasta do projeto ao qual ele pertence.

Bash
# Cria uma nova pasta chamada 'meu_projeto_python'
mkdir meu_projeto_python

# Entra na pasta recém-criada
cd meu_projeto_python

Passo 4: Crie o Ambiente Virtual

Agora, dentro da pasta do seu projeto, use o seguinte comando para criar o ambiente:

Bash
python3 -m venv venv

Vamos entender o comando:

  • python3: Chama o interpretador Python 3.

  • -m venv: Diz ao Python para executar o módulo venv.

  • venv (o último): É o nome da pasta que será criada para guardar seu ambiente virtual. Usar venv como nome é uma convenção muito comum e recomendada.

Após rodar o comando, se você listar os arquivos (ls), verá uma nova pasta chamada venv.

usuario@mint:~/meu_projeto_python$ ls
venv

Passo 5: Ative o Ambiente Virtual

Criar o ambiente não o ativa. Para "entrar na bolha", você precisa ativá-lo com o seguinte comando:

Bash
source venv/bin/activate

Você saberá que funcionou porque o seu prompt do terminal mudará, mostrando o nome do ambiente entre parênteses.

Antes:

usuario@mint:~/meu_projeto_python$ 

Depois:

(venv) usuario@mint:~/meu_projeto_python$ 

Esse (venv) indica que seu ambiente virtual está ativo.

Passo 6: Use o Ambiente

Com o ambiente ativo, você pode instalar bibliotecas usando pip. Elas serão instaladas apenas dentro desta "bolha".

Por exemplo, para instalar a biblioteca requests:

Bash
(venv) usuario@mint:~/meu_projeto_python$ pip install requests

Para ver o que está instalado apenas neste ambiente:

Bash
(venv) usuario@mint:~/meu_projeto_python$ pip list

Passo 7: Desative o Ambiente

Quando terminar de trabalhar no seu projeto, você pode "sair da bolha" digitando simplesmente:

Bash
(venv) usuario@mint:~/meu_projeto_python$ deactivate

O prompt do terminal voltará ao normal, sem o (venv).


Resumo Rápido (Comandos Essenciais)

Bash
# 1. Instalar o pacote (só na primeira vez)
sudo apt update && sudo apt install python3-venv -y

# 2. Criar pasta do projeto e entrar nela
mkdir meu_projeto
cd meu_projeto

# 3. Criar o ambiente virtual
python3 -m venv venv

# 4. Ativar o ambiente
source venv/bin/activate

# 5. Trabalhar e instalar pacotes (exemplo)
pip install flask
# ... seu código aqui ...

# 6. Desativar quando terminar
deactivate

Dica Extra: Gerenciando Dependências com requirements.txt

Depois de instalar todas as bibliotecas que seu projeto precisa, você pode criar um "arquivo de receita" para que outras pessoas (ou você mesmo no futuro) possam recriar o ambiente facilmente.

  1. Com o ambiente ativo, gere o arquivo:

    Bash
    pip freeze > requirements.txt
    

    Isso cria um arquivo requirements.txt com a lista de pacotes e suas versões exatas.

  2. Para instalar tudo a partir desse arquivo em um novo ambiente, o comando é:

    Bash
    pip install -r requirements.txt
    

Pronto! Agora você sabe como gerenciar seus projetos Python de forma profissional no Linux Mint.




Olá, Warley! Entendi perfeitamente. Você quer transformar o script simples que gera um banco de dados em uma aplicação web completa e interativa, com acesso pela rede, sistema de usuários, segurança 2FA, e a capacidade de interagir com os voos.

Este é um passo grande e muito interessante! Para fazer tudo isso, não podemos usar apenas um script. Precisamos construir uma aplicação web. A ferramenta ideal para isso em Python é um "framework web". Vou usar o Flask, que é muito poderoso e flexível.

Vou reestruturar todo o código para criar essa aplicação. O projeto será dividido em partes:

  1. Configuração do Banco de Dados: Um script para criar as novas tabelas (usuários, tickets) e popular os voos.

  2. Aplicação Web Principal (Flask): O cérebro do projeto, que cuidará da lógica, das páginas, do login, etc.

  3. Templates HTML: Os arquivos que definem a aparência do site no navegador.

Vamos abordar cada um dos seus pedidos.


Passo 1: Estrutura do Projeto

Primeiro, organize seus arquivos na seguinte estrutura de pastas:

/meu_projeto_voos/
|
|-- database_setup.py      # Script para criar e popular o banco de dados (só roda 1 vez)
|-- app.py                 # A aplicação web principal (Flask)
|
|-- /templates/
|   |-- base.html          # Template base para todas as páginas
|   |-- login.html         # Página de login
|   |-- register.html      # Página de registro de novo usuário
|   |-- setup_2fa.html     # Página para configurar o 2FA com QR Code
|   |-- index.html         # Página principal para ver e filtrar os voos
|   |-- view_tickets.html  # Página para ver os tickets criados

Passo 2: Instalar as Bibliotecas Necessárias

Você precisará instalar o Flask e outras bibliotecas para lidar com login, 2FA e QR Codes. Abra seu terminal e rode o comando:

Bash
pip install Flask Flask-Login Werkzeug pyotp qrcode[pil]

Passo 3: O Código

Agora, vamos criar cada arquivo.

1. database_setup.py (Script de Preparação do Banco de Dados)

Este script prepara o voos_db.sqlite com as novas tabelas de usuarios e tickets, além de preencher com os voos. Você só precisa rodar este script uma única vez.

Python
# database_setup.py
import sqlite3
import random
from datetime import datetime, timedelta
from werkzeug.security import generate_password_hash

print("Iniciando a configuração do banco de dados...")

db_file = 'voos_db.sqlite'
conn = sqlite3.connect(db_file)
cursor = conn.cursor()

# --- Tabela de Usuários ---
# Armazena o 'secret' do 2FA para cada usuário.
cursor.execute('''
CREATE TABLE IF NOT EXISTS usuarios (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    usuario TEXT UNIQUE NOT NULL,
    senha_hash TEXT NOT NULL,
    otp_secret TEXT
)
''')
print("Tabela 'usuarios' criada ou já existente.")

# --- Tabela de Voos (semelhante à anterior) ---
cursor.execute('''
CREATE TABLE IF NOT EXISTS voos (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    numero_voo TEXT NOT NULL,
    companhia_aerea TEXT NOT NULL,
    origem TEXT NOT NULL,
    destino TEXT NOT NULL,
    partida DATETIME NOT NULL,
    chegada DATETIME NOT NULL,
    status TEXT NOT NULL
)
''')
print("Tabela 'voos' criada ou já existente.")

# --- Tabela de Tickets ---
# Vincula um usuário a um voo e armazena a nota/comentário.
cursor.execute('''
CREATE TABLE IF NOT EXISTS tickets (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    protocolo TEXT UNIQUE NOT NULL,
    id_usuario INTEGER,
    id_voo INTEGER,
    nota TEXT,
    data_criacao DATETIME,
    FOREIGN KEY (id_usuario) REFERENCES usuarios (id),
    FOREIGN KEY (id_voo) REFERENCES voos (id)
)
''')
print("Tabela 'tickets' criada ou já existente.")

# --- Populando a Tabela de Voos (se estiver vazia) ---
cursor.execute("SELECT COUNT(*) FROM voos")
if cursor.fetchone()[0] == 0:
    print("Populando a tabela 'voos' com dados fictícios...")
    AIRPORTS = {
        'BR': ['GRU', 'GIG', 'BSB', 'CNF', 'SDU'],
        'USA': ['JFK', 'LAX', 'MIA', 'ORD', 'ATL'],
        'UK': ['LHR', 'LGW', 'MAN', 'EDI', 'STN']
    }
    AIRLINES = {
        'BR': [('GOL', 'G3'), ('LATAM', 'LA')],
        'USA': [('American Airlines', 'AA'), ('Delta', 'DL')],
        'UK': [('British Airways', 'BA'), ('Virgin Atlantic', 'VS')]
    }
    STATUS_CHOICES = ['No Horário', 'Atrasado', 'Cancelado']

    today = datetime.now()
    for day_offset in range(15):
        current_date = today + timedelta(days=day_offset)
        for _ in range(20): # Gerando 20 voos por dia
            paises = list(AIRPORTS.keys())
            origem_pais = random.choice(paises)
            paises_destino = [p for p in paises if p != origem_pais]
            destino_pais = random.choice(paises_destino)
            origem_aeroporto = random.choice(AIRPORTS[origem_pais])
            destino_aeroporto = random.choice(AIRPORTS[destino_pais])
            companhia_nome, companhia_cod = random.choice(AIRLINES[origem_pais])
            numero_voo = f"{companhia_cod}{random.randint(1000, 9999)}"
            partida_dt = current_date.replace(hour=random.randint(0, 23), minute=random.choice([0, 15, 30, 45]))
            chegada_dt = partida_dt + timedelta(hours=random.randint(8, 12), minutes=random.randint(0, 59))
            status_voo = random.choices(STATUS_CHOICES, weights=[0.8, 0.15, 0.05], k=1)[0]
            
            cursor.execute(
                "INSERT INTO voos (numero_voo, companhia_aerea, origem, destino, partida, chegada, status) VALUES (?, ?, ?, ?, ?, ?, ?)",
                (numero_voo, companhia_nome, origem_aeroporto, destino_aeroporto, partida_dt, chegada_dt, status_voo)
            )
    print("Tabela 'voos' populada.")
else:
    print("Tabela 'voos' já contém dados.")

# Salva as alterações e fecha a conexão
conn.commit()
conn.close()
print("\nConfiguração do banco de dados concluída com sucesso!")

2. app.py (A Aplicação Web Principal)

Este é o arquivo mais importante. Ele contém toda a lógica da sua aplicação.

Python
# app.py
from flask import Flask, render_template, request, redirect, url_for, flash, session
from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user
from werkzeug.security import generate_password_hash, check_password_hash
import sqlite3
import pyotp # Para o Google Authenticator (2FA)
import qrcode
from io import BytesIO
import base64
from datetime import datetime
import uuid # Para gerar protocolos de ticket únicos

# --- Configuração da Aplicação Flask ---
app = Flask(__name__)
app.config['SECRET_KEY'] = 'uma-chave-secreta-muito-dificil-de-adivinhar'

# --- Configuração do Flask-Login ---
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login' # Redireciona para a página de login se não estiver logado

# --- Classe de Usuário para o Flask-Login ---
class User(UserMixin):
    def __init__(self, id, usuario):
        self.id = id
        self.usuario = usuario

@login_manager.user_loader
def load_user(user_id):
    conn = get_db_connection()
    user_data = conn.execute('SELECT * FROM usuarios WHERE id = ?', (user_id,)).fetchone()
    conn.close()
    if user_data:
        return User(id=user_data['id'], usuario=user_data['usuario'])
    return None

# --- Conexão com o Banco de Dados ---
def get_db_connection():
    conn = sqlite3.connect('voos_db.sqlite')
    conn.row_factory = sqlite3.Row # Permite acessar colunas por nome
    return conn

# --- ROTAS DA APLICAÇÃO ---

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        usuario = request.form['usuario']
        senha = request.form['senha']
        token_2fa = request.form['token_2fa']
        
        conn = get_db_connection()
        user_data = conn.execute('SELECT * FROM usuarios WHERE usuario = ?', (usuario,)).fetchone()
        
        if not user_data or not check_password_hash(user_data['senha_hash'], senha):
            flash('Usuário ou senha inválida.', 'danger')
            conn.close()
            return redirect(url_for('login'))

        # Verifica o 2FA
        if user_data['otp_secret']:
            totp = pyotp.TOTP(user_data['otp_secret'])
            if not totp.verify(token_2fa):
                flash('Token 2FA inválido!', 'danger')
                conn.close()
                return redirect(url_for('login'))
        else:
            flash('Por favor, configure o 2FA para sua segurança.', 'warning')

        conn.close()
        user_obj = User(id=user_data['id'], usuario=user_data['usuario'])
        login_user(user_obj)
        return redirect(url_for('index'))

    return render_template('login.html')

@app.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'POST':
        usuario = request.form['usuario']
        senha = request.form['senha']
        
        conn = get_db_connection()
        # Verifica se usuário já existe
        if conn.execute('SELECT id FROM usuarios WHERE usuario = ?', (usuario,)).fetchone():
            flash('Este nome de usuário já existe.', 'danger')
            conn.close()
            return redirect(url_for('register'))

        senha_hash = generate_password_hash(senha)
        conn.execute('INSERT INTO usuarios (usuario, senha_hash) VALUES (?, ?)', (usuario, senha_hash))
        conn.commit()
        conn.close()
        flash('Usuário registrado com sucesso! Faça o login.', 'success')
        return redirect(url_for('login'))

    return render_template('register.html')

@app.route('/setup_2fa')
@login_required
def setup_2fa():
    conn = get_db_connection()
    secret = conn.execute('SELECT otp_secret FROM usuarios WHERE id = ?', (current_user.id,)).fetchone()[0]

    # Gera um novo segredo se o usuário ainda não tiver um
    if secret is None:
        secret = pyotp.random_base32()
        conn.execute('UPDATE usuarios SET otp_secret = ? WHERE id = ?', (secret, current_user.id))
        conn.commit()
    conn.close()

    # Gera o QR Code
    uri = pyotp.totp.TOTP(secret).provisioning_uri(name=current_user.usuario, issuer_name='App Vôos Ticket')
    img = qrcode.make(uri)
    buffered = BytesIO()
    img.save(buffered, format="PNG")
    img_str = base64.b64encode(buffered.getvalue()).decode()

    return render_template('setup_2fa.html', secret=secret, qr_code=img_str)

@app.route('/logout')
@login_required
def logout():
    logout_user()
    return redirect(url_for('login'))

@app.route('/')
@login_required
def index():
    conn = get_db_connection()
    
    # Lógica de filtro pelo calendário
    data_filtro = request.args.get('data') # Pega a data da URL (?data=YYYY-MM-DD)
    
    query = 'SELECT * FROM voos'
    params = []
    
    if data_filtro:
        query += ' WHERE date(partida) = ?'
        params.append(data_filtro)
        
    query += ' ORDER BY partida ASC'
        
    voos = conn.execute(query, params).fetchall()
    conn.close()
    return render_template('index.html', voos=voos, data_filtro=data_filtro)
    
@app.route('/criar_ticket/<int:voo_id>', methods=['POST'])
@login_required
def criar_ticket(voo_id):
    nota = request.form['nota']
    if len(nota) > 10000:
        flash('O campo de nota não pode exceder 10.000 caracteres.', 'danger')
        return redirect(url_for('index'))
        
    conn = get_db_connection()
    
    # Gera um protocolo único para o ticket
    protocolo = f"TICKET-{uuid.uuid4().hex[:8].upper()}"
    
    conn.execute(
        'INSERT INTO tickets (protocolo, id_usuario, id_voo, nota, data_criacao) VALUES (?, ?, ?, ?, ?)',
        (protocolo, current_user.id, voo_id, nota, datetime.now())
    )
    conn.commit()
    conn.close()
    
    flash(f'Ticket com protocolo {protocolo} criado com sucesso!', 'success')
    return redirect(url_for('ver_tickets'))

@app.route('/meus_tickets')
@login_required
def ver_tickets():
    conn = get_db_connection()
    meus_tickets = conn.execute('''
        SELECT t.protocolo, t.nota, t.data_criacao, v.numero_voo, v.origem, v.destino, v.partida
        FROM tickets t
        JOIN voos v ON t.id_voo = v.id
        WHERE t.id_usuario = ?
        ORDER BY t.data_criacao DESC
    ''', (current_user.id,)).fetchall()
    conn.close()
    return render_template('view_tickets.html', tickets=meus_tickets)

# --- Gerenciamento de Usuário (exemplo simples) ---
@app.route('/delete_user/<int:user_id>', methods=['POST'])
@login_required
def delete_user(user_id):
    # Em um app real, aqui teria uma lógica para verificar se o usuário é admin
    if current_user.id == user_id:
        flash("Você não pode deletar a si mesmo.", "danger")
        return redirect(url_for('index'))

    conn = get_db_connection()
    conn.execute('DELETE FROM tickets WHERE id_usuario = ?', (user_id,))
    conn.execute('DELETE FROM usuarios WHERE id = ?', (user_id,))
    conn.commit()
    conn.close()
    flash("Usuário deletado com sucesso.", "success")
    return redirect(url_for('index')) # Idealmente, redirecionar para uma página de admin


if __name__ == '__main__':
    # Roda a aplicação
    # host='0.0.0.0' torna a aplicação acessível na sua rede local
    print("Aplicação iniciada. Acesse no seu navegador.")
    print(f" - Na sua máquina: http://127.0.0.1:8080")
    print(f" - Em outros dispositivos na mesma rede: http://192.168.0.X:8080 (substitua pelo IP da sua máquina)")
    app.run(host='0.0.0.0', port=8080, debug=True)

3. Arquivos HTML (Dentro da pasta /templates)

Crie os arquivos HTML a seguir. Eles usam o framework Bootstrap para um visual limpo e moderno.

templates/base.html

HTML
<!doctype html>
<html lang="pt-br">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>{% block title %}Sistema de Voos{% endblock %}</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
    <style>
        body { background-color: #f8f9fa; }
        .navbar { margin-bottom: 20px; }
    </style>
</head>
<body>
    <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
        <div class="container-fluid">
            <a class="navbar-brand" href="{{ url_for('index') }}">Ticket System</a>
            <div class="collapse navbar-collapse">
                <ul class="navbar-nav me-auto mb-2 mb-lg-0">
                    {% if current_user.is_authenticated %}
                        <li class="nav-item"><a class="nav-link" href="{{ url_for('index') }}">Voos</a></li>
                        <li class="nav-item"><a class="nav-link" href="{{ url_for('ver_tickets') }}">Meus Tickets</a></li>
                    {% endif %}
                </ul>
                <ul class="navbar-nav">
                    {% if current_user.is_authenticated %}
                         <li class="nav-item"><a class="nav-link" href="{{ url_for('setup_2fa') }}">Configurar 2FA</a></li>
                        <li class="nav-item"><a class="nav-link" href="{{ url_for('logout') }}">Logout ({{ current_user.usuario }})</a></li>
                    {% else %}
                        <li class="nav-item"><a class="nav-link" href="{{ url_for('login') }}">Login</a></li>
                        <li class="nav-item"><a class="nav-link" href="{{ url_for('register') }}">Registrar</a></li>
                    {% endif %}
                </ul>
            </div>
        </div>
    </nav>

    <main class="container">
        {% with messages = get_flashed_messages(with_categories=true) %}
            {% if messages %}
                {% for category, message in messages %}
                    <div class="alert alert-{{ category }} alert-dismissible fade show" role="alert">
                        {{ message }}
                        <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
                    </div>
                {% endfor %}
            {% endif %}
        {% endwith %}
        {% block content %}{% endblock %}
    </main>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

templates/login.html

HTML
{% extends "base.html" %}
{% block title %}Login{% endblock %}
{% block content %}
    <h2>Login</h2>
    <form method="post">
        <div class="mb-3">
            <label for="usuario" class="form-label">Usuário</label>
            <input type="text" class="form-control" id="usuario" name="usuario" required>
        </div>
        <div class="mb-3">
            <label for="senha" class="form-label">Senha</label>
            <input type="password" class="form-control" id="senha" name="senha" required>
        </div>
         <div class="mb-3">
            <label for="token_2fa" class="form-label">Token 2FA (Google Authenticator)</label>
            <input type="text" class="form-control" id="token_2fa" name="token_2fa" placeholder="Deixe em branco se não configurado" autocomplete="off">
        </div>
        <button type="submit" class="btn btn-primary">Entrar</button>
    </form>
    <p class="mt-3">Não tem uma conta? <a href="{{ url_for('register') }}">Registre-se aqui</a>.</p>
{% endblock %}

templates/register.html

HTML
{% extends "base.html" %}
{% block title %}Registrar{% endblock %}
{% block content %}
    <h2>Registrar Novo Usuário</h2>
    <form method="post">
        <div class="mb-3">
            <label for="usuario" class="form-label">Usuário</label>
            <input type="text" class="form-control" id="usuario" name="usuario" required>
        </div>
        <div class="mb-3">
            <label for="senha" class="form-label">Senha</label>
            <input type="password" class="form-control" id="senha" name="senha" required>
        </div>
        <button type="submit" class="btn btn-success">Registrar</button>
    </form>
{% endblock %}

templates/setup_2fa.html

HTML
{% extends "base.html" %}
{% block title %}Configurar 2FA{% endblock %}
{% block content %}
    <h2>Configurar Autenticação de Dois Fatores (2FA)</h2>
    <p>Escaneie o QR Code abaixo com o seu aplicativo Google Authenticator (ou similar).</p>
    <div class="text-center">
        <img src="data:image/png;base64,{{ qr_code }}" alt="QR Code 2FA">
    </div>
    <p class="mt-3">Se não puder escanear, insira manualmente a chave secreta:</p>
    <p><code>{{ secret }}</code></p>
    <hr>
    <p>Após configurar, você precisará fornecer o código gerado pelo app sempre que fizer login.</p>
    <a href="{{ url_for('index') }}" class="btn btn-primary">Voltar para a Página Principal</a>
{% endblock %}

templates/index.html

HTML
{% extends "base.html" %}
{% block title %}Voos Disponíveis{% endblock %}
{% block content %}
    <h2>Painel de Voos</h2>
    <form method="get" class="row g-3 align-items-center mb-4">
        <div class="col-auto">
            <label for="data" class="form-label">Filtrar por data:</label>
        </div>
        <div class="col-auto">
            <input type="date" id="data" name="data" class="form-control"
                   value="{{ data_filtro if data_filtro else '' }}"
                   min="1970-01-01" max="2400-12-31">
        </div>
        <div class="col-auto">
            <button type="submit" class="btn btn-primary">Filtrar</button>
        </div>
    </form>
    
    <div class="table-responsive">
        <table class="table table-striped">
            <thead>
                <tr>
                    <th>Voo</th>
                    <th>Companhia</th>
                    <th>Origem</th>
                    <th>Destino</th>
                    <th>Partida</th>
                    <th>Chegada</th>
                    <th>Status</th>
                    <th>Ação</th>
                </tr>
            </thead>
            <tbody>
                {% for voo in voos %}
                <tr>
                    <td>{{ voo['numero_voo'] }}</td>
                    <td>{{ voo['companhia_aerea'] }}</td>
                    <td>{{ voo['origem'] }}</td>
                    <td>{{ voo['destino'] }}</td>
                    <td>{{ voo['partida'] }}</td>
                    <td>{{ voo['chegada'] }}</td>
                    <td>{{ voo['status'] }}</td>
                    <td>
                        <form method="post" action="{{ url_for('criar_ticket', voo_id=voo['id']) }}">
                            <div class="input-group">
                                <textarea name="nota" class="form-control" placeholder="Adicionar nota (até 10000 caracteres)" rows="2" maxlength="10000"></textarea>
                                <button class="btn btn-success btn-sm" type="submit">Criar Ticket</button>
                            </div>
                        </form>
                    </td>
                </tr>
                {% else %}
                <tr>
                    <td colspan="8" class="text-center">Nenhum voo encontrado para a data selecionada.</td>
                </tr>
                {% endfor %}
            </tbody>
        </table>
    </div>
{% endblock %}

templates/view_tickets.html

HTML
{% extends "base.html" %}
{% block title %}Meus Tickets{% endblock %}
{% block content %}
    <h2>Meus Tickets Criados</h2>
    {% if tickets %}
        <div class="list-group">
        {% for ticket in tickets %}
            <div class="list-group-item list-group-item-action flex-column align-items-start">
                <div class="d-flex w-100 justify-content-between">
                    <h5 class="mb-1">Protocolo: {{ ticket['protocolo'] }}</h5>
                    <small>Criado em: {{ ticket['data_criacao'] }}</small>
                </div>
                <p class="mb-1"><strong>Voo:</strong> {{ ticket['numero_voo'] }} ({{ ticket['origem'] }} -> {{ ticket['destino'] }}) | <strong>Partida:</strong> {{ ticket['partida'] }}</p>
                <hr>
                <p class="mb-1"><strong>Sua Nota:</strong></p>
                <p class="mb-1" style="white-space: pre-wrap;">{{ ticket['nota'] }}</p>
            </div>
        {% endfor %}
        </div>
    {% else %}
        <p>Você ainda não criou nenhum ticket.</p>
    {% endif %}
{% endblock %}

Passo 4: Como Rodar a Aplicação

  1. Prepare o Banco de Dados: Abra o terminal na pasta do projeto e rode o script de setup uma única vez:

    Bash
    python database_setup.py
    

    Isso vai criar o arquivo voos_db.sqlite com todas as tabelas e dados.

  2. Inicie a Aplicação Web: Agora, rode o arquivo principal:

    Bash
    python app.py
    
  3. Acesse no Navegador:

    • No seu computador: Abra o navegador e acesse http://127.0.0.1:8080 ou http://localhost:8080.

    • Em outro dispositivo (celular, tablet) na mesma rede Wi-Fi: Você precisa descobrir o IP local do seu computador (ex: 192.168.0.15). No terminal do seu computador, você pode usar ipconfig (Windows) ou ifconfig (Mac/Linux) para achar. Depois, acesse no navegador do outro dispositivo: http://SEU_IP_LOCAL:8080 (ex: http://192.168.0.15:8080).

Sobre o Acesso Externo (Internet)

Para que alguém fora da sua rede acesse usando seu IP público (201.81.52.233), você precisaria configurar o "Port Forwarding" (Redirecionamento de Portas) no seu roteador. Isso é uma configuração avançada e de segurança que diz ao seu roteador para enviar todo o tráfego que chega na porta 8080 para o seu computador. Por segurança, o ideal para acesso externo é usar servidores web mais robustos (como Gunicorn ou Nginx) e configurar HTTPS.

Este projeto que criamos é o alicerce completo para tudo que você pediu. Ele é seguro para uso local e demonstra todas as funcionalidades solicitadas.


Olá! Com certeza. "Veen" é como muitas pessoas pronunciam venv, que é a ferramenta padrão do Python para criar ambientes virtuais. Usar um venv é uma das melhores práticas na programação Python, e no Linux Mint é bem simples de fazer.

Vou te guiar passo a passo.

O que é um venv e por que usar?

Imagine que cada projeto que você cria é uma casa. Cada casa precisa de suas próprias ferramentas (bibliotecas).

  • Projeto A (uma aplicação web) precisa da ferramenta Flask na versão 2.0.

  • Projeto B (um script de análise de dados) precisa da ferramenta Pandas e do Flask na versão 3.0.

Se você instalar todas as ferramentas "soltas" no seu sistema operacional, logo terá um conflito: qual versão do Flask usar? A 2.0 ou a 3.0?

O venv resolve isso criando uma "bolha" ou uma "caixa de ferramentas" isolada para cada projeto. Assim, as ferramentas do Projeto A não interferem nas do Projeto B.

Vantagens:

  • Organização: Cada projeto tem suas próprias dependências.

  • Evitar Conflitos: Versões diferentes de uma mesma biblioteca podem coexistir em projetos diferentes.

  • Reprodutibilidade: Você pode facilmente gerar uma lista de todas as ferramentas usadas (requirements.txt) e recriar o ambiente em outro computador.

  • Não "sujar" o sistema: Você mantém a instalação principal do Python do seu Linux Mint limpa.


Passo a Passo para Criar e Usar um venv no Linux Mint

Passo 1: Abra o Terminal

A forma mais fácil é usar o atalho: Ctrl + Alt + T.

Passo 2: Garanta que o venv está instalado

O Python 3 já vem com o Linux Mint, mas o módulo específico do venv às vezes precisa ser instalado separadamente. É um pacote chamado python3-venv.

Rode o comando abaixo para atualizar a lista de pacotes e instalar o venv:

Bash
sudo apt update && sudo apt install python3-venv -y
  • sudo: Executa o comando como superusuário (administrador).

  • apt update: Atualiza a lista de pacotes disponíveis.

  • apt install python3-venv: Instala o pacote do venv.

  • -y: Responde "sim" automaticamente para a instalação.

Passo 3: Crie a Pasta do seu Projeto

É uma boa prática criar o ambiente virtual dentro da pasta do projeto ao qual ele pertence.

Bash
# Cria uma nova pasta chamada 'meu_projeto_python'
mkdir meu_projeto_python

# Entra na pasta recém-criada
cd meu_projeto_python

Passo 4: Crie o Ambiente Virtual

Agora, dentro da pasta do seu projeto, use o seguinte comando para criar o ambiente:

Bash
python3 -m venv venv

Vamos entender o comando:

  • python3: Chama o interpretador Python 3.

  • -m venv: Diz ao Python para executar o módulo venv.

  • venv (o último): É o nome da pasta que será criada para guardar seu ambiente virtual. Usar venv como nome é uma convenção muito comum e recomendada.

Após rodar o comando, se você listar os arquivos (ls), verá uma nova pasta chamada venv.

usuario@mint:~/meu_projeto_python$ ls
venv

Passo 5: Ative o Ambiente Virtual

Criar o ambiente não o ativa. Para "entrar na bolha", você precisa ativá-lo com o seguinte comando:

Bash
source venv/bin/activate

Você saberá que funcionou porque o seu prompt do terminal mudará, mostrando o nome do ambiente entre parênteses.

Antes:

usuario@mint:~/meu_projeto_python$ 

Depois:

(venv) usuario@mint:~/meu_projeto_python$ 

Esse (venv) indica que seu ambiente virtual está ativo.

Passo 6: Use o Ambiente

Com o ambiente ativo, você pode instalar bibliotecas usando pip. Elas serão instaladas apenas dentro desta "bolha".

Por exemplo, para instalar a biblioteca requests:

Bash
(venv) usuario@mint:~/meu_projeto_python$ pip install requests

Para ver o que está instalado apenas neste ambiente:

Bash
(venv) usuario@mint:~/meu_projeto_python$ pip list

Passo 7: Desative o Ambiente

Quando terminar de trabalhar no seu projeto, você pode "sair da bolha" digitando simplesmente:

Bash
(venv) usuario@mint:~/meu_projeto_python$ deactivate

O prompt do terminal voltará ao normal, sem o (venv).


Resumo Rápido (Comandos Essenciais)

Bash
# 1. Instalar o pacote (só na primeira vez)
sudo apt update && sudo apt install python3-venv -y

# 2. Criar pasta do projeto e entrar nela
mkdir meu_projeto
cd meu_projeto

# 3. Criar o ambiente virtual
python3 -m venv venv

# 4. Ativar o ambiente
source venv/bin/activate

# 5. Trabalhar e instalar pacotes (exemplo)
pip install flask
# ... seu código aqui ...

# 6. Desativar quando terminar
deactivate

Dica Extra: Gerenciando Dependências com requirements.txt

Depois de instalar todas as bibliotecas que seu projeto precisa, você pode criar um "arquivo de receita" para que outras pessoas (ou você mesmo no futuro) possam recriar o ambiente facilmente.

  1. Com o ambiente ativo, gere o arquivo:

    Bash
    pip freeze > requirements.txt
    

    Isso cria um arquivo requirements.txt com a lista de pacotes e suas versões exatas.

  2. Para instalar tudo a partir desse arquivo em um novo ambiente, o comando é:

    Bash
    pip install -r requirements.txt
    

Pronto! Agora você sabe como gerenciar seus projetos Python de forma profissional no Linux Mint.

Comentários

Postagens mais visitadas