A hosting service for Jekyll Blogs
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

218 lines
6.9 KiB

package MJB::Web::Controller::Blog;
use Mojo::Base 'Mojolicious::Controller', -signatures;
use Try::Tiny;
#=====
# This file handles the initial creation of a blog.
#
# It is a controller, the template files live in templates/blog.
#=====
#==
# GET /blog | show_blog
#
# Redirect the user to the initial step of the blog creation process.
#==
sub index ( $c ) {
$c->redirect_to( 'show_blog_domain_hosted' );
}
#==
# GET /blog/domain/hosted | show_blog_domain_hosted
#
# The initial entrypoint for blog creation.
#==
sub domain_hosted ( $c ) {
}
#==
# POST /blog/domain/hosted | do_blog_domain_hosted
# subdomain | A subdomain that the user would like to use
# hosted_domain_id | The id of a hosted_domain that the user wants to use
#
# This route will create a blog as a subdomain of a hosted domain. We control
# the DNS, SSL, etc.
#==
sub do_domain_hosted ( $c ) {
my $sub_domain = $c->stash->{form}->{subdomain} = $c->param('subdomain');
my $top_domain = $c->db->hosted_domain( $c->param('hosted_domain_id') );
# Store the hosted domain id so we can have the right domain selected on the drop down
# for errors.
$c->stash->{form}->{hdid} = $top_domain->id;
$sub_domain = lc($sub_domain);
push @{$c->stash->{errors}}, "Please select a domain from the drop down menu."
unless $top_domain;
push @{$c->stash->{errors}}, "Please enter a value for the subdomain."
unless $sub_domain;
push @{$c->stash->{errors}}, "Subdomains must start with a letter, and may use letters, numbers, dashes and hyphens."
unless $sub_domain =~ /^[a-z]+[a-z0-9-_]*$/;
push @{$c->stash->{errors}}, "That domain name is already being used."
unless $c->db->domains( { name => $sub_domain . '.' . $top_domain->name } )->count == 0;
return $c->redirect_error( 'show_blog_domain_hosted' )
if $c->stash->{errors};
my $domain_name = $sub_domain . '.' . $top_domain->name;
my $domain_ssl = $top_domain->letsencrypt_challenge ne 'http' ? $top_domain->name : '';
return $c->_initialize_blog( $domain_name, 'show_blog_domain_hosted', $domain_ssl );
}
#==
# GET /blog/domain/owned | show_blog_domain_owned
#
# The initial entrypoint for blog creation on a domain that the user controls
# DNS for.
#==
sub domain_owned ( $c ) {
$c->stash->{dns_record} = 'external.' . $c->db->hosted_domains->first->name;
}
#==
# POST /blog/domain/owned | do_blog_domain_owned
# domain_name | The domain name that the user would like to use
#
# This route will create a blog with whatever domain the user supplies. They will
# need to have ensured that DNS is pointed to the correct addresses so that it works.
#==
sub do_domain_owned ( $c ) {
my $domain_name = $c->stash->{form}->{domain_name} = $c->param('domain_name');
$domain_name = lc($domain_name);
push @{$c->stash->{errors}}, "Please enter a value for the domain name."
unless $domain_name;
push @{$c->stash->{errors}}, "That domain name is already being used."
unless $c->db->domains( { name => $domain_name } )->count == 0;
return $c->redirect_error( 'show_blog_domain_owned' )
if $c->stash->{errors};
return $c->_initialize_blog( $domain_name, 'show_blog_domain_owned', '' );
}
#==
# Helper Function...
#
# This will make the blog after domain_hosted / domain_owned figures out what
# it's making.
#==
sub _initialize_blog ( $c, $domain, $from, $ssl_domain ) {
# Do we already have this domain name?
if ( $c->db->domain( { name => $domain } ) ) {
$c->flash( errors => [ 'That domain name is already being hosted.' ] );
$c->redirect_to( $c->url_for( $from ) );
return;
}
# Create the Jekyll repo for the site
# This is where a job to build it on the build server should happen...
my $jekyll = $c->jekyll($domain)->init;
my $blog = try {
$c->db->storage->schema->txn_do( sub {
# Make the domain name record.
my $domain_record = $c->stash->{person}->create_related('domains', {
name => $domain,
( $ssl_domain ? ( ssl => $ssl_domain ) : () ),
});
# Make the website record
my $blog = $c->stash->{person}->create_related('blogs', {
domain_id => $domain_record->id,
});
$blog->create_related( 'repoes', {
url => $jekyll->repo,
});
return $blog;
});
} catch {
push @{$c->stash->{errors}}, "Blog could not be created: $_";
};
if ( $c->stash->{errors} ) {
$c->flash( errors => $c->stash->{errors} );
$c->redirect_to( $c->url_for( $from ) );
return;
}
# Schedule a job to deploy the website
if ( ! $ssl_domain ) {
my $ssl_job_id = $c->minion->enqueue( 'create_ssl_cert', [ $blog->id ], {
notes => { '_bid_' . $blog->id => 1 },
priority => $blog->build_priority,
queue => 'certbot',
});
$blog->create_related( 'jobs', { minion_job_id => $ssl_job_id } );
}
$c->redirect_to( $c->url_for( 'show_blog_settings', { id => $blog->id } ) );
}
#==
# GET /blog/:id/settings | show_blog_settings
#
# This page gives the user the chance to set the title, description, email, etc.
#==
sub settings ( $c ) {
}
#==
# POST /blog/:id/settings | show_blog_settings
# configTitle | The title for the blog
# configDesc | The description for the blog
# configEmail | An email address for the blog's author
#
# This route handles the initial configuration of the blog, and schedules
# the minion job to initialize it.
#==
sub do_settings ( $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);
my $title = $c->stash->{form_title} = $c->param( 'configTitle' );
my $desc = $c->stash->{form_desc} = $c->param( 'configDesc' );
my $email = $c->stash->{form_email} = $c->param( 'configEmail' );
$jekyll->config->data->{title} = $title;
$jekyll->config->data->{description} = $desc;
$jekyll->config->data->{email} = $email;
$jekyll->config->data->{url} = 'https://' . $blog->domain->name ;
$jekyll->write_config;
my $build_job_id = $c->minion->enqueue( 'initialize_blog', [ $blog->id ], {
notes => { '_bid_' . $blog->id => 1 },
priority => $blog->build_priority,
});
$blog->create_related( 'jobs', { minion_job_id => $build_job_id } );
$c->flash( confirmation => "Welcome to the dashboard for your new blog!" );
$c->redirect_to( $c->url_for( 'show_dashboard_blog', { id => $blog->id } ) );
}
1;