mirror of
https://github.com/Kovah/LinkAce.git
synced 2025-01-17 13:18:21 +01:00
Add RSS feeds for lists and tags links (#197)
This commit is contained in:
parent
e8aec55015
commit
80e73ba1d4
@ -11,7 +11,7 @@ use Illuminate\Http\Response;
|
||||
|
||||
class FeedController extends Controller
|
||||
{
|
||||
public function links(Request $request)
|
||||
public function links(Request $request): Response
|
||||
{
|
||||
$links = Link::latest()->with('user')->get();
|
||||
$meta = [
|
||||
@ -27,7 +27,7 @@ class FeedController extends Controller
|
||||
]), 200, ['Content-Type' => 'application/xml']);
|
||||
}
|
||||
|
||||
public function lists(Request $request)
|
||||
public function lists(Request $request): Response
|
||||
{
|
||||
$lists = LinkList::latest()->with('user')->get();
|
||||
$meta = [
|
||||
@ -43,7 +43,23 @@ class FeedController extends Controller
|
||||
]), 200, ['Content-Type' => 'application/xml']);
|
||||
}
|
||||
|
||||
public function tags(Request $request)
|
||||
public function listLinks(Request $request, LinkList $list): Response
|
||||
{
|
||||
$links = $list->links()->with('user')->latest()->get();
|
||||
$meta = [
|
||||
'title' => $list->name,
|
||||
'link' => $request->fullUrl(),
|
||||
'updated' => now()->toRfc3339String(),
|
||||
'id' => $request->fullUrl(),
|
||||
];
|
||||
|
||||
return new Response(view('actions.feed.links', [
|
||||
'meta' => $meta,
|
||||
'links' => $links,
|
||||
]), 200, ['Content-Type' => 'application/xml']);
|
||||
}
|
||||
|
||||
public function tags(Request $request): Response
|
||||
{
|
||||
$tags = Tag::latest()->with('user')->get();
|
||||
$meta = [
|
||||
@ -58,4 +74,20 @@ class FeedController extends Controller
|
||||
'tags' => $tags,
|
||||
]), 200, ['Content-Type' => 'application/xml']);
|
||||
}
|
||||
|
||||
public function tagLinks(Request $request, Tag $tag): Response
|
||||
{
|
||||
$links = $tag->links()->with('user')->latest()->get();
|
||||
$meta = [
|
||||
'title' => $tag->name,
|
||||
'link' => $request->fullUrl(),
|
||||
'updated' => now()->toRfc3339String(),
|
||||
'id' => $request->fullUrl(),
|
||||
];
|
||||
|
||||
return new Response(view('actions.feed.links', [
|
||||
'meta' => $meta,
|
||||
'links' => $links,
|
||||
]), 200, ['Content-Type' => 'application/xml']);
|
||||
}
|
||||
}
|
||||
|
@ -43,6 +43,23 @@ class FeedController extends Controller
|
||||
]), 200, ['Content-Type' => 'application/xml']);
|
||||
}
|
||||
|
||||
public function listLinks(Request $request, $listID)
|
||||
{
|
||||
$list = LinkList::publicOnly()->findOrFail($listID);
|
||||
$links = $list->links()->publicOnly()->latest()->with('user')->get();
|
||||
$meta = [
|
||||
'title' => $list->name,
|
||||
'link' => $request->fullUrl(),
|
||||
'updated' => now()->toRfc3339String(),
|
||||
'id' => $request->fullUrl(),
|
||||
];
|
||||
|
||||
return new Response(view('actions.feed.links', [
|
||||
'meta' => $meta,
|
||||
'links' => $links,
|
||||
]), 200, ['Content-Type' => 'application/xml']);
|
||||
}
|
||||
|
||||
public function tags(Request $request)
|
||||
{
|
||||
$tags = Tag::publicOnly()->latest()->with('user')->get();
|
||||
@ -58,4 +75,21 @@ class FeedController extends Controller
|
||||
'tags' => $tags,
|
||||
]), 200, ['Content-Type' => 'application/xml']);
|
||||
}
|
||||
|
||||
public function tagLinks(Request $request, $tagID)
|
||||
{
|
||||
$tag = Tag::publicOnly()->findOrFail($tagID);
|
||||
$links = $tag->links()->publicOnly()->latest()->with('user')->get();
|
||||
$meta = [
|
||||
'title' => $tag->name,
|
||||
'link' => $request->fullUrl(),
|
||||
'updated' => now()->toRfc3339String(),
|
||||
'id' => $request->fullUrl(),
|
||||
];
|
||||
|
||||
return new Response(view('actions.feed.links', [
|
||||
'meta' => $meta,
|
||||
'links' => $links,
|
||||
]), 200, ['Content-Type' => 'application/xml']);
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ class TagController extends Controller
|
||||
$tag = Tag::publicOnly()->findOrFail($tagID);
|
||||
|
||||
$links = $tag->links()
|
||||
->privateOnly(false)
|
||||
->privateOnly()
|
||||
->orderBy(
|
||||
$request->input('orderBy', 'title'),
|
||||
$request->input('orderDir', 'ASC')
|
||||
|
@ -1,131 +0,0 @@
|
||||
<div class="card">
|
||||
<header class="card-header">
|
||||
@lang('link.add')
|
||||
</header>
|
||||
<div class="card-body">
|
||||
|
||||
<form action="{{ route('links.store') }}" method="POST">
|
||||
@csrf
|
||||
|
||||
<div class="form-group">
|
||||
<label class="label" for="url">@lang('link.url')</label>
|
||||
<input name="url" id="url" type="url"
|
||||
class="form-control form-control-lg{{ $errors->has('url') ? ' is-invalid' : '' }}"
|
||||
placeholder="@lang('placeholder.link_url')" value="{{ old('url') ?: $bookmark_url ?? '' }}"
|
||||
required autofocus>
|
||||
|
||||
<p class="invalid-feedback {{ $errors->has('url') ? 'd-none' : '' }}">
|
||||
@lang('validation.unique', ['attribute' => trans('link.url')])
|
||||
</p>
|
||||
|
||||
@if ($errors->has('url'))
|
||||
<p class="invalid-feedback" role="alert">
|
||||
{{ $errors->first('url') }}
|
||||
</p>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-6 col-md-7">
|
||||
|
||||
<div class="form-group">
|
||||
<label class="label" for="title">@lang('link.title')</label>
|
||||
<input name="title" id="title"
|
||||
class="form-control{{ $errors->has('title') ? ' is-invalid' : '' }}"
|
||||
type="text" placeholder="@lang('placeholder.link_title')"
|
||||
value="{{ old('title') ?: $bookmark_title ?? '' }}">
|
||||
@if ($errors->has('title'))
|
||||
<p class="invalid-feedback" role="alert">
|
||||
{{ $errors->first('title') }}
|
||||
</p>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="description">@lang('link.description')</label>
|
||||
<textarea name="description" id="description" rows="4" class="form-control"
|
||||
>{{ old('description') }}</textarea>
|
||||
|
||||
@if ($errors->has('description'))
|
||||
<p class="invalid-feedback" role="alert">
|
||||
{{ $errors->first('description') }}
|
||||
</p>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="col-12 col-sm-6 col-md-5">
|
||||
|
||||
<div class="form-group">
|
||||
<label for="lists">@lang('list.lists')</label>
|
||||
<input name="lists" id="lists" type="text" placeholder="@lang('placeholder.list_select')"
|
||||
class="tags-select" value="{{ old('lists') }}" data-tag-type="lists">
|
||||
|
||||
@if ($errors->has('lists'))
|
||||
<p class="invalid-feedback" role="alert">
|
||||
{{ $errors->first('lists') }}
|
||||
</p>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="tags">@lang('tag.tags')</label>
|
||||
<input name="tags" id="tags" type="text" placeholder="@lang('placeholder.tags_select')"
|
||||
class="tags-select" value="{{ old('tags') }}" data-tag-type="tags">
|
||||
|
||||
@if ($errors->has('tags'))
|
||||
<p class="invalid-feedback" role="alert">
|
||||
{{ $errors->first('tags') }}
|
||||
</p>
|
||||
@endif
|
||||
|
||||
<div class="tag-suggestions mt-2 d-none">
|
||||
<small>@lang('We found some tags which might be interesting...')</small>
|
||||
<div class="tag-suggestions-content mt-1"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="is_private">@lang('linkace.is_private')</label>
|
||||
<select id="is_private" name="is_private"
|
||||
class="custom-select{{ $errors->has('is_private') ? ' is-invalid' : '' }}">
|
||||
<option value="0">
|
||||
@lang('linkace.no')
|
||||
</option>
|
||||
<option value="1" @if(usersettings('links_private_default') === '1') selected @endif>
|
||||
@lang('linkace.yes')
|
||||
</option>
|
||||
</select>
|
||||
|
||||
@if ($errors->has('is_private'))
|
||||
<p class="invalid-feedback" role="alert">
|
||||
{{ $errors->first('is_private') }}
|
||||
</p>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 d-sm-flex align-items-center justify-content-end">
|
||||
|
||||
@if(!isset($bookmark_url))
|
||||
<div class="custom-control custom-checkbox mb-3 mb-sm-0 mr-sm-4">
|
||||
<input class="custom-control-input" type="checkbox" id="reload_view" name="reload_view"
|
||||
@if(session('reload_view')) checked @endif>
|
||||
<label class="custom-control-label" for="reload_view">
|
||||
@lang('linkace.continue_adding')
|
||||
</label>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<x-icon.save class="mr-2"/> @lang('link.add')
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
@ -12,7 +12,7 @@
|
||||
</h3>
|
||||
<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>
|
||||
<span class="sr-only">@lang('linkace.feed')</span>
|
||||
</a>
|
||||
<div class="dropdown ml-1">
|
||||
@include('models.lists.partials.index-order-dropdown', ['baseRoute' => 'lists.index'])
|
||||
|
@ -3,8 +3,15 @@
|
||||
@section('content')
|
||||
|
||||
<div class="card">
|
||||
<header class="card-header">
|
||||
@lang('list.list')
|
||||
<header class="card-header d-flex align-items-center">
|
||||
|
||||
<span class="mr-3">@lang('list.list')</span>
|
||||
<a href="{{ route('guest.lists.links.feed', ['list' => $list]) }}"
|
||||
class="ml-auto btn btn-xs btn-outline-secondary">
|
||||
<x-icon.feed/>
|
||||
<span class="sr-only">@lang('linkace.feed')</span>
|
||||
</a>
|
||||
|
||||
</header>
|
||||
<div class="card-body">
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
</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>
|
||||
<span class="sr-only">@lang('linkace.feed')</span>
|
||||
</a>
|
||||
</header>
|
||||
|
||||
|
@ -3,13 +3,18 @@
|
||||
@section('content')
|
||||
|
||||
<div class="card">
|
||||
<header class="card-header">
|
||||
@lang('tag.tag')
|
||||
<header class="card-header d-flex align-items-center">
|
||||
|
||||
<span class="mr-3">@lang('tag.tag')</span>
|
||||
<a href="{{ route('guest.tags.links.feed', ['tag' => $tag]) }}"
|
||||
class="ml-auto btn btn-xs btn-outline-secondary">
|
||||
<x-icon.feed/>
|
||||
<span class="sr-only">@lang('linkace.feed')</span>
|
||||
</a>
|
||||
|
||||
</header>
|
||||
<div class="card-body">
|
||||
|
||||
<h2 class="mb-0">{{ $tag->name }}</h2>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -58,7 +58,9 @@ Route::get('cron/{token}', CronController::class)->name('cron');
|
||||
Route::group(['middleware' => 'auth:api'], function () {
|
||||
Route::get('links/feed', [FeedController::class, 'links'])->name('links.feed');
|
||||
Route::get('lists/feed', [FeedController::class, 'lists'])->name('lists.feed');
|
||||
Route::get('lists/{list}/feed', [FeedController::class, 'listLinks'])->name('lists.links.feed');
|
||||
Route::get('tags/feed', [FeedController::class, 'tags'])->name('tags.feed');
|
||||
Route::get('tags/{tag}/feed', [FeedController::class, 'tagLinks'])->name('tags.links.feed');
|
||||
});
|
||||
|
||||
// Model routes
|
||||
@ -139,7 +141,9 @@ Route::prefix('guest')->middleware(['guestaccess'])->group(function () {
|
||||
|
||||
Route::get('links/feed', [GuestFeedController::class, 'links'])->name('guest.links.feed');
|
||||
Route::get('lists/feed', [GuestFeedController::class, 'lists'])->name('guest.lists.feed');
|
||||
Route::get('lists/{list}/feed', [GuestFeedController::class, 'listLinks'])->name('guest.lists.links.feed');
|
||||
Route::get('tags/feed', [GuestFeedController::class, 'tags'])->name('guest.tags.feed');
|
||||
Route::get('tags/{tag}/feed', [GuestFeedController::class, 'tagLinks'])->name('guest.tags.links.feed');
|
||||
|
||||
Route::resource('links', GuestLinkController::class)
|
||||
->only(['index'])
|
||||
|
@ -50,6 +50,22 @@ class FeedControllerTest extends TestCase
|
||||
->assertSee($list->name);
|
||||
}
|
||||
|
||||
public function testListLinkFeed(): void
|
||||
{
|
||||
$link = LinkList::factory()->create();
|
||||
$listLink = Link::factory()->create();
|
||||
$unrelatedLink = Link::factory()->create();
|
||||
|
||||
$listLink->lists()->sync([$link->id]);
|
||||
|
||||
$response = $this->getAuthorized('lists/1/feed');
|
||||
|
||||
$response->assertOk()
|
||||
->assertSee($link->name)
|
||||
->assertSee($listLink->url)
|
||||
->assertDontSee($unrelatedLink->url);
|
||||
}
|
||||
|
||||
public function testTagsFeed(): void
|
||||
{
|
||||
$tag = Tag::factory()->create();
|
||||
@ -60,6 +76,22 @@ class FeedControllerTest extends TestCase
|
||||
->assertSee($tag->name);
|
||||
}
|
||||
|
||||
public function testTagLinkFeed(): void
|
||||
{
|
||||
$tag = Tag::factory()->create();
|
||||
$tagLink = Link::factory()->create();
|
||||
$unrelatedLink = Link::factory()->create();
|
||||
|
||||
$tagLink->tags()->sync([$tag->id]);
|
||||
|
||||
$response = $this->getAuthorized('tags/1/feed');
|
||||
|
||||
$response->assertOk()
|
||||
->assertSee($tag->name)
|
||||
->assertSee($tagLink->url)
|
||||
->assertDontSee($unrelatedLink->url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an authorized request for the GET method.
|
||||
*
|
||||
|
@ -47,6 +47,33 @@ class FeedControllerTest extends TestCase
|
||||
->assertDontSee($listPrivate->name);
|
||||
}
|
||||
|
||||
public function testListLinkFeed(): void
|
||||
{
|
||||
$link = LinkList::factory()->create(['is_private' => false]);
|
||||
$listLink = Link::factory()->create(['is_private' => false]);
|
||||
$privateListLink = Link::factory()->create(['is_private' => true]);
|
||||
$unrelatedLink = Link::factory()->create();
|
||||
|
||||
$listLink->lists()->sync([$link->id]);
|
||||
|
||||
$response = $this->get('guest/lists/1/feed');
|
||||
|
||||
$response->assertOk()
|
||||
->assertSee($link->name)
|
||||
->assertSee($listLink->url)
|
||||
->assertDontSee($privateListLink->url)
|
||||
->assertDontSee($unrelatedLink->url);
|
||||
}
|
||||
|
||||
public function testPrivateListLinkFeed(): void
|
||||
{
|
||||
LinkList::factory()->create(['is_private' => true]);
|
||||
|
||||
$response = $this->get('guest/lists/1/feed');
|
||||
|
||||
$response->assertNotFound();
|
||||
}
|
||||
|
||||
public function testTagsFeed(): void
|
||||
{
|
||||
$tagPublic = Tag::factory()->create(['is_private' => false]);
|
||||
@ -58,4 +85,31 @@ class FeedControllerTest extends TestCase
|
||||
->assertSee($tagPublic->name)
|
||||
->assertDontSee($tagPrivate->name);
|
||||
}
|
||||
|
||||
public function testTagLinkFeed(): void
|
||||
{
|
||||
$tag = Tag::factory()->create(['is_private' => false]);
|
||||
$tagLink = Link::factory()->create(['is_private' => false]);
|
||||
$privateTagLink = Link::factory()->create(['is_private' => true]);
|
||||
$unrelatedLink = Link::factory()->create();
|
||||
|
||||
$tagLink->tags()->sync([$tag->id]);
|
||||
|
||||
$response = $this->get('guest/tags/1/feed');
|
||||
|
||||
$response->assertOk()
|
||||
->assertSee($tag->name)
|
||||
->assertSee($tagLink->url)
|
||||
->assertDontSee($privateTagLink->url)
|
||||
->assertDontSee($unrelatedLink->url);
|
||||
}
|
||||
|
||||
public function testPrivateTagLinkFeed(): void
|
||||
{
|
||||
Tag::factory()->create(['is_private' => true]);
|
||||
|
||||
$response = $this->get('guest/tags/1/feed');
|
||||
|
||||
$response->assertNotFound();
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user