Refactored admin controller.

master
Manager Bot 3 years ago
parent 9eaf1d4dff
commit b991658a87
  1. 9
      Web/lib/MJB/Web.pm
  2. 238
      Web/lib/MJB/Web/Controller/Admin.pm

@ -68,13 +68,20 @@ sub startup ($self) {
# Helper to redirect on errors, support setting the form and errors in a flash # Helper to redirect on errors, support setting the form and errors in a flash
# if they exist in the stash. # if they exist in the stash.
$self->helper( redirect_error => sub ( $c, $redirect_to, $redirect_args = {} ) { $self->helper( redirect_error => sub ( $c, $redirect_to, $redirect_args = {}, $errors = [] ) {
push @{$c->stash->{errors}}, @{$errors} if $errors;
$c->flash( form => $c->stash->{form} ) if $c->stash->{form}; $c->flash( form => $c->stash->{form} ) if $c->stash->{form};
$c->flash( errors => $c->stash->{errors} ) if $c->stash->{errors}; $c->flash( errors => $c->stash->{errors} ) if $c->stash->{errors};
$c->redirect_to( $c->url_for( $redirect_to, $redirect_args ) ); $c->redirect_to( $c->url_for( $redirect_to, $redirect_args ) );
}); });
# Helper to redirect on success, support setting a message and redirecting to a named route.
$self->helper( redirect_success => sub ( $c, $redirect_to, $success_message ) {
$c->flash( confirmation => $success_message );
$c->redirect_to( $c->url_for( $redirect_to ) );
});
# Minion plugin & tasks # Minion plugin & tasks
$self->plugin( Minion => { Pg => $self->config->{database}->{minion} } ); $self->plugin( Minion => { Pg => $self->config->{database}->{minion} } );

@ -2,26 +2,30 @@ package MJB::Web::Controller::Admin;
use Mojo::Base 'Mojolicious::Controller', -signatures; use Mojo::Base 'Mojolicious::Controller', -signatures;
use Try::Tiny; use Try::Tiny;
#==
# GET /admin | show_admin
#
# Redirect to the people listing page.
#==
sub index ( $c ) { sub index ( $c ) {
$c->redirect_to( 'show_admin_people' ); $c->redirect_to( 'show_admin_people' );
} }
# POST /admin #==
# POST /admin | do_admin_become
# uid | A user id, that the admin would like to become
# bid | A blog id, that the admin will go to the manage page for
# url | A URL to return to when the admin logs out of the user account
# #
# An admin may inpersonate any other user for technical support purposes, # An admin may inpersonate any other user for technical support purposes,
# this code is called to become another user. Sign out to become your origional # this code is called to become another user. Sign out to become your origional
# user again. # user again.
# #
# INPUT:
# uid | A user id
# bid | A blog id belonging to the user
# url | A URL to return to when the admin logs out of the user account
#
# When given a uid, become that user and go to the user's dashboard. # When given a uid, become that user and go to the user's dashboard.
# #
# When given a uid and a bid that the user owns, become that user # When given a uid and a bid that the user owns, become that user
# and go to the blog's dashboard. # and go to the blog's dashboard.
# #==
sub do_admin_become ( $c ) { sub do_admin_become ( $c ) {
my ( $uid, $bid, $url ) = ( $c->param('uid'), $c->param('bid'), $c->param('url') ); my ( $uid, $bid, $url ) = ( $c->param('uid'), $c->param('bid'), $c->param('url') );
@ -38,15 +42,31 @@ sub do_admin_become ( $c ) {
} }
} }
#==
# GET /admin/people | show_admin_people
#
# This route shows people, users, who exist on this system.
#==
sub people ( $c ) { sub people ( $c ) {
my $people = $c->stash->{people} = [ $c->db->people->all ]; my $people = $c->stash->{people} = [ $c->db->people->all ];
} }
#==
# GET /admin/person/:id | show_admin_person, { id => ? }
#
# This route shows a given person, their blogs, and notes about them.
#==
sub person ( $c ) { sub person ( $c ) {
my $profile = $c->stash->{profile} = $c->db->person( $c->param('id') ); my $profile = $c->stash->{profile} = $c->db->person( $c->param('id') );
my $notes = $c->stash->{notes} = [ $profile->person_note_people->all ]; my $notes = $c->stash->{notes} = [ $profile->person_note_people->all ];
} }
#==
# POST /admin/person/:id/note | do_admin_person_note { id => person.id }
# content | The content of the message about this user.
#
# This route makes a note about a person on their profile page.
#==
sub do_person_note ( $c ) { sub do_person_note ( $c ) {
my $profile = $c->db->person( $c->param('id') ); my $profile = $c->db->person( $c->param('id') );
my $content = $c->param('content'); my $content = $c->param('content');
@ -58,24 +78,35 @@ sub do_person_note ( $c ) {
$c->flash( confirmation => "Added note to this account." ); $c->flash( confirmation => "Added note to this account." );
$c->redirect_to( $c->url_for( 'show_admin_person', { id => $profile->id } ) ); $c->redirect_to( $c->url_for( 'show_admin_person', { id => $profile->id } ) );
} }
#==
# GET /admin/blogs | show_admin_blogs
#
# This route lists blogs that are hosted on this system.
#==
sub blogs ( $c ) { sub blogs ( $c ) {
my $blogs = $c->stash->{blogs} = [ $c->db->blogs->all ]; my $blogs = $c->stash->{blogs} = [ $c->db->blogs->all ];
} }
sub servers ( $c ) { #==
my $servers = $c->stash->{servers} = [ $c->db->servers->all ]; # GET /admin/invites | show_admin_invites
#
} # This route shows the invites that currently exist and can be used.
#==
sub invites ( $c ) { sub invites ( $c ) {
my $invites = $c->stash->{invites} = [ $c->db->invites->all ]; my $invites = $c->stash->{invites} = [ $c->db->invites->all ];
} }
#==
# POST /admin/invite | do_admin_invite
# code | The invite code, this is case-sensitive.
# is_multi_use | When true, the code may be used more than once.
#
# This route adds an invite code.
#==
sub do_invite ( $c ) { sub do_invite ( $c ) {
my $code = $c->param('code'); my $code = $c->param('code');
my $is_multi_use = $c->param('is_multi_use' ); my $is_multi_use = $c->param('is_multi_use' );
@ -88,29 +119,50 @@ sub do_invite ( $c ) {
}); });
}); });
} catch { } catch {
$c->flash( error_message => "Invite Code could not be created: $_" ); push @{$c->stash->{errors}}, "Invite code could not be created: $_";
}; };
return $c->redirect_error( 'show_admin_invites' )
if $c->stash->{errors};
$c->redirect_to( $c->url_for( 'show_admin_invites' ) ); return $c->redirect_success( 'show_admin_invites', "Added $code to invites." );
return;
} }
#==
# POST /admin/invite/remove | do_admin_invite_remove
# iid | The id of the invite code to delete
#
# This route deletes an invite code.
#==
sub do_invite_remove ( $c ) { sub do_invite_remove ( $c ) {
my $invite = $c->db->invite($c->param('iid')); my $invite = $c->db->invite($c->param('iid'));
if ( ! $invite ) { return $c->redirect_error( 'show_admin_invites', {}, [ 'The invite does not exist' ] )
$c->flash( error_message => "Invite could not be removed, because it doesn't exist?" ); unless $invite;
$c->redirect_to( $c->url_for( 'show_admin_invites' ) );
return;
}
my $code = $invite->code; my $code = $invite->code;
$invite->delete; $invite->delete;
$c->flash( confirmation => "Removed $code from invite pool." ); return $c->redirect_success( 'show_admin_invites', "Removed $code from invite pool." );
$c->redirect_to( $c->url_for( 'show_admin_invites' ) ); }
#==
# GET /admin/servers | show_admin_servers
#
# This route shows servers that blogs are hosted on, and deployed to.
#==
sub servers ( $c ) {
my $servers = $c->stash->{servers} = [ $c->db->servers->all ];
} }
#==
# POST /admin/server | do_admin_server
# server_fqdn | The domain name to use for the server, builder and certbot
# servers should have ssh access to these servers.
#
# This route adds a server to the pool for deployment. These servers are used by
# the certbot and builder servers to deploy ssl certs and blogs to.
#==
sub do_server ( $c ) { sub do_server ( $c ) {
my $fqdn = $c->param('server_fqdn'); my $fqdn = $c->param('server_fqdn');
@ -119,36 +171,53 @@ sub do_server ( $c ) {
$c->db->servers->create({ hostname => $fqdn }); $c->db->servers->create({ hostname => $fqdn });
}); });
} catch { } catch {
$c->flash( error_message => "Server could not be created: $_" ); push @{$c->stash->{errors}}, "Server could not be created: $_";
$c->redirect_to( $c->url_for( 'show_admin_servers' ) );
return;
}; };
return $c->redirect_error( 'show_admin_servers' )
if $c->stash->{errors};
$c->flash( confirmation => "Added $fqdn to server pool." ); return $c->redirect_success( 'show_admin_servers', "Added $fqdn to server pool." );
$c->redirect_to( $c->url_for( 'show_admin_servers' ) );
} }
#==
# POST /admin/server/remove | do_admin_server_remove
# sid | The id of the server to remove
#
# This route removes a server from the rotation used for deploying blogs/ssl certs.
#==
sub do_server_remove ( $c ) { sub do_server_remove ( $c ) {
my $server = $c->db->server($c->param('sid')); my $server = $c->db->server($c->param('sid'));
if ( ! $server ) { return $c->redirect_error( 'show_admin_servers', {}, [ 'The server does not exist' ] )
$c->flash( error_message => "Server could not be removed, because it doesn't exist?" ); unless $server;
$c->redirect_to( $c->url_for( 'show_admin_servers' ) );
return;
}
my $hostname = $server->hostname; my $hostname = $server->hostname;
$server->delete; $server->delete;
$c->flash( confirmation => "Removed $hostname from server pool." ); return $c->redirect_success( 'show_admin_servers', "Removed $hostname to server pool." );
$c->redirect_to( $c->url_for( 'show_admin_servers' ) );
} }
#==
# GET /admin/domains | show_admin_domains
#
# This route shows domains that users can host their blogs under.
#==
sub domains ( $c ) { sub domains ( $c ) {
my $domains = $c->stash->{domains} = [ $c->db->hosted_domains->all ]; $c->stash->{domains} = [ $c->db->hosted_domains->all ];
} }
#==
# POST /admin/domain | do_admin_domain
# domain_fqdn | The fully qualified domain name we will use for hosting (i.e. foobar.net)
# ssl_challenge | The challenge type -- dns-linode or http to use for validating domains
#
# This route will add a domain to use for hosting. For example, if one adds foobar.net, then
# users will be able to host blogs like myblog.foobar.net.
#
# http challenges will use the certbot server and /.well-known/ forwarding for creation/updating w/ --standalone
# dns-linode challenges will use the --dns-linode plugin and credentials expected to be done with ansible.
#==
sub do_domain ( $c ) { sub do_domain ( $c ) {
my $fqdn = $c->param('domain_fqdn'); my $fqdn = $c->param('domain_fqdn');
my $ssl = $c->param('ssl_challenge'); my $ssl = $c->param('ssl_challenge');
@ -158,35 +227,44 @@ sub do_domain ( $c ) {
$c->db->hosted_domains->create({ name => $fqdn, letsencrypt_challenge => $ssl }); $c->db->hosted_domains->create({ name => $fqdn, letsencrypt_challenge => $ssl });
}); });
} catch { } catch {
$c->flash( error_message => "domain could not be created: $_" ); push @{$c->stash->{errors}}, "Domain could not be created: $_";
$c->redirect_to( $c->url_for( 'show_admin_domains' ) );
return;
}; };
return $c->redirect_error( 'show_admin_domains' )
if $c->stash->{errors};
if ( $ssl eq 'dns-linode' ) { if ( $ssl eq 'dns-linode' ) {
$c->minion->enqueue( 'mk_wildcard_ssl', [ $domain->id ], { queue => 'certbot' } ); $c->minion->enqueue( 'mk_wildcard_ssl', [ $domain->id ], { queue => 'certbot' } );
} }
$c->flash( confirmation => "Added $fqdn to domain pool." ); return $c->redirect_success( 'show_admin_domains', "Added $fqdn to domain pool." );
$c->redirect_to( $c->url_for( 'show_admin_domains' ) );
} }
#==
# POST /admin/domain/remove | do_admin_domain_remove
# did | The ID for the domain to remove.
#
# This route will remove a hosted domain by its ID.
#==
sub do_domain_remove ( $c ) { sub do_domain_remove ( $c ) {
my $domain = $c->db->hosted_domain($c->param('did')); my $domain = $c->db->hosted_domain($c->param('did'));
if ( ! $domain ) { return $c->redirect_error( 'show_admin_domains', {}, [ "That domain doesn't seem to exist." ] )
$c->flash( error_message => "domain could not be removed, because it doesn't exist?" ); unless $domain;
$c->redirect_to( $c->url_for( 'show_admin_domains' ) );
return;
}
my $hostname = $domain->name; my $hostname = $domain->name;
$domain->delete; $domain->delete;
$c->flash( confirmation => "Removed $hostname from domain pool." ); return $c->redirect_success( 'show_admin_domains', "Removed $hostname from domain pool." );
$c->redirect_to( $c->url_for( 'show_admin_domains' ) );
} }
#==
# POST /admin/update_ssl | do_admin_update_ssl
#
# This route will schedule a job for update_ssl SSL certs on
# the certbot server and then sync them with the webserver.
# certbot server to the webservers.
#==
sub do_update_ssl ( $c ) { sub do_update_ssl ( $c ) {
my $id = $c->minion->enqueue( 'update_ssl_certs', [ ], { my $id = $c->minion->enqueue( 'update_ssl_certs', [ ], {
queue => 'certbot', queue => 'certbot',
@ -194,10 +272,15 @@ sub do_update_ssl ( $c ) {
}); });
$c->db->admin_jobs->create({ minion_job_id => $id }); $c->db->admin_jobs->create({ minion_job_id => $id });
$c->flash( confirmation => "Scheduled job to update SSL certs." ); return $c->redirect_success( 'show_admin_jobs', 'Scheduled job to update SSL certs.' );
$c->redirect_to( $c->url_for( 'show_admin_jobs' ) );
} }
#==
# POST /admin/sync_ssl | do_admin_sync_ssl
#
# This route will schedule a job for syncing SSL certs from the
# certbot server to the webservers.
#==
sub do_sync_ssl ( $c ) { sub do_sync_ssl ( $c ) {
my $id = $c->minion->enqueue( 'sync_ssl_certs', [ ], { my $id = $c->minion->enqueue( 'sync_ssl_certs', [ ], {
queue => 'certbot', queue => 'certbot',
@ -205,58 +288,61 @@ sub do_sync_ssl ( $c ) {
}); });
$c->db->admin_jobs->create({ minion_job_id => $id }); $c->db->admin_jobs->create({ minion_job_id => $id });
$c->flash( confirmation => "Scheduled job to sync SSL certs." ); return $c->redirect_success( 'show_admin_jobs', 'Scheduled job to sync SSL certs.' );
$c->redirect_to( $c->url_for( 'show_admin_jobs' ) );
} }
#==
# POST /admin/alert/read | do_admin_alert_read
# nid | The ID for the system_note
#
# This route will mark a system_note as read when given the note id.
#==
sub do_alert_read ( $c ) { sub do_alert_read ( $c ) {
my $note = $c->db->system_note( $c->param('nid') ); my $note = $c->db->system_note( $c->param('nid') );
if ( ! $note ) { return $c->redirect_error( 'show_admin_alerts', {}, [ "That note doesn't seem to exist." ] )
$c->flash( error_message => "Note could not be marked as read, because it doesn't exist?" ); unless $note;
$c->redirect_to( $c->url_for( 'show_admin_alerts' ) );
return;
}
$note->is_read( 1 ); $note->is_read( 1 );
$note->update; $note->update;
$c->flash( confirmation => "Note marked as read." ); return $c->redirect_success( 'show_admin_alerts', 'Note marked as read.' );
$c->redirect_to( $c->url_for( 'show_admin_alerts' ) );
} }
#==
# POST /admin/alert/unread | do_admin_alert_unread
# nid | The ID for the system_note
#
# This route will mark a system_note as unread when given the note id.
#==
sub do_alert_unread ( $c ) { sub do_alert_unread ( $c ) {
my $note = $c->db->system_note( $c->param('nid') ); my $note = $c->db->system_note( $c->param('nid') );
if ( ! $note ) { return $c->redirect_error( 'show_admin_alerts', {}, [ "That note doesn't seem to exist." ] )
$c->flash( error_message => "Note could not be marked as unread, because it doesn't exist?" ); unless $note;
$c->redirect_to( $c->url_for( 'show_admin_alerts' ) );
return;
}
$note->is_read( 0 ); $note->is_read( 0 );
$note->update; $note->update;
$c->flash( confirmation => "Note marked as read." ); return $c->redirect_success( 'show_admin_alerts', 'Note marked as unread.' );
$c->redirect_to( $c->url_for( 'show_admin_alerts' ) );
} }
#==
# POST /admin/alert/remove | do_admin_alert_remove
# nid | The ID for the system_note
#
# This route will delete a system_note when given the note id.
#==
sub do_alert_remove ( $c ) { sub do_alert_remove ( $c ) {
my $note = $c->db->system_note( $c->param('nid') ); my $note = $c->db->system_note( $c->param('nid') );
if ( ! $note ) { return $c->redirect_error( 'show_admin_alerts', {}, [ "That note doesn't seem to exist." ] )
$c->flash( error_message => "Note could not be removed, because it doesn't exist?" ); unless $note;
$c->redirect_to( $c->url_for( 'show_admin_alerts' ) );
return;
}
$note->delete; $note->delete;
$c->flash( confirmation => "Note removed" ); return $c->redirect_success( 'show_admin_alerts', 'Note removed.' );
$c->redirect_to( $c->url_for( 'show_admin_alerts' ) );
} }
1; 1;

Loading…
Cancel
Save