Merge branch 'release/0.5'
This commit is contained in:
commit
a7117b3972
55 changed files with 2324 additions and 1231 deletions
|
@ -22,7 +22,7 @@ REDIS_PASSWORD=null
|
||||||
REDIS_PORT=6379
|
REDIS_PORT=6379
|
||||||
|
|
||||||
MAIL_DRIVER=smtp
|
MAIL_DRIVER=smtp
|
||||||
MAIL_HOST=mailtrap.io
|
MAIL_HOST=smtp.mailtrap.io
|
||||||
MAIL_PORT=2525
|
MAIL_PORT=2525
|
||||||
MAIL_USERNAME=null
|
MAIL_USERNAME=null
|
||||||
MAIL_PASSWORD=null
|
MAIL_PASSWORD=null
|
||||||
|
@ -52,3 +52,5 @@ TWITTER_ACCESS_TOKEN_SECRET=
|
||||||
SCOUT_DRIVER=pgsql
|
SCOUT_DRIVER=pgsql
|
||||||
|
|
||||||
PIWIK=false
|
PIWIK=false
|
||||||
|
|
||||||
|
PSYSH_CONFIG=tinker.config.php
|
||||||
|
|
1
.gitattributes
vendored
1
.gitattributes
vendored
|
@ -1,3 +1,4 @@
|
||||||
* text=auto
|
* text=auto
|
||||||
*.css linguist-vendored
|
*.css linguist-vendored
|
||||||
*.scss linguist-vendored
|
*.scss linguist-vendored
|
||||||
|
*.js linguist-vendored
|
||||||
|
|
|
@ -19,6 +19,7 @@ addons:
|
||||||
paths:
|
paths:
|
||||||
- $(ls tests/Browser/screenshots/*.png | tr "\n" ":")
|
- $(ls tests/Browser/screenshots/*.png | tr "\n" ":")
|
||||||
- $(ls tests/Browser/console/*.log | tr "\n" ":")
|
- $(ls tests/Browser/console/*.log | tr "\n" ":")
|
||||||
|
- $(ls storage/logs/*.log | tr "\n" ":")
|
||||||
- $(ls /tmp/*.log | tr "\n" ":")
|
- $(ls /tmp/*.log | tr "\n" ":")
|
||||||
|
|
||||||
services:
|
services:
|
||||||
|
@ -49,16 +50,18 @@ install:
|
||||||
- travis/install-nginx.sh
|
- travis/install-nginx.sh
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
|
- 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'
|
||||||
- psql -U travis -d travis_ci_test -c 'create extension postgis'
|
- psql -U travis -d travis_ci_test -c 'create extension postgis'
|
||||||
- cp .env.travis .env
|
- cp .env.travis .env
|
||||||
- php artisan key:generate
|
- php artisan key:generate
|
||||||
- php artisan migrate
|
- php artisan migrate
|
||||||
- php artisan db:seed
|
- php artisan db:seed
|
||||||
|
- php artisan token:generate
|
||||||
- phantomjs --webdriver=127.0.0.1:9515 --webdriver-loglevel=DEBUG &
|
- phantomjs --webdriver=127.0.0.1:9515 --webdriver-loglevel=DEBUG &
|
||||||
- sleep 5 # Give artisan some time to start serving
|
- sleep 5 # Give artisan some time to start serving
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- php vendor/bin/phpunit --coverage-text
|
- php vendor/bin/phpunit --coverage-text
|
||||||
- php artisan dusk
|
- php artisan dusk
|
||||||
- php artisan security:check
|
- php vendor/bin/security-checker security:check ./composer.lock --end-point=http://security.sensiolabs.org/check_lock
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
|
|
||||||
namespace App\Console\Commands;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\IndieWebUser;
|
||||||
use App\Services\TokenService;
|
use App\Services\TokenService;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use Illuminate\Support\Facades\Storage;
|
|
||||||
|
|
||||||
class GenerateToken extends Command
|
class GenerateToken extends Command
|
||||||
{
|
{
|
||||||
|
@ -49,10 +49,12 @@ class GenerateToken extends Command
|
||||||
$data = [
|
$data = [
|
||||||
'me' => config('app.url'),
|
'me' => config('app.url'),
|
||||||
'client_id' => route('micropub-client'),
|
'client_id' => route('micropub-client'),
|
||||||
'scope' => 'post',
|
'scope' => 'create update',
|
||||||
];
|
];
|
||||||
$token = $tokenService->getNewToken($data);
|
$token = $tokenService->getNewToken($data);
|
||||||
Storage::disk('local')->put('dev-token', $token);
|
$user = IndieWebUser::where('me', config('app.url'))->first();
|
||||||
|
$user->token = $token;
|
||||||
|
$user->save();
|
||||||
|
|
||||||
$this->info('Set token');
|
$this->info('Set token');
|
||||||
}
|
}
|
||||||
|
|
13
app/Exceptions/InvalidTokenException.php
Normal file
13
app/Exceptions/InvalidTokenException.php
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Exceptions;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
class InvalidTokenException extends Exception
|
||||||
|
{
|
||||||
|
public function __construct($message, $code = 0, Exception $previous = null)
|
||||||
|
{
|
||||||
|
parent::__construct($message, $code, $previous);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,35 +2,26 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\IndieWebUser;
|
||||||
|
use IndieAuth\Client;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Services\TokenService;
|
|
||||||
use App\Services\IndieAuthService;
|
|
||||||
|
|
||||||
class IndieAuthController extends Controller
|
class IndieAuthController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* This service isolates the IndieAuth Client code.
|
* The IndieAuth Client.
|
||||||
*/
|
*/
|
||||||
protected $indieAuthService;
|
protected $client;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Token handling service.
|
* Inject the dependency.
|
||||||
*/
|
|
||||||
protected $tokenService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inject the dependencies.
|
|
||||||
*
|
*
|
||||||
* @param \App\Services\IndieAuthService $indieAuthService
|
* @param \IndieAuth\Client $client
|
||||||
* @param \App\Services\TokenService $tokenService
|
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(Client $client = null)
|
||||||
IndieAuthService $indieAuthService = null,
|
{
|
||||||
TokenService $tokenService = null
|
$this->client = $client ?? new Client();
|
||||||
) {
|
|
||||||
$this->indieAuthService = $indieAuthService ?? new IndieAuthService();
|
|
||||||
$this->tokenService = $tokenService ?? new TokenService();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -44,25 +35,31 @@ class IndieAuthController extends Controller
|
||||||
*/
|
*/
|
||||||
public function start(Request $request)
|
public function start(Request $request)
|
||||||
{
|
{
|
||||||
$authorizationEndpoint = $this->indieAuthService->getAuthorizationEndpoint(
|
$url = normalize_url($request->input('me'));
|
||||||
$request->input('me')
|
$authorizationEndpoint = $this->client->discoverAuthorizationEndpoint($url);
|
||||||
);
|
if ($authorizationEndpoint != null) {
|
||||||
if ($authorizationEndpoint !== null) {
|
$state = bin2hex(openssl_random_pseudo_bytes(16));
|
||||||
$authorizationURL = $this->indieAuthService->buildAuthorizationURL(
|
session(['state' => $state]);
|
||||||
|
$authorizationURL = $this->client->buildAuthorizationURL(
|
||||||
$authorizationEndpoint,
|
$authorizationEndpoint,
|
||||||
$request->input('me')
|
$url,
|
||||||
|
route('indieauth-callback'), //redirect_uri
|
||||||
|
route('micropub-client'), //client_id
|
||||||
|
$state
|
||||||
);
|
);
|
||||||
if ($authorizationURL) {
|
if ($authorizationURL) {
|
||||||
return redirect($authorizationURL);
|
return redirect($authorizationURL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return redirect(route('micropub-client'))->with('error', 'Error building authorization URL');
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect(route('micropub-client'))->with('error', 'Unable to determine authorisation endpoint');
|
return redirect(route('micropub-client'))->with('error', 'Unable to determine authorisation endpoint');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Once they have verified themselves through the authorisation endpint
|
* Once they have verified themselves through the authorisation endpoint
|
||||||
* the next step is retreiveing a token from the token endpoint.
|
* the next step is register/login the user.
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Http\Rrequest $request
|
* @param \Illuminate\Http\Rrequest $request
|
||||||
* @return \Illuminate\Routing\RedirectResponse redirect
|
* @return \Illuminate\Routing\RedirectResponse redirect
|
||||||
|
@ -75,38 +72,16 @@ class IndieAuthController extends Controller
|
||||||
'Invalid <code>state</code> value returned from indieauth server'
|
'Invalid <code>state</code> value returned from indieauth server'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
$tokenEndpoint = $this->indieAuthService->getTokenEndpoint($request->input('me'));
|
|
||||||
if ($tokenEndpoint === false) {
|
|
||||||
return redirect(route('micropub-client'))->with(
|
|
||||||
'error',
|
|
||||||
'Unable to determine token endpoint'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
$data = [
|
|
||||||
'endpoint' => $tokenEndpoint,
|
|
||||||
'code' => $request->input('code'),
|
|
||||||
'me' => $request->input('me'),
|
|
||||||
'redirect_url' => route('indieauth-callback'),
|
|
||||||
'client_id' => route('micropub-client'),
|
|
||||||
'state' => $request->input('state'),
|
|
||||||
];
|
|
||||||
$token = $this->indieAuthService->getAccessToken($data);
|
|
||||||
|
|
||||||
if (array_key_exists('access_token', $token)) {
|
$url = normalize_url($request->input('me'));
|
||||||
$request->session()->put('me', $token['me']);
|
$indiewebUser = IndieWebUser::firstOrCreate(['me' => $url]);
|
||||||
$request->session()->put('token', $token['access_token']);
|
$request->session()->put(['me' => $url]);
|
||||||
|
|
||||||
return redirect(route('micropub-client'));
|
return redirect(route('micropub-client'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect(route('micropub-client'))->with(
|
|
||||||
'error',
|
|
||||||
'Unable to get a token from the endpoint'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Log out the user, flush an session data, and overwrite any cookie data.
|
* Log out the user, flush the session data.
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Routing\RedirectResponse redirect
|
* @return \Illuminate\Routing\RedirectResponse redirect
|
||||||
*/
|
*/
|
||||||
|
@ -114,44 +89,6 @@ class IndieAuthController extends Controller
|
||||||
{
|
{
|
||||||
$request->session()->flush();
|
$request->session()->flush();
|
||||||
|
|
||||||
return redirect(route('micropub-client'))->cookie('me', 'loggedout', 1);
|
return redirect(route('micropub-client'));
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If the user has auth’d via IndieAuth, issue a valid token.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
|
||||||
public function tokenEndpoint(Request $request)
|
|
||||||
{
|
|
||||||
$authData = [
|
|
||||||
'code' => $request->input('code'),
|
|
||||||
'me' => $request->input('me'),
|
|
||||||
'redirect_url' => $request->input('redirect_uri'),
|
|
||||||
'client_id' => $request->input('client_id'),
|
|
||||||
'state' => $request->input('state'),
|
|
||||||
];
|
|
||||||
$auth = $this->indieAuthService->verifyIndieAuthCode($authData);
|
|
||||||
if (array_key_exists('me', $auth)) {
|
|
||||||
$scope = $auth['scope'] ?? '';
|
|
||||||
$tokenData = [
|
|
||||||
'me' => $request->input('me'),
|
|
||||||
'client_id' => $request->input('client_id'),
|
|
||||||
'scope' => $auth['scope'],
|
|
||||||
];
|
|
||||||
$token = $this->tokenService->getNewToken($tokenData);
|
|
||||||
$content = http_build_query([
|
|
||||||
'me' => $request->input('me'),
|
|
||||||
'scope' => $scope,
|
|
||||||
'access_token' => $token,
|
|
||||||
]);
|
|
||||||
|
|
||||||
return response($content)
|
|
||||||
->header('Content-Type', 'application/x-www-form-urlencoded');
|
|
||||||
}
|
|
||||||
$content = 'There was an error verifying the authorisation code.';
|
|
||||||
|
|
||||||
return response($content, 400);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Services\IndieAuthService;
|
use App\IndieWebUser;
|
||||||
use IndieAuth\Client as IndieClient;
|
use IndieAuth\Client as IndieClient;
|
||||||
use GuzzleHttp\Client as GuzzleClient;
|
use GuzzleHttp\Client as GuzzleClient;
|
||||||
use Illuminate\Http\{Request, Response};
|
use Illuminate\Http\{Request, Response};
|
||||||
|
@ -10,20 +10,13 @@ use GuzzleHttp\Exception\{ClientException, ServerException};
|
||||||
|
|
||||||
class MicropubClientController extends Controller
|
class MicropubClientController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* The IndieAuth service container.
|
|
||||||
*/
|
|
||||||
protected $indieAuthService;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inject the dependencies.
|
* Inject the dependencies.
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
IndieAuthService $indieAuthService = null,
|
|
||||||
IndieClient $indieClient = null,
|
IndieClient $indieClient = null,
|
||||||
GuzzleClient $guzzleClient = null
|
GuzzleClient $guzzleClient = null
|
||||||
) {
|
) {
|
||||||
$this->indieAuthService = $indieAuthService ?? new IndieAuthService();
|
|
||||||
$this->guzzleClient = $guzzleClient ?? new GuzzleClient();
|
$this->guzzleClient = $guzzleClient ?? new GuzzleClient();
|
||||||
$this->indieClient = $indieClient ?? new IndieClient();
|
$this->indieClient = $indieClient ?? new IndieClient();
|
||||||
}
|
}
|
||||||
|
@ -37,8 +30,11 @@ class MicropubClientController extends Controller
|
||||||
public function create(Request $request)
|
public function create(Request $request)
|
||||||
{
|
{
|
||||||
$url = $request->session()->get('me');
|
$url = $request->session()->get('me');
|
||||||
$syndication = $request->session()->get('syndication');
|
if ($url) {
|
||||||
$mediaEndpoint = $request->session()->get('media-endpoint');
|
$indiewebUser = IndieWebUser::where('me', $url)->first();
|
||||||
|
}
|
||||||
|
$syndication = $this->parseSyndicationTargets($indiewebUser->syndication);
|
||||||
|
$mediaEndpoint = $indiewebUser->mediaEndpoint ?? null;
|
||||||
$mediaURLs = $request->session()->get('media-links');
|
$mediaURLs = $request->session()->get('media-links');
|
||||||
|
|
||||||
return view('micropub.create', compact('url', 'syndication', 'mediaEndpoint', 'mediaURLs'));
|
return view('micropub.create', compact('url', 'syndication', 'mediaEndpoint', 'mediaURLs'));
|
||||||
|
@ -56,19 +52,17 @@ class MicropubClientController extends Controller
|
||||||
return back();
|
return back();
|
||||||
}
|
}
|
||||||
|
|
||||||
$mediaEndpoint = $request->session()->get('media-endpoint');
|
$user = IndieWebUser::where('me', $request->session()->get('me'))->firstOrFail();
|
||||||
if ($mediaEndpoint == null) {
|
if ($user->mediaEndpoint == null || $user->token == null) {
|
||||||
return back();
|
return back();
|
||||||
}
|
}
|
||||||
|
|
||||||
$token = $request->session()->get('token');
|
|
||||||
|
|
||||||
$mediaURLs = [];
|
$mediaURLs = [];
|
||||||
foreach ($request->file('file') as $file) {
|
foreach ($request->file('file') as $file) {
|
||||||
try {
|
try {
|
||||||
$response = $this->guzzleClient->request('POST', $mediaEndpoint, [
|
$response = $this->guzzleClient->request('POST', $user->mediaEndpoint, [
|
||||||
'headers' => [
|
'headers' => [
|
||||||
'Authorization' => 'Bearer ' . $token,
|
'Authorization' => 'Bearer ' . $user->token,
|
||||||
],
|
],
|
||||||
'multipart' => [
|
'multipart' => [
|
||||||
[
|
[
|
||||||
|
@ -109,93 +103,23 @@ class MicropubClientController extends Controller
|
||||||
*/
|
*/
|
||||||
public function store(Request $request)
|
public function store(Request $request)
|
||||||
{
|
{
|
||||||
$domain = $request->session()->get('me');
|
$url = normalize_url($request->session()->get('me'));
|
||||||
$token = $request->session()->get('token');
|
$user = IndieWebUser::where('me', $url)->firstOrFail();
|
||||||
|
|
||||||
$micropubEndpoint = $this->indieAuthService->discoverMicropubEndpoint(
|
if ($user->token == null) {
|
||||||
$domain,
|
return redirect(route('micropub-client'))->with('error', 'You haven’t requested a token yet');
|
||||||
$this->indieClient
|
}
|
||||||
);
|
|
||||||
|
$micropubEndpoint = $this->indieClient->discoverMicropubEndpoint($url);
|
||||||
if (! $micropubEndpoint) {
|
if (! $micropubEndpoint) {
|
||||||
return redirect(route('micropub-client'))->with('error', 'Unable to determine micropub API endpoint');
|
return redirect(route('micropub-client'))->with('error', 'Unable to determine micropub API endpoint');
|
||||||
}
|
}
|
||||||
|
|
||||||
$response = $this->postNoteRequest($request, $micropubEndpoint, $token);
|
$headers = [
|
||||||
|
'Authorization' => 'Bearer ' . $user->token,
|
||||||
|
];
|
||||||
|
|
||||||
if ($response->getStatusCode() == 201) {
|
if ($user->syntax == 'html') {
|
||||||
$request->session()->forget('media-links');
|
|
||||||
$location = $response->getHeader('Location');
|
|
||||||
if (is_array($location)) {
|
|
||||||
return redirect($location[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return redirect($location);
|
|
||||||
}
|
|
||||||
|
|
||||||
return redirect(route('micropub-client'))->with('error', 'Endpoint didn’t create the note.');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show currently stored configuration values.
|
|
||||||
*
|
|
||||||
* @param Illuminate\Http\Request $request
|
|
||||||
* @return view
|
|
||||||
*/
|
|
||||||
public function config(Request $request)
|
|
||||||
{
|
|
||||||
$data['me'] = $request->session()->get('me');
|
|
||||||
$data['token'] = $request->session()->get('token');
|
|
||||||
$data['syndication'] = $request->session()->get('syndication') ?? 'none defined';
|
|
||||||
$data['media-endpoint'] = $request->session()->get('media-endpoint') ?? 'none defined';
|
|
||||||
|
|
||||||
return view('micropub.config', compact('data'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Query the micropub endpoint and store response in the session.
|
|
||||||
*
|
|
||||||
* @param Illuminate\Http\Request $request
|
|
||||||
* @return redirect
|
|
||||||
*/
|
|
||||||
public function queryEndpoint(Request $request)
|
|
||||||
{
|
|
||||||
$domain = $request->session()->get('me');
|
|
||||||
$token = $request->session()->get('token');
|
|
||||||
$micropubEndpoint = $this->indieAuthService->discoverMicropubEndpoint($domain);
|
|
||||||
if ($micropubEndpoint !== null) {
|
|
||||||
try {
|
|
||||||
$response = $this->guzzleClient->get($micropubEndpoint, [
|
|
||||||
'headers' => ['Authorization' => 'Bearer ' . $token],
|
|
||||||
'query' => 'q=config',
|
|
||||||
]);
|
|
||||||
} catch (ClientException | ServerException $e) {
|
|
||||||
return back();
|
|
||||||
}
|
|
||||||
$body = (string) $response->getBody();
|
|
||||||
|
|
||||||
$syndication = $this->parseSyndicationTargets($body);
|
|
||||||
$request->session()->put('syndication', $syndication);
|
|
||||||
|
|
||||||
$mediaEndpoint = $this->parseMediaEndpoint($body);
|
|
||||||
$request->session()->put('media-endpoint', $mediaEndpoint);
|
|
||||||
|
|
||||||
return back();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method performs the actual POST request.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @param string The Micropub endpoint to post to
|
|
||||||
* @param string The token to authenticate the request with
|
|
||||||
* @return \GuzzleHttp\Response $response | \Illuminate\RedirectFactory redirect
|
|
||||||
*/
|
|
||||||
private function postNoteRequest(
|
|
||||||
Request $request,
|
|
||||||
$micropubEndpoint,
|
|
||||||
$token
|
|
||||||
) {
|
|
||||||
$multipart = [
|
$multipart = [
|
||||||
[
|
[
|
||||||
'name' => 'h',
|
'name' => 'h',
|
||||||
|
@ -246,9 +170,6 @@ class MicropubClientController extends Controller
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$headers = [
|
|
||||||
'Authorization' => 'Bearer ' . $token,
|
|
||||||
];
|
|
||||||
try {
|
try {
|
||||||
$response = $this->guzzleClient->post($micropubEndpoint, [
|
$response = $this->guzzleClient->post($micropubEndpoint, [
|
||||||
'multipart' => $multipart,
|
'multipart' => $multipart,
|
||||||
|
@ -261,7 +182,208 @@ class MicropubClientController extends Controller
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $response;
|
if ($response->getStatusCode() == 201) {
|
||||||
|
$request->session()->forget('media-links');
|
||||||
|
$location = $response->getHeader('Location');
|
||||||
|
if (is_array($location)) {
|
||||||
|
return redirect($location[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect($location);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($user->syntax == 'json') {
|
||||||
|
$json = [];
|
||||||
|
$json['type'] = ['h-entry'];
|
||||||
|
$json['properties'] = ['content' => [$request->input('content')]];
|
||||||
|
|
||||||
|
if ($request->input('in-reply-to') != '') {
|
||||||
|
$json['properties']['in-reply-to'] = [$request->input('in-reply-to')];
|
||||||
|
}
|
||||||
|
if ($request->input('mp-syndicate-to')) {
|
||||||
|
foreach ($request->input('mp-syndicate-to') as $syn) {
|
||||||
|
$json['properties']['mp-syndicate-to'] = [$syn];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($request->input('location')) {
|
||||||
|
if ($request->input('location') !== 'no-location') {
|
||||||
|
$json['properties']['location'] = [$request->input('location')];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($request->input('media')) {
|
||||||
|
$json['properties']['photo'] = [];
|
||||||
|
foreach ($request->input('media') as $media) {
|
||||||
|
$json['properties']['photo'][] = $media;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$response = $this->guzzleClient->post($micropubEndpoint, [
|
||||||
|
'json' => $json,
|
||||||
|
'headers' => $headers,
|
||||||
|
]);
|
||||||
|
} catch (\GuzzleHttp\Exception\BadResponseException $e) {
|
||||||
|
return redirect(route('micropub-client'))->with(
|
||||||
|
'error',
|
||||||
|
'There was a bad response from the micropub endpoint.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($response->getStatusCode() == 201) {
|
||||||
|
$request->session()->forget('media-links');
|
||||||
|
$location = $response->getHeader('Location');
|
||||||
|
if (is_array($location)) {
|
||||||
|
return redirect($location[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect($location);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect(route('micropub-client'))->with('error', 'Endpoint didn’t create the note.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show currently stored configuration values.
|
||||||
|
*
|
||||||
|
* @param Illuminate\Http\Request $request
|
||||||
|
* @return view
|
||||||
|
*/
|
||||||
|
public function config(Request $request)
|
||||||
|
{
|
||||||
|
//default values
|
||||||
|
$data = [
|
||||||
|
'me' => '',
|
||||||
|
'token' => 'none',
|
||||||
|
'syndication' => 'none defined',
|
||||||
|
'media-endpoint' => 'none defined',
|
||||||
|
'syntax' => 'html',
|
||||||
|
];
|
||||||
|
if ($request->session()->has('me')) {
|
||||||
|
$data['me'] = normalize_url($request->session()->get('me'));
|
||||||
|
$user = IndieWebUser::where('me', $request->session()->get('me'))->first();
|
||||||
|
$data['token'] = $user->token ?? 'none defined';
|
||||||
|
$data['syndication'] = $user->syndication ?? 'none defined';
|
||||||
|
$data['media-endpoint'] = $user->mediaEndpoint ?? 'none defined';
|
||||||
|
$data['syntax'] = $user->syntax;
|
||||||
|
}
|
||||||
|
|
||||||
|
return view('micropub.config', compact('data'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a new token.
|
||||||
|
*
|
||||||
|
* @param Illuminate\Http\Request $request
|
||||||
|
* @return view
|
||||||
|
*/
|
||||||
|
public function getNewToken(Request $request)
|
||||||
|
{
|
||||||
|
if ($request->session()->has('me')) {
|
||||||
|
$url = normalize_url($request->session()->get('me'));
|
||||||
|
$authozationEndpoint = $this->indieClient->discoverAuthorizationEndpoint($url);
|
||||||
|
if ($authozationEndpoint) {
|
||||||
|
$state = bin2hex(random_bytes(16));
|
||||||
|
$request->session()->put('state', $state);
|
||||||
|
$authorizationURL = $this->indieClient->buildAuthorizationURL(
|
||||||
|
$authozationEndpoint,
|
||||||
|
$url,
|
||||||
|
route('micropub-client-get-new-token-callback'), // redirect_uri
|
||||||
|
route('micropub-client'), //client_id
|
||||||
|
$state,
|
||||||
|
'create update' // scope needs to be a setting
|
||||||
|
);
|
||||||
|
|
||||||
|
return redirect($authorizationURL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return back();
|
||||||
|
}
|
||||||
|
|
||||||
|
return back();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The callback for getting a token.
|
||||||
|
*/
|
||||||
|
public function getNewTokenCallback(Request $request)
|
||||||
|
{
|
||||||
|
if ($request->input('state') !== $request->session()->get('state')) {
|
||||||
|
return route('micropub-client')->with('error', 'The <code>state</code> didn’t match.');
|
||||||
|
}
|
||||||
|
$tokenEndpoint = $this->indieClient->discoverTokenEndpoint(normalize_url($request->input('me')));
|
||||||
|
if ($tokenEndpoint) {
|
||||||
|
$token = $this->indieClient->getAccessToken(
|
||||||
|
$tokenEndpoint,
|
||||||
|
$request->input('code'),
|
||||||
|
$request->input('me'),
|
||||||
|
route('micropub-client-get-new-token-callback'), // redirect_uri
|
||||||
|
route('micropub-client'), // client_id
|
||||||
|
$request->input('state')
|
||||||
|
);
|
||||||
|
if (array_key_exists('access_token', $token)) {
|
||||||
|
$url = normalize_url($token['me']);
|
||||||
|
$user = IndieWebUser::where('me', $url)->firstOrFail();
|
||||||
|
$user->token = $token['access_token'];
|
||||||
|
$user->save();
|
||||||
|
|
||||||
|
return redirect('micropub-config');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query the micropub endpoint and store response.
|
||||||
|
*
|
||||||
|
* @param Illuminate\Http\Request $request
|
||||||
|
* @return redirect
|
||||||
|
*/
|
||||||
|
public function queryEndpoint(Request $request)
|
||||||
|
{
|
||||||
|
$url = normalize_url($request->session()->get('me'));
|
||||||
|
$user = IndieWebUser::where('me', $url)->firstOrFail();
|
||||||
|
$token = $user->token;
|
||||||
|
$micropubEndpoint = $this->indieClient->discoverMicropubEndpoint($url);
|
||||||
|
if ($micropubEndpoint) {
|
||||||
|
try {
|
||||||
|
$response = $this->guzzleClient->get($micropubEndpoint, [
|
||||||
|
'headers' => ['Authorization' => 'Bearer ' . $token],
|
||||||
|
'query' => 'q=config',
|
||||||
|
]);
|
||||||
|
} catch (ClientException | ServerException $e) {
|
||||||
|
return back();
|
||||||
|
}
|
||||||
|
$body = (string) $response->getBody();
|
||||||
|
$data = json_decode($body, true);
|
||||||
|
|
||||||
|
if (array_key_exists('syndicate-to', $data)) {
|
||||||
|
$user->syndication = json_encode($data['syndicate-to']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array_key_exists('media-endpoint', $data)) {
|
||||||
|
$user->mediaEndpoint = $data['media-endpoint'];
|
||||||
|
}
|
||||||
|
$user->save();
|
||||||
|
|
||||||
|
return back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the syntax setting.
|
||||||
|
*
|
||||||
|
* @param Illuminate\Http\Request $request
|
||||||
|
* @return Illuminate\Http\RedirectResponse
|
||||||
|
* @todo validate input
|
||||||
|
*/
|
||||||
|
public function updateSyntax(Request $request)
|
||||||
|
{
|
||||||
|
$user = IndieWebUser::where('me', $request->session()->get('me'))->firstOrFail();
|
||||||
|
$user->syntax = $request->syntax;
|
||||||
|
$user->save();
|
||||||
|
|
||||||
|
return redirect(route('micropub-config'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -272,16 +394,17 @@ class MicropubClientController extends Controller
|
||||||
*/
|
*/
|
||||||
public function newPlace(Request $request)
|
public function newPlace(Request $request)
|
||||||
{
|
{
|
||||||
if ($request->session()->has('token') === false) {
|
$url = normalize_url($request->session()->get('me'));
|
||||||
|
$user = IndieWebUser::where('me', $url)->firstOrFail();
|
||||||
|
|
||||||
|
if ($user->token === null) {
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'error' => true,
|
'error' => true,
|
||||||
'error_description' => 'No known token',
|
'error_description' => 'No known token',
|
||||||
], 400);
|
], 400);
|
||||||
}
|
}
|
||||||
$domain = $request->session()->get('me');
|
|
||||||
$token = $request->session()->get('token');
|
|
||||||
|
|
||||||
$micropubEndpoint = $this->indieAuthService->discoverMicropubEndpoint($domain, $this->indieClient);
|
$micropubEndpoint = $this->indieClient->discoverMicropubEndpoint($url);
|
||||||
if (! $micropubEndpoint) {
|
if (! $micropubEndpoint) {
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'error' => true,
|
'error' => true,
|
||||||
|
@ -289,13 +412,27 @@ class MicropubClientController extends Controller
|
||||||
], 400);
|
], 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
$place = $this->postPlaceRequest($request, $micropubEndpoint, $token);
|
$formParams = [
|
||||||
if ($place === false) {
|
'h' => 'card',
|
||||||
|
'name' => $request->input('place-name'),
|
||||||
|
'description' => $request->input('place-description'),
|
||||||
|
'geo' => 'geo:' . $request->input('place-latitude') . ',' . $request->input('place-longitude'),
|
||||||
|
];
|
||||||
|
$headers = [
|
||||||
|
'Authorization' => 'Bearer ' . $user->token,
|
||||||
|
];
|
||||||
|
try {
|
||||||
|
$response = $this->guzzleClient->request('POST', $micropubEndpoint, [
|
||||||
|
'form_params' => $formParams,
|
||||||
|
'headers' => $headers,
|
||||||
|
]);
|
||||||
|
} catch (ClientException $e) {
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'error' => true,
|
'error' => true,
|
||||||
'error_description' => 'Unable to create the new place',
|
'error_description' => 'Unable to create the new place',
|
||||||
], 400);
|
], 400);
|
||||||
}
|
}
|
||||||
|
$place = $response->getHeader('Location')[0];
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'uri' => $place,
|
'uri' => $place,
|
||||||
|
@ -305,44 +442,6 @@ class MicropubClientController extends Controller
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Actually make a micropub request to make a new place.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @param string The Micropub endpoint to post to
|
|
||||||
* @param string The token to authenticate the request with
|
|
||||||
* @param \GuzzleHttp\Client $client
|
|
||||||
* @return \GuzzleHttp\Response $response | \Illuminate\RedirectFactory redirect
|
|
||||||
*/
|
|
||||||
private function postPlaceRequest(
|
|
||||||
Request $request,
|
|
||||||
$micropubEndpoint,
|
|
||||||
$token
|
|
||||||
) {
|
|
||||||
$formParams = [
|
|
||||||
'h' => 'card',
|
|
||||||
'name' => $request->input('place-name'),
|
|
||||||
'description' => $request->input('place-description'),
|
|
||||||
'geo' => 'geo:' . $request->input('place-latitude') . ',' . $request->input('place-longitude'),
|
|
||||||
];
|
|
||||||
$headers = [
|
|
||||||
'Authorization' => 'Bearer ' . $token,
|
|
||||||
];
|
|
||||||
try {
|
|
||||||
$response = $this->guzzleClient->request('POST', $micropubEndpoint, [
|
|
||||||
'form_params' => $formParams,
|
|
||||||
'headers' => $headers,
|
|
||||||
]);
|
|
||||||
} catch (ClientException $e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if ($response->getStatusCode() == 201) {
|
|
||||||
return $response->getHeader('Location')[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make a request to the micropub endpoint requesting any nearby places.
|
* Make a request to the micropub endpoint requesting any nearby places.
|
||||||
*
|
*
|
||||||
|
@ -351,16 +450,17 @@ class MicropubClientController extends Controller
|
||||||
*/
|
*/
|
||||||
public function nearbyPlaces(Request $request)
|
public function nearbyPlaces(Request $request)
|
||||||
{
|
{
|
||||||
if ($request->session()->has('token') === false) {
|
$url = normalize_url($request->session()->get('me'));
|
||||||
|
$user = IndieWebUser::where('me', $url)->firstOrFail();
|
||||||
|
|
||||||
|
if ($user->token === null) {
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'error' => true,
|
'error' => true,
|
||||||
'error_description' => 'No known token',
|
'error_description' => 'No known token',
|
||||||
], 400);
|
], 400);
|
||||||
}
|
}
|
||||||
$domain = $request->session()->get('me');
|
|
||||||
$token = $request->session()->get('token');
|
|
||||||
|
|
||||||
$micropubEndpoint = $this->indieAuthService->discoverMicropubEndpoint($domain, $this->indieClient);
|
$micropubEndpoint = $this->indieClient->discoverMicropubEndpoint($url);
|
||||||
|
|
||||||
if (! $micropubEndpoint) {
|
if (! $micropubEndpoint) {
|
||||||
return response()->json([
|
return response()->json([
|
||||||
|
@ -375,7 +475,7 @@ class MicropubClientController extends Controller
|
||||||
$query .= ';u=' . $request->input('u');
|
$query .= ';u=' . $request->input('u');
|
||||||
}
|
}
|
||||||
$response = $this->guzzleClient->get($micropubEndpoint, [
|
$response = $this->guzzleClient->get($micropubEndpoint, [
|
||||||
'headers' => ['Authorization' => 'Bearer ' . $token],
|
'headers' => ['Authorization' => 'Bearer ' . $user->token],
|
||||||
'query' => ['q' => $query],
|
'query' => ['q' => $query],
|
||||||
]);
|
]);
|
||||||
} catch (\GuzzleHttp\Exception\BadResponseException $e) {
|
} catch (\GuzzleHttp\Exception\BadResponseException $e) {
|
||||||
|
@ -390,31 +490,35 @@ class MicropubClientController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse the syndication targets retreived from a cookie, to a form that can
|
* Parse the syndication targets JSON into a an array.
|
||||||
* be used in a view.
|
|
||||||
*
|
*
|
||||||
* @param string $syndicationTargets
|
* @param string|null
|
||||||
* @return array|null
|
* @return array|null
|
||||||
*/
|
*/
|
||||||
private function parseSyndicationTargets($syndicationTargets = null)
|
private function parseSyndicationTargets($syndicationTargets = null)
|
||||||
{
|
{
|
||||||
if ($syndicationTargets === null) {
|
if ($syndicationTargets === null || $syndicationTargets === '') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$syndicateTo = [];
|
$syndicateTo = [];
|
||||||
$data = json_decode($syndicationTargets, true);
|
$data = json_decode($syndicationTargets, true);
|
||||||
if (array_key_exists('syndicate-to', $data)) {
|
if (array_key_exists('uid', $data)) {
|
||||||
foreach ($data['syndicate-to'] as $syn) {
|
$syndicateTo[] = [
|
||||||
|
'target' => $data['uid'],
|
||||||
|
'name' => $data['name'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
foreach ($data as $syn) {
|
||||||
|
if (array_key_exists('uid', $syn)) {
|
||||||
$syndicateTo[] = [
|
$syndicateTo[] = [
|
||||||
'target' => $syn['uid'],
|
'target' => $syn['uid'],
|
||||||
'name' => $syn['name'],
|
'name' => $syn['name'],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (count($syndicateTo) > 0) {
|
|
||||||
return $syndicateTo;
|
return $syndicateTo;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse the media-endpoint retrieved from querying a micropub endpoint.
|
* Parse the media-endpoint retrieved from querying a micropub endpoint.
|
||||||
|
|
|
@ -3,8 +3,9 @@
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use Ramsey\Uuid\Uuid;
|
use Ramsey\Uuid\Uuid;
|
||||||
use App\{Media, Place};
|
use App\{Media, Note, Place};
|
||||||
use Illuminate\Http\{Request, Response};
|
use Illuminate\Http\{Request, Response};
|
||||||
|
use App\Exceptions\InvalidTokenException;
|
||||||
use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
|
use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
|
||||||
use App\Services\{NoteService, PlaceService, TokenService};
|
use App\Services\{NoteService, PlaceService, TokenService};
|
||||||
|
|
||||||
|
@ -47,29 +48,52 @@ class MicropubController extends Controller
|
||||||
*/
|
*/
|
||||||
public function post(Request $request)
|
public function post(Request $request)
|
||||||
{
|
{
|
||||||
$httpAuth = $request->header('Authorization');
|
try {
|
||||||
if (preg_match('/Bearer (.+)/', $httpAuth, $match)) {
|
$tokenData = $this->tokenService->validateToken($request->bearerToken());
|
||||||
$token = $match[1];
|
} catch (InvalidTokenException $e) {
|
||||||
$tokenData = $this->tokenService->validateToken($token);
|
return response()->json([
|
||||||
|
'response' => 'error',
|
||||||
|
'error' => 'invalid_token',
|
||||||
|
'error_description' => 'The provided token did not pass validation',
|
||||||
|
], 400);
|
||||||
|
}
|
||||||
if ($tokenData->hasClaim('scope')) {
|
if ($tokenData->hasClaim('scope')) {
|
||||||
$scopes = explode(' ', $tokenData->getClaim('scope'));
|
|
||||||
if (array_search('post', $scopes) !== false) {
|
|
||||||
$clientId = $tokenData->getClaim('client_id');
|
|
||||||
if (($request->input('h') == 'entry') || ($request->input('type')[0] == 'h-entry')) {
|
if (($request->input('h') == 'entry') || ($request->input('type')[0] == 'h-entry')) {
|
||||||
|
if (stristr($tokenData->getClaim('scope'), 'create') === false) {
|
||||||
|
return $this->returnInsufficientScopeResponse();
|
||||||
|
}
|
||||||
$data = [];
|
$data = [];
|
||||||
$data['client-id'] = $clientId;
|
$data['client-id'] = $tokenData->getClaim('client_id');
|
||||||
if ($request->header('Content-Type') == 'application/json') {
|
if ($request->header('Content-Type') == 'application/json') {
|
||||||
$data['content'] = $request->input('properties.content')[0];
|
if (is_string($request->input('properties.content')[0])) {
|
||||||
|
$data['content'] = $request->input('properties.content')[0]; //plaintext content
|
||||||
|
}
|
||||||
|
if (is_array($request->input('properties.content')[0])
|
||||||
|
&& array_key_exists('html', $request->input('properties.content')[0])
|
||||||
|
) {
|
||||||
|
$data['content'] = $request->input('properties.content')[0]['html'];
|
||||||
|
}
|
||||||
$data['in-reply-to'] = $request->input('properties.in-reply-to')[0];
|
$data['in-reply-to'] = $request->input('properties.in-reply-to')[0];
|
||||||
$data['location'] = $request->input('properties.location');
|
$data['location'] = $request->input('properties.location');
|
||||||
//flatten location if array
|
//flatten location if array
|
||||||
if (is_array($data['location'])) {
|
if (is_array($data['location'])) {
|
||||||
$data['location'] = $data['location'][0];
|
$data['location'] = $data['location'][0];
|
||||||
}
|
}
|
||||||
|
$data['published'] = $request->input('properties.published')[0];
|
||||||
|
//create checkin place
|
||||||
|
if (array_key_exists('checkin', $request->input('properties'))) {
|
||||||
|
$data['checkin'] = $request->input('properties.checkin.0.properties.url.0');
|
||||||
|
try {
|
||||||
|
$this->placeService->createPlaceFromCheckin($request->input('properties.checkin.0'));
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$data['checkin'] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$data['content'] = $request->input('content');
|
$data['content'] = $request->input('content');
|
||||||
$data['in-reply-to'] = $request->input('in-reply-to');
|
$data['in-reply-to'] = $request->input('in-reply-to');
|
||||||
$data['location'] = $request->input('location');
|
$data['location'] = $request->input('location');
|
||||||
|
$data['published'] = $request->input('published');
|
||||||
}
|
}
|
||||||
$data['syndicate'] = [];
|
$data['syndicate'] = [];
|
||||||
$targets = array_pluck(config('syndication.targets'), 'uid', 'service.name');
|
$targets = array_pluck(config('syndication.targets'), 'uid', 'service.name');
|
||||||
|
@ -105,7 +129,7 @@ class MicropubController extends Controller
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
$note = $this->noteService->createNote($data);
|
$note = $this->noteService->createNote($data);
|
||||||
} catch (Exception $exception) {
|
} catch (\Exception $exception) {
|
||||||
return response()->json(['error' => true], 400);
|
return response()->json(['error' => true], 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,6 +139,9 @@ class MicropubController extends Controller
|
||||||
], 201)->header('Location', $note->longurl);
|
], 201)->header('Location', $note->longurl);
|
||||||
}
|
}
|
||||||
if ($request->input('h') == 'card' || $request->input('type')[0] == 'h-card') {
|
if ($request->input('h') == 'card' || $request->input('type')[0] == 'h-card') {
|
||||||
|
if (stristr($tokenData->getClaim('scope'), 'create') === false) {
|
||||||
|
return $this->returnInsufficientScopeResponse();
|
||||||
|
}
|
||||||
$data = [];
|
$data = [];
|
||||||
if ($request->header('Content-Type') == 'application/json') {
|
if ($request->header('Content-Type') == 'application/json') {
|
||||||
$data['name'] = $request->input('properties.name');
|
$data['name'] = $request->input('properties.name');
|
||||||
|
@ -135,7 +162,7 @@ class MicropubController extends Controller
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
$place = $this->placeService->createPlace($data);
|
$place = $this->placeService->createPlace($data);
|
||||||
} catch (Exception $exception) {
|
} catch (\Exception $exception) {
|
||||||
return response()->json(['error' => true], 400);
|
return response()->json(['error' => true], 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,21 +171,90 @@ class MicropubController extends Controller
|
||||||
'location' => $place->longurl,
|
'location' => $place->longurl,
|
||||||
], 201)->header('Location', $place->longurl);
|
], 201)->header('Location', $place->longurl);
|
||||||
}
|
}
|
||||||
|
if ($request->input('action') == 'update') {
|
||||||
|
if (stristr($tokenData->getClaim('scope'), 'update') === false) {
|
||||||
|
return $this->returnInsufficientScopeResponse();
|
||||||
|
}
|
||||||
|
$urlPath = parse_url($request->input('url'), PHP_URL_PATH);
|
||||||
|
//is it a note we are updating?
|
||||||
|
if (mb_substr($urlPath, 1, 5) === 'notes') {
|
||||||
|
try {
|
||||||
|
$note = Note::nb60(basename($urlPath))->first();
|
||||||
|
} catch (\Exception $exception) {
|
||||||
|
return response()->json([
|
||||||
|
'error' => 'invalid_request',
|
||||||
|
'error_description' => 'No known note with given ID',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
//got the note, are we dealing with a “replace” request?
|
||||||
|
if ($request->has('replace')) {
|
||||||
|
foreach ($request->input('replace') as $property => $value) {
|
||||||
|
if ($property == 'content') {
|
||||||
|
$note->note = $value[0];
|
||||||
|
}
|
||||||
|
if ($property == 'syndication') {
|
||||||
|
foreach ($value as $syndicationURL) {
|
||||||
|
if (starts_with($syndicationURL, 'https://www.facebook.com')) {
|
||||||
|
$note->facebook_url = $syndicationURL;
|
||||||
|
}
|
||||||
|
if (starts_with($syndicationURL, 'https://www.swarmapp.com')) {
|
||||||
|
$note->swarm_url = $syndicationURL;
|
||||||
|
}
|
||||||
|
if (starts_with($syndicationURL, 'https://twitter.com')) {
|
||||||
|
$note->tweet_id = basename(parse_url($syndicationURL, PHP_URL_PATH));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$note->save();
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'response' => 'updated',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
//how about “add”
|
||||||
|
if ($request->has('add')) {
|
||||||
|
foreach ($request->input('add') as $property => $value) {
|
||||||
|
if ($property == 'syndication') {
|
||||||
|
foreach ($value as $syndicationURL) {
|
||||||
|
if (starts_with($syndicationURL, 'https://www.facebook.com')) {
|
||||||
|
$note->facebook_url = $syndicationURL;
|
||||||
|
}
|
||||||
|
if (starts_with($syndicationURL, 'https://www.swarmapp.com')) {
|
||||||
|
$note->swarm_url = $syndicationURL;
|
||||||
|
}
|
||||||
|
if (starts_with($syndicationURL, 'https://twitter.com')) {
|
||||||
|
$note->tweet_id = basename(parse_url($syndicationURL, PHP_URL_PATH));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($property == 'photo') {
|
||||||
|
foreach ($value as $photoURL) {
|
||||||
|
if (start_with($photo, 'https://')) {
|
||||||
|
$media = new Media();
|
||||||
|
$media->path = $photoURL;
|
||||||
|
$media->type = 'image';
|
||||||
|
$media->save();
|
||||||
|
$note->media()->save($media);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$note->save();
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'response' => 'updated',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'response' => 'error',
|
'response' => 'error',
|
||||||
'error' => 'invalid_token',
|
'error' => 'forbidden',
|
||||||
'error_description' => 'The token provided is not valid or does not have the necessary scope',
|
'error_description' => 'The token has no scopes',
|
||||||
], 400);
|
], 403);
|
||||||
}
|
|
||||||
|
|
||||||
return response()->json([
|
|
||||||
'response' => 'error',
|
|
||||||
'error' => 'no_token',
|
|
||||||
'error_description' => 'No OAuth token sent with request',
|
|
||||||
], 400);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -172,12 +268,9 @@ class MicropubController extends Controller
|
||||||
*/
|
*/
|
||||||
public function get(Request $request)
|
public function get(Request $request)
|
||||||
{
|
{
|
||||||
$httpAuth = $request->header('Authorization');
|
try {
|
||||||
if (preg_match('/Bearer (.+)/', $httpAuth, $match)) {
|
$tokenData = $this->tokenService->validateToken($request->bearerToken());
|
||||||
$token = $match[1];
|
} catch (InvalidTokenException $e) {
|
||||||
$valid = $this->tokenService->validateToken($token);
|
|
||||||
|
|
||||||
if ($valid === null) {
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'response' => 'error',
|
'response' => 'error',
|
||||||
'error' => 'invalid_token',
|
'error' => 'invalid_token',
|
||||||
|
@ -222,20 +315,13 @@ class MicropubController extends Controller
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'response' => 'token',
|
'response' => 'token',
|
||||||
'token' => [
|
'token' => [
|
||||||
'me' => $valid->getClaim('me'),
|
'me' => $tokenData->getClaim('me'),
|
||||||
'scope' => $valid->getClaim('scope'),
|
'scope' => $tokenData->getClaim('scope'),
|
||||||
'client_id' => $valid->getClaim('client_id'),
|
'client_id' => $tokenData->getClaim('client_id'),
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json([
|
|
||||||
'response' => 'error',
|
|
||||||
'error' => 'no_token',
|
|
||||||
'error_description' => 'No token provided with request',
|
|
||||||
], 400);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process a media item posted to the media endpoint.
|
* Process a media item posted to the media endpoint.
|
||||||
*
|
*
|
||||||
|
@ -244,13 +330,9 @@ class MicropubController extends Controller
|
||||||
*/
|
*/
|
||||||
public function media(Request $request)
|
public function media(Request $request)
|
||||||
{
|
{
|
||||||
//can this go in middleware
|
try {
|
||||||
$httpAuth = $request->header('Authorization');
|
$tokenData = $this->tokenService->validateToken($request->bearerToken());
|
||||||
if (preg_match('/Bearer (.+)/', $httpAuth, $match)) {
|
} catch (InvalidTokenException $e) {
|
||||||
$token = $match[1];
|
|
||||||
$tokenData = $this->tokenService->validateToken($token);
|
|
||||||
|
|
||||||
if ($tokenData === null) {
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'response' => 'error',
|
'response' => 'error',
|
||||||
'error' => 'invalid_token',
|
'error' => 'invalid_token',
|
||||||
|
@ -260,8 +342,9 @@ class MicropubController extends Controller
|
||||||
|
|
||||||
//check post scope
|
//check post scope
|
||||||
if ($tokenData->hasClaim('scope')) {
|
if ($tokenData->hasClaim('scope')) {
|
||||||
$scopes = explode(' ', $tokenData->getClaim('scope'));
|
if (stristr($token->getClaim('scope'), 'post') === false) {
|
||||||
if (array_search('post', $scopes) !== false) {
|
return $this->returnInsufficientScopeResponse();
|
||||||
|
}
|
||||||
//check media valid
|
//check media valid
|
||||||
if ($request->hasFile('file') && $request->file('file')->isValid()) {
|
if ($request->hasFile('file') && $request->file('file')->isValid()) {
|
||||||
$type = $this->getFileTypeFromMimeType($request->file('file')->getMimeType());
|
$type = $this->getFileTypeFromMimeType($request->file('file')->getMimeType());
|
||||||
|
@ -284,7 +367,7 @@ class MicropubController extends Controller
|
||||||
], 503);
|
], 503);
|
||||||
}
|
}
|
||||||
$media = new Media();
|
$media = new Media();
|
||||||
$media->token = $token;
|
$media->token = $request->bearerToken();
|
||||||
$media->path = $path;
|
$media->path = $path;
|
||||||
$media->type = $type;
|
$media->type = $type;
|
||||||
$media->save();
|
$media->save();
|
||||||
|
@ -304,22 +387,8 @@ class MicropubController extends Controller
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'response' => 'error',
|
'response' => 'error',
|
||||||
'error' => 'insufficient_scope',
|
'error' => 'invalid_request',
|
||||||
'error_description' => 'The provided token has insufficient scopes',
|
'error_description' => 'The provided token has no scopes',
|
||||||
], 401);
|
|
||||||
}
|
|
||||||
|
|
||||||
return response()->json([
|
|
||||||
'response' => 'error',
|
|
||||||
'error' => 'unauthorized',
|
|
||||||
'error_description' => 'No token provided with request',
|
|
||||||
], 401);
|
|
||||||
}
|
|
||||||
|
|
||||||
return response()->json([
|
|
||||||
'response' => 'error',
|
|
||||||
'error' => 'no_token',
|
|
||||||
'error_description' => 'There was no token provided with the request',
|
|
||||||
], 400);
|
], 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,4 +435,13 @@ class MicropubController extends Controller
|
||||||
|
|
||||||
return 'download';
|
return 'download';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function returnInsufficientScopeResponse()
|
||||||
|
{
|
||||||
|
return response()->json([
|
||||||
|
'response' => 'error',
|
||||||
|
'error' => 'insufficient_scope',
|
||||||
|
'error_description' => 'The token’s scope does not have the necessary requirements.',
|
||||||
|
], 401);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
79
app/Http/Controllers/TokenEndpointController.php
Normal file
79
app/Http/Controllers/TokenEndpointController.php
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use IndieAuth\Client;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use App\Services\TokenService;
|
||||||
|
|
||||||
|
class TokenEndpointController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The IndieAuth Client.
|
||||||
|
*/
|
||||||
|
protected $client;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Token handling service.
|
||||||
|
*/
|
||||||
|
protected $tokenService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inject the dependencies.
|
||||||
|
*
|
||||||
|
* @param \IndieAuth\Client $client
|
||||||
|
* @param \App\Services\TokenService $tokenService
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
Client $client = null,
|
||||||
|
TokenService $tokenService = null
|
||||||
|
) {
|
||||||
|
$this->client = $client ?? new Client();
|
||||||
|
$this->tokenService = $tokenService ?? new TokenService();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the user has auth’d via the IndieAuth protocol, issue a valid token.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @return \Illuminate\Http\Response
|
||||||
|
*/
|
||||||
|
public function create(Request $request)
|
||||||
|
{
|
||||||
|
$authorizationEndpoint = $this->client->discoverAuthorizationEndpoint(normalize_url($request->input('me')));
|
||||||
|
if ($authorizationEndpoint) {
|
||||||
|
$auth = $this->client->verifyIndieAuthCode(
|
||||||
|
$authorizationEndpoint,
|
||||||
|
$request->input('code'),
|
||||||
|
$request->input('me'),
|
||||||
|
$request->input('redirect_uri'),
|
||||||
|
$request->input('client_id'),
|
||||||
|
$request->input('state')
|
||||||
|
);
|
||||||
|
if (array_key_exists('me', $auth)) {
|
||||||
|
$scope = $auth['scope'] ?? '';
|
||||||
|
$tokenData = [
|
||||||
|
'me' => $request->input('me'),
|
||||||
|
'client_id' => $request->input('client_id'),
|
||||||
|
'scope' => $scope,
|
||||||
|
];
|
||||||
|
$token = $this->tokenService->getNewToken($tokenData);
|
||||||
|
$content = http_build_query([
|
||||||
|
'me' => $request->input('me'),
|
||||||
|
'scope' => $scope,
|
||||||
|
'access_token' => $token,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return response($content)->header(
|
||||||
|
'Content-Type',
|
||||||
|
'application/x-www-form-urlencoded'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response('There was an error verifying the authorisation code.', 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response('Can’t determine the authorisation endpoint.', 400);
|
||||||
|
}
|
||||||
|
}
|
|
@ -34,7 +34,8 @@ class Kernel extends HttpKernel
|
||||||
\App\Http\Middleware\VerifyCsrfToken::class,
|
\App\Http\Middleware\VerifyCsrfToken::class,
|
||||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||||
\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,
|
||||||
],
|
],
|
||||||
|
|
||||||
'api' => [
|
'api' => [
|
||||||
|
@ -58,5 +59,6 @@ class Kernel extends HttpKernel
|
||||||
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
|
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
|
||||||
'myauth' => \App\Http\Middleware\MyAuthMiddleware::class,
|
'myauth' => \App\Http\Middleware\MyAuthMiddleware::class,
|
||||||
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||||
|
'micropub.token' => \App\Http\Middleware\VerifyMicropubToken::class,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
26
app/Http/Middleware/LocalhostSessionMiddleware.php
Normal file
26
app/Http/Middleware/LocalhostSessionMiddleware.php
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
|
||||||
|
class LocalhostSessionMiddleware
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Whilst we are developing locally, automatically log in as
|
||||||
|
* `['me' => config('app.url')]` as I can’t manually log in as
|
||||||
|
* a .localhost domain.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @param \Closure $next
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function handle($request, Closure $next)
|
||||||
|
{
|
||||||
|
if (config('app.env') !== 'production') {
|
||||||
|
session(['me' => config('app.url')]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
28
app/Http/Middleware/VerifyMicropubToken.php
Normal file
28
app/Http/Middleware/VerifyMicropubToken.php
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
|
||||||
|
class VerifyMicropubToken
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @param \Closure $next
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function handle($request, Closure $next)
|
||||||
|
{
|
||||||
|
if ($request->bearerToken() === null) {
|
||||||
|
return response()->json([
|
||||||
|
'response' => 'error',
|
||||||
|
'error' => 'unauthorized',
|
||||||
|
'error_description' => 'No access token was provided in the request',
|
||||||
|
], 401);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
15
app/IndieWebUser.php
Normal file
15
app/IndieWebUser.php
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class IndieWebUser extends Model
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Mass assignment protection.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $fillable = ['me'];
|
||||||
|
}
|
|
@ -28,6 +28,10 @@ class Media extends Model
|
||||||
*/
|
*/
|
||||||
public function getUrlAttribute()
|
public function getUrlAttribute()
|
||||||
{
|
{
|
||||||
|
if (starts_with($this->path, 'https://')) {
|
||||||
|
return $this->path;
|
||||||
|
}
|
||||||
|
|
||||||
return config('filesystems.disks.s3.url') . '/' . $this->path;
|
return config('filesystems.disks.s3.url') . '/' . $this->path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
14
app/Note.php
14
app/Note.php
|
@ -191,6 +191,20 @@ class Note extends Model
|
||||||
return $name;
|
return $name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scope a query to select a note via a NewBase60 id.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||||
|
* @param string $nb60id
|
||||||
|
* @return \Illuminate\Database\Eloquent\Builder
|
||||||
|
*/
|
||||||
|
public function scopeNb60($query, $nb60id)
|
||||||
|
{
|
||||||
|
$numbers = new Numbers();
|
||||||
|
|
||||||
|
return $query->where('id', $numbers->b60tonum($nb60id));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Take note that this method does two things, given @username (NOT [@username](URL)!)
|
* Take note that this method does two things, given @username (NOT [@username](URL)!)
|
||||||
* we try to create a fancy hcard from our contact info. If this is not possible
|
* we try to create a fancy hcard from our contact info. If this is not possible
|
||||||
|
|
|
@ -33,7 +33,7 @@ class AppServiceProvider extends ServiceProvider
|
||||||
//Add tags for notes
|
//Add tags for notes
|
||||||
Note::created(function ($note) {
|
Note::created(function ($note) {
|
||||||
$tagsToAdd = [];
|
$tagsToAdd = [];
|
||||||
preg_match_all('/#([^\s<>]+)\b/', $note, $tags);
|
preg_match_all('/#([^\s<>]+)\b/', $note->note, $tags);
|
||||||
foreach ($tags[1] as $tag) {
|
foreach ($tags[1] as $tag) {
|
||||||
$tag = Tag::normalizeTag($tag);
|
$tag = Tag::normalizeTag($tag);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ class EventServiceProvider extends ServiceProvider
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $listen = [
|
protected $listen = [
|
||||||
'App\Events\SomeEvent' => [
|
'App\Events\Event' => [
|
||||||
'App\Listeners\EventListener',
|
'App\Listeners\EventListener',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
|
@ -45,14 +45,12 @@ class IndieAuthService
|
||||||
session(['state' => $state]);
|
session(['state' => $state]);
|
||||||
$redirectURL = route('indieauth-callback');
|
$redirectURL = route('indieauth-callback');
|
||||||
$clientId = route('micropub-client');
|
$clientId = route('micropub-client');
|
||||||
$scope = 'post';
|
|
||||||
$authorizationURL = $this->client->buildAuthorizationURL(
|
$authorizationURL = $this->client->buildAuthorizationURL(
|
||||||
$authEndpoint,
|
$authEndpoint,
|
||||||
$this->client->normalizeMeURL($domain),
|
$this->client->normalizeMeURL($domain),
|
||||||
$redirectURL,
|
$redirectURL,
|
||||||
$clientId,
|
$clientId,
|
||||||
$state,
|
$state
|
||||||
$scope
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return $authorizationURL;
|
return $authorizationURL;
|
||||||
|
|
|
@ -17,6 +17,16 @@ class NoteService
|
||||||
*/
|
*/
|
||||||
public function createNote(array $data): Note
|
public function createNote(array $data): Note
|
||||||
{
|
{
|
||||||
|
//check the input
|
||||||
|
if (array_key_exists('content', $data) === false) {
|
||||||
|
throw new \Exception('No content defined'); //we can’t fudge the data
|
||||||
|
}
|
||||||
|
if (array_key_exists('in-reply-to', $data) === false) {
|
||||||
|
$data['in-reply-to'] = null;
|
||||||
|
}
|
||||||
|
if (array_key_exists('client-id', $data) === false) {
|
||||||
|
$data['client-id'] = null;
|
||||||
|
}
|
||||||
$note = Note::create(
|
$note = Note::create(
|
||||||
[
|
[
|
||||||
'note' => $data['content'],
|
'note' => $data['content'],
|
||||||
|
@ -25,6 +35,11 @@ class NoteService
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (array_key_exists('published', $data) && empty($data['published']) === false) {
|
||||||
|
$carbon = new \Carbon\Carbon($data['published']);
|
||||||
|
$note->created_at = $note->updated_at = $carbon->toDateTimeString();
|
||||||
|
}
|
||||||
|
|
||||||
if (array_key_exists('location', $data) && $data['location'] !== null && $data['location'] !== 'no-location') {
|
if (array_key_exists('location', $data) && $data['location'] !== null && $data['location'] !== 'no-location') {
|
||||||
if (starts_with($data['location'], config('app.url'))) {
|
if (starts_with($data['location'], config('app.url'))) {
|
||||||
//uri of form http://host/places/slug, we want slug
|
//uri of form http://host/places/slug, we want slug
|
||||||
|
@ -44,6 +59,13 @@ class NoteService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (array_key_exists('checkin', $data) && $data['checkin'] !== null) {
|
||||||
|
$place = Place::where('foursquare', $data['checkin'])->first();
|
||||||
|
if ($place !== null) {
|
||||||
|
$note->place()->associate($place);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* drop image support for now
|
/* drop image support for now
|
||||||
//add images to media library
|
//add images to media library
|
||||||
if ($request->hasFile('photo')) {
|
if ($request->hasFile('photo')) {
|
||||||
|
@ -55,12 +77,17 @@ class NoteService
|
||||||
*/
|
*/
|
||||||
//add support for media uploaded as URLs
|
//add support for media uploaded as URLs
|
||||||
foreach ($data['photo'] as $photo) {
|
foreach ($data['photo'] as $photo) {
|
||||||
// check the media was uploaded to my endpoint
|
// check the media was uploaded to my endpoint, and use path
|
||||||
if (starts_with($photo, config('filesystems.disks.s3.url'))) {
|
if (starts_with($photo, config('filesystems.disks.s3.url'))) {
|
||||||
$path = substr($photo, strlen(config('filesystems.disks.s3.url')));
|
$path = substr($photo, strlen(config('filesystems.disks.s3.url')));
|
||||||
$media = Media::where('path', ltrim($path, '/'))->firstOrFail();
|
$media = Media::where('path', ltrim($path, '/'))->firstOrFail();
|
||||||
$note->media()->save($media);
|
} else {
|
||||||
|
$media = Media::firstOrNew(['path' => $photo]);
|
||||||
|
// currently assuming this is a photo from Swarm
|
||||||
|
$media->type = 'image';
|
||||||
|
$media->save();
|
||||||
}
|
}
|
||||||
|
$note->media()->save($media);
|
||||||
}
|
}
|
||||||
|
|
||||||
$note->save();
|
$note->save();
|
||||||
|
|
|
@ -36,4 +36,39 @@ class PlaceService
|
||||||
|
|
||||||
return $place;
|
return $place;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a place from a h-card checkin, for exameple from OwnYourSwarm.
|
||||||
|
*
|
||||||
|
* @param array
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function createPlaceFromCheckin(array $checkin): bool
|
||||||
|
{
|
||||||
|
//check if the place exists if from swarm
|
||||||
|
if (array_key_exists('url', $checkin['properties'])) {
|
||||||
|
$search = Place::where('foursquare', $checkin['properties']['url'][0])->count();
|
||||||
|
if ($search === 1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (array_key_exists('name', $checkin['properties']) === false) {
|
||||||
|
throw new \InvalidArgumentException('Missing required name');
|
||||||
|
}
|
||||||
|
if (array_key_exists('latitude', $checkin['properties']) === false) {
|
||||||
|
throw new \InvalidArgumentException('Missing required longitude/latitude');
|
||||||
|
}
|
||||||
|
$place = new Place();
|
||||||
|
$place->name = $checkin['properties']['name'][0];
|
||||||
|
if (starts_with($checkin['properties']['url'][0], 'https://foursquare.com')) {
|
||||||
|
$place->foursquare = $checkin['properties']['url'][0];
|
||||||
|
}
|
||||||
|
$place->location = new Point(
|
||||||
|
(float) $checkin['properties']['latitude'][0],
|
||||||
|
(float) $checkin['properties']['longitude'][0]
|
||||||
|
);
|
||||||
|
$place->save();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,12 +4,9 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Services;
|
namespace App\Services;
|
||||||
|
|
||||||
use RuntimeException;
|
|
||||||
use Lcobucci\JWT\Token;
|
|
||||||
use Lcobucci\JWT\Parser;
|
|
||||||
use Lcobucci\JWT\Builder;
|
|
||||||
use InvalidArgumentException;
|
|
||||||
use Lcobucci\JWT\Signer\Hmac\Sha256;
|
use Lcobucci\JWT\Signer\Hmac\Sha256;
|
||||||
|
use App\Exceptions\InvalidTokenException;
|
||||||
|
use Lcobucci\JWT\{Builder, Parser, Token};
|
||||||
|
|
||||||
class TokenService
|
class TokenService
|
||||||
{
|
{
|
||||||
|
@ -39,17 +36,18 @@ class TokenService
|
||||||
* @param string The token
|
* @param string The token
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function validateToken(string $token): ?Token
|
public function validateToken(string $bearerToken): ?Token
|
||||||
{
|
{
|
||||||
$signer = new Sha256();
|
$signer = new Sha256();
|
||||||
try {
|
try {
|
||||||
$token = (new Parser())->parse((string) $token);
|
$token = (new Parser())->parse((string) $bearerToken);
|
||||||
} catch (InvalidArgumentException | RuntimeException $e) {
|
} catch (\InvalidArgumentException $e) {
|
||||||
return null;
|
throw new InvalidTokenException('Token could not be parsed');
|
||||||
}
|
}
|
||||||
if ($token->verify($signer, config('app.key'))) {
|
if (! $token->verify($signer, config('app.key'))) {
|
||||||
//signuture valid
|
throw new InvalidTokenException('Token failed verification');
|
||||||
|
}
|
||||||
|
|
||||||
return $token;
|
return $token;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## Version 0.5 (2017-06-18)
|
||||||
|
- Update micropub client to allow indieweb users
|
||||||
|
- Update micropub endpoint to allow for entry updates
|
||||||
|
- Add support for checkins, so we can use ownyourswarm
|
||||||
|
|
||||||
## Version 0.4.2 (2017-03-24)
|
## Version 0.4.2 (2017-03-24)
|
||||||
- fixed issue#47, only the slug was being sent by client, which was messing up endpoint code
|
- fixed issue#47, only the slug was being sent by client, which was messing up endpoint code
|
||||||
- minor changes to es6 code, bet lint-staged working again
|
- minor changes to es6 code, bet lint-staged working again
|
||||||
|
|
|
@ -42,7 +42,10 @@
|
||||||
],
|
],
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"App\\": "app/"
|
"App\\": "app/"
|
||||||
}
|
},
|
||||||
|
"files": [
|
||||||
|
"helpers.php"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"autoload-dev": {
|
"autoload-dev": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
|
@ -67,6 +70,7 @@
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"preferred-install": "dist",
|
"preferred-install": "dist",
|
||||||
"sort-packages": true
|
"sort-packages": true,
|
||||||
|
"optimize-autoloader": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
381
composer.lock
generated
381
composer.lock
generated
|
@ -8,16 +8,16 @@
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "aws/aws-sdk-php",
|
"name": "aws/aws-sdk-php",
|
||||||
"version": "3.24.7",
|
"version": "3.27.2",
|
||||||
"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": "f062d7ea2123fe2aefef91da855c10ef8ff3af1c"
|
"reference": "eb10e43cccf8e868f9622ab8ce2beb9fb756b5a8"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/f062d7ea2123fe2aefef91da855c10ef8ff3af1c",
|
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/eb10e43cccf8e868f9622ab8ce2beb9fb756b5a8",
|
||||||
"reference": "f062d7ea2123fe2aefef91da855c10ef8ff3af1c",
|
"reference": "eb10e43cccf8e868f9622ab8ce2beb9fb756b5a8",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -39,7 +39,7 @@
|
||||||
"ext-simplexml": "*",
|
"ext-simplexml": "*",
|
||||||
"ext-spl": "*",
|
"ext-spl": "*",
|
||||||
"nette/neon": "^2.3",
|
"nette/neon": "^2.3",
|
||||||
"phpunit/phpunit": "~4.0|~5.0",
|
"phpunit/phpunit": "^4.8.35|^5.4.0",
|
||||||
"psr/cache": "^1.0"
|
"psr/cache": "^1.0"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
|
@ -84,7 +84,7 @@
|
||||||
"s3",
|
"s3",
|
||||||
"sdk"
|
"sdk"
|
||||||
],
|
],
|
||||||
"time": "2017-03-23T22:17:20+00:00"
|
"time": "2017-05-11T21:23:43+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "barnabywalters/mf-cleaner",
|
"name": "barnabywalters/mf-cleaner",
|
||||||
|
@ -180,6 +180,65 @@
|
||||||
],
|
],
|
||||||
"time": "2016-08-19T16:43:44+00:00"
|
"time": "2016-08-19T16:43:44+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "composer/ca-bundle",
|
||||||
|
"version": "1.0.7",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/composer/ca-bundle.git",
|
||||||
|
"reference": "b17e6153cb7f33c7e44eb59578dc12eee5dc8e12"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/composer/ca-bundle/zipball/b17e6153cb7f33c7e44eb59578dc12eee5dc8e12",
|
||||||
|
"reference": "b17e6153cb7f33c7e44eb59578dc12eee5dc8e12",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-openssl": "*",
|
||||||
|
"ext-pcre": "*",
|
||||||
|
"php": "^5.3.2 || ^7.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^4.5",
|
||||||
|
"psr/log": "^1.0",
|
||||||
|
"symfony/process": "^2.5 || ^3.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"symfony/process": "This is necessary to reliably check whether openssl_x509_parse is vulnerable on older php versions, but can be ignored on PHP 5.5.6+"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "1.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Composer\\CaBundle\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Jordi Boggiano",
|
||||||
|
"email": "j.boggiano@seld.be",
|
||||||
|
"homepage": "http://seld.be"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.",
|
||||||
|
"keywords": [
|
||||||
|
"cabundle",
|
||||||
|
"cacert",
|
||||||
|
"certificate",
|
||||||
|
"ssl",
|
||||||
|
"tls"
|
||||||
|
],
|
||||||
|
"time": "2017-03-06T11:59:08+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "dnoegel/php-xdg-base-dir",
|
"name": "dnoegel/php-xdg-base-dir",
|
||||||
"version": "0.1",
|
"version": "0.1",
|
||||||
|
@ -685,16 +744,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "erusev/parsedown",
|
"name": "erusev/parsedown",
|
||||||
"version": "1.6.1",
|
"version": "1.6.2",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/erusev/parsedown.git",
|
"url": "https://github.com/erusev/parsedown.git",
|
||||||
"reference": "20ff8bbb57205368b4b42d094642a3e52dac85fb"
|
"reference": "1bf24f7334fe16c88bf9d467863309ceaf285b01"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/erusev/parsedown/zipball/20ff8bbb57205368b4b42d094642a3e52dac85fb",
|
"url": "https://api.github.com/repos/erusev/parsedown/zipball/1bf24f7334fe16c88bf9d467863309ceaf285b01",
|
||||||
"reference": "20ff8bbb57205368b4b42d094642a3e52dac85fb",
|
"reference": "1bf24f7334fe16c88bf9d467863309ceaf285b01",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -723,7 +782,7 @@
|
||||||
"markdown",
|
"markdown",
|
||||||
"parser"
|
"parser"
|
||||||
],
|
],
|
||||||
"time": "2016-11-02T15:56:58+00:00"
|
"time": "2017-03-29T16:04:15+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "ezyang/htmlpurifier",
|
"name": "ezyang/htmlpurifier",
|
||||||
|
@ -1045,16 +1104,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "indieauth/client",
|
"name": "indieauth/client",
|
||||||
"version": "0.2.0",
|
"version": "0.2.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/indieweb/indieauth-client-php.git",
|
"url": "https://github.com/indieweb/indieauth-client-php.git",
|
||||||
"reference": "4b9bd766a92b8abbe420f5889bf7ebac7678151d"
|
"reference": "f5f6efad79334d1ff9370fe4dce8ccf4814820fa"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/indieweb/indieauth-client-php/zipball/4b9bd766a92b8abbe420f5889bf7ebac7678151d",
|
"url": "https://api.github.com/repos/indieweb/indieauth-client-php/zipball/f5f6efad79334d1ff9370fe4dce8ccf4814820fa",
|
||||||
"reference": "4b9bd766a92b8abbe420f5889bf7ebac7678151d",
|
"reference": "f5f6efad79334d1ff9370fe4dce8ccf4814820fa",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -1080,7 +1139,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "IndieAuth Client Library",
|
"description": "IndieAuth Client Library",
|
||||||
"time": "2017-02-09T23:42:05+00:00"
|
"time": "2017-04-26T21:44:35+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "indieweb/link-rel-parser",
|
"name": "indieweb/link-rel-parser",
|
||||||
|
@ -1405,16 +1464,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "laravel/framework",
|
"name": "laravel/framework",
|
||||||
"version": "v5.4.16",
|
"version": "v5.4.23",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/laravel/framework.git",
|
"url": "https://github.com/laravel/framework.git",
|
||||||
"reference": "6cf379ec34d08bcdc9c7183e369a8fdf04ade80d"
|
"reference": "ad82327705658dbf5f0ce72805caa950dfbe150d"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/laravel/framework/zipball/6cf379ec34d08bcdc9c7183e369a8fdf04ade80d",
|
"url": "https://api.github.com/repos/laravel/framework/zipball/ad82327705658dbf5f0ce72805caa950dfbe150d",
|
||||||
"reference": "6cf379ec34d08bcdc9c7183e369a8fdf04ade80d",
|
"reference": "ad82327705658dbf5f0ce72805caa950dfbe150d",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -1530,20 +1589,20 @@
|
||||||
"framework",
|
"framework",
|
||||||
"laravel"
|
"laravel"
|
||||||
],
|
],
|
||||||
"time": "2017-03-21T19:34:41+00:00"
|
"time": "2017-05-11T20:10:35+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "laravel/scout",
|
"name": "laravel/scout",
|
||||||
"version": "v3.0.2",
|
"version": "v3.0.3",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/laravel/scout.git",
|
"url": "https://github.com/laravel/scout.git",
|
||||||
"reference": "1ddb0fa6f165bf6a69864960102062e7cf3f989d"
|
"reference": "64d28db58a054174eadf1d4df38dad81ff7e68dd"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/laravel/scout/zipball/1ddb0fa6f165bf6a69864960102062e7cf3f989d",
|
"url": "https://api.github.com/repos/laravel/scout/zipball/64d28db58a054174eadf1d4df38dad81ff7e68dd",
|
||||||
"reference": "1ddb0fa6f165bf6a69864960102062e7cf3f989d",
|
"reference": "64d28db58a054174eadf1d4df38dad81ff7e68dd",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -1590,7 +1649,7 @@
|
||||||
"laravel",
|
"laravel",
|
||||||
"search"
|
"search"
|
||||||
],
|
],
|
||||||
"time": "2017-03-01T14:37:40+00:00"
|
"time": "2017-04-09T00:54:26+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "laravel/tinker",
|
"name": "laravel/tinker",
|
||||||
|
@ -1710,16 +1769,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "league/commonmark",
|
"name": "league/commonmark",
|
||||||
"version": "0.15.3",
|
"version": "0.15.4",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/thephpleague/commonmark.git",
|
"url": "https://github.com/thephpleague/commonmark.git",
|
||||||
"reference": "c8b43ee5821362216f8e9ac684f0f59de164edcc"
|
"reference": "c4c8e6bf99e62d9568875d9fc3ef473fe3e18e0c"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/thephpleague/commonmark/zipball/c8b43ee5821362216f8e9ac684f0f59de164edcc",
|
"url": "https://api.github.com/repos/thephpleague/commonmark/zipball/c4c8e6bf99e62d9568875d9fc3ef473fe3e18e0c",
|
||||||
"reference": "c8b43ee5821362216f8e9ac684f0f59de164edcc",
|
"reference": "c4c8e6bf99e62d9568875d9fc3ef473fe3e18e0c",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -1775,20 +1834,20 @@
|
||||||
"markdown",
|
"markdown",
|
||||||
"parser"
|
"parser"
|
||||||
],
|
],
|
||||||
"time": "2016-12-19T00:11:43+00:00"
|
"time": "2017-05-09T12:47:53+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "league/flysystem",
|
"name": "league/flysystem",
|
||||||
"version": "1.0.37",
|
"version": "1.0.40",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/thephpleague/flysystem.git",
|
"url": "https://github.com/thephpleague/flysystem.git",
|
||||||
"reference": "78b5cc4feb61a882302df4fbaf63b7662e5e4ccd"
|
"reference": "3828f0b24e2c1918bb362d57a53205d6dc8fde61"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/78b5cc4feb61a882302df4fbaf63b7662e5e4ccd",
|
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/3828f0b24e2c1918bb362d57a53205d6dc8fde61",
|
||||||
"reference": "78b5cc4feb61a882302df4fbaf63b7662e5e4ccd",
|
"reference": "3828f0b24e2c1918bb362d57a53205d6dc8fde61",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -1810,12 +1869,12 @@
|
||||||
"league/flysystem-azure": "Allows you to use Windows Azure Blob storage",
|
"league/flysystem-azure": "Allows you to use Windows Azure Blob storage",
|
||||||
"league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching",
|
"league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching",
|
||||||
"league/flysystem-copy": "Allows you to use Copy.com storage",
|
"league/flysystem-copy": "Allows you to use Copy.com storage",
|
||||||
"league/flysystem-dropbox": "Allows you to use Dropbox storage",
|
|
||||||
"league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem",
|
"league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem",
|
||||||
"league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files",
|
"league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files",
|
||||||
"league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib",
|
"league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib",
|
||||||
"league/flysystem-webdav": "Allows you to use WebDAV storage",
|
"league/flysystem-webdav": "Allows you to use WebDAV storage",
|
||||||
"league/flysystem-ziparchive": "Allows you to use ZipArchive adapter"
|
"league/flysystem-ziparchive": "Allows you to use ZipArchive adapter",
|
||||||
|
"spatie/flysystem-dropbox": "Allows you to use Dropbox storage"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
|
@ -1858,25 +1917,25 @@
|
||||||
"sftp",
|
"sftp",
|
||||||
"storage"
|
"storage"
|
||||||
],
|
],
|
||||||
"time": "2017-03-22T15:43:14+00:00"
|
"time": "2017-04-28T10:15:08+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "league/flysystem-aws-s3-v3",
|
"name": "league/flysystem-aws-s3-v3",
|
||||||
"version": "1.0.13",
|
"version": "1.0.15",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/thephpleague/flysystem-aws-s3-v3.git",
|
"url": "https://github.com/thephpleague/flysystem-aws-s3-v3.git",
|
||||||
"reference": "dc56a8faf3aff0841f9eae04b6af94a50657896c"
|
"reference": "c947f36f977b495a57e857ae1630df0da35ec456"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/dc56a8faf3aff0841f9eae04b6af94a50657896c",
|
"url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/c947f36f977b495a57e857ae1630df0da35ec456",
|
||||||
"reference": "dc56a8faf3aff0841f9eae04b6af94a50657896c",
|
"reference": "c947f36f977b495a57e857ae1630df0da35ec456",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"aws/aws-sdk-php": "^3.0.0",
|
"aws/aws-sdk-php": "^3.0.0",
|
||||||
"league/flysystem": "~1.0",
|
"league/flysystem": "^1.0.40",
|
||||||
"php": ">=5.5.0"
|
"php": ">=5.5.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
|
@ -1905,7 +1964,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "Flysystem adapter for the AWS S3 SDK v3.x",
|
"description": "Flysystem adapter for the AWS S3 SDK v3.x",
|
||||||
"time": "2016-06-21T21:34:35+00:00"
|
"time": "2017-04-28T10:21:54+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "martinbean/laravel-sluggable-trait",
|
"name": "martinbean/laravel-sluggable-trait",
|
||||||
|
@ -2658,16 +2717,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "ramsey/uuid",
|
"name": "ramsey/uuid",
|
||||||
"version": "3.6.0",
|
"version": "3.6.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/ramsey/uuid.git",
|
"url": "https://github.com/ramsey/uuid.git",
|
||||||
"reference": "0b7bdfb180e72c8d76e75a649ced67e392201458"
|
"reference": "4ae32dd9ab8860a4bbd750ad269cba7f06f7934e"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/ramsey/uuid/zipball/0b7bdfb180e72c8d76e75a649ced67e392201458",
|
"url": "https://api.github.com/repos/ramsey/uuid/zipball/4ae32dd9ab8860a4bbd750ad269cba7f06f7934e",
|
||||||
"reference": "0b7bdfb180e72c8d76e75a649ced67e392201458",
|
"reference": "4ae32dd9ab8860a4bbd750ad269cba7f06f7934e",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -2679,9 +2738,9 @@
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"apigen/apigen": "^4.1",
|
"apigen/apigen": "^4.1",
|
||||||
"codeception/aspect-mock": "1.0.0",
|
"codeception/aspect-mock": "^1.0 | ^2.0",
|
||||||
"doctrine/annotations": "~1.2.0",
|
"doctrine/annotations": "~1.2.0",
|
||||||
"goaop/framework": "1.0.0-alpha.2",
|
"goaop/framework": "1.0.0-alpha.2 | ^1.0 | ^2.1",
|
||||||
"ircmaxell/random-lib": "^1.1",
|
"ircmaxell/random-lib": "^1.1",
|
||||||
"jakub-onderka/php-parallel-lint": "^0.9.0",
|
"jakub-onderka/php-parallel-lint": "^0.9.0",
|
||||||
"mockery/mockery": "^0.9.4",
|
"mockery/mockery": "^0.9.4",
|
||||||
|
@ -2736,23 +2795,24 @@
|
||||||
"identifier",
|
"identifier",
|
||||||
"uuid"
|
"uuid"
|
||||||
],
|
],
|
||||||
"time": "2017-03-18T15:38:09+00:00"
|
"time": "2017-03-26T20:37:53+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sensiolabs/security-checker",
|
"name": "sensiolabs/security-checker",
|
||||||
"version": "v4.0.2",
|
"version": "v4.0.4",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sensiolabs/security-checker.git",
|
"url": "https://github.com/sensiolabs/security-checker.git",
|
||||||
"reference": "56bded66985e22f6eac2cf86735fd21c625bff2f"
|
"reference": "9e69eddf3bc49d1ee5c7908564da3141796d4bbc"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sensiolabs/security-checker/zipball/56bded66985e22f6eac2cf86735fd21c625bff2f",
|
"url": "https://api.github.com/repos/sensiolabs/security-checker/zipball/9e69eddf3bc49d1ee5c7908564da3141796d4bbc",
|
||||||
"reference": "56bded66985e22f6eac2cf86735fd21c625bff2f",
|
"reference": "9e69eddf3bc49d1ee5c7908564da3141796d4bbc",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
"composer/ca-bundle": "^1.0",
|
||||||
"symfony/console": "~2.7|~3.0"
|
"symfony/console": "~2.7|~3.0"
|
||||||
},
|
},
|
||||||
"bin": [
|
"bin": [
|
||||||
|
@ -2780,20 +2840,20 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "A security checker for your composer.lock",
|
"description": "A security checker for your composer.lock",
|
||||||
"time": "2017-03-09T17:33:20+00:00"
|
"time": "2017-03-31T14:50:32+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "swiftmailer/swiftmailer",
|
"name": "swiftmailer/swiftmailer",
|
||||||
"version": "v5.4.6",
|
"version": "v5.4.8",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/swiftmailer/swiftmailer.git",
|
"url": "https://github.com/swiftmailer/swiftmailer.git",
|
||||||
"reference": "81fdccfaf8bdc5d5d7a1ef6bb3a61bbb1a6c4a3e"
|
"reference": "9a06dc570a0367850280eefd3f1dc2da45aef517"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/81fdccfaf8bdc5d5d7a1ef6bb3a61bbb1a6c4a3e",
|
"url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/9a06dc570a0367850280eefd3f1dc2da45aef517",
|
||||||
"reference": "81fdccfaf8bdc5d5d7a1ef6bb3a61bbb1a6c4a3e",
|
"reference": "9a06dc570a0367850280eefd3f1dc2da45aef517",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -2834,20 +2894,20 @@
|
||||||
"mail",
|
"mail",
|
||||||
"mailer"
|
"mailer"
|
||||||
],
|
],
|
||||||
"time": "2017-02-13T07:52:53+00:00"
|
"time": "2017-05-01T15:54:03+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/console",
|
"name": "symfony/console",
|
||||||
"version": "v3.2.6",
|
"version": "v3.2.8",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/console.git",
|
"url": "https://github.com/symfony/console.git",
|
||||||
"reference": "28fb243a2b5727774ca309ec2d92da240f1af0dd"
|
"reference": "a7a17e0c6c3c4d70a211f80782e4b90ddadeaa38"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/console/zipball/28fb243a2b5727774ca309ec2d92da240f1af0dd",
|
"url": "https://api.github.com/repos/symfony/console/zipball/a7a17e0c6c3c4d70a211f80782e4b90ddadeaa38",
|
||||||
"reference": "28fb243a2b5727774ca309ec2d92da240f1af0dd",
|
"reference": "a7a17e0c6c3c4d70a211f80782e4b90ddadeaa38",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -2897,20 +2957,20 @@
|
||||||
],
|
],
|
||||||
"description": "Symfony Console Component",
|
"description": "Symfony Console Component",
|
||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
"time": "2017-03-06T19:30:27+00:00"
|
"time": "2017-04-26T01:39:17+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/css-selector",
|
"name": "symfony/css-selector",
|
||||||
"version": "v3.2.6",
|
"version": "v3.2.8",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/css-selector.git",
|
"url": "https://github.com/symfony/css-selector.git",
|
||||||
"reference": "a48f13dc83c168f1253a5d2a5a4fb46c36244c4c"
|
"reference": "02983c144038e697c959e6b06ef6666de759ccbc"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/css-selector/zipball/a48f13dc83c168f1253a5d2a5a4fb46c36244c4c",
|
"url": "https://api.github.com/repos/symfony/css-selector/zipball/02983c144038e697c959e6b06ef6666de759ccbc",
|
||||||
"reference": "a48f13dc83c168f1253a5d2a5a4fb46c36244c4c",
|
"reference": "02983c144038e697c959e6b06ef6666de759ccbc",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -2950,20 +3010,20 @@
|
||||||
],
|
],
|
||||||
"description": "Symfony CssSelector Component",
|
"description": "Symfony CssSelector Component",
|
||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
"time": "2017-02-21T09:12:04+00:00"
|
"time": "2017-05-01T14:55:58+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/debug",
|
"name": "symfony/debug",
|
||||||
"version": "v3.2.6",
|
"version": "v3.2.8",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/debug.git",
|
"url": "https://github.com/symfony/debug.git",
|
||||||
"reference": "b90c9f91ad8ac37d9f114e369042d3226b34dc1a"
|
"reference": "fd6eeee656a5a7b384d56f1072243fe1c0e81686"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/debug/zipball/b90c9f91ad8ac37d9f114e369042d3226b34dc1a",
|
"url": "https://api.github.com/repos/symfony/debug/zipball/fd6eeee656a5a7b384d56f1072243fe1c0e81686",
|
||||||
"reference": "b90c9f91ad8ac37d9f114e369042d3226b34dc1a",
|
"reference": "fd6eeee656a5a7b384d56f1072243fe1c0e81686",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -3007,20 +3067,20 @@
|
||||||
],
|
],
|
||||||
"description": "Symfony Debug Component",
|
"description": "Symfony Debug Component",
|
||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
"time": "2017-02-18T17:28:00+00:00"
|
"time": "2017-04-19T20:17:50+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/event-dispatcher",
|
"name": "symfony/event-dispatcher",
|
||||||
"version": "v3.2.6",
|
"version": "v3.2.8",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/event-dispatcher.git",
|
"url": "https://github.com/symfony/event-dispatcher.git",
|
||||||
"reference": "b7a1b9e0a0f623ce43b4c8d775eb138f190c9d8d"
|
"reference": "b8a401f733b43251e1d088c589368b2a94155e40"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b7a1b9e0a0f623ce43b4c8d775eb138f190c9d8d",
|
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b8a401f733b43251e1d088c589368b2a94155e40",
|
||||||
"reference": "b7a1b9e0a0f623ce43b4c8d775eb138f190c9d8d",
|
"reference": "b8a401f733b43251e1d088c589368b2a94155e40",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -3067,20 +3127,20 @@
|
||||||
],
|
],
|
||||||
"description": "Symfony EventDispatcher Component",
|
"description": "Symfony EventDispatcher Component",
|
||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
"time": "2017-02-21T09:12:04+00:00"
|
"time": "2017-05-01T14:58:48+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/finder",
|
"name": "symfony/finder",
|
||||||
"version": "v3.2.6",
|
"version": "v3.2.8",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/finder.git",
|
"url": "https://github.com/symfony/finder.git",
|
||||||
"reference": "92d7476d2df60cd851a3e13e078664b1deb8ce10"
|
"reference": "9cf076f8f492f4b1ffac40aae9c2d287b4ca6930"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/finder/zipball/92d7476d2df60cd851a3e13e078664b1deb8ce10",
|
"url": "https://api.github.com/repos/symfony/finder/zipball/9cf076f8f492f4b1ffac40aae9c2d287b4ca6930",
|
||||||
"reference": "92d7476d2df60cd851a3e13e078664b1deb8ce10",
|
"reference": "9cf076f8f492f4b1ffac40aae9c2d287b4ca6930",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -3116,20 +3176,20 @@
|
||||||
],
|
],
|
||||||
"description": "Symfony Finder Component",
|
"description": "Symfony Finder Component",
|
||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
"time": "2017-02-21T09:12:04+00:00"
|
"time": "2017-04-12T14:13:17+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/http-foundation",
|
"name": "symfony/http-foundation",
|
||||||
"version": "v3.2.6",
|
"version": "v3.2.8",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/http-foundation.git",
|
"url": "https://github.com/symfony/http-foundation.git",
|
||||||
"reference": "c57009887010eb4e58bfca2970314a5b820b24b9"
|
"reference": "9de6add7f731e5af7f5b2e9c0da365e43383ebef"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/c57009887010eb4e58bfca2970314a5b820b24b9",
|
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/9de6add7f731e5af7f5b2e9c0da365e43383ebef",
|
||||||
"reference": "c57009887010eb4e58bfca2970314a5b820b24b9",
|
"reference": "9de6add7f731e5af7f5b2e9c0da365e43383ebef",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -3169,20 +3229,20 @@
|
||||||
],
|
],
|
||||||
"description": "Symfony HttpFoundation Component",
|
"description": "Symfony HttpFoundation Component",
|
||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
"time": "2017-03-04T12:23:14+00:00"
|
"time": "2017-05-01T14:55:58+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/http-kernel",
|
"name": "symfony/http-kernel",
|
||||||
"version": "v3.2.6",
|
"version": "v3.2.8",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/http-kernel.git",
|
"url": "https://github.com/symfony/http-kernel.git",
|
||||||
"reference": "bc909e85b8585c9edf043d0fca871308c41bb9b4"
|
"reference": "46e8b209abab55c072c47d72d5cd1d62c0585e05"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/bc909e85b8585c9edf043d0fca871308c41bb9b4",
|
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/46e8b209abab55c072c47d72d5cd1d62c0585e05",
|
||||||
"reference": "bc909e85b8585c9edf043d0fca871308c41bb9b4",
|
"reference": "46e8b209abab55c072c47d72d5cd1d62c0585e05",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -3251,7 +3311,7 @@
|
||||||
],
|
],
|
||||||
"description": "Symfony HttpKernel Component",
|
"description": "Symfony HttpKernel Component",
|
||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
"time": "2017-03-10T18:35:31+00:00"
|
"time": "2017-05-01T17:46:48+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/polyfill-mbstring",
|
"name": "symfony/polyfill-mbstring",
|
||||||
|
@ -3314,16 +3374,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/process",
|
"name": "symfony/process",
|
||||||
"version": "v3.2.6",
|
"version": "v3.2.8",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/process.git",
|
"url": "https://github.com/symfony/process.git",
|
||||||
"reference": "68bfa8c83f24c0ac04ea7193bcdcda4519f41892"
|
"reference": "999c2cf5061e627e6cd551dc9ebf90dd1d11d9f0"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/process/zipball/68bfa8c83f24c0ac04ea7193bcdcda4519f41892",
|
"url": "https://api.github.com/repos/symfony/process/zipball/999c2cf5061e627e6cd551dc9ebf90dd1d11d9f0",
|
||||||
"reference": "68bfa8c83f24c0ac04ea7193bcdcda4519f41892",
|
"reference": "999c2cf5061e627e6cd551dc9ebf90dd1d11d9f0",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -3359,20 +3419,20 @@
|
||||||
],
|
],
|
||||||
"description": "Symfony Process Component",
|
"description": "Symfony Process Component",
|
||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
"time": "2017-03-04T12:23:14+00:00"
|
"time": "2017-04-12T14:13:17+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/routing",
|
"name": "symfony/routing",
|
||||||
"version": "v3.2.6",
|
"version": "v3.2.8",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/routing.git",
|
"url": "https://github.com/symfony/routing.git",
|
||||||
"reference": "d6605f9a5767bc5bc4895e1c762ba93964608aee"
|
"reference": "5029745d6d463585e8b487dbc83d6333f408853a"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/routing/zipball/d6605f9a5767bc5bc4895e1c762ba93964608aee",
|
"url": "https://api.github.com/repos/symfony/routing/zipball/5029745d6d463585e8b487dbc83d6333f408853a",
|
||||||
"reference": "d6605f9a5767bc5bc4895e1c762ba93964608aee",
|
"reference": "5029745d6d463585e8b487dbc83d6333f408853a",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -3434,20 +3494,20 @@
|
||||||
"uri",
|
"uri",
|
||||||
"url"
|
"url"
|
||||||
],
|
],
|
||||||
"time": "2017-03-02T15:58:09+00:00"
|
"time": "2017-04-12T14:13:17+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/translation",
|
"name": "symfony/translation",
|
||||||
"version": "v3.2.6",
|
"version": "v3.2.8",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/translation.git",
|
"url": "https://github.com/symfony/translation.git",
|
||||||
"reference": "0e1b15ce8fbf3890f4ccdac430ed5e07fdfe0690"
|
"reference": "f4a04d2df710f81515df576b2de06bdeee518b83"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/translation/zipball/0e1b15ce8fbf3890f4ccdac430ed5e07fdfe0690",
|
"url": "https://api.github.com/repos/symfony/translation/zipball/f4a04d2df710f81515df576b2de06bdeee518b83",
|
||||||
"reference": "0e1b15ce8fbf3890f4ccdac430ed5e07fdfe0690",
|
"reference": "f4a04d2df710f81515df576b2de06bdeee518b83",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -3498,20 +3558,20 @@
|
||||||
],
|
],
|
||||||
"description": "Symfony Translation Component",
|
"description": "Symfony Translation Component",
|
||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
"time": "2017-03-04T12:23:14+00:00"
|
"time": "2017-04-12T14:13:17+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/var-dumper",
|
"name": "symfony/var-dumper",
|
||||||
"version": "v3.2.6",
|
"version": "v3.2.8",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/var-dumper.git",
|
"url": "https://github.com/symfony/var-dumper.git",
|
||||||
"reference": "4100f347aff890bc16b0b4b42843b599db257b2d"
|
"reference": "fa47963ac7979ddbd42b2d646d1b056bddbf7bb8"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/4100f347aff890bc16b0b4b42843b599db257b2d",
|
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/fa47963ac7979ddbd42b2d646d1b056bddbf7bb8",
|
||||||
"reference": "4100f347aff890bc16b0b4b42843b599db257b2d",
|
"reference": "fa47963ac7979ddbd42b2d646d1b056bddbf7bb8",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -3522,9 +3582,11 @@
|
||||||
"phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0"
|
"phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
|
"ext-iconv": "*",
|
||||||
"twig/twig": "~1.20|~2.0"
|
"twig/twig": "~1.20|~2.0"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
|
"ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).",
|
||||||
"ext-symfony_debug": ""
|
"ext-symfony_debug": ""
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
|
@ -3564,7 +3626,7 @@
|
||||||
"debug",
|
"debug",
|
||||||
"dump"
|
"dump"
|
||||||
],
|
],
|
||||||
"time": "2017-02-20T13:45:48+00:00"
|
"time": "2017-05-01T14:55:58+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "themattharris/tmhoauth",
|
"name": "themattharris/tmhoauth",
|
||||||
|
@ -3610,16 +3672,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "thujohn/twitter",
|
"name": "thujohn/twitter",
|
||||||
"version": "2.2.2",
|
"version": "2.2.5",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/thujohn/twitter.git",
|
"url": "https://github.com/thujohn/twitter.git",
|
||||||
"reference": "203d903856212835206675ae9c0504d74b681886"
|
"reference": "ff414bdadba3f1570ca211355e5359ec266552d8"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/thujohn/twitter/zipball/203d903856212835206675ae9c0504d74b681886",
|
"url": "https://api.github.com/repos/thujohn/twitter/zipball/ff414bdadba3f1570ca211355e5359ec266552d8",
|
||||||
"reference": "203d903856212835206675ae9c0504d74b681886",
|
"reference": "ff414bdadba3f1570ca211355e5359ec266552d8",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -3650,7 +3712,7 @@
|
||||||
"laravel5",
|
"laravel5",
|
||||||
"twitter"
|
"twitter"
|
||||||
],
|
],
|
||||||
"time": "2017-01-31T23:37:52+00:00"
|
"time": "2017-04-27T09:00:04+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "tijsverkoyen/css-to-inline-styles",
|
"name": "tijsverkoyen/css-to-inline-styles",
|
||||||
|
@ -3861,16 +3923,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "facebook/webdriver",
|
"name": "facebook/webdriver",
|
||||||
"version": "1.4.0",
|
"version": "1.4.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/facebook/php-webdriver.git",
|
"url": "https://github.com/facebook/php-webdriver.git",
|
||||||
"reference": "3ea034c056189e11c0ce7985332a9f4b5b2b5db2"
|
"reference": "eadb0b7a7c3e6578185197fd40158b08c3164c83"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/facebook/php-webdriver/zipball/3ea034c056189e11c0ce7985332a9f4b5b2b5db2",
|
"url": "https://api.github.com/repos/facebook/php-webdriver/zipball/eadb0b7a7c3e6578185197fd40158b08c3164c83",
|
||||||
"reference": "3ea034c056189e11c0ce7985332a9f4b5b2b5db2",
|
"reference": "eadb0b7a7c3e6578185197fd40158b08c3164c83",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -3909,7 +3971,7 @@
|
||||||
"selenium",
|
"selenium",
|
||||||
"webdriver"
|
"webdriver"
|
||||||
],
|
],
|
||||||
"time": "2017-03-22T10:56:03+00:00"
|
"time": "2017-04-28T14:54:49+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "fzaninotto/faker",
|
"name": "fzaninotto/faker",
|
||||||
|
@ -4053,21 +4115,22 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "laravel/dusk",
|
"name": "laravel/dusk",
|
||||||
"version": "v1.0.10",
|
"version": "v1.1.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/laravel/dusk.git",
|
"url": "https://github.com/laravel/dusk.git",
|
||||||
"reference": "11537ac1a939a2194e9e3cdc2536e6e34eff9ea6"
|
"reference": "6b81e97ae1ce384e3d8dbd020b2b9751c1449889"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/laravel/dusk/zipball/11537ac1a939a2194e9e3cdc2536e6e34eff9ea6",
|
"url": "https://api.github.com/repos/laravel/dusk/zipball/6b81e97ae1ce384e3d8dbd020b2b9751c1449889",
|
||||||
"reference": "11537ac1a939a2194e9e3cdc2536e6e34eff9ea6",
|
"reference": "6b81e97ae1ce384e3d8dbd020b2b9751c1449889",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"facebook/webdriver": "~1.0",
|
"facebook/webdriver": "~1.0",
|
||||||
"illuminate/support": "~5.3",
|
"illuminate/console": "~5.4",
|
||||||
|
"illuminate/support": "~5.4",
|
||||||
"nesbot/carbon": "~1.20",
|
"nesbot/carbon": "~1.20",
|
||||||
"php": ">=5.6.4",
|
"php": ">=5.6.4",
|
||||||
"symfony/console": "~3.2",
|
"symfony/console": "~3.2",
|
||||||
|
@ -4104,7 +4167,7 @@
|
||||||
"testing",
|
"testing",
|
||||||
"webdriver"
|
"webdriver"
|
||||||
],
|
],
|
||||||
"time": "2017-03-03T14:36:19+00:00"
|
"time": "2017-04-23T17:13:04+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "maximebf/debugbar",
|
"name": "maximebf/debugbar",
|
||||||
|
@ -4172,12 +4235,12 @@
|
||||||
"version": "0.9.9",
|
"version": "0.9.9",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/padraic/mockery.git",
|
"url": "https://github.com/mockery/mockery.git",
|
||||||
"reference": "6fdb61243844dc924071d3404bb23994ea0b6856"
|
"reference": "6fdb61243844dc924071d3404bb23994ea0b6856"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/padraic/mockery/zipball/6fdb61243844dc924071d3404bb23994ea0b6856",
|
"url": "https://api.github.com/repos/mockery/mockery/zipball/6fdb61243844dc924071d3404bb23994ea0b6856",
|
||||||
"reference": "6fdb61243844dc924071d3404bb23994ea0b6856",
|
"reference": "6fdb61243844dc924071d3404bb23994ea0b6856",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
|
@ -4234,16 +4297,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "myclabs/deep-copy",
|
"name": "myclabs/deep-copy",
|
||||||
"version": "1.6.0",
|
"version": "1.6.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/myclabs/DeepCopy.git",
|
"url": "https://github.com/myclabs/DeepCopy.git",
|
||||||
"reference": "5a5a9fc8025a08d8919be87d6884d5a92520cefe"
|
"reference": "8e6e04167378abf1ddb4d3522d8755c5fd90d102"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/5a5a9fc8025a08d8919be87d6884d5a92520cefe",
|
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/8e6e04167378abf1ddb4d3522d8755c5fd90d102",
|
||||||
"reference": "5a5a9fc8025a08d8919be87d6884d5a92520cefe",
|
"reference": "8e6e04167378abf1ddb4d3522d8755c5fd90d102",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -4272,7 +4335,7 @@
|
||||||
"object",
|
"object",
|
||||||
"object graph"
|
"object graph"
|
||||||
],
|
],
|
||||||
"time": "2017-01-26T22:05:40+00:00"
|
"time": "2017-04-12T18:52:22+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpdocumentor/reflection-common",
|
"name": "phpdocumentor/reflection-common",
|
||||||
|
@ -4485,16 +4548,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/php-code-coverage",
|
"name": "phpunit/php-code-coverage",
|
||||||
"version": "4.0.7",
|
"version": "4.0.8",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||||
"reference": "09e2277d14ea467e5a984010f501343ef29ffc69"
|
"reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/09e2277d14ea467e5a984010f501343ef29ffc69",
|
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ef7b2f56815df854e66ceaee8ebe9393ae36a40d",
|
||||||
"reference": "09e2277d14ea467e5a984010f501343ef29ffc69",
|
"reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -4544,7 +4607,7 @@
|
||||||
"testing",
|
"testing",
|
||||||
"xunit"
|
"xunit"
|
||||||
],
|
],
|
||||||
"time": "2017-03-01T09:12:17+00:00"
|
"time": "2017-04-02T07:44:40+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/php-file-iterator",
|
"name": "phpunit/php-file-iterator",
|
||||||
|
@ -4734,16 +4797,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/phpunit",
|
"name": "phpunit/phpunit",
|
||||||
"version": "5.7.17",
|
"version": "5.7.19",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||||
"reference": "68752b665d3875f9a38a357e3ecb35c79f8673bf"
|
"reference": "69c4f49ff376af2692bad9cebd883d17ebaa98a1"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/68752b665d3875f9a38a357e3ecb35c79f8673bf",
|
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/69c4f49ff376af2692bad9cebd883d17ebaa98a1",
|
||||||
"reference": "68752b665d3875f9a38a357e3ecb35c79f8673bf",
|
"reference": "69c4f49ff376af2692bad9cebd883d17ebaa98a1",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -4812,7 +4875,7 @@
|
||||||
"testing",
|
"testing",
|
||||||
"xunit"
|
"xunit"
|
||||||
],
|
],
|
||||||
"time": "2017-03-19T16:52:12+00:00"
|
"time": "2017-04-03T02:22:27+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/phpunit-mock-objects",
|
"name": "phpunit/phpunit-mock-objects",
|
||||||
|
@ -5477,16 +5540,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/yaml",
|
"name": "symfony/yaml",
|
||||||
"version": "v3.2.6",
|
"version": "v3.2.8",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/yaml.git",
|
"url": "https://github.com/symfony/yaml.git",
|
||||||
"reference": "093e416ad096355149e265ea2e4cc1f9ee40ab1a"
|
"reference": "acec26fcf7f3031e094e910b94b002fa53d4e4d6"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/093e416ad096355149e265ea2e4cc1f9ee40ab1a",
|
"url": "https://api.github.com/repos/symfony/yaml/zipball/acec26fcf7f3031e094e910b94b002fa53d4e4d6",
|
||||||
"reference": "093e416ad096355149e265ea2e4cc1f9ee40ab1a",
|
"reference": "acec26fcf7f3031e094e910b94b002fa53d4e4d6",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -5528,20 +5591,20 @@
|
||||||
],
|
],
|
||||||
"description": "Symfony Yaml Component",
|
"description": "Symfony Yaml Component",
|
||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
"time": "2017-03-07T16:47:02+00:00"
|
"time": "2017-05-01T14:55:58+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "theseer/fdomdocument",
|
"name": "theseer/fdomdocument",
|
||||||
"version": "1.6.1",
|
"version": "1.6.5",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/theseer/fDOMDocument.git",
|
"url": "https://github.com/theseer/fDOMDocument.git",
|
||||||
"reference": "d9ad139d6c2e8edf5e313ffbe37ff13344cf0684"
|
"reference": "8dcfd392135a5bd938c3c83ea71419501ad9855d"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/theseer/fDOMDocument/zipball/d9ad139d6c2e8edf5e313ffbe37ff13344cf0684",
|
"url": "https://api.github.com/repos/theseer/fDOMDocument/zipball/8dcfd392135a5bd938c3c83ea71419501ad9855d",
|
||||||
"reference": "d9ad139d6c2e8edf5e313ffbe37ff13344cf0684",
|
"reference": "8dcfd392135a5bd938c3c83ea71419501ad9855d",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -5568,7 +5631,7 @@
|
||||||
],
|
],
|
||||||
"description": "The classes contained within this repository extend the standard DOM to use exceptions at all occasions of errors instead of PHP warnings or notices. They also add various custom methods and shortcuts for convenience and to simplify the usage of DOM.",
|
"description": "The classes contained within this repository extend the standard DOM to use exceptions at all occasions of errors instead of PHP warnings or notices. They also add various custom methods and shortcuts for convenience and to simplify the usage of DOM.",
|
||||||
"homepage": "https://github.com/theseer/fDOMDocument",
|
"homepage": "https://github.com/theseer/fDOMDocument",
|
||||||
"time": "2015-05-27T22:58:02+00:00"
|
"time": "2017-04-21T14:50:31+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "webmozart/assert",
|
"name": "webmozart/assert",
|
||||||
|
|
|
@ -46,8 +46,9 @@ return [
|
||||||
'database' => env('DB_DATABASE', 'forge'),
|
'database' => env('DB_DATABASE', 'forge'),
|
||||||
'username' => env('DB_USERNAME', 'forge'),
|
'username' => env('DB_USERNAME', 'forge'),
|
||||||
'password' => env('DB_PASSWORD', ''),
|
'password' => env('DB_PASSWORD', ''),
|
||||||
'charset' => 'utf8',
|
'unix_socket' => env('DB_SOCKET', ''),
|
||||||
'collation' => 'utf8_unicode_ci',
|
'charset' => 'utf8mb4',
|
||||||
|
'collation' => 'utf8mb4_unicode_ci',
|
||||||
'prefix' => '',
|
'prefix' => '',
|
||||||
'strict' => true,
|
'strict' => true,
|
||||||
'engine' => null,
|
'engine' => null,
|
||||||
|
|
|
@ -14,7 +14,7 @@ return [
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'paths' => [
|
'paths' => [
|
||||||
realpath(base_path('resources/views')),
|
resource_path('views'),
|
||||||
],
|
],
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
class CreateIndieWebUsersTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('indie_web_users', function (Blueprint $table) {
|
||||||
|
$table->increments('id');
|
||||||
|
$table->string('me')->unique();
|
||||||
|
$table->text('token')->nullable();
|
||||||
|
$table->string('syntax')->default('json');
|
||||||
|
$table->jsonb('syndication')->nullable();
|
||||||
|
$table->string('mediaEndpoint')->nullable();
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('indie_web_users');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
class UpdateNotesTableAddSwarmUrl extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('notes', function (Blueprint $table) {
|
||||||
|
$table->string('swarm_url')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('notes', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('swarm_url');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
class UpdatePlacesTableAddFoursquareColumn extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('places', function (Blueprint $table) {
|
||||||
|
$table->string('foursquare')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('places', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('foursquare');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,5 +17,6 @@ class DatabaseSeeder extends Seeder
|
||||||
$this->call(PlacesTableSeeder::class);
|
$this->call(PlacesTableSeeder::class);
|
||||||
$this->call(NotesTableSeeder::class);
|
$this->call(NotesTableSeeder::class);
|
||||||
$this->call(WebMentionsTableSeeder::class);
|
$this->call(WebMentionsTableSeeder::class);
|
||||||
|
$this->call(IndieWebUserTableSeeder::class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
16
database/seeds/IndieWebUserTableSeeder.php
Normal file
16
database/seeds/IndieWebUserTableSeeder.php
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
|
||||||
|
class IndieWebUserTableSeeder extends Seeder
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the database seeds.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
App\IndieWebUser::create(['me' => config('app.url')]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,8 @@
|
||||||
echo "Putting the Laravel app in maintenance mode"
|
echo "Putting the Laravel app in maintenance mode"
|
||||||
php artisan down
|
php artisan down
|
||||||
|
|
||||||
echo "Updating composer dependencies"
|
echo "Updating composer and dependencies"
|
||||||
|
composer self-update
|
||||||
composer install
|
composer install
|
||||||
|
|
||||||
echo "Caching Laravel route and config files"
|
echo "Caching Laravel route and config files"
|
||||||
|
|
199
helpers.php
Normal file
199
helpers.php
Normal file
|
@ -0,0 +1,199 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
helpers.php
|
||||||
|
*/
|
||||||
|
|
||||||
|
// sourced from https://github.com/flattr/normalize-url/blob/master/normalize_url.php
|
||||||
|
if (! function_exists('normalize_url')) {
|
||||||
|
function normalize_url(?string $url): ?string
|
||||||
|
{
|
||||||
|
if ($url === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$newUrl = '';
|
||||||
|
$url = parse_url($url);
|
||||||
|
$defaultSchemes = ['http' => 80, 'https' => 443];
|
||||||
|
if (isset($url['scheme'])) {
|
||||||
|
$url['scheme'] = strtolower($url['scheme']);
|
||||||
|
// Strip scheme default ports
|
||||||
|
if (isset($defaultSchemes[$url['scheme']]) &&
|
||||||
|
isset($url['port']) &&
|
||||||
|
$defaultSchemes[$url['scheme']] == $url['port']
|
||||||
|
) {
|
||||||
|
unset($url['port']);
|
||||||
|
}
|
||||||
|
$newUrl .= "{$url['scheme']}://";
|
||||||
|
}
|
||||||
|
if (isset($url['host'])) {
|
||||||
|
$url['host'] = mb_strtolower($url['host']);
|
||||||
|
$newUrl .= $url['host'];
|
||||||
|
}
|
||||||
|
if (isset($url['port'])) {
|
||||||
|
$newUrl .= ":{$url['port']}";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($url['path'])) {
|
||||||
|
// Case normalization
|
||||||
|
$url['path'] = normalizer_normalize($url['path'], Normalizer::FORM_C);
|
||||||
|
// Strip duplicate slashes
|
||||||
|
while (preg_match("/\/\//", $url['path'])) {
|
||||||
|
$url['path'] = preg_replace('/\/\//', '/', $url['path']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Decode unreserved characters, http://www.apps.ietf.org/rfc/rfc3986.html#sec-2.3
|
||||||
|
* Heavily rewritten version of urlDecodeUnreservedChars() in Glen Scott's url-normalizer.
|
||||||
|
*/
|
||||||
|
$u = [];
|
||||||
|
for ($o = 65; $o <= 90; $o++) {
|
||||||
|
$u[] = dechex($o);
|
||||||
|
}
|
||||||
|
for ($o = 97; $o <= 122; $o++) {
|
||||||
|
$u[] = dechex($o);
|
||||||
|
}
|
||||||
|
for ($o = 48; $o <= 57; $o++) {
|
||||||
|
$u[] = dechex($o);
|
||||||
|
}
|
||||||
|
$chrs = ['-', '.', '_', '~'];
|
||||||
|
foreach ($chrs as $chr) {
|
||||||
|
$u[] = dechex(ord($chr));
|
||||||
|
}
|
||||||
|
$url['path'] = preg_replace_callback(
|
||||||
|
array_map(
|
||||||
|
create_function('$str', 'return "/%" . strtoupper($str) . "/x";'),
|
||||||
|
$u
|
||||||
|
),
|
||||||
|
create_function('$matches', 'return chr(hexdec($matches[0]));'),
|
||||||
|
$url['path']
|
||||||
|
);
|
||||||
|
// Remove directory index
|
||||||
|
$defaultIndexes = ["/default\.aspx/" => 'default.aspx/', "/default\.asp/" => 'default.asp/',
|
||||||
|
"/index\.html/" => 'index.html/', "/index\.htm/" => 'index.htm/',
|
||||||
|
"/default\.html/" => 'default.html/', "/default\.htm/" => 'default.htm/',
|
||||||
|
"/index\.php/" => 'index.php/', "/index\.jsp/" => 'index.jsp/', ];
|
||||||
|
foreach ($defaultIndexes as $index => $strip) {
|
||||||
|
if (preg_match($index, $url['path'])) {
|
||||||
|
$url['path'] = str_replace($strip, '', $url['path']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// here we only want to drop a slash for the root domain
|
||||||
|
// e.g. http://example.com/ -> http://example.com
|
||||||
|
// but http://example.com/path/ -/-> http://example.com/path
|
||||||
|
if ($url['path'] == '/') {
|
||||||
|
unset($url['path']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Path segment normalization, http://www.apps.ietf.org/rfc/rfc3986.html#sec-5.2.4
|
||||||
|
* Heavily rewritten version of removeDotSegments() in Glen Scott's url-normalizer.
|
||||||
|
*/
|
||||||
|
$new_path = '';
|
||||||
|
while (! empty($url['path'])) {
|
||||||
|
if (preg_match('!^(\.\./|\./)!x', $url['path'])) {
|
||||||
|
$url['path'] = preg_replace('!^(\.\./|\./)!x', '', $url['path']);
|
||||||
|
} elseif (preg_match('!^(/\./)!x', $url['path'], $matches)
|
||||||
|
|| preg_match('!^(/\.)$!x', $url['path'], $matches)) {
|
||||||
|
$url['path'] = preg_replace('!^' . $matches[1] . '!', '/', $url['path']);
|
||||||
|
} elseif (preg_match('!^(/\.\./|/\.\.)!x', $url['path'], $matches)) {
|
||||||
|
$url['path'] = preg_replace('!^' . preg_quote($matches[1], '!') . '!x', '/', $url['path']);
|
||||||
|
$new_path = preg_replace('!/([^/]+)$!x', '', $new_path);
|
||||||
|
} elseif (preg_match('!^(\.|\.\.)$!x', $url['path'])) {
|
||||||
|
$url['path'] = preg_replace('!^(\.|\.\.)$!x', '', $url['path']);
|
||||||
|
} else {
|
||||||
|
if (preg_match('!(/*[^/]*)!x', $url['path'], $matches)) {
|
||||||
|
$first_path_segment = $matches[1];
|
||||||
|
$url['path'] = preg_replace('/^' . preg_quote($first_path_segment, '/') . '/', '', $url['path'], 1);
|
||||||
|
$new_path .= $first_path_segment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$newUrl .= $new_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($url['fragment'])) {
|
||||||
|
unset($url['fragment']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort GET params alphabetically, not because the RFC requires it but because it's cool!
|
||||||
|
if (isset($url['query'])) {
|
||||||
|
if (preg_match('/&/', $url['query'])) {
|
||||||
|
$s = explode('&', $url['query']);
|
||||||
|
$url['query'] = '';
|
||||||
|
sort($s);
|
||||||
|
foreach ($s as $z) {
|
||||||
|
$url['query'] .= "{$z}&";
|
||||||
|
}
|
||||||
|
$url['query'] = preg_replace('/&\Z/', '', $url['query']);
|
||||||
|
}
|
||||||
|
$newUrl .= "?{$url['query']}";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $newUrl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sourced from https://stackoverflow.com/a/9776726
|
||||||
|
if (! function_exists('prettyPrintJson')) {
|
||||||
|
function prettyPrintJson(string $json): string
|
||||||
|
{
|
||||||
|
$result = '';
|
||||||
|
$level = 0;
|
||||||
|
$in_quotes = false;
|
||||||
|
$in_escape = false;
|
||||||
|
$ends_line_level = null;
|
||||||
|
$json_length = strlen($json);
|
||||||
|
|
||||||
|
for ($i = 0; $i < $json_length; $i++) {
|
||||||
|
$char = $json[$i];
|
||||||
|
$new_line_level = null;
|
||||||
|
$post = '';
|
||||||
|
if ($ends_line_level !== null) {
|
||||||
|
$new_line_level = $ends_line_level;
|
||||||
|
$ends_line_level = null;
|
||||||
|
}
|
||||||
|
if ($in_escape) {
|
||||||
|
$in_escape = false;
|
||||||
|
} elseif ($char === '"') {
|
||||||
|
$in_quotes = ! $in_quotes;
|
||||||
|
} elseif (! $in_quotes) {
|
||||||
|
switch ($char) {
|
||||||
|
case '}':
|
||||||
|
case ']':
|
||||||
|
$level--;
|
||||||
|
$ends_line_level = null;
|
||||||
|
$new_line_level = $level;
|
||||||
|
break;
|
||||||
|
case '{':
|
||||||
|
case '[':
|
||||||
|
$level++;
|
||||||
|
//no break
|
||||||
|
case ',':
|
||||||
|
$ends_line_level = $level;
|
||||||
|
break;
|
||||||
|
case ':':
|
||||||
|
$post = ' ';
|
||||||
|
break;
|
||||||
|
case ' ':
|
||||||
|
case "\t":
|
||||||
|
case "\n":
|
||||||
|
case "\r":
|
||||||
|
$char = '';
|
||||||
|
$ends_line_level = $new_line_level;
|
||||||
|
$new_line_level = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} elseif ($char === '\\') {
|
||||||
|
$in_escape = true;
|
||||||
|
}
|
||||||
|
if ($new_line_level !== null) {
|
||||||
|
$result .= "\n".str_repeat("\t", $new_line_level);
|
||||||
|
}
|
||||||
|
$result .= $char.$post;
|
||||||
|
}
|
||||||
|
|
||||||
|
return str_replace("\t", ' ', $result);
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,15 +6,15 @@
|
||||||
"license": "CC0-1.0",
|
"license": "CC0-1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"alertify.js": "^1.0.12",
|
"alertify.js": "^1.0.12",
|
||||||
"mapbox-gl": "^0.34.0",
|
"mapbox-gl": "0.37.0",
|
||||||
"marked": "^0.3.6",
|
"marked": "^0.3.6",
|
||||||
"normalize.css": "^5.0.0",
|
"normalize.css": "7.0.0",
|
||||||
"webStorage": "^1.2.2"
|
"webStorage": "^1.2.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-cli": "^6.18.0",
|
"babel-cli": "^6.18.0",
|
||||||
"babel-core": "^6.21.0",
|
"babel-core": "^6.21.0",
|
||||||
"babel-loader": "^6.2.10",
|
"babel-loader": "7.0.0",
|
||||||
"babel-preset-env": "^1.2.2",
|
"babel-preset-env": "^1.2.2",
|
||||||
"babel-preset-es2015": "^6.18.0",
|
"babel-preset-es2015": "^6.18.0",
|
||||||
"babel-preset-latest": "^6.16.0",
|
"babel-preset-latest": "^6.16.0",
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
94
public/assets/prism/prism.css
vendored
94
public/assets/prism/prism.css
vendored
|
@ -1,20 +1,21 @@
|
||||||
/* http://prismjs.com/download.html?themes=prism-dark&languages=markup+css+clike+javascript+git+http+markdown+php+php-extras+scss+sql&plugins=line-numbers+show-invisibles */
|
/* http://prismjs.com/download.html?themes=prism-okaidia&languages=markup+css+clike+javascript+bash+c+csharp+cpp+ruby+css-extras+diff+git+go+http+ini+json+latex+lua+makefile+markdown+nginx+objectivec+php+php-extras+python+rust+sass+scss+sql+swift+vim+wiki+yaml&plugins=line-numbers+autolinker */
|
||||||
/**
|
/**
|
||||||
* prism.js Dark theme for JavaScript, CSS and HTML
|
* okaidia theme for JavaScript, CSS and HTML
|
||||||
* Based on the slides of the talk “/Reg(exp){2}lained/”
|
* Loosely based on Monokai textmate theme by http://www.monokai.nl/
|
||||||
* @author Lea Verou
|
* @author ocodia
|
||||||
*/
|
*/
|
||||||
|
|
||||||
code[class*="language-"],
|
code[class*="language-"],
|
||||||
pre[class*="language-"] {
|
pre[class*="language-"] {
|
||||||
color: white;
|
color: #f8f8f2;
|
||||||
text-shadow: 0 -.1em .2em black;
|
background: none;
|
||||||
|
text-shadow: 0 1px rgba(0, 0, 0, 0.3);
|
||||||
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
|
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
|
||||||
direction: ltr;
|
|
||||||
text-align: left;
|
text-align: left;
|
||||||
white-space: pre;
|
white-space: pre;
|
||||||
word-spacing: normal;
|
word-spacing: normal;
|
||||||
word-break: normal;
|
word-break: normal;
|
||||||
|
word-wrap: normal;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
|
|
||||||
-moz-tab-size: 4;
|
-moz-tab-size: 4;
|
||||||
|
@ -27,45 +28,35 @@ pre[class*="language-"] {
|
||||||
hyphens: none;
|
hyphens: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media print {
|
|
||||||
code[class*="language-"],
|
|
||||||
pre[class*="language-"] {
|
|
||||||
text-shadow: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pre[class*="language-"],
|
|
||||||
:not(pre) > code[class*="language-"] {
|
|
||||||
background: hsl(30, 20%, 25%);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Code blocks */
|
/* Code blocks */
|
||||||
pre[class*="language-"] {
|
pre[class*="language-"] {
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
margin: .5em 0;
|
margin: .5em 0;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
border: .3em solid hsl(30, 20%, 40%);
|
border-radius: 0.3em;
|
||||||
border-radius: .5em;
|
}
|
||||||
box-shadow: 1px 1px .5em black inset;
|
|
||||||
|
:not(pre) > code[class*="language-"],
|
||||||
|
pre[class*="language-"] {
|
||||||
|
background: #272822;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Inline code */
|
/* Inline code */
|
||||||
:not(pre) > code[class*="language-"] {
|
:not(pre) > code[class*="language-"] {
|
||||||
padding: .15em .2em .05em;
|
padding: .1em;
|
||||||
border-radius: .3em;
|
border-radius: .3em;
|
||||||
border: .13em solid hsl(30, 20%, 40%);
|
white-space: normal;
|
||||||
box-shadow: 1px 1px .3em -.1em black inset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.token.comment,
|
.token.comment,
|
||||||
.token.prolog,
|
.token.prolog,
|
||||||
.token.doctype,
|
.token.doctype,
|
||||||
.token.cdata {
|
.token.cdata {
|
||||||
color: hsl(30, 20%, 50%);
|
color: slategray;
|
||||||
}
|
}
|
||||||
|
|
||||||
.token.punctuation {
|
.token.punctuation {
|
||||||
opacity: .7;
|
color: #f8f8f2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.namespace {
|
.namespace {
|
||||||
|
@ -74,11 +65,15 @@ pre[class*="language-"] {
|
||||||
|
|
||||||
.token.property,
|
.token.property,
|
||||||
.token.tag,
|
.token.tag,
|
||||||
.token.boolean,
|
|
||||||
.token.number,
|
|
||||||
.token.constant,
|
.token.constant,
|
||||||
.token.symbol {
|
.token.symbol,
|
||||||
color: hsl(350, 40%, 70%);
|
.token.deleted {
|
||||||
|
color: #f92672;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.boolean,
|
||||||
|
.token.number {
|
||||||
|
color: #ae81ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.token.selector,
|
.token.selector,
|
||||||
|
@ -87,7 +82,7 @@ pre[class*="language-"] {
|
||||||
.token.char,
|
.token.char,
|
||||||
.token.builtin,
|
.token.builtin,
|
||||||
.token.inserted {
|
.token.inserted {
|
||||||
color: hsl(75, 70%, 60%);
|
color: #a6e22e;
|
||||||
}
|
}
|
||||||
|
|
||||||
.token.operator,
|
.token.operator,
|
||||||
|
@ -96,18 +91,22 @@ pre[class*="language-"] {
|
||||||
.language-css .token.string,
|
.language-css .token.string,
|
||||||
.style .token.string,
|
.style .token.string,
|
||||||
.token.variable {
|
.token.variable {
|
||||||
color: hsl(40, 90%, 60%);
|
color: #f8f8f2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.token.atrule,
|
.token.atrule,
|
||||||
.token.attr-value,
|
.token.attr-value,
|
||||||
|
.token.function {
|
||||||
|
color: #e6db74;
|
||||||
|
}
|
||||||
|
|
||||||
.token.keyword {
|
.token.keyword {
|
||||||
color: hsl(350, 40%, 70%);
|
color: #66d9ef;
|
||||||
}
|
}
|
||||||
|
|
||||||
.token.regex,
|
.token.regex,
|
||||||
.token.important {
|
.token.important {
|
||||||
color: #e90;
|
color: #fd971f;
|
||||||
}
|
}
|
||||||
|
|
||||||
.token.important,
|
.token.important,
|
||||||
|
@ -122,10 +121,6 @@ pre[class*="language-"] {
|
||||||
cursor: help;
|
cursor: help;
|
||||||
}
|
}
|
||||||
|
|
||||||
.token.deleted {
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre.line-numbers {
|
pre.line-numbers {
|
||||||
position: relative;
|
position: relative;
|
||||||
padding-left: 3.8em;
|
padding-left: 3.8em;
|
||||||
|
@ -166,23 +161,6 @@ pre.line-numbers > code {
|
||||||
padding-right: 0.8em;
|
padding-right: 0.8em;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
.token.tab:not(:empty):before,
|
.token a {
|
||||||
.token.cr:before,
|
color: inherit;
|
||||||
.token.lf:before {
|
|
||||||
color: hsl(24, 20%, 85%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.tab:not(:empty):before {
|
|
||||||
content: '\21E5';
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.cr:before {
|
|
||||||
content: '\240D';
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.crlf:before {
|
|
||||||
content: '\240D\240A';
|
|
||||||
}
|
|
||||||
.token.lf:before {
|
|
||||||
content: '\240A';
|
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
Binary file not shown.
52
public/assets/prism/prism.js
vendored
52
public/assets/prism/prism.js
vendored
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
|
@ -7,10 +7,34 @@ Micropub Config «
|
||||||
@section('content')
|
@section('content')
|
||||||
<p>The values for your micropub endpoint.</p>
|
<p>The values for your micropub endpoint.</p>
|
||||||
<dl>
|
<dl>
|
||||||
<dt>Me (your url)</dt><dd>{{ $data['me'] }}</dd>
|
<dt>Me (your url)</dt><dd><code>{{ $data['me'] }}</code></dd>
|
||||||
<dt>Token</dt><dd>{{ $data['token'] }}</dd>
|
<dt>Token</dt><dd><code>{{ $data['token'] }}</code></dd>
|
||||||
<dt>Syndication Targets</dt><dd>@if(is_array($data['syndication']))<ul>@foreach ($data['syndication'] as $syn)<li>{{ $syn['name'] }} ({{ $syn['target'] }})</li>@endforeach</ul>@else{{ $data['syndication'] }}@endif</dd>
|
<dt>Syndication Targets</dt><dd>
|
||||||
<dt>Media Endpoint</dt><dd>{{ $data['media-endpoint'] }}</dd>
|
@if(is_array($data['syndication']))<ul>@foreach ($data['syndication'] as $syn)
|
||||||
|
<li>{{ $syn['name'] }} ({{ $syn['target'] }})</li>
|
||||||
|
@endforeach</ul>@elseif($data['syndication'] == 'none defined')
|
||||||
|
<code>none defined</code>
|
||||||
|
@else
|
||||||
|
<pre><code class="language-json">{{ prettyPrintJson($data['syndication']) }}</code></pre>
|
||||||
|
@endif</dd>
|
||||||
|
<dt>Media Endpoint</dt><dd><code>{{ $data['media-endpoint'] }}</code></dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
<p>Get a <a href="{{ route('micropub-client-get-new-token') }}">new token</a>.</p>
|
||||||
<p><a href="{{ route('micropub-query-action') }}">Re-query</a> the endpoint.</p>
|
<p><a href="{{ route('micropub-query-action') }}">Re-query</a> the endpoint.</p>
|
||||||
|
<p>Return to <a href="{{ route('micropub-client') }}">client</a>.
|
||||||
|
|
||||||
|
<form action="{{ route('micropub-update-syntax') }}" method="post">
|
||||||
|
{{ csrf_field() }}
|
||||||
|
<fieldset>
|
||||||
|
<legend>Syntax</legend>
|
||||||
|
<p><input type="radio" name="syntax" value="html" id="mf2"@if($data['syntax'] == 'html') checked @endif> <label for="html"><code>x-www-form-urlencoded</code> or <code>multipart/form-data</code></label></p>
|
||||||
|
<p><input type="radio" name="syntax" value="json" id="json"@if($data['syntax'] == 'json') checked @endif> <label for="json"><code>json</code></label></p>
|
||||||
|
<p><button type="submit">Update syntax</button></p>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
@stop
|
||||||
|
|
||||||
|
@section('scripts')
|
||||||
|
<script src="/assets/prism/prism.js"></script>
|
||||||
|
<link rel="stylesheet" href="/assets/prism/prism.css">
|
||||||
@stop
|
@stop
|
||||||
|
|
|
@ -89,36 +89,37 @@ Route::group(['domain' => config('url.longurl')], function () {
|
||||||
Route::get('blog/{year?}/{month?}', 'ArticlesController@index');
|
Route::get('blog/{year?}/{month?}', 'ArticlesController@index');
|
||||||
Route::get('blog/{year}/{month}/{slug}', 'ArticlesController@show');
|
Route::get('blog/{year}/{month}/{slug}', 'ArticlesController@show');
|
||||||
|
|
||||||
//micropub new notes page
|
|
||||||
//this needs to be first so `notes/new` doesn't match `notes/{id}`
|
|
||||||
|
|
||||||
|
|
||||||
//Notes pages using NotesController
|
//Notes pages using NotesController
|
||||||
Route::get('notes', 'NotesController@index');
|
Route::get('notes', 'NotesController@index');
|
||||||
Route::get('notes/{id}', 'NotesController@show');
|
Route::get('notes/{id}', 'NotesController@show');
|
||||||
Route::get('note/{id}', 'NotesController@redirect');
|
Route::get('note/{id}', 'NotesController@redirect');
|
||||||
Route::get('notes/tagged/{tag}', 'NotesController@tagged');
|
Route::get('notes/tagged/{tag}', 'NotesController@tagged');
|
||||||
|
|
||||||
//indieauth
|
// IndieAuth
|
||||||
Route::post('indieauth/start', 'IndieAuthController@start')->name('indieauth-start');
|
Route::post('indieauth/start', 'IndieAuthController@start')->name('indieauth-start');
|
||||||
Route::get('indieauth/callback', 'IndieAuthController@callback')->name('indieauth-callback');
|
Route::get('indieauth/callback', 'IndieAuthController@callback')->name('indieauth-callback');
|
||||||
Route::get('logout', 'IndieAuthController@logout')->name('indieauth-logout');
|
Route::get('logout', 'IndieAuthController@logout')->name('indieauth-logout');
|
||||||
Route::post('api/token', 'IndieAuthController@tokenEndpoint'); //hmmm?
|
|
||||||
|
// Token Endpoint
|
||||||
|
Route::post('api/token', 'TokenEndpointController@create');
|
||||||
|
|
||||||
// Micropub Client
|
// Micropub Client
|
||||||
Route::get('micropub/create', 'MicropubClientController@create')->name('micropub-client');
|
Route::get('micropub/create', 'MicropubClientController@create')->name('micropub-client');
|
||||||
Route::post('micropub', 'MicropubClientController@store')->name('micropub-client-post');
|
Route::post('micropub', 'MicropubClientController@store')->name('micropub-client-post');
|
||||||
Route::get('micropub/config', 'MicropubClientController@config')->name('micropub-config');
|
Route::get('micropub/config', 'MicropubClientController@config')->name('micropub-config');
|
||||||
|
Route::get('micropub/get-new-token', 'MicropubClientController@getNewToken')->name('micropub-client-get-new-token');
|
||||||
|
Route::get('micropub/get-new-token/callback', 'MicropubClientController@getNewTokenCallback')->name('micropub-client-get-new-token-callback');
|
||||||
Route::get('micropub/query-endpoint', 'MicropubClientController@queryEndpoint')->name('micropub-query-action');
|
Route::get('micropub/query-endpoint', 'MicropubClientController@queryEndpoint')->name('micropub-query-action');
|
||||||
|
Route::post('micropub/update-syntax', 'MicropubClientController@updateSyntax')->name('micropub-update-syntax');
|
||||||
Route::get('micropub/places', 'MicropubClientController@nearbyPlaces');
|
Route::get('micropub/places', 'MicropubClientController@nearbyPlaces');
|
||||||
Route::post('micropub/places', 'MicropubClientController@newPlace');
|
Route::post('micropub/places', 'MicropubClientController@newPlace');
|
||||||
Route::post('micropub/media', 'MicropubClientController@processMedia')->name('process-media');
|
Route::post('micropub/media', 'MicropubClientController@processMedia')->name('process-media');
|
||||||
Route::get('micropub/media/clearlinks', 'MicropubClientController@clearLinks');
|
Route::get('micropub/media/clearlinks', 'MicropubClientController@clearLinks');
|
||||||
|
|
||||||
// Micropub Endpoint
|
// Micropub Endpoints
|
||||||
Route::get('api/post', 'MicropubController@get');
|
Route::get('api/post', 'MicropubController@get')->middleware('micropub.token');
|
||||||
Route::post('api/post', 'MicropubController@post');
|
Route::post('api/post', 'MicropubController@post')->middleware('micropub.token');
|
||||||
Route::post('api/media', 'MicropubController@media')->name('media-endpoint');
|
Route::post('api/media', 'MicropubController@media')->middleware('micropub.token')->name('media-endpoint');
|
||||||
|
|
||||||
//webmention
|
//webmention
|
||||||
Route::get('webmention', 'WebMentionsController@get');
|
Route::get('webmention', 'WebMentionsController@get');
|
||||||
|
|
2
storage/framework/testing/.gitignore
vendored
Normal file
2
storage/framework/testing/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
*
|
||||||
|
!.gitignore
|
|
@ -22,13 +22,16 @@ class MicropubClientTest extends DuskTestCase
|
||||||
|
|
||||||
public function test_client_page_creates_new_note()
|
public function test_client_page_creates_new_note()
|
||||||
{
|
{
|
||||||
|
\Artisan::call('token:generate');
|
||||||
$faker = \Faker\Factory::create();
|
$faker = \Faker\Factory::create();
|
||||||
$note = 'Fake note from #LaravelDusk: ' . $faker->text;
|
$note = 'Fake note from #LaravelDusk: ' . $faker->text;
|
||||||
$this->browse(function ($browser) use ($note) {
|
$this->browse(function ($browser) use ($note) {
|
||||||
$browser->visit(route('micropub-client'))
|
$browser->visit(route('micropub-client'))
|
||||||
|
->assertSeeLink('log out')
|
||||||
->type('content', $note)
|
->type('content', $note)
|
||||||
->press('Submit');
|
->press('Submit');
|
||||||
});
|
});
|
||||||
|
sleep(2);
|
||||||
$this->assertDatabaseHas('notes', ['note' => $note]);
|
$this->assertDatabaseHas('notes', ['note' => $note]);
|
||||||
$newNote = \App\Note::where('note', $note)->first();
|
$newNote = \App\Note::where('note', $note)->first();
|
||||||
$newNote->forceDelete();
|
$newNote->forceDelete();
|
||||||
|
|
|
@ -19,11 +19,11 @@ class MicropubControllerTest extends TestCase
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function test_micropub_request_without_token_returns_400_response()
|
public function test_micropub_request_without_token_returns_401_response()
|
||||||
{
|
{
|
||||||
$response = $this->get('/api/post');
|
$response = $this->get('/api/post');
|
||||||
$response->assertStatus(400);
|
$response->assertStatus(401);
|
||||||
$response->assertJsonFragment(['error_description' => 'No token provided with request']);
|
$response->assertJsonFragment(['error_description' => 'No access token was provided in the request']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -202,9 +202,9 @@ class MicropubControllerTest extends TestCase
|
||||||
$response
|
$response
|
||||||
->assertJson([
|
->assertJson([
|
||||||
'response' => 'error',
|
'response' => 'error',
|
||||||
'error' => 'no_token'
|
'error' => 'unauthorized'
|
||||||
])
|
])
|
||||||
->assertStatus(400);
|
->assertStatus(401);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -231,9 +231,9 @@ class MicropubControllerTest extends TestCase
|
||||||
$response
|
$response
|
||||||
->assertJson([
|
->assertJson([
|
||||||
'response' => 'error',
|
'response' => 'error',
|
||||||
'error' => 'invalid_token'
|
'error' => 'insufficient_scope'
|
||||||
])
|
])
|
||||||
->assertStatus(400);
|
->assertStatus(401);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_micropub_request_with_json_syntax_creates_new_place()
|
public function test_micropub_request_with_json_syntax_creates_new_place()
|
||||||
|
@ -276,6 +276,47 @@ class MicropubControllerTest extends TestCase
|
||||||
->assertStatus(201);
|
->assertStatus(201);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_micropub_request_with_json_syntax_update_replace_post()
|
||||||
|
{
|
||||||
|
$response = $this->json(
|
||||||
|
'POST',
|
||||||
|
'/api/post',
|
||||||
|
[
|
||||||
|
'action' => 'update',
|
||||||
|
'url' => config('app.url') . '/notes/A',
|
||||||
|
'replace' => [
|
||||||
|
'content' => ['replaced content'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
['HTTP_Authorization' => 'Bearer ' . $this->getToken()]
|
||||||
|
);
|
||||||
|
$response
|
||||||
|
->assertJson(['response' => 'updated'])
|
||||||
|
->assertStatus(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_micropub_request_with_json_syntax_update_add_post()
|
||||||
|
{
|
||||||
|
$response = $this->json(
|
||||||
|
'POST',
|
||||||
|
'/api/post',
|
||||||
|
[
|
||||||
|
'action' => 'update',
|
||||||
|
'url' => config('app.url') . '/notes/A',
|
||||||
|
'add' => [
|
||||||
|
'syndication' => ['https://www.swarmapp.com/checkin/123'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
['HTTP_Authorization' => 'Bearer ' . $this->getToken()]
|
||||||
|
);
|
||||||
|
$response
|
||||||
|
->assertJson(['response' => 'updated'])
|
||||||
|
->assertStatus(200);
|
||||||
|
$this->assertDatabaseHas('notes', [
|
||||||
|
'swarm_url' => 'https://www.swarmapp.com/checkin/123'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a valid token to be used in the tests.
|
* Generate a valid token to be used in the tests.
|
||||||
*
|
*
|
||||||
|
@ -287,7 +328,7 @@ class MicropubControllerTest extends TestCase
|
||||||
$token = (new Builder())
|
$token = (new Builder())
|
||||||
->set('client_id', 'https://quill.p3k.io')
|
->set('client_id', 'https://quill.p3k.io')
|
||||||
->set('me', 'https://jonnybarnes.localhost')
|
->set('me', 'https://jonnybarnes.localhost')
|
||||||
->set('scope', 'post')
|
->set('scope', 'create update')
|
||||||
->set('issued_at', time())
|
->set('issued_at', time())
|
||||||
->sign($signer, env('APP_KEY'))
|
->sign($signer, env('APP_KEY'))
|
||||||
->getToken();
|
->getToken();
|
||||||
|
|
69
tests/Feature/SwarmTest.php
Normal file
69
tests/Feature/SwarmTest.php
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Feature;
|
||||||
|
|
||||||
|
use Tests\TestCase;
|
||||||
|
use Lcobucci\JWT\Builder;
|
||||||
|
use Lcobucci\JWT\Signer\Hmac\Sha256;
|
||||||
|
use Illuminate\Foundation\Testing\WithoutMiddleware;
|
||||||
|
use Illuminate\Foundation\Testing\DatabaseMigrations;
|
||||||
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||||
|
|
||||||
|
class SwarmTest extends TestCase
|
||||||
|
{
|
||||||
|
use DatabaseTransactions;
|
||||||
|
|
||||||
|
public function test_faked_ownyourswarm_request()
|
||||||
|
{
|
||||||
|
$response = $this->json(
|
||||||
|
'POST',
|
||||||
|
'api/post',
|
||||||
|
[
|
||||||
|
'type' => ['h-entry'],
|
||||||
|
'properties' => [
|
||||||
|
'published' => [\Carbon\Carbon::now()->toDateTimeString()],
|
||||||
|
'syndication' => ['https://www.swarmapp.com/checkin/abc'],
|
||||||
|
'content' => [[
|
||||||
|
'value' => 'My first #checkin using Example Product',
|
||||||
|
'html' => 'My first #checkin using <a href="http://example.org">Example Product</a>',
|
||||||
|
]],
|
||||||
|
'checkin' => [[
|
||||||
|
'type' => ['h-card'],
|
||||||
|
'properties' => [
|
||||||
|
'name' => ['Awesome Venue'],
|
||||||
|
'url' => ['https://foursquare.com/v/123456'],
|
||||||
|
'latitude' => ['1.23'],
|
||||||
|
'longitude' => ['4.56'],
|
||||||
|
],
|
||||||
|
]],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
['HTTP_Authorization' => 'Bearer ' . $this->getToken()]
|
||||||
|
);
|
||||||
|
$response
|
||||||
|
->assertStatus(201)
|
||||||
|
->assertJson(['response' => 'created']);
|
||||||
|
$this->assertDatabaseHas('places', [
|
||||||
|
'foursquare' => 'https://foursquare.com/v/123456'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
}
|
38
tests/Feature/TokenEndpointTest.php
Normal file
38
tests/Feature/TokenEndpointTest.php
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Feature;
|
||||||
|
|
||||||
|
use Mockery;
|
||||||
|
use Tests\TestCase;
|
||||||
|
use IndieAuth\Client;
|
||||||
|
use Illuminate\Foundation\Testing\WithoutMiddleware;
|
||||||
|
use Illuminate\Foundation\Testing\DatabaseMigrations;
|
||||||
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||||
|
|
||||||
|
class TokenEndpointTest extends TestCase
|
||||||
|
{
|
||||||
|
public function test_token_endpoint_issues_token()
|
||||||
|
{
|
||||||
|
$mockClient = Mockery::mock(Client::class);
|
||||||
|
$mockClient->shouldReceive('discoverAuthorizationEndpoint')
|
||||||
|
->with(normalize_url(config('app.url')))
|
||||||
|
->once()
|
||||||
|
->andReturn('https://indieauth.com/auth');
|
||||||
|
$mockClient->shouldReceive('verifyIndieAuthCode')
|
||||||
|
->andReturn([
|
||||||
|
'me' => config('app.url'),
|
||||||
|
'scope' => 'create update',
|
||||||
|
]);
|
||||||
|
$this->app->instance(Client::class, $mockClient);
|
||||||
|
$response = $this->post('/api/token', [
|
||||||
|
'me' => config('app.url'),
|
||||||
|
'code' => 'abc123',
|
||||||
|
'redirect_uri' => route('indieauth-callback'),
|
||||||
|
'client_id' => route('micropub-client'),
|
||||||
|
'state' => mt_rand(1000, 10000),
|
||||||
|
]);
|
||||||
|
parse_str($response->content(), $output);
|
||||||
|
$this->assertEquals(config('app.url'), $output['me']);
|
||||||
|
$this->assertTrue(array_key_exists('access_token', $output));
|
||||||
|
}
|
||||||
|
}
|
69
tests/Unit/HelpersTest.php
Normal file
69
tests/Unit/HelpersTest.php
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Unit;
|
||||||
|
|
||||||
|
use Tests\TestCase;
|
||||||
|
use Illuminate\Foundation\Testing\DatabaseMigrations;
|
||||||
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||||
|
|
||||||
|
class HelpersTest extends TestCase
|
||||||
|
{
|
||||||
|
public function test_normalize_url_is_idempotent()
|
||||||
|
{
|
||||||
|
$input = 'http://example.org:80/index.php?foo=bar&baz=1';
|
||||||
|
$this->assertEquals(normalize_url(normalize_url($input)), normalize_url($input));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider urlProvider
|
||||||
|
*/
|
||||||
|
public function test_normalize_url($input, $output)
|
||||||
|
{
|
||||||
|
$this->assertEquals($output, normalize_url($input));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function urlProvider()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['https://example.org/', 'https://example.org'],
|
||||||
|
['https://example.org:443/', 'https://example.org'],
|
||||||
|
['http://www.foo.bar/index.php/', 'http://www.foo.bar'],
|
||||||
|
['https://example.org/?foo=bar&baz=true', 'https://example.org?baz=true&foo=bar'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_pretty_print_json()
|
||||||
|
{
|
||||||
|
$json = <<<JSON
|
||||||
|
{"glossary": {"title": "example glossary", "GlossDiv": {"title": "S", "GlossList": {"GlossEntry": {"ID": "SGML", "SortAs": "SGML", "GlossTerm": "Standard Generalized Markup Language", "Acronym": "SGML", "Abbrev": "ISO 8879:1986", "GlossDef": {"para": "A meta-markup language, used to create markup languages such as DocBook.", "GlossSeeAlso": ["GML", "XML"]}, "GlossSee": "markup"}}}}}
|
||||||
|
JSON;
|
||||||
|
$expected = <<<EXPECTED
|
||||||
|
{
|
||||||
|
"glossary": {
|
||||||
|
"title": "example glossary",
|
||||||
|
"GlossDiv": {
|
||||||
|
"title": "S",
|
||||||
|
"GlossList": {
|
||||||
|
"GlossEntry": {
|
||||||
|
"ID": "SGML",
|
||||||
|
"SortAs": "SGML",
|
||||||
|
"GlossTerm": "Standard Generalized Markup Language",
|
||||||
|
"Acronym": "SGML",
|
||||||
|
"Abbrev": "ISO 8879:1986",
|
||||||
|
"GlossDef": {
|
||||||
|
"para": "A meta-markup language, used to create markup languages such as DocBook.",
|
||||||
|
"GlossSeeAlso": [
|
||||||
|
"GML",
|
||||||
|
"XML"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"GlossSee": "markup"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPECTED;
|
||||||
|
$this->assertEquals($expected, prettyPrintJson($json));
|
||||||
|
}
|
||||||
|
}
|
38
tinker.config.php
Normal file
38
tinker.config.php
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Automatically alias Laravel Model's to their base classname.
|
||||||
|
* Ex: "App\Models\User" now can just be accessed by "User"
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (! function_exists('aliasModels')) {
|
||||||
|
function aliasModels() {
|
||||||
|
$finder = new \Symfony\Component\Finder\Finder();
|
||||||
|
$finder->files()->name('*.php')->in(base_path().'/app');
|
||||||
|
foreach ($finder as $file) {
|
||||||
|
$namespace = 'App\\';
|
||||||
|
if ($relativePath = $file->getRelativePath()) {
|
||||||
|
$namespace .= strtr($relativePath, '/', '\\') . '\\';
|
||||||
|
}
|
||||||
|
$class = $namespace . $file->getBasename('.php');
|
||||||
|
try {
|
||||||
|
$r = new \ReflectionClass($class);
|
||||||
|
if ($r->isSubclassOf('Illuminate\\Database\\Eloquent\\Model')) {
|
||||||
|
class_alias($class, $file->getBasename('.php'));
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
aliasModels();
|
||||||
|
|
||||||
|
return [
|
||||||
|
'startupMessage' => '<info>Using local config file (tinker.config.php)</info>',
|
||||||
|
|
||||||
|
'commands' => [
|
||||||
|
// new \App\Tinker\TestCommand,
|
||||||
|
],
|
||||||
|
];
|
|
@ -1,4 +1,5 @@
|
||||||
[global]
|
[global]
|
||||||
|
error_log = /tmp/php-fpm.error.log
|
||||||
|
|
||||||
[travis]
|
[travis]
|
||||||
user = {USER}
|
user = {USER}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue