Massive simplification of code for displaying webmentions of notes, and the micropub client used to make a note

This commit is contained in:
Jonny Barnes 2017-06-22 15:41:23 +01:00
parent c96539f9c8
commit 8477aba87b
6 changed files with 173 additions and 117 deletions

View file

@ -2,16 +2,9 @@
namespace App\Http\Controllers;
use Twitter;
use HTMLPurifier;
use App\{Note, Tag};
use GuzzleHttp\Client;
use HTMLPurifier_Config;
use App\Note;
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!
@ -44,50 +37,18 @@ class NotesController extends Controller
*/
public function show($urlId)
{
$authorship = new Authorship();
$note = Note::nb60($urlId)->first();
$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];
$content['author'] = $webmention->author;
$content['published'] = $webmention->published;
$content['source'] = $webmention->source;
switch ($webmention->type) {
case 'in-reply-to':
$content['source'] = $webmention->source;
if (isset($microformats['items'][0]['properties']['published'][0])) {
try {
$content['date'] = $carbon->parse(
$microformats['items'][0]['properties']['published'][0]
)->toDayDateTimeString();
} catch (\Exception $exception) {
$content['date'] = $webmention->updated_at->toDayDateTimeString();
}
} else {
$content['date'] = $webmention->updated_at->toDayDateTimeString();
}
$content['reply'] = $webmention->reply;
$microformats = json_decode($webmention->mf2, true);
$content['reply'] = $this->filterHTML(
$microformats['items'][0]['properties']['content'][0]['html']
);
@ -95,10 +56,6 @@ class NotesController extends Controller
break;
case 'repost-of':
$content['date'] = $carbon->parse(
$microformats['items'][0]['properties']['published'][0]
)->toDayDateTimeString();
$content['source'] = $webmention->source;
$reposts[] = $content;
break;
@ -138,66 +95,7 @@ class NotesController extends Controller
$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('notes.tagged', compact('notes', '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;
}
/**
* 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');
$config->set('HTML.TargetBlank', true);
$purifier = new HTMLPurifier($config);
return $purifier->purify($html);
}
}

View file

@ -0,0 +1,42 @@
<?php
namespace App\Jobs;
use App\MicropubClient;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
class AddClientToDatabase implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $client_id;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct(string $client_id)
{
$this->client_id = $client_id;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
if (MicropubClient::where('client_url', $this->client_id)->count() == 0) {
$client = MicropubClient::create([
'client_url' => $this->client_id,
'client_name' => $this->client_id, // default client name is the URL
]);
}
}
}

View file

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace App\Services;
use App\Jobs\AddClientToDatabase;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use App\Exceptions\InvalidTokenException;
use Lcobucci\JWT\{Builder, Parser, Token};
@ -26,6 +27,7 @@ class TokenService
->set('nonce', bin2hex(random_bytes(8)))
->sign($signer, config('app.key'))
->getToken();
dispatch(new AddClientToDatabase($data['client_id']));
return (string) $token;
}

View file

@ -2,7 +2,13 @@
namespace App;
use Twitter;
use HTMLPurifier;
use Carbon\Carbon;
use HTMLPurifier_Config;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Database\Eloquent\Model;
use Jonnybarnes\WebmentionsParser\Authorship;
class WebMention extends Model
{
@ -29,4 +35,112 @@ class WebMention extends Model
* @var array
*/
protected $guarded = ['id'];
/**
* Get the author of the webmention.
*
* @return array
*/
public function getAuthorAttribute()
{
$authorship = new Authorship();
$hCard = $authorship->findAuthor(json_decode($this->mf2, true));
if (array_key_exists('properties', $hCard) &&
array_key_exists('photo', $hCard['properties'])
) {
$hCard['properties']['photo'][0] = $this->createPhotoLink($hCard['properties']['photo'][0]);
}
return $hCard;
}
/**
* Get the published value for the webmention.
*
* @return string
*/
public function getPublishedAttribute()
{
$microformats = json_decode($this->mf2, true);
$carbon = new Carbon();
if (isset($microformats['items'][0]['properties']['published'][0])) {
try {
$published = $carbon->parse(
$microformats['items'][0]['properties']['published'][0]
)->toDayDateTimeString();
} catch (\Exception $exception) {
$published = $webmention->updated_at->toDayDateTimeString();
}
} else {
$published = $webmention->updated_at->toDayDateTimeString();
}
return $published;
}
/**
* Get the filteres HTML of a reply.
*
* @return strin|null
*/
public function getReplyAttribute()
{
$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']);
}
}
/**
* Create the photo link.
*
* @param string
* @return string
*/
public function createPhotoLink(string $url): string
{
$url = normalize_url($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;
}
/**
* 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');
$config->set('HTML.TargetBlank', true);
$purifier = new HTMLPurifier($config);
return $purifier->purify($html);
}
}

View file

@ -9,9 +9,9 @@
@include('templates.note', ['note' => $note])
@foreach($replies as $reply)
<div class="u-comment h-cite">
<a class="u-author h-card mini-h-card" href="{{ $reply['url'] }}">
<img src="{{ $reply['photo'] }}" alt="" class="photo u-photo logo"> <span class="fn">{{ $reply['name'] }}</span>
</a> said at <a class="dt-published u-url" href="{{ $reply['source'] }}">{{ $reply['date'] }}</a>
<a class="u-author h-card mini-h-card" href="{{ $reply['author']['properties']['url'][0] }}">
<img src="{{ $reply['author']['properties']['photo'][0] }}" alt="" class="photo u-photo logo"> <span class="fn">{{ $reply['author']['properties']['name'][0] }}</span>
</a> said at <a class="dt-published u-url" href="{{ $reply['source'] }}">{{ $reply['published'] }}</a>
<div class="e-content p-name">
{!! $reply['reply'] !!}
</div>
@ -19,13 +19,13 @@
@endforeach
@if(count($likes) > 0)<h1 class="notes-subtitle">Likes</h1>@endif
@foreach($likes as $like)
<a href="{{ $like['url'] }}"><img src="{{ $like['photo'] }}" alt="profile picture of {{ $like['name'] }}" class="like-photo"></a>
<a href="{{ $like['author']['properties']['url'][0] }}"><img src="{{ $like['author']['properties']['photo'][0] }}" alt="profile picture of {{ $like['author']['properties']['name'][0] }}" class="like-photo"></a>
@endforeach
@if(count($reposts) > 0)<h1 class="notes-subtitle">Reposts</h1>@endif
@foreach($reposts as $repost)
<p><a class="h-card vcard mini-h-card p-author" href="{{ $repost['url'] }}">
<img src="{{ $repost['photo'] }}" alt="profile picture of {{ $repost['name'] }}" class="photo u-photo logo"> <span class="fn">{{ $repost['name'] }}</span>
</a> reposted this at <a href="{{ $repost['source'] }}">{{ $repost['date'] }}</a>.</p>
<p><a class="h-card vcard mini-h-card p-author" href="{{ $repost['author']['properties']['url'][0] }}">
<img src="{{ $repost['author']['properties']['photo'][0] }}" alt="profile picture of {{ $repost['author']['properties']['name'][0] }}" class="photo u-photo logo"> <span class="fn">{{ $repost['author']['properties']['name'][0] }}</span>
</a> reposted this at <a href="{{ $repost['source'] }}">{{ $repost['published'] }}</a>.</p>
@endforeach
<!-- these empty tags are for https://brid.gys publishing service -->
<a href="https://brid.gy/publish/twitter"></a>

View file

@ -1,13 +1,13 @@
@extends('master')
@section('title')
Tagged Notes «
Tagged Notes «
@stop
@section('content')
<h2>Notes tagged with <em>{{ $tag }}</em></h2>
@foreach ($notes as $note)
<div>{!! $note->note !!}
<a href="/note/{{ $note->id }}">{{ $note->human_time }}</a></div>
<a href="/note/{{ $note->id }}">{{ $note->humandiff }}</a></div>
@endforeach
@stop