diff --git a/app/Http/Controllers/Admin/SyndicationTargetsController.php b/app/Http/Controllers/Admin/SyndicationTargetsController.php
new file mode 100644
index 00000000..f8c93260
--- /dev/null
+++ b/app/Http/Controllers/Admin/SyndicationTargetsController.php
@@ -0,0 +1,99 @@
+validate([
+ 'uid' => 'required|string',
+ 'name' => 'required|string',
+ ]);
+
+ SyndicationTarget::create($validated);
+
+ return redirect('/admin/syndication');
+ }
+
+ /**
+ * Show a form to edit a syndication target.
+ *
+ * @param SyndicationTarget $syndicationTarget
+ * @return View
+ */
+ public function edit(SyndicationTarget $syndicationTarget): View
+ {
+ return view('admin.syndication.edit', [
+ 'syndication_target' => $syndicationTarget,
+ ]);
+ }
+
+ /**
+ * Process the request to edit a client name.
+ *
+ * @param Request $request
+ * @param SyndicationTarget $syndicationTarget
+ * @return RedirectResponse
+ */
+ public function update(Request $request, SyndicationTarget $syndicationTarget): RedirectResponse
+ {
+ $validated = $request->validate([
+ 'uid' => 'required|string',
+ 'name' => 'required|string',
+ ]);
+
+ $syndicationTarget->update($validated);
+
+ return redirect('/admin/syndication');
+ }
+
+ /**
+ * Process a request to delete a client.
+ *
+ * @param SyndicationTarget $syndicationTarget
+ * @return RedirectResponse
+ */
+ public function destroy(SyndicationTarget $syndicationTarget): RedirectResponse
+ {
+ $syndicationTarget->delete();
+
+ return redirect('/admin/syndication');
+ }
+}
diff --git a/app/Http/Controllers/MicropubController.php b/app/Http/Controllers/MicropubController.php
index ea7d1413..b540ca18 100644
--- a/app/Http/Controllers/MicropubController.php
+++ b/app/Http/Controllers/MicropubController.php
@@ -6,11 +6,13 @@ namespace App\Http\Controllers;
use App\Http\Responses\MicropubResponses;
use App\Models\Place;
+use App\Models\SyndicationTarget;
use App\Services\Micropub\HCardService;
use App\Services\Micropub\HEntryService;
use App\Services\Micropub\UpdateService;
use App\Services\TokenService;
use Illuminate\Http\JsonResponse;
+use Illuminate\Http\Request;
use Lcobucci\JWT\Encoding\CannotDecodeContent;
use Lcobucci\JWT\Token\InvalidTokenStructure;
use Lcobucci\JWT\Validation\RequiredConstraintsViolated;
@@ -43,13 +45,14 @@ class MicropubController extends Controller
* This function receives an API request, verifies the authenticity
* then passes over the info to the relevant Service class.
*
+ * @param Request $request
* @return JsonResponse
*/
- public function post(): JsonResponse
+ public function post(Request $request): JsonResponse
{
try {
- $tokenData = $this->tokenService->validateToken(request()->input('access_token'));
- } catch (RequiredConstraintsViolated | InvalidTokenStructure | CannotDecodeContent $exception) {
+ $tokenData = $this->tokenService->validateToken($request->input('access_token'));
+ } catch (RequiredConstraintsViolated | InvalidTokenStructure | CannotDecodeContent) {
$micropubResponses = new MicropubResponses();
return $micropubResponses->invalidTokenResponse();
@@ -61,15 +64,15 @@ class MicropubController extends Controller
return $micropubResponses->tokenHasNoScopeResponse();
}
- $this->logMicropubRequest(request()->all());
+ $this->logMicropubRequest($request->all());
- if ((request()->input('h') == 'entry') || (request()->input('type.0') == 'h-entry')) {
- if (stristr($tokenData->claims()->get('scope'), 'create') === false) {
+ if (($request->input('h') === 'entry') || ($request->input('type.0') === 'h-entry')) {
+ if (stripos($tokenData->claims()->get('scope'), 'create') === false) {
$micropubResponses = new MicropubResponses();
return $micropubResponses->insufficientScopeResponse();
}
- $location = $this->hentryService->process(request()->all(), $this->getCLientId());
+ $location = $this->hentryService->process($request->all(), $this->getCLientId());
return response()->json([
'response' => 'created',
@@ -77,13 +80,13 @@ class MicropubController extends Controller
], 201)->header('Location', $location);
}
- if (request()->input('h') == 'card' || request()->input('type.0') == 'h-card') {
- if (stristr($tokenData->claims()->get('scope'), 'create') === false) {
+ if ($request->input('h') === 'card' || $request->input('type.0') === 'h-card') {
+ if (stripos($tokenData->claims()->get('scope'), 'create') === false) {
$micropubResponses = new MicropubResponses();
return $micropubResponses->insufficientScopeResponse();
}
- $location = $this->hcardService->process(request()->all());
+ $location = $this->hcardService->process($request->all());
return response()->json([
'response' => 'created',
@@ -91,14 +94,14 @@ class MicropubController extends Controller
], 201)->header('Location', $location);
}
- if (request()->input('action') == 'update') {
- if (stristr($tokenData->claims()->get('scope'), 'update') === false) {
+ if ($request->input('action') === 'update') {
+ if (stripos($tokenData->claims()->get('scope'), 'update') === false) {
$micropubResponses = new MicropubResponses();
return $micropubResponses->insufficientScopeResponse();
}
- return $this->updateService->process(request()->all());
+ return $this->updateService->process($request->all());
}
return response()->json([
@@ -121,21 +124,19 @@ class MicropubController extends Controller
{
try {
$tokenData = $this->tokenService->validateToken(request()->input('access_token'));
- } catch (RequiredConstraintsViolated | InvalidTokenStructure $exception) {
- $micropubResponses = new MicropubResponses();
-
- return $micropubResponses->invalidTokenResponse();
+ } catch (RequiredConstraintsViolated | InvalidTokenStructure) {
+ return (new MicropubResponses())->invalidTokenResponse();
}
if (request()->input('q') === 'syndicate-to') {
return response()->json([
- 'syndicate-to' => config('syndication.targets'),
+ 'syndicate-to' => SyndicationTarget::all(),
]);
}
- if (request()->input('q') == 'config') {
+ if (request()->input('q') === 'config') {
return response()->json([
- 'syndicate-to' => config('syndication.targets'),
+ 'syndicate-to' => SyndicationTarget::all(),
'media-endpoint' => route('media-endpoint'),
]);
}
diff --git a/app/Models/SyndicationTarget.php b/app/Models/SyndicationTarget.php
new file mode 100644
index 00000000..85d674c1
--- /dev/null
+++ b/app/Models/SyndicationTarget.php
@@ -0,0 +1,84 @@
+
+ */
+ protected $visible = [
+ 'uid',
+ 'name',
+ 'service',
+ 'user',
+ ];
+
+ /**
+ * The accessors to append to the model's array form.
+ *
+ * @var array
+ */
+ protected $appends = [
+ 'service',
+ 'user',
+ ];
+
+ /**
+ * Get the service data as a single attribute.
+ *
+ * @vreturn Attribute
+ */
+ protected function service(): Attribute
+ {
+ return Attribute::get(
+ get: fn ($value, $attributes) => [
+ 'name' => $attributes['service_name'],
+ 'url' => $attributes['service_url'],
+ 'photo' => $attributes['service_photo'],
+ ],
+ );
+ }
+
+ /**
+ * Get the user data as a single attribute.
+ *
+ * @vreturn Attribute
+ */
+ protected function user(): Attribute
+ {
+ return Attribute::get(
+ get: fn ($value, $attributes) => [
+ 'name' => $attributes['user_name'],
+ 'url' => $attributes['user_url'],
+ 'photo' => $attributes['user_photo'],
+ ],
+ );
+ }
+}
diff --git a/app/Services/BookmarkService.php b/app/Services/BookmarkService.php
index 2bf71d5f..d9012912 100644
--- a/app/Services/BookmarkService.php
+++ b/app/Services/BookmarkService.php
@@ -8,6 +8,7 @@ use App\Exceptions\InternetArchiveException;
use App\Jobs\ProcessBookmark;
use App\Jobs\SyndicateBookmarkToTwitter;
use App\Models\Bookmark;
+use App\Models\SyndicationTarget;
use App\Models\Tag;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;
@@ -52,7 +53,6 @@ class BookmarkService
$bookmark->tags()->save($tag);
}
- $targets = Arr::pluck(config('syndication.targets'), 'uid', 'service.name');
$mpSyndicateTo = null;
if (Arr::get($request, 'mp-syndicate-to')) {
$mpSyndicateTo = Arr::get($request, 'mp-syndicate-to');
@@ -60,18 +60,13 @@ class BookmarkService
if (Arr::get($request, 'properties.mp-syndicate-to')) {
$mpSyndicateTo = Arr::get($request, 'properties.mp-syndicate-to');
}
- if (is_string($mpSyndicateTo)) {
- $service = array_search($mpSyndicateTo, $targets);
- if ($service == 'Twitter') {
+ $mpSyndicateTo = Arr::wrap($mpSyndicateTo);
+ foreach ($mpSyndicateTo as $uid) {
+ $target = SyndicationTarget::where('uid', $uid)->first();
+ if ($target && $target->service_name === 'Twitter') {
SyndicateBookmarkToTwitter::dispatch($bookmark);
- }
- }
- if (is_array($mpSyndicateTo)) {
- foreach ($mpSyndicateTo as $uid) {
- $service = array_search($uid, $targets);
- if ($service == 'Twitter') {
- SyndicateBookmarkToTwitter::dispatch($bookmark);
- }
+
+ break;
}
}
diff --git a/app/Services/Micropub/HEntryService.php b/app/Services/Micropub/HEntryService.php
index bf19201f..2f8a2779 100644
--- a/app/Services/Micropub/HEntryService.php
+++ b/app/Services/Micropub/HEntryService.php
@@ -21,19 +21,13 @@ class HEntryService
public function process(array $request, ?string $client = null): ?string
{
if (Arr::get($request, 'properties.like-of') || Arr::get($request, 'like-of')) {
- $like = resolve(LikeService::class)->createLike($request);
-
- return $like->longurl;
+ return resolve(LikeService::class)->createLike($request)->longurl;
}
if (Arr::get($request, 'properties.bookmark-of') || Arr::get($request, 'bookmark-of')) {
- $bookmark = resolve(BookmarkService::class)->createBookmark($request);
-
- return $bookmark->longurl;
+ return resolve(BookmarkService::class)->createBookmark($request)->longurl;
}
- $note = resolve(NoteService::class)->createNote($request, $client);
-
- return $note->longurl;
+ return resolve(NoteService::class)->createNote($request, $client)->longurl;
}
}
diff --git a/app/Services/NoteService.php b/app/Services/NoteService.php
index 9c4dd357..57458389 100644
--- a/app/Services/NoteService.php
+++ b/app/Services/NoteService.php
@@ -9,6 +9,7 @@ use App\Jobs\SyndicateNoteToTwitter;
use App\Models\Media;
use App\Models\Note;
use App\Models\Place;
+use App\Models\SyndicationTarget;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
@@ -18,7 +19,7 @@ class NoteService
* Create a new note.
*
* @param array $request Data from request()->all()
- * @param string $client
+ * @param string|null $client
* @return Note
*/
public function createNote(array $request, ?string $client = null): Note
@@ -52,11 +53,9 @@ class NoteService
dispatch(new SendWebMentions($note));
- //syndication targets
- if (count($this->getSyndicationTargets($request)) > 0) {
- if (in_array('twitter', $this->getSyndicationTargets($request))) {
- dispatch(new SyndicateNoteToTwitter($note));
- }
+ // Syndication targets
+ if (in_array('twitter', $this->getSyndicationTargets($request), true)) {
+ dispatch(new SyndicateNoteToTwitter($note));
}
return $note;
@@ -206,22 +205,14 @@ class NoteService
private function getSyndicationTargets(array $request): array
{
$syndication = [];
- $targets = Arr::pluck(config('syndication.targets'), 'uid', 'service.name');
$mpSyndicateTo = Arr::get($request, 'mp-syndicate-to') ?? Arr::get($request, 'properties.mp-syndicate-to');
- if (is_string($mpSyndicateTo)) {
- $service = array_search($mpSyndicateTo, $targets);
- if ($service == 'Twitter') {
+ $mpSyndicateTo = Arr::wrap($mpSyndicateTo);
+ foreach ($mpSyndicateTo as $uid) {
+ $target = SyndicationTarget::where('uid', $uid)->first();
+ if ($target && $target->service_name === 'Twitter') {
$syndication[] = 'twitter';
}
}
- if (is_array($mpSyndicateTo)) {
- foreach ($mpSyndicateTo as $uid) {
- $service = array_search($uid, $targets);
- if ($service == 'Twitter') {
- $syndication[] = 'twitter';
- }
- }
- }
return $syndication;
}
diff --git a/config/syndication.php b/config/syndication.php
deleted file mode 100644
index 7a0a92f9..00000000
--- a/config/syndication.php
+++ /dev/null
@@ -1,26 +0,0 @@
- [];
- 'targets' => [
- [
- 'uid' => 'https://twitter.com/jonnybarnes',
- 'name' => 'jonnybarnes on Twitter',
- 'service' => [
- 'name' => 'Twitter',
- 'url' => 'https://twitter.com',
- 'photo' => 'https://upload.wikimedia.org/wikipedia/commons/4/4f/Twitter-logo.svg',
- ],
- 'user' => [
- 'name' => 'jonnybarnes',
- 'url' => 'https://twitter.com/jonnybarnes',
- 'photo' => 'https://pbs.twimg.com/profile_images/875422855932121089/W628ZI8w_400x400.jpg',
- ],
- ],
- ],
-];
diff --git a/database/factories/SyndicationTargetFactory.php b/database/factories/SyndicationTargetFactory.php
new file mode 100644
index 00000000..c877c9d4
--- /dev/null
+++ b/database/factories/SyndicationTargetFactory.php
@@ -0,0 +1,30 @@
+
+ */
+class SyndicationTargetFactory extends Factory
+{
+ /**
+ * Define the model's default state.
+ *
+ * @return array No saved syndication targets.
+ Create a new syndication target?
+ New Syndication Target
+
+@stop
diff --git a/resources/views/admin/syndication/edit.blade.php b/resources/views/admin/syndication/edit.blade.php
new file mode 100644
index 00000000..400ff5d4
--- /dev/null
+++ b/resources/views/admin/syndication/edit.blade.php
@@ -0,0 +1,52 @@
+@extends('master')
+
+@section('title')Edit Syndication Target « Admin CP « @stop
+
+@section('content')
+ Edit syndication target
+
+
+
+@stop
diff --git a/resources/views/admin/syndication/index.blade.php b/resources/views/admin/syndication/index.blade.php
new file mode 100644
index 00000000..513e2c76
--- /dev/null
+++ b/resources/views/admin/syndication/index.blade.php
@@ -0,0 +1,22 @@
+@extends('master')
+
+@section('title')List Syndication Targets « Admin CP « @stop
+
+@section('content')
+ Syndication Targets
+ @if($targets->isEmpty())
+
+ @foreach($targets as $target)
+
+ @endif
+
+ You can either create new syndication targets, + or edit them. +
@stop diff --git a/routes/web.php b/routes/web.php index 4d83f871..f721a2df 100644 --- a/routes/web.php +++ b/routes/web.php @@ -18,6 +18,7 @@ use App\Http\Controllers\Admin\HomeController; use App\Http\Controllers\Admin\LikesController as AdminLikesController; use App\Http\Controllers\Admin\NotesController as AdminNotesController; use App\Http\Controllers\Admin\PlacesController as AdminPlacesController; +use App\Http\Controllers\Admin\SyndicationTargetsController; use App\Http\Controllers\ArticlesController; use App\Http\Controllers\AuthController; use App\Http\Controllers\BookmarksController; @@ -122,6 +123,16 @@ Route::group(['domain' => config('url.longurl')], function () { Route::put('/{id}', [AdminLikesController::class, 'update']); Route::delete('/{id}', [AdminLikesController::class, 'destroy']); }); + + // Syndication Targets + Route::group(['prefix' => 'syndication'], function () { + Route::get('/', [SyndicationTargetsController::class, 'index']); + Route::get('/create', [SyndicationTargetsController::class, 'create']); + Route::post('/', [SyndicationTargetsController::class, 'store']); + Route::get('/{syndicationTarget}/edit', [SyndicationTargetsController::class, 'edit']); + Route::put('/{syndicationTarget}', [SyndicationTargetsController::class, 'update']); + Route::delete('/{syndicationTarget}', [SyndicationTargetsController::class, 'destroy']); + }); }); // Blog pages using ArticlesController diff --git a/tests/Feature/BookmarksTest.php b/tests/Feature/BookmarksTest.php index 8b298dbf..b1f25982 100644 --- a/tests/Feature/BookmarksTest.php +++ b/tests/Feature/BookmarksTest.php @@ -7,6 +7,7 @@ namespace Tests\Feature; use App\Jobs\ProcessBookmark; use App\Jobs\SyndicateBookmarkToTwitter; use App\Models\Bookmark; +use App\Models\SyndicationTarget; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Support\Facades\Queue; use Tests\TestCase; @@ -36,6 +37,11 @@ class BookmarksTest extends TestCase { Queue::fake(); + SyndicationTarget::factory()->create([ + 'uid' => 'https://twitter.com/jonnybarnes', + 'service_name' => 'Twitter', + ]); + $response = $this->withHeaders([ 'Authorization' => 'Bearer ' . $this->getToken(), ])->post('/api/post', [ @@ -58,6 +64,11 @@ class BookmarksTest extends TestCase { Queue::fake(); + SyndicationTarget::factory()->create([ + 'uid' => 'https://twitter.com/jonnybarnes', + 'service_name' => 'Twitter', + ]); + $response = $this->withHeaders([ 'Authorization' => 'Bearer ' . $this->getToken(), ])->json('POST', '/api/post', [ @@ -82,6 +93,11 @@ class BookmarksTest extends TestCase { Queue::fake(); + SyndicationTarget::factory()->create([ + 'uid' => 'https://twitter.com/jonnybarnes', + 'service_name' => 'Twitter', + ]); + $response = $this->withHeaders([ 'Authorization' => 'Bearer ' . $this->getToken(), ])->post('/api/post', [ diff --git a/tests/Feature/MicropubControllerTest.php b/tests/Feature/MicropubControllerTest.php index 688ca1b8..12604ad3 100644 --- a/tests/Feature/MicropubControllerTest.php +++ b/tests/Feature/MicropubControllerTest.php @@ -9,6 +9,7 @@ use App\Jobs\SyndicateNoteToTwitter; use App\Models\Media; use App\Models\Note; use App\Models\Place; +use App\Models\SyndicationTarget; use Carbon\Carbon; use Faker\Factory; use Illuminate\Foundation\Testing\RefreshDatabase; @@ -51,10 +52,18 @@ class MicropubControllerTest extends TestCase } /** @test */ - public function micropubClientsCanRequestSyndicationTargets(): void + public function micropubClientsCanRequestSyndicationTargetsCanBeEmpty(): void { $response = $this->get('/api/post?q=syndicate-to', ['HTTP_Authorization' => 'Bearer ' . $this->getToken()]); - $response->assertJsonFragment(['uid' => 'https://twitter.com/jonnybarnes']); + $response->assertJsonFragment(['syndicate-to' => []]); + } + + /** @test */ + public function micropubClientsCanRequestSyndicationTargetsPopulatesFromModel(): void + { + $syndicationTarget = SyndicationTarget::factory()->create(); + $response = $this->get('/api/post?q=syndicate-to', ['HTTP_Authorization' => 'Bearer ' . $this->getToken()]); + $response->assertJsonFragment(['uid' => $syndicationTarget->uid]); } /** @test */ @@ -91,7 +100,7 @@ class MicropubControllerTest extends TestCase public function micropubClientCanRequestEndpointConfig(): void { $response = $this->get('/api/post?q=config', ['HTTP_Authorization' => 'Bearer ' . $this->getToken()]); - $response->assertJsonFragment(['uid' => 'https://twitter.com/jonnybarnes']); + $response->assertJsonFragment(['media-endpoint' => route('media-endpoint')]); } /** @test */ @@ -117,6 +126,12 @@ class MicropubControllerTest extends TestCase public function micropubClientCanRequestTheNewNoteIsSyndicatedToTwitter(): void { Queue::fake(); + + SyndicationTarget::factory()->create([ + 'uid' => 'https://twitter.com/jonnybarnes', + 'service_name' => 'Twitter', + ]); + $faker = Factory::create(); $note = $faker->text; $response = $this->post( @@ -224,6 +239,11 @@ class MicropubControllerTest extends TestCase 'path' => 'test-photo.jpg', 'type' => 'image', ]); + SyndicationTarget::factory()->create([ + 'uid' => 'https://twitter.com/jonnybarnes', + 'service_name' => 'Twitter', + ]); + $faker = Factory::create(); $note = $faker->text; $response = $this->postJson(