Merge branch 'release/0.0.7'

This commit is contained in:
Jonny Barnes 2016-07-04 16:02:19 +01:00
commit 1283afe0a5
49 changed files with 167 additions and 80 deletions

View file

@ -13,12 +13,10 @@ env:
- setup=basic - setup=basic
php: php:
- 7.0.6 - 7.0
- 7.0.7
- nightly - nightly
matrix: matrix:
allow_failures: allow_failures:
- php: 7.0.7 # A known bug in PHP 7.0.7 stops phpdbg producing code coverage reports
- php: nightly - php: nightly
before_install: before_install:

View file

@ -37,9 +37,7 @@ class MicropubClientController extends Controller
public function newNotePage(Request $request) public function newNotePage(Request $request)
{ {
$url = $request->session()->get('me'); $url = $request->session()->get('me');
$syndication = $this->parseSyndicationTargets( $syndication = $request->session()->get('syndication');
$request->session()->get('syndication')
);
return view('micropubnewnotepage', [ return view('micropubnewnotepage', [
'url' => $url, 'url' => $url,
@ -113,7 +111,7 @@ class MicropubClientController extends Controller
return redirect('notes/new')->withErrors('Bad response when refreshing syndication targets', 'endpoint'); return redirect('notes/new')->withErrors('Bad response when refreshing syndication targets', 'endpoint');
} }
$body = (string) $response->getBody(); $body = (string) $response->getBody();
$syndication = str_replace(['&', '[]'], [';', ''], $body); $syndication = $this->parseSyndicationTargets($body);
$request->session()->put('syndication', $syndication); $request->session()->put('syndication', $syndication);
@ -321,10 +319,9 @@ class MicropubClientController extends Controller
return; return;
} }
$syndicateTo = []; $syndicateTo = [];
$parts = explode(';', $syndicationTargets); $data = json_decode($syndicationTargets, true);
foreach ($parts as $part) { foreach ($syndicateTo['syndicate-to'] as $syn) {
$target = explode('=', $part); $syndicateTo[] = $syn['uid'];
$syndicateTo[] = urldecode($target[1]);
} }
if (count($syndicateTo) > 0) { if (count($syndicateTo) > 0) {
return $syndicateTo; return $syndicateTo;

View file

@ -27,7 +27,7 @@ class MicropubController extends Controller
protected $placeService; protected $placeService;
/** /**
* Injest the dependency. * Inject the dependencies.
*/ */
public function __construct( public function __construct(
TokenService $tokenService = null, TokenService $tokenService = null,
@ -59,31 +59,53 @@ class MicropubController extends Controller
$type = $request->input('h'); $type = $request->input('h');
if ($type == 'entry') { if ($type == 'entry') {
$note = $this->noteService->createNote($request, $clientId); $note = $this->noteService->createNote($request, $clientId);
$content = 'Note created at ' . $note->longurl; $content = <<<EOD
{
"response": "created",
"location": "$note->longurl"
}
EOD;
return (new Response($content, 201)) return (new Response($content, 201))
->header('Location', $note->longurl); ->header('Location', $note->longurl)
->header('Content-Type', 'application/json');
} }
if ($type == 'card') { if ($type == 'card') {
$place = $this->placeService->createPlace($request); $place = $this->placeService->createPlace($request);
$content = 'Place created at ' . $place->longurl; $content = <<<EOD
{
"response": "created",
"location": "$place->longurl"
}
EOD;
return (new Response($content, 201)) return (new Response($content, 201))
->header('Location', $place->longurl); ->header('Location', $place->longurl)
->header('Content-Type', 'application/json');
} }
} }
} }
$content = http_build_query([ $content = <<<EOD
'error' => 'invalid_token', {
'error_description' => 'The token provided is not valid or does not have the necessary scope', "response": "error",
]); "error": "invalid_token",
"error_description": "The token provided is not valid or does not have the necessary scope",
}
EOD;
return (new Response($content, 400)) return (new Response($content, 400))
->header('Content-Type', 'application/x-www-form-urlencoded'); ->header('Content-Type', 'application/json');
} }
$content = 'No OAuth token sent with request.'; $content = <<<EOD
{
"response": "error",
"error": "no_token",
"error_description": "No OAuth token sent with request"
}
EOD;
return new Response($content, 400); return (new Response($content, 400))
->header('Content-Type', 'application/json');
} }
/** /**
@ -104,16 +126,34 @@ class MicropubController extends Controller
$valid = $this->tokenService->validateToken($token); $valid = $this->tokenService->validateToken($token);
if ($valid === null) { if ($valid === null) {
return new Response('Invalid token', 400); $content = <<<EOD
{
"respose": "error",
"error": "invalid_token",
"error_description": "The provided token did not pass validation"
}
EOD;
return (new Response($content, 400))
->header('Content-Type', 'application/json');
} }
//we have a valid token, is `syndicate-to` set? //we have a valid token, is `syndicate-to` set?
if ($request->input('q') === 'syndicate-to') { if ($request->input('q') === 'syndicate-to') {
$content = http_build_query([ return response()->json([
'syndicate-to' => 'twitter.com/jonnybarnes', 'syndicate-to' => [[
'uid' => 'https://twitter.com/jonnybarnes',
'name' => 'jonnybarnes on Twitter',
'service' => [
'name' => 'Twitter',
'url' => 'https://twitter.com',
'photo' => 'https://upload.wikimedia.org/wikipedia/en/9/9f/Twitter_bird_logo_2012.svg',
],
'user' => [
'name' => 'jonnybarnes',
'url' => 'https://twitter.com/jonnybarnes',
'photo' => 'https://pbs.twimg.com/profile_images/1853565405/jmb-bw.jpg',
],
]],
]); ]);
return (new Response($content, 200))
->header('Content-Type', 'application/x-www-form-urlencoded');
} }
//nope, how about a geo URL? //nope, how about a geo URL?
if (substr($request->input('q'), 0, 4) === 'geo:') { if (substr($request->input('q'), 0, 4) === 'geo:') {
@ -123,21 +163,51 @@ class MicropubController extends Controller
$longitude = $latlng[1]; $longitude = $latlng[1];
$places = Place::near($latitude, $longitude, 1000); $places = Place::near($latitude, $longitude, 1000);
return (new Response(json_encode($places), 200)) return response()->json([
->header('Content-Type', 'application/json'); 'response' => 'places',
'places' => $places
]);
}
//nope, ho about a config query?
if ($request->input('q') == 'config') {
return response()->json([
'syndicate-to' => [[
'uid' => 'https://twitter.com/jonnybarnes',
'name' => 'jonnybarnes on Twitter',
'service' => [
'name' => 'Twitter',
'url' => 'https://twitter.com',
'photo' => 'https://upload.wikimedia.org/wikipedia/en/9/9f/Twitter_bird_logo_2012.svg',
],
'user' => [
'name' => 'jonnybarnes',
'url' => 'https://twitter.com/jonnybarnes',
'photo' => 'https://pbs.twimg.com/profile_images/1853565405/jmb-bw.jpg',
],
]],
]);
} }
//nope, just return the token
$content = http_build_query([
'me' => $valid->getClaim('me'),
'scope' => $valid->getClaim('scope'),
'client_id' => $valid->getClaim('client_id'),
]);
return (new Response($content, 200)) //nope, just return the token
->header('Content-Type', 'application/x-www-form-urlencoded'); return response()->json([
'response' => 'token',
'token' => [
'me' => $valid->getClaim('me'),
'scope' => $valid->getClaim('scope'),
'client_id' => $valid->getClaim('client_id'),
],
]);
} }
$content = 'No OAuth token sent with request.'; $content = 'No OAuth token sent with request.';
$content = <<<EOD
{
"response": "error",
"error": "no_token",
"error_description": "No token provided with request"
}
EOD;
return new Response($content, 400); return (new Response($content, 400))
->header('Content-Type', 'application/json');
} }
} }

View file

@ -41,8 +41,7 @@ class NotesController extends Controller
} }
} }
if ($note->place !== null) { if ($note->place !== null) {
preg_match('/\((.*)\)/', $note->place->location, $matches); $lnglat = explode(' ', $note->place->location);
$lnglat = explode(' ', $matches[1]);
$note->latitude = $lnglat[1]; $note->latitude = $lnglat[1];
$note->longitude = $lnglat[0]; $note->longitude = $lnglat[0];
$note->address = $note->place->name; $note->address = $note->place->name;
@ -110,8 +109,7 @@ class NotesController extends Controller
} }
} }
if ($note->place !== null) { if ($note->place !== null) {
preg_match('/\((.*)\)/', $note->place->location, $matches); $lnglat = explode(' ', $note->place->location);
$lnglat = explode(' ', $matches[1]);
$note->latitude = $lnglat[1]; $note->latitude = $lnglat[1];
$note->longitude = $lnglat[0]; $note->longitude = $lnglat[0];
$note->address = $note->place->name; $note->address = $note->place->name;

View file

@ -63,6 +63,9 @@ class SendWebMentions extends Job implements ShouldQueue
if (parse_url($url, PHP_URL_HOST) == env('LONG_URL', 'localhost')) { if (parse_url($url, PHP_URL_HOST) == env('LONG_URL', 'localhost')) {
return false; return false;
} }
if (starts_with($url, '/notes/tagged/')) {
return false;
}
$endpoint = null; $endpoint = null;

View file

@ -32,7 +32,10 @@ class Place extends Model
* *
* @var array * @var array
*/ */
protected $postgisFields = [Point::class, Polygon::class]; protected $postgisFields = [
'location' => Point::class,
'polygon' => Polygon::class,
];
/** /**
* Define the relationship with Notes. * Define the relationship with Notes.
@ -74,18 +77,18 @@ class Place extends Model
return $places; return $places;
} }
/** /*
* Convert location to text. * Convert location to text.
* *
* @param text $value * @param text $value
* @return text * @return text
*/ *
public function getLocationAttribute($value) public function getLocationAttribute($value)
{ {
$result = DB::select(DB::raw("SELECT ST_AsText('$value')")); $result = DB::select(DB::raw("SELECT ST_AsText('$value')"));
return $result[0]->st_astext; return $result[0]->st_astext;
} }*/
/** /**
* Get the latitude from the `location` property. * Get the latitude from the `location` property.
@ -94,9 +97,7 @@ class Place extends Model
*/ */
public function getLatitudeAttribute() public function getLatitudeAttribute()
{ {
preg_match('/\((.*)\)/', $this->location, $latlng); return explode(' ', $this->location)[1];
return explode(' ', $latlng[1])[1];
} }
/** /**
@ -106,9 +107,7 @@ class Place extends Model
*/ */
public function getLongitudeAttribute() public function getLongitudeAttribute()
{ {
preg_match('/\((.*)\)/', $this->location, $latlng); return explode(' ', $this->location)[0];
return explode(' ', $latlng[1])[0];
} }
/** /**

View file

@ -48,11 +48,11 @@ class NoteService
$this->dispatch(new SendWebMentions($note)); $this->dispatch(new SendWebMentions($note));
if (//micropub request, syndication sent as array if (//micropub request, syndication sent as array
(is_array($request->input('mp-syndicate-to')) (is_array($request->input('syndicate-to'))
&& &&
(in_array('twitter.com/jonnybarnes', $request->input('mp-syndicate-to'))) (in_array('https://twitter.com/jonnybarnes', $request->input('syndicate-to')))
|| //micropub request, syndication sent as string || //micropub request, syndication sent as string
($request->input('mp-syndicate-to') == 'twitter.com/jonnybarnes') ($request->input('syndicate-to') == 'https://twitter.com/jonnybarnes')
|| //local admin cp request || //local admin cp request
($request->input('twitter') == true)) ($request->input('twitter') == true))
) { ) {

View file

@ -1,5 +1,20 @@
# Changelog # Changelog
## Version 0.0.7 (2016-07-04)
- Use JSON for syndication endpoint query response
- Use JSON for all micropub requests
- Add support for `q=config` query of the micropub endpoint
## Version 0.0.6.3 (2016-06-29)
- Fix an issue with dispatching the syndication job
## Version 0.0.6.2 (2016-06-28)
- Fix an issue with sending webmentions
## Version 0.0.6 (2016-06-28)
- Better use of `laravel-postgis`
- Change style for inline mini-profile images
## Version 0.0.5 (2016-06-23) ## Version 0.0.5 (2016-06-23)
- Automatically send webmentions - Automatically send webmentions
- Change `mp-syndicate-to` to `syndicate-to` - Change `mp-syndicate-to` to `syndicate-to`

22
composer.lock generated
View file

@ -59,16 +59,16 @@
}, },
{ {
"name": "aws/aws-sdk-php", "name": "aws/aws-sdk-php",
"version": "3.18.19", "version": "3.18.21",
"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": "2ffb032afe91b143293f75b48ec7593659c66ddb" "reference": "db88adc1569789e7d680809f51a62d2bd3410216"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/2ffb032afe91b143293f75b48ec7593659c66ddb", "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/db88adc1569789e7d680809f51a62d2bd3410216",
"reference": "2ffb032afe91b143293f75b48ec7593659c66ddb", "reference": "db88adc1569789e7d680809f51a62d2bd3410216",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -135,7 +135,7 @@
"s3", "s3",
"sdk" "sdk"
], ],
"time": "2016-06-21 21:41:45" "time": "2016-06-27 22:52:29"
}, },
{ {
"name": "barnabywalters/mf-cleaner", "name": "barnabywalters/mf-cleaner",
@ -640,16 +640,16 @@
}, },
{ {
"name": "guzzlehttp/psr7", "name": "guzzlehttp/psr7",
"version": "1.3.0", "version": "1.3.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/guzzle/psr7.git", "url": "https://github.com/guzzle/psr7.git",
"reference": "31382fef2889136415751badebbd1cb022a4ed72" "reference": "5c6447c9df362e8f8093bda8f5d8873fe5c7f65b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/31382fef2889136415751badebbd1cb022a4ed72", "url": "https://api.github.com/repos/guzzle/psr7/zipball/5c6447c9df362e8f8093bda8f5d8873fe5c7f65b",
"reference": "31382fef2889136415751badebbd1cb022a4ed72", "reference": "5c6447c9df362e8f8093bda8f5d8873fe5c7f65b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -665,7 +665,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.0-dev" "dev-master": "1.4-dev"
} }
}, },
"autoload": { "autoload": {
@ -694,7 +694,7 @@
"stream", "stream",
"uri" "uri"
], ],
"time": "2016-04-13 19:56:01" "time": "2016-06-24 23:00:38"
}, },
{ {
"name": "indieauth/client", "name": "indieauth/client",

View file

@ -82,7 +82,7 @@ nav {
white-space: nowrap; } white-space: nowrap; }
.mini-h-card img { .mini-h-card img {
display: inline; height: 1em;
border-radius: 2px; border-radius: 2px;
vertical-align: text-bottom; } vertical-align: text-bottom; }

File diff suppressed because one or more lines are too long

View file

@ -82,7 +82,7 @@ nav {
white-space: nowrap; } white-space: nowrap; }
.mini-h-card img { .mini-h-card img {
display: inline; height: 1em;
border-radius: 2px; border-radius: 2px;
vertical-align: text-bottom; } vertical-align: text-bottom; }

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

View file

@ -6,7 +6,7 @@
"assets/bower/marked.min.js": "assets/bower/marked-c2a88705e2.min.js", "assets/bower/marked.min.js": "assets/bower/marked-c2a88705e2.min.js",
"assets/bower/sanitize.css": "assets/bower/sanitize-85919f917a.css", "assets/bower/sanitize.css": "assets/bower/sanitize-85919f917a.css",
"assets/bower/store2.min.js": "assets/bower/store2-c4daa8f871.min.js", "assets/bower/store2.min.js": "assets/bower/store2-c4daa8f871.min.js",
"assets/css/global.css": "assets/css/global-c8783949cd.css", "assets/css/global.css": "assets/css/global-5eaecdf53d.css",
"assets/css/projects.css": "assets/css/projects-d945298e4f.css", "assets/css/projects.css": "assets/css/projects-d945298e4f.css",
"assets/js/form-save.js": "assets/js/form-save-4d4f6e1cb8.js", "assets/js/form-save.js": "assets/js/form-save-4d4f6e1cb8.js",
"assets/js/links.js": "assets/js/links-c394f9c920.js", "assets/js/links.js": "assets/js/links-c394f9c920.js",

View file

@ -96,7 +96,7 @@ nav {
} }
.mini-h-card img { .mini-h-card img {
display: inline; height: 1em;
border-radius: 2px; border-radius: 2px;
vertical-align: text-bottom; vertical-align: text-bottom;
} }

View file

@ -32,12 +32,13 @@ class MicropubClientTest extends TestCase
public function testClientPageRecentAuth() public function testClientPageRecentAuth()
{ {
$syndication = ['https://twitter.com/jonnybarnes'];
$this->withSession([ $this->withSession([
'me' => $this->appurl, 'me' => $this->appurl,
'syndication' => 'mp-syndicate-to=twitter.com%2Fjbl5', 'syndication' => $syndication,
])->visit($this->appurl . '/notes/new') ])->visit($this->appurl . '/notes/new')
->see($this->appurl) ->see($this->appurl)
->see('twitter.com/jbl5'); ->see('https://twitter.com/jonnybarnes');
} }
/** /**

View file

@ -25,26 +25,26 @@ class MicropubTest extends TestCase
{ {
$this->call('GET', $this->appurl . '/api/post'); $this->call('GET', $this->appurl . '/api/post');
$this->assertResponseStatus(400); $this->assertResponseStatus(400);
$this->see('No OAuth token sent with request.'); $this->seeJson(['error_description' => 'No token provided with request']);
} }
public function testMicropubRequestWithoutValidToken() public function testMicropubRequestWithoutValidToken()
{ {
$this->call('GET', $this->appurl . '/api/post', [], [], [], ['HTTP_Authorization' => 'Bearer abc123']); $this->call('GET', $this->appurl . '/api/post', [], [], [], ['HTTP_Authorization' => 'Bearer abc123']);
$this->assertResponseStatus(400); $this->assertResponseStatus(400);
$this->see('Invalid token'); $this->seeJson(['error_description' => 'The provided token did not pass validation']);
} }
public function testMicropubRequestWithValidToken() public function testMicropubRequestWithValidToken()
{ {
$this->call('GET', $this->appurl . '/api/post', [], [], [], ['HTTP_Authorization' => 'Bearer ' . $this->getToken()]); $this->call('GET', $this->appurl . '/api/post', [], [], [], ['HTTP_Authorization' => 'Bearer ' . $this->getToken()]);
$this->see('me=https%3A%2F%2Fjonnybarnes.localhost'); $this->seeJson(['response' => 'token']);
} }
public function testMicropubRequestForSyndication() public function testMicropubRequestForSyndication()
{ {
$this->call('GET', $this->appurl . '/api/post', ['q' => 'syndicate-to'], [], [], ['HTTP_Authorization' => 'Bearer ' . $this->getToken()]); $this->call('GET', $this->appurl . '/api/post', ['q' => 'syndicate-to'], [], [], ['HTTP_Authorization' => 'Bearer ' . $this->getToken()]);
$this->see('twitter.com%2Fjonnybarnes'); $this->seeJson(['uid' => 'https://twitter.com/jonnybarnes']);
} }
public function testMicropubRequestForNearbyPlacesThatExist() public function testMicropubRequestForNearbyPlacesThatExist()
@ -59,6 +59,12 @@ class MicropubTest extends TestCase
$this->see('[]'); $this->see('[]');
} }
public function testMicropubRequestForConfig()
{
$this->call('GET', $this->appurl . '/api/post', ['q' => 'config'], [], [], ['HTTP_Authorization' => 'Bearer ' . $this->getToken()]);
$this->seeJson(['uid' => 'https://twitter.com/jonnybarnes']);
}
public function testMicropubRequestCreateNewNote() public function testMicropubRequestCreateNewNote()
{ {
$faker = \Faker\Factory::create(); $faker = \Faker\Factory::create();