diff --git a/.env.travis b/.env.travis index 766e9ed8..177e5cc8 100644 --- a/.env.travis +++ b/.env.travis @@ -12,3 +12,6 @@ SESSION_DRIVER=array QUEUE_DRIVER=sync SCOUT_DRIVER=pgsql + +DISPLAY_NAME='Travis Test' +USER_NAME=travis diff --git a/.travis.yml b/.travis.yml index a93b22a5..f99b6ea4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,7 +34,6 @@ env: - setup=basic php: - - 7.1 - 7.2 before_install: diff --git a/app/Console/Commands/ParseCachedWebMentions.php b/app/Console/Commands/ParseCachedWebMentions.php index 960a1b9f..2183cd4a 100644 --- a/app/Console/Commands/ParseCachedWebMentions.php +++ b/app/Console/Commands/ParseCachedWebMentions.php @@ -1,5 +1,7 @@ securityChecker->check(base_path() . '/composer.lock'); if (count($alerts) === 0) { diff --git a/app/Http/Controllers/Admin/ArticlesController.php b/app/Http/Controllers/Admin/ArticlesController.php index 1db84696..848f8440 100644 --- a/app/Http/Controllers/Admin/ArticlesController.php +++ b/app/Http/Controllers/Admin/ArticlesController.php @@ -1,19 +1,23 @@ orderBy('id', 'desc')->get(); @@ -23,9 +27,9 @@ class ArticlesController extends Controller /** * Show the new article form. * - * @return \Illuminate\View\Factory view + * @return \Illuminate\View\View */ - public function create() + public function create(): View { $message = session('message'); @@ -35,23 +39,22 @@ class ArticlesController extends Controller /** * Process an incoming request for a new article and save it. * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\View\Factory view + * @return \Illuminate\Http\RedirectResponse */ - public function store(Request $request) + public function store(): RedirectResponse { //if a `.md` is attached use that for the main content. - if ($request->hasFile('article')) { - $file = $request->file('article')->openFile(); + if (request()->hasFile('article')) { + $file = request()->file('article')->openFile(); $content = $file->fread($file->getSize()); } - $main = $content ?? $request->input('main'); + $main = $content ?? request()->input('main'); $article = Article::create( [ - 'url' => $request->input('url'), - 'title' => $request->input('title'), + 'url' => request()->input('url'), + 'title' => request()->input('title'), 'main' => $main, - 'published' => $request->input('published') ?? 0, + 'published' => request()->input('published') ?? 0, ] ); @@ -61,10 +64,10 @@ class ArticlesController extends Controller /** * Show the edit form for an existing article. * - * @param string The article id - * @return \Illuminate\View\Factory view + * @param int $articleId + * @return \Illuminate\View\View */ - public function edit($articleId) + public function edit(int $articleId): View { $post = Article::select( 'title', @@ -79,17 +82,16 @@ class ArticlesController extends Controller /** * Process an incoming request to edit an article. * - * @param \Illuminate\Http\Request $request - * @param string - * @return \Illuminate|View\Factory view + * @param int $articleId + * @return \Illuminate\Http\RedirectResponse */ - public function update(Request $request, $articleId) + public function update(int $articleId): RedirectResponse { $article = Article::find($articleId); - $article->title = $request->input('title'); - $article->url = $request->input('url'); - $article->main = $request->input('main'); - $article->published = $request->input('published') ?? 0; + $article->title = request()->input('title'); + $article->url = request()->input('url'); + $article->main = request()->input('main'); + $article->published = request()->input('published') ?? 0; $article->save(); return redirect('/admin/blog'); @@ -98,10 +100,10 @@ class ArticlesController extends Controller /** * Process a request to delete an aricle. * - * @param string The article id - * @return \Illuminate\View\Factory view + * @param int $articleId + * @return \Illuminate\Http\RedirectResponse */ - public function destroy($articleId) + public function destroy(int $articleId): RedirectResponse { Article::where('id', $articleId)->delete(); diff --git a/app/Http/Controllers/Admin/ClientsController.php b/app/Http/Controllers/Admin/ClientsController.php index 366e0994..9eb37c97 100644 --- a/app/Http/Controllers/Admin/ClientsController.php +++ b/app/Http/Controllers/Admin/ClientsController.php @@ -1,19 +1,23 @@ $request->input('client_url'), - 'client_name' => $request->input('client_name'), + 'client_url' => request()->input('client_url'), + 'client_name' => request()->input('client_name'), ]); return redirect('/admin/clients'); @@ -49,10 +52,10 @@ class ClientsController extends Controller /** * Show a form to edit a client name. * - * @param string The client id - * @return \Illuminate\View\Factory view + * @param int $clientId + * @return \Illuminate\View\View */ - public function edit($clientId) + public function edit(int $clientId): View { $client = MicropubClient::findOrFail($clientId); @@ -66,15 +69,14 @@ class ClientsController extends Controller /** * Process the request to edit a client name. * - * @param string The client id - * @param \Illuminate\Http\Request $request - * @return \Illuminate\View\Factory view + * @param int $clientId + * @return \Illuminate\Http\RedirectResponse */ - public function update($clientId, Request $request) + public function update(int $clientId): RedirectResponse { $client = MicropubClient::findOrFail($clientId); - $client->client_url = $request->input('client_url'); - $client->client_name = $request->input('client_name'); + $client->client_url = request()->input('client_url'); + $client->client_name = request()->input('client_name'); $client->save(); return redirect('/admin/clients'); @@ -83,10 +85,10 @@ class ClientsController extends Controller /** * Process a request to delete a client. * - * @param string The client id - * @return redirect + * @param int $clientId + * @return \Illuminate\Http\RedirectResponse */ - public function destroy($clientId) + public function destroy(int $clientId): RedirectResponse { MicropubClient::where('id', $clientId)->delete(); diff --git a/app/Http/Controllers/Admin/ContactsController.php b/app/Http/Controllers/Admin/ContactsController.php index 82ec7e88..c32aa610 100644 --- a/app/Http/Controllers/Admin/ContactsController.php +++ b/app/Http/Controllers/Admin/ContactsController.php @@ -1,21 +1,25 @@ name = $request->input('name'); - $contact->nick = $request->input('nick'); - $contact->homepage = $request->input('homepage'); - $contact->twitter = $request->input('twitter'); - $contact->facebook = $request->input('facebook'); + $contact->name = request()->input('name'); + $contact->nick = request()->input('nick'); + $contact->homepage = request()->input('homepage'); + $contact->twitter = request()->input('twitter'); + $contact->facebook = request()->input('facebook'); $contact->save(); return redirect('/admin/contacts'); @@ -54,10 +57,10 @@ class ContactsController extends Controller /** * Show the form to edit an existing contact. * - * @param string The contact id - * @return \Illuminate\View\Factory view + * @param int $contactId + * @return \Illuminate\View\View */ - public function edit($contactId) + public function edit(int $contactId): View { $contact = Contact::findOrFail($contactId); @@ -69,28 +72,27 @@ class ContactsController extends Controller * * @todo Allow saving profile pictures for people without homepages * - * @param string The contact id - * @param \Illuminate\Http\Request $request - * @return \Illuminate\View\Factory view + * @param int $contactId + * @return \Illuminate\Http\RedirectResponse */ - public function update($contactId, Request $request) + public function update(int $contactId): RedirectResponse { $contact = Contact::findOrFail($contactId); - $contact->name = $request->input('name'); - $contact->nick = $request->input('nick'); - $contact->homepage = $request->input('homepage'); - $contact->twitter = $request->input('twitter'); - $contact->facebook = $request->input('facebook'); + $contact->name = request()->input('name'); + $contact->nick = request()->input('nick'); + $contact->homepage = request()->input('homepage'); + $contact->twitter = request()->input('twitter'); + $contact->facebook = request()->input('facebook'); $contact->save(); - if ($request->hasFile('avatar') && ($request->input('homepage') != '')) { - $dir = parse_url($request->input('homepage'), PHP_URL_HOST); + if (request()->hasFile('avatar') && (request()->input('homepage') != '')) { + $dir = parse_url(request()->input('homepage'), PHP_URL_HOST); $destination = public_path() . '/assets/profile-images/' . $dir; $filesystem = new Filesystem(); if ($filesystem->isDirectory($destination) === false) { $filesystem->makeDirectory($destination); } - $request->file('avatar')->move($destination, 'image'); + request()->file('avatar')->move($destination, 'image'); } return redirect('/admin/contacts'); @@ -99,10 +101,10 @@ class ContactsController extends Controller /** * Process the request to delete a contact. * - * @param string The contact id - * @return \Illuminate\View\Factory view + * @param int $contactId + * @return \Illuminate\Http\RedirectResponse */ - public function destroy($contactId) + public function destroy(int $contactId): RedirectResponse { $contact = Contact::findOrFail($contactId); $contact->delete(); @@ -116,16 +118,16 @@ class ContactsController extends Controller * This method attempts to find the microformat marked-up profile image * from a given homepage and save it accordingly * - * @param string The contact id - * @return \Illuminate\View\Factory view + * @param int $contactId + * @return \Illuminate\Http\RedirectResponse|\Illuminate\View\View */ - public function getAvatar($contactId) + public function getAvatar(int $contactId) { // Initialising $avatarURL = null; $avatar = null; $contact = Contact::findOrFail($contactId); - if (mb_strlen($contact->homepage !== null) !== 0) { + if ($contact->homepage !== null && mb_strlen($contact->homepage) !== 0) { $client = resolve(Client::class); try { $response = $client->get($contact->homepage); diff --git a/app/Http/Controllers/Admin/HomeController.php b/app/Http/Controllers/Admin/HomeController.php index ebb06f31..6ad2d0d7 100644 --- a/app/Http/Controllers/Admin/HomeController.php +++ b/app/Http/Controllers/Admin/HomeController.php @@ -1,12 +1,20 @@ config('admin.user')]); } diff --git a/app/Http/Controllers/Admin/LikesController.php b/app/Http/Controllers/Admin/LikesController.php index acb08222..6d69a879 100644 --- a/app/Http/Controllers/Admin/LikesController.php +++ b/app/Http/Controllers/Admin/LikesController.php @@ -12,6 +12,11 @@ use Illuminate\Http\RedirectResponse; class LikesController extends Controller { + /** + * List the likes that can be edited. + * + * @return \Illuminate\View\View + */ public function index(): View { $likes = Like::all(); @@ -19,11 +24,21 @@ class LikesController extends Controller return view('admin.likes.index', compact('likes')); } + /** + * Show the form to make a new like. + * + * @return \Illuminate\View\View + */ public function create(): View { return view('admin.likes.create'); } + /** + * Process a request to make a new like. + * + * @return \Illuminate\Http\RedirectResponse + */ public function store(): RedirectResponse { $like = Like::create([ @@ -34,6 +49,12 @@ class LikesController extends Controller return redirect('/admin/likes'); } + /** + * Display the form to edit a specific like. + * + * @param int $likeId + * @return \Illuminate\View\View + */ public function edit(int $likeId): View { $like = Like::findOrFail($likeId); @@ -44,6 +65,12 @@ class LikesController extends Controller ]); } + /** + * Process a request to edit a like. + * + * @param int $likeId + * @return \Illuminate\Http\RedirectResponse + */ public function update(int $likeId): RedirectResponse { $like = Like::findOrFail($likeId); @@ -54,6 +81,12 @@ class LikesController extends Controller return redirect('/admin/likes'); } + /** + * Process the request to delete a like. + * + * @param int $likeId + * @return \Illuminate\Http\RedirectResponse + */ public function destroy(int $likeId): RedirectResponse { Like::where('id', $likeId)->delete(); diff --git a/app/Http/Controllers/Admin/NotesController.php b/app/Http/Controllers/Admin/NotesController.php index 44b4a30f..98ef6f9a 100644 --- a/app/Http/Controllers/Admin/NotesController.php +++ b/app/Http/Controllers/Admin/NotesController.php @@ -1,20 +1,24 @@ orderBy('id', 'desc')->get(); foreach ($notes as $note) { @@ -27,9 +31,9 @@ class NotesController extends Controller /** * Show the form to make a new note. * - * @return \Illuminate\View\Factory view + * @return \Illuminate\View\View */ - public function create() + public function create(): View { return view('admin.notes.create'); } @@ -37,14 +41,13 @@ class NotesController extends Controller /** * Process a request to make a new note. * - * @param Illuminate\Http\Request $request - * @todo Sort this mess out + * @return \Illuminate\Http\RedirectResponse */ - public function store(Request $request) + public function store(): RedirectResponse { Note::create([ - 'in-reply-to' => $request->input('in-reply-to'), - 'note' => $request->input('content'), + 'in-reply-to' => request()->input('in-reply-to'), + 'note' => request()->input('content'), ]); return redirect('/admin/notes'); @@ -53,10 +56,10 @@ class NotesController extends Controller /** * Display the form to edit a specific note. * - * @param string The note id - * @return \Illuminate\View\Factory view + * @param int $noteId + * @return \Illuminate\View\View */ - public function edit($noteId) + public function edit(int $noteId): View { $note = Note::find($noteId); $note->originalNote = $note->getOriginal('note'); @@ -68,18 +71,18 @@ class NotesController extends Controller * Process a request to edit a note. Easy since this can only be done * from the admin CP. * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\View\Factory view + * @param int $noteId + * @return \Illuminate\Http\RedirectResponse */ - public function update($noteId, Request $request) + public function update(int $noteId): RedirectResponse { //update note data $note = Note::findOrFail($noteId); - $note->note = $request->input('content'); - $note->in_reply_to = $request->input('in-reply-to'); + $note->note = request()->input('content'); + $note->in_reply_to = request()->input('in-reply-to'); $note->save(); - if ($request->input('webmentions')) { + if (request()->input('webmentions')) { dispatch(new SendWebMentions($note)); } @@ -89,12 +92,12 @@ class NotesController extends Controller /** * Delete the note. * - * @param int id - * @return view + * @param int $noteId + * @return \Illuminate\Http\RedirectResponse */ - public function destroy($id) + public function destroy(int $noteId): RedirectResponse { - $note = Note::findOrFail($id); + $note = Note::findOrFail($noteId); $note->delete(); return redirect('/admin/notes'); diff --git a/app/Http/Controllers/Admin/PlacesController.php b/app/Http/Controllers/Admin/PlacesController.php index 4bf54f4a..9247eb31 100644 --- a/app/Http/Controllers/Admin/PlacesController.php +++ b/app/Http/Controllers/Admin/PlacesController.php @@ -1,11 +1,15 @@ only(['name', 'description', 'latitude', 'longitude']); + $data = request()->only(['name', 'description', 'latitude', 'longitude']); $place = $this->placeService->createPlace($data); return redirect('/admin/places'); @@ -56,10 +59,10 @@ class PlacesController extends Controller /** * Display the form to edit a specific place. * - * @param string The place id - * @return \Illuminate\View\Factory view + * @param int $placeId + * @return \Illuminate\View\View */ - public function edit($placeId) + public function edit(int $placeId): View { $place = Place::findOrFail($placeId); @@ -69,17 +72,19 @@ class PlacesController extends Controller /** * Process a request to edit a place. * - * @param string The place id - * @param Illuminate\Http\Request $request - * @return Illuminate\View\Factory view + * @param int $placeId + * @return \Illuminate\Http\RedirectResponse */ - public function update($placeId, Request $request) + public function update(int $placeId): RedirectResponse { $place = Place::findOrFail($placeId); - $place->name = $request->name; - $place->description = $request->description; - $place->location = new Point((float) $request->latitude, (float) $request->longitude); - $place->icon = $request->icon; + $place->name = request()->input('name'); + $place->description = request()->input('description'); + $place->location = new Point( + (float) request()->input('latitude'), + (float) request()->input('longitude') + ); + $place->icon = request()->input('icon'); $place->save(); return redirect('/admin/places'); @@ -88,10 +93,10 @@ class PlacesController extends Controller /** * List the places we can merge with the current place. * - * @param string Place id - * @return Illuminate\View\Factory view + * @param int $placeId + * @return \Illuminate\View\View */ - public function mergeIndex($placeId) + public function mergeIndex(int $placeId): View { $first = Place::find($placeId); $results = Place::near(new Point($first->latitude, $first->longitude))->get(); @@ -105,27 +110,39 @@ class PlacesController extends Controller return view('admin.places.merge.index', compact('first', 'places')); } - public function mergeEdit($place1_id, $place2_id) + /** + * Show a form for merging two specific places. + * + * @param int $placeId1 + * @param int $placeId2 + * @return \Illuminate\View\View + */ + public function mergeEdit(int $placeId1, int $placeId2): View { - $place1 = Place::find($place1_id); - $place2 = Place::find($place2_id); + $place1 = Place::find($placeId1); + $place2 = Place::find($placeId2); return view('admin.places.merge.edit', compact('place1', 'place2')); } - public function mergeStore(Request $request) + /** + * Process the request to merge two places. + * + * @return \Illuminate\Http\RedirectResponse + */ + public function mergeStore(): RedirectResponse { - $place1 = Place::find($request->input('place1')); - $place2 = Place::find($request->input('place2')); + $place1 = Place::find(request()->input('place1')); + $place2 = Place::find(request()->input('place2')); - if ($request->input('delete') === '1') { + if (request()->input('delete') === '1') { foreach ($place1->notes as $note) { $note->place()->dissociate(); $note->place()->associate($place2->id); } $place1->delete(); } - if ($request->input('delete') === '2') { + if (request()->input('delete') === '2') { foreach ($place2->notes as $note) { $note->place()->dissociate(); $note->place()->associate($place1->id); diff --git a/app/Http/Controllers/ArticlesController.php b/app/Http/Controllers/ArticlesController.php index df2f1988..cdb91b61 100644 --- a/app/Http/Controllers/ArticlesController.php +++ b/app/Http/Controllers/ArticlesController.php @@ -1,21 +1,27 @@ date((int) $year, (int) $month) + ->date($year, $month) ->orderBy('updated_at', 'desc') ->simplePaginate(5); @@ -25,9 +31,12 @@ class ArticlesController extends Controller /** * Show a single article. * - * @return \Illuminate\View\Factory view + * @param int $year + * @param int $month + * @param string $slug + * @return \Illuminate\Http\RedirectResponse|\Illuminate\View\View */ - public function show($year, $month, $slug) + public function show(int $year, int $month, string $slug) { $article = Article::where('titleurl', $slug)->firstOrFail(); if ($article->updated_at->year != $year || $article->updated_at->month != $month) { @@ -44,12 +53,12 @@ class ArticlesController extends Controller * We only have the ID, work out post title, year and month * and redirect to it. * - * @return \Illuminte\Routing\RedirectResponse redirect + * @param int $idFromUrl + * @return \Illuminte\Http\RedirectResponse */ - public function onlyIdInUrl($inURLId) + public function onlyIdInUrl(int $idFromUrl): RedirectResponse { - $numbers = new Numbers(); - $realId = $numbers->b60tonum($inURLId); + $realId = resolve(Numbers::class)->b60tonum($idFromUrl); $article = Article::findOrFail($realId); return redirect($article->link); diff --git a/app/Http/Controllers/AuthController.php b/app/Http/Controllers/AuthController.php index b58ed184..b2793be4 100644 --- a/app/Http/Controllers/AuthController.php +++ b/app/Http/Controllers/AuthController.php @@ -1,12 +1,21 @@ input('username') === config('admin.user') + if (request()->input('username') === config('admin.user') && - $request->input('password') === config('admin.pass') + request()->input('password') === config('admin.pass') ) { session(['loggedin' => true]); diff --git a/app/Http/Controllers/BookmarksController.php b/app/Http/Controllers/BookmarksController.php index a19bdeb6..8bd95d96 100644 --- a/app/Http/Controllers/BookmarksController.php +++ b/app/Http/Controllers/BookmarksController.php @@ -1,19 +1,33 @@ with('tags')->withCount('tags')->paginate(10); return view('bookmarks.index', compact('bookmarks')); } - public function show(Bookmark $bookmark) + /** + * Show a single bookmark. + * + * @param \App\Models\Bookmark $bookmark + * @return \Illuminate\View\View + */ + public function show(Bookmark $bookmark): View { $bookmark->loadMissing('tags'); diff --git a/app/Http/Controllers/ContactsController.php b/app/Http/Controllers/ContactsController.php index c85e12a4..5ed7f945 100644 --- a/app/Http/Controllers/ContactsController.php +++ b/app/Http/Controllers/ContactsController.php @@ -1,8 +1,11 @@ firstOrFail(); diff --git a/app/Http/Controllers/FeedsController.php b/app/Http/Controllers/FeedsController.php index 2d6da628..3ffb99f8 100644 --- a/app/Http/Controllers/FeedsController.php +++ b/app/Http/Controllers/FeedsController.php @@ -1,7 +1,10 @@ latest('updated_at')->take(20)->get(); $buildDate = $articles->first()->updated_at->toRssString(); @@ -26,7 +29,7 @@ class FeedsController extends Controller * * @return \Illuminate\Http\Response */ - public function blogAtom() + public function blogAtom(): Response { $articles = Article::where('published', '1')->latest('updated_at')->take(20)->get(); @@ -40,7 +43,7 @@ class FeedsController extends Controller * * @return \Illuminate\Http\Response */ - public function notesRss() + public function notesRss(): Response { $notes = Note::latest()->take(20)->get(); $buildDate = $notes->first()->updated_at->toRssString(); @@ -55,7 +58,7 @@ class FeedsController extends Controller * * @return \Illuminate\Http\Response */ - public function notesAtom() + public function notesAtom(): Response { $notes = Note::latest()->take(20)->get(); @@ -64,10 +67,12 @@ class FeedsController extends Controller ->header('Content-Type', 'application/atom+xml; charset=utf-8'); } + /** @todo sort out return type for json responses */ + /** * Returns the blog JSON feed. * - * @return \Illuminate\Http\response + * @return \Illuminate\Http\JsonResponse */ public function blogJson() { @@ -100,7 +105,7 @@ class FeedsController extends Controller /** * Returns the notes JSON feed. * - * @return \Illuminate\Http\response + * @return \Illuminate\Http\JsonResponse */ public function notesJson() { diff --git a/app/Http/Controllers/LikesController.php b/app/Http/Controllers/LikesController.php index ea9e503b..dbc92ec6 100644 --- a/app/Http/Controllers/LikesController.php +++ b/app/Http/Controllers/LikesController.php @@ -1,19 +1,33 @@ paginate(20); return view('likes.index', compact('likes')); } - public function show(Like $like) + /** + * Show a single like. + * + * @param \App\Models\Like $like + * @return \Illuminate\View\View + */ + public function show(Like $like): View { return view('likes.show', compact('like')); } diff --git a/app/Http/Controllers/MicropubController.php b/app/Http/Controllers/MicropubController.php index a0fd24b0..149f8acc 100644 --- a/app/Http/Controllers/MicropubController.php +++ b/app/Http/Controllers/MicropubController.php @@ -1,11 +1,14 @@ input('access_token')); $tokenData = $this->tokenService->validateToken(request()->input('access_token')); } catch (InvalidTokenException $e) { return $this->invalidTokenResponse(); @@ -96,14 +98,16 @@ class MicropubController extends Controller } /** + * Respond to a GET request to the micropub endpoint. + * * A GET request has been made to `api/post` with an accompanying * token, here we check wether the token is valid and respond * appropriately. Further if the request has the query parameter * synidicate-to we respond with the known syndication endpoints. * - * @return \Illuminate\Http\Response + * @return \Illuminate\Http\JsonResponse */ - public function get() + public function get(): JsonResponse { try { $tokenData = $this->tokenService->validateToken(request()->bearerToken()); @@ -124,7 +128,7 @@ class MicropubController extends Controller ]); } - if (substr(request()->input('q'), 0, 4) === 'geo:') { + if (request()->has('q') && substr(request()->input('q'), 0, 4) === 'geo:') { preg_match_all( '/([0-9\.\-]+)/', request()->input('q'), @@ -153,9 +157,9 @@ class MicropubController extends Controller /** * Process a media item posted to the media endpoint. * - * @return Illuminate\Http\Response + * @return Illuminate\Http\JsonResponse */ - public function media() + public function media(): JsonResponse { try { $tokenData = $this->tokenService->validateToken(request()->bearerToken()); @@ -210,10 +214,10 @@ class MicropubController extends Controller /** * Get the file type from the mimetype of the uploaded file. * - * @param string The mimetype - * @return string The type + * @param string $mimetype + * @return string */ - private function getFileTypeFromMimeType($mimetype) + private function getFileTypeFromMimeType(string $mimetype): string { //try known images $imageMimeTypes = [ @@ -252,6 +256,11 @@ class MicropubController extends Controller return 'download'; } + /** + * Determine the client id from the access token sent with the request. + * + * @return string + */ private function getClientId(): string { return resolve(TokenService::class) @@ -259,6 +268,11 @@ class MicropubController extends Controller ->getClaim('client_id'); } + /** + * Save the details of the micropub request to a log file. + * + * @param array $request This is the info from request()->all() + */ private function logMicropubRequest(array $request) { $logger = new Logger('micropub'); @@ -266,7 +280,13 @@ class MicropubController extends Controller $logger->debug('MicropubLog', $request); } - private function saveFile(UploadedFile $file) + /** + * Save an uploaded file to the local disk. + * + * @param \Illuminate\Http\UploadedFele $file + * @return string $filename + */ + private function saveFile(UploadedFile $file): string { $filename = Uuid::uuid4() . '.' . $file->extension(); Storage::disk('local')->put($filename, $file); @@ -274,6 +294,11 @@ class MicropubController extends Controller return $filename; } + /** + * Generate a response to be returned when the token has insufficient scope. + * + * @return \Illuminate\Http\JsonRepsonse + */ private function insufficientScopeResponse() { return response()->json([ @@ -283,6 +308,11 @@ class MicropubController extends Controller ], 401); } + /** + * Generate a response to be returned when the token is invalid. + * + * @return \Illuminate\Http\JsonRepsonse + */ private function invalidTokenResponse() { return response()->json([ @@ -292,6 +322,11 @@ class MicropubController extends Controller ], 400); } + /** + * Generate a response to be returned when the token has no scope. + * + * @return \Illuminate\Http\JsonRepsonse + */ private function tokenHasNoScopeResponse() { return response()->json([ diff --git a/app/Http/Controllers/NotesController.php b/app/Http/Controllers/NotesController.php index 06ab3eb8..d5ff483e 100644 --- a/app/Http/Controllers/NotesController.php +++ b/app/Http/Controllers/NotesController.php @@ -1,10 +1,14 @@ with('webmentions')->firstOrFail(); @@ -51,10 +55,10 @@ class NotesController extends Controller /** * Redirect /note/{decID} to /notes/{nb60id}. * - * @param string The decimal id of he note - * @return \Illuminate\Routing\RedirectResponse redirect + * @param int $decId The decimal id of the note + * @return \Illuminate\Http\RedirectResponse */ - public function redirect($decId) + public function redirect(int $decId): RedirectResponse { return redirect(config('app.url') . '/notes/' . (new Numbers())->numto60($decId)); } @@ -62,10 +66,10 @@ class NotesController extends Controller /** * Show all notes tagged with {tag}. * - * @param string The tag - * @return \Illuminate\View\Factory view + * @param string $tag + * @return \Illuminate\View\View */ - public function tagged($tag) + public function tagged(string $tag): View { $notes = Note::whereHas('tags', function ($query) use ($tag) { $query->where('tag', $tag); diff --git a/app/Http/Controllers/PlacesController.php b/app/Http/Controllers/PlacesController.php index 37ee61f7..f93ab259 100644 --- a/app/Http/Controllers/PlacesController.php +++ b/app/Http/Controllers/PlacesController.php @@ -1,17 +1,20 @@ firstOrFail(); diff --git a/app/Http/Controllers/SearchController.php b/app/Http/Controllers/SearchController.php index 6ef9af6c..b03c16d0 100644 --- a/app/Http/Controllers/SearchController.php +++ b/app/Http/Controllers/SearchController.php @@ -1,15 +1,22 @@ terms)->paginate(10); + $notes = Note::search(request()->input('terms'))->paginate(10); return view('search', compact('notes')); } diff --git a/app/Http/Controllers/SessionStoreController.php b/app/Http/Controllers/SessionStoreController.php index c7d239eb..042aa958 100644 --- a/app/Http/Controllers/SessionStoreController.php +++ b/app/Http/Controllers/SessionStoreController.php @@ -1,9 +1,16 @@ input('css'); diff --git a/app/Http/Controllers/ShortURLsController.php b/app/Http/Controllers/ShortURLsController.php index a4979ca0..2510a7b0 100644 --- a/app/Http/Controllers/ShortURLsController.php +++ b/app/Http/Controllers/ShortURLsController.php @@ -1,7 +1,11 @@ client->discoverAuthorizationEndpoint(normalize_url($request->input('me'))); + $authorizationEndpoint = $this->client->discoverAuthorizationEndpoint(normalize_url(request()->input('me'))); if ($authorizationEndpoint) { $auth = $this->client->verifyIndieAuthCode( $authorizationEndpoint, - $request->input('code'), - $request->input('me'), - $request->input('redirect_uri'), - $request->input('client_id') + request()->input('code'), + request()->input('me'), + request()->input('redirect_uri'), + request()->input('client_id') ); if (array_key_exists('me', $auth)) { $scope = $auth['scope'] ?? ''; $tokenData = [ - 'me' => $request->input('me'), - 'client_id' => $request->input('client_id'), + 'me' => request()->input('me'), + 'client_id' => request()->input('client_id'), 'scope' => $scope, ]; $token = $this->tokenService->getNewToken($tokenData); $content = http_build_query([ - 'me' => $request->input('me'), + 'me' => request()->input('me'), 'scope' => $scope, 'access_token' => $token, ]); diff --git a/app/Http/Controllers/WebMentionsController.php b/app/Http/Controllers/WebMentionsController.php index b9110f56..960840ea 100644 --- a/app/Http/Controllers/WebMentionsController.php +++ b/app/Http/Controllers/WebMentionsController.php @@ -1,9 +1,11 @@ has('target') !== true) || ($request->has('source') !== true)) { - return new Response( + if ((request()->has('target') !== true) || (request()->has('source') !== true)) { + return response( 'You need both the target and source parameters', 400 ); } //next check the $target is valid - $path = parse_url($request->input('target'), PHP_URL_PATH); + $path = parse_url(request()->input('target'), PHP_URL_PATH); $pathParts = explode('/', $path); if ($pathParts[1] == 'notes') { //we have a note $noteId = $pathParts[2]; - $numbers = new Numbers(); try { - $note = Note::findOrFail($numbers->b60tonum($noteId)); - dispatch(new ProcessWebMention($note, $request->input('source'))); + $note = Note::findOrFail(resolve(Numbers::class)->b60tonum($noteId)); + dispatch(new ProcessWebMention($note, request()->input('source'))); } catch (ModelNotFoundException $e) { - return new Response('This note doesn’t exist.', 400); + return response('This note doesn’t exist.', 400); } - return new Response( + return response( 'Webmention received, it will be processed shortly', 202 ); } if ($pathParts[1] == 'blog') { - return new Response( + return response( 'I don’t accept webmentions for blog posts yet.', 501 ); } - return new Response( + return response( 'Invalid request', 400 ); diff --git a/app/Http/Middleware/ActivityStreamLinks.php b/app/Http/Middleware/ActivityStreamLinks.php index 4c240759..4cad411f 100644 --- a/app/Http/Middleware/ActivityStreamLinks.php +++ b/app/Http/Middleware/ActivityStreamLinks.php @@ -1,8 +1,11 @@ path() === '/') { diff --git a/app/Http/Middleware/LocalhostSessionMiddleware.php b/app/Http/Middleware/LocalhostSessionMiddleware.php index ded4f25a..5131b9fc 100644 --- a/app/Http/Middleware/LocalhostSessionMiddleware.php +++ b/app/Http/Middleware/LocalhostSessionMiddleware.php @@ -1,8 +1,11 @@ config('app.url')]); diff --git a/app/Http/Middleware/MyAuthMiddleware.php b/app/Http/Middleware/MyAuthMiddleware.php index 5354e55b..73b04266 100644 --- a/app/Http/Middleware/MyAuthMiddleware.php +++ b/app/Http/Middleware/MyAuthMiddleware.php @@ -1,8 +1,11 @@ session()->has('loggedin') !== true) { //they’re not logged in, so send them to login form diff --git a/app/Http/Middleware/VerifyMicropubToken.php b/app/Http/Middleware/VerifyMicropubToken.php index 73edd404..aa650560 100644 --- a/app/Http/Middleware/VerifyMicropubToken.php +++ b/app/Http/Middleware/VerifyMicropubToken.php @@ -1,8 +1,11 @@ input('access_token')) { return $next($request); diff --git a/app/Jobs/AddClientToDatabase.php b/app/Jobs/AddClientToDatabase.php index 89e2cae5..b7d9c0f4 100644 --- a/app/Jobs/AddClientToDatabase.php +++ b/app/Jobs/AddClientToDatabase.php @@ -1,5 +1,7 @@ getStatusCode() == '200') { - $filesystem = new \Illuminate\FileSystem\FileSystem(); + $filesystem = new FileSystem(); $filename = storage_path('HTML') . '/' . $this->createFilenameFromURL($this->source); //backup file first $filenameBackup = $filename . '.' . date('Y-m-d') . '.backup'; diff --git a/app/Jobs/ProcessBookmark.php b/app/Jobs/ProcessBookmark.php index 14e4ac4c..491c2b5c 100644 --- a/app/Jobs/ProcessBookmark.php +++ b/app/Jobs/ProcessBookmark.php @@ -1,5 +1,7 @@ isTweet($this->like->url)) { $tweet = Twitter::getOembed(['url' => $this->like->url]); @@ -83,8 +87,16 @@ class ProcessLike implements ShouldQueue } $this->like->save(); + + return 0; } + /** + * Determine if a given URL is that of a Tweet. + * + * @param string $url + * @return bool + */ private function isTweet(string $url): bool { $host = parse_url($url, PHP_URL_HOST); diff --git a/app/Jobs/ProcessMedia.php b/app/Jobs/ProcessMedia.php index 08985383..dcac4a82 100644 --- a/app/Jobs/ProcessMedia.php +++ b/app/Jobs/ProcessMedia.php @@ -1,5 +1,7 @@ microformats = $microformats; } @@ -30,7 +32,7 @@ class SaveProfileImage implements ShouldQueue /** * Execute the job. * - * @return void + * @param \Jonnybarnes\WebmentionsParser\Authorship $authorship */ public function handle(Authorship $authorship) { diff --git a/app/Jobs/SendWebMentions.php b/app/Jobs/SendWebMentions.php index 0635e117..e60946ff 100644 --- a/app/Jobs/SendWebMentions.php +++ b/app/Jobs/SendWebMentions.php @@ -1,5 +1,7 @@ note->in_reply_to); + $inReplyTo = $this->note->in_reply_to ?? ''; + // above so explode doesn’t complain about null being passed in + $urlsInReplyTo = explode(' ', $inReplyTo); $urlsNote = $this->getLinks($this->note->note); $urls = array_filter(array_merge($urlsInReplyTo, $urlsNote)); //filter out none URLs foreach ($urls as $url) { @@ -54,10 +57,10 @@ class SendWebMentions implements ShouldQueue /** * Discover if a URL has a webmention endpoint. * - * @param string The URL - * @return string The webmention endpoint URL + * @param string $url + * @return string|null */ - public function discoverWebmentionEndpoint($url) + public function discoverWebmentionEndpoint(string $url) { //let’s not send webmentions to myself if (parse_url($url, PHP_URL_HOST) == config('app.longurl')) { @@ -97,8 +100,8 @@ class SendWebMentions implements ShouldQueue /** * Get the URLs from a note. * - * @param string $html - * @return array $urls + * @param string $html + * @return array $urls */ public function getLinks($html) { @@ -119,8 +122,8 @@ class SendWebMentions implements ShouldQueue /** * Resolve a URI if necessary. * - * @param string $url - * @param string $base + * @param string $url + * @param string $base The base of the URL * @return string */ public function resolveUri(string $url, string $base): string diff --git a/app/Jobs/SyndicateBookmarkToFacebook.php b/app/Jobs/SyndicateBookmarkToFacebook.php index dc555f8a..973ea249 100644 --- a/app/Jobs/SyndicateBookmarkToFacebook.php +++ b/app/Jobs/SyndicateBookmarkToFacebook.php @@ -1,5 +1,7 @@ [ @@ -52,7 +55,7 @@ class Article extends Model * * @return string */ - public function getHtmlAttribute() + public function getHtmlAttribute(): string { $markdown = new CommonMarkConverter(); $html = $markdown->convertToHtml($this->main); @@ -70,7 +73,7 @@ class Article extends Model * * @return string */ - public function getW3cTimeAttribute() + public function getW3cTimeAttribute(): string { return $this->updated_at->toW3CString(); } @@ -80,7 +83,7 @@ class Article extends Model * * @return string */ - public function getTooltipTimeAttribute() + public function getTooltipTimeAttribute(): string { return $this->updated_at->toRFC850String(); } @@ -90,7 +93,7 @@ class Article extends Model * * @return string */ - public function getHumanTimeAttribute() + public function getHumanTimeAttribute(): string { return $this->updated_at->diffForHumans(); } @@ -100,7 +103,7 @@ class Article extends Model * * @return string */ - public function getPubdateAttribute() + public function getPubdateAttribute(): string { return $this->updated_at->toRSSString(); } @@ -110,7 +113,7 @@ class Article extends Model * * @return string */ - public function getLinkAttribute() + public function getLinkAttribute(): string { return '/blog/' . $this->updated_at->year . '/' . $this->updated_at->format('m') . '/' . $this->titleurl; } @@ -120,7 +123,7 @@ class Article extends Model * * @return \Illuminate\Database\Eloquent\Builder */ - public function scopeDate($query, int $year = null, int $month = null) + public function scopeDate($query, int $year = null, int $month = null): Builder { if ($year == null) { return $query; diff --git a/app/Models/Bookmark.php b/app/Models/Bookmark.php index 9b9ab747..e633098b 100644 --- a/app/Models/Bookmark.php +++ b/app/Models/Bookmark.php @@ -1,5 +1,7 @@ id; } diff --git a/app/Models/Contact.php b/app/Models/Contact.php index b77decc7..5cf4bb82 100644 --- a/app/Models/Contact.php +++ b/app/Models/Contact.php @@ -1,5 +1,7 @@ attributes['url'] = normalize_url($value); } - public function setAuthorUrlAttribute($value) + /** + * Normalize the URL of the author of the like. + * + * @param string $value The author’s url + */ + public function setAuthorUrlAttribute(?string $value) { $this->attributes['author_url'] = normalize_url($value); } - public function getContentAttribute($value) + /** + * If the content contains HTML, filter it. + * + * @param string $value The content of the like + * @return string|null + */ + public function getContentAttribute(?string $value): ?string { if ($value === null) { return null; @@ -38,7 +56,13 @@ class Like extends Model return $value; } - public function filterHTML($html) + /** + * Filter some HTML with HTMLPurifier. + * + * @param string $html + * @return string + */ + private function filterHTML(string $html): string { $config = HTMLPurifier_Config::createDefault(); $config->set('Cache.SerializerPath', storage_path() . '/HTMLPurifier'); diff --git a/app/Models/Media.php b/app/Models/Media.php index 232d3132..4d25c74f 100644 --- a/app/Models/Media.php +++ b/app/Models/Media.php @@ -1,8 +1,11 @@ belongsTo('App\Models\Note'); } @@ -33,7 +38,7 @@ class Media extends Model * * @return string */ - public function getUrlAttribute() + public function getUrlAttribute(): string { if (starts_with($this->path, 'https://')) { return $this->path; @@ -47,7 +52,7 @@ class Media extends Model * * @return string */ - public function getMediumurlAttribute() + public function getMediumurlAttribute(): string { $basename = $this->getBasename($this->path); $extension = $this->getExtension($this->path); @@ -60,7 +65,7 @@ class Media extends Model * * @return string */ - public function getSmallurlAttribute() + public function getSmallurlAttribute(): string { $basename = $this->getBasename($this->path); $extension = $this->getExtension($this->path); @@ -68,7 +73,13 @@ class Media extends Model return config('filesystems.disks.s3.url') . '/' . $basename . '-small.' . $extension; } - public function getBasename($path) + /** + * Give the real part of a filename, i.e. strip the file extension. + * + * @param string $path + * @return string + */ + public function getBasename(string $path): string { // the following achieves this data flow // foo.bar.png => ['foo', 'bar', 'png'] => ['foo', 'bar'] => foo.bar @@ -81,7 +92,13 @@ class Media extends Model return $basename; } - public function getExtension($path) + /** + * Get the extension from a given filename. + * + * @param string $path + * @return string + */ + public function getExtension(string $path): string { $parts = explode('.', $path); diff --git a/app/Models/MicropubClient.php b/app/Models/MicropubClient.php index d769b193..5d2b45e0 100644 --- a/app/Models/MicropubClient.php +++ b/app/Models/MicropubClient.php @@ -1,8 +1,11 @@ hasMany('App\Models\Note', 'client_id', 'client_url'); } diff --git a/app/Models/Note.php b/app/Models/Note.php index 0acb627a..73f504a7 100644 --- a/app/Models/Note.php +++ b/app/Models/Note.php @@ -1,5 +1,7 @@ $this->note, @@ -127,30 +138,36 @@ class Note extends Model /** * Normalize the note to Unicode FORM C. * - * @param string $value - * @return string + * @param string|null $value */ - public function setNoteAttribute($value) + public function setNoteAttribute(?string $value) { - $normalized = normalizer_normalize($value, Normalizer::FORM_C); - if ($normalized === '') { //we don’t want to save empty strings to the db - $normalized = null; + if ($value !== null) { + $normalized = normalizer_normalize($value, Normalizer::FORM_C); + if ($normalized === '') { //we don’t want to save empty strings to the db + $normalized = null; + } + $this->attributes['note'] = $normalized; } - $this->attributes['note'] = $normalized; } /** * Pre-process notes for web-view. * - * @param string - * @return string + * @param string|null $value + * @return string|null */ - public function getNoteAttribute($value) + public function getNoteAttribute(?string $value): ?string { if ($value === null && $this->place !== null) { $value = '📍: ' . $this->place->name . ''; } + // if $value is still null, just return null + if ($value === null) { + return null; + } + $hcards = $this->makeHCards($value); $hashtags = $this->autoLinkHashtag($hcards); $html = $this->convertMarkdown($hashtags); @@ -164,11 +181,10 @@ class Note extends Model * * @return string */ - public function getNb60idAttribute() + public function getNb60idAttribute(): string { - $numbers = new Numbers(); - - return $numbers->numto60($this->id); + // we cast to string because sometimes the nb60id is an “int” + return (string) resolve(Numbers::class)->numto60($this->id); } /** @@ -176,7 +192,7 @@ class Note extends Model * * @return string */ - public function getLongurlAttribute() + public function getLongurlAttribute(): string { return config('app.url') . '/notes/' . $this->nb60id; } @@ -186,7 +202,7 @@ class Note extends Model * * @return string */ - public function getShorturlAttribute() + public function getShorturlAttribute(): string { return config('app.shorturl') . '/notes/' . $this->nb60id; } @@ -196,7 +212,7 @@ class Note extends Model * * @return string */ - public function getIso8601Attribute() + public function getIso8601Attribute(): string { return $this->updated_at->toISO8601String(); } @@ -206,7 +222,7 @@ class Note extends Model * * @return string */ - public function getHumandiffAttribute() + public function getHumandiffAttribute(): string { return $this->updated_at->diffForHumans(); } @@ -216,7 +232,7 @@ class Note extends Model * * @return string */ - public function getPubdateAttribute() + public function getPubdateAttribute(): string { return $this->updated_at->toRSSString(); } @@ -224,9 +240,9 @@ class Note extends Model /** * Get the latitude value. * - * @return string|null + * @return float|null */ - public function getLatitudeAttribute() + public function getLatitudeAttribute(): ?float { if ($this->place !== null) { return $this->place->location->getLat(); @@ -235,16 +251,18 @@ class Note extends Model $pieces = explode(':', $this->location); $latlng = explode(',', $pieces[0]); - return trim($latlng[0]); + return (float) trim($latlng[0]); } + + return null; } /** * Get the longitude value. * - * @return string|null + * @return float|null */ - public function getLongitudeAttribute() + public function getLongitudeAttribute(): ?float { if ($this->place !== null) { return $this->place->location->getLng(); @@ -253,8 +271,10 @@ class Note extends Model $pieces = explode(':', $this->location); $latlng = explode(',', $pieces[0]); - return trim($latlng[1]); + return (float) trim($latlng[1]); } + + return null; } /** @@ -263,7 +283,7 @@ class Note extends Model * * @return string|null */ - public function getAddressAttribute() + public function getAddressAttribute(): ?string { if ($this->place !== null) { return $this->place->name; @@ -271,12 +291,19 @@ class Note extends Model if ($this->location !== null) { return $this->reverseGeoCode((float) $this->latitude, (float) $this->longitude); } + + return null; } - public function getTwitterAttribute() + /** + * Get the OEmbed html for a tweet the note is a reply to. + * + * @return object|null + */ + public function getTwitterAttribute(): ?object { if ($this->in_reply_to == null || mb_substr($this->in_reply_to, 0, 20, 'UTF-8') !== 'https://twitter.com/') { - return; + return null; } $tweetId = basename($this->in_reply_to); @@ -292,7 +319,7 @@ class Note extends Model 'maxwidth' => 512, ]); } catch (\Exception $e) { - return; + return null; } Cache::put($tweetId, $oEmbed, ($oEmbed->cache_age / 60)); @@ -301,20 +328,24 @@ class Note extends Model /** * Show a specific form of the note for twitter. + * + * That is we swap the contacts names for their known Twitter handles. + * + * @return string|null */ - public function getTwitterContentAttribute() + public function getTwitterContentAttribute(): ?string { if ($this->contacts === null) { - return; + return null; } if (count($this->contacts) === 0) { - return; + return null; } if (count(array_unique(array_values($this->contacts))) === 1 && array_unique(array_values($this->contacts))[0] === null) { - return; + return null; } // swap in twitter usernames @@ -338,15 +369,22 @@ class Note extends Model return $this->convertMarkdown($swapped); } - public function getFacebookContentAttribute() + /** + * Show a specific form of the note for facebook. + * + * That is we swap the contacts names for their known Facebook usernames. + * + * @return string|null + */ + public function getFacebookContentAttribute(): ?string { if (count($this->contacts) === 0) { - return; + return null; } if (count(array_unique(array_values($this->contacts))) === 1 && array_unique(array_values($this->contacts))[0] === null) { - return; + return null; } // swap in facebook usernames @@ -374,27 +412,27 @@ class Note extends Model /** * Scope a query to select a note via a NewBase60 id. * - * @param \Illuminate\Database\Eloquent\Builder $query - * @param string $nb60id + * @param \Illuminate\Database\Eloquent\Builder $query + * @param string $nb60id * @return \Illuminate\Database\Eloquent\Builder */ - public function scopeNb60($query, $nb60id) + public function scopeNb60(Builder $query, string $nb60id): Builder { - $numbers = new Numbers(); - - return $query->where('id', $numbers->b60tonum($nb60id)); + return $query->where('id', resolve(Numbers::class)->b60tonum($nb60id)); } /** + * Swap contact’s nicks for a full mf2 h-card. + * * Take note that this method does two things, given @username (NOT [@username](URL)!) * we try to create a fancy hcard from our contact info. If this is not possible * due to lack of contact info, we assume @username is a twitter handle and link it * as such. * - * @param string The note’s text + * @param string $text * @return string */ - private function makeHCards($text) + private function makeHCards(string $text): string { $this->getContacts(); @@ -424,6 +462,9 @@ class Note extends Model return $hcards; } + /** + * Get the value of the `contacts` property. + */ public function getContacts() { if ($this->contacts === null) { @@ -431,6 +472,9 @@ class Note extends Model } } + /** + * Process the note and save the contacts to the `contacts` property. + */ public function setContacts() { $contacts = []; @@ -446,14 +490,16 @@ class Note extends Model } /** + * Turn text hashtags to full HTML links. + * * Given a string and section, finds all hashtags matching * `#[\-_a-zA-Z0-9]+` and wraps them in an `a` element with * `rel=tag` set and a `href` of 'section/tagged/' + tagname without the #. * - * @param string The note + * @param string $note * @return string */ - public function autoLinkHashtag($text) + public function autoLinkHashtag(string $note): string { return preg_replace_callback( '/#([^\s]*)\b/', @@ -462,25 +508,31 @@ class Note extends Model . Tag::normalize($matches[1]) . '">#' . $matches[1] . ''; }, - $text + $note ); } - private function convertMarkdown($text) + /** + * Pass a note through the commonmark library. + * + * @param string $note + * @return string + */ + private function convertMarkdown(string $note): string { $environment = Environment::createCommonMarkEnvironment(); $environment->addExtension(new LinkifyExtension()); $converter = new Converter(new DocParser($environment), new HtmlRenderer($environment)); - return $converter->convertToHtml($text); + return $converter->convertToHtml($note); } /** * Do a reverse geocode lookup of a `lat,lng` value. * - * @param float The latitude - * @param float The longitude - * @return string The location HTML + * @param float $latitude + * @param float $longitude + * @return string */ public function reverseGeoCode(float $latitude, float $longitude): string { @@ -498,7 +550,7 @@ class Note extends Model ], 'headers' => ['User-Agent' => 'jonnybarnes.uk via Guzzle, email jonny@jonnybarnes.uk'], ]); - $json = json_decode($response->getBody()); + $json = json_decode((string) $response->getBody()); if (isset($json->address->town)) { $address = '' . $json->address->town diff --git a/app/Models/Place.php b/app/Models/Place.php index 1f09faea..05a75f2e 100644 --- a/app/Models/Place.php +++ b/app/Models/Place.php @@ -1,5 +1,7 @@ [ @@ -49,7 +51,7 @@ class Place extends Model /** * Define the relationship with Notes. * - * @var array + * @return \Illuminate\Database\Eloquent\Relations\HasMany */ public function notes() { @@ -59,12 +61,12 @@ class Place extends Model /** * Select places near a given location. * - * @param \Illuminate\Database\Eloquent\Builder $query - * @param Point $point - * @param int Distance + * @param \Illuminate\Database\Eloquent\Builder $query + * @param \Phaza\LaravelPostgis\Geometries\Point $point + * @param int $distance * @return \Illuminate\Database\Eloquent\Builder */ - public function scopeNear(Builder $query, Point $point, $distance = 1000) + public function scopeNear(Builder $query, Point $point, $distance = 1000): Builder { $field = DB::raw( sprintf( @@ -77,7 +79,14 @@ class Place extends Model return $query->where($field, '<=', $distance)->orderBy($field); } - public function scopeWhereExternalURL(Builder $query, string $url) + /** + * Select places based on a URL. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * @param string $url + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeWhereExternalURL(Builder $query, string $url): Builder { return $query->where('external_urls', '@>', json_encode([ $this->getType($url) => $url, @@ -87,21 +96,21 @@ class Place extends Model /** * Get the latitude from the `location` property. * - * @return string latitude + * @return float */ - public function getLatitudeAttribute() + public function getLatitudeAttribute(): float { - return explode(' ', $this->location)[1]; + return $this->location->getLat(); } /** * Get the longitude from the `location` property. * - * @return string longitude + * @return float */ - public function getLongitudeAttribute() + public function getLongitudeAttribute(): float { - return explode(' ', $this->location)[0]; + return $this->location->getLng(); } /** @@ -109,7 +118,7 @@ class Place extends Model * * @return string */ - public function getLongurlAttribute() + public function getLongurlAttribute(): string { return config('app.url') . '/places/' . $this->slug; } @@ -119,7 +128,7 @@ class Place extends Model * * @return string */ - public function getShorturlAttribute() + public function getShorturlAttribute(): string { return config('app.shorturl') . '/places/' . $this->slug; } @@ -129,12 +138,17 @@ class Place extends Model * * @return string */ - public function getUriAttribute() + public function getUriAttribute(): string { return $this->longurl; } - public function setExternalUrlsAttribute($url) + /** + * Dealing with a jsonb column, so we check input first. + * + * @param string|null $url + */ + public function setExternalUrlsAttribute(?string $url) { if ($url === null) { return; @@ -148,7 +162,13 @@ class Place extends Model $this->attributes['external_urls'] = json_encode($already); } - private function getType(string $url): ?string + /** + * Given a URL, see if it is one of our known types. + * + * @param string $url + * @return string + */ + private function getType(string $url): string { $host = parse_url($url, PHP_URL_HOST); if (ends_with($host, 'foursquare.com') === true) { diff --git a/app/Models/Tag.php b/app/Models/Tag.php index 89e08ee5..5007ad5c 100644 --- a/app/Models/Tag.php +++ b/app/Models/Tag.php @@ -1,5 +1,7 @@ attributes['tag'] = $this->normalize($value); } @@ -45,9 +49,10 @@ class Tag extends Model * This method actually normalizes a tag. That means lowercase-ing and * removing fancy diatric characters. * - * @param string + * @param string $tag + * @return string */ - public static function normalize($tag) + public static function normalize(string $tag): string { return mb_strtolower( preg_replace( diff --git a/app/Models/User.php b/app/Models/User.php index 6bd0f157..7fc687c7 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -1,5 +1,7 @@ findAuthor(json_decode($this->mf2, true)); @@ -57,11 +59,12 @@ class WebMention extends Model /** * Get the published value for the webmention. * - * @return string + * @return string|null */ - public function getPublishedAttribute() + public function getPublishedAttribute(): ?string { - $microformats = json_decode($this->mf2, true); + $mf2 = $this->mf2 ?? ''; + $microformats = json_decode($mf2, true); if (isset($microformats['items'][0]['properties']['published'][0])) { try { $published = carbon()->parse( @@ -82,12 +85,17 @@ class WebMention extends Model * * @return string|null */ - public function getReplyAttribute() + public function getReplyAttribute(): ?string { + if ($this->mf2 === null) { + return null; + } $microformats = json_decode($this->mf2, true); if (isset($microformats['items'][0]['properties']['content'][0]['html'])) { return $this->filterHTML($microformats['items'][0]['properties']['content'][0]['html']); } + + return null; } /** @@ -126,10 +134,10 @@ class WebMention extends Model /** * Filter the HTML in a reply webmention. * - * @param string The reply HTML - * @return string The filtered HTML + * @param string $html + * @return string */ - private function filterHTML($html) + private function filterHTML(string $html): string { $config = HTMLPurifier_Config::createDefault(); $config->set('Cache.SerializerPath', storage_path() . '/HTMLPurifier'); diff --git a/app/Observers/NoteObserver.php b/app/Observers/NoteObserver.php index bf618edb..d74d9e47 100644 --- a/app/Observers/NoteObserver.php +++ b/app/Observers/NoteObserver.php @@ -1,8 +1,11 @@ getTagsFromNote($note->getAttributes()['note'] ?? null); + $text = array_get($note->getAttributes(), 'note'); + if ($text === null) { + return; + } + $tags = $this->getTagsFromNote($text); if (count($tags) === 0) { return; @@ -31,11 +37,15 @@ class NoteObserver * Listen to the Note updated event. * * @param \App\Note $Note - * @return void */ public function updated(Note $note) { - $tags = $this->getTagsFromNote($note->getAttributes()['note']); + $text = array_get($note->getAttributes(), 'note'); + if ($text === null) { + return; + } + + $tags = $this->getTagsFromNote($text); if (count($tags) === 0) { return; } @@ -53,14 +63,19 @@ class NoteObserver * Listen to the Note deleting event. * * @param \App\Note $note - * @return void */ public function deleting(Note $note) { $note->tags()->detach(); } - public function getTagsFromNote($note) + /** + * Retrieve the tags from a note’s text, tag for form #tag. + * + * @param string $note + * @return \Illuminate\Support\Collection + */ + private function getTagsFromNote(string $note): Collection { preg_match_all('/#([^\s<>]+)\b/', $note, $tags); diff --git a/app/Services/ActivityStreamsService.php b/app/Services/ActivityStreamsService.php index 04923d62..d7d9f660 100644 --- a/app/Services/ActivityStreamsService.php +++ b/app/Services/ActivityStreamsService.php @@ -1,11 +1,18 @@ header('Content-Type', 'application/activity+json'); } + /** + * Return the relevant data to an AS2.0 request for a particular note. + * + * @param \App\Models\Note $note + * @return \Illuminate\Http\Response + */ public function singleNoteResponse(Note $note) { $data = json_encode([ diff --git a/app/Services/BookmarkService.php b/app/Services/BookmarkService.php index b1dcaf50..f05d6a1e 100644 --- a/app/Services/BookmarkService.php +++ b/app/Services/BookmarkService.php @@ -20,7 +20,7 @@ class BookmarkService /** * Create a new Bookmark. * - * @param array $request + * @param array $request Data from request()->all() * @return Bookmark $bookmark */ public function createBookmark(array $request): Bookmark @@ -84,6 +84,12 @@ class BookmarkService return $bookmark; } + /** + * Given a URL, use browsershot to save an image of the page. + * + * @param string $url + * @return string The uuid for the screenshot + */ public function saveScreenshot(string $url): string { $browsershot = new Browsershot(); @@ -99,6 +105,12 @@ class BookmarkService return $uuid->toString(); } + /** + * Given a URL, attempt to save it to the Internet Archive. + * + * @param string $url + * @return string + */ public function getArchiveLink(string $url): string { $client = resolve(Client::class); diff --git a/app/Services/Micropub/HCardService.php b/app/Services/Micropub/HCardService.php index 62907379..f3d1ff3c 100644 --- a/app/Services/Micropub/HCardService.php +++ b/app/Services/Micropub/HCardService.php @@ -1,12 +1,20 @@ all() + * @return string + */ + public function process(array $request): string { $data = []; if (array_get($request, 'properties.name')) { diff --git a/app/Services/Micropub/HEntryService.php b/app/Services/Micropub/HEntryService.php index fe44c04a..edb054ab 100644 --- a/app/Services/Micropub/HEntryService.php +++ b/app/Services/Micropub/HEntryService.php @@ -1,12 +1,21 @@ all() + * @param string|null $client The micropub client that made the request + * @return string|null + */ + public function process(array $request, ?string $client = null): ?string { if (array_get($request, 'properties.like-of') || array_get($request, 'like-of')) { $like = resolve(LikeService::class)->createLike($request); diff --git a/app/Services/Micropub/UpdateService.php b/app/Services/Micropub/UpdateService.php index 45756584..b4f81085 100644 --- a/app/Services/Micropub/UpdateService.php +++ b/app/Services/Micropub/UpdateService.php @@ -1,5 +1,7 @@ all() + * @return \Illuminate\Http\JsonResponse + */ public function process(array $request) { $urlPath = parse_url(array_get($request, 'url'), PHP_URL_PATH); diff --git a/app/Services/NoteService.php b/app/Services/NoteService.php index 2680ec29..b29f5d3c 100644 --- a/app/Services/NoteService.php +++ b/app/Services/NoteService.php @@ -12,11 +12,11 @@ class NoteService /** * Create a new note. * - * @param array $request - * @param string $client - * @return \App\Note $note + * @param array $request Data from request()->all() + * @param string $client + * @return \App\Note */ - public function createNote(array $request, string $client = null): Note + public function createNote(array $request, ?string $client = null): Note { $note = Note::create( [ @@ -60,6 +60,12 @@ class NoteService return $note; } + /** + * Get the content from the request to create a new note. + * + * @param array $request Data from request()->all() + * @return string|null + */ private function getContent(array $request): ?string { if (array_get($request, 'properties.content.0.html')) { @@ -72,6 +78,12 @@ class NoteService return array_get($request, 'content'); } + /** + * Get the in-reply-to from the request to create a new note. + * + * @param array $request Data from request()->all() + * @return string|null + */ private function getInReplyTo(array $request): ?string { if (array_get($request, 'properties.in-reply-to.0')) { @@ -81,6 +93,12 @@ class NoteService return array_get($request, 'in-reply-to'); } + /** + * Get the published time from the request to create a new note. + * + * @param array $request Data from request()->all() + * @return string|null + */ private function getPublished(array $request): ?string { if (array_get($request, 'properties.published.0')) { @@ -94,6 +112,12 @@ class NoteService return null; } + /** + * Get the location data from the request to create a new note. + * + * @param array $request Data from request()->all() + * @return string|null + */ private function getLocation(array $request): ?string { $location = array_get($request, 'properties.location.0') ?? array_get($request, 'location'); @@ -110,6 +134,12 @@ class NoteService return null; } + /** + * Get the checkin data from the request to create a new note. This will be a Place. + * + * @param array $request Data from request()->all() + * @return \App\Models\Place|null + */ private function getCheckin(array $request): ?Place { if (array_get($request, 'properties.location.0.type.0') === 'h-card') { @@ -149,6 +179,12 @@ class NoteService return null; } + /** + * Get the Swarm URL from the syndication data in the request to create a new note. + * + * @param array $request Data from request()->all() + * @return string|null + */ private function getSwarmUrl(array $request): ?string { if (stristr(array_get($request, 'properties.syndication.0', ''), 'swarmapp')) { @@ -158,6 +194,12 @@ class NoteService return null; } + /** + * Get the syndication targets from the request to create a new note. + * + * @param array $request Data from request()->all() + * @return array + */ private function getSyndicationTargets(array $request): array { $syndication = []; @@ -187,6 +229,12 @@ class NoteService return $syndication; } + /** + * Get the media URLs from the request to create a new note. + * + * @param array $request Data from request()->all() + * @return array + */ private function getMedia(array $request): array { $media = []; @@ -211,6 +259,12 @@ class NoteService return $media; } + /** + * Get the Instagram photo URL from the request to create a new note. + * + * @param array $request Data from request()->all() + * @return string|null + */ private function getInstagramUrl(array $request): ?string { if (starts_with(array_get($request, 'properties.syndication.0'), 'https://www.instagram.com')) { diff --git a/changelog.md b/changelog.md index 755e3eb0..87be660a 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,8 @@ # Changelog +## Version {next} + - Improve code-base by liberal use of `strict_types` + ## Version 0.15.3 (2018-01-12) - Improve `likes`, including adding a new section in the admin cp - Add the ability to POSSE the like of a Tweet diff --git a/tests/Feature/MicropubControllerTest.php b/tests/Feature/MicropubControllerTest.php index 81a86591..20db8222 100644 --- a/tests/Feature/MicropubControllerTest.php +++ b/tests/Feature/MicropubControllerTest.php @@ -887,7 +887,7 @@ class MicropubControllerTest extends TestCase 'h' => 'entry', 'content' => $note, 'published' => Carbon::now()->toW3CString(), - 'access_token' => $this->getToken(), + 'access_token' => (string) $this->getToken(), ] ); $response->assertJson(['response' => 'created']); diff --git a/tests/Feature/SwarmTest.php b/tests/Feature/SwarmTest.php index ff86eaaa..7e8f133b 100644 --- a/tests/Feature/SwarmTest.php +++ b/tests/Feature/SwarmTest.php @@ -146,7 +146,6 @@ class SwarmTest extends TestCase $response ->assertStatus(201) ->assertJson(['response' => 'created']); - //dump($response->__get('headers')->get('location')); $this->assertDatabaseHas('places', [ 'external_urls' => '{"foursquare": "https://foursquare.com/v/654321"}' ]); diff --git a/tests/Feature/TokenServiceTest.php b/tests/Feature/TokenServiceTest.php index c9c33078..58b4cc3d 100644 --- a/tests/Feature/TokenServiceTest.php +++ b/tests/Feature/TokenServiceTest.php @@ -55,6 +55,5 @@ class TokenServiceTest extends TestCase $service = new TokenService(); $token = $service->validateToken($token); - dump($token); } }