jonnybarnes.uk/app/Http/Controllers/NotesController.php
Jonny Barnes 0b7bf7a378 Updating codebase to use es6/7
Squashed commit of the following:

commit 07b27d00f135a521143154a2e77abdc1680b7d5b
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Thu Jan 26 14:59:35 2017 +0000

    Fix styleci.io issue

commit 9e67f0a96484f8047f22d13abb4cd41c2e44b95d
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Thu Jan 26 08:28:22 2017 +0000

    Remove some unused dependencies

commit 3c65070f3ff2aec10d821ae9f12821bc08e37d0a
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Wed Jan 25 18:00:10 2017 +0000

    Compressed webpack/babel output

commit 694c43d1a9a6c8cb84d4cc789a6643b8d2863cec
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Wed Jan 25 17:59:27 2017 +0000

    Let’s compress the es5 output

commit debffc0e41760fcc87e6d3768163e6ed8ea5d98c
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Wed Jan 25 17:45:05 2017 +0000

    webpack/babel generated es5 assets

commit 1e978d6c5795f230ab320f94ad2fb98871bb6fa5
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Wed Jan 25 17:36:52 2017 +0000

    Allow content of micropub form page to be persisted

commit 44fb8026962ef574700f07ef93d18bdb38cdedb2
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Wed Jan 25 17:35:58 2017 +0000

    Name the micropub form

commit 732abaf561bf9d6392fe506d30d320e9c17b8226
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Wed Jan 25 17:34:39 2017 +0000

    Add webStorage dependency

commit a4520085dfc673c5c3d940150358b8ecc3cdf022
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Mon Jan 16 12:32:33 2017 +0000

    No need for a form id on the micropub form untill form autosave is added

commit a182be46a616d8e4085be5e24cbd3623f13cc28d
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Sat Jan 14 20:37:31 2017 +0000

    Polyfill fetch and promise only in older browsers using unpkg.com

commit fdc044150dc8e2b755f93119b196ba0455bbbb83
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Fri Jan 13 15:46:05 2017 +0000

    Generated js from webpack/babel

commit d24e6aa9fff38823a0c667e6f9e43dcb2ca179c4
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Fri Jan 13 15:45:32 2017 +0000

    Lots of es6 to generate and add map, particularly the new note form

commit e7004a9fe475e07d43de905fb00d51c659878474
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Fri Jan 13 15:44:54 2017 +0000

    Don’t link to commons.js, it aint being made at the moment

commit d4a2e4e143b644287f9da109eb2850c2361b2f20
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Fri Jan 13 15:43:27 2017 +0000

    Temporarily don’t optimize JS

commit 05623de122da7d88642af60f85e5320a3ff651fc
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Wed Jan 11 14:24:15 2017 +0000

    Add places to geojson data

commit 3eb1a4f29bb4263b9998a6f3f53abb7d1eeff520
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Wed Jan 11 14:22:53 2017 +0000

    Use alertify.js to give relevant feedback to user

commit 6f123fa178d6cd19528130ebd78157c37eaab1a1
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Wed Jan 11 14:21:24 2017 +0000

    Add alertify.css back

commit 89fca3b3aeb23ef97fb767514e0502298d1b83fd
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Wed Jan 11 14:19:56 2017 +0000

    Webpack’d javascript

commit 94ab60f34079238ed6228bf6e789f14d7a09823b
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Mon Jan 9 09:10:17 2017 +0000

    Webpack’d javascript

commit 1ca3a55a27c20ea08633b589023fe5ad1acb2b68
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Mon Jan 9 09:09:06 2017 +0000

    Define const functions in order of usage

commit dc5535b32a357611860e0e98fcdc7d9c12c5d383
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Sun Jan 8 18:50:55 2017 +0000

    Link to correct js files with defer option

commit 42f0e5b85825943ed148736e8e0fe22f5654ae90
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Sun Jan 8 18:50:18 2017 +0000

    New webpacked es6 code

commit 300443bb0ce7b65bda1cf550fe5c7173a89edaf3
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Sun Jan 8 18:49:44 2017 +0000

    Moving towards consolidated es6 map code

commit b1001760e03dd358f896feb90dd3acc0bc6728fc
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Sun Jan 8 18:44:40 2017 +0000

    Don’t mangle the fetch function

commit 289e59025634b6d2569b73ae87e3ea4942034e33
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Sun Jan 8 18:43:47 2017 +0000

    Updated yarn/npm dependencies

commit 3439b008e6bd96d8c45591c2a945c4ac246440ec
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Thu Dec 29 11:58:50 2016 +0000

    Link to the correct assets on the new note page

commit 81dc83e362266028f8336ae5a27e92c8c8a2b6dc
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Thu Dec 29 11:57:46 2016 +0000

    Add a map to the new note page

commit 5101ecd3dd60cd78e9a4bce81a5e60a2f575bc57
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Thu Dec 29 11:56:54 2016 +0000

    Bundle common JS between entry points

commit 1f916adcfd1b07df388417b6bd800e109cec543c
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Thu Dec 29 11:55:31 2016 +0000

    Add geojson to individual notes

commit 7a6ae8ca49b4ca49413ddb977f7b534f62b41c20
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Wed Dec 28 19:53:30 2016 +0000

    Link to self-hosted mapbox-gl.css

commit 8be006ec2b738cbcebd06283e18c292b3efd7d16
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Wed Dec 28 19:52:41 2016 +0000

    Use self-hosted mapbox-gl css, and a better default geojson title value

commit 5ec480842a2194a071b6a23ae181a8de5b8d47cd
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Wed Dec 28 17:09:46 2016 +0000

    Access geojson data to markup map correctly

commit f2f1d7563f7b0cb7cc62658cc2817e56d2b47c31
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Wed Dec 28 17:09:07 2016 +0000

    Generate geojson data for places

commit 9f8c9ba02f7ac37b4ab81aad2fb0cd2c077c45cd
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Fri Dec 23 11:55:10 2016 +0000

    Use geojson to add a default you location point

commit 3da499d3ea6a214f8008d1b98f9b0c2f31ecba0c
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Thu Dec 22 22:29:18 2016 +0000

    Some code cleaning

commit 39376097eda82491df272cc214d70ff3095d4873
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Thu Dec 22 22:21:29 2016 +0000

    Use satellite streets view

commit f3db8f43fc403bc180e24d63e21c8311441cb2b0
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Thu Dec 22 16:46:03 2016 +0000

    Semi working map state, still need to add own css, and add marker

commit 5f398a642b9db67f4b0733988c20138b37d2141d
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Thu Dec 22 13:17:04 2016 +0000

    Reference new maps.js with bundled mapbox

commit bad97649a623c5552e6b607a1975aa2de8131191
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Thu Dec 22 13:16:25 2016 +0000

    Add mapbox-gl again

commit 47484962e7620aa7a9a5153cfc03e2ba4030dd5c
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Wed Dec 21 00:03:23 2016 +0000

    Early working version of maps.js

commit e53e0f39952a65996c09b06fd35918ffabed0de2
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Tue Dec 20 17:14:17 2016 +0000

    Setup webpack

commit f930a1e2bd7d18809bd40d0cc22f9c3af75f1984
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Tue Dec 20 15:00:42 2016 +0000

    Add webpack v2

commit b16e8d62db071155a8b5fb216d3d60ebf6fa9468
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Tue Dec 20 14:53:47 2016 +0000

    Define default settings for babel

commit 97c13cb753e08d25aa48ecff579efa05173a2c81
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Tue Dec 20 14:53:31 2016 +0000

    Add babeljs

commit dd9efc3b056cf96323d7f11acff0fb1ab137caef
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Tue Dec 20 14:49:23 2016 +0000

    Remove old javascript

commit ab99c251ad
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Fri Dec 16 13:26:10 2016 +0000

    update readme to reflect changes to how syndication targets need to be set
2017-01-26 15:21:21 +00:00

370 lines
12 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Tag;
use Twitter;
use App\Note;
use HTMLPurifier;
use GuzzleHttp\Client;
use HTMLPurifier_Config;
use Illuminate\Http\Request;
use Jonnybarnes\IndieWeb\Numbers;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Support\Facades\Cache;
use Jonnybarnes\WebmentionsParser\Authorship;
// Need to sort out Twitter and webmentions!
class NotesController extends Controller
{
/**
* Show all the notes.
*
* @param Illuminate\Http\Request request;
* @return \Illuminte\View\Factory view
*/
public function showNotes(Request $request)
{
$notes = Note::orderBy('id', 'desc')->with('webmentions', 'place', 'media')->paginate(10);
foreach ($notes as $note) {
$replies = 0;
foreach ($note->webmentions as $webmention) {
if ($webmention->type == 'in-reply-to') {
$replies++;
}
}
$note->replies = $replies;
$note->twitter = $this->checkTwitterReply($note->in_reply_to);
$note->iso8601_time = $note->updated_at->toISO8601String();
$note->human_time = $note->updated_at->diffForHumans();
if ($note->location && ($note->place === null)) {
$pieces = explode(':', $note->location);
$latlng = explode(',', $pieces[0]);
$note->latitude = trim($latlng[0]);
$note->longitude = trim($latlng[1]);
$note->address = $this->reverseGeoCode((float) trim($latlng[0]), (float) trim($latlng[1]));
}
if ($note->place !== null) {
$lnglat = explode(' ', $note->place->location);
$note->latitude = $lnglat[1];
$note->longitude = $lnglat[0];
$note->address = $note->place->name;
$note->placeLink = '/places/' . $note->place->slug;
$note->geoJson = $this->getGeoJson($note->longitude, $note->latitude, $note->place->name, $note->place->icon);
}
$photoURLs = [];
$photos = $note->getMedia();
foreach ($photos as $photo) {
$photoURLs[] = $photo->getUrl();
}
$note->photoURLs = $photoURLs;
}
$homepage = ($request->path() == '/');
return view('allnotes', ['notes' => $notes, 'homepage' => $homepage]);
}
/**
* Show a single note.
*
* @param string The id of the note
* @return \Illuminate\View\Factory view
*/
public function singleNote($urlId)
{
$numbers = new Numbers();
$authorship = new Authorship();
$realId = $numbers->b60tonum($urlId);
$note = Note::find($realId);
$replies = [];
$reposts = [];
$likes = [];
$carbon = new \Carbon\Carbon();
foreach ($note->webmentions as $webmention) {
/*
reply->url |
reply->photo | Author
reply->name |
reply->source
reply->date
reply->reply
repost->url |
repost->photo | Author
repost->name |
repost->date
repost->source
like->url |
like->photo | Author
like->name |
*/
$microformats = json_decode($webmention->mf2, true);
$authorHCard = $authorship->findAuthor($microformats);
$content['url'] = $authorHCard['properties']['url'][0];
$content['photo'] = $this->createPhotoLink($authorHCard['properties']['photo'][0]);
$content['name'] = $authorHCard['properties']['name'][0];
switch ($webmention->type) {
case 'in-reply-to':
$content['source'] = $webmention->source;
if (isset($microformats['items'][0]['properties']['published'][0])) {
$content['date'] = $carbon->parse(
$microformats['items'][0]['properties']['published'][0]
)->toDayDateTimeString();
} else {
$content['date'] = $webmention->updated_at->toDayDateTimeString();
}
$content['reply'] = $this->filterHTML(
$microformats['items'][0]['properties']['content'][0]['html']
);
$replies[] = $content;
break;
case 'repost-of':
$content['date'] = $carbon->parse(
$microformats['items'][0]['properties']['published'][0]
)->toDayDateTimeString();
$content['source'] = $webmention->source;
$reposts[] = $content;
break;
case 'like-of':
$likes[] = $content;
break;
}
}
$note->twitter = $this->checkTwitterReply($note->in_reply_to);
$note->iso8601_time = $note->updated_at->toISO8601String();
$note->human_time = $note->updated_at->diffForHumans();
if ($note->location && ($note->place === null)) {
$pieces = explode(':', $note->location);
$latlng = explode(',', $pieces[0]);
$note->latitude = trim($latlng[0]);
$note->longitude = trim($latlng[1]);
$note->address = $this->reverseGeoCode((float) trim($latlng[0]), (float) trim($latlng[1]));
}
if ($note->place !== null) {
$lnglat = explode(' ', $note->place->location);
$note->latitude = $lnglat[1];
$note->longitude = $lnglat[0];
$note->address = $note->place->name;
$note->placeLink = '/places/' . $note->place->slug;
$note->geoJson = $this->getGeoJson($note->longitude, $note->latitude, $note->place->name, $note->place->icon);
}
$photoURLs = [];
$photos = $note->getMedia();
foreach ($photos as $photo) {
$photoURLs[] = $photo->getUrl();
}
$note->photoURLs = $photoURLs;
return view('singlenote', [
'note' => $note,
'replies' => $replies,
'reposts' => $reposts,
'likes' => $likes,
]);
}
/**
* Redirect /note/{decID} to /notes/{nb60id}.
*
* @param string The decimal id of he note
* @return \Illuminate\Routing\RedirectResponse redirect
*/
public function singleNoteRedirect($decId)
{
$numbers = new Numbers();
$realId = $numbers->numto60($decId);
$url = config('app.url') . '/notes/' . $realId;
return redirect($url);
}
/**
* Show all notes tagged with {tag}.
*
* @param string The tag
* @return \Illuminate\View\Factory view
*/
public function taggedNotes($tag)
{
$notes = Note::whereHas('tags', function ($query) use ($tag) {
$query->where('tag', $tag);
})->get();
foreach ($notes as $note) {
$note->iso8601_time = $note->updated_at->toISO8601String();
$note->human_time = $note->updated_at->diffForHumans();
}
return view('taggednotes', ['notes' => $notes, 'tag' => $tag]);
}
/**
* Create the photo link.
*
* We shall leave twitter.com and twimg.com links as they are. Then we shall
* check for local copies, if that fails leave the link as is.
*
* @param string
* @return string
*/
public function createPhotoLink($url)
{
$host = parse_url($url, PHP_URL_HOST);
if ($host == 'pbs.twimg.com') {
//make sure we use HTTPS, we know twitter supports it
return str_replace('http://', 'https://', $url);
}
if ($host == 'twitter.com') {
if (Cache::has($url)) {
return Cache::get($url);
}
$username = parse_url($url, PHP_URL_PATH);
try {
$info = Twitter::getUsers(['screen_name' => $username]);
$profile_image = $info->profile_image_url_https;
Cache::put($url, $profile_image, 10080); //1 week
} catch (Exception $e) {
return $url; //not sure here
}
return $profile_image;
}
$filesystem = new Filesystem();
if ($filesystem->exists(public_path() . '/assets/profile-images/' . $host . '/image')) {
return '/assets/profile-images/' . $host . '/image';
}
return $url;
}
/**
* Twitter!!!
*
* @param string The reply to URL
* @return string | null
*/
private function checkTwitterReply($url)
{
if ($url == null) {
return;
}
if (mb_substr($url, 0, 20, 'UTF-8') !== 'https://twitter.com/') {
return;
}
$arr = explode('/', $url);
$tweetId = end($arr);
if (Cache::has($tweetId)) {
return Cache::get($tweetId);
}
try {
$oEmbed = Twitter::getOembed([
'id' => $tweetId,
'align' => 'center',
'omit_script' => true,
'maxwidth' => 550,
]);
} catch (\Exception $e) {
return;
}
Cache::put($tweetId, $oEmbed, ($oEmbed->cache_age / 60));
return $oEmbed;
}
/**
* Filter the HTML in a reply webmention.
*
* @param string The reply HTML
* @return string The filtered HTML
*/
private function filterHTML($html)
{
$config = HTMLPurifier_Config::createDefault();
$config->set('Cache.SerializerPath', storage_path() . '/HTMLPurifier');
$purifier = new HTMLPurifier($config);
return $purifier->purify($html);
}
/**
* Do a reverse geocode lookup of a `lat,lng` value.
*
* @param float The latitude
* @param float The longitude
* @return string The location HTML
*/
public function reverseGeoCode(float $latitude, float $longitude): string
{
$latlng = $latitude . ',' . $longitude;
return Cache::get($latlng, function () use ($latlng, $latitude, $longitude) {
$guzzle = new Client();
$response = $guzzle->request('GET', 'https://nominatim.openstreetmap.org/reverse', [
'query' => [
'format' => 'json',
'lat' => $latitude,
'lon' => $longitude,
'zoom' => 18,
'addressdetails' => 1,
],
'headers' => ['User-Agent' => 'jonnybarnes.uk via Guzzle, email jonny@jonnybarnes.uk'],
]);
$json = json_decode($response->getBody());
if (isset($json->address->town)) {
$address = '<span class="p-locality">'
. $json->address->town
. '</span>, <span class="p-country-name">'
. $json->address->country
. '</span>';
Cache::forever($latlng, $address);
return $address;
}
if (isset($json->address->city)) {
$address = $json->address->city . ', ' . $json->address->country;
Cache::forever($latlng, $address);
return $address;
}
if (isset($json->address->county)) {
$address = '<span class="p-region">'
. $json->address->county
. '</span>, <span class="p-country-name">'
. $json->address->country
. '</span>';
Cache::forever($latlng, $address);
return $address;
}
$adress = '<span class="p-country-name">' . $json->address->country . '</span>';
Cache::forever($latlng, $address);
return $address;
});
}
private function getGeoJson($longitude, $latitude, $title, $icon)
{
$icon = $icon ?? 'marker';
return '{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [' . $longitude . ', ' . $latitude . ']
},
"properties": {
"title": "' . $title . '",
"icon": "' . $icon . '"
}
}';
}
}