prepared and gallery fixes

This commit is contained in:
2026-02-19 08:36:32 +01:00
parent 8935065af1
commit c30fa5a392
36 changed files with 1437 additions and 104 deletions

View File

@@ -1,13 +1,12 @@
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\CategoryPageController;
use App\Http\Controllers\Web\BrowseGalleryController;
use App\Http\Controllers\Controller;
use App\Http\Requests\ArtworkIndexRequest;
use App\Models\Artwork;
use App\Models\Category;
use App\Services\Recommendations\SimilarArtworksService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
@@ -71,15 +70,27 @@ class ArtworkController extends Controller
$foundArtwork = Artwork::where('slug', $artworkSlug)->first();
}
// When the URL can represent a nested category path (e.g. /skins/audio/winamp),
// prefer category rendering over artwork slug collisions so same-level groups
// behave consistently.
if (! empty($artworkSlug)) {
$combinedPath = trim($categoryPath . '/' . $artworkSlug, '/');
$resolvedCategory = Category::findByPath($contentTypeSlug, $combinedPath);
if ($resolvedCategory) {
return app(BrowseGalleryController::class)->content(request(), $contentTypeSlug, $combinedPath);
}
}
// If no artwork was found, treat the request as a category path.
// The route places the artwork slug in the last segment, so include it
// when forwarding to CategoryPageController to support arbitrary-depth paths
// The route places the artwork slug in the last segment, so include it.
// Delegate to BrowseGalleryController to render the same modern gallery
// layout used by routes like /skins/audio.
if (! $foundArtwork) {
$combinedPath = $categoryPath;
if ($artworkSlug) {
$combinedPath = trim($categoryPath . '/' . $artworkSlug, '/');
}
return app(CategoryPageController::class)->show(request(), $contentTypeSlug, $combinedPath);
return app(BrowseGalleryController::class)->content(request(), $contentTypeSlug, $combinedPath);
}
if (! $foundArtwork->is_public || ! $foundArtwork->is_approved || $foundArtwork->trashed()) {

View File

@@ -41,4 +41,40 @@ class ChatController extends Controller
return view('community.chat', compact('page_title', 'adHtml', 'chatHtml', 'smileys'));
}
/**
* Handle legacy AJAX chat posts from old JS.
*/
public function post(Request $request)
{
$message = $request->input('message') ?? $request->input('chat_txt') ?? null;
if (empty($message)) {
return response()->json(['ok' => false, 'error' => 'empty_message'], 400);
}
// Ensure legacy $_SESSION keys exist for Chat class (best-effort sync from Laravel session/auth)
if (empty($_SESSION['web_login']['user_id'])) {
$webLogin = session('web_login');
if ($webLogin && isset($webLogin['user_id'])) {
$_SESSION['web_login'] = $webLogin;
} elseif (auth()->check()) {
$user = auth()->user();
$_SESSION['web_login'] = [
'user_id' => $user->id,
'username' => $user->username ?? $user->name ?? null,
'status' => true,
];
}
}
$chat = new \App\Chat();
try {
$chat->StoreMessage($message);
$chat->UpdateChatFile('cron/chat_log.txt', 50);
} catch (\Throwable $e) {
return response()->json(['ok' => false, 'error' => 'store_failed', 'message' => $e->getMessage()], 500);
}
return response()->json(['ok' => true]);
}
}

View File

@@ -18,13 +18,76 @@ class ForumController extends Controller
public function index()
{
$data = $this->legacy->forumIndex();
if (empty($data['topics']) || count($data['topics']) === 0) {
try {
$categories = \App\Models\ForumCategory::query()
->withCount(['threads as num_subtopics'])
->orderBy('position')
->orderBy('id')
->get();
$topics = $categories->map(function ($category) {
$threadIds = \App\Models\ForumThread::where('category_id', $category->id)->pluck('id');
return (object) [
'topic_id' => $category->id,
'topic' => $category->name,
'discuss' => null,
'last_update' => \App\Models\ForumThread::where('category_id', $category->id)->max('last_post_at'),
'num_posts' => $threadIds->isEmpty() ? 0 : \App\Models\ForumPost::whereIn('thread_id', $threadIds)->count(),
'num_subtopics' => (int) ($category->num_subtopics ?? 0),
];
});
$data['topics'] = $topics;
} catch (\Throwable $e) {
// keep legacy response
}
}
return view('community.forum.index', $data);
}
public function topic(Request $request, $topic_id)
public function topic(Request $request, $topic_id, $slug = null)
{
// Redirect to canonical slug when possible
try {
$thread = \App\Models\ForumThread::find((int) $topic_id);
if ($thread && !empty($thread->slug)) {
$correct = $thread->slug;
if ($slug !== $correct) {
$qs = $request->getQueryString();
$url = route('legacy.forum.topic', ['topic_id' => $topic_id, 'slug' => $correct]);
if ($qs) $url .= '?' . $qs;
return redirect($url, 301);
}
}
} catch (\Throwable $e) {
// ignore
}
$data = $this->legacy->forumTopic((int) $topic_id, (int) $request->query('page', 1));
if (! $data) {
// fallback to new forum tables if migration already ran
try {
$thread = \App\Models\ForumThread::with(['posts.user'])->find((int) $topic_id);
if ($thread) {
$posts = \App\Models\ForumPost::where('thread_id', $thread->id)->orderBy('created_at')->get();
$data = [
'type' => 'posts',
'thread' => $thread,
'posts' => $posts,
'page_title' => $thread->title ?? 'Forum',
];
}
} catch (\Throwable $e) {
// ignore and fall through to placeholder
}
}
if (! $data) {
return view('shared.placeholder');
}

View File

@@ -26,6 +26,19 @@ class NewsController extends Controller
return redirect('/');
}
// redirect to canonical slug for SEO if available
try {
$correct = \Illuminate\Support\Str::slug($news->headline ?? 'news-' . $id);
if ($slug !== $correct) {
$qs = $request->getQueryString();
$url = route('legacy.news.show', ['id' => $id, 'slug' => $correct]);
if ($qs) $url .= '?' . $qs;
return redirect($url, 301);
}
} catch (\Throwable $e) {
// ignore
}
try {
$comments = DB::table('news_comment as c')
->leftJoin('users as u', 'c.user_id', '=', 'u.user_id')

View File

@@ -18,6 +18,30 @@ class ArtController extends Controller
public function show(Request $request, $id, $slug = null)
{
// canonicalize to new artwork route when possible
try {
$art = \App\Models\Artwork::find((int)$id);
if ($art && !empty($art->slug)) {
if ($slug !== $art->slug) {
// attempt to derive contentType and category for route
$category = $art->categories()->with('contentType')->first();
if ($category && $category->contentType) {
$contentTypeSlug = $category->contentType->slug ?? 'other';
$categoryPath = $category->slug ?? $category->category_name ?? 'other';
return redirect(route('artworks.show', [
'contentTypeSlug' => $contentTypeSlug,
'categoryPath' => $categoryPath,
'artwork' => $art->slug,
]), 301);
} elseif (!empty($art->slug)) {
// fallback: redirect to artwork slug only (may be handled by router)
return redirect('/' . $art->slug, 301);
}
}
}
} catch (\Throwable $e) {
// ignore and continue rendering legacy view
}
if ($request->isMethod('post') && $request->input('action') === 'store_comment') {
if (auth()->check()) {
try {

View File

@@ -4,10 +4,10 @@ namespace App\Http\Controllers\Web;
use App\Models\Category;
use App\Models\ContentType;
use App\Models\Artwork;
use App\Services\ArtworkService;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use App\Http\Controllers\ArtworkController as ArtworkControllerAlias;
class BrowseGalleryController extends \App\Http\Controllers\Controller
{
@@ -120,13 +120,32 @@ class BrowseGalleryController extends \App\Http\Controllers\Controller
]);
}
public function showArtwork(Request $request, string $contentTypeSlug, string $categoryPath, string $artwork)
public function showArtwork(...$params)
{
return app(\App\Http\Controllers\ArtController::class)->show(
$request,
strtolower($contentTypeSlug),
trim($categoryPath, '/'),
$artwork
$req = request();
$pathSegments = array_values(array_filter(explode('/', trim($req->path(), '/'))));
$contentTypeSlug = $params[0] ?? ($pathSegments[0] ?? null);
$categoryPath = $params[1] ?? null;
$artwork = $params[2] ?? null;
// If artwork wasn't provided (some route invocations supply fewer args),
// derive it from the request path's last segment.
if ($artwork === null) {
$artwork = end($pathSegments) ?: null;
}
$contentTypeSlug = strtolower((string) $contentTypeSlug);
$categoryPath = $categoryPath !== null ? trim((string) $categoryPath, '/') : (isset($pathSegments[1]) ? implode('/', array_slice($pathSegments, 1, max(0, count($pathSegments) - 2))) : '');
// Normalize artwork param if route-model binding returned an Artwork model
$artworkSlug = $artwork instanceof Artwork ? (string) $artwork->slug : (string) $artwork;
return app(\App\Http\Controllers\ArtworkController::class)->show(
$req,
$contentTypeSlug,
$categoryPath,
$artworkSlug
);
}

View File

@@ -17,6 +17,19 @@ class GalleryController extends Controller
abort(404);
}
// canonicalize username in URL when possible
try {
$correctName = $user->name ?? $user->uname ?? null;
if ($username && $correctName && $username !== $correctName) {
$qs = $request->getQueryString();
$url = route('legacy.gallery', ['id' => $user->id, 'username' => $correctName]);
if ($qs) $url .= '?' . $qs;
return redirect($url, 301);
}
} catch (\Throwable $e) {
// ignore
}
$page = max(1, (int) $request->query('page', 1));
$hits = 20;

View File

@@ -6,6 +6,8 @@ use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Services\ArtworkService;
use Illuminate\Support\Facades\DB;
use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\Log;
class HomeController extends Controller
{
@@ -36,34 +38,49 @@ class HomeController extends Controller
$latestUploads = $this->artworks->getLatestArtworks(20);
// Forum news (root forum section id 2876)
$forumNews = DB::table('forum_topics as t1')
->leftJoin('users as u', 't1.user_id', '=', 'u.user_id')
->select('t1.topic_id', 't1.topic', 'u.uname', 't1.post_date', 't1.preview')
->where('t1.root_id', 2876)
->where('t1.privilege', '<', 4)
->orderBy('t1.post_date', 'desc')
->limit(8)
->get();
try {
$forumNews = DB::table('forum_topics as t1')
->leftJoin('users as u', 't1.user_id', '=', 'u.user_id')
->select('t1.topic_id', 't1.topic', 'u.uname', 't1.post_date', 't1.preview')
->where('t1.root_id', 2876)
->where('t1.privilege', '<', 4)
->orderBy('t1.post_date', 'desc')
->limit(8)
->get();
} catch (QueryException $e) {
Log::warning('Forum topics table missing or DB error when loading forum news', ['exception' => $e->getMessage()]);
$forumNews = collect();
}
// Our news (latest site news)
$ourNews = DB::table('news as t1')
->join('news_categories as c', 't1.category_id', '=', 'c.category_id')
->join('users as u', 't1.user_id', '=', 'u.user_id')
->selectRaw('t1.news_id, t1.headline, t1.user_id, t1.picture, t1.preview, u.uname, t1.create_date, t1.views, c.category_name, (SELECT COUNT(*) FROM news_comments WHERE news_id = t1.news_id) AS num_comments')
->orderBy('t1.create_date', 'desc')
->limit(5)
->get();
try {
$ourNews = DB::table('news as t1')
->join('news_categories as c', 't1.category_id', '=', 'c.category_id')
->join('users as u', 't1.user_id', '=', 'u.user_id')
->selectRaw('t1.news_id, t1.headline, t1.user_id, t1.picture, t1.preview, u.uname, t1.create_date, t1.views, c.category_name, (SELECT COUNT(*) FROM news_comments WHERE news_id = t1.news_id) AS num_comments')
->orderBy('t1.create_date', 'desc')
->limit(5)
->get();
} catch (QueryException $e) {
Log::warning('News table missing or DB error when loading our news', ['exception' => $e->getMessage()]);
$ourNews = collect();
}
// Latest forum activity (exclude rootless and news root)
$latestForumActivity = DB::table('forum_topics as t1')
->selectRaw('t1.topic_id, t1.topic, (SELECT COUNT(*) FROM forum_posts WHERE topic_id = t1.topic_id) AS numPosts')
->where('t1.root_id', '<>', 0)
->where('t1.root_id', '<>', 2876)
->where('t1.privilege', '<', 4)
->orderBy('t1.last_update', 'desc')
->orderBy('t1.post_date', 'desc')
->limit(10)
->get();
try {
$latestForumActivity = DB::table('forum_topics as t1')
->selectRaw('t1.topic_id, t1.topic, (SELECT COUNT(*) FROM forum_posts WHERE topic_id = t1.topic_id) AS numPosts')
->where('t1.root_id', '<>', 0)
->where('t1.root_id', '<>', 2876)
->where('t1.privilege', '<', 4)
->orderBy('t1.last_update', 'desc')
->orderBy('t1.post_date', 'desc')
->limit(10)
->get();
} catch (QueryException $e) {
Log::warning('Forum topics table missing or DB error when loading latest forum activity', ['exception' => $e->getMessage()]);
$latestForumActivity = collect();
}
return view('web.home', compact(
'page_title',