more fixes
This commit is contained in:
157
app/Http/Controllers/News/NewsController.php
Normal file
157
app/Http/Controllers/News/NewsController.php
Normal file
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\News;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use cPad\Plugins\News\Models\NewsArticle;
|
||||
use cPad\Plugins\News\Models\NewsCategory;
|
||||
use cPad\Plugins\News\Models\NewsTag;
|
||||
use cPad\Plugins\News\Models\NewsView;
|
||||
|
||||
class NewsController extends Controller
|
||||
{
|
||||
// -----------------------------------------------------------------------
|
||||
// Homepage — /news
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$perPage = config('news.articles_per_page', 12);
|
||||
|
||||
$featured = NewsArticle::with('author', 'category')
|
||||
->published()
|
||||
->featured()
|
||||
->orderByDesc('published_at')
|
||||
->first();
|
||||
|
||||
$query = NewsArticle::with('author', 'category')
|
||||
->published()
|
||||
->orderByDesc('published_at');
|
||||
|
||||
if ($featured) {
|
||||
$query->where('id', '!=', $featured->id);
|
||||
}
|
||||
|
||||
$articles = $query->paginate($perPage);
|
||||
$categories = NewsCategory::active()->withCount('publishedArticles')->ordered()->get();
|
||||
$trending = NewsArticle::published()
|
||||
->orderByDesc('views')
|
||||
->limit(config('news.trending_limit', 5))
|
||||
->get(['id', 'title', 'slug', 'views', 'published_at']);
|
||||
|
||||
$tags = NewsTag::has('articles')->orderBy('name')->get();
|
||||
|
||||
return view('news.index', [
|
||||
'featured' => $featured,
|
||||
'articles' => $articles,
|
||||
'categories' => $categories,
|
||||
'trending' => $trending,
|
||||
'tags' => $tags,
|
||||
]);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Category page — /news/category/{slug}
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
public function category(Request $request, string $slug)
|
||||
{
|
||||
$category = NewsCategory::where('slug', $slug)->where('is_active', true)->firstOrFail();
|
||||
$perPage = config('news.articles_per_page', 12);
|
||||
|
||||
$articles = NewsArticle::with('author', 'category')
|
||||
->published()
|
||||
->byCategory($category->id)
|
||||
->orderByDesc('published_at')
|
||||
->paginate($perPage);
|
||||
|
||||
$categories = NewsCategory::active()->withCount('publishedArticles')->ordered()->get();
|
||||
|
||||
return view('news.category', [
|
||||
'category' => $category,
|
||||
'articles' => $articles,
|
||||
'categories' => $categories,
|
||||
]);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Tag page — /news/tag/{slug}
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
public function tag(Request $request, string $slug)
|
||||
{
|
||||
$tag = NewsTag::where('slug', $slug)->firstOrFail();
|
||||
$perPage = config('news.articles_per_page', 12);
|
||||
|
||||
$articles = NewsArticle::with('author', 'category')
|
||||
->published()
|
||||
->whereHas('tags', fn ($q) => $q->where('news_tags.slug', $slug))
|
||||
->orderByDesc('published_at')
|
||||
->paginate($perPage);
|
||||
|
||||
$categories = NewsCategory::active()->withCount('publishedArticles')->ordered()->get();
|
||||
|
||||
return view('news.tag', [
|
||||
'tag' => $tag,
|
||||
'articles' => $articles,
|
||||
'categories' => $categories,
|
||||
]);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Article page — /news/{slug}
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
public function show(Request $request, string $slug)
|
||||
{
|
||||
$article = NewsArticle::with('author', 'category', 'tags')
|
||||
->published()
|
||||
->where('slug', $slug)
|
||||
->firstOrFail();
|
||||
|
||||
// Track view (once per session / IP)
|
||||
$this->trackView($request, $article);
|
||||
|
||||
// Related articles (same category, excluding current)
|
||||
$related = NewsArticle::with('author')
|
||||
->published()
|
||||
->when($article->category_id, fn ($q) => $q->where('category_id', $article->category_id))
|
||||
->where('id', '!=', $article->id)
|
||||
->orderByDesc('published_at')
|
||||
->limit(config('news.related_limit', 4))
|
||||
->get();
|
||||
|
||||
return view('news.show', [
|
||||
'article' => $article,
|
||||
'related' => $related,
|
||||
]);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Helpers
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
private function trackView(Request $request, NewsArticle $article): void
|
||||
{
|
||||
$ip = $request->ip();
|
||||
$userId = Auth::id();
|
||||
$session = 'news_view_' . $article->id;
|
||||
|
||||
if ($request->session()->has($session)) {
|
||||
return;
|
||||
}
|
||||
|
||||
NewsView::create([
|
||||
'article_id' => $article->id,
|
||||
'user_id' => $userId,
|
||||
'ip' => $ip,
|
||||
'created_at' => now(),
|
||||
]);
|
||||
|
||||
$article->incrementViews();
|
||||
|
||||
$request->session()->put($session, true);
|
||||
}
|
||||
}
|
||||
74
app/Http/Controllers/News/NewsRssController.php
Normal file
74
app/Http/Controllers/News/NewsRssController.php
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\News;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Response;
|
||||
use cPad\Plugins\News\Models\NewsArticle;
|
||||
|
||||
class NewsRssController extends Controller
|
||||
{
|
||||
/**
|
||||
* Generate RSS 2.0 feed for published news articles.
|
||||
* Endpoint: GET /rss/news
|
||||
*/
|
||||
public function feed(): Response
|
||||
{
|
||||
$articles = NewsArticle::with('author', 'category')
|
||||
->published()
|
||||
->orderByDesc('published_at')
|
||||
->limit(config('news.rss_limit', 25))
|
||||
->get();
|
||||
|
||||
$xml = $this->buildRss($articles);
|
||||
|
||||
return response($xml, 200, [
|
||||
'Content-Type' => 'application/rss+xml; charset=UTF-8',
|
||||
]);
|
||||
}
|
||||
|
||||
private function buildRss($articles): string
|
||||
{
|
||||
$siteUrl = config('app.url');
|
||||
$title = e(config('news.rss_title', 'News'));
|
||||
$description = e(config('news.rss_description', 'Latest news.'));
|
||||
$now = now()->toRfc2822String();
|
||||
|
||||
$items = '';
|
||||
foreach ($articles as $article) {
|
||||
$link = e(url('/news/' . $article->slug));
|
||||
$pubDate = $article->published_at?->toRfc2822String() ?? $now;
|
||||
$articleTitle = e($article->title);
|
||||
$excerpt = e(strip_tags((string) ($article->excerpt ?? '')));
|
||||
$category = e((string) ($article->category?->name ?? ''));
|
||||
$author = e((string) ($article->author?->name ?? ''));
|
||||
|
||||
$items .= <<<ITEM
|
||||
<item>
|
||||
<title><![CDATA[{$articleTitle}]]></title>
|
||||
<link>{$link}</link>
|
||||
<guid isPermaLink="true">{$link}</guid>
|
||||
<description><![CDATA[{$excerpt}]]></description>
|
||||
<pubDate>{$pubDate}</pubDate>
|
||||
<author>{$author}</author>
|
||||
<category>{$category}</category>
|
||||
</item>
|
||||
|
||||
ITEM;
|
||||
}
|
||||
|
||||
return <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
||||
<channel>
|
||||
<title>{$title}</title>
|
||||
<link>{$siteUrl}/news</link>
|
||||
<description>{$description}</description>
|
||||
<language>en-us</language>
|
||||
<lastBuildDate>{$now}</lastBuildDate>
|
||||
<atom:link href="{$siteUrl}/rss/news" rel="self" type="application/rss+xml"/>
|
||||
{$items} </channel>
|
||||
</rss>
|
||||
XML;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user