Repair: copy legacy joinDate into new user's created_at when creating users from legacy wallz

This commit is contained in:
2026-03-22 09:13:39 +01:00
parent e8b5edf5d2
commit 2608be7420
80 changed files with 3991 additions and 723 deletions

View File

@@ -49,6 +49,18 @@ use Inertia\Inertia;
class ProfileController extends Controller
{
private const PROFILE_TABS = [
'posts',
'artworks',
'stories',
'achievements',
'collections',
'about',
'stats',
'favourites',
'activity',
];
public function __construct(
private readonly ArtworkService $artworkService,
private readonly UsernameApprovalService $usernameApprovalService,
@@ -84,7 +96,12 @@ class ProfileController extends Controller
return redirect()->route('profile.show', ['username' => strtolower((string) $user->username)], 301);
}
return $this->renderProfilePage($request, $user);
$tab = $this->normalizeProfileTab($request->query('tab'));
if ($tab !== null) {
return $this->redirectToProfileTab($request, (string) $user->username, $tab);
}
return $this->renderProfilePage($request, $user, 'Profile/ProfileShow', false, 'posts');
}
public function showGalleryByUsername(Request $request, string $username)
@@ -111,6 +128,45 @@ class ProfileController extends Controller
return $this->renderProfilePage($request, $user, 'Profile/ProfileGallery', true);
}
public function showTabByUsername(Request $request, string $username, string $tab)
{
$normalized = UsernamePolicy::normalize($username);
$user = User::query()->whereRaw('LOWER(username) = ?', [$normalized])->first();
$normalizedTab = $this->normalizeProfileTab($tab);
if ($normalizedTab === null) {
abort(404);
}
if (! $user) {
$redirect = DB::table('username_redirects')
->whereRaw('LOWER(old_username) = ?', [$normalized])
->value('new_username');
if ($redirect) {
return redirect()->route('profile.tab', [
'username' => strtolower((string) $redirect),
'tab' => $normalizedTab,
], 301);
}
abort(404);
}
if ($username !== strtolower((string) $user->username)) {
return redirect()->route('profile.tab', [
'username' => strtolower((string) $user->username),
'tab' => $normalizedTab,
], 301);
}
if ($request->query->has('tab')) {
return $this->redirectToProfileTab($request, (string) $user->username, $normalizedTab);
}
return $this->renderProfilePage($request, $user, 'Profile/ProfileShow', false, $normalizedTab);
}
public function legacyById(Request $request, int $id, ?string $username = null)
{
$user = User::query()->findOrFail($id);
@@ -836,7 +892,13 @@ class ProfileController extends Controller
return Redirect::route('dashboard.profile')->with('status', 'password-updated');
}
private function renderProfilePage(Request $request, User $user, string $component = 'Profile/ProfileShow', bool $galleryOnly = false)
private function renderProfilePage(
Request $request,
User $user,
string $component = 'Profile/ProfileShow',
bool $galleryOnly = false,
?string $initialTab = null,
)
{
$isOwner = Auth::check() && Auth::id() === $user->id;
$viewer = Auth::user();
@@ -1088,8 +1150,19 @@ class ProfileController extends Controller
$usernameSlug = strtolower((string) ($user->username ?? ''));
$canonical = url('/@' . $usernameSlug);
$galleryUrl = url('/@' . $usernameSlug . '/gallery');
$profileTabUrls = collect(self::PROFILE_TABS)
->mapWithKeys(fn (string $tab) => [$tab => url('/@' . $usernameSlug . '/' . $tab)])
->all();
$achievementSummary = $this->achievements->summary((int) $user->id);
$leaderboardRank = $this->leaderboards->creatorRankSummary((int) $user->id);
$resolvedInitialTab = $this->normalizeProfileTab($initialTab);
$isTabLanding = ! $galleryOnly && $resolvedInitialTab !== null;
$activeProfileUrl = $resolvedInitialTab !== null
? ($profileTabUrls[$resolvedInitialTab] ?? $canonical)
: $canonical;
$tabMetaLabel = $resolvedInitialTab !== null
? ucfirst($resolvedInitialTab)
: null;
return Inertia::render($component, [
'user' => [
@@ -1133,20 +1206,51 @@ class ProfileController extends Controller
'countryName' => $countryName,
'isOwner' => $isOwner,
'auth' => $authData,
'initialTab' => $resolvedInitialTab,
'profileUrl' => $canonical,
'galleryUrl' => $galleryUrl,
'profileTabUrls' => $profileTabUrls,
])->withViewData([
'page_title' => $galleryOnly
? (($user->username ?? $user->name ?? 'User') . ' Gallery on Skinbase')
: (($user->username ?? $user->name ?? 'User') . ' on Skinbase'),
'page_canonical' => $galleryOnly ? $galleryUrl : $canonical,
: ($isTabLanding
? (($user->username ?? $user->name ?? 'User') . ' ' . $tabMetaLabel . ' on Skinbase')
: (($user->username ?? $user->name ?? 'User') . ' on Skinbase')),
'page_canonical' => $galleryOnly ? $galleryUrl : $activeProfileUrl,
'page_meta_description' => $galleryOnly
? ('Browse the public gallery of ' . ($user->username ?? $user->name) . ' on Skinbase.')
: ('View the profile of ' . ($user->username ?? $user->name) . ' on Skinbase.org — artworks, favourites and more.'),
: ($isTabLanding
? ('Explore the ' . strtolower((string) $tabMetaLabel) . ' section for ' . ($user->username ?? $user->name) . ' on Skinbase.')
: ('View the profile of ' . ($user->username ?? $user->name) . ' on Skinbase.org — artworks, favourites and more.')),
'og_image' => $avatarUrl,
]);
}
private function normalizeProfileTab(mixed $tab): ?string
{
if (! is_string($tab)) {
return null;
}
$normalized = strtolower(trim($tab));
return in_array($normalized, self::PROFILE_TABS, true) ? $normalized : null;
}
private function redirectToProfileTab(Request $request, string $username, string $tab): RedirectResponse
{
$baseUrl = url('/@' . strtolower($username) . '/' . $tab);
$query = $request->query();
unset($query['tab']);
if ($query !== []) {
$baseUrl .= '?' . http_build_query($query);
}
return redirect()->to($baseUrl, 301);
}
private function resolveFavouriteTable(): ?string
{
foreach (['artwork_favourites', 'user_favorites', 'artworks_favourites', 'favourites'] as $table) {
@@ -1164,6 +1268,9 @@ class ProfileController extends Controller
private function mapArtworkCardPayload(Artwork $art): array
{
$present = ThumbnailPresenter::present($art, 'md');
$category = $art->categories->first();
$contentType = $category?->contentType;
$stats = $art->stats;
return [
'id' => $art->id,
@@ -1178,6 +1285,13 @@ class ProfileController extends Controller
'user_id' => $art->user_id,
'author_level' => (int) ($art->user?->level ?? 1),
'author_rank' => (string) ($art->user?->rank ?? 'Newbie'),
'content_type' => $contentType?->name,
'content_type_slug' => $contentType?->slug,
'category' => $category?->name,
'category_slug' => $category?->slug,
'views' => (int) ($stats?->views ?? $art->view_count ?? 0),
'downloads' => (int) ($stats?->downloads ?? 0),
'likes' => (int) ($stats?->favorites ?? $art->favourite_count ?? 0),
'width' => $art->width,
'height' => $art->height,
];