Code clean-up, refactoring, commenting

Did an audit of the code to tidy things up, refactor, get rid of
some unused stuff that came with Laravel, and comment everything.
This commit is contained in:
St John Karp 2018-10-10 17:58:51 -07:00
parent 157b9eed48
commit 3d1747e13e
16 changed files with 335 additions and 276 deletions

View File

@ -1,35 +1,17 @@
APP_NAME=Laravel
APP_NAME=Planiverse
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_LOG_LEVEL=debug
APP_URL=http://localhost
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret
DB_CONNECTION=sqlite
DB_DATABASE=/var/www/planiverse/database/database.sqlite
BROADCAST_DRIVER=log
CACHE_DRIVER=file
SESSION_DRIVER=file
SESSION_LIFETIME=120
QUEUE_DRIVER=sync
SESSION_LIFETIME=1440
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MASTODON_DOMAIN=http://127.0.0.1
MASTODON_REDIRECT=https://localhost/callback
MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1
SHOW_BEATS=true

48
app/Helpers/Links.php Normal file
View File

@ -0,0 +1,48 @@
<?php
namespace App\Helpers;
use Mastodon;
use GuzzleHttp\Psr7;
/**
* Container class to hold pagination links.
*/
class Links
{
public $next;
public $prev;
/**
* Generate pagination links for the given route.
*
* After receiving a paginated response from the Mastodon API,
* parse the "link" header from the Mastodon response and use
* it to generate next and previous links for the requested route.
*
* @param string[] $links_header An array of values of the "link" header,
* as might be returned from Guzzle's getHeader() method.
* @param string $route The name of the route to generate links for.
*/
function __construct(array $links_header, string $route)
{
foreach (Psr7\parse_header($links_header) as $link)
{
# Find the prev and next links.
if ($link['rel'] === 'prev' || $link['rel'] === 'next')
{
$url = parse_url(trim($link[0], '<>'));
foreach (explode('&', $url['query']) as $query_param)
{
# Grab the ID query parameters from the link.
if (strpos($query_param, 'max_id=') === 0
|| strpos($query_param, 'since_id=') === 0)
{
# Construct new links with the correct offset.
$this->$link['rel'] = route($route) . '?' . $query_param;
}
}
}
}
}
}

View File

@ -1,62 +0,0 @@
<?php
namespace App\Helpers;
use Mastodon;
use GuzzleHttp\Psr7;
use Illuminate\Http\Request;
class Pagination
{
public static function compile_links(string $route)
{
$links = [
'next' => null,
'prev' => null
];
# Parse out the links header returned from the Mastodon API.
$links_header = Mastodon::getResponse()->getHeader('link');
foreach (Psr7\parse_header($links_header) as $link)
{
# Find the prev and next links.
if ($link['rel'] === 'prev' || $link['rel'] === 'next')
{
$url = parse_url(trim($link[0], '<>'));
foreach (explode('&', $url['query']) as $query_param)
{
# Grab the ID query parameters from the link.
if (strpos($query_param, 'max_id=') === 0
|| strpos($query_param, 'since_id=') === 0)
{
# Construct new links with the correct offset.
$links[$link['rel']] = route($route) . '?' . $query_param;
}
}
}
}
return $links;
}
public static function compile_params(Request $request)
{
$params = [];
if ($request->has('max_id') && $request->has('since_id'))
{
# This scenario makes no sense. Someone's trying to dicker with the URL.
abort(400);
}
elseif ($request->has('max_id'))
{
$params['max_id'] = $request->max_id;
}
elseif ($request->has('since_id'))
{
$params['since_id'] = $request->since_id;
}
return $params;
}
}

View File

@ -0,0 +1,54 @@
<?php
namespace App\Helpers;
use Illuminate\Http\Request;
/**
* Parse and store pagination query parameters.
*/
class PaginationParameters
{
public $max_id;
public $since_id;
/**
* Parse a Request and populate the pagination parameters from it.
*
* @param Request $request The request received with pagination query params.
*/
function __construct(Request $request)
{
if ($request->has('max_id') && $request->has('since_id'))
{
# This scenario makes no sense.
# Someone's trying to dicker with the URL.
abort(400);
}
elseif ($request->has('max_id'))
{
$this->max_id = $request->max_id;
}
elseif ($request->has('since_id'))
{
$this->since_id = $request->since_id;
}
}
/**
* Figure out which property is set and return it in an array.
*
* @return string[] The max_id or the since_id in an associative array.
*/
public function to_array()
{
if (isset($this->max_id))
{
return ['max_id' => $this->max_id];
}
else
{
return ['since_id' => $this->since_id];
}
}
}

View File

@ -6,27 +6,41 @@ use App\Http\Controllers\Controller;
use Mastodon;
use Illuminate\Http\Request;
/**
* Controller for Account functions.
*/
class AccountController extends Controller
{
public function view_account(Request $request, string $account_id)
/**
* Fetch an Account from the Mastodon API and present it to the user.
*
* The returned view will show the details of the Account and the actions
* the user can perform (follow, mute, etc.)
*
* @param string $account_id The ID of the Account to query.
*
* @return Illuminate\View\View The Account details page.
*/
public function view_account(string $account_id)
{
$user = session('user');
# Get the Account from the API.
$account = Mastodon::domain(env('MASTODON_DOMAIN'))
->token($user->token)
->get('/accounts/' . $account_id);
if (session()->has('relationship'))
{
// The user is coming here after peforming an action on an account,
// in which case we don't need to re-query the relationship.
# The user is coming here after peforming an action on an account,
# in which case we don't need to re-query the relationship.
$relationship = session('relationship');
}
else
{
// If the relationship hasn't been returned from performing an action,
// we need to query for it.
# If the relationship hasn't been returned from performing an action,
# we need to query for it.
$relationships = Mastodon::domain(env('MASTODON_DOMAIN'))
->token($user->token)
@ -44,35 +58,58 @@ class AccountController extends Controller
return view('account', $vars);
}
public function follow_account(Request $request, string $account_id)
/**
* Follow an Account and redirect to the "account" view.
*
* @param string $account_id The ID of the Account to query.
*
* @return Illuminate\Routing\Redirector Redirect to the account details page.
*/
public function follow_account(string $account_id)
{
$user = session('user');
# Query the API to follow the Account.
$relationship = Mastodon::domain(env('MASTODON_DOMAIN'))
->token($user->token)
->post('/accounts/' . $account_id . '/follow');
# Redirect with the resulting relationship as a temporary session variable.
return redirect()->route('account', ['account_id' => $account_id])
->with('relationship', $relationship);
}
/**
* Unfollow an Account and redirect to the "account" view.
*
* @param string $account_id The ID of the Account to query.
*
* @return Illuminate\Routing\Redirector Redirect to the account details page.
*/
public function unfollow_account(Request $request, string $account_id)
{
$user = session('user');
# Unfollow via the API.
$relationship = Mastodon::domain(env('MASTODON_DOMAIN'))
->token($user->token)
->post('/accounts/' . $account_id . '/unfollow');
# Redirect with the resulting relationship as a temporary session variable.
return redirect()->route('account', ['account_id' => $account_id])
->with('relationship', $relationship);
}
/**
* Show the page that lets users search for an Account.
*
* @return Illuminate\View\View The search page.
*/
public function show_search()
{
if (session()->has('accounts'))
{
// The user is coming here after peforming a search.
# The user is coming here after peforming a search.
$accounts = session('accounts');
}
@ -89,6 +126,13 @@ class AccountController extends Controller
return view('search_accounts', $vars);
}
/**
* Process a search request.
*
* @param Request $request The POST request with search parameters.
*
* @return Illuminate\Routing\Redirector Redirect to the search page.
*/
public function search(Request $request)
{
$user = session('user');
@ -99,6 +143,10 @@ class AccountController extends Controller
abort(400);
}
# Query the search end-point.
/* To-do: currently this always throws an exception from Guzzle.
I've commented out the nav link to the search page until I can figure
this out. */
$accounts = Mastodon::domain(env('MASTODON_DOMAIN'))
->token($user->token)
->get('/accounts/search', ['q' => $request->account]);

View File

@ -7,12 +7,25 @@ use Mastodon;
use Illuminate\Support\Facades\DB;
use Socialite;
/**
* Controller for login functions.
*/
class LoginController extends Controller
{
/**
* Direct the user to the Mastodon OAuth login page.
*
* First check to see if we are registered as an app with the Mastodon API,
* then direct users to the OAuth login.
*
* @return Illuminate\Http\RedirectResponse Redirect to the OAuth login.
*/
public function login()
{
# Check if this app is already registered.
$app = DB::table('apps')->where('server', env('MASTODON_DOMAIN'))->first();
$app = DB::table('apps')
->where('server', env('MASTODON_DOMAIN'))
->first();
if ($app == null)
{
@ -28,6 +41,7 @@ class LoginController extends Controller
$client_id = $app_info['client_id'];
$client_secret = $app_info['client_secret'];
# Log the client details so we don't have to re-register.
DB::table('apps')->insert([
'server' => env('MASTODON_DOMAIN'),
'client_name' => env('APP_NAME'),
@ -59,6 +73,14 @@ class LoginController extends Controller
return Socialite::driver('mastodon')->redirect();
}
/**
* Process the logged-in user.
*
* After logging in remotely, the user will be redirected to this callback.
* We juggle their login details, then direct them to the home page.
*
* @return Illuminate\Routing\Redirector Redirect to the home page.
*/
public function callback()
{
$domain = session('mastodon_domain');

View File

@ -5,15 +5,29 @@ namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Mastodon;
use Illuminate\Http\Request;
use App\Helpers\Pagination;
use App\Helpers\Links;
use App\Helpers\PaginationParameters;
/**
* Controller for the notifications page.
*/
class NotificationsController extends Controller
{
/**
* Get and display notifications.
*
* @param Request $request The request containing pagination parameters.
*
* @return Illuminate\View\View The notifications page.
*/
public function get_notifications(Request $request)
{
$user = session('user');
$params = Pagination::compile_params($request);
$params = (new PaginationParameters($request))
->to_array();
# Fetch notifications from the API.
$notifications = Mastodon::domain(env('MASTODON_DOMAIN'))
->token($user->token)
->get('/notifications', $params);
@ -21,7 +35,10 @@ class NotificationsController extends Controller
$vars = [
'notifications' => $notifications,
'mastodon_domain' => explode('//', env('MASTODON_DOMAIN'))[1],
'links' => Pagination::compile_links('notifications')
'links' => new Links(
Mastodon::getResponse()->getHeader('link'),
'notifications'
)
];
return view('notifications', $vars);

View File

@ -6,27 +6,39 @@ use App\Http\Controllers\Controller;
use Mastodon;
use Illuminate\Http\Request;
/**
* Controller for managing Statuses.
*/
class StatusController extends Controller
{
public function show_status(Request $request, string $status_id)
/**
* Show a Status.
*
* Conditionally shows a reply form if the user is logged in.
*
* @param string $status_id The ID of the Status to display.
*
* @return Illuminate\View\View The Status view page.
*/
public function show_status(string $status_id)
{
if (session()->has('status'))
{
// The user is coming here after peforming an action on a status,
// in which case we don't need to re-query it.
# The user is coming here after peforming an action on a status,
# in which case we don't need to re-query it.
$status = session('status');
}
else
{
// If the status hasn't been returned from performing an action,
// we need to query for it.
# If the status hasn't been returned from performing an action,
# we need to query for it.
if (session()->has('user'))
{
// If the user is logged in, send the token to ensure they
// can see private and direct statuses. Otherwise the API
// returns a 404.
# If the user is logged in, send the token to ensure they
# can see private and direct statuses. Otherwise the API
# returns a 404.
$status = Mastodon::domain(env('MASTODON_DOMAIN'))
->token(session('user')->token)
@ -39,17 +51,17 @@ class StatusController extends Controller
}
}
// Compile a list of accounts to include in the reply.
# Compile a list of accounts to include in the reply.
$reply_mentions = [];
if (session()->has('user'))
{
// Include the original poster, if not the current user.
# Include the original poster, if not the current user.
if ($status['account']['acct'] !== session('user')->user['acct'])
{
array_push($reply_mentions, '@' . $status['account']['acct']);
}
// Include all mentions, excluding the current user.
# Include all mentions, excluding the current user.
foreach ($status['mentions'] as $mention)
{
if ($mention['acct'] !== session('user')->user['acct'])
@ -69,10 +81,18 @@ class StatusController extends Controller
return view('show_status', $vars);
}
public function reblog_status(Request $request, string $status_id)
/**
* Reblog a Status.
*
* @param string $status_id The ID of the Status to reblog.
*
* @return Illuminate\Routing\Redirector Redirect to the Status view page.
*/
public function reblog_status(string $status_id)
{
$user = session('user');
# Reblog request to the API.
$status = Mastodon::domain(env('MASTODON_DOMAIN'))
->token($user->token)
->post('/statuses/' . $status_id . '/reblog');
@ -81,10 +101,18 @@ class StatusController extends Controller
->with('status', $status);
}
public function unreblog_status(Request $request, string $status_id)
/**
* Unreblog a Status.
*
* @param string $status_id The ID of the Status to unreblog.
*
* @return Illuminate\Routing\Redirector Redirect to the Status view page.
*/
public function unreblog_status(string $status_id)
{
$user = session('user');
# Unreblog request to the API.
$status = Mastodon::domain(env('MASTODON_DOMAIN'))
->token($user->token)
->post('/statuses/' . $status_id . '/unreblog');
@ -93,10 +121,18 @@ class StatusController extends Controller
->with('status', $status);
}
public function favourite_status(Request $request, string $status_id)
/**
* Favourite a Status.
*
* @param string $status_id The ID of the Status to favourite.
*
* @return Illuminate\Routing\Redirector Redirect to the Status view page.
*/
public function favourite_status(string $status_id)
{
$user = session('user');
# Favourite the Status.
$status = Mastodon::domain(env('MASTODON_DOMAIN'))
->token($user->token)
->post('/statuses/' . $status_id . '/favourite');
@ -105,10 +141,18 @@ class StatusController extends Controller
->with('status', $status);
}
public function unfavourite_status(Request $request, string $status_id)
/**
* Unfavourite a Status.
*
* @param string $status_id The ID of the Status to unfavourite.
*
* @return Illuminate\Routing\Redirector Redirect to the Status view page.
*/
public function unfavourite_status(string $status_id)
{
$user = session('user');
# Unfavourite request to the API.
$status = Mastodon::domain(env('MASTODON_DOMAIN'))
->token($user->token)
->post('/statuses/' . $status_id . '/unfavourite');
@ -117,6 +161,13 @@ class StatusController extends Controller
->with('status', $status);
}
/**
* Post a new Status.
*
* @param Request $request Request containing the form submission.
*
* @return Illuminate\Routing\Redirector Redirect to the home timeline page.
*/
public function post_status(Request $request)
{
$user = session('user');
@ -140,6 +191,8 @@ class StatusController extends Controller
'language'
];
# Grab each of the optional inputs from the form.
# Not all of these are present in the HTML of the view yet.
foreach ($inputs as $input)
{
if ($request->has($input))
@ -148,6 +201,7 @@ class StatusController extends Controller
}
}
# Post the Status via the API.
$new_status = Mastodon::domain(env('MASTODON_DOMAIN'))
->token($user->token)
->post('/statuses', $params);
@ -155,11 +209,22 @@ class StatusController extends Controller
return redirect()->route('home');
}
public function context(Request $request, string $status_id)
/**
* Show the context of a Status.
*
* Show a Status in its thread of ancestors and descendants.
*
* @param string $status_id The ID of the Status to display.
*
* @return Illuminate\View\View The context view page.
*/
public function context(string $status_id)
{
# Get the Status itself.
$status = Mastodon::domain(env('MASTODON_DOMAIN'))
->get('/statuses/' . $status_id);
# Get the context.
$context = Mastodon::domain(env('MASTODON_DOMAIN'))
->get('/statuses/' . $status_id . '/context');

View File

@ -5,33 +5,62 @@ namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Mastodon;
use Illuminate\Http\Request;
use App\Helpers\Pagination;
use App\Helpers\Links;
use App\Helpers\PaginationParameters;
/**
* Controller for the public and user timelines.
*/
class TimelineController extends Controller
{
/**
* Show the public timeline.
*
* The user does not have to be logged in to see this.
*
* @param Request $request The request containing pagination parameters.
*
* @return Illuminate\View\View The public timeline.
*/
public function public_timeline(Request $request)
{
$params = Pagination::compile_params($request);
$params = (new PaginationParameters($request))
->to_array();
$params['local'] = true;
# Query for the public timeline.
$timeline = Mastodon::domain(env('MASTODON_DOMAIN'))
->get('/timelines/public', $params);
$vars = [
'statuses' => $timeline,
'mastodon_domain' => explode('//', env('MASTODON_DOMAIN'))[1],
'links' => Pagination::compile_links('public')
'links' => new Links(
Mastodon::getResponse()->getHeader('link'),
'public'
)
];
return view('public_timeline', $vars);
}
/**
* Show the home timeline.
*
* @param Request $request The request containing pagination parameters.
*
* @return Illuminate\View\View The user's home timeline.
*/
public function home_timeline(Request $request)
{
$user = session('user');
$params = Pagination::compile_params($request);
$params = (new PaginationParameters($request))
->to_array();
# Query for the user's timeline.
$timeline = Mastodon::domain(env('MASTODON_DOMAIN'))
->token($user->token)
->get('/timelines/home', $params);
@ -39,7 +68,10 @@ class TimelineController extends Controller
$vars = [
'statuses' => $timeline,
'mastodon_domain' => explode('//', env('MASTODON_DOMAIN'))[1],
'links' => Pagination::compile_links('home')
'links' => new Links(
Mastodon::getResponse()->getHeader('link'),
'home'
)
];
return view('home_timeline', $vars);

View File

@ -1,22 +0,0 @@
/**
* First we will load all of this project's JavaScript dependencies which
* includes Vue and other libraries. It is a great starting point when
* building robust, powerful web applications using Vue and Laravel.
*/
require('./bootstrap');
window.Vue = require('vue');
/**
* Next, we will create a fresh Vue application instance and attach it to
* the page. Then, you may begin adding components to this application
* or customize the JavaScript scaffolding to fit your unique needs.
*/
Vue.component('example-component', require('./components/ExampleComponent.vue'));
const app = new Vue({
el: '#app'
});

View File

@ -1,55 +0,0 @@
window._ = require('lodash');
/**
* We'll load jQuery and the Bootstrap jQuery plugin which provides support
* for JavaScript based Bootstrap features such as modals and tabs. This
* code may be modified to fit the specific needs of your application.
*/
try {
window.$ = window.jQuery = require('jquery');
require('bootstrap-sass');
} catch (e) {}
/**
* We'll load the axios HTTP library which allows us to easily issue requests
* to our Laravel back-end. This library automatically handles sending the
* CSRF token as a header based on the value of the "XSRF" token cookie.
*/
window.axios = require('axios');
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
/**
* Next we will register the CSRF Token as a common header with Axios so that
* all outgoing HTTP requests automatically have it attached. This is just
* a simple convenience so we don't have to attach every token manually.
*/
let token = document.head.querySelector('meta[name="csrf-token"]');
if (token) {
window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
} else {
console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
}
/**
* Echo exposes an expressive API for subscribing to channels and listening
* for events that are broadcast by Laravel. Echo and event broadcasting
* allows your team to easily build robust real-time web applications.
*/
// import Echo from 'laravel-echo'
// window.Pusher = require('pusher-js');
// window.Echo = new Echo({
// broadcaster: 'pusher',
// key: 'your-pusher-key',
// cluster: 'mt1',
// encrypted: true
// });

View File

@ -1,23 +0,0 @@
<template>
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">Example Component</div>
<div class="panel-body">
I'm an example component!
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
mounted() {
console.log('Component mounted.')
}
}
</script>

View File

@ -1,38 +0,0 @@
// Body
$body-bg: #f5f8fa;
// Borders
$laravel-border-color: darken($body-bg, 10%);
$list-group-border: $laravel-border-color;
$navbar-default-border: $laravel-border-color;
$panel-default-border: $laravel-border-color;
$panel-inner-border: $laravel-border-color;
// Brands
$brand-primary: #3097D1;
$brand-info: #8eb4cb;
$brand-success: #2ab27b;
$brand-warning: #cbb956;
$brand-danger: #bf5329;
// Typography
$icon-font-path: "~bootstrap-sass/assets/fonts/bootstrap/";
$font-family-sans-serif: "Raleway", sans-serif;
$font-size-base: 14px;
$line-height-base: 1.6;
$text-color: #636b6f;
// Navbar
$navbar-default-bg: #fff;
// Buttons
$btn-default-color: $text-color;
// Inputs
$input-border: lighten($text-color, 40%);
$input-border-focus: lighten($brand-primary, 25%);
$input-color-placeholder: lighten($text-color, 30%);
// Panels
$panel-default-heading-bg: #fff;

View File

@ -1,9 +0,0 @@
// Fonts
@import url("https://fonts.googleapis.com/css?family=Raleway:300,400,600");
// Variables
@import "variables";
// Bootstrap
@import "~bootstrap-sass/assets/stylesheets/bootstrap";

View File

@ -1,11 +1,11 @@
<nav>
<ul>
@if ($links['prev'] !== null)
<li><a href="{{ $links['prev'] }}">Previous</a></li>
@if (isset($links->prev))
<li><a href="{{ $links->prev }}">Previous</a></li>
@endif
@if ($links['next'] !== null)
<li><a href="{{ $links['next'] }}">Next</a></li>
@if (isset($links->next))
<li><a href="{{ $links->next }}">Next</a></li>
@endif
</ul>
</nav>

View File

@ -24,22 +24,22 @@
<div class="actions">
<!-- Context -->
<span title="Expand thread">
<a href="{{ route('thread', ['id' => $status['id']]) }}">&#10568;</a>
<a href="{{ route('thread', ['status_id' => $status['id']]) }}">&#10568;</a>
</span>
<!-- Reply -->
<span title="Reply">
<a href="{{ route('status', ['id' => $status['id']]) }}">&#8629;</a>
<a href="{{ route('status', ['status_id' => $status['id']]) }}">&#8629;</a>
</span>
<!-- Reblog -->
<span title="Reblog">
@if ($status['reblogged'])
<span class="reblogged">
<a href="{{ route('unreblog', ['id' => $status['id']]) }}">&#8634;</a>
<a href="{{ route('unreblog', ['status_id' => $status['id']]) }}">&#8634;</a>
</span>
@else
<a href="{{ route('reblog', ['id' => $status['id']]) }}">&#8634;</a>
<a href="{{ route('reblog', ['status_id' => $status['id']]) }}">&#8634;</a>
@endif
{{ $status['reblogs_count'] }}
</span>
@ -48,10 +48,10 @@
<span title="Favourite">
@if ($status['favourited'])
<span class="favourited">
<a href="{{ route('unfavourite', ['id' => $status['id']]) }}">&#9733;</a>
<a href="{{ route('unfavourite', ['status_id' => $status['id']]) }}">&#9733;</a>
</span>
@else
<a href="{{ route('favourite', ['id' => $status['id']]) }}">&#9734;</a>
<a href="{{ route('favourite', ['status_id' => $status['id']]) }}">&#9734;</a>
@endif
{{ $status['favourites_count'] }}
</span>