feat(webmail,auth): leitor estilo Outlook, responder a todos, importantes e isolamento do admin de dominio
Webmail - Leitor de mensagem em componente proprio, com barra de comandos fixa, cabecalho compacto, faixa de imagens bloqueadas e chips de anexo. - Divisor arrastavel entre lista e leitor (mouse, setas, duplo clique), largura persistida e limites que preservam os dois paineis. - Destinatarios em chips (Para, Cc, Cco): aceita nomes com virgula, colagem de listas, validacao e bloqueio de envio com endereco invalido. - Responder a todos, sem o proprio endereco e sem repetidos; In-Reply-To e References nas respostas; prefixo Re:/Fwd: sem repeticao. - Marcar como importante (estrela, filtro, linha da lista) e enviar com alta importancia (Importance/X-Priority), com etiqueta no leitor. - Sanitizador: a regexp de URI customizada descartava todo atributo que nao fosse link (width, colspan, bgcolor...), o que desmontava tabelas de e-mail; imagens de fundo agora sao bloqueadas de forma reversivel. Protocols - POST /api/v1/mail/flagged (\Flagged) com bump de modseq para IMAP. - Renderizacao expoe message_id, in_reply_to e important. - Cabecalhos de resposta validados contra injecao. Auth - As views do admin de dominio eram globais: dashboard, fila de saida, DMARC, preflight e diagnostico mostravam dados de todos os dominios. Agora todas respeitam o escopo da sessao; super admin segue vendo tudo. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
b5baf33a63
commit
50a67531ba
30 files changed
+1810
-348
No files matched your search
@@ -169,3 +169,25 @@ func TestExtractAttachment_FindsInlineNamedParts(t *testing.T) {
|
||||
t.Errorf("ExtractAttachment = %q/%q", data, ctype)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRenderMessage_ReadsPriorityAndMessageID(t *testing.T) {
|
||||
cases := map[string]bool{
|
||||
"Importance: high\r\n": true,
|
||||
"Importance: High\r\n": true,
|
||||
"X-Priority: 1 (Highest)\r\n": true,
|
||||
"X-Priority: 2 (High)\r\n": true,
|
||||
"X-Priority: 3 (Normal)\r\n": false,
|
||||
"Importance: normal\r\n": false,
|
||||
"": false,
|
||||
}
|
||||
for header, want := range cases {
|
||||
raw := "From: a@b.test\r\nMessage-ID: <m1@b.test>\r\n" + header + "Subject: s\r\n\r\nbody\r\n"
|
||||
got := RenderMessage([]byte(raw), 1)
|
||||
if got.Important != want {
|
||||
t.Errorf("%q: Important = %v, want %v", header, got.Important, want)
|
||||
}
|
||||
if got.MessageID != "<m1@b.test>" {
|
||||
t.Errorf("MessageID = %q", got.MessageID)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user