Blog page UI.

master
Blog Manager Robot 3 years ago
parent db57abd017
commit ef8290954b
  1. 6
      Web/lib/MJB/Web.pm
  2. 123
      Web/lib/MJB/Web/Controller/Dashboard.pm
  3. 15
      Web/templates/dashboard/_blog_nav.html.ep
  4. 28
      Web/templates/dashboard/blog_page.html.ep
  5. 25
      Web/templates/dashboard/blog_page_edit.html.ep
  6. 50
      Web/templates/dashboard/blog_pages.html.ep
  7. 35
      libs/MJB-Backend-Jekyll/lib/MJB/Backend/Jekyll.pm
  8. 30
      libs/MJB-Backend-Jekyll/lib/MJB/Backend/Jekyll/MarkdownFile.pm

@ -132,6 +132,12 @@ sub startup ($self) {
$auth->get ( '/dashboard/blog/:id/history' )->to('Dashboard#blog_history' )->name('show_dashboard_blog_history' );
$auth->post( '/dashboard/blog/:id/history' )->to('Dashboard#do_blog_history' )->name('do_dashboard_blog_history' );
$auth->get ( '/dashboard/blog/:id/pages' )->to('Dashboard#blog_pages' )->name('show_dashboard_blog_pages' );
$auth->get ( '/dashboard/blog/:id/page' )->to('Dashboard#blog_page' )->name('show_dashboard_blog_page' );
$auth->post( '/dashboard/blog/:id/page' )->to('Dashboard#do_blog_page' )->name('do_dashboard_blog_page' );
$auth->get ( '/dashboard/blog/:id/page/edit' )->to('Dashboard#blog_page_edit' )->name('show_dashboard_blog_page_edit' );
$auth->post( '/dashboard/blog/:id/page/edit' )->to('Dashboard#do_blog_page_edit' )->name('do_dashboard_blog_page_edit' );
# Blog Management
$auth->get ( '/blog' )->to('Blog#create' )->name('show_blog_create' );
$auth->post( '/blog' )->to('Blog#do_create' )->name('do_blog_create' );

@ -392,5 +392,128 @@ sub do_blog_history ( $c ) {
}
}
sub blog_pages ( $c ) {
my $blog = $c->stash->{blog} = $c->db->blog( $c->param('id') );
if ( $blog->person->id ne $c->stash->{person}->id ) {
$c->render(
text => "Error: This blog isn't owned by you.",
status => 404,
format => 'txt',
);
return;
}
my $blog_pages = $c->stash->{blog_pages} = [ map { $_->read } @{$c->jekyll($blog->domain->name)->list_pages} ];
}
sub blog_page_edit ( $c ) {
my $blog = $c->stash->{blog} = $c->db->blog( $c->param('id') );
if ( $blog->person->id ne $c->stash->{person}->id ) {
$c->render(
text => "Error: This blog isn't owned by you.",
status => 404,
format => 'txt',
);
return;
}
# This is a dumb-expensive way of loading the file. TODO, fix this.
my $blog_pages = $c->stash->{blog_pages} = [ map { $_->read } @{$c->jekyll($blog->domain->name)->list_pages} ];
my $rel_path = $c->param('file');
( $c->stash->{blog_page} ) = grep { $_->rel_path eq $rel_path } @{$blog_pages};
}
sub do_blog_page_edit ( $c ) {
my $blog = $c->stash->{blog} = $c->db->blog( $c->param('id') );
if ( $blog->person->id ne $c->stash->{person}->id ) {
$c->render(
text => "Error: This blog isn't owned by you.",
status => 404,
format => 'txt',
);
return;
}
my $jekyll = $c->jekyll($blog->domain->name);
# This is a dumb-expensive way of loading the file. TODO, fix this.
my $blog_pages = $c->stash->{blog_pages} = [ map { $_->read } @{$jekyll->list_pages} ];
my $rel_path = $c->param('file');
my $content = $c->param('pageContent');
my $headers = $c->param('pageHeaders');
my ( $blog_page ) = grep { $_->rel_path eq $rel_path } @{$blog_pages};
$blog_page->set_headers_from_string( $headers );
$blog_page->markdown( $content );
$jekyll->write_post( $blog_page );
my $build_job_id = $c->minion->enqueue( 'deploy_blog', [ $blog->id ], {
notes => { '_bid_' . $blog->id => 1 },
priority => $blog->build_priority,
});
$blog->create_related( 'builds', { job_id => $build_job_id } );
$c->flash( confirmation => "Updated Page " . $blog_page->filename . "!" );
$c->redirect_to( $c->url_for( 'show_dashboard_blog_pages', { id => $blog->id } ) );
}
sub blog_page ( $c ) {
my $blog = $c->stash->{blog} = $c->db->blog( $c->param('id') );
if ( $blog->person->id ne $c->stash->{person}->id ) {
$c->render(
text => "Error: This blog isn't owned by you.",
status => 404,
format => 'txt',
);
return;
}
}
sub do_blog_page ( $c ) {
my $blog = $c->stash->{blog} = $c->db->blog( $c->param('id') );
if ( $blog->person->id ne $c->stash->{person}->id ) {
$c->render(
text => "Error: This blog isn't owned by you.",
status => 404,
format => 'txt',
);
return;
}
my $path = $c->param('pagePath');
my $content = $c->param('pageContent');
my $headers = $c->param('pageHeaders');
my $jekyll = $c->jekyll($blog->domain->name);
my $page = $jekyll->new_page( $path );
$page->set_headers_from_string( $headers );
$page->markdown( $content );
$jekyll->write_post( $page );
my $build_job_id = $c->minion->enqueue( 'deploy_blog', [ $blog->id ], {
notes => { '_bid_' . $blog->id => 1 },
priority => $blog->build_priority,
});
$blog->create_related( 'builds', { job_id => $build_job_id } );
$c->flash( confirmation => "Created Page " . $page->filename . "!" );
$c->redirect_to( $c->url_for( 'show_dashboard_blog_pages', { id => $blog->id } ) );
}
1;

@ -36,6 +36,21 @@
<a class="nav-link active" href="#">Post Editor</a>
</li>
% }
<li class="nav-item">
<a class="nav-link <%= $page eq 'pages' ? 'active' : '' %>" href="<%= $c->url_for( 'show_dashboard_blog_pages' ) %>">Pages</a>
</li>
% if ( $page eq 'page-create' ) {
<li class="nav-item">
<a class="nav-link active" href="#">Page Creator</a>
</li>
% }
% if ( $page eq 'page-edit' ) {
<li class="nav-item">
<a class="nav-link active" href="#">Page Editor</a>
</li>
% }
<li class="nav-item">
<a class="nav-link <%= $page eq 'media' ? 'active' : '' %>" href="<%= $c->url_for( 'show_dashboard_blog_media' ) %>">Media</a>

@ -0,0 +1,28 @@
% layout 'standard', title => 'Dashboard', sb_active => 'dashboard';
%= include 'dashboard/_blog_nav', page => 'page-create'
<p class="mt-3 fs-4" >Editing <span class="fw-bolder">Create New Page</span></p>
<form method="POST" action="<%= $c->url_for( 'do_dashboard_blog_page' ) %>">
<div class="mt-3 mb-3">
<label for="pagePath" class="col-sm-2 col-form-label">File Path</label>
<input type="text" class="form-control" id="pagePath" name="pagePath" value="">
</div>
<div class="mb-3">
<label for="pageHeaders" class="form-label">Page Headers</label>
<textarea class="form-control" id="pageHeaders" name="pageHeaders" rows="5"></textarea>
</div>
<div class="mb-3">
<label for="pageContent" class="form-label">Page Content</label>
<textarea class="form-control" id="pageContent" name="pageContent" rows="25"></textarea>
</div>
<div class="mb-3">
<input type="submit" class="btn btn-primary btn-sm float-end" width="100%" value="Create Page">
</div>
</form>

@ -0,0 +1,25 @@
% layout 'standard', title => 'Dashboard', sb_active => 'dashboard';
%= include 'dashboard/_blog_nav', page => 'page-edit'
<p class="mt-3 fs-4" >Editing <span class="fw-bolder"><%= $blog_page->rel_path %></span></p>
<form method="POST" action="<%= $c->url_for( 'do_dashboard_blog_page_edit' ) %>">
<input type="hidden" name="file" value="<%= $blog_page->rel_path %>">
<div class="mb-3">
<label for="pageHeaders" class="form-label">Page Headers</label>
<textarea class="form-control" id="pageHeaders" name="pageHeaders" rows="5"><%= $blog_page->headers_as_string %></textarea>
</div>
<div class="mb-3">
<label for="pageContent" class="form-label">Page Content</label>
<textarea class="form-control" id="pageContent" name="pageContent" rows="25"><%= $blog_page->markdown %></textarea>
</div>
<div class="mb-3">
<input type="submit" class="btn btn-primary btn-sm float-end" width="100%" value="Update Page">
</div>
</form>

@ -0,0 +1,50 @@
% layout 'standard', title => 'Dashboard', sb_active => 'dashboard';
%= include 'dashboard/_blog_nav', page => 'pages'
% if ( my $confirmation = flash 'confirmation' ) {
<div style="margin-top: 2em" class="alert alert-success" role="alert">
<%== $confirmation %>
</div>
% }
% if ( $c->stash->{success} ) {
<div style="margin-top: 2em" class="alert alert-success" role="alert">
<%= $c->stash->{success_message} %>
</div>
% }
% if ( $c->stash->{errors} ) {
<div style="margin-top: 2em" class="alert alert-danger" role="alert">
There were errors with your request that could not be resolved:
<ul>
% for my $error ( @{$c->stash->{errors}} ) {
<li><%= $error %></li>
% }
</ul>
</div>
% }
<a href="<%= $c->url_for( 'show_dashboard_blog_page' ) %>">Create New Page</a>
% if ( $blog_pages ) {
<table style="border: 1px solid #ccc" class="table mt-5">
<tbody>
<tr>
<th class="text-nowrap">Path</th>
<th class="text-nowrap">Type</th>
<th class="text-nowrap">Edit</th>
</tr>
</thead>
<tbody>
% for my $page ( @{$blog_pages} ) {
<tr>
<td><a href="<%= $c->url_for( 'show_dashboard_blog', { id => $blog->id } ) %>"><%= $page->filename %></a></td>
<td><a href="<%= $c->url_for( 'show_dashboard_blog', { id => $blog->id } ) %>"><%= $page->headers->{layout} %></a></td>
<td><a href="<%= $c->url_for( 'show_dashboard_blog_page_edit', { id => $blog->id } )->query( file => $page->rel_path ) %>">Edit Post</a></td>
</tr>
% }
</tbody>
</table>
% }

@ -3,6 +3,7 @@ use Moo;
use IPC::Run3 qw( run3 );
use Cwd qw( getcwd );
use File::Path qw( make_path );
use File::Find;
use Storable qw( dclone );
use Mojo::File;
use MJB::Backend::Jekyll::MarkdownFile;
@ -125,17 +126,39 @@ sub list_posts {
# TODO: Sort by date for the listing on the front end.
foreach my $file ( $posts->list->each ) {
push @files, MJB::Backend::Jekyll::MarkdownFile->new(
path => $file->to_string,
root => $self->repo_path,
path => $file->to_string,
);
}
return [ @files ];
}
sub list_pages {
my ( $self ) = @_;
$self->_ensure_repository_is_latest;
my @files;
find( sub {
return unless $_ =~ /\.(?:markdown|md)$/; # Only markdown files
return if substr((split m|/|, $File::Find::dir)[-1], 0, 1) eq '_'; # Skip directories that start with _
push @files, MJB::Backend::Jekyll::MarkdownFile->new(
root => $self->repo_path,
path => $File::Find::name,
);
}, $self->repo_path );
return [ @files ];
}
sub get_post {
my ( $self, $filename ) = @_;
return MJB::Backend::Jekyll::MarkdownFile->new(
root => $self->repo_path,
path => $self->repo_path . "/_posts/" . $filename,
)->read;
}
@ -145,10 +168,20 @@ sub new_post {
my ( $self, $filename ) = @_;
return MJB::Backend::Jekyll::MarkdownFile->new(
root => $self->repo_path,
path => $self->repo_path . "/_posts/" . $filename,
);
}
sub new_page {
my ( $self, $filename ) = @_;
return MJB::Backend::Jekyll::MarkdownFile->new(
root => $self->repo_path,
path => $self->repo_path . $filename,
);
}
sub get_title_of_post {
my ( $self, $file ) = @_;

@ -8,6 +8,22 @@ has path => (
required => 1,
);
# root / domain from parent class.
has root => (
is => 'ro',
required => 1,
);
has rel_path => (
is => 'lazy',
);
sub _build_rel_path {
my ( $self ) = @_;
return substr($self->path, length($self->root));
}
has filename => (
is => 'lazy',
);
@ -27,6 +43,20 @@ has markdown => (
is => 'rw',
);
sub headers_as_string {
my ( $self ) = @_;
return Dump($self->headers);
}
sub set_headers_from_string {
my ( $self, $string ) = @_;
$self->headers( Load( $string ) );
return $self;
}
sub read {
my ( $self ) = @_;

Loading…
Cancel
Save