Merge branch 'feature/better-places' into develop

This commit is contained in:
Jonny Barnes 2016-09-23 16:56:29 +01:00
commit 5ffcee06c0
7 changed files with 208 additions and 87 deletions

View file

@ -204,34 +204,37 @@ class MicropubClientController extends Controller
*/ */
public function postNewPlace(Request $request) public function postNewPlace(Request $request)
{ {
if ($request->session()->has('token') === false) {
return response()->json([
'error' => true,
'error_description' => 'No known token',
], 400);
}
$domain = $request->session()->get('me'); $domain = $request->session()->get('me');
$token = $request->session()->get('token'); $token = $request->session()->get('token');
$micropubEndpoint = $this->indieAuthService->discoverMicropubEndpoint($domain, $this->indieClient); $micropubEndpoint = $this->indieAuthService->discoverMicropubEndpoint($domain, $this->indieClient);
if (! $micropubEndpoint) { if (! $micropubEndpoint) {
return (new Response(json_encode([ return response()->json([
'error' => true, 'error' => true,
'message' => 'Could not determine the micropub endpoint.', 'error_description' => 'Could not determine the micropub endpoint.',
]), 400)) ], 400);
->header('Content-Type', 'application/json');
} }
$place = $this->postPlaceRequest($request, $micropubEndpoint, $token); $place = $this->postPlaceRequest($request, $micropubEndpoint, $token);
if ($place === false) { if ($place === false) {
return (new Response(json_encode([ return response()->json([
'error' => true, 'error' => true,
'message' => 'Unable to create the new place', 'error_description' => 'Unable to create the new place',
]), 400)) ], 400);
->header('Content-Type', 'application/json');
} }
return (new Response(json_encode([ return response()->json([
'url' => $place, 'url' => $place,
'name' => $request->input('place-name'), 'name' => $request->input('place-name'),
'latitude' => $request->input('place-latitude'), 'latitude' => $request->input('place-latitude'),
'longitude' => $request->input('place-longitude'), 'longitude' => $request->input('place-longitude'),
]), 200)) ]);
->header('Content-Type', 'application/json');
} }
/** /**
@ -263,7 +266,7 @@ class MicropubClientController extends Controller
'headers' => $headers, 'headers' => $headers,
]); ]);
} catch (ClientException $e) { } catch (ClientException $e) {
//not sure yet... return false;
} }
if ($response->getStatusCode() == 201) { if ($response->getStatusCode() == 201) {
return $response->getHeader('Location')[0]; return $response->getHeader('Location')[0];
@ -285,12 +288,22 @@ class MicropubClientController extends Controller
$latitude, $latitude,
$longitude $longitude
) { ) {
if ($request->session()->has('token') === false) {
return response()->json([
'error' => true,
'error_description' => 'No known token',
], 400);
}
$domain = $request->session()->get('me'); $domain = $request->session()->get('me');
$token = $request->session()->get('token'); $token = $request->session()->get('token');
$micropubEndpoint = $this->indieAuthService->discoverMicropubEndpoint($domain, $this->indieClient); $micropubEndpoint = $this->indieAuthService->discoverMicropubEndpoint($domain, $this->indieClient);
if (! $micropubEndpoint) { if (! $micropubEndpoint) {
return; return response()->json([
'error' => true,
'error_description' => 'No known endpoint',
], 400);
} }
try { try {
@ -299,7 +312,10 @@ class MicropubClientController extends Controller
'query' => ['q' => 'geo:' . $latitude . ',' . $longitude], 'query' => ['q' => 'geo:' . $latitude . ',' . $longitude],
]); ]);
} catch (\GuzzleHttp\Exception\BadResponseException $e) { } catch (\GuzzleHttp\Exception\BadResponseException $e) {
return; return response()->json([
'error' => true,
'error_description' => 'The endpoint returned a non-good response',
], 400);
} }
return (new Response($response->getBody(), 200)) return (new Response($response->getBody(), 200))

View file

@ -57,54 +57,43 @@ class MicropubController extends Controller
if (array_search('post', $scopes) !== false) { if (array_search('post', $scopes) !== false) {
$clientId = $tokenData->getClaim('client_id'); $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')) {
$note = $this->noteService->createNote($request, $clientId); try {
$content = <<<EOD $note = $this->noteService->createNote($request, $clientId);
{ } catch (Exception $exception) {
"response": "created", return response()->json(['error' => true], 400);
"location": "$note->longurl" }
} return response()->json([
EOD; 'response' => 'created',
'location' => $note->longurl
return (new Response($content, 201)) ], 201)->header('Location', $note->longurl);
->header('Location', $note->longurl)
->header('Content-Type', 'application/json');
} }
if ($request->input('h') == 'card' || $request->input('type')[0] == 'h-card') { if ($request->input('h') == 'card' || $request->input('type')[0] == 'h-card') {
$place = $this->placeService->createPlace($request); try {
$content = <<<EOD $place = $this->placeService->createPlace($request);
{ } catch (Exception $exception) {
"response": "created", return response()->json(['error' => true], 400);
"location": "$place->longurl" }
}
EOD;
return (new Response($content, 201)) return response()->json([
->header('Location', $place->longurl) 'response' => 'created',
->header('Content-Type', 'application/json'); 'location' => $place->longurl
], 201)->header('Location', $place->longurl);
} }
} }
} }
$content = <<<'EOD'
{
"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 response()->json([
->header('Content-Type', 'application/json'); 'response' => 'error',
'error' => 'invalid_token',
'error_description' => 'The token provided is not valid or does not have the necessary scope'
], 400);
} }
$content = <<<'EOD'
{
"response": "error",
"error": "no_token",
"error_description": "No OAuth token sent with request"
}
EOD;
return (new Response($content, 400)) return response()->json([
->header('Content-Type', 'application/json'); 'response' => 'error',
'error' => 'no_token',
'error_description' => 'No OAuth token sent with request'
], 400);
} }
/** /**

View file

@ -4,9 +4,7 @@ namespace App;
use DB; use DB;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Phaza\LaravelPostgis\Geometries\Point;
use MartinBean\Database\Eloquent\Sluggable; use MartinBean\Database\Eloquent\Sluggable;
use Phaza\LaravelPostgis\Geometries\Polygon;
use Phaza\LaravelPostgis\Eloquent\PostgisTrait; use Phaza\LaravelPostgis\Eloquent\PostgisTrait;
class Place extends Model class Place extends Model
@ -33,8 +31,8 @@ class Place extends Model
* @var array * @var array
*/ */
protected $postgisFields = [ protected $postgisFields = [
'location' => Point::class, 'location',
'polygon' => Polygon::class, 'polygon',
]; ];
/** /**

View file

@ -16,21 +16,26 @@ class PlaceService
*/ */
public function createPlace(Request $request) public function createPlace(Request $request)
{ {
//well either have latitude and longitude sent together in a if ($request->header('Content-Type') == 'application/json') {
//geo-url (micropub), or seperatley (/admin) $name = $request->input('properties.name');
if ($request->input('geo') !== null) { $description = $request->input('properties.description') ?? null;
$parts = explode(':', $request->input('geo')); $geo = $request->input('properties.geo');
$latlng = explode(',', $parts[1]); } else {
$latitude = $latlng[0]; $name = $request->input('name');
$longitude = $latlng[1]; $description = $request->input('description');
$geo = $request->input('geo');
} }
$parts = explode(':', $geo);
$latlng = explode(',', $parts[1]);
$latitude = $latlng[0];
$longitude = $latlng[1];
if ($request->input('latitude') !== null) { if ($request->input('latitude') !== null) {
$latitude = $request->input('latitude'); $latitude = $request->input('latitude');
$longitude = $request->input('longitude'); $longitude = $request->input('longitude');
} }
$place = new Place(); $place = new Place();
$place->name = $request->input('name'); $place->name = $name;
$place->description = $request->input('description'); $place->description = $description;
$place->location = new Point((float) $latitude, (float) $longitude); $place->location = new Point((float) $latitude, (float) $longitude);
$place->save(); $place->save();

View file

@ -12,11 +12,11 @@ if ('geolocation' in navigator) {
function getLocation() { function getLocation() {
navigator.geolocation.getCurrentPosition(function (position) { navigator.geolocation.getCurrentPosition(function (position) {
//the locate button has been clicked so add the places/map //the locate button has been clicked so add the places/map
addPlaces(position.coords.latitude, position.coords.longitude); addPlacesMap(position.coords.latitude, position.coords.longitude);
}); });
} }
function addPlaces(latitude, longitude) { function addPlacesMap(latitude, longitude) {
//get the nearby places //get the nearby places
fetch('/places/near/' + latitude + '/' + longitude, { fetch('/places/near/' + latitude + '/' + longitude, {
credentials: 'same-origin', credentials: 'same-origin',
@ -24,6 +24,10 @@ function addPlaces(latitude, longitude) {
}).then(function (response) { }).then(function (response) {
return response.json(); return response.json();
}).then(function (j) { }).then(function (j) {
if (j.error == true) {
alertify.reset();
alertify.error(j.error_description);
}
if (j.length > 0) { if (j.length > 0) {
var i; var i;
var places = []; var places = [];
@ -195,17 +199,13 @@ function addMap(latitude, longitude, places) {
method: 'post', method: 'post',
body: formData body: formData
}) })
.then(function (response) {
if (response.status >= 200 && response.status < 300) {
return Promise.resolve(response);
} else {
return Promise.reject(new Error(response.statusText));
}
})
.then(function (response) { .then(function (response) {
return response.json(); return response.json();
}) })
.then(function (placeJson) { .then(function (placeJson) {
if (placeJson.error == true) {
throw new Error(placeJson.error_description);
}
//create the slug from the url //create the slug from the url
var urlParts = placeJson.split('/'); var urlParts = placeJson.split('/');
var slug = urlParts.pop(); var slug = urlParts.pop();
@ -247,7 +247,8 @@ function addMap(latitude, longitude, places) {
//make selected //make selected
selectPlace(slug); selectPlace(slug);
}).catch(function (placeError) { }).catch(function (placeError) {
console.error(placeError); alertify.reset();
alertify.error(placeError);
}); });
}); });
}); });

View file

@ -1,4 +1,4 @@
/* global L */ /* global L, alertify */
if ('geolocation' in navigator) { if ('geolocation' in navigator) {
var button = document.querySelector('#locate'); var button = document.querySelector('#locate');
if (button.addEventListener) { if (button.addEventListener) {
@ -12,11 +12,11 @@ if ('geolocation' in navigator) {
function getLocation() { function getLocation() {
navigator.geolocation.getCurrentPosition(function (position) { navigator.geolocation.getCurrentPosition(function (position) {
//the locate button has been clicked so add the places/map //the locate button has been clicked so add the places/map
addPlaces(position.coords.latitude, position.coords.longitude); addPlacesMap(position.coords.latitude, position.coords.longitude);
}); });
} }
function addPlaces(latitude, longitude) { function addPlacesMap(latitude, longitude) {
//get the nearby places //get the nearby places
fetch('/places/near/' + latitude + '/' + longitude, { fetch('/places/near/' + latitude + '/' + longitude, {
credentials: 'same-origin', credentials: 'same-origin',
@ -24,6 +24,10 @@ function addPlaces(latitude, longitude) {
}).then(function (response) { }).then(function (response) {
return response.json(); return response.json();
}).then(function (j) { }).then(function (j) {
if (j.error == true) {
alertify.reset();
alertify.error(j.error_description);
}
if (j.length > 0) { if (j.length > 0) {
var i; var i;
var places = []; var places = [];
@ -195,17 +199,13 @@ function addMap(latitude, longitude, places) {
method: 'post', method: 'post',
body: formData body: formData
}) })
.then(function (response) {
if (response.status >= 200 && response.status < 300) {
return Promise.resolve(response);
} else {
return Promise.reject(new Error(response.statusText));
}
})
.then(function (response) { .then(function (response) {
return response.json(); return response.json();
}) })
.then(function (placeJson) { .then(function (placeJson) {
if (placeJson.error == true) {
throw new Error(placeJson.error_description);
}
//create the slug from the url //create the slug from the url
var urlParts = placeJson.split('/'); var urlParts = placeJson.split('/');
var slug = urlParts.pop(); var slug = urlParts.pop();
@ -247,7 +247,8 @@ function addMap(latitude, longitude, places) {
//make selected //make selected
selectPlace(slug); selectPlace(slug);
}).catch(function (placeError) { }).catch(function (placeError) {
console.error(placeError); alertify.reset();
alertify.error(placeError);
}); });
}); });
}); });

View file

@ -116,6 +116,103 @@ class MicropubTest extends TestCase
['HTTP_Authorization' => 'Bearer ' . $this->getToken()] ['HTTP_Authorization' => 'Bearer ' . $this->getToken()]
)->seeJson([ )->seeJson([
'response' => 'created' 'response' => 'created'
])->assertResponseStatus(201);
}
public function testMicropubJSONRequestCreateNewNoteWithoutToken()
{
$faker = \Faker\Factory::create();
$note = $faker->text;
$this->json(
'POST',
$this->appurl . '/api/post',
[
'type' => ['h-entry'],
'properties' => [
'content' => [$note],
],
]
)->seeJson([
'response' => 'error',
'error' => 'no_token'
])->assertResponseStatus(400);
}
public function testMicropubJSONRequestCreateNewNoteWithInvalidToken()
{
$faker = \Faker\Factory::create();
$note = $faker->text;
$this->json(
'POST',
$this->appurl . '/api/post',
[
'type' => ['h-entry'],
'properties' => [
'content' => [$note],
],
],
['HTTP_Authorization' => 'Bearer ' . $this->getInvalidToken()]
)->seeJson([
'response' => 'error',
'error' => 'invalid_token'
]);
}
public function testMicropubJSONRequestCreateNewPlace()
{
$faker = \Faker\Factory::create();
$this->json(
'POST',
$this->appurl . '/api/post',
[
'type' => ['h-card'],
'properties' => [
'name' => $faker->name,
'geo' => 'geo:' . $faker->latitude . ',' . $faker->longitude
],
],
['HTTP_Authorization' => 'Bearer ' . $this->getToken()]
)->seeJson([
'response' => 'created'
])->assertResponseStatus(201);
}
public function testMicropubJSONRequestCreateNewPlaceWithoutToken()
{
$faker = \Faker\Factory::create();
$this->json(
'POST',
$this->appurl . '/api/post',
[
'type' => ['h-entry'],
'properties' => [
'name' => $faker->name,
'geo' => 'geo:' . $faker->latitude . ',' . $faker->longitude
],
]
)->seeJson([
'response' => 'error',
'error' => 'no_token'
])->assertResponseStatus(400);
}
public function testMicropubJSONRequestCreateNewPlaceWithInvalidToken()
{
$faker = \Faker\Factory::create();
$this->json(
'POST',
$this->appurl . '/api/post',
[
'type' => ['h-entry'],
'properties' => [
'name' => $faker->name,
'geo' => 'geo:' . $faker->latitude . ',' . $faker->longitude
],
],
['HTTP_Authorization' => 'Bearer ' . $this->getInvalidToken()]
)->seeJson([
'response' => 'error',
'error' => 'invalid_token'
]); ]);
} }
@ -132,4 +229,18 @@ class MicropubTest extends TestCase
return $token; return $token;
} }
private function getInvalidToken()
{
$signer = new Sha256();
$token = (new Builder())
->set('client_id', 'https://quill.p3k.io')
->set('me', 'https://jonnybarnes.localhost')
->set('scope', 'view')
->set('issued_at', time())
->sign($signer, env('APP_KEY'))
->getToken();
return $token;
}
} }