Amalgamate the api route controller functionality into a single ApiController, and implement both vue component and traditional blade versions of a blog page on the public facing part of the site

This commit is contained in:
Kevin MacMartin 2018-04-26 20:26:18 -04:00
parent b83213c16e
commit a9aca7d4fe
12 changed files with 283 additions and 40 deletions

View file

@ -1,11 +1,45 @@
<?php namespace App\Http\Controllers;
use Newsletter;
use Log;
use Mail;
use Newsletter;
use App\Models\Blog;
use App\Models\Contact;
use App\Models\Subscriptions;
use Illuminate\Http\Request;
class SubscriptionController extends Controller {
class ApiController extends Controller {
public function getBlogEntries()
{
return Blog::getBlogEntries();
}
public function postContactSubmit(Request $request)
{
$this->validate($request, [
'name' => 'required',
'email' => 'required|email',
'message' => 'required'
]);
$contact = new Contact;
$contact->name = $request['name'];
$contact->email = $request['email'];
$contact->message = $request['message'];
$contact->save();
// Send the email if the MAIL_SENDTO variable is set
if (env('MAIL_SENDTO') != null) {
Mail::send('email.contact', [ 'contact' => $contact ], function($mail) use ($contact) {
$mail->from(env('MAIL_SENDFROM'), env('APP_NAME'))
->to(env('MAIL_SENDTO'))
->subject('Contact form submission');
});
}
return 'success';
}
public function postSubscriptionSubmit(Request $request)
{

View file

@ -1,35 +0,0 @@
<?php namespace App\Http\Controllers;
use Mail;
use App\Models\Contact;
use Illuminate\Http\Request;
class ContactController extends Controller {
public function postContactSubmit(Request $request)
{
$this->validate($request, [
'name' => 'required',
'email' => 'required|email',
'message' => 'required'
]);
$contact = new Contact;
$contact->name = $request['name'];
$contact->email = $request['email'];
$contact->message = $request['message'];
$contact->save();
// Send the email if the MAIL_SENDTO variable is set
if (env('MAIL_SENDTO') != null) {
Mail::send('email.contact', [ 'contact' => $contact ], function($mail) use ($contact) {
$mail->from(env('MAIL_SENDFROM'), env('APP_NAME'))
->to(env('MAIL_SENDTO'))
->subject('Contact form submission');
});
}
return 'success';
}
}

View file

@ -2,7 +2,9 @@
namespace App\Models;
use Parsedown;
use Illuminate\Database\Eloquent\Model;
use App\User;
class Blog extends DashboardModel
{
@ -22,4 +24,38 @@ class Blog extends DashboardModel
[ 'name' => 'tags', 'type' => 'text' ],
[ 'name' => 'header-image', 'title' => 'Header Image', 'type' => 'image', 'delete' => true ]
];
public static function getBlogEntries()
{
$blog_entries = [];
foreach (self::orderBy(self::$dashboard_sort_column, self::$dashboard_sort_direction)->get() as $blog_entry) {
// Add the name of the user that created the post
$blog_entry['username'] = User::find($blog_entry->user_id)->name;
// Add a string with the date and time the post was made
$blog_entry['date'] = date('M j, Y @ g:iA', strtotime($blog_entry->created_at));
// Convert the markdown in the body to html
$blog_entry['body'] = Parsedown::instance()->setBreaksEnabled(true)->setMarkupEscaped(true)->parse($blog_entry['body']);
// Replace the tags string with an array
$tags = [];
foreach (explode(';', $blog_entry['tags']) as $tag) {
array_push($tags, $tag);
}
$blog_entry['tags'] = $tags;
// Add the header image if one exists
$header_image_path = '/uploads/blog/img/' . $blog_entry->id . '-header-image.jpg';
$blog_entry['headerimage'] = file_exists(base_path() . '/public' . $header_image_path) ? $header_image_path : '';
// Add the processed blog entry to the array
array_push($blog_entries, $blog_entry);
}
return $blog_entries;
}
}

View file

@ -17,6 +17,7 @@ Vue.http.headers.common["X-CSRF-TOKEN"] = env.csrfToken;
// Import page components
import HomePage from "pages/home.vue";
import BlogPage from "pages/blog.vue";
import ContactPage from "pages/contact.vue";
import Error404Page from "pages/error404.vue";
@ -36,6 +37,7 @@ const router = new VueRouter({
routes: [
{ path: "/", component: HomePage },
{ path: "/blog", component: BlogPage },
{ path: "/contact", component: ContactPage },
{ path: "/*", component: Error404Page }
],

View file

@ -28,7 +28,7 @@ $c-accent: #fa7921; // accent
$c-error: #fa2036; // error
// Values
$nav-link-count: 2;
$nav-link-count: 3;
// Sizes
$nav-height-desktop: 60px;

81
resources/assets/sass/pages/_blog.scss vendored Normal file
View file

@ -0,0 +1,81 @@
.blog-page-component {
padding: $grid-gutter-width 0px;
h1 {
margin-bottom: $grid-gutter-width;
}
.blog-entry {
border: 1px solid lighten($c-base, 75%);
border-radius: 5px;
@include media-breakpoint-up(md) {
display: flex;
}
&:not(:last-child) {
margin-bottom: $grid-gutter-width;
}
&-header-image {
background-position: center center;
background-size: cover;
background-repeat: no-repeat;
@include media-breakpoint-down(sm) {
@include aspect-ratio(3, 1);
width: 100%;
}
@include media-breakpoint-up(md) {
width: 35%;
flex-shrink: 0;
}
}
&-content {
padding: 25px;
@include media-breakpoint-up(md) {
display: flex;
flex-direction: row;
flex-grow: 1;
flex-wrap: wrap;
}
> * {
width: 100%;
}
&-title {
@include font-sans-semibold;
margin-bottom: $grid-gutter-width;
font-size: 25px;
text-align: center;
text-transform: uppercase;
}
&-info {
color: lighten($c-text, 30%);
}
&-body {
margin: ($grid-gutter-width / 2) 0px;
}
&-taglist {
width: 100%;
&-item {
margin-right: 5px;
display: inline-block;
padding: 3px 8px;
border-radius: 3px;
background-color: $c-accent;
color: $c-text-light;
}
}
}
}
}

View file

@ -0,0 +1,66 @@
<template>
<div class="blog-page-component">
<div class="container">
<div class="row">
<div class="col-12 col-lg-10 offset-lg-1 col-xl-8 offset-xl-2 col-xxl-6 offset-xxl-3">
<h1>Blog</h1>
<div
v-for="entry in blogEntries"
class="blog-entry">
<div
v-if="entry.headerimage !== ''"
class="blog-entry-header-image"
:style="{ backgroundImage: 'url(' + entry.headerimage + ')' }">
</div>
<div class="blog-entry-content">
<h2 class="blog-entry-content-title">{{ entry.title }}</h2>
<div class="blog-entry-content-info">
<span class="blog-entry-content-info-name">{{ entry.username }}</span> |
<span class="blog-entry-content-info-date">{{ entry.date }}</span>
</div>
<p class="blog-entry-content-body" v-html="entry.body"></p>
<div class="blog-entry-content-taglist">
<span
v-for="tag in entry.tags"
class="blog-entry-content-taglist-item">
{{ tag }}
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
blogEntries: []
};
},
methods: {
populateBlogEntries() {
this.$http.get("/api/blog-entries" + env.apiToken).then((response) => {
this.blogEntries = response.body;
}, (response) => {
console.log("Failed to retrieve blog entries");
});
}
},
created() {
this.populateBlogEntries();
}
};
</script>

View file

@ -40,6 +40,7 @@
navLinks: [
{ path: "/", title: "Home" },
{ path: "/blog", title: "Blog" },
{ path: "/contact", title: "Contact" }
]
};

View file

@ -17,11 +17,19 @@ Route::middleware('auth:api')->get('/user', function(Request $request) {
return $request->user();
});
/*
|--------------------------------------------------------------------------
| Get Routes
|--------------------------------------------------------------------------
*/
Route::get('/blog-entries', 'ApiController@getBlogEntries');
/*
|--------------------------------------------------------------------------
| Post Routes
|--------------------------------------------------------------------------
*/
Route::post('/contact-submit', 'ContactController@postContactSubmit');
Route::post('/subscription-submit', 'SubscriptionController@postSubscriptionSubmit');
Route::post('/contact-submit', 'ApiController@postContactSubmit');
Route::post('/subscription-submit', 'ApiController@postSubscriptionSubmit');

View file

@ -0,0 +1,45 @@
@extends('templates.public', [ 'title' => 'Blog' ])
@section('content')
<div class="blog-page-component">
<div class="container">
<div class="row">
<div class="col-12 col-lg-10 offset-lg-1 col-xl-8 offset-xl-2 col-xxl-6 offset-xxl-3">
<h1>Blog</h1>
@foreach(App\Models\Blog::getBlogEntries() as $entry)
<div class="blog-entry">
@if($entry['headerimage'] != '')
<div
class="blog-entry-header-image"
style="background-image: url({{ $entry['headerimage'] }})">
</div>
@endif
<div class="blog-entry-content">
<h2 class="blog-entry-content-title">{{ $entry['title'] }}</h2>
<div class="blog-entry-content-info">
<span class="blog-entry-content-info-name">{{ $entry['username'] }}</span> |
<span class="blog-entry-content-info-date">{{ $entry['date'] }}</span>
</div>
<p class="blog-entry-content-body">
{!! $entry['body'] !!}
</p>
<div class="blog-entry-content-taglist">
@foreach($entry['tags'] as $tag)
<span class="blog-entry-content-taglist-item">
{{ $tag }}
</span>
@endforeach
</div>
</div>
</div>
@endforeach
</div>
</div>
</div>
</div>
@endsection

View file

@ -11,6 +11,7 @@
<div class="nav-section-component-links" :class="{ open: openNav }">
<div class="nav-section-component-links-wrapper">
<a class="navlink" href="/"><span>Home</span></a>
<a class="navlink" href="/blog"><span>Blog</span></a>
<a class="navlink" href="/contact"><span>Contact</span></a>
</div>
</div>

View file

@ -69,6 +69,10 @@ Route::get('/', function() {
return view('pages.index');
});
Route::get('/blog', function() {
return view('pages.blog');
});
Route::get('/contact', function() {
return view('pages.contact');
});