Skip to content

Commit

Permalink
Merge branch 'master' into modern-hubs-available
Browse files Browse the repository at this point in the history
  • Loading branch information
wescopeland authored Jan 26, 2025
2 parents 89f362b + 40a70de commit 5845f77
Show file tree
Hide file tree
Showing 217 changed files with 6,399 additions and 1,522 deletions.
28 changes: 28 additions & 0 deletions app/Community/Actions/ApproveNewDisplayNameAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

namespace App\Community\Actions;

use App\Models\User;
use App\Models\UserUsername;

class ApproveNewDisplayNameAction
{
public function execute(User $user, UserUsername $changeRequest): void
{
// Automatically mark conflicting requests as denied.
UserUsername::where('username', $changeRequest->username)
->where('id', '!=', $changeRequest->id)
->whereNull('approved_at')
->whereNull('denied_at')
->update(['denied_at' => now()]);

$changeRequest->update(['approved_at' => now()]);

$user->display_name = $changeRequest->username;
$user->save();

sendDisplayNameChangeConfirmationEmail($user, $changeRequest->username);
}
}
20 changes: 20 additions & 0 deletions app/Community/Actions/FetchDynamicShortcodeContentAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@
use App\Data\UserData;
use App\Models\Achievement;
use App\Models\Game;
use App\Models\GameSet;
use App\Models\Ticket;
use App\Models\User;
use App\Platform\Data\AchievementData;
use App\Platform\Data\GameData;
use App\Platform\Data\GameSetData;
use App\Platform\Data\TicketData;
use App\Platform\Enums\GameSetType;
use Illuminate\Support\Collection;

class FetchDynamicShortcodeContentAction
Expand All @@ -21,12 +24,14 @@ public function execute(
array $ticketIds = [],
array $achievementIds = [],
array $gameIds = [],
array $hubIds = [],
): array {
$results = collect([
'users' => $this->fetchUsers($usernames),
'tickets' => $this->fetchTickets($ticketIds),
'achievements' => $this->fetchAchievements($achievementIds),
'games' => $this->fetchGames($gameIds),
'hubs' => $this->fetchHubs($hubIds),
]);

return $results->toArray();
Expand Down Expand Up @@ -97,4 +102,19 @@ private function fetchGames(array $gameIds): Collection
->get()
->map(fn (Game $game) => GameData::fromGame($game)->include('badgeUrl', 'system.name'));
}

/**
* @return Collection<int, GameSetData>
*/
private function fetchHubs(array $hubIds): Collection
{
if (empty($hubIds)) {
return collect();
}

return GameSet::whereIn('id', $hubIds)
->where('type', GameSetType::Hub)
->get()
->map(fn (GameSet $gameSet) => GameSetData::fromGameSetWithCounts($gameSet)->include('gameId'));
}
}
3 changes: 3 additions & 0 deletions app/Community/AppServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace App\Community;

use App\Community\Commands\ConvertGameShortcodesToHubs;
use App\Community\Commands\GenerateAnnualRecap;
use App\Community\Commands\SyncComments;
use App\Community\Commands\SyncForumCategories;
Expand Down Expand Up @@ -47,6 +48,8 @@ public function boot(): void
{
if ($this->app->runningInConsole()) {
$this->commands([
ConvertGameShortcodesToHubs::class,

SyncComments::class,
SyncForumCategories::class,
SyncForums::class,
Expand Down
259 changes: 259 additions & 0 deletions app/Community/Commands/ConvertGameShortcodesToHubs.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
<?php

declare(strict_types=1);

namespace App\Community\Commands;

use App\Models\ForumTopicComment;
use App\Models\Game;
use App\Models\GameSet;
use App\Models\Message;
use App\Platform\Enums\GameSetType;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;

class ConvertGameShortcodesToHubs extends Command
{
protected $signature = 'ra:community:migrate-game-shortcodes {--undo}';

protected $description = 'Migrate all [game=id] shortcodes for legacy hubs to [hub=id]';

public function handle(): void
{
if ($this->option('undo')) {
$this->info("\nUndoing the migration of [hub=id] shortcodes back to [game=id].");

$this->undoForumMigration();
$this->undoMessagesMigration();
} else {
$this->info("\nStarting the migration of legacy hub [game=id] shortcodes to [hub=id].");

$this->migrateForumShortcodes();
$this->migrateMessageShortcodes();
}
}

private function migrateForumShortcodes(): void
{
// Get the total count of comments that need to be processed.
$totalComments = ForumTopicComment::where('body', 'like', '%[game=%')->count();

$progressBar = $this->output->createProgressBar($totalComments);
ForumTopicComment::where('body', 'like', '%[game=%')->chunkById(1000, function ($forumTopicComments) use ($progressBar) {
// Collect all game IDs to fetch hub mappings in bulk.
$gameIds = [];

/** @var ForumTopicComment $forumTopicComment */
foreach ($forumTopicComments as $forumTopicComment) {
preg_match_all('/\[game=(\d+)\]/', $forumTopicComment->body, $matches);
$gameIds = array_merge($gameIds, $matches[1]);
}

// Remove duplicates and fetch games that are legacy hubs.
$gameIds = array_unique($gameIds);
$legacyHubs = Game::whereIn('ID', $gameIds)
->where('ConsoleID', 100)
->get()
->keyBy('ID');

// Fetch corresponding hub IDs for these legacy games.
$hubMappings = GameSet::where('type', GameSetType::Hub)
->whereIn('game_id', $legacyHubs->pluck('ID'))
->get()
->keyBy('game_id');

// Process each comment.
/** @var ForumTopicComment $forumTopicComment */
foreach ($forumTopicComments as $forumTopicComment) {
$originalPayload = $forumTopicComment->body;
$updatedPayload = preg_replace_callback('/\[game=(\d+)\]/', function ($matches) use ($legacyHubs, $hubMappings) {
$gameId = (int) $matches[1];

// Only replace if it's a legacy hub and we have a mapping.
if ($legacyHubs->has($gameId) && $hubMappings->has($gameId)) {
return "[hub={$hubMappings->get($gameId)->id}]";
}

return $matches[0];
}, $forumTopicComment->body);

// Update the comment in the DB only if it has actually changed.
// Use `DB` so we don't change the `updated_at` value.
if ($originalPayload !== $updatedPayload) {
DB::table('forum_topic_comments')
->where('id', $forumTopicComment->id)
->update([
'body' => $updatedPayload,
'updated_at' => DB::raw('updated_at'), // don't change the value
]);
}
}

$progressBar->advance(count($forumTopicComments));
});
$progressBar->finish();

$this->info("\nForumTopicComments migration completed successfully.");
}

private function migrateMessageShortcodes(): void
{
// Get the total count of messages that need to be processed.
$totalMessages = Message::where('body', 'like', '%[game=%')->count();

$progressBar = $this->output->createProgressBar($totalMessages);
Message::where('body', 'like', '%[game=%')->chunkById(1000, function ($messages) use ($progressBar) {
// Collect all game IDs to fetch hub mappings in bulk.
$gameIds = [];

/** @var Message $message */
foreach ($messages as $message) {
preg_match_all('/\[game=(\d+)\]/', $message->body, $matches);
$gameIds = array_merge($gameIds, $matches[1]);
}

// Remove duplicates and fetch games that are legacy hubs.
$gameIds = array_unique($gameIds);
$legacyHubs = Game::whereIn('ID', $gameIds)
->where('ConsoleID', 100)
->get()
->keyBy('ID');

// Fetch corresponding hub IDs for these legacy games.
$hubMappings = GameSet::where('type', GameSetType::Hub)
->whereIn('game_id', $legacyHubs->pluck('ID'))
->get()
->keyBy('game_id');

// Process each message.
/** @var Message $message */
foreach ($messages as $message) {
$originalBody = $message->body;
$updatedBody = preg_replace_callback('/\[game=(\d+)\]/', function ($matches) use ($legacyHubs, $hubMappings) {
$gameId = (int) $matches[1];

// Only replace if it's a legacy hub and we have a mapping.
if ($legacyHubs->has($gameId) && $hubMappings->has($gameId)) {
return "[hub={$hubMappings->get($gameId)->id}]";
}

return $matches[0];
}, $message->body);

// Update the message in the DB only if it has actually changed.
// Use `DB` so we don't change the `updated_at` value.
if ($originalBody !== $updatedBody) {
$message->body = $updatedBody;
$message->save();
}
}

$progressBar->advance(count($messages));
});
$progressBar->finish();

$this->info("\nMessages migration completed successfully.");
}

private function undoForumMigration(): void
{
// Get the total count of comments that need to be processed.
$totalComments = ForumTopicComment::where('body', 'like', '%[hub=%')->count();

$progressBar = $this->output->createProgressBar($totalComments);
ForumTopicComment::where('body', 'like', '%[hub=%')->chunkById(1000, function ($forumTopicComments) use ($progressBar) {
// Collect all hub IDs to fetch game mappings in bulk.
$hubIds = [];

/** @var ForumTopicComment $forumTopicComment */
foreach ($forumTopicComments as $forumTopicComment) {
preg_match_all('/\[hub=(\d+)\]/', $forumTopicComment->body, $matches);
$hubIds = array_merge($hubIds, $matches[1]);
}

// Remove duplicates and fetch hub mappings.
$hubIds = array_unique($hubIds);
$hubMappings = GameSet::whereIn('id', $hubIds)
->where('type', GameSetType::Hub)
->get()
->keyBy('id');

// Process each comment.
/** @var ForumTopicComment $forumTopicComment */
foreach ($forumTopicComments as $forumTopicComment) {
$originalPayload = $forumTopicComment->body;
$updatedPayload = preg_replace_callback('/\[hub=(\d+)\]/', function ($matches) use ($hubMappings) {
$hubId = (int) $matches[1];
$hubMapping = $hubMappings->get($hubId);

return $hubMapping ? "[game={$hubMapping->game_id}]" : $matches[0];
}, $forumTopicComment->body);

// Update the comment in the DB only if it has actually changed.
// Use `DB` so we don't change the `updated_at` value.
if ($originalPayload !== $updatedPayload) {
DB::table('forum_topic_comments')
->where('id', $forumTopicComment->id)
->update([
'body' => $updatedPayload,
'updated_at' => DB::raw('updated_at'), // don't change the value
]);
}
}

$progressBar->advance(count($forumTopicComments));
});
$progressBar->finish();

$this->info("\nForumTopicComments undo completed successfully.");
}

private function undoMessagesMigration(): void
{
// Get the total count of messages that need to be processed.
$totalMessages = Message::where('body', 'like', '%[hub=%')->count();

$progressBar = $this->output->createProgressBar($totalMessages);
Message::where('body', 'like', '%[hub=%')->chunkById(1000, function ($messages) use ($progressBar) {
// Collect all hub IDs to fetch game mappings in bulk.
$hubIds = [];

/** @var Message $message */
foreach ($messages as $message) {
preg_match_all('/\[hub=(\d+)\]/', $message->body, $matches);
$hubIds = array_merge($hubIds, $matches[1]);
}

// Remove duplicates and fetch hub mappings.
$hubIds = array_unique($hubIds);
$hubMappings = GameSet::whereIn('id', $hubIds)
->where('type', GameSetType::Hub)
->get()
->keyBy('id');

// Process each message.
/** @var Message $message */
foreach ($messages as $message) {
$originalBody = $message->body;
$updatedBody = preg_replace_callback('/\[hub=(\d+)\]/', function ($matches) use ($hubMappings) {
$hubId = (int) $matches[1];
$hubMapping = $hubMappings->get($hubId);

return $hubMapping ? "[game={$hubMapping->game_id}]" : $matches[0];
}, $message->body);

// Update the message in the DB only if it has actually changed.
// Use `DB` so we don't change the `updated_at` value.
if ($originalBody !== $updatedBody) {
$message->body = $updatedBody;
$message->save();
}
}

$progressBar->advance(count($messages));
});
$progressBar->finish();

$this->info("\nMessages undo completed successfully.");
}
}
9 changes: 5 additions & 4 deletions app/Community/Components/UserCard.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ function () use ($username): ?array {
return $foundUser ? [
...$foundUser->toArray(),
'isMuted' => $foundUser->isMuted(),
'visibleRoleName' => $foundUser->visible_role?->name,
] : null;
}
);
Expand All @@ -72,7 +73,7 @@ private function buildAllCardViewValues(string $username, array $rawUserData): a
{
$cardBioData = $this->buildCardBioData($rawUserData);
$cardRankData = $this->buildCardRankData($username, $rawUserData['RAPoints'], $rawUserData['RASoftcorePoints'], $rawUserData['Untracked'] ? true : false);
$cardRoleData = $this->buildCardRoleData($username, $rawUserData['Permissions']);
$cardRoleData = $this->buildCardRoleData($username, $rawUserData['visibleRoleName']);

return array_merge($cardBioData, $cardRankData, $cardRoleData);
}
Expand Down Expand Up @@ -147,10 +148,10 @@ private function buildCardRankData(string $username, int $hardcorePoints, int $s
);
}

private function buildCardRoleData(string $username, int $permissions): array
private function buildCardRoleData(string $username, ?string $visibleRoleName): array
{
$canShowUserRole = $permissions >= Permissions::JuniorDeveloper;
$roleLabel = Permissions::toString($permissions);
$canShowUserRole = $visibleRoleName !== null;
$roleLabel = $visibleRoleName ? __('permission.role.' . $visibleRoleName) : null;

$useExtraNamePadding =
$canShowUserRole
Expand Down
Loading

0 comments on commit 5845f77

Please sign in to comment.