Save workspace changes
This commit is contained in:
@@ -0,0 +1,187 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Controllers\Web;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Artwork;
|
||||
use App\Services\ContentTypes\ContentTypeSlugResolver;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\View\View;
|
||||
|
||||
/**
|
||||
* RssFeedController
|
||||
*
|
||||
* GET /rss-feeds → info page listing all available feeds
|
||||
* GET /rss/latest-uploads.xml → all published artworks (legacy)
|
||||
* GET /rss/latest-skins.xml → skins only (legacy)
|
||||
* GET /rss/latest-wallpapers.xml → wallpapers only (legacy)
|
||||
* GET /rss/latest-photos.xml → photography only (legacy)
|
||||
*
|
||||
* Nova feeds live in App\Http\Controllers\RSS\*.
|
||||
*/
|
||||
final class RssFeedController extends Controller
|
||||
{
|
||||
/** Number of items per legacy feed. */
|
||||
private const FEED_LIMIT = 25;
|
||||
|
||||
/** Flat feed list kept for backward-compatibility (old view logic). */
|
||||
public const FEEDS = [
|
||||
'uploads' => ['title' => 'Latest Uploads', 'url' => '/rss/latest-uploads.xml'],
|
||||
'skins' => ['title' => 'Latest Skins', 'url' => '/rss/latest-skins.xml'],
|
||||
'wallpapers' => ['title' => 'Latest Wallpapers', 'url' => '/rss/latest-wallpapers.xml'],
|
||||
'photos' => ['title' => 'Latest Photos', 'url' => '/rss/latest-photos.xml'],
|
||||
];
|
||||
|
||||
public function __construct(private readonly ContentTypeSlugResolver $contentTypeResolver)
|
||||
{
|
||||
}
|
||||
|
||||
/** Info page at /rss-feeds */
|
||||
public function index(): View
|
||||
{
|
||||
return view('web.rss-feeds', [
|
||||
'page_title' => 'RSS Feeds — Skinbase',
|
||||
'page_meta_description' => 'Subscribe to Skinbase RSS feeds to stay up to date with the latest uploads, skins, wallpapers, and photos.',
|
||||
'page_canonical' => url('/rss-feeds'),
|
||||
'hero_title' => 'RSS Feeds',
|
||||
'hero_description' => 'Subscribe to stay up to date with the latest content on Skinbase.',
|
||||
'breadcrumbs' => collect([
|
||||
(object) ['name' => 'Home', 'url' => '/'],
|
||||
(object) ['name' => 'RSS Feeds', 'url' => '/rss-feeds'],
|
||||
]),
|
||||
'feeds' => self::FEEDS,
|
||||
'feed_groups' => $this->feedGroups(),
|
||||
'center_content' => true,
|
||||
'center_max' => '3xl',
|
||||
]);
|
||||
}
|
||||
|
||||
/** /rss/latest-uploads.xml — all content types */
|
||||
public function latestUploads(): Response
|
||||
{
|
||||
$artworks = Artwork::published()
|
||||
->with(['user'])
|
||||
->latest('published_at')
|
||||
->limit(self::FEED_LIMIT)
|
||||
->get();
|
||||
|
||||
return $this->buildFeed('Latest Uploads', url('/rss/latest-uploads.xml'), $artworks);
|
||||
}
|
||||
|
||||
/** /rss/latest-skins.xml */
|
||||
public function latestSkins(): Response
|
||||
{
|
||||
return $this->feedByContentType('skins', 'Latest Skins', '/rss/latest-skins.xml');
|
||||
}
|
||||
|
||||
/** /rss/latest-wallpapers.xml */
|
||||
public function latestWallpapers(): Response
|
||||
{
|
||||
return $this->feedByContentType('wallpapers', 'Latest Wallpapers', '/rss/latest-wallpapers.xml');
|
||||
}
|
||||
|
||||
/** /rss/latest-photos.xml */
|
||||
public function latestPhotos(): Response
|
||||
{
|
||||
return $this->feedByContentType('photography', 'Latest Photos', '/rss/latest-photos.xml');
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
private function feedByContentType(string $slug, string $title, string $feedPath): Response
|
||||
{
|
||||
$contentType = $this->contentTypeResolver->resolve($slug)->contentType;
|
||||
|
||||
$query = Artwork::published()->with(['user'])->latest('published_at')->limit(self::FEED_LIMIT);
|
||||
|
||||
if ($contentType) {
|
||||
$query->whereHas('categories', fn ($q) => $q->where('content_type_id', $contentType->id));
|
||||
}
|
||||
|
||||
return $this->buildFeed($title, url($feedPath), $query->get());
|
||||
}
|
||||
|
||||
private function buildFeed(string $channelTitle, string $feedUrl, $artworks): Response
|
||||
{
|
||||
$content = view('rss.feed', [
|
||||
'channelTitle' => $channelTitle . ' — Skinbase',
|
||||
'channelDescription' => 'The latest ' . strtolower($channelTitle) . ' from Skinbase.org',
|
||||
'channelLink' => url('/'),
|
||||
'feedUrl' => $feedUrl,
|
||||
'artworks' => $artworks,
|
||||
'buildDate' => now()->toRfc2822String(),
|
||||
])->render();
|
||||
|
||||
return response($content, 200, [
|
||||
'Content-Type' => 'application/rss+xml; charset=utf-8',
|
||||
]);
|
||||
}
|
||||
|
||||
private function feedGroups(): array
|
||||
{
|
||||
$exploreFeeds = [[
|
||||
'title' => 'All Artworks',
|
||||
'url' => '/rss/explore/artworks',
|
||||
'description' => 'Latest artworks of all types.',
|
||||
]];
|
||||
|
||||
foreach ($this->contentTypeResolver->publicContentTypes() as $contentType) {
|
||||
$name = (string) $contentType->name;
|
||||
$slug = (string) $contentType->slug;
|
||||
|
||||
$exploreFeeds[] = [
|
||||
'title' => $name,
|
||||
'url' => '/rss/explore/' . $slug,
|
||||
'description' => 'Latest ' . strtolower($name) . '.',
|
||||
];
|
||||
}
|
||||
|
||||
if ($this->contentTypeResolver->publicContentTypes()->isNotEmpty()) {
|
||||
$firstType = $this->contentTypeResolver->publicContentTypes()->first();
|
||||
|
||||
$exploreFeeds[] = [
|
||||
'title' => 'Trending ' . $firstType->name,
|
||||
'url' => '/rss/explore/' . $firstType->slug . '/trending',
|
||||
'description' => 'Trending ' . strtolower((string) $firstType->name) . ' this week.',
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'global' => [
|
||||
'label' => 'Global',
|
||||
'feeds' => [
|
||||
['title' => 'Latest Artworks', 'url' => '/rss', 'description' => 'All new artworks across the platform.'],
|
||||
],
|
||||
],
|
||||
'discover' => [
|
||||
'label' => 'Discover',
|
||||
'feeds' => [
|
||||
['title' => 'Fresh Uploads', 'url' => '/rss/discover/fresh', 'description' => 'The newest artworks just published.'],
|
||||
['title' => 'Trending', 'url' => '/rss/discover/trending', 'description' => 'Most-viewed artworks over the past 7 days.'],
|
||||
['title' => 'Rising', 'url' => '/rss/discover/rising', 'description' => 'Artworks gaining momentum right now.'],
|
||||
],
|
||||
],
|
||||
'explore' => [
|
||||
'label' => 'Explore',
|
||||
'feeds' => $exploreFeeds,
|
||||
],
|
||||
'blog' => [
|
||||
'label' => 'Blog',
|
||||
'feeds' => [
|
||||
['title' => 'Blog Posts', 'url' => '/rss/blog', 'description' => 'Latest posts from the Skinbase blog.'],
|
||||
],
|
||||
],
|
||||
'legacy' => [
|
||||
'label' => 'Legacy Feeds',
|
||||
'feeds' => [
|
||||
['title' => 'Latest Uploads (XML)', 'url' => '/rss/latest-uploads.xml', 'description' => 'Legacy XML feed.'],
|
||||
['title' => 'Latest Skins (XML)', 'url' => '/rss/latest-skins.xml', 'description' => 'Legacy XML feed.'],
|
||||
['title' => 'Latest Wallpapers (XML)', 'url' => '/rss/latest-wallpapers.xml', 'description' => 'Legacy XML feed.'],
|
||||
['title' => 'Latest Photos (XML)', 'url' => '/rss/latest-photos.xml', 'description' => 'Legacy XML feed.'],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user