Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add hub shortcode #3084

Merged
merged 9 commits into from
Jan 26, 2025
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
253 changes: 253 additions & 0 deletions app/Community/Commands/ConvertGameShortcodesToHubs.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
<?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) {
$forumTopicComment->body = $updatedPayload;
$forumTopicComment->timestamps = false;
$forumTopicComment->save();
Jamiras marked this conversation as resolved.
Show resolved Hide resolved
}
}

$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) {
$forumTopicComment->body = $updatedPayload;
$forumTopicComment->timestamps = false;
$forumTopicComment->save();
}
}

$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.");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public function preview(
ticketIds: $request->input('ticketIds'),
achievementIds: $request->input('achievementIds'),
gameIds: $request->input('gameIds'),
hubIds: $request->input('hubIds'),
);

return response()->json($entities);
Expand Down
2 changes: 2 additions & 0 deletions app/Community/Requests/PreviewForumPostRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ public function rules(): array
'achievementIds.*' => 'integer',
'gameIds' => 'present|array',
'gameIds.*' => 'integer',
'hubIds' => 'present|array',
'hubIds.*' => 'integer',
];
}
}
3 changes: 2 additions & 1 deletion app/Helpers/render/game.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ function gameAvatar(
bool $tooltip = true,
?string $context = null,
?string $title = null,
?string $href = null,
): string {
$id = $game;

Expand Down Expand Up @@ -52,7 +53,7 @@ function gameAvatar(
resource: 'game',
id: $id,
label: $label !== false && ($label || !$icon) ? $label : null,
link: route('game.show', $id),
link: $href ?? route('game.show', $id),
tooltip: $tooltip,
iconUrl: $icon !== false && ($icon || !$label) ? $icon : null,
iconSize: $iconSize,
Expand Down
1 change: 1 addition & 0 deletions app/Helpers/shortcode.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ function normalize_shortcodes(string $input): string

$modifiedInput = normalize_targeted_shortcodes($modifiedInput, 'user');
$modifiedInput = normalize_targeted_shortcodes($modifiedInput, 'game');
$modifiedInput = normalize_targeted_shortcodes($modifiedInput, 'hub');
$modifiedInput = normalize_targeted_shortcodes($modifiedInput, 'achievement', 'ach');
$modifiedInput = normalize_targeted_shortcodes($modifiedInput, 'ticket');

Expand Down
Loading