jonnybarnes.uk/app/Http/Controllers/MicropubClientController.php

349 lines
11 KiB
PHP
Raw Normal View History

2016-05-19 15:01:28 +01:00
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use App\Services\IndieAuthService;
use IndieAuth\Client as IndieClient;
use GuzzleHttp\Client as GuzzleClient;
class MicropubClientController extends Controller
{
/**
* The IndieAuth service container.
*/
protected $indieAuthService;
/**
* Inject the dependencies.
*/
public function __construct(
IndieAuthService $indieAuthService = null,
IndieClient $indieClient = null,
GuzzleClient $guzzleClient = null
) {
$this->indieAuthService = $indieAuthService ?? new IndieAuthService();
$this->guzzleClient = $guzzleClient ?? new GuzzleClient();
$this->indieClient = $indieClient ?? new IndieClient();
}
/**
* Display the new notes form.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\View\Factory view
*/
public function newNotePage(Request $request)
{
$url = $request->session()->get('me');
$syndication = $request->session()->get('syndication');
2016-05-19 15:01:28 +01:00
return view('micropubnewnotepage', [
'url' => $url,
'syndication' => $syndication,
]);
}
/**
* Post the notes content to the relavent micropub API endpoint.
*
* @todo make sure this works with multiple syndication targets
*
* @param \Illuminate\Http\Request $request
* @return mixed
*/
public function postNewNote(Request $request)
{
$domain = $request->session()->get('me');
$token = $request->session()->get('token');
$micropubEndpoint = $this->indieAuthService->discoverMicropubEndpoint(
$domain,
$this->indieClient
);
if (! $micropubEndpoint) {
return redirect('notes/new')->withErrors('Unable to determine micropub API endpoint', 'endpoint');
}
$response = $this->postNoteRequest($request, $micropubEndpoint, $token);
if ($response->getStatusCode() == 201) {
$location = $response->getHeader('Location');
if (is_array($location)) {
return redirect($location[0]);
}
return redirect($location);
}
return redirect('notes/new')->withErrors('Endpoint didnt create the note.', 'endpoint');
}
/**
* We make a request to the micropub endpoint requesting syndication targets
* and store them in the session.
*
* @todo better handling of response regarding mp-syndicate-to
* and syndicate-to
*
* @param \Illuminate\Http\Request $request
* @param \IndieAuth\Client $indieClient
* @param \GuzzleHttp\Client $guzzleClient
* @return \Illuminate\Routing\Redirector redirect
*/
public function refreshSyndicationTargets(Request $request)
{
$domain = $request->session()->get('me');
$token = $request->session()->get('token');
$micropubEndpoint = $this->indieAuthService->discoverMicropubEndpoint($domain, $this->indieClient);
if (! $micropubEndpoint) {
return redirect('notes/new')->withErrors('Unable to determine micropub API endpoint', 'endpoint');
}
try {
$response = $this->guzzleClient->get($micropubEndpoint, [
'headers' => ['Authorization' => 'Bearer ' . $token],
'query' => ['q' => 'syndicate-to'],
]);
} catch (\GuzzleHttp\Exception\BadResponseException $e) {
return redirect('notes/new')->withErrors('Bad response when refreshing syndication targets', 'endpoint');
}
$body = (string) $response->getBody();
$syndication = $this->parseSyndicationTargets($body);
2016-05-19 15:01:28 +01:00
$request->session()->put('syndication', $syndication);
return redirect('notes/new');
}
/**
* 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 = [
[
'name' => 'h',
'contents' => 'entry',
],
[
'name' => 'content',
'contents' => $request->input('content'),
],
];
if ($request->hasFile('photo')) {
$photos = $request->file('photo');
foreach ($photos as $photo) {
$multipart[] = [
'name' => 'photo[]',
'contents' => fopen($photo->path(), 'r'),
'filename' => $photo->getClientOriginalName(),
2016-05-19 15:01:28 +01:00
];
}
}
if ($request->input('in-reply-to') != '') {
$multipart[] = [
'name' => 'in-reply-to',
'contents' => $request->input('reply-to'),
];
}
if ($request->input('syndicate-to')) {
foreach ($request->input('syndicate-to') as $syn) {
2016-05-19 15:01:28 +01:00
$multipart[] = [
'name' => 'syndicate-to',
2016-05-19 15:01:28 +01:00
'contents' => $syn,
];
}
}
if ($request->input('location')) {
if ($request->input('location') !== 'no-location') {
2016-05-19 15:01:28 +01:00
$multipart[] = [
'name' => 'location',
2016-10-05 16:13:00 +01:00
'contents' => $request->input('location'),
2016-05-19 15:01:28 +01:00
];
}
}
$headers = [
'Authorization' => 'Bearer ' . $token,
];
try {
$response = $this->guzzleClient->post($micropubEndpoint, [
'multipart' => $multipart,
'headers' => $headers,
]);
} catch (\GuzzleHttp\Exception\BadResponseException $e) {
return redirect('notes/new')
->withErrors('There was a bad response from the micropub endpoint.', 'endpoint');
}
return $response;
}
/**
* Create a new place.
*
* @param \Illuminate\Http\Request $request
* @return mixed
*/
public function postNewPlace(Request $request)
{
if ($request->session()->has('token') === false) {
return response()->json([
'error' => true,
'error_description' => 'No known token',
], 400);
}
2016-05-19 15:01:28 +01:00
$domain = $request->session()->get('me');
$token = $request->session()->get('token');
$micropubEndpoint = $this->indieAuthService->discoverMicropubEndpoint($domain, $this->indieClient);
if (! $micropubEndpoint) {
return response()->json([
2016-05-19 15:01:28 +01:00
'error' => true,
'error_description' => 'Could not determine the micropub endpoint.',
], 400);
2016-05-19 15:01:28 +01:00
}
$place = $this->postPlaceRequest($request, $micropubEndpoint, $token);
if ($place === false) {
return response()->json([
2016-05-19 15:01:28 +01:00
'error' => true,
'error_description' => 'Unable to create the new place',
], 400);
2016-05-19 15:01:28 +01:00
}
return response()->json([
2016-10-07 12:17:12 +01:00
'uri' => $place,
2016-05-19 15:01:28 +01:00
'name' => $request->input('place-name'),
'latitude' => $request->input('place-latitude'),
'longitude' => $request->input('place-longitude'),
]);
2016-05-19 15:01:28 +01:00
}
/**
* 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;
2016-05-19 15:01:28 +01:00
}
if ($response->getStatusCode() == 201) {
return $response->getHeader('Location')[0];
}
return false;
}
/**
* Make a request to the micropub endpoint requesting any nearby places.
*
* @param \Illuminate\Http\Request $request
* @param string $latitude
* @param string $longitude
* @return \Illuminate\Http\Response
*/
public function nearbyPlaces(
Request $request,
$latitude,
$longitude
) {
if ($request->session()->has('token') === false) {
return response()->json([
'error' => true,
'error_description' => 'No known token',
], 400);
}
2016-05-19 15:01:28 +01:00
$domain = $request->session()->get('me');
$token = $request->session()->get('token');
2016-05-19 15:01:28 +01:00
$micropubEndpoint = $this->indieAuthService->discoverMicropubEndpoint($domain, $this->indieClient);
if (! $micropubEndpoint) {
return response()->json([
'error' => true,
'error_description' => 'No known endpoint',
], 400);
2016-05-19 15:01:28 +01:00
}
try {
Squashed commit of the following: commit e7f1c4c84579b959fe2997ff4d2315ee53acfe9a Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Thu Sep 29 11:22:44 2016 +0100 Add latest change, fix spelling errors in rest of changelog commit 637b5107b557f1c2a56327a40b3d7b4b7297fa29 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Wed Sep 28 21:13:06 2016 +0100 Add a test for uncertainty parameter commit 5e7504b323debf9c91e0cca428b4dca7dda0789d Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Wed Sep 28 21:11:12 2016 +0100 Format the ternaty operator correctly commit 19c978a5ac59cd7dfdceee9a8f1aaa6539d8ac66 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Wed Sep 28 20:46:19 2016 +0100 Fix typo commit d4e5b5fc384d0ccd715ea28a51821f958f6c2caa Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Wed Sep 28 20:41:23 2016 +0100 Add paraphanalia commit a96f104894de6c06dc5e41044482de2355cb4965 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Wed Sep 28 20:35:17 2016 +0100 Add the geolocation uncertainty to nearby places request commit 0f6d5649e2f3316040d7453f5fcc96ac1f0ac783 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Wed Sep 28 20:34:38 2016 +0100 Use a query parameter for geolocation uncertainty commit a9147a074315fabb0d76e5991b34a70b2143761c Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Wed Sep 28 19:58:08 2016 +0100 Make use of uncertainty parameter when finding nearby places commit bad384b5d8be3ea8905d8f6ca3c20f448869853d Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Wed Sep 28 19:28:42 2016 +0100 Support sending uncertainty value to micropub endpoint
2016-09-29 11:28:31 +01:00
$query = 'geo:' . $latitude . ',' . $longitude;
2016-10-03 14:46:53 +01:00
if ($request->input('u') !== null) {
$query .= ';u=' . $request->input('u');
Squashed commit of the following: commit e7f1c4c84579b959fe2997ff4d2315ee53acfe9a Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Thu Sep 29 11:22:44 2016 +0100 Add latest change, fix spelling errors in rest of changelog commit 637b5107b557f1c2a56327a40b3d7b4b7297fa29 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Wed Sep 28 21:13:06 2016 +0100 Add a test for uncertainty parameter commit 5e7504b323debf9c91e0cca428b4dca7dda0789d Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Wed Sep 28 21:11:12 2016 +0100 Format the ternaty operator correctly commit 19c978a5ac59cd7dfdceee9a8f1aaa6539d8ac66 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Wed Sep 28 20:46:19 2016 +0100 Fix typo commit d4e5b5fc384d0ccd715ea28a51821f958f6c2caa Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Wed Sep 28 20:41:23 2016 +0100 Add paraphanalia commit a96f104894de6c06dc5e41044482de2355cb4965 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Wed Sep 28 20:35:17 2016 +0100 Add the geolocation uncertainty to nearby places request commit 0f6d5649e2f3316040d7453f5fcc96ac1f0ac783 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Wed Sep 28 20:34:38 2016 +0100 Use a query parameter for geolocation uncertainty commit a9147a074315fabb0d76e5991b34a70b2143761c Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Wed Sep 28 19:58:08 2016 +0100 Make use of uncertainty parameter when finding nearby places commit bad384b5d8be3ea8905d8f6ca3c20f448869853d Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Wed Sep 28 19:28:42 2016 +0100 Support sending uncertainty value to micropub endpoint
2016-09-29 11:28:31 +01:00
}
2016-05-19 15:01:28 +01:00
$response = $this->guzzleClient->get($micropubEndpoint, [
'headers' => ['Authorization' => 'Bearer ' . $token],
Squashed commit of the following: commit e7f1c4c84579b959fe2997ff4d2315ee53acfe9a Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Thu Sep 29 11:22:44 2016 +0100 Add latest change, fix spelling errors in rest of changelog commit 637b5107b557f1c2a56327a40b3d7b4b7297fa29 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Wed Sep 28 21:13:06 2016 +0100 Add a test for uncertainty parameter commit 5e7504b323debf9c91e0cca428b4dca7dda0789d Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Wed Sep 28 21:11:12 2016 +0100 Format the ternaty operator correctly commit 19c978a5ac59cd7dfdceee9a8f1aaa6539d8ac66 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Wed Sep 28 20:46:19 2016 +0100 Fix typo commit d4e5b5fc384d0ccd715ea28a51821f958f6c2caa Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Wed Sep 28 20:41:23 2016 +0100 Add paraphanalia commit a96f104894de6c06dc5e41044482de2355cb4965 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Wed Sep 28 20:35:17 2016 +0100 Add the geolocation uncertainty to nearby places request commit 0f6d5649e2f3316040d7453f5fcc96ac1f0ac783 Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Wed Sep 28 20:34:38 2016 +0100 Use a query parameter for geolocation uncertainty commit a9147a074315fabb0d76e5991b34a70b2143761c Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Wed Sep 28 19:58:08 2016 +0100 Make use of uncertainty parameter when finding nearby places commit bad384b5d8be3ea8905d8f6ca3c20f448869853d Author: Jonny Barnes <jonny@jonnybarnes.uk> Date: Wed Sep 28 19:28:42 2016 +0100 Support sending uncertainty value to micropub endpoint
2016-09-29 11:28:31 +01:00
'query' => ['q' => $query],
2016-05-19 15:01:28 +01:00
]);
} catch (\GuzzleHttp\Exception\BadResponseException $e) {
return response()->json([
'error' => true,
'error_description' => 'The endpoint returned a non-good response',
], 400);
2016-05-19 15:01:28 +01:00
}
return (new Response($response->getBody(), 200))
->header('Content-Type', 'application/json');
}
/**
* Parse the syndication targets retreived from a cookie, to a form that can
* be used in a view.
*
* @param string $syndicationTargets
* @return array|null
*/
private function parseSyndicationTargets($syndicationTargets = null)
{
if ($syndicationTargets === null) {
return;
}
$syndicateTo = [];
$data = json_decode($syndicationTargets, true);
if (array_key_exists('syndicate-to', $data)) {
foreach ($data['syndicate-to'] as $syn) {
2016-07-13 17:32:10 +01:00
$syndicateTo[] = [
'target' => $syn['uid'],
'name' => $syn['name'],
];
}
2016-05-19 15:01:28 +01:00
}
if (count($syndicateTo) > 0) {
return $syndicateTo;
2016-05-19 15:01:28 +01:00
}
}
}