Commit inicial: app de exportação da SD + deploy Docker/Coolify
Aplicação Flask (enviar SD.md -> corrigir pendências -> exportar JSON), scripts de contrato (scripts/) e infraestrutura de deploy (Dockerfile, docker-compose.yml) para VPS via Coolify. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
"""
|
||||
sessao.py — a fonte única da SD entre o upload e o download.
|
||||
|
||||
O problema que esta camada resolve: a SD é carregada uma vez, vive em memória,
|
||||
é editada e reavaliada — e o exportador recebe ESSE objeto, não um caminho de
|
||||
arquivo. Sem isto, a correção feita no formulário nunca chegaria ao JSON.
|
||||
|
||||
O que a sessão sabe: os dados (frontmatter, como CommentedMap do ruamel para o
|
||||
writeback preservar comentários), a prosa, e o resultado da última análise do
|
||||
exportador — a prévia do payload e a lista de pendências. Pendência vazia é a
|
||||
única condição para exportar, e ela é reavaliada no servidor a cada POST: o
|
||||
botão desabilitado é conforto de tela.
|
||||
|
||||
Estado em memória de processo, uma SD por vez: é ferramenta local de uso
|
||||
individual. Reiniciar o servidor descarta a sessão — o SD.md de origem continua
|
||||
intacto no disco, e nada é gravado sem ação explícita.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "scripts"))
|
||||
|
||||
from exporta_sd import Pendencia, analisar # noqa: E402
|
||||
from regras_sd import Canonico # noqa: E402
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Estados — os que a tela precisa distinguir, e nenhum a mais
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
SEM_ARQUIVO = "sem_arquivo"
|
||||
COM_PENDENCIAS = "com_pendencias"
|
||||
PRONTA = "pronta"
|
||||
EXPORTADA = "exportada"
|
||||
|
||||
ROTULO_ESTADO = {
|
||||
SEM_ARQUIVO: "Arquivo não enviado",
|
||||
COM_PENDENCIAS: "Com pendências",
|
||||
PRONTA: "Pronta para exportar",
|
||||
EXPORTADA: "JSON exportado",
|
||||
}
|
||||
|
||||
|
||||
@dataclass
|
||||
class Sessao:
|
||||
nome_arquivo: str
|
||||
dados: dict # CommentedMap do ruamel — FONTE ÚNICA, mutada pelo formulário
|
||||
corpo: str
|
||||
estado: str = COM_PENDENCIAS
|
||||
pendencias: list[Pendencia] = field(default_factory=list)
|
||||
previa: dict | None = None
|
||||
caminho_origem: Path | None = None
|
||||
ultimo_erro: str | None = None
|
||||
exportada_em: str | None = None
|
||||
|
||||
def reavaliar(self, canon: Canonico) -> None:
|
||||
"""Roda o exportador em modo de análise sobre os dados COMO ESTÃO.
|
||||
|
||||
É grátis e instantâneo; roda a cada edição. Uma edição depois da
|
||||
exportação volta a sessão para pronta/pendente: o que foi exportado era
|
||||
outra versão dos dados, e a tela não pode dizer "exportada" sobre esta.
|
||||
"""
|
||||
self.previa, self.pendencias = analisar(self.dados, self.corpo, canon)
|
||||
self.estado = PRONTA if not self.pendencias else COM_PENDENCIAS
|
||||
self.exportada_em = None
|
||||
|
||||
@property
|
||||
def pode_exportar(self) -> bool:
|
||||
return not self.pendencias
|
||||
|
||||
def marcar_exportada(self) -> None:
|
||||
self.estado = EXPORTADA
|
||||
self.exportada_em = datetime.now().isoformat(timespec="seconds")
|
||||
|
||||
def rotulo_estado(self) -> str:
|
||||
return ROTULO_ESTADO.get(self.estado, self.estado)
|
||||
Reference in New Issue
Block a user