Arquivos e e-mail
Tradução automática
Esta página foi traduzida automaticamente do inglês e ainda não foi revisada por um falante nativo; correções são bem-vindas no GitHub. Se algo não bater, vale o original em inglês. O código é o mesmo do original.
Um formulário pode receber um arquivo, uma página pode devolver um, e uma ação pode mandar e-mail. O projects/helpdesk usa os três: chamados com um anexo, um e-mail para a equipe de suporte e para quem abriu o chamado.
Receber um arquivo
Declare o arquivo como um parâmetro da ação. accept e maxsize são regras como minlength: um arquivo que as quebra nunca chega à ação, e o formulário mostra o motivo ao lado do campo.
<q:action name="open" method="POST">
<q:param name="title" required="true" minlength="5" />
<q:param name="attachment" type="file" maxsize="5MB" accept=".png,.jpg,.pdf" />
<q:if condition="attachment">
<q:file action="upload" file="{attachment}" result="saved" />
<!-- saved.filename, saved.original_filename, saved.size, saved.mimetype -->
</q:if>
<q:redirect url="/" flash="Ticket opened: {title}" />
</q:action>
<ui:form on-submit="open" submit="Open ticket">
<ui:input bind="title" />
<ui:input bind="attachment" />
</ui:form>O formulário sabe que a ação recebe um arquivo: ele envia multipart/form-data, e attachment é um campo de arquivo que oferece .png,.jpg,.pdf. Você não escreve nenhum dos dois.
O arquivo é salvo em paths.uploads (./uploads, a menos que a configuração diga outra coisa), com um nome seguro; destination="invoices" o coloca numa pasta lá dentro. Guarde o saved.filename — é como você acha o arquivo de novo.
q:file action é upload, delete ou send (abaixo); qualquer outra coisa não passa pelo parser:
<q:file action="copy" file="{attachment}" />Erro: <q:file action="copy">: use upload, delete or send
Um campo de várias linhas é <ui:input bind="description" rows="6" />.
Devolver um arquivo
Os uploads não são servidos como arquivos estáticos: qualquer um com a URL poderia lê-los. Uma página envia um, e decide quem pode recebê-lo:
<!-- components/attachment/[id].q -->
<q:component name="Attachment">
<q:query name="ticket" datasource="db">
SELECT attachment, attachment_name FROM tickets WHERE id = :id AND attachment IS NOT NULL
<q:param name="id" value="{id}" type="integer" />
</q:query>
<q:if condition="ticket_result.recordCount == 1">
<q:file action="send" file="{ticket[0].attachment}" name="{ticket[0].attachment_name}" />
</q:if>
<p>There is no attachment for ticket #{id}.</p>
</q:component>q:file action="send" termina a página com o arquivo como download. O nome guardado vem do banco, nunca da URL; um caminho fora de paths.uploads é recusado, e um arquivo que falta responde 404. Coloque uma guarda na página (require_auth, ou um q:if com q:redirect) e só as pessoas certas o recebem.
Mandar e-mail
Uma ação manda uma mensagem com q:mail; o servidor é a seção mail: do quantum.config.yaml. Da receita E-mail em desenvolvimento, testada como aparece:
<q:component name="Contact">
<q:action name="send" method="POST">
<q:param name="email" type="email" required="true" />
<q:param name="message" required="true" minlength="5" />
<q:mail to="support@example.com" reply_to="{email}" subject="Contact from {email}" type="text">{message}</q:mail>
<q:redirect url="/" flash="Thanks! We will answer {email}." />
</q:action>
<h1>Contact us</h1>
<q:if condition="flash"><p class="flash">{flash}</p></q:if>
<form method="POST" action="/?action=send">
<input name="email" type="email" />
<textarea name="message"></textarea>
<button>Send</button>
</form>
</q:component># Recipe: mail in development. `host: log` writes each message to the log
# instead of sending it; set SMTP_HOST in production and the same page sends.
paths:
components: ./components
mail:
host: ${SMTP_HOST:-log}
from: support@example.comhost: log grava cada mensagem no log em vez de enviá-la — use em desenvolvimento. Sem uma seção mail:, o q:mail é um erro que diz isso; ele nunca finge enviar:
<q:mail to="ana@example.com" subject="Welcome">Hello, Ana!</q:mail>Erro: q:mail needs a mail server
Quando o servidor diz não
Uma mensagem que o servidor não aceita para a ação com o motivo do servidor. Quando o resto da ação precisa acontecer mesmo assim, diga onerror="continue" e confira <name>_result.success — da receita Quando o servidor de e-mail diz não, em que o pedido é salvo mesmo quando a confirmação não pode ser enviada:
<q:component name="Order">
<q:action name="order" method="POST">
<q:param name="email" type="email" required="true" />
<q:param name="item" required="true" />
<q:query name="saved" datasource="db">
INSERT INTO orders (email, item) VALUES (:email, :item)
<q:param name="email" value="{email}" type="string" />
<q:param name="item" value="{item}" type="string" />
</q:query>
<!-- onerror="continue": a refused message does not undo the order -->
<q:mail name="confirmation" to="{email}" subject="Your order: {item}"
type="text" onerror="continue">We received your order for {item}.</q:mail>
<q:if condition="confirmation_result.success">
<q:redirect url="/" flash="Ordered {item}. A confirmation is on its way." />
</q:if>
<q:redirect url="/" flash="Ordered {item}. We could not send the confirmation e-mail." />
</q:action>
<h1>Order</h1>
<q:if condition="flash"><p class="flash">{flash}</p></q:if>
<form method="POST" action="/?action=order">
<input name="email" type="email" />
<input name="item" />
<button>Order</button>
</form>
</q:component>O helpdesk (projects/helpdesk) faz o mesmo: salva o chamado primeiro e diz, na sua mensagem, quando um e-mail não pôde ser enviado.