diff --git a/app/views/recaptcha.html.twig b/app/themes/default/recaptcha.html.twig
similarity index 100%
rename from app/views/recaptcha.html.twig
rename to app/themes/default/recaptcha.html.twig
diff --git a/composer.lock b/composer.lock
index 25cd546..9660eca 100644
--- a/composer.lock
+++ b/composer.lock
@@ -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": [
{
diff --git a/src/Sikofitt/Controller/ApiControllerProvider.php b/src/Sikofitt/Controller/ApiControllerProvider.php
index 549a0f3..f71d740 100644
--- a/src/Sikofitt/Controller/ApiControllerProvider.php
+++ b/src/Sikofitt/Controller/ApiControllerProvider.php
@@ -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;
+ }
}
diff --git a/src/Sikofitt/Controller/ResumeControllerProvider.php b/src/Sikofitt/Controller/ResumeControllerProvider.php
index c299621..be4f731 100644
--- a/src/Sikofitt/Controller/ResumeControllerProvider.php
+++ b/src/Sikofitt/Controller/ResumeControllerProvider.php
@@ -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(),
diff --git a/src/Sikofitt/Form/Type/ContactType.php b/src/Sikofitt/Form/Type/ContactType.php
index 8b45c1a..ca891e1 100644
--- a/src/Sikofitt/Form/Type/ContactType.php
+++ b/src/Sikofitt/Form/Type/ContactType.php
@@ -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;',
],
]);
}
diff --git a/src/Sikofitt/js/resume.js b/src/Sikofitt/js/resume.js
index 8feef42..0c57109 100644
--- a/src/Sikofitt/js/resume.js
+++ b/src/Sikofitt/js/resume.js
@@ -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('
' + response.message + ' ('+response.code+')
', {
+ pos: 'top-center',
+ status: 'danger'
+ });
+ console.log(response);
+ } else {
+ console.log(response);
+ UIkit.notify('Thank you for your message.
I will get back to you as soon as possible.
');
+ $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');
+ }
});
});
\ No newline at end of file
diff --git a/src/Sikofitt/less/resume.less b/src/Sikofitt/less/resume.less
index a212e53..1fead3e 100644
--- a/src/Sikofitt/less/resume.less
+++ b/src/Sikofitt/less/resume.less
@@ -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;
}
\ No newline at end of file