fixed sanitazer and academy

This commit is contained in:
2026-06-05 16:53:20 +02:00
parent 15870ddb1f
commit f89ee937c0
29 changed files with 2444 additions and 1039 deletions

View File

@@ -42,6 +42,7 @@ class RegisteredUserController extends Controller
return view('auth.register', [
'prefillEmail' => (string) $request->query('email', ''),
'page_canonical' => route('register'),
'turnstile' => [
'enabled' => $this->turnstileVerifier->isEnabled(),
'siteKey' => $this->turnstileVerifier->siteKey(),

View File

@@ -79,6 +79,7 @@ class GroupController extends Controller
{
$this->authorize('view', $group);
$section = in_array($section, ['overview', 'artworks', 'collections', 'members', 'about', 'posts', 'projects', 'releases', 'challenges', 'events', 'activity'], true) ? $section : 'overview';
$viewer = $request->user();
$group->loadMissing('owner.profile');
$members = collect($this->memberships->mapMembers($group, $viewer))
@@ -89,7 +90,8 @@ class GroupController extends Controller
return Inertia::render('Group/GroupShow', [
'group' => $groupPayload,
'section' => in_array($section, ['overview', 'artworks', 'collections', 'members', 'about', 'posts', 'projects', 'releases', 'challenges', 'events', 'activity'], true) ? $section : 'overview',
'section' => $section,
'seo' => $this->seoPayload($group, $section),
'featuredArtworks' => $this->groups->featuredArtworkCards($group),
'artworks' => $this->groups->publicArtworkCards($group),
'featuredCollections' => $this->groups->featuredCollectionCards($group, $viewer),
@@ -140,4 +142,19 @@ class GroupController extends Controller
{
return $this->show($request, $group, 'activity');
}
}
private function seoPayload(Group $group, string $section): array
{
$canonical = $section === 'overview'
? route('groups.show', ['group' => $group])
: route('groups.section', ['group' => $group, 'section' => $section]);
$sectionLabel = $section === 'overview' ? '' : ' '.ucfirst($section);
return [
'title' => trim($group->name.$sectionLabel.' - Skinbase'),
'description' => $group->headline ?: $group->bio ?: 'Skinbase group',
'canonical' => $canonical,
'og_url' => $canonical,
];
}
}

View File

@@ -767,6 +767,17 @@ final class AcademyAdminController extends Controller
];
}
if ($resource === 'challenges') {
return [
'links' => array_filter([
'preview' => $record->exists ? route('academy.challenges.show', ['slug' => $record->slug]) : null,
]),
'coverUploadUrl' => route('api.studio.academy.lessons.media.upload'),
'coverDeleteUrl' => route('api.studio.academy.lessons.media.destroy'),
'coverCdnBaseUrl' => rtrim((string) config('cdn.files_url', 'https://files.skinbase.org'), '/'),
];
}
if ($resource !== 'lessons') {
return [];
}
@@ -1200,6 +1211,7 @@ final class AcademyAdminController extends Controller
'voting_starts_at' => optional($record->voting_starts_at)?->format('Y-m-d\TH:i'),
'voting_ends_at' => optional($record->voting_ends_at)?->format('Y-m-d\TH:i'),
'cover_image' => (string) ($record->cover_image ?? ''),
'cover_image_url' => $this->resolveLessonCoverImageUrl((string) ($record->cover_image ?? '')),
'prize_text' => (string) ($record->prize_text ?? ''),
'required_tags' => implode(', ', (array) ($record->required_tags ?? [])),
'allowed_categories' => implode(', ', (array) ($record->allowed_categories ?? [])),

View File

@@ -5,7 +5,9 @@ declare(strict_types=1);
namespace App\Http\Controllers\Studio;
use App\Http\Controllers\Controller;
use App\Models\User;
use App\Services\News\NewsService;
use App\Support\AvatarUrl;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
@@ -46,6 +48,8 @@ final class StudioNewsController extends Controller
{
$this->authorizeNews($request);
$user = $request->user();
return Inertia::render('Studio/StudioNewsEditor', [
'title' => 'Create article',
'description' => 'Draft a new News story with editorial workflow, SEO metadata, and related entity links.',
@@ -61,11 +65,14 @@ final class StudioNewsController extends Controller
'storeUrl' => route('studio.news.store'),
'coverUploadUrl' => route('api.studio.news.media.upload'),
'coverDeleteUrl' => route('api.studio.news.media.destroy'),
'bodyMediaUploadUrl' => route('api.studio.news.media.upload'),
'bodyMediaDeleteUrl' => route('api.studio.news.media.destroy'),
'coverCdnBaseUrl' => rtrim((string) config('cdn.files_url', 'https://files.skinbase.org'), '/'),
'entitySearchUrl' => route('studio.news.entity-search'),
'categoriesUrl' => route('studio.news.categories'),
'tagsUrl' => route('studio.news.tags'),
'defaultAuthor' => $this->news->searchEntities('user', (string) $request->user()->username)[0] ?? null,
'defaultAuthor' => $this->mapDefaultAuthor($user),
'defaultPublishedAt' => now()->format('Y-m-d\TH:i'),
]);
}
@@ -96,6 +103,8 @@ final class StudioNewsController extends Controller
'relationTypeOptions' => $this->news->relationTypeOptions(),
'coverUploadUrl' => route('api.studio.news.media.upload'),
'coverDeleteUrl' => route('api.studio.news.media.destroy'),
'bodyMediaUploadUrl' => route('api.studio.news.media.upload'),
'bodyMediaDeleteUrl' => route('api.studio.news.media.destroy'),
'coverCdnBaseUrl' => rtrim((string) config('cdn.files_url', 'https://files.skinbase.org'), '/'),
'updateUrl' => route('studio.news.update', ['article' => $article->id]),
'destroyUrl' => route('studio.news.destroy', ['article' => $article->id]),
@@ -250,6 +259,29 @@ final class StudioNewsController extends Controller
]);
}
private function mapDefaultAuthor(mixed $user): ?array
{
if (! $user instanceof User) {
return null;
}
$user->loadMissing('profile');
return [
'id' => (int) $user->id,
'entity_type' => 'user',
'entity_label' => 'User',
'title' => (string) ($user->name ?: $user->username),
'subtitle' => $user->username ? '@' . $user->username : null,
'description' => Str::limit(trim((string) ($user->profile?->bio ?? '')), 120),
'url' => $user->username ? route('profile.show', ['username' => $user->username]) : null,
'image' => null,
'avatar' => AvatarUrl::forUser((int) $user->id, $user->profile?->avatar_hash ?? null, 96),
'context_label' => 'Profile',
'meta' => [],
];
}
public function storeCategory(Request $request): RedirectResponse
{
$this->authorizeNews($request);

View File

@@ -50,7 +50,8 @@ class TopAuthorsController extends Controller
});
$page_title = 'Top Creators';
$page_canonical = route('creators.top');
return view('web.authors.top', compact('page_title', 'authors', 'metric'));
return view('web.authors.top', compact('page_title', 'page_canonical', 'authors', 'metric'));
}
}

View File

@@ -65,6 +65,7 @@ final class DiscoverController extends Controller
return view('web.discover.index', [
'artworks' => $results,
'page_title' => 'Trending Artworks',
'page_canonical' => $this->canonicalRoute('discover.trending'),
'section' => 'trending',
'description' => 'The most-viewed artworks on Skinbase over the past 7 days.',
'icon' => 'fa-fire',
@@ -97,6 +98,7 @@ final class DiscoverController extends Controller
return view('web.discover.index', [
'artworks' => $results,
'page_title' => 'Rising Now',
'page_canonical' => $this->canonicalRoute('discover.rising'),
'section' => 'rising',
'description' => 'Fastest growing artworks right now.',
'icon' => 'fa-rocket',
@@ -119,6 +121,7 @@ final class DiscoverController extends Controller
return view('web.discover.index', [
'artworks' => $results,
'page_title' => 'Fresh Uploads',
'page_canonical' => $this->canonicalRoute('discover.fresh'),
'section' => 'fresh',
'description' => 'The latest artworks just uploaded to Skinbase.',
'icon' => 'fa-bolt',
@@ -138,6 +141,7 @@ final class DiscoverController extends Controller
return view('web.discover.index', [
'artworks' => $results,
'page_title' => 'Top Rated Artworks',
'page_canonical' => $this->canonicalRoute('discover.top-rated'),
'section' => 'top-rated',
'description' => 'The most-loved artworks on Skinbase, ranked by community favourites.',
'icon' => 'fa-medal',
@@ -157,6 +161,7 @@ final class DiscoverController extends Controller
return view('web.discover.index', [
'artworks' => $results,
'page_title' => 'Most Downloaded',
'page_canonical' => $this->canonicalRoute('discover.most-downloaded'),
'section' => 'most-downloaded',
'description' => 'All-time most downloaded artworks on Skinbase.',
'icon' => 'fa-download',
@@ -178,9 +183,9 @@ final class DiscoverController extends Controller
'categories:id,name,slug,content_type_id,parent_id,sort_order',
'categories.contentType:id,slug,name',
])
->whereRaw('MONTH(published_at) = ?', [$today->month])
->whereRaw('DAY(published_at) = ?', [$today->day])
->whereRaw('YEAR(published_at) < ?', [$today->year])
->whereMonth('published_at', $today->month)
->whereDay('published_at', $today->day)
->whereYear('published_at', '<', $today->year)
->orderMissingThumbnailsLast()
->orderByDesc('published_at')
->paginate($perPage)
@@ -191,6 +196,7 @@ final class DiscoverController extends Controller
return view('web.discover.index', [
'artworks' => $artworks,
'page_title' => 'On This Day',
'page_canonical' => $this->canonicalRoute('discover.on-this-day'),
'section' => 'on-this-day',
'description' => 'Artworks published on ' . $today->format('F j') . ' in previous years.',
'icon' => 'fa-calendar-day',
@@ -246,6 +252,7 @@ final class DiscoverController extends Controller
return view('web.creators.rising', [
'creators' => $creators,
'page_title' => 'Rising Creators — Skinbase',
'page_canonical' => $this->canonicalRoute('creators.rising'),
]);
}
@@ -327,6 +334,7 @@ final class DiscoverController extends Controller
return view('web.discover.index', [
'artworks' => collect(),
'page_title' => 'Following Feed',
'page_canonical' => $this->canonicalRoute('discover.following'),
'section' => 'following',
'description' => 'Follow some creators to see their work here.',
'icon' => 'fa-user-group',
@@ -366,6 +374,7 @@ final class DiscoverController extends Controller
return view('web.discover.index', [
'artworks' => $artworks,
'page_title' => 'Following Feed',
'page_canonical' => $this->canonicalRoute('discover.following'),
'section' => 'following',
'description' => 'The latest artworks from creators you follow.',
'icon' => 'fa-user-group',
@@ -388,6 +397,11 @@ final class DiscoverController extends Controller
return ! $items || $items->isEmpty();
}
private function canonicalRoute(string $routeName): string
{
return route($routeName);
}
private function paginatorHasNoRisingMomentum($paginator): bool
{
if (! is_object($paginator) || ! method_exists($paginator, 'getCollection')) {