commit 19ec350ca9c3a2ec9da6ee3823f3b0a09efe3eaa Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Tue Nov 22 16:07:42 2016 +0000 Update changelog commit 73428d3d94c659e5e4431b6740ba10dc2a609e44 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Tue Nov 22 16:03:37 2016 +0000 output of gulp compress commit 4bb8038e787e35b5d38be9d63600b10bb9d75a07 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Tue Nov 22 16:03:11 2016 +0000 import Guzzle’s ClientException namespace commit 4bcb676bb95274da2422023fefa88b8d246b7f97 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Tue Nov 22 16:02:24 2016 +0000 Update manual testing token commit d902de76f00b4f3bba94ce6528f87e43f6c113f9 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Tue Nov 22 16:01:52 2016 +0000 output of gulp js-assets commit 0a495956e4f540aae0d1515229dd29c30c76fd64 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Tue Nov 22 16:01:27 2016 +0000 Update new note page to use Mapbox GL JS commit bf22004256179c9487c668eb77785a9bc90227bc Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Mon Nov 21 18:47:59 2016 +0000 output of gulp js-assets commit 22ed61cb853d98a4638754d44f042841e2b4495c Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Mon Nov 21 18:47:06 2016 +0000 Attempting to use mapbox gl on the newnote page commit 47fd891f1b3f0da59d10e937f7ed11f3b603c4af Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Sat Nov 19 17:21:53 2016 +0000 gulp derived assets commit 19e83f33b1c8c7a90a74d0ad17a6cace8761bcef Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Sat Nov 19 17:21:16 2016 +0000 Move .map styles into mapbox.scss commit 3d848d59126032671907a1e354cf121441d9a6e3 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Sat Nov 19 17:12:51 2016 +0000 gulp derived assets commit 9e51e8690ac8b782bc56663e7ec682837b27d4a1 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Sat Nov 19 17:12:32 2016 +0000 Link to mapbox-gl files commit 296b5fd7770f2a1c5c26ed4efedd99a7a0ad0bed Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Sat Nov 19 17:12:08 2016 +0000 Use mapbox gl to add maps to notes commit bd031df6e969b7af741730acabe41465f68bd3a1 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Sat Nov 19 17:11:27 2016 +0000 Update sass to style mapbox gl maps commit a7cd5e6eaa9510b5c9de672b6d5ed6917dabd7c6 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Nov 18 16:19:45 2016 +0000 output of gulp compress commit fe63c7ed394d62cd0e47a9ef718d9629d8643e71 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Nov 18 16:18:47 2016 +0000 output of gulp sass commit 15ac4012681635753a4b1f52d81f7f9e24830eb4 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Nov 18 16:18:05 2016 +0000 Add a dividing line between notes and bio on the homepage commit 5ada66b1a01ae57359145eb757cab65769400f1e Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Nov 18 16:12:01 2016 +0000 output of gulp sass commit 86adf97c3831c3310683a25c2671c7560700de1a Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Nov 18 16:11:33 2016 +0000 Resize note metadata for spacial flow commit 3f3fc51ea8df8206d5b13512295ac09827bb2ede Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Nov 18 15:37:21 2016 +0000 output of gulp sass commit df6f7f827641dc4deca621d099357757f760ece4 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Nov 18 15:36:51 2016 +0000 Use system UI fonts commit b71950275ddaf274b26195694a07c1b58f746725 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Nov 18 15:31:30 2016 +0000 output of gulp compress commit 5ff5d73a803b9bcc4e2f314946c1d757dcabae67 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Nov 18 15:30:12 2016 +0000 output of gulp js-assets commit d8ff563569223bddc836ab9f8fc7c43970273b44 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Nov 18 15:29:27 2016 +0000 use containing divs in new place section of form commit 3cbf3083612210cdd7609c930737cf7a698ec024 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Nov 18 14:39:27 2016 +0000 gulp sass output commit 239b742a355a397f5b84377b26b2d7a4254bd50e Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Nov 18 14:38:52 2016 +0000 Better spacing of form elements on mobile commit a20279e3f4216b87ff59ed4e507b6de9e212db9f Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Nov 18 13:41:31 2016 +0000 Derived assets commit 86ebd05472498814084e86fb0c2d674633f00096 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Nov 18 13:40:42 2016 +0000 Use containing divs for flex layout commit 00e0e6f3f462ca575e92209a86ada67b7f5ff757 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Thu Nov 17 14:38:39 2016 +0000 Correct scss according to stylelint commit 6dd8ff4d13c3ab83c6a811501b817c45b89338ce Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Thu Nov 17 14:33:46 2016 +0000 Get stylelint working commit 9b9a64defd9335014b46070e2b92a392929f4aa5 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Thu Nov 17 09:48:28 2016 +0000 Add missing new-line to match style commit 2521446f32420047d6d5f7372f4f7afc17200a1c Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Tue Nov 15 13:16:45 2016 +0000 Add logging during an error, improve the error message commit 095507bec225992aac510a2ca852f65c197f0298 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Tue Nov 15 13:15:59 2016 +0000 Update test token commit 374ef70fecaedf041f12a57688ed9596e25a2ce6 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Tue Nov 15 13:15:16 2016 +0000 Remove typekit for now commit f5671ad435732ddb3288a2e02de7631a6acb4183 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Nov 11 16:06:01 2016 +0000 Better designed new note form commit f38df507b85502e733fa38e970cd584f7d79bca1 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Nov 11 13:28:21 2016 +0000 More styling, use normal pagination, improve bio commit 077076d4f92014d488bca5d4dbbab5af913e6cf0 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Fri Nov 11 00:05:56 2016 +0000 Use an anchor for permalinks, re-word projects page commit 37c6e862b693c2bfd3a39654a533627e0f73fd1a Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Thu Nov 10 23:58:54 2016 +0000 The resulting CSS files commit 1a3b6d7064b1b67238ffd3909d6d1ae54a4f78e1 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Thu Nov 10 23:31:53 2016 +0000 Sass for very basic redesign commit e5d9e9d41b50d7f316fcae9bae75863aa09a7d63 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Thu Nov 10 23:00:35 2016 +0000 Use app.(s)css commit 231c5292e68220f588e9d300975bb19dfea20b4f Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Thu Nov 10 22:59:50 2016 +0000 Restructure homepage to show notes, also show bio when on '/', but note '/notes' commit 11a272b2a3050297dd84105a6c70adc937a0c409 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Thu Nov 10 17:49:30 2016 +0000 Set my homepage to the stream of notes commit 2e46ccad4038be64b5007f15dabee0321061fe98 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Tue Nov 8 23:58:11 2016 +0000 Drop sanitize.css and use normalize.css instead, also fix compress method commit 8082403d7464a873691fabab07ae4f6116993cdf Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Tue Nov 8 23:48:35 2016 +0000 Sort out yarn dependencies commit 8ef7137d160ae8577e42ab1fd19e957aa37cf08b Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Tue Nov 8 23:39:49 2016 +0000 Remove the compiled css commit 8284cdf838f5222eff87c942f119d6000a1b6fc6 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Tue Nov 8 23:16:27 2016 +0000 Remove sass files
337 lines
11 KiB
PHP
337 lines
11 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use Twitter;
|
|
use App\Tag;
|
|
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;
|
|
}
|
|
$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;
|
|
}
|
|
|
|
$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;
|
|
});
|
|
}
|
|
}
|