Merge branch 'develop' of github.com:jonnybarnes/jonnybarnes.uk into develop

This commit is contained in:
Jonny Barnes 2017-09-24 12:40:08 +01:00
commit 3be0a6c3a7
64 changed files with 1162 additions and 259 deletions

View file

@ -16,6 +16,7 @@ addons:
- nginx - nginx
- realpath - realpath
- postgresql-9.6-postgis-2.3 - postgresql-9.6-postgis-2.3
- imagemagick
artifacts: artifacts:
s3_region: "eu-west-1" s3_region: "eu-west-1"
paths: paths:
@ -33,8 +34,10 @@ env:
php: php:
- 7.1 - 7.1
- 7.2
before_install: before_install:
- printf "\n" | pecl install imagick
- cp .env.travis .env - cp .env.travis .env
- echo 'error_log = "/tmp/php.error.log"' >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini - echo 'error_log = "/tmp/php.error.log"' >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini
- psql -U travis -c 'create database travis_ci_test' - psql -U travis -c 'create database travis_ci_test'

View file

@ -0,0 +1,20 @@
<?php
namespace App\Http\Controllers;
use App\Like;
class LikesController extends Controller
{
public function index()
{
$likes = Like::latest()->paginate(20);
return view('likes.index', compact('likes'));
}
public function show(Like $like)
{
return view('likes.show', compact('like'));
}
}

View file

@ -2,10 +2,14 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use Storage;
use Monolog\Logger; use Monolog\Logger;
use Ramsey\Uuid\Uuid; use Ramsey\Uuid\Uuid;
use App\{Media, Note, Place}; use App\Jobs\ProcessImage;
use App\Services\LikeService;
use Monolog\Handler\StreamHandler; use Monolog\Handler\StreamHandler;
use App\{Like, Media, Note, Place};
use Intervention\Image\ImageManager;
use Illuminate\Http\{Request, Response}; use Illuminate\Http\{Request, Response};
use App\Exceptions\InvalidTokenException; use App\Exceptions\InvalidTokenException;
use Phaza\LaravelPostgis\Geometries\Point; use Phaza\LaravelPostgis\Geometries\Point;
@ -70,6 +74,14 @@ class MicropubController extends Controller
if (stristr($tokenData->getClaim('scope'), 'create') === false) { if (stristr($tokenData->getClaim('scope'), 'create') === false) {
return $this->returnInsufficientScopeResponse(); return $this->returnInsufficientScopeResponse();
} }
if ($request->has('properties.like-of') || $request->has('like-of')) {
$like = (new LikeService())->createLike($request);
return response()->json([
'response' => 'created',
'location' => config('app.url') . "/likes/$like->id",
], 201)->header('Location', config('app.url') . "/likes/$like->id");
}
$data = []; $data = [];
$data['client-id'] = $tokenData->getClaim('client_id'); $data['client-id'] = $tokenData->getClaim('client_id');
if ($request->header('Content-Type') == 'application/json') { if ($request->header('Content-Type') == 'application/json') {
@ -90,7 +102,9 @@ class MicropubController extends Controller
if (is_array($request->input('properties.location.0'))) { if (is_array($request->input('properties.location.0'))) {
if ($request->input('properties.location.0.type.0' === 'h-card')) { if ($request->input('properties.location.0.type.0' === 'h-card')) {
try { try {
$place = $this->placeService->createPlaceFromCheckin($request->input('properties.location.0')); $place = $this->placeService->createPlaceFromCheckin(
$request->input('properties.location.0')
);
$data['checkin'] = $place->longurl; $data['checkin'] = $place->longurl;
} catch (\Exception $e) { } catch (\Exception $e) {
// //
@ -102,7 +116,9 @@ class MicropubController extends Controller
if (array_key_exists('checkin', $request->input('properties'))) { if (array_key_exists('checkin', $request->input('properties'))) {
$data['swarm-url'] = $request->input('properties.syndication.0'); $data['swarm-url'] = $request->input('properties.syndication.0');
try { try {
$place = $this->placeService->createPlaceFromCheckin($request->input('properties.checkin.0')); $place = $this->placeService->createPlaceFromCheckin(
$request->input('properties.checkin.0')
);
$data['checkin'] = $place->longurl; $data['checkin'] = $place->longurl;
} catch (\Exception $e) { } catch (\Exception $e) {
$data['checkin'] = null; $data['checkin'] = null;
@ -395,8 +411,11 @@ class MicropubController extends Controller
'error_description' => 'A problem occured handling your request', 'error_description' => 'A problem occured handling your request',
], 500); ], 500);
} }
$size = $request->file('file')->getClientSize();
Storage::disk('local')->put($filename, $request->file('file')->openFile()->fread($size));
try { try {
$path = $request->file('file')->storeAs('media', $filename, 's3'); Storage::disk('s3')->put('media/' . $filename, $request->file('file')->openFile()->fread($size));
} catch (Exception $e) { // which exception? } catch (Exception $e) { // which exception?
return response()->json([ return response()->json([
'response' => 'error', 'response' => 'error',
@ -404,12 +423,25 @@ class MicropubController extends Controller
'error_description' => 'Unable to save media to S3', 'error_description' => 'Unable to save media to S3',
], 503); ], 503);
} }
$manager = app()->make(ImageManager::class);
try {
$image = $manager->make($request->file('file'));
$width = $image->width();
} catch (\Intervention\Image\Exception\NotReadableException $exception) {
// not an image
$width = null;
}
$media = new Media(); $media = new Media();
$media->token = $request->bearerToken(); $media->token = $request->bearerToken();
$media->path = $path; $media->path = 'media/' . $filename;
$media->type = $this->getFileTypeFromMimeType($request->file('file')->getMimeType()); $media->type = $this->getFileTypeFromMimeType($request->file('file')->getMimeType());
$media->image_widths = $width;
$media->save(); $media->save();
dispatch(new ProcessImage($filename));
return response()->json([ return response()->json([
'response' => 'created', 'response' => 'created',
'location' => $media->url, 'location' => $media->url,

View file

@ -5,20 +5,24 @@ namespace App\Http\Controllers;
use App\Note; use App\Note;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Jonnybarnes\IndieWeb\Numbers; use Jonnybarnes\IndieWeb\Numbers;
use App\Services\ActivityStreamsService;
// Need to sort out Twitter and webmentions! // Need to sort out Twitter and webmentions!
class NotesController extends Controller class NotesController extends Controller
{ {
/** /**
* Show all the notes. * Show all the notes. This is also the homepage.
* *
* @param Illuminate\Http\Request request;
* @return \Illuminte\View\Factory view * @return \Illuminte\View\Factory view
*/ */
public function index(Request $request) public function index()
{ {
$notes = Note::orderBy('id', 'desc') if (request()->wantsActivityStream()) {
return (new ActivityStreamsService)->siteOwnerResponse();
}
$notes = Note::latest()
->with('place', 'media', 'client') ->with('place', 'media', 'client')
->withCount(['webmentions As replies' => function ($query) { ->withCount(['webmentions As replies' => function ($query) {
$query->where('type', 'in-reply-to'); $query->where('type', 'in-reply-to');
@ -37,6 +41,10 @@ class NotesController extends Controller
{ {
$note = Note::nb60($urlId)->with('webmentions')->firstOrFail(); $note = Note::nb60($urlId)->with('webmentions')->firstOrFail();
if (request()->wantsActivityStream()) {
return (new ActivityStreamsService)->singleNoteResponse($note);
}
return view('notes.show', compact('note')); return view('notes.show', compact('note'));
} }

View file

@ -38,6 +38,7 @@ class Kernel extends HttpKernel
\App\Http\Middleware\LinkHeadersMiddleware::class, \App\Http\Middleware\LinkHeadersMiddleware::class,
//\App\Http\Middleware\DevTokenMiddleware::class, //\App\Http\Middleware\DevTokenMiddleware::class,
\App\Http\Middleware\LocalhostSessionMiddleware::class, \App\Http\Middleware\LocalhostSessionMiddleware::class,
\App\Http\Middleware\ActivityStreamLinks::class,
], ],
'api' => [ 'api' => [

View file

@ -0,0 +1,28 @@
<?php
namespace App\Http\Middleware;
use Closure;
class ActivityStreamLinks
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$response = $next($request);
if ($request->path() === '/') {
$response->header('Link', '<' . config('app.url') . '>; rel="application/activity+json"', false);
}
if ($request->is('notes/*')) {
$response->header('Link', '<' . $request->url() . '>; rel="application/activity+json"', false);
}
return $response;
}
}

68
app/Jobs/ProcessImage.php Normal file
View file

@ -0,0 +1,68 @@
<?php
namespace App\Jobs;
use Storage;
use Illuminate\Bus\Queueable;
use Intervention\Image\ImageManager;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Intervention\Image\Exception\NotReadableException;
class ProcessImage implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $filename;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct(string $filename)
{
$this->filename = $filename;
}
/**
* Execute the job.
*
* @return void
*/
public function handle(ImageManager $manager)
{
//open file
try {
$image = $manager->make(storage_path('app') . '/' . $this->filename);
} catch (NotReadableException $exception) {
// not an image; delete file and end job
unlink(storage_path('app') . '/' . $this->filename);
return;
}
//create smaller versions if necessary
if ($image->width() >= 1000) {
$filenameParts = explode('.', $this->filename);
$extension = array_pop($filenameParts);
// the following acheives this data flow
// foo.bar.png => ['foo', 'bar', 'png'] => ['foo', 'bar'] => foo.bar
$basename = ltrim(array_reduce($filenameParts, function ($carry, $item) {
return $carry . '.' . $item;
}, ''), '.');
$medium = $image->resize(1000, null, function ($constraint) {
$constraint->aspectRatio();
});
Storage::disk('s3')->put('media/'. $basename . '-medium.' . $extension, (string) $medium->encode());
$small = $image->resize(500, null, function ($constraint) {
$constraint->aspectRatio();
});
Storage::disk('s3')->put('media/' . $basename . '-small.' . $extension, (string) $small->encode());
}
// now we can delete the locally saved image
unlink(storage_path('app') . '/' . $this->filename);
}
}

59
app/Jobs/ProcessLike.php Normal file
View file

@ -0,0 +1,59 @@
<?php
namespace App\Jobs;
use App\Like;
use GuzzleHttp\Client;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Jonnybarnes\WebmentionsParser\Authorship;
use Jonnybarnes\WebmentionsParser\Exceptions\AuthorshipParserException;
class ProcessLike implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $like;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct(Like $like)
{
$this->like = $like;
}
/**
* Execute the job.
*
* @return void
*/
public function handle(Client $client, Authorship $authorship)
{
$response = $client->request('GET', $this->like->url);
$mf2 = \Mf2\parse((string) $response->getBody(), $this->like->url);
if (array_has($mf2, 'items.0.properties.content')) {
$this->like->content = $mf2['items'][0]['properties']['content'][0]['html'];
}
try {
$author = $authorship->findAuthor($mf2);
if (is_array($author)) {
$this->like->author_name = $author['name'];
$this->like->author_url = $author['url'];
}
if (is_string($author) && $author !== '') {
$this->like->author_name = $author;
}
} catch (AuthorshipParserException $exception) {
return;
}
$this->like->save();
}
}

View file

@ -40,6 +40,7 @@ class SyndicateToFacebook implements ShouldQueue
'form_params' => [ 'form_params' => [
'source' => $this->note->longurl, 'source' => $this->note->longurl,
'target' => 'https://brid.gy/publish/facebook', 'target' => 'https://brid.gy/publish/facebook',
'bridgy_omit_link' => 'maybe',
], ],
] ]
); );

View file

@ -41,6 +41,7 @@ class SyndicateToTwitter implements ShouldQueue
'form_params' => [ 'form_params' => [
'source' => $this->note->longurl, 'source' => $this->note->longurl,
'target' => 'https://brid.gy/publish/twitter', 'target' => 'https://brid.gy/publish/twitter',
'bridgy_omit_link' => 'maybe',
], ],
] ]
); );

44
app/Like.php Normal file
View file

@ -0,0 +1,44 @@
<?php
namespace App;
use Mf2;
use HTMLPurifier;
use HTMLPurifier_Config;
use Illuminate\Database\Eloquent\Model;
class Like extends Model
{
protected $fillable = ['url'];
public function setUrlAttribute($value)
{
$this->attributes['url'] = normalize_url($value);
}
public function setAuthorUrlAttribute($value)
{
$this->attributes['author_url'] = normalize_url($value);
}
public function getContentAttribute($value)
{
if ($value === null) {
return $this->url;
}
$mf2 = Mf2\parse($value, $this->url);
return $this->filterHTML($mf2['items'][0]['properties']['content'][0]['html']);
}
public 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

@ -41,4 +41,40 @@ class Media extends Model
return config('filesystems.disks.s3.url') . '/' . $this->path; return config('filesystems.disks.s3.url') . '/' . $this->path;
} }
/**
* Get the URL for the medium size of an S3 image file.
*
* @return string
*/
public function getMediumurlAttribute()
{
$filenameParts = explode('.', $this->path);
$extension = array_pop($filenameParts);
// the following acheives this data flow
// foo.bar.png => ['foo', 'bar', 'png'] => ['foo', 'bar'] => foo.bar
$basename = ltrim(array_reduce($filenameParts, function ($carry, $item) {
return $carry . '.' . $item;
}, ''), '.');
return config('filesystems.disks.s3.url') . '/' . $basename . '-medium.' . $extension;
}
/**
* Get the URL for the small size of an S3 image file.
*
* @return string
*/
public function getSmallurlAttribute()
{
$filenameParts = explode('.', $this->path);
$extension = array_pop($filenameParts);
// the following acheives this data flow
// foo.bar.png => ['foo', 'bar', 'png'] => ['foo', 'bar'] => foo.bar
$basename = ltrim(array_reduce($filenameParts, function ($carry, $item) {
return $carry . '.' . $item;
}, ''), '.');
return config('filesystems.disks.s3.url') . '/' . $basename . '-small.' . $extension;
}
} }

View file

@ -280,8 +280,8 @@ class Note extends Model
try { try {
$oEmbed = Twitter::getOembed([ $oEmbed = Twitter::getOembed([
'id' => $tweetId, 'id' => $tweetId,
'dnt' => true,
'align' => 'center', 'align' => 'center',
'omit_script' => true,
'maxwidth' => 550, 'maxwidth' => 550,
]); ]);
} catch (\Exception $e) { } catch (\Exception $e) {
@ -368,7 +368,8 @@ class Note extends Model
return $matches[0]; return $matches[0];
} }
if ($contact->facebook) { if ($contact->facebook) {
return '<a class="u-category h-card" href="https://facebook.com/' . $contact->facebook . '">' . $contact->name . '</a>'; return '<a class="u-category h-card" href="https://facebook.com/'
. $contact->facebook . '">' . $contact->name . '</a>';
} }
return $contact->name; return $contact->name;

View file

@ -67,7 +67,8 @@ class Place extends Model
public function scopeNear(Builder $query, Point $point, $distance = 1000) public function scopeNear(Builder $query, Point $point, $distance = 1000)
{ {
$field = DB::raw( $field = DB::raw(
sprintf("ST_Distance(%s.location, ST_GeogFromText('%s'))", sprintf(
"ST_Distance(%s.location, ST_GeogFromText('%s'))",
$this->getTable(), $this->getTable(),
$point->toWKT() $point->toWKT()
) )

View file

@ -5,6 +5,7 @@ namespace App\Providers;
use App\Tag; use App\Tag;
use App\Note; use App\Note;
use Validator; use Validator;
use Illuminate\Http\Request;
use Laravel\Dusk\DuskServiceProvider; use Laravel\Dusk\DuskServiceProvider;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;
@ -42,10 +43,20 @@ class AppServiceProvider extends ServiceProvider
$tag = Tag::firstOrCreate(['tag' => $tag]); $tag = Tag::firstOrCreate(['tag' => $tag]);
$tagsToAdd[] = $tag->id; $tagsToAdd[] = $tag->id;
} }
if (count($tagsToAdd > 0)) { if (count($tagsToAdd) > 0) {
$note->tags()->attach($tagsToAdd); $note->tags()->attach($tagsToAdd);
} }
}); });
// Request AS macro
Request::macro('wantsActivityStream', function () {
return str_contains(mb_strtolower($this->header('Accept')), 'application/activity+json');
});
// configure Intervention/Image
$this->app->bind('Intervention\Image\ImageManager', function () {
return new \Intervention\Image\ImageManager(['driver' => config('image.driver')]);
});
} }
/** /**

View file

@ -0,0 +1,50 @@
<?php
namespace App\Services;
use App\Note;
class ActivityStreamsService
{
public function siteOwnerResponse()
{
$data = json_encode([
'@context' => 'https://www.w3.org/ns/activitystreams',
'id' => config('app.url'),
'type' => 'Person',
'name' => config('user.displayname'),
'preferredUsername' => config('user.username'),
]);
return response($data)->header('Content-Type', 'application/activity+json');
}
public function singleNoteResponse(Note $note)
{
$data = json_encode([
'@context' => 'https://www.w3.org/ns/activitystreams',
'summary' => strtok(config('user.displayname'), ' ') . ' added a note to their microblog',
'type' => 'Add',
'published' => $note->updated_at->toW3cString(),
'actor' => [
'type' => 'Person',
'id' => config('app.url'),
'name' => config('app.display_name'),
'url' => config('app.url'),
'image' => [
'type' => 'Link',
'href' => config('app.url') . '/assets/img/profile.jpg',
'mediaType' => '/image/jpeg',
],
],
'object' => [
'id' => $note->longurl,
'type' => 'Note',
'url' => $note->longurl,
'name' => strip_tags($note->note),
],
]);
return response($data)->header('Content-Type', 'application/activity+json');
}
}

View file

@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
namespace App\Services;
use App\Like;
use App\Jobs\ProcessLike;
use Illuminate\Http\Request;
class LikeService
{
/**
* Create a new Like.
*
* @param Request $request
*/
public function createLike(Request $request): Like
{
if ($request->header('Content-Type') == 'application/json') {
//micropub request
$url = normalize_url($request->input('properties.like-of.0'));
}
if (
($request->header('Content-Type') == 'x-www-url-formencoded')
||
($request->header('Content-Type') == 'multipart/form-data')
) {
$url = normalize_url($request->input('like-of'));
}
$like = Like::create(['url' => $url]);
ProcessLike::dispatch($like);
return $like;
}
}

View file

@ -37,7 +37,7 @@ class NoteService
); );
if (array_key_exists('published', $data) && empty($data['published']) === false) { if (array_key_exists('published', $data) && empty($data['published']) === false) {
$carbon = new \Carbon\Carbon($data['published']); $carbon = carbon($data['published']);
$note->created_at = $note->updated_at = $carbon->toDateTimeString(); $note->created_at = $note->updated_at = $carbon->toDateTimeString();
} }

View file

@ -5,7 +5,6 @@ namespace App;
use Cache; use Cache;
use Twitter; use Twitter;
use HTMLPurifier; use HTMLPurifier;
use Carbon\Carbon;
use HTMLPurifier_Config; use HTMLPurifier_Config;
use Illuminate\Filesystem\Filesystem; use Illuminate\Filesystem\Filesystem;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
@ -63,10 +62,9 @@ class WebMention extends Model
public function getPublishedAttribute() public function getPublishedAttribute()
{ {
$microformats = json_decode($this->mf2, true); $microformats = json_decode($this->mf2, true);
$carbon = new Carbon();
if (isset($microformats['items'][0]['properties']['published'][0])) { if (isset($microformats['items'][0]['properties']['published'][0])) {
try { try {
$published = $carbon->parse( $published = carbon()->parse(
$microformats['items'][0]['properties']['published'][0] $microformats['items'][0]['properties']['published'][0]
)->toDayDateTimeString(); )->toDayDateTimeString();
} catch (\Exception $exception) { } catch (\Exception $exception) {

View file

@ -1,5 +1,26 @@
# Changelog # Changelog
## Version {next}
- Add support for `likes` (issue#69)
- Only included links on truncated syndicated notes https://brid.gy/about#omit-link
## Version 0.8.1 (2017-09-16)
- Order notes by latest (issue#70)
- AcitivtyStream support is now indicated with HTTP Link headers
## Version 0.8 (2017-09-16)
- Improve embedding of tweets (issue#66)
- Allow for “responsive” images (issue#62)
## Version 0.7.3 (2017-09-13)
- Fix a test
## Version 0.7.2 (2017-09-13)
- Small AS2.0 improvements
## Version 0.7.1 (2017-09-13)
- Add content-negotiated AS data for homepage and single notes
## Version 0.7 (2017-09-08) ## Version 0.7 (2017-09-08)
- Add Laravel Horizon - Add Laravel Horizon

View file

@ -11,6 +11,7 @@
"fideloper/proxy": "~3.3", "fideloper/proxy": "~3.3",
"guzzlehttp/guzzle": "~6.0", "guzzlehttp/guzzle": "~6.0",
"indieauth/client": "~0.1", "indieauth/client": "~0.1",
"intervention/image": "^2.4",
"jonnybarnes/commonmark-linkify": "^0.2", "jonnybarnes/commonmark-linkify": "^0.2",
"jonnybarnes/emoji-a11y": "^0.3", "jonnybarnes/emoji-a11y": "^0.3",
"jonnybarnes/indieweb": "dev-master", "jonnybarnes/indieweb": "dev-master",
@ -32,6 +33,7 @@
}, },
"require-dev": { "require-dev": {
"barryvdh/laravel-debugbar": "~3.0", "barryvdh/laravel-debugbar": "~3.0",
"bmitch/churn-php": "^0.2.0",
"filp/whoops": "~2.0", "filp/whoops": "~2.0",
"fzaninotto/faker": "~1.4", "fzaninotto/faker": "~1.4",
"jakub-onderka/php-parallel-lint": "^0.9.2", "jakub-onderka/php-parallel-lint": "^0.9.2",

312
composer.lock generated
View file

@ -4,20 +4,20 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "551d407b87a7d9ff3e65969f33605014", "content-hash": "560e297345d19c326c8ff08ccfd3668c",
"packages": [ "packages": [
{ {
"name": "aws/aws-sdk-php", "name": "aws/aws-sdk-php",
"version": "3.36.3", "version": "3.36.9",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/aws/aws-sdk-php.git", "url": "https://github.com/aws/aws-sdk-php.git",
"reference": "7ffaee4359c161339867e565f18f6e3b7e77e44e" "reference": "7b89fa65cccb966da1599b715dcea8c09eafc175"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/7ffaee4359c161339867e565f18f6e3b7e77e44e", "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/7b89fa65cccb966da1599b715dcea8c09eafc175",
"reference": "7ffaee4359c161339867e565f18f6e3b7e77e44e", "reference": "7b89fa65cccb966da1599b715dcea8c09eafc175",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -84,7 +84,7 @@
"s3", "s3",
"sdk" "sdk"
], ],
"time": "2017-09-07T22:30:02+00:00" "time": "2017-09-15T19:12:04+00:00"
}, },
{ {
"name": "barnabywalters/mf-cleaner", "name": "barnabywalters/mf-cleaner",
@ -303,16 +303,16 @@
}, },
{ {
"name": "composer/ca-bundle", "name": "composer/ca-bundle",
"version": "1.0.7", "version": "1.0.8",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/composer/ca-bundle.git", "url": "https://github.com/composer/ca-bundle.git",
"reference": "b17e6153cb7f33c7e44eb59578dc12eee5dc8e12" "reference": "9dd73a03951357922d8aee6cc084500de93e2343"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/composer/ca-bundle/zipball/b17e6153cb7f33c7e44eb59578dc12eee5dc8e12", "url": "https://api.github.com/repos/composer/ca-bundle/zipball/9dd73a03951357922d8aee6cc084500de93e2343",
"reference": "b17e6153cb7f33c7e44eb59578dc12eee5dc8e12", "reference": "9dd73a03951357922d8aee6cc084500de93e2343",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -358,7 +358,7 @@
"ssl", "ssl",
"tls" "tls"
], ],
"time": "2017-03-06T11:59:08+00:00" "time": "2017-09-11T07:24:36+00:00"
}, },
{ {
"name": "cviebrock/eloquent-sluggable", "name": "cviebrock/eloquent-sluggable",
@ -1493,6 +1493,76 @@
], ],
"time": "2017-01-11T17:14:49+00:00" "time": "2017-01-11T17:14:49+00:00"
}, },
{
"name": "intervention/image",
"version": "2.4.0",
"source": {
"type": "git",
"url": "https://github.com/Intervention/image.git",
"reference": "322a4ade249467179c50a3e50eda8760ff3af2a3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Intervention/image/zipball/322a4ade249467179c50a3e50eda8760ff3af2a3",
"reference": "322a4ade249467179c50a3e50eda8760ff3af2a3",
"shasum": ""
},
"require": {
"ext-fileinfo": "*",
"guzzlehttp/psr7": "~1.1",
"php": ">=5.4.0"
},
"require-dev": {
"mockery/mockery": "~0.9.2",
"phpunit/phpunit": "^4.8 || ^5.7"
},
"suggest": {
"ext-gd": "to use GD library based image processing.",
"ext-imagick": "to use Imagick based image processing.",
"intervention/imagecache": "Caching extension for the Intervention Image library"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.3-dev"
},
"laravel": {
"providers": [
"Intervention\\Image\\ImageServiceProvider"
],
"aliases": {
"Image": "Intervention\\Image\\Facades\\Image"
}
}
},
"autoload": {
"psr-4": {
"Intervention\\Image\\": "src/Intervention/Image"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Oliver Vogel",
"email": "oliver@olivervogel.com",
"homepage": "http://olivervogel.com/"
}
],
"description": "Image handling and manipulation library with support for Laravel integration",
"homepage": "http://image.intervention.io/",
"keywords": [
"gd",
"image",
"imagick",
"laravel",
"thumbnail",
"watermark"
],
"time": "2017-07-03T15:50:40+00:00"
},
{ {
"name": "jakub-onderka/php-console-color", "name": "jakub-onderka/php-console-color",
"version": "0.1", "version": "0.1",
@ -1815,16 +1885,16 @@
}, },
{ {
"name": "laravel/framework", "name": "laravel/framework",
"version": "v5.5.3", "version": "v5.5.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laravel/framework.git", "url": "https://github.com/laravel/framework.git",
"reference": "779a98d3b2ebed2128db1a668dcc10a65c9b01be" "reference": "d3e0493bead126cf7fb9a005c64e6b58a9190e51"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/779a98d3b2ebed2128db1a668dcc10a65c9b01be", "url": "https://api.github.com/repos/laravel/framework/zipball/d3e0493bead126cf7fb9a005c64e6b58a9190e51",
"reference": "779a98d3b2ebed2128db1a668dcc10a65c9b01be", "reference": "d3e0493bead126cf7fb9a005c64e6b58a9190e51",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1943,20 +2013,20 @@
"framework", "framework",
"laravel" "laravel"
], ],
"time": "2017-09-07T13:50:21+00:00" "time": "2017-09-13T13:36:29+00:00"
}, },
{ {
"name": "laravel/horizon", "name": "laravel/horizon",
"version": "v1.0.1", "version": "v1.0.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laravel/horizon.git", "url": "https://github.com/laravel/horizon.git",
"reference": "856fe55c6d054dc063e71d97c0873013803d96df" "reference": "df65f5b3f5119cc5f0a6bfbd501f83580efd0842"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laravel/horizon/zipball/856fe55c6d054dc063e71d97c0873013803d96df", "url": "https://api.github.com/repos/laravel/horizon/zipball/df65f5b3f5119cc5f0a6bfbd501f83580efd0842",
"reference": "856fe55c6d054dc063e71d97c0873013803d96df", "reference": "df65f5b3f5119cc5f0a6bfbd501f83580efd0842",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2011,20 +2081,20 @@
"laravel", "laravel",
"queue" "queue"
], ],
"time": "2017-09-06T19:57:45+00:00" "time": "2017-09-12T12:50:19+00:00"
}, },
{ {
"name": "laravel/scout", "name": "laravel/scout",
"version": "v3.0.7", "version": "v3.0.10",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laravel/scout.git", "url": "https://github.com/laravel/scout.git",
"reference": "b899432186096dacc90700d5320d95cc3db1efe1" "reference": "681c15a26bbc973528af2e77e0bb61981dc07206"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laravel/scout/zipball/b899432186096dacc90700d5320d95cc3db1efe1", "url": "https://api.github.com/repos/laravel/scout/zipball/681c15a26bbc973528af2e77e0bb61981dc07206",
"reference": "b899432186096dacc90700d5320d95cc3db1efe1", "reference": "681c15a26bbc973528af2e77e0bb61981dc07206",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2076,7 +2146,7 @@
"laravel", "laravel",
"search" "search"
], ],
"time": "2017-07-12T18:42:43+00:00" "time": "2017-09-14T12:32:30+00:00"
}, },
{ {
"name": "laravel/tinker", "name": "laravel/tinker",
@ -3402,16 +3472,16 @@
}, },
{ {
"name": "symfony/console", "name": "symfony/console",
"version": "v3.3.8", "version": "v3.3.9",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/console.git", "url": "https://github.com/symfony/console.git",
"reference": "d6596cb5022b6a0bd940eae54a1de78646a5fda6" "reference": "a1e1b01293a090cb9ae2ddd221a3251a4a7e4abf"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/d6596cb5022b6a0bd940eae54a1de78646a5fda6", "url": "https://api.github.com/repos/symfony/console/zipball/a1e1b01293a090cb9ae2ddd221a3251a4a7e4abf",
"reference": "d6596cb5022b6a0bd940eae54a1de78646a5fda6", "reference": "a1e1b01293a090cb9ae2ddd221a3251a4a7e4abf",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3466,11 +3536,11 @@
], ],
"description": "Symfony Console Component", "description": "Symfony Console Component",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"time": "2017-08-27T14:52:21+00:00" "time": "2017-09-06T16:40:18+00:00"
}, },
{ {
"name": "symfony/css-selector", "name": "symfony/css-selector",
"version": "v3.3.8", "version": "v3.3.9",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/css-selector.git", "url": "https://github.com/symfony/css-selector.git",
@ -3523,16 +3593,16 @@
}, },
{ {
"name": "symfony/debug", "name": "symfony/debug",
"version": "v3.3.8", "version": "v3.3.9",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/debug.git", "url": "https://github.com/symfony/debug.git",
"reference": "084d804fe35808eb2ef596ec83d85d9768aa6c9d" "reference": "8beb24eec70b345c313640962df933499373a944"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/debug/zipball/084d804fe35808eb2ef596ec83d85d9768aa6c9d", "url": "https://api.github.com/repos/symfony/debug/zipball/8beb24eec70b345c313640962df933499373a944",
"reference": "084d804fe35808eb2ef596ec83d85d9768aa6c9d", "reference": "8beb24eec70b345c313640962df933499373a944",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3575,11 +3645,11 @@
], ],
"description": "Symfony Debug Component", "description": "Symfony Debug Component",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"time": "2017-08-27T14:52:21+00:00" "time": "2017-09-01T13:23:39+00:00"
}, },
{ {
"name": "symfony/event-dispatcher", "name": "symfony/event-dispatcher",
"version": "v3.3.8", "version": "v3.3.9",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/event-dispatcher.git", "url": "https://github.com/symfony/event-dispatcher.git",
@ -3642,7 +3712,7 @@
}, },
{ {
"name": "symfony/finder", "name": "symfony/finder",
"version": "v3.3.8", "version": "v3.3.9",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/finder.git", "url": "https://github.com/symfony/finder.git",
@ -3691,16 +3761,16 @@
}, },
{ {
"name": "symfony/http-foundation", "name": "symfony/http-foundation",
"version": "v3.3.8", "version": "v3.3.9",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/http-foundation.git", "url": "https://github.com/symfony/http-foundation.git",
"reference": "14bacad23a4f075bfd3fd456755236cb261320e3" "reference": "2cdc7de1921d1a1c805a13dc05e44a2cd58f5ad3"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/14bacad23a4f075bfd3fd456755236cb261320e3", "url": "https://api.github.com/repos/symfony/http-foundation/zipball/2cdc7de1921d1a1c805a13dc05e44a2cd58f5ad3",
"reference": "14bacad23a4f075bfd3fd456755236cb261320e3", "reference": "2cdc7de1921d1a1c805a13dc05e44a2cd58f5ad3",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3740,20 +3810,20 @@
], ],
"description": "Symfony HttpFoundation Component", "description": "Symfony HttpFoundation Component",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"time": "2017-08-10T07:07:06+00:00" "time": "2017-09-06T17:07:39+00:00"
}, },
{ {
"name": "symfony/http-kernel", "name": "symfony/http-kernel",
"version": "v3.3.8", "version": "v3.3.9",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/http-kernel.git", "url": "https://github.com/symfony/http-kernel.git",
"reference": "1c1717d28904744dc9a9f6a9d97a8b9bed1680e9" "reference": "70f5bb3cdd737624249953b61023411e26be5db7"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/1c1717d28904744dc9a9f6a9d97a8b9bed1680e9", "url": "https://api.github.com/repos/symfony/http-kernel/zipball/70f5bb3cdd737624249953b61023411e26be5db7",
"reference": "1c1717d28904744dc9a9f6a9d97a8b9bed1680e9", "reference": "70f5bb3cdd737624249953b61023411e26be5db7",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3826,7 +3896,7 @@
], ],
"description": "Symfony HttpKernel Component", "description": "Symfony HttpKernel Component",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"time": "2017-08-28T22:35:03+00:00" "time": "2017-09-11T16:13:23+00:00"
}, },
{ {
"name": "symfony/polyfill-mbstring", "name": "symfony/polyfill-mbstring",
@ -3889,7 +3959,7 @@
}, },
{ {
"name": "symfony/process", "name": "symfony/process",
"version": "v3.3.8", "version": "v3.3.9",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/process.git", "url": "https://github.com/symfony/process.git",
@ -3938,7 +4008,7 @@
}, },
{ {
"name": "symfony/routing", "name": "symfony/routing",
"version": "v3.3.8", "version": "v3.3.9",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/routing.git", "url": "https://github.com/symfony/routing.git",
@ -4016,7 +4086,7 @@
}, },
{ {
"name": "symfony/translation", "name": "symfony/translation",
"version": "v3.3.8", "version": "v3.3.9",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/translation.git", "url": "https://github.com/symfony/translation.git",
@ -4081,7 +4151,7 @@
}, },
{ {
"name": "symfony/var-dumper", "name": "symfony/var-dumper",
"version": "v3.3.8", "version": "v3.3.9",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/var-dumper.git", "url": "https://github.com/symfony/var-dumper.git",
@ -4400,6 +4470,67 @@
], ],
"time": "2017-08-29T08:54:25+00:00" "time": "2017-08-29T08:54:25+00:00"
}, },
{
"name": "bmitch/churn-php",
"version": "0.2.0",
"source": {
"type": "git",
"url": "https://github.com/bmitch/churn-php.git",
"reference": "0026a7db3bebb83dc9b1cd1941e1cb15629c1dc8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/bmitch/churn-php/zipball/0026a7db3bebb83dc9b1cd1941e1cb15629c1dc8",
"reference": "0026a7db3bebb83dc9b1cd1941e1cb15629c1dc8",
"shasum": ""
},
"require": {
"php": "^7.0",
"symfony/console": "^3.2",
"symfony/process": "^3.2",
"symfony/yaml": "^3.3",
"tightenco/collect": "^5.4"
},
"require-dev": {
"bmitch/codor": "^1.0",
"jakub-onderka/php-console-highlighter": "^0.3.2",
"jakub-onderka/php-parallel-lint": "^0.9.2",
"larapack/dd": "^1.1",
"mockery/mockery": "dev-master",
"phploc/phploc": "^3.0",
"phpmd/phpmd": "^2.5",
"phpunit/phpunit": "^5.7",
"sebastian/phpcpd": "^2.0",
"sensiolabs/security-checker": "^4.0",
"slevomat/coding-standard": "^2.0"
},
"bin": [
"churn"
],
"type": "library",
"autoload": {
"psr-4": {
"Churn\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Bill Mitchell",
"email": "wkmitch@gmail.com"
}
],
"description": "Discover files in need of refactoring.",
"homepage": "https://github.com/bmitch/churn-php",
"keywords": [
"bmitch",
"churn-php"
],
"time": "2017-09-02T00:42:45+00:00"
},
{ {
"name": "doctrine/instantiator", "name": "doctrine/instantiator",
"version": "1.1.0", "version": "1.1.0",
@ -4711,16 +4842,16 @@
}, },
{ {
"name": "laravel/dusk", "name": "laravel/dusk",
"version": "v2.0.1", "version": "v2.0.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laravel/dusk.git", "url": "https://github.com/laravel/dusk.git",
"reference": "5e0ceaa27c9a78897f201a26f176b23bef20210f" "reference": "1c702f428b4813cdb2ea92f1026f066cb0be90a2"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laravel/dusk/zipball/5e0ceaa27c9a78897f201a26f176b23bef20210f", "url": "https://api.github.com/repos/laravel/dusk/zipball/1c702f428b4813cdb2ea92f1026f066cb0be90a2",
"reference": "5e0ceaa27c9a78897f201a26f176b23bef20210f", "reference": "1c702f428b4813cdb2ea92f1026f066cb0be90a2",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -4768,7 +4899,7 @@
"testing", "testing",
"webdriver" "webdriver"
], ],
"time": "2017-09-06T13:19:28+00:00" "time": "2017-09-12T18:46:34+00:00"
}, },
{ {
"name": "maximebf/debugbar", "name": "maximebf/debugbar",
@ -5042,16 +5173,16 @@
}, },
{ {
"name": "phpdocumentor/reflection-common", "name": "phpdocumentor/reflection-common",
"version": "1.0", "version": "1.0.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpDocumentor/ReflectionCommon.git", "url": "https://github.com/phpDocumentor/ReflectionCommon.git",
"reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c" "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c", "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6",
"reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c", "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -5092,7 +5223,7 @@
"reflection", "reflection",
"static analysis" "static analysis"
], ],
"time": "2015-12-27T11:43:31+00:00" "time": "2017-09-11T18:02:19+00:00"
}, },
{ {
"name": "phpdocumentor/reflection-docblock", "name": "phpdocumentor/reflection-docblock",
@ -6290,6 +6421,61 @@
"homepage": "https://github.com/sebastianbergmann/version", "homepage": "https://github.com/sebastianbergmann/version",
"time": "2016-10-03T07:35:21+00:00" "time": "2016-10-03T07:35:21+00:00"
}, },
{
"name": "symfony/yaml",
"version": "v3.3.9",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
"reference": "1d8c2a99c80862bdc3af94c1781bf70f86bccac0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/1d8c2a99c80862bdc3af94c1781bf70f86bccac0",
"reference": "1d8c2a99c80862bdc3af94c1781bf70f86bccac0",
"shasum": ""
},
"require": {
"php": "^5.5.9|>=7.0.8"
},
"require-dev": {
"symfony/console": "~2.8|~3.0"
},
"suggest": {
"symfony/console": "For validating YAML files using the lint command"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.3-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Yaml\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com",
"time": "2017-07-29T21:54:42+00:00"
},
{ {
"name": "theseer/fdomdocument", "name": "theseer/fdomdocument",
"version": "1.6.6", "version": "1.6.6",

20
config/image.php Normal file
View file

@ -0,0 +1,20 @@
<?php
return array(
/*
|--------------------------------------------------------------------------
| Image Driver
|--------------------------------------------------------------------------
|
| Intervention Image supports "GD Library" and "Imagick" to process images
| internally. You may choose one of them according to your PHP
| configuration. By default PHP's "GD Library" implementation is used.
|
| Supported: "gd", "imagick"
|
*/
'driver' => 'imagick'
);

7
config/user.php Normal file
View file

@ -0,0 +1,7 @@
<?php
return [
'displayname' => env('DISPLAY_NAME'),
'username' => env('USER_NAME'),
];

View file

@ -0,0 +1,12 @@
<?php
use Faker\Generator as Faker;
$factory->define(App\Like::class, function (Faker $faker) {
return [
'url' => $faker->url,
'author_name' => $faker->name,
'author_url' => $faker->url,
'content' => '<html><body><div class="h-entry"><div class="e-content">' . $faker->realtext() . '</div></div></body></html>',
];
});

View file

@ -0,0 +1,32 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class UpdateMediaEndpointTableAddNullableImageWidthColumn extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('media_endpoint', function (Blueprint $table) {
$table->text('image_widths')->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('media_endpoint', function (Blueprint $table) {
$table->dropColumn('image_widths');
});
}
}

View file

@ -0,0 +1,35 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateLikesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('likes', function (Blueprint $table) {
$table->increments('id');
$table->string('url');
$table->string('author_name')->nullable();
$table->string('author_url')->nullable();
$table->text('content')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('likes');
}
}

View file

@ -18,5 +18,6 @@ class DatabaseSeeder extends Seeder
$this->call(NotesTableSeeder::class); $this->call(NotesTableSeeder::class);
$this->call(WebMentionsTableSeeder::class); $this->call(WebMentionsTableSeeder::class);
$this->call(IndieWebUserTableSeeder::class); $this->call(IndieWebUserTableSeeder::class);
$this->call(LikesTableSeeder::class);
} }
} }

View file

@ -0,0 +1,16 @@
<?php
use Illuminate\Database\Seeder;
class LikesTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
factory(App\Like::class, 10)->create();
}
}

View file

@ -12,6 +12,7 @@ class NotesTableSeeder extends Seeder
public function run() public function run()
{ {
factory(App\Note::class, 10)->create(); factory(App\Note::class, 10)->create();
sleep(1);
$noteWithPlace = App\Note::create([ $noteWithPlace = App\Note::create([
'note' => 'Having a #beer at the local. 🍺', 'note' => 'Having a #beer at the local. 🍺',
'tweet_id' => '123456789', 'tweet_id' => '123456789',
@ -19,17 +20,21 @@ class NotesTableSeeder extends Seeder
$place = App\Place::find(1); $place = App\Place::find(1);
$noteWithPlace->place()->associate($place); $noteWithPlace->place()->associate($place);
$noteWithPlace->save(); $noteWithPlace->save();
sleep(1);
$noteWithContact = App\Note::create([ $noteWithContact = App\Note::create([
'note' => 'Hi @tantek' 'note' => 'Hi @tantek'
]); ]);
sleep(1);
$noteWithContactPlusPic = App\Note::create([ $noteWithContactPlusPic = App\Note::create([
'note' => 'Hi @aaron', 'note' => 'Hi @aaron',
'client_id' => 'https://jbl5.dev/notes/new' 'client_id' => 'https://jbl5.dev/notes/new'
]); ]);
sleep(1);
$noteWithoutContact = App\Note::create([ $noteWithoutContact = App\Note::create([
'note' => 'Hi @bob', 'note' => 'Hi @bob',
'client_id' => 'https://quill.p3k.io' 'client_id' => 'https://quill.p3k.io'
]); ]);
sleep(1);
//copy aarons profile pic in place //copy aarons profile pic in place
$spl = new SplFileInfo(public_path() . '/assets/profile-images/aaronparecki.com'); $spl = new SplFileInfo(public_path() . '/assets/profile-images/aaronparecki.com');
if ($spl->isDir() === false) { if ($spl->isDir() === false) {
@ -40,6 +45,7 @@ class NotesTableSeeder extends Seeder
'note' => 'Note from somehwere', 'note' => 'Note from somehwere',
'location' => '53.499,-2.379' 'location' => '53.499,-2.379'
]); ]);
sleep(1);
$noteSyndicated = App\Note::create([ $noteSyndicated = App\Note::create([
'note' => 'This note has all the syndication targets', 'note' => 'This note has all the syndication targets',
'tweet_id' => '123456', 'tweet_id' => '123456',

View file

@ -16,6 +16,7 @@ if (! function_exists('normalize_url')) {
$newUrl = ''; $newUrl = '';
$url = parse_url($url); $url = parse_url($url);
$defaultSchemes = ['http' => 80, 'https' => 443]; $defaultSchemes = ['http' => 80, 'https' => 443];
if (isset($url['scheme'])) { if (isset($url['scheme'])) {
$url['scheme'] = strtolower($url['scheme']); $url['scheme'] = strtolower($url['scheme']);
// Strip scheme default ports // Strip scheme default ports
@ -27,10 +28,12 @@ if (! function_exists('normalize_url')) {
} }
$newUrl .= "{$url['scheme']}://"; $newUrl .= "{$url['scheme']}://";
} }
if (isset($url['host'])) { if (isset($url['host'])) {
$url['host'] = mb_strtolower($url['host']); $url['host'] = mb_strtolower($url['host']);
$newUrl .= $url['host']; $newUrl .= $url['host'];
} }
if (isset($url['port'])) { if (isset($url['port'])) {
$newUrl .= ":{$url['port']}"; $newUrl .= ":{$url['port']}";
} }
@ -63,10 +66,14 @@ if (! function_exists('normalize_url')) {
} }
$url['path'] = preg_replace_callback( $url['path'] = preg_replace_callback(
array_map( array_map(
create_function('$str', 'return "/%" . strtoupper($str) . "/x";'), function ($str) {
return "/%" . strtoupper($str) . "/x";
},
$u $u
), ),
create_function('$matches', 'return chr(hexdec($matches[0]));'), function ($matches) {
return chr(hexdec($matches[0]));
},
$url['path'] $url['path']
); );
// Remove directory index // Remove directory index
@ -197,3 +204,10 @@ if (! function_exists('prettyPrintJson')) {
return str_replace("\t", ' ', $result); return str_replace("\t", ' ', $result);
} }
} }
// sourced from https://twitter.com/jrubsc/status/907776591320764416/photo/1
if (! function_exists('carbon')) {
function carbon(...$args) {
return new Carbon\Carbon(...$args);
}
}

72
package-lock.json generated
View file

@ -29,11 +29,6 @@
"resolved": "https://registry.npmjs.org/@mapbox/whoots-js/-/whoots-js-3.0.0.tgz", "resolved": "https://registry.npmjs.org/@mapbox/whoots-js/-/whoots-js-3.0.0.tgz",
"integrity": "sha1-wd5CkwgUJNo6wwwjr6hQrxAZu1Q=" "integrity": "sha1-wd5CkwgUJNo6wwwjr6hQrxAZu1Q="
}, },
"JSV": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/JSV/-/JSV-4.0.2.tgz",
"integrity": "sha1-0Hf2glVx+CEy+d/67Vh7QCn+/1c="
},
"abbrev": { "abbrev": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz",
@ -3889,6 +3884,14 @@
} }
} }
}, },
"string_decoder": {
"version": "1.0.1",
"bundled": true,
"dev": true,
"requires": {
"safe-buffer": "5.0.1"
}
},
"string-width": { "string-width": {
"version": "1.0.2", "version": "1.0.2",
"bundled": true, "bundled": true,
@ -3899,14 +3902,6 @@
"strip-ansi": "3.0.1" "strip-ansi": "3.0.1"
} }
}, },
"string_decoder": {
"version": "1.0.1",
"bundled": true,
"dev": true,
"requires": {
"safe-buffer": "5.0.1"
}
},
"stringstream": { "stringstream": {
"version": "0.0.5", "version": "0.0.5",
"bundled": true, "bundled": true,
@ -4817,6 +4812,11 @@
} }
} }
}, },
"JSV": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/JSV/-/JSV-4.0.2.tgz",
"integrity": "sha1-0Hf2glVx+CEy+d/67Vh7QCn+/1c="
},
"kdbush": { "kdbush": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/kdbush/-/kdbush-1.0.1.tgz", "resolved": "https://registry.npmjs.org/kdbush/-/kdbush-1.0.1.tgz",
@ -7587,6 +7587,21 @@
"integrity": "sha1-Rb8dny19wJvtgfHDB8Qw5ouEz/4=", "integrity": "sha1-Rb8dny19wJvtgfHDB8Qw5ouEz/4=",
"dev": true "dev": true
}, },
"string_decoder": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.2.tgz",
"integrity": "sha1-sp4fThEl+pehA4K4pTNze3SR4Xk=",
"requires": {
"safe-buffer": "5.0.1"
},
"dependencies": {
"safe-buffer": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz",
"integrity": "sha1-0mPKVGls2KMGtcplUekt5XkY++c="
}
}
},
"string-length": { "string-length": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/string-length/-/string-length-1.0.1.tgz", "resolved": "https://registry.npmjs.org/string-length/-/string-length-1.0.1.tgz",
@ -7605,21 +7620,6 @@
"strip-ansi": "3.0.1" "strip-ansi": "3.0.1"
} }
}, },
"string_decoder": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.2.tgz",
"integrity": "sha1-sp4fThEl+pehA4K4pTNze3SR4Xk=",
"requires": {
"safe-buffer": "5.0.1"
},
"dependencies": {
"safe-buffer": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz",
"integrity": "sha1-0mPKVGls2KMGtcplUekt5XkY++c="
}
}
},
"stringify-object": { "stringify-object": {
"version": "3.2.0", "version": "3.2.0",
"resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.2.0.tgz", "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.2.0.tgz",
@ -8520,14 +8520,6 @@
} }
} }
}, },
"webStorage": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/webStorage/-/webStorage-1.2.4.tgz",
"integrity": "sha1-/jNN8N5uLe58i9A2uxVaw115FTY=",
"requires": {
"gr-event-dispatcher": "1.1.1"
}
},
"webpack": { "webpack": {
"version": "3.5.6", "version": "3.5.6",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-3.5.6.tgz", "resolved": "https://registry.npmjs.org/webpack/-/webpack-3.5.6.tgz",
@ -8790,6 +8782,14 @@
} }
} }
}, },
"webStorage": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/webStorage/-/webStorage-1.2.4.tgz",
"integrity": "sha1-/jNN8N5uLe58i9A2uxVaw115FTY=",
"requires": {
"gr-event-dispatcher": "1.1.1"
}
},
"webworkify": { "webworkify": {
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/webworkify/-/webworkify-1.4.0.tgz", "resolved": "https://registry.npmjs.org/webworkify/-/webworkify-1.4.0.tgz",

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

View file

@ -1 +1 @@
{"version":3,"sources":["../../../resources/assets/sass/app.scss","../../../resources/assets/sass/layout.scss","../../../resources/assets/sass/styles.scss","../../../resources/assets/sass/pagination.scss","../../../resources/assets/sass/note-form.scss","../../../resources/assets/sass/mapbox.scss","../../../resources/assets/sass/contacts.scss","../../../resources/assets/sass/emoji.scss","../../../resources/assets/sass/bridgy-links.scss"],"names":[],"mappings":"AAIA,KACI,8BACA,AADA,sBACA,cAAe,CAClB,qBAKG,2BAAmB,AAAnB,kBAAmB,CACtB,KCVG,eACA,cACA,iBACA,kBACA,oBAAqB,CACxB,WAGG,iBAAkB,CACrB,SAGG,gBAAiB,CACpB,MAGG,oBACA,AADA,oBACA,AADA,aACA,4BAAsB,AAAtB,6BAAsB,AAAtB,0BAAsB,AAAtB,qBAAsB,CACzB,eAGG,oBACA,AADA,oBACA,AADA,aACA,8BACA,AADA,6BACA,AADA,uBACA,AADA,mBACA,yBACA,AADA,sBACA,AADA,8BACA,gBAAiB,CACpB,UAGG,gBACA,WACA,eACA,4BAA6B,CAChC,cAGG,oBACA,AADA,oBACA,AADA,aACA,yBAAmB,AAAnB,sBAAmB,AAAnB,kBAAmB,CACtB,kBAGG,gBAAiB,CACpB,aAGG,iBAAkB,CACrB,qBAGG,kBACA,WAAY,CACf,wBAGG,YAAa,CAChB,8BAGG,eACA,uBACA,sBACA,kBACA,gBACA,WACA,UACA,WACA,2BAA4B,CAC/B,oBAGG,kBACA,SACA,WACA,WACA,YACA,mBAAoB,CACvB,wBAGG,aAAc,CACjB,qBAGG,aACA,eAAgB,CACnB,aAGG,eACA,yBAA0B,CAC7B,OAGG,eAAgB,CACnB,cAGG,eAAgB,CACnB,WAGG,eACA,cACA,iBAAkB,CACrB,sBAGG,cAAe,CAClB,sBAGG,iBACA,cAAe,CAClB,WAGG,kBACA,WACA,SACA,qBAAsB,CACzB,SAGG,kBACA,MACA,OACA,WACA,WAAY,CACf,KC9HG,6JAWc,CACjB,EAGG,qBACA,wBACA,UAAW,CACd,gBAGG,kBAAmB,CACtB,MAGG,WACA,UAAW,CACd,OAGG,iBACA,iBAAkB,CACrB,WAGG,kBAAmB,CACtB,UAGG,YACA,WAAY,CACf,YC1CG,WACA,YACA,oBACA,AADA,oBACA,AADA,aACA,8BACA,AADA,6BACA,AADA,uBACA,AADA,mBACA,yBACA,AADA,sBACA,AADA,8BACA,yBAAmB,AAAnB,sBAAmB,AAAnB,kBAAmB,CACtB,eAGG,oBAAqB,CACxB,SCVG,oBACA,AADA,oBACA,AADA,aACA,4BAAsB,AAAtB,6BAAsB,AAAtB,0BAAsB,AAAtB,qBAAsB,CACzB,0BAGG,aACI,oBACA,AADA,oBACA,AADA,aACA,8BACA,AADA,6BACA,AADA,uBACA,AADA,mBACA,cAAe,CAClB,mBAGG,SAAU,CACb,CAGL,0BACI,mBACI,UAAW,CACd,4BAIG,UAAW,CACd,CAGL,eACI,UACA,oBACA,gBAAiB,CACpB,oDAIG,mBAAO,AAAP,WAAO,AAAP,MAAO,CACV,kBAGG,qBAAsB,CACzB,QAGG,mBAAoB,CACvB,aAGG,oBAAqB,CACxB,cAGG,WACA,SAAU,CACb,KCrDG,eACA,YAAa,CAChB,oBAGG,kBAAmB,CACtB,QAGG,y4HACA,wBACA,WACA,WAAY,CACf,UAGG,kBACA,MACA,OACA,iBACA,cAAe,CAClB,gBAGG,gBACA,gBAAiB,CACpB,SC1BG,oBACA,AADA,oBACA,AADA,aACA,8BACA,AADA,6BACA,AADA,uBACA,AADA,mBACA,eACA,6BAA8B,CACjC,aAGG,oBACA,YACA,YAAa,CAChB,sDCPG,iBAAkB,CACrB,gFAIG,kBACA,cACA,UACA,aACA,OACA,cACA,qBACA,yBACA,oBACA,4CACA,AADA,oCACA,yBACA,kCACA,WACA,cACA,0CAAkC,AAAlC,iCAAkC,CACrC,2BAGG,KACI,aACA,6BACA,wCACA,0BACA,8BAAkC,AAAlC,qBAAkC,CAGtC,GACI,aACA,kCACA,yBACA,WACA,4CAAgD,AAAhD,mCAAgD,CAAA,CAIxD,AApBC,mBAGG,KACI,aACA,6BACA,wCACA,0BACA,8BAAkC,AAAlC,qBAAkC,CAGtC,GACI,aACA,kCACA,yBACA,WACA,4CAAgD,AAAhD,mCAAgD,CAAA,CAIxD,aACI,kCACI,kCAAmC,CACtC,CC/CL,qDAEI,YAAa,CAChB","file":"app.css"} {"version":3,"sources":["../../../resources/assets/sass/app.scss","../../../resources/assets/sass/layout.scss","../../../resources/assets/sass/styles.scss","../../../resources/assets/sass/pagination.scss","../../../resources/assets/sass/note-form.scss","../../../resources/assets/sass/mapbox.scss","../../../resources/assets/sass/contacts.scss","../../../resources/assets/sass/emoji.scss","../../../resources/assets/sass/bridgy-links.scss"],"names":[],"mappings":"AAIA,KACI,8BACA,AADA,sBACA,cAAe,CAClB,qBAKG,2BAAmB,AAAnB,kBAAmB,CACtB,KCVG,eACA,cACA,iBACA,kBACA,oBAAqB,CACxB,WAGG,iBAAkB,CACrB,SAGG,gBAAiB,CACpB,MAGG,oBACA,AADA,oBACA,AADA,aACA,4BAAsB,AAAtB,6BAAsB,AAAtB,0BAAsB,AAAtB,qBAAsB,CACzB,eAGG,oBACA,AADA,oBACA,AADA,aACA,8BACA,AADA,6BACA,AADA,uBACA,AADA,mBACA,yBACA,AADA,sBACA,AADA,8BACA,gBAAiB,CACpB,UAGG,gBACA,WACA,eACA,4BAA6B,CAChC,cAGG,oBACA,AADA,oBACA,AADA,aACA,yBAAmB,AAAnB,sBAAmB,AAAnB,kBAAmB,CACtB,kBAGG,gBAAiB,CACpB,aAGG,iBAAkB,CACrB,qBAGG,kBACA,WAAY,CACf,wBAGG,YAAa,CAChB,8BAGG,eACA,uBACA,sBACA,kBACA,gBACA,WACA,UACA,WACA,2BAA4B,CAC/B,oBAGG,kBACA,SACA,WACA,WACA,YACA,mBAAoB,CACvB,wBAGG,aAAc,CACjB,qBAGG,aACA,eAAgB,CACnB,aAGG,eACA,yBAA0B,CAC7B,OAGG,eAAgB,CACnB,cAGG,eAAgB,CACnB,WAGG,eACA,cACA,iBAAkB,CACrB,sBAGG,cAAe,CAClB,sBAGG,iBACA,cAAe,CAClB,WAGG,kBACA,WACA,SACA,qBAAsB,CACzB,SAGG,kBACA,MACA,OACA,WACA,WAAY,CACf,KC9HG,6JAWc,CACjB,EAGG,qBACA,wBACA,UAAW,CACd,aAGG,mBACA,aAAc,CACjB,gBAGG,kBAAmB,CACtB,MAGG,WACA,UAAW,CACd,OAGG,iBACA,iBAAkB,CACrB,WAGG,kBAAmB,CACtB,UAGG,YACA,WAAY,CACf,YC/CG,WACA,YACA,oBACA,AADA,oBACA,AADA,aACA,8BACA,AADA,6BACA,AADA,uBACA,AADA,mBACA,yBACA,AADA,sBACA,AADA,8BACA,yBAAmB,AAAnB,sBAAmB,AAAnB,kBAAmB,CACtB,eAGG,oBAAqB,CACxB,SCVG,oBACA,AADA,oBACA,AADA,aACA,4BAAsB,AAAtB,6BAAsB,AAAtB,0BAAsB,AAAtB,qBAAsB,CACzB,0BAGG,aACI,oBACA,AADA,oBACA,AADA,aACA,8BACA,AADA,6BACA,AADA,uBACA,AADA,mBACA,cAAe,CAClB,mBAGG,SAAU,CACb,CAGL,0BACI,mBACI,UAAW,CACd,4BAIG,UAAW,CACd,CAGL,eACI,UACA,oBACA,gBAAiB,CACpB,oDAIG,mBAAO,AAAP,WAAO,AAAP,MAAO,CACV,kBAGG,qBAAsB,CACzB,QAGG,mBAAoB,CACvB,aAGG,oBAAqB,CACxB,cAGG,WACA,SAAU,CACb,KCrDG,eACA,YAAa,CAChB,oBAGG,kBAAmB,CACtB,QAGG,y4HACA,wBACA,WACA,WAAY,CACf,UAGG,kBACA,MACA,OACA,iBACA,cAAe,CAClB,gBAGG,gBACA,gBAAiB,CACpB,SC1BG,oBACA,AADA,oBACA,AADA,aACA,8BACA,AADA,6BACA,AADA,uBACA,AADA,mBACA,eACA,6BAA8B,CACjC,aAGG,oBACA,YACA,YAAa,CAChB,sDCPG,iBAAkB,CACrB,gFAIG,kBACA,cACA,UACA,aACA,OACA,cACA,qBACA,yBACA,oBACA,4CACA,AADA,oCACA,yBACA,kCACA,WACA,cACA,0CAAkC,AAAlC,iCAAkC,CACrC,2BAGG,KACI,aACA,6BACA,wCACA,0BACA,8BAAkC,AAAlC,qBAAkC,CAGtC,GACI,aACA,kCACA,yBACA,WACA,4CAAgD,AAAhD,mCAAgD,CAAA,CAIxD,AApBC,mBAGG,KACI,aACA,6BACA,wCACA,0BACA,8BAAkC,AAAlC,qBAAkC,CAGtC,GACI,aACA,kCACA,yBACA,WACA,4CAAgD,AAAhD,mCAAgD,CAAA,CAIxD,aACI,kCACI,kCAAmC,CACtC,CC/CL,qDAEI,YAAa,CAChB","file":"app.css"}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -22,6 +22,11 @@ a {
color: blue; color: blue;
} }
a.naked-link {
border-bottom: none;
color: inherit;
}
.social-links a { .social-links a {
border-bottom: none; border-bottom: none;
} }

View file

@ -0,0 +1,27 @@
@extends('master')
@section('title')
Likes «
@stop
@section('content')
<div class="h-feed">
@foreach($likes as $like)
<div class="h-entry">
<div class="h-cite u-like-of">
Liked <a class="u-url" href="{{ $like->url }}">a post</a> by
<span class="p-author h-card">
@isset($like->author_url)
<a class="u-url p-name" href="{{ $like->author_url }}">{{ $like->author_name }}</a>
@else
<span class="p-name">{{ $like->author_name }}</span>
@endisset
</span>:
<blockquote class="e-content">
{!! $like->content !!}
</blockquote>
</div>
</div>
@endforeach
</div>
@stop

View file

@ -0,0 +1,23 @@
@extends('master')
@section('title')
Like «
@stop
@section('content')
<div class="h-entry">
<div class="h-cite u-like-of">
Liked <a class="u-url" href="{{ $like->url }}">a post</a> by
<span class="p-author h-card">
@isset($like->author_url)
<a class="u-url p-name" href="{{ $like->author_url }}">{{ $like->author_name }}</a>
@else
<span class="p-name">{{ $like->author_name }}</span>
@endisset
</span>:
<blockquote class="e-content">
{!! $like->content !!}
</blockquote>
</div>
</div>
@stop

View file

@ -9,7 +9,7 @@
<div class="e-content p-name"> <div class="e-content p-name">
{!! $note->note !!} {!! $note->note !!}
@foreach($note->media as $media) @foreach($note->media as $media)
@if($media->type == 'image')<img class="u-photo" src="{{ $media->url }}" alt="">@endif @if($media->type == 'image')<a class="naked-link" href="{{ $media->url }}"><img class="u-photo" src="{{ $media->url }}" alt="" @if($media->image_widths !== null) srcset="{{ $media->url }} {{ $media->image_widths }}w, {{ $media->mediumurl }} 1000w, {{ $media->smallurl }} 500w" sizes="80vh"@endif></a>@endif
@if($media->type == 'audio')<audio class="u-audio" src="{{ $media->url }}" controls>@endif @if($media->type == 'audio')<audio class="u-audio" src="{{ $media->url }}" controls>@endif
@if($media->type == 'video')<video class="u-video" src="{{ $media->url }}" controls>@endif @if($media->type == 'video')<video class="u-video" src="{{ $media->url }}" controls>@endif
@if($media->type == 'download')<p><a class="u-attachment" href="{{ $media->url }}">Download the attached media</a></p>@endif @if($media->type == 'download')<p><a class="u-attachment" href="{{ $media->url }}">Download the attached media</a></p>@endif

View file

@ -108,6 +108,12 @@ Route::group(['domain' => config('url.longurl')], function () {
}); });
Route::get('note/{id}', 'NotesController@redirect'); // for legacy note URLs Route::get('note/{id}', 'NotesController@redirect'); // for legacy note URLs
// Likes
Route::group(['prefix' => 'likes'], function () {
Route::get('/', 'LikesController@index');
Route::get('/{like}', 'LikesController@show');
});
// Micropub Client // Micropub Client
Route::group(['prefix' => 'micropub'], function () { Route::group(['prefix' => 'micropub'], function () {
Route::get('/create', 'MicropubClientController@create')->name('micropub-client'); Route::get('/create', 'MicropubClientController@create')->name('micropub-client');

View file

@ -9,7 +9,10 @@ git pull
echo "Updating composer and dependencies" echo "Updating composer and dependencies"
sudo composer self-update sudo composer self-update
composer install --no-dev composer install --no-dev --optimize-autoloader
echo "running any migrations"
php artisan migrate
echo "Caching Laravel route and config files" echo "Caching Laravel route and config files"
php artisan route:cache php artisan route:cache

View file

@ -1,23 +0,0 @@
<?php
namespace Tests\Browser;
use Tests\DuskTestCase;
use Laravel\Dusk\Browser;
use Illuminate\Foundation\Testing\DatabaseMigrations;
class ExampleTest extends DuskTestCase
{
/**
* A basic browser test example.
*
* @return void
*/
public function test_basic_example()
{
$this->browse(function (Browser $browser) {
$browser->visit('/')
->assertSee('Built with love');
});
}
}

View file

@ -0,0 +1,50 @@
<?php
namespace Tests\Feature;
use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
class ActivityStreamTest extends TestCase
{
/**
* Test request to homepage returns data for site owner.
*
* @return void
*/
public function test_homepage_returns_data_for_site_owner()
{
$response = $this->get('/', ['Accept' => 'application/activity+json']);
$response->assertHeader('Content-Type', 'application/activity+json');
$response->assertJson([
'@context' => 'https://www.w3.org/ns/activitystreams',
'id' => config('app.url'),
'type' => 'Person',
'name' => config('user.displayname'),
]);
}
/**
* Test request to a single note returns AS2.0 data.
*
* @return void
*/
public function test_single_note_returns_as_data()
{
$note = \App\Note::find(11);
$response = $this->get('/notes/B', ['Accept' => 'application/activity+json']);
$response->assertHeader('Content-Type', 'application/activity+json');
$response->assertJson([
'@context' => 'https://www.w3.org/ns/activitystreams',
'type' => 'Add',
'actor' => [
'type' => 'Person',
'id' => config('app.url'),
],
'object' => [
'type' => 'Note',
'name' => strip_tags($note->note)
]
]);
}
}

View file

@ -1,21 +0,0 @@
<?php
namespace Tests\Feature;
use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
class ExampleTest extends TestCase
{
/**
* A basic test example.
*
* @return void
*/
public function testBasicTest()
{
$response = $this->get('/');
$response->assertStatus(200);
}
}

View file

@ -0,0 +1,88 @@
<?php
namespace Tests\Feature;
use Queue;
use App\Like;
use Tests\TestCase;
use Tests\TestToken;
use GuzzleHttp\Client;
use App\Jobs\ProcessLike;
use Lcobucci\JWT\Builder;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Psr7\Response;
use GuzzleHttp\Handler\MockHandler;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Jonnybarnes\WebmentionsParser\Authorship;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class LikesTest extends TestCase
{
use DatabaseTransactions, TestToken;
public function test_likes_page()
{
$response = $this->get('/likes');
$response->assertViewIs('likes.index');
}
public function test_single_like_page()
{
$response = $this->get('/likes');
$response->assertViewIs('likes.index');
}
public function test_like_micropub_request()
{
Queue::fake();
$response = $this->withHeaders([
'Authorization' => 'Bearer ' . $this->getToken(),
])->json('POST', '/api/post', [
'type' => ['h-entry'],
'properties' => [
'like-of' => ['https://example.org/blog-post'],
],
]);
$response->assertJson(['response' => 'created']);
Queue::assertPushed(ProcessLike::class);
$this->assertDatabaseHas('likes', ['url' => 'https://example.org/blog-post']);
}
public function test_process_like_job()
{
$like = new Like();
$like->url = 'http://example.org/note/id';
$like->save();
$id = $like->id;
$job = new ProcessLike($like);
$content = <<<END
<html>
<body>
<div class="h-entry">
<div class="e-content">
A post that I like.
</div>
by <span class="p-author">Fred Bloggs</span>
</div>
</body>
</html>
END;
$mock = new MockHandler([
new Response(200, [], $content),
new Response(200, [], $content),
]);
$handler = HandlerStack::create($mock);
$client = new Client(['handler' => $handler]);
$this->app->bind(Client::class, $client);
$authorship = new Authorship();
$job->handle($client, $authorship);
$this->assertEquals('Fred Bloggs', Like::find($id)->author_name);
}
}

View file

@ -38,6 +38,7 @@ class MicropubClientControllerTest extends TestCase
'mp-syndicate-to' => ['https://twitter.com/jonnybarnes', 'https://facebook.com/jonnybarnes'], 'mp-syndicate-to' => ['https://twitter.com/jonnybarnes', 'https://facebook.com/jonnybarnes'],
] ]
); );
$expected = '{"type":["h-entry"],"properties":{"content":["Hello Fred"],"in-reply-to":["https:\/\/fredbloggs.com\/note\/abc"],"mp-syndicate-to":["https:\/\/twitter.com\/jonnybarnes","https:\/\/facebook.com\/jonnybarnes"]}}'; $expected = '{"type":["h-entry"],"properties":{"content":["Hello Fred"],"in-reply-to":["https:\/\/fredbloggs.com\/note\/abc"],"mp-syndicate-to":["https:\/\/twitter.com\/jonnybarnes","https:\/\/facebook.com\/jonnybarnes"]}}';
foreach ($container as $transaction) { foreach ($container as $transaction) {

View file

@ -3,13 +3,14 @@
namespace Tests\Feature; namespace Tests\Feature;
use Tests\TestCase; use Tests\TestCase;
use Tests\TestToken;
use Lcobucci\JWT\Builder; use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Signer\Hmac\Sha256; use Lcobucci\JWT\Signer\Hmac\Sha256;
use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Foundation\Testing\DatabaseTransactions;
class MicropubControllerTest extends TestCase class MicropubControllerTest extends TestCase
{ {
use DatabaseTransactions; use DatabaseTransactions, TestToken;
/** /**
* Test a GET request for the micropub endpoint without a token gives a * Test a GET request for the micropub endpoint without a token gives a
@ -314,42 +315,4 @@ class MicropubControllerTest extends TestCase
'swarm_url' => 'https://www.swarmapp.com/checkin/123' 'swarm_url' => 'https://www.swarmapp.com/checkin/123'
]); ]);
} }
/**
* Generate a valid token to be used in the tests.
*
* @return Lcobucci\JWT\Token\Plain $token
*/
private function getToken()
{
$signer = new Sha256();
$token = (new Builder())
->set('client_id', 'https://quill.p3k.io')
->set('me', 'https://jonnybarnes.localhost')
->set('scope', 'create update')
->set('issued_at', time())
->sign($signer, env('APP_KEY'))
->getToken();
return $token;
}
/**
* Generate an invalid token to be used in the tests.
*
* @return Lcobucci\JWT\Token\Plain $token
*/
private function getInvalidToken()
{
$signer = new Sha256();
$token = (new Builder())
->set('client_id', 'https://quill.p3k.io')
->set('me', 'https://jonnybarnes.localhost')
->set('scope', 'view') //error here
->set('issued_at', time())
->sign($signer, env('APP_KEY'))
->getToken();
return $token;
}
} }

View file

@ -3,13 +3,14 @@
namespace Tests\Feature; namespace Tests\Feature;
use Tests\TestCase; use Tests\TestCase;
use Tests\TestToken;
use Lcobucci\JWT\Builder; use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Signer\Hmac\Sha256; use Lcobucci\JWT\Signer\Hmac\Sha256;
use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Foundation\Testing\DatabaseTransactions;
class OwnYourGramTest extends TestCase class OwnYourGramTest extends TestCase
{ {
use DatabaseTransactions; use DatabaseTransactions, TestToken;
public function test_ownyourgram_post() public function test_ownyourgram_post()
{ {
@ -40,18 +41,4 @@ class OwnYourGramTest extends TestCase
'instagram_url' => 'https://www.instagram.com/p/BVC_nVTBFfi/' 'instagram_url' => 'https://www.instagram.com/p/BVC_nVTBFfi/'
]); ]);
} }
private function getToken()
{
$signer = new Sha256();
$token = (new Builder())
->set('client_id', 'https://ownyourgram.com')
->set('me', config('app.url'))
->set('scope', 'create')
->set('issued_at', time())
->sign($signer, env('APP_KEY'))
->getToken();
return $token;
}
} }

View file

@ -0,0 +1,43 @@
<?php
namespace Tests\Feature;
use Storage;
use Tests\TestCase;
use Intervention\Image\ImageManager;
class ProcessImageTest extends TestCase
{
public function test_job_does_nothing_to_non_image()
{
$manager = app()->make(ImageManager::class);
Storage::disk('local')->put('file.txt', 'This is not an image');
$job = new \App\Jobs\ProcessImage('file.txt');
$job->handle($manager);
$this->assertFalse(file_exists(storage_path('app') . '/file.txt'));
}
public function test_job_does_nothing_to_small_images()
{
$manager = app()->make(ImageManager::class);
Storage::disk('local')->put('aaron.png', file_get_contents(__DIR__.'/../aaron.png'));
$job = new \App\Jobs\ProcessImage('aaron.png');
$job->handle($manager);
$this->assertFalse(file_exists(storage_path('app') . '/aaron.png'));
}
public function test_large_images_have_smaller_files_created()
{
$manager = app()->make(ImageManager::class);
Storage::disk('local')->put('test-image.jpg', file_get_contents(__DIR__.'/../test-image.jpg'));
Storage::fake('s3');
$job = new \App\Jobs\ProcessImage('test-image.jpg');
$job->handle($manager);
Storage::disk('s3')->assertExists('media/test-image-small.jpg');
Storage::disk('s3')->assertExists('media/test-image-medium.jpg');
$this->assertFalse(file_exists(storage_path('app') . '/test-image.jpg'));
}
}

View file

@ -3,13 +3,14 @@
namespace Tests\Feature; namespace Tests\Feature;
use Tests\TestCase; use Tests\TestCase;
use Tests\TestToken;
use Lcobucci\JWT\Builder; use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Signer\Hmac\Sha256; use Lcobucci\JWT\Signer\Hmac\Sha256;
use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Foundation\Testing\DatabaseTransactions;
class SwarmTest extends TestCase class SwarmTest extends TestCase
{ {
use DatabaseTransactions; use DatabaseTransactions, TestToken;
public function test_faked_ownyourswarm_request() public function test_faked_ownyourswarm_request()
{ {
@ -82,23 +83,4 @@ class SwarmTest extends TestCase
'swarm_url' => 'https://www.swarmapp.com/checkin/def' 'swarm_url' => 'https://www.swarmapp.com/checkin/def'
]); ]);
} }
/**
* Generate a valid token to be used in the tests.
*
* @return Lcobucci\JWT\Token\Plain $token
*/
private function getToken()
{
$signer = new Sha256();
$token = (new Builder())
->set('client_id', 'https://ownyourswarm.p3k.io')
->set('me', 'https://jonnybarnes.localhost')
->set('scope', 'create update')
->set('issued_at', time())
->sign($signer, env('APP_KEY'))
->getToken();
return $token;
}
} }

37
tests/TestToken.php Normal file
View file

@ -0,0 +1,37 @@
<?php
namespace Tests;
use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Signer\Hmac\Sha256;
trait TestToken
{
public function getToken()
{
$signer = new Sha256();
$token = (new Builder())
->set('client_id', 'https://quill.p3k.io')
->set('me', 'https://jonnybarnes.localhost')
->set('scope', 'create update')
->set('issued_at', time())
->sign($signer, env('APP_KEY'))
->getToken();
return $token;
}
public function getInvalidToken()
{
$signer = new Sha256();
$token = (new Builder())
->set('client_id', 'https://quill.p3k.io')
->set('me', 'https://jonnybarnes.localhost')
->set('scope', 'view') //error here
->set('issued_at', time())
->sign($signer, env('APP_KEY'))
->getToken();
return $token;
}
}

View file

@ -1,19 +0,0 @@
<?php
namespace Tests\Unit;
use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
class ExampleTest extends TestCase
{
/**
* A basic test example.
*
* @return void
*/
public function testBasicTest()
{
$this->assertTrue(true);
}
}

BIN
tests/test-image.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB