1
0
mirror of https://github.com/Kovah/LinkAce.git synced 2025-01-17 13:18:21 +01:00

Add RSS feeds for public lists accessible via guest mode (#197)

This commit is contained in:
Kovah 2021-03-28 23:53:12 +02:00
parent 1c98fc39ce
commit b8135ac162
No known key found for this signature in database
GPG Key ID: AAAA031BA9830D7B
12 changed files with 216 additions and 4 deletions

View File

@ -0,0 +1,61 @@
<?php
namespace App\Http\Controllers\Guest;
use App\Http\Controllers\Controller;
use App\Models\Link;
use App\Models\LinkList;
use App\Models\Tag;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class FeedController extends Controller
{
public function links(Request $request)
{
$links = Link::publicOnly()->latest()->with('user')->get();
$meta = [
'title' => 'LinkAce Links',
'link' => $request->fullUrl(),
'updated' => now()->toRfc3339String(),
'id' => $request->fullUrl(),
];
return new Response(view('guest.links.feed', [
'meta' => $meta,
'links' => $links,
]), 200, ['Content-Type' => 'application/xml']);
}
public function lists(Request $request)
{
$lists = LinkList::publicOnly()->latest()->with('user')->get();
$meta = [
'title' => 'LinkAce Lists',
'link' => $request->fullUrl(),
'updated' => now()->toRfc3339String(),
'id' => $request->fullUrl(),
];
return new Response(view('guest.lists.feed', [
'meta' => $meta,
'lists' => $lists,
]), 200, ['Content-Type' => 'application/xml']);
}
public function tags(Request $request)
{
$tags = Tag::publicOnly()->latest()->with('user')->get();
$meta = [
'title' => 'LinkAce Links',
'link' => $request->fullUrl(),
'updated' => now()->toRfc3339String(),
'id' => $request->fullUrl(),
];
return new Response(view('guest.tags.feed', [
'meta' => $meta,
'tags' => $tags,
]), 200, ['Content-Type' => 'application/xml']);
}
}

View File

@ -31,6 +31,7 @@ return [
'menu' => 'Menu',
'entries' => 'Entries',
'feed' => 'Feed',
'continue_adding' => 'Continue Adding',

View File

@ -0,0 +1 @@
<svg {{ $attributes->merge(['class' => 'icon', 'viewBox' =>'0 0 448 512', 'xmlns' => 'http://www.w3.org/2000/svg', 'aria-hidden' => 'true', 'focusable' => 'false']) }}><path d="M128.081 415.959c0 35.369-28.672 64.041-64.041 64.041S0 451.328 0 415.959s28.672-64.041 64.041-64.041 64.04 28.673 64.04 64.041zm175.66 47.25c-8.354-154.6-132.185-278.587-286.95-286.95C7.656 175.765 0 183.105 0 192.253v48.069c0 8.415 6.49 15.472 14.887 16.018 111.832 7.284 201.473 96.702 208.772 208.772.547 8.397 7.604 14.887 16.018 14.887h48.069c9.149.001 16.489-7.655 15.995-16.79zm144.249.288C439.596 229.677 251.465 40.445 16.503 32.01 7.473 31.686 0 38.981 0 48.016v48.068c0 8.625 6.835 15.645 15.453 15.999 191.179 7.839 344.627 161.316 352.465 352.465.353 8.618 7.373 15.453 15.999 15.453h48.068c9.034-.001 16.329-7.474 16.005-16.504z"/></svg>

After

Width:  |  Height:  |  Size: 830 B

View File

@ -0,0 +1,20 @@
<?= '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL ?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>{{ $meta['title'] }}</title>
<link href="{{ $meta['link'] }}"/>
<updated>{{ $meta['updated'] }}</updated>
<id>{{ $meta['id'] }}</id>
@foreach($links as $link)
<entry>
<title><![CDATA[{{ $link->title }}]]></title>
<id>{{ $link->url }}</id>
<author>
<name> <![CDATA[{{ $link->user->name }}]]></name>
</author>
<summary type="html">
<![CDATA[{!! $link->markdownDescription !!}]]>
</summary>
<updated>{{ $link->updated_at->toRfc3339String() }}</updated>
</entry>
@endforeach
</feed>

View File

@ -1,12 +1,20 @@
@extends('layouts.guest')
@push('html-header')
<link rel="alternate" type="application/atom+xml" href="{{ route('guest.links.feed') }}">
@endpush
@section('content')
<header class="d-flex align-items-center">
<h3 class="mb-0">
<h3 class="mb-0 mr-3">
@lang('link.links')
</h3>
<div class="dropdown ml-auto">
<a href="{{ route('guest.links.feed') }}" class="ml-auto btn btn-sm btn-outline-secondary">
<x-icon.feed/>
<span class="sr-only">@lang('linkace.add')</span>
</a>
<div class="dropdown ml-1">
@include('models.links.partials.index-order-dropdown', ['baseRoute' => 'guest.links.index'])
</div>
</header>

View File

@ -0,0 +1,21 @@
<?= '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL ?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>{{ $meta['title'] }}</title>
<link href="{{ $meta['link'] }}"/>
<updated>{{ $meta['updated'] }}</updated>
<id>{{ $meta['id'] }}</id>
@foreach($lists as $list)
<entry>
<title><![CDATA[{{ $list->name }}]]></title>
<link rel="alternate" href="{{ route('guest.lists.show', ['list' => $list]) }}"/>
<id>{{ url($list->id) }}</id>
<author>
<name> <![CDATA[{{ $list->user->name }}]]></name>
</author>
<summary type="html">
<![CDATA[{!! $list->description !!}]]>
</summary>
<updated>{{ $list->updated_at->toRfc3339String() }}</updated>
</entry>
@endforeach
</feed>

View File

@ -1,12 +1,20 @@
@extends('layouts.guest')
@push('html-header')
<link rel="alternate" type="application/atom+xml" href="{{ route('guest.lists.feed') }}">
@endpush
@section('content')
<header class="d-flex align-items-center">
<h3 class="mb-0 mr-3">
@lang('list.lists')
</h3>
<div class="dropdown ml-auto">
<a href="{{ route('guest.lists.feed') }}" class="ml-auto btn btn-sm btn-outline-secondary">
<x-icon.feed/>
<span class="sr-only">@lang('linkace.add')</span>
</a>
<div class="dropdown ml-1">
@include('models.lists.partials.index-order-dropdown', ['baseRoute' => 'lists.index'])
</div>
</header>

View File

@ -0,0 +1,17 @@
<?= '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL ?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>{{ $meta['title'] }}</title>
<link href="{{ $meta['link'] }}"/>
<updated>{{ $meta['updated'] }}</updated>
<id>{{ $meta['id'] }}</id>
@foreach($tags as $tag)
<entry>
<title><![CDATA[{{ $tag->name }}]]></title>
<id>{{ route('tags.show', ['tag' => $tag]) }}</id>
<author>
<name> <![CDATA[{{ $tag->user->name }}]]></name>
</author>
<updated>{{ $tag->updated_at->toRfc3339String() }}</updated>
</entry>
@endforeach
</feed>

View File

@ -1,11 +1,19 @@
@extends('layouts.guest')
@push('html-header')
<link rel="alternate" type="application/atom+xml" href="{{ route('guest.tags.feed') }}">
@endpush
@section('content')
<header class="d-flex align-items-center">
<h3 class="mb-0">
<h3 class="mb-0 mr-3">
@lang('tag.tags')
</h3>
<a href="{{ route('guest.tags.feed') }}" class="ml-auto btn btn-sm btn-outline-secondary">
<x-icon.feed/>
<span class="sr-only">@lang('linkace.add')</span>
</a>
</header>
<div class="card my-3 mb-3">

View File

@ -4,6 +4,7 @@
<title>{{ systemsettings('system_page_title') ?: config('app.name', 'LinkAce') }}</title>
@stack('html-header')
@include('partials.favicon')
@include('partials.configure-darkmode')

View File

@ -11,6 +11,7 @@ use App\Http\Controllers\App\UserSettingsController;
use App\Http\Controllers\CronController;
use App\Http\Controllers\FetchController;
use App\Http\Controllers\FrontController;
use App\Http\Controllers\Guest\FeedController;
use App\Http\Controllers\Guest\LinkController as GuestLinkController;
use App\Http\Controllers\Guest\ListController as GuestListController;
use App\Http\Controllers\Guest\TagController as GuestTagController;
@ -129,6 +130,10 @@ Route::group(['middleware' => ['auth']], function () {
// Guest access routes
Route::prefix('guest')->middleware(['guestaccess'])->group(function () {
Route::get('links/feed', [FeedController::class, 'links'])->name('guest.links.feed');
Route::get('lists/feed', [FeedController::class, 'lists'])->name('guest.lists.feed');
Route::get('tags/feed', [FeedController::class, 'tags'])->name('guest.tags.feed');
Route::resource('links', GuestLinkController::class)
->only(['index'])
->names([

View File

@ -0,0 +1,61 @@
<?php
namespace Tests\Controller\Guest;
use App\Models\Link;
use App\Models\LinkList;
use App\Models\Setting;
use App\Models\Tag;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class FeedControllerTest extends TestCase
{
use RefreshDatabase;
protected function setUp(): void
{
parent::setUp();
Setting::create([
'key' => 'system_guest_access',
'value' => '1',
]);
}
public function testLinkFeed(): void
{
$linkPublic = Link::factory()->create(['is_private' => false]);
$linkPrivate = Link::factory()->create(['is_private' => true]);
$response = $this->get('guest/links/feed');
$response->assertOk()
->assertSee($linkPublic->url)
->assertDontSee($linkPrivate->url);
}
public function testListFeed(): void
{
$listPublic = LinkList::factory()->create(['is_private' => false]);
$listPrivate = LinkList::factory()->create(['is_private' => true]);
$response = $this->get('guest/lists/feed');
$response->assertOk()
->assertSee($listPublic->name)
->assertDontSee($listPrivate->name);
}
public function testTagsFeed(): void
{
$tagPublic = Tag::factory()->create(['is_private' => false]);
$tagPrivate = Tag::factory()->create(['is_private' => true]);
$response = $this->get('guest/tags/feed');
$response->assertOk()
->assertSee($tagPublic->name)
->assertDontSee($tagPrivate->name);
}
}