Recentemente, montei um site Jekyll hospedado nas páginas do GitHub aqui: tgarcia.com.br
Como você provavelmente sabe, as páginas do GitHub servem sites apenas estáticos (que irei me referir como front-end), o que significa que não há back-end disponível para criar coisas como formulário de contato.
Em primeiro lugar, estava apenas a fornecer o meu endereço de e-mail no site, que acabou por ser BAD IDEA. Pensando melhor decidi que precisava de um formulário de contato com um desafio de Captcha – e para isso preciso de um back-end para enviar este e-mail.
Não demorou muito para eu encontrar o post Criar um formulário de contato para Jekyll , que é incrível, porém descreve uma solução para sites que atendem tanto front-end quanto back-end no mesmo nó.
O que difere do meu caso, uma vez que tenho o front-end sendo servido nas páginas do GitHub, e o back-end deve ser servido em outro lugar (no meu caso, eu uso o Heroku ).
Bom, depois de um final de semana de trabalho consegui montar uma solução para contemplar meu cenário e aqui eu o descrevo. Tive que adicionar tratamento de requisições CORS e melhorar o fluxo de trabalho fazendo toda a validação na mesma requisição, sem usar sessões para torná-la mais segura e rápida.
- Inscreva-se para uma conta gratuita do Heroku se ainda não tiver uma.
- Crie um aplicativo no Heroku e escolha um nome significativo para você (o meu é tgarcia-contact-form ), caso contrário, o Heroku gerará um nome aleatório.
- Inscreva-se em um plano Sendgrid Starter em seu aplicativo.
- Inscreva-se em uma conta reCAPTCHA e registre seu back-end do Heroku (o meu é tgarcia-contact-form.herokuapp.com ). IMPORTANTE: selecione a opção para gerá-la como uma CHAVE GLOBAL, caso contrário, o front-end de suas páginas do GitHub não funcionará com o reCAPTCHA.
- Crie um repositório git local para um aplicativo baseado em Rack e adicione os seguintes arquivos:
Gemfile
source 'https://rubygems.org'
ruby '2.0.0'
gem 'rack'
gem 'rack-recaptcha'
gem 'sinatra'
gem 'pony'
gem 'json'
config.ru
require 'rubygems'
require 'sinatra'
require 'json'
require 'rack/recaptcha'
require 'pony'
use Rack::Recaptcha, :public_key => 'YOUR_PUBLIC_KEY_FROM_RECAPTCHA', :private_key => YOUR_PRIVATE_KEY_FROM_RECAPTCHA'
helpers Rack::Recaptcha::Helpers
require './application'
run Sinatra::Application
Insira as chaves pública e privada do seu reCAPTCHA onde especificado.
application.rb
before do
content_type :json
headers 'Access-Control-Allow-Origin' => '*',
'Access-Control-Allow-Methods' => ['POST']
end
set :protection, false
set :public_dir, Proc.new { File.join(root, "_site") }
post '/send_email' do
if recaptcha_valid?
res = Pony.mail(
:from => params[:name] + "<" + params[:email] + ">",
:to => 'YOUR_EMAIL_ADDRESS',
:subject => "[YOUR FILTER] " + params[:subject],
:body => params[:message],
:via => :smtp,
:via_options => {
:address => 'smtp.sendgrid.net',
:port => '587',
:enable_starttls_auto => true,
:user_name => ENV['SENDGRID_USERNAME'],
:password => ENV['SENDGRID_PASSWORD'],
:authentication => :plain,
:domain => 'heroku.com'
})
content_type :json
if res
{ :message => 'success' }.to_json
else
{ :message => 'failure_email' }.to_json
end
else
{ :message => 'failure_captcha' }.to_json
end
end
not_found do
File.read('_site/404.html')
end
get '/*' do
file_name = "_site#{request.path_info}/index.html".gsub(%r{/+},'/')
if File.exists?(file_name)
File.read(file_name)
else
raise Sinatra::NotFound
end
end
Insira seu endereço de e-mail e um filtro para o assunto do e-mail.
- Agora você precisa adicionar algum código do lado do cliente que irá para o seu site Jekyll nas páginas do GitHub:
function showRecaptcha(element) {
Recaptcha.create('YOUR_PUBLIC_KEY_FROM_RECAPTCHA', element, {
theme: 'custom', // you can pick another at https://developers.google.com/recaptcha/docs/customization
custom_theme_widget: 'recaptcha_widget'
});
}
function setupRecaptcha() {
var contactFormHost = 'YOUR_BACKEND_ADDRESS_FROM_HEROKU',
form = $('#contact-form'),
notice = form.find('#notice');
if (form.length) {
showRecaptcha('recaptcha_widget');
form.submit(function(ev){
ev.preventDefault();
$.ajax({
type: 'POST',
url: contactFormHost + 'send_email',
data: form.serialize(),
dataType: 'json',
success: function(response) {
switch (response.message) {
case 'success':
form.fadeOut(function() {
form.html('<h4>' + form.data('success') + '</h4>').fadeIn();
});
break;
case 'failure_captcha':
showRecaptcha('recaptcha_widget');
notice.text(notice.data('captcha-failed')).fadeIn();
break;
case 'failure_email':
notice.text(notice.data('error')).fadeIn();
}
},
error: function(xhr, ajaxOptions, thrownError) {
notice.text(notice.data('error')).fadeIn();
}
});
});
}
}
E aqui está o meu formulário HTML:
<form id="contact-form" class="contact-form" method="post" data-success="Message successfully sent!">
<label for="name">Name</label>
<input id="name" type="text" name="name" class="field" required autofocus /><br/>
<label for="email">E-mail</label>
<input id="email" type="email" name="email" class="field" required /><br/>
<label for="subject">Subject</label>
<input id="subject" type="text" name="subject" class="field" required /><br/>
<label for="message">Message</label>
<textarea id="message" name="message" required ></textarea><br/>
<label for="recaptcha_response_field">Captcha</label>
<div id="recaptcha_widget" class="recaptcha">
<div class="image">
<div id="recaptcha_image"></div>
</div>
<div class="headline recaptcha_only_if_image">Enter the words above:</div>
<div class="headline recaptcha_only_if_audio">Enter the numbers you hear:</div>
<input type="text" id="recaptcha_response_field" name="recaptcha_response_field" required />
<span class="recaptcha_icon"><a href="javascript:Recaptcha.reload()"><i class="fa fa-refresh"></i></a></span>
<span class="recaptcha_icon recaptcha_only_if_image"><a href="javascript:Recaptcha.switch_type('audio')"><i class="fa fa-volume-up"></i></a></span>
<span class="recaptcha_icon recaptcha_only_if_audio"><a href="javascript:Recaptcha.switch_type('image')"><i class="fa fa-font"></i></a></span>
<span class="recaptcha_icon"><a href="javascript:Recaptcha.showhelp()"><i class="fa fa-question-circle"></i></a></span>
</div><br/>
<div id="notice" class="notice" data-captcha-failed="Incorrect captcha!" data-error="There was an error sending the message, please try again."></div>
<button type="submit">Send</button>
</form>
<script type="text/javascript" src="http://www.google.com/recaptcha/api/js/recaptcha_ajax.js"></script>
BTW, estou usando o Font Awesome aqui.
E se você quiser ver meus estilos (usei MENOS aqui)
.contact-form {
h4 {
color: #668944;
margin-left: 20px;
}
label {
width: 100px;
margin: 5px 0;
display: inline-block;
vertical-align: top;
}
input, textarea, .recaptcha, button {
margin: 5px 0;
padding: 5px;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
border: 1px solid #bbb;
&:focus {
outline-color: @accent-color;
}
}
input.field, textarea {
min-width: 330px;
}
input[name=subject], textarea {
width: 73%;
}
textarea {
height: 150px;
}
button {
border: 0;
background-color: @accent-color;
padding: 8px 20px;
color: #fff;
margin-top: 20px;
&:hover {
background-color: darken(@accent-color, 10%);
color: darken(#fff, 10%);
}
}
.notice {
display: none;
background-color: #f2dede;
border: 1px solid #ebccd1;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
padding: 10px 15px;
color: #a94442;
margin-top: 15px;
}
.recaptcha {
padding: 0;
display: inline-block;
div.image {
-webkit-border-radius: 5px 5px 0 0;
-moz-border-radius: 5px 5px 0 0;
border-radius: 5px 5px 0 0;
padding: 10px;
background-color: #fff;
width: 320px;
br {
display: none;
}
embed, span {
float: left;
clear: both;
a {
cursor: pointer;
font-size: 0.9em;
}
}
}
div.headline {
padding: 5px 5px 0 10px;
}
input[type=text] {
margin: 10px;
}
}
}
Aqui, @ accent-color é minha cor de link padrão.
Espero que te sirva bem!