Merge branch 'feature/better-places' into develop
This commit is contained in:
commit
5ffcee06c0
7 changed files with 208 additions and 87 deletions
|
@ -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))
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -16,21 +16,26 @@ class PlaceService
|
||||||
*/
|
*/
|
||||||
public function createPlace(Request $request)
|
public function createPlace(Request $request)
|
||||||
{
|
{
|
||||||
//we’ll 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();
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue