diff --git a/app/App.php b/app/App.php index f0efad5..5793a9c 100644 --- a/app/App.php +++ b/app/App.php @@ -84,7 +84,7 @@ class App extends Application */ public function getResumeSchema() { - return $this->getDataDirectory() . '/resume.schema.json'; + return $this->getDataDirectory() . '/schema/schema.v1.json'; } public function getLogDirectory() @@ -129,15 +129,32 @@ class App extends Application } else { $matches = 'Available methods are unknown.'; } - $message = json_encode(['status' => 'error', 'message' => 'Method not allowed', 'allowedMethods' => $matches, 'requestedMethod' => $request->getMethod(), 'code' => $code]); - $this->log($e->getMessage(), ['code' => $code], \Symfony\Bridge\Monolog\Logger::WARNING); + $message = [ + 'status' => 'error', + 'message' => 'Method not allowed', + 'allowedMethods' => $matches, + 'requestedMethod' => $request->getMethod(), + 'code' => $code, + ]; + if($request->isXmlHttpRequest()) { + $message = json_encode($message); + } else { + $message = $this->renderView('error.405.html.twig', $message); + } + $this->log($e->getMessage(), ['code' => $code], \Symfony\Bridge\Monolog\Logger::WARNING); break; case 500: $message = json_encode(['status' => 'error', 'message' => 'Critical Error', 'code' => $code]); $this->log($e->getMessage(), ['code' => $code], \Symfony\Bridge\Monolog\Logger::CRITICAL); break; default: - $message = json_encode(['status' => 'error', 'message' => $e->getMessage(), 'code' => $code]); + $message = ['status' => 'error', 'message' => $e->getMessage(), 'code' => $code, 'requestUri' => $request->getRequestUri()]; + if($request->isXmlHttpRequest()) { + $message = json_decode($message); + } else { + $message = $this->renderView('error.html.twig', $message); + } + $this->log($e->getMessage(), ['code' => $code], \Symfony\Bridge\Monolog\Logger::ERROR); break; } diff --git a/app/config/config.yml b/app/config/config.yml index 0b6d523..68821c5 100644 --- a/app/config/config.yml +++ b/app/config/config.yml @@ -14,3 +14,4 @@ app: smtp_port: 465 smtp_user: eric@rewiv.com smtp_password: 'P*8ic32!100023&p' + from_email: no-reply@rewiv.com diff --git a/app/config/config.yml.dist b/app/config/config.yml.dist index 25f75b5..5d52f53 100644 --- a/app/config/config.yml.dist +++ b/app/config/config.yml.dist @@ -2,8 +2,9 @@ app: debug: true environment: dev title: R. Eric Wheeler | Resume - email: eric@rewiv.com - phone: 510-646-2135 + email: email@example.com + from_email: no-reply@example.com + phone: 510-555-5555 schema: https://raw.githubusercontent.com/jsonresume/resume-schema/v1.0.0/schema.json captcha: true captcha_sitekey: 6LcvmSQTAAAAAMmf9w6mhCbpdLvknuD9SGVHT0q- diff --git a/app/themes/default/error.405.html.twig b/app/themes/default/error.405.html.twig new file mode 100644 index 0000000..17b3ea6 --- /dev/null +++ b/app/themes/default/error.405.html.twig @@ -0,0 +1,13 @@ +{% extends 'base.html.twig' %} + +{% block title %}HTTP 405{% endblock %} +{% block body %} +
+ +

HTTP 405

+

{{ message }} [{{ requestedMethod }}]

+ Error 405 +

Return to the home page.

+ +
+{% endblock %} \ No newline at end of file diff --git a/app/themes/default/error.html.twig b/app/themes/default/error.html.twig new file mode 100644 index 0000000..dca8658 --- /dev/null +++ b/app/themes/default/error.html.twig @@ -0,0 +1,13 @@ +{% extends 'base.html.twig' %} + +{% block title %}HTTP {{ code }}{% endblock %} +{% block body %} +
+ +

HTTP {{ code }}

+

{{ message }} / {{ requestUri }}

+ HTTP Error {{ code }} +

Return to the home page.

+ +
+{% endblock %} diff --git a/src/Sikofitt/Controller/ApiControllerProvider.php b/src/Sikofitt/Controller/ApiControllerProvider.php index af6f5e5..9e27c34 100644 --- a/src/Sikofitt/Controller/ApiControllerProvider.php +++ b/src/Sikofitt/Controller/ApiControllerProvider.php @@ -26,6 +26,7 @@ namespace Sikofitt\Controller; use ReCaptcha\ReCaptcha; +use Sikofitt\Form\Type\ContactType; use Silex\Api\ControllerProviderInterface; use Silex\Application; use Symfony\Component\HttpFoundation\JsonResponse; @@ -36,6 +37,7 @@ use Symfony\Component\Validator\Constraints\Email; use Symfony\Component\Validator\Constraints\EqualTo; use Symfony\Component\Validator\Constraints\Length; use Symfony\Component\Validator\Constraints\NotBlank; +use Symfony\Component\Validator\Constraints\Type; /** * Class ApiControllerProvider @@ -85,6 +87,7 @@ class ApiControllerProvider implements ControllerProviderInterface { 'message' => 'Name must not be blank.', ] ), + new Type('string'), ], 'email' => [ new Email([ @@ -93,6 +96,7 @@ class ApiControllerProvider implements ControllerProviderInterface { new NotBlank([ 'message' => 'Email must not be blank.', ]), + new Type('string'), ], 'message' => [ new Length([ @@ -102,9 +106,11 @@ class ApiControllerProvider implements ControllerProviderInterface { new NotBlank([ 'message' => 'Message must not be blank', ]), + new Type('string'), ], '_token' => [ new EqualTo(['value' => $csrf, 'message' => 'Invalid token.']), + new Type('string'), ], ] ), @@ -136,57 +142,44 @@ class ApiControllerProvider implements ControllerProviderInterface { $contactFormName = $contactFormData['contact']['name']; $contactFormEmail = $contactFormData['contact']['email']; - $contactFormMessage = $contactFormData['contact']['message']; - $message = sprintf("%s\n\nEmail : %s <%s>", $contactFormMessage, $contactFormName, $contactFormEmail); + $contactFormMessage = sprintf("%s\n\nEmail : %s <%s>", $contactFormData['contact']['message'], $contactFormName, $contactFormEmail); $failures = ''; - - $sent = $app['mailer']->send(\Swift_Message::newInstance() - ->setSubject('[Resume] Message') - ->setFrom(['no-reply@rewiv.com' => $contactFormName]) - ->setTo([$app->config('app.email') => 'No-Reply']) - ->setReplyTo([$contactFormEmail => $contactFormName]) - ->setBody($message) - , $failures); - if($sent > 0) { - $request->getSession()->remove('_csrf/contact'); - return new JsonResponse([ - 'status' => 'success', - 'message' => 'Message successfully sent.', - 'code' => 201, - 'data' => $contactFormData, - 'failed' => $failures, - 'sent' => $sent, - ], 200); - - } else { - return new JsonResponse([ - 'status' => 'error', - 'message' => 'There was an error sending the message.', - 'code' => 255, - 'data' => $contactFormData, - 'failed' => $failures, - 'sent' => $sent, - ], 255); - } - } - - - })->method('GET|POST')->bind('api_message'); - - $controllers->get('/v1/emailTest', function (Request $request) use ($app) { - try { - $app->mail(\Swift_Message::newInstance() + $message = \Swift_Message::newInstance() ->setSubject('[Resume] Message') - ->setFrom(['eric@rewiv.com' => 'Eric']) - ->setTo('eric@ericwheeler.net') - ->setBody('Testing message.') - ); - } catch (\Exception $e) { - dump($e->getMessage()); + ->setFrom([$app->config('app.from_email') => $contactFormName]) + ->setTo([$app->config('app.email') => 'No-Reply']) + ->setReplyTo([$contactFormEmail => $contactFormName]) + ->setBody($contactFormMessage); + + $sent = $app['mailer']->send($message, $failures); + if ($sent > 0) { + $request->getSession()->remove('_csrf/contact'); + + return new JsonResponse([ + 'status' => 'success', + 'message' => 'Message successfully sent.', + 'code' => 201, + 'data' => $contactFormData, + 'sent' => $sent, + ], 201); + } + else { + return new JsonResponse([ + 'status' => 'error', + 'message' => 'There was an error sending the message.', + 'code' => 255, + 'failed' => $failures, + 'sent' => $sent, + ], 255); + } } - return new Response('Hello'); - }); + + })->method('POST')->bind('api_message'); + $controllers->post('/v1/update', function(Request $request) use ($app) { + + return new JsonResponse($app->decodeFile($app->getResumeSchema())); + })->bind('api_update'); $controllers->post('/v1/captcha', function (Request $request) use ($app) { $captcha = new ReCaptcha('6LcvmSQTAAAAAITkvYJjgLar1LqGGLz-ic0ZMiXo'); diff --git a/src/Sikofitt/Controller/ResumeControllerProvider.php b/src/Sikofitt/Controller/ResumeControllerProvider.php index 20ae70c..944aa2d 100644 --- a/src/Sikofitt/Controller/ResumeControllerProvider.php +++ b/src/Sikofitt/Controller/ResumeControllerProvider.php @@ -15,6 +15,7 @@ use ReCaptcha\ReCaptcha; use Sikofitt\Form\Type\ContactType; use Silex\Api\ControllerProviderInterface; use Silex\Application; +use Symfony\Component\Form\Form; use Symfony\Component\Form\FormFactory; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; diff --git a/src/Sikofitt/Json/JsonFileTrait.php b/src/Sikofitt/Json/JsonFileTrait.php index 392c7a9..7fb4d90 100644 --- a/src/Sikofitt/Json/JsonFileTrait.php +++ b/src/Sikofitt/Json/JsonFileTrait.php @@ -34,6 +34,6 @@ trait JsonFileTrait public function decodeFile($file, $schema = null) { - return $this['json.decode']->decodeFile($file, $file, $schema); + return $this['json.decode']->decodeFile($file, $schema); } } diff --git a/src/Sikofitt/js/resume.js b/src/Sikofitt/js/resume.js index cf1bc07..cca0182 100644 --- a/src/Sikofitt/js/resume.js +++ b/src/Sikofitt/js/resume.js @@ -16,10 +16,10 @@ jq(document).ready(function (jq) { }); } else if (true === data.valid) { var divRoot = jq('
'), - h1 = jq('

'), - href = jq(''), - phone = jq('.hidden-phone'); - href + h1 = jq('

'), + href = jq(''), + phone = jq('.hidden-phone'); + href .attr('href', 'tel:' + data.message.phone) .text(data.message.phone); @@ -33,14 +33,14 @@ jq(document).ready(function (jq) { } }); }); // Phone form - jq('form[name=contact]').on('submit', function(event) { - contactModal = UIkit.modal('#spinner-modal', { modal:false, center:true, bgclose:false }); + jq('form[name=contact]').on('submit', function (event) { + contactModal = UIkit.modal('#spinner-modal', {modal: false, center: true, bgclose: false}); contactModal.show(); - jq.post(jq(this).attr('action'), jq(this).serialize(), function(response) { - if(response.status !== 'success') { + jq.post(jq(this).attr('action'), jq(this).serialize(), function (response) { + if (response.status !== 'success') { resp = response; jq('#' + response.id).addClass('uk-form-danger'); - UIkit.notify('' + response.message + ' ('+response.code+')

', { + UIkit.notify('' + response.message + ' (' + response.code + ')', { pos: 'top-center', status: 'danger' }); @@ -52,28 +52,28 @@ jq(document).ready(function (jq) { status: 'success' }); var $wrapper = jq('#contact-form'), - $button = jq(''), - $thankYouText = jq('

Thank you for your message.

I will get back to you as soon as possible.

'); + $button = jq(''), + $thankYouText = jq('

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'); } - }).fail(function(response, code, resp) { + }).fail(function (response) { contactModal.hide(); - resp = response; - console.log(response); - UIkit.notify(''+ response.message + ' ('+response.status+')', { + UIkit.notify('' + response.message + ' (' + response.status + ')', { pos: 'top-center', status: 'danger' }); - }).done(function () { + }).done(function () { + contactModal.hide(); + }).always(function () { contactModal.hide(); }); }); - jq('form[name=contact] input, form[name=contact] textarea').on('focus', function() { - if(jq(this).hasClass('uk-form-danger')) { + 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'); } });