Finished mailer

This commit is contained in:
R. Eric Wheeler 2016-07-13 14:29:34 -07:00
parent 70c0a92595
commit da55c23343
15 changed files with 242 additions and 91 deletions

View File

@ -74,9 +74,9 @@ module.exports = function (grunt) {
mangle: true,
report: 'gzip',
compress: {
drop_console: true
drop_console: false
},
banner: '/*! \n * Resume.PHP - v<%= pkg.version %> @license MIT (http://resume.reric.me)\n' +
banner: '/*! \n * Resume.PHP - v<%= pkg.version %> MIT (http://resume.reric.me)\n' +
' * <%= grunt.template.today("dddd, mmmm dS, yyyy, h:MM:ss tt") %> \n */\n',
footer: '\n/*! Resume.PHP end */',
nameCache: '.tmp/grunt-uglify-cache.json',

View File

@ -9,8 +9,4 @@ app:
captcha: true
captcha_sitekey: 6LcvmSQTAAAAAMmf9w6mhCbpdLvknuD9SGVHT0q-
captcha_secret: 6LcvmSQTAAAAAITkvYJjgLar1LqGGLz-ic0ZMiXo
twig_theme: default
twig_paths:
- views
- default
twig_template: uikit.html.twig
theme: default

View File

@ -8,8 +8,8 @@ app:
captcha: true
captcha_sitekey: 6LcvmSQTAAAAAMmf9w6mhCbpdLvknuD9SGVHT0q-
captcha_secret: 6LcvmSQTAAAAAITkvYJjgLar1LqGGLz-ic0ZMiXo
twig_theme: default
twig_paths:
- views
twig_template: uikit.html.twig
theme: default
#twig_paths:
# - views
#twig_template: uikit.html.twig

View File

@ -1,14 +0,0 @@
<?php
/*
* This file is part of Resume.PHP.
*
* (copyleft) R. Eric Wheeler <sikofitt@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
return [
'app' => 'neat',
];

View File

@ -38,11 +38,10 @@ $app->register(new ConfigServiceProvider(), [
$app->setDebug();
$app
->register(new TwigServiceProvider(), [
'twig.path' => [
$app->getRootDirectory() . '/app/views',
],
'twig.path' => $app->getAppDirectory() . '/themes/' . $app->config('app.theme'),
])
->register(new JsonServiceProvider())
->register(new AssetServiceProvider())
@ -59,7 +58,22 @@ $app
'monolog.name' => 'Resume.PHP',
'monolog.level' => $app->getDebug() ? Logger::DEBUG : Logger::INFO,
])
->register(new RoutingServiceProvider())
->register(new \Silex\Provider\SwiftmailerServiceProvider());
if(false === getenv('SPARKPOST_API_KEY')) {
$app['swiftmailer.transport'] = new Swift_SendmailTransport();
} else {
$app['swiftmailer.options'] = [
'host' => getenv('SPARKPOST_SMTP_HOST'),
'port' => getenv('SPARKPOST_SMTP_PORT'),
'username' => getenv('SPARKPOST_SMTP_USERNAME'),
'password' => getenv('SPARKPOST_SMTP_PASSWORD'),
'encryption' => 'tls',
'auth_mode' => 'plain',
];
}
$app->register(new RoutingServiceProvider())
->register(new ServiceControllerServiceProvider())
->register(new HttpFragmentServiceProvider());

View File

@ -1,4 +1,4 @@
{% extends app.config.twig.template %}
{% extends 'base.html.twig' %}
{% block title %}
{{ app.config.app.title | default('Resume') }}
@ -175,10 +175,10 @@
</div>
</div>
<div class="uk-form-row">
{{ form_label(contact_form.message) }}
{{ form_label(contact_form.message|raw) }}
<div class="uk-form-controls">
{{ form_widget(contact_form.message, {'attr':{'placeholder': "Please leave me a message. I will get back to you as soon as possible."}}) }} </div>
{{ form_widget(contact_form.message) }}
</div>
</div>
<div class="uk-form-row">
{{ form_label(contact_form.submit) }}
@ -207,7 +207,7 @@
<h1>Verify</h1>
<div>
<p> Verify that you are a human please.</p>
<form class="uk-form" id="recaptcha" method="post" action="/api/v1/captcha"
<form class="uk-form" id="recaptcha" method="post" action="{{ path('api_captcha') }}"
onsubmit="return false;">
<div class="uk-form-row">
<div class="g-recaptcha" data-sitekey="6LcvmSQTAAAAAMmf9w6mhCbpdLvknuD9SGVHT0q-"></div>

2
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "58b6f8f80e5846af7b9ae23a628a0861",
"hash": "e690fdd7168c515136615a9ee42053de",
"content-hash": "9d13427d982ec276ccfba5e7fdc2cd8a",
"packages": [
{

View File

@ -24,43 +24,155 @@
namespace Sikofitt\Controller;
use Prophecy\Doubler\ClassPatch\ReflectionClassNewInstancePatch;
use ReCaptcha\ReCaptcha;
use Sikofitt\Form\Type\ContactType;
use Silex\Api\ControllerProviderInterface;
use Silex\Application;
use Silex\Provider\SecurityServiceProvider;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Validator\Constraints\Collection;
use Symfony\Component\Validator\Constraints\Email;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\EqualTo;
use Symfony\Component\Validator\ValidatorBuilder;
class ApiControllerProvider implements ControllerProviderInterface
{
/**
* {@inheritdoc}
*
* @param Application $app
*
* @return mixed
*/
public function connect(Application $app)
{
$controllers = $app['controllers_factory'];
class ApiControllerProvider implements ControllerProviderInterface {
/**
* {@inheritdoc}
*
* @param Application $app
*
* @return mixed
*/
public function connect(Application $app) {
$controllers = $app['controllers_factory'];
$controllers->get('/v1/schema', function () use ($app) {
$response = new Response(file_get_contents($app->getDataDirectory() . '/schema/schema.v1.json'), Response::HTTP_OK);
$response->headers->set('Content-Type', 'application/schema+json');
$controllers->get('/v1/schema', function () use ($app) {
$response = new Response(file_get_contents($app->getDataDirectory() . '/schema/schema.v1.json'), Response::HTTP_OK);
$response->headers->set('Content-Type', 'application/schema+json');
return $response;
return $response;
});
$controllers->match('/v1/message', function (Request $request) use ($app) {
/*$app->mail(\Swift_Message::newInstance()
->setSubject('[YourSite] Feedback')
->setFrom(array('noreply@yoursite.com'))
->setTo(array('feedback@yoursite.com'))
->setBody($request->get('message'))); */
return new Response('This is the message.');
})->method('GET|POST');
$controllers->post('/v1/captcha', function (Request $request) use ($app) {
$controllers->match('/v1/message', function (Request $request) use ($app) {
static $code = 255;
$returnData = [
'status' => 'error',
'message' => 'Unknown error.',
'code' => $code,
];
$csrf = $request->getSession()->get('_csrf/contact') ?: false;
// Set some validation constraints
$constraints = [
'contact' => new Collection([
'name' => [
new Length([
'min' => 4,
'minMessage' => 'Name must be at least 4 characters.',
]
),
new NotBlank([
'message' => 'Name must not be blank.',
]
),
],
'email' => [
new Email([
'message' => 'Invalid email',
]),
new NotBlank([
'message' => 'Email must not be blank.',
]),
],
'message' => [
new Length([
'min' => 20,
'minMessage' => 'Message must be at least 20 characters.',
]),
new NotBlank([
'message' => 'Message must not be blank',
]),
],
'_token' => [
new EqualTo(['value' => $csrf, 'message' => 'Invalid token.']),
]
]
),
];
$contactFormData = $request->request->all();
$valid = $app['validator']->validate($contactFormData, new Collection($constraints));
if(count($valid) > 0) {
$sanitizeProperty = function() use ($valid) {
return str_replace(['][', '[', ']'], ['_','',''], $valid[0]->getPropertyPath());
};
return new JsonResponse([
'status' => 'error',
'message' => $valid[0]->getMessage(),
'id' => $sanitizeProperty(),
'const' => $valid[0]->getCode(),
'code' => 256
], 256);
} else {
$contactFormName = $contactFormData['contact']['name'];
$contactFormEmail = $contactFormData['contact']['email'];
$contactFormMessage = $contactFormData['contact']['message'];
$request->getSession()->remove('_csrf/contact');
try {
$app->mail(\Swift_Message::newInstance()
->setSubject('[Resume] Message')
->setFrom([$contactFormEmail => $contactFormName])
->setTo($app->config('app.email'))
->setBody($contactFormMessage)
);
$returnData = [
'status' => 'success',
'message' => 'Message successfully sent.',
'code' => 201,
'data' => $contactFormData,
];
} catch(\Exception $e) {
$returnData = [
'status' => 'error',
'message' => 'Could not send message.',
'code' => 256,
'data' => $e->getMessage(),
];
}
return new JsonResponse($returnData, 201);
}
})->method('GET|POST')->bind('api_message');
$controllers->get('/v1/emailTest', function(Request $request) use ($app) {
try {
$app->mail(\Swift_Message::newInstance()
->setSubject('[Resume] Message')
->setFrom(['eric@rewiv.com' => 'Eric'])
->setTo('eric@ericwheeler.net')
->setBody('Testing message.')
);
}
catch(\Exception $e) {
dump($e->getMessage());
}
return new Response('Hello');
});
$controllers->post('/v1/captcha', function (Request $request) use ($app) {
$captcha = new ReCaptcha('6LcvmSQTAAAAAITkvYJjgLar1LqGGLz-ic0ZMiXo');
$valid = $captcha->verify(
@ -68,38 +180,39 @@ class ApiControllerProvider implements ControllerProviderInterface
$request->server->get('REMOTE_ADDR')
);
if ($valid->isSuccess()) {
$return = [
'valid' => true,
$return = [
'valid' => true,
'message' => [
'email' => null !== $app->config('app.email') ? $app->config('app.email') : 'No email has been set in the configuration. Please let the owner know.',
'phone' => null !== $app->config('app.phone') ? $app->config('app.phone') : 'No phone has been set in the configuration. Please let the owner know.',
],
];
} else {
$errorCodes = [
'missing-input-secret' => 'The secret parameter is missing.',
'invalid-input-secret' => 'The secret parameter is invalid or malformed.',
'missing-input-response' =>'The response parameter is missing.',
'invalid-input-response' => 'The response parameter is invalid or malformed.'
}
else {
$errorCodes = [
'missing-input-secret' => 'The secret parameter is missing.',
'invalid-input-secret' => 'The secret parameter is invalid or malformed.',
'missing-input-response' => 'The response parameter is missing.',
'invalid-input-response' => 'The response parameter is invalid or malformed.',
];
foreach ($valid->getErrorCodes() as $code) {
if (array_key_exists($code, $errorCodes)) {
$errors[] = $errorCodes[$code];
}
foreach ($valid->getErrorCodes() as $code) {
if (array_key_exists($code, $errorCodes)) {
$errors[] = $errorCodes[$code];
}
if (!isset($errors)) {
$errors[] = 'An unknown error occurred.';
}
$return = [
'valid' => false,
}
if (!isset($errors)) {
$errors[] = 'An unknown error occurred.';
}
$return = [
'valid' => false,
'message' => $errors,
];
}
return new JsonResponse(json_encode($return));
});
})->bind('api_captcha');
return $controllers;
}
return $controllers;
}
}

View File

@ -46,7 +46,7 @@ class ResumeControllerProvider implements ControllerProviderInterface
$controllers->get('/', function (Request $request) use ($app, $contactForm) {
return $app['twig']->render('resume.html.twig', [
return $app['twig']->render('index.html.twig', [
'fullData' => $this->resumeData,
'basics' => $this->getResumeBasics(),

View File

@ -32,14 +32,15 @@ use Symfony\Component\Validator\Constraints\NotBlank;
class ContactType extends AbstractType
{
/**
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->setAction('/api/v1/message')
->add('name', TextType::class, [
'constraints' => [
new Length([
@ -53,7 +54,7 @@ class ContactType extends AbstractType
],
'label' => 'Name',
'label_attr' => [
'class' => 'uk-form-label',
'class' => 'uk-hidden-small uk-form-label',
],
])
->add('email', EmailType::class, [
@ -67,7 +68,7 @@ class ContactType extends AbstractType
],
'label' => 'Email',
'label_attr' => [
'class' => 'uk-form-label',
'class' => 'uk-hidden-small uk-form-label',
],
])
->add('message', TextareaType::class, [
@ -75,7 +76,7 @@ class ContactType extends AbstractType
'rows' => 5,
'cols' => 40,
'class' => 'uk-form-large uk-width-1-1',
'placeholder' => 'Please leave me a message, I will get back to you as soon as possible.',
'placeholder' => 'Please leave me a message. I will get back to you as soon as possible.',
],
'constraints' => [
new NotBlank(),
@ -84,8 +85,9 @@ class ContactType extends AbstractType
]),
],
'label_attr' => [
'class' => 'uk-invisible uk-form-label',
'class' => 'uk-hidden-small uk-form-label',
],
'label' => 'If you prefer you can send me a message at eric@ericwheeler.net',
])
->add('submit', SubmitType::class, [
@ -109,6 +111,7 @@ class ContactType extends AbstractType
$resolver->setDefaults([
'attr' => [
'class' => 'uk-form uk-form-horizontal',
'onsubmit' => 'return false;',
],
]);
}

View File

@ -32,5 +32,35 @@ jq(document).ready(function (jq) {
}
});
}); // Phone form
jq('form[name=contact]').on('submit', function(event) {
jq.post(jq(this).attr('action'), jq(this).serialize(), function(response) {
if(response.status !== 'success') {
jq('#' + response.id).addClass('uk-form-danger');
UIkit.notify('<i class="uk-icon uk-icon-frown-o uk-icon-justify uk-margin-right"></i>' + response.message + ' ('+response.code+')</div>', {
pos: 'top-center',
status: 'danger'
});
console.log(response);
} else {
console.log(response);
UIkit.notify('<i class="uk-icon uk-icon-check uk-icon-justify uk-margin-right"></i> ' + response.message, {
pos: 'top-center',
status: 'success'
});
var $wrapper = jq('#contact-form'),
$button = jq('<button class="uk-modal-close uk-button uk-button-massive uk-button-primary uk-align-center" type="button">Close</button>'),
$thankYouText = jq('<p class="uk-text-lead uk-text-center">Thank you for your message.</p><p class="uk-text-center">I will get back to you as soon as possible.</p>');
$wrapper.empty().append($thankYouText).append($button);
jq('a[href="#contact-form-wrapper"]').replaceWith('eric@ericwheeler.net');
}
});
});
jq('form[name=contact] input, form[name=contact] textarea').on('focus', function() {
if(jq(this).hasClass('uk-form-danger')) {
jq(this).removeClass('uk-form-danger');
}
});
});

View File

@ -49,8 +49,17 @@ a.profile-link {
border-bottom: 1px solid #ccc;
padding-bottom: 12px;
}
.uk-close {
&:after {
font-size:30px;
.uk-modal-dialog-blank {
.uk-close {
&:after {
font-size: 30px;
}
}
}
.uk-button-massive {
min-height: 64px;
padding: 0 36px;
line-height: 40px;
font-size: 34px;
border-radius: 2px;
}