Skip to content

Commit

Permalink
Merge branch 'master' into feature/future_event
Browse files Browse the repository at this point in the history
  • Loading branch information
Jamiras authored Feb 2, 2025
2 parents 338103f + 62672aa commit 078f861
Show file tree
Hide file tree
Showing 14 changed files with 320 additions and 28 deletions.
84 changes: 64 additions & 20 deletions .hooks/pre-push
Original file line number Diff line number Diff line change
@@ -1,31 +1,75 @@
#!/bin/sh
# exit on error
# Exit on error.
set -e

printf "\n⏳ composer lint\n"
vendor/bin/pint --test
# Checks if files matching a pattern have changed.
check_changed_files() {
# Get the list of changed files between current branch and master.
changed_files=$(git diff --name-only master...HEAD)

# Check each pattern against the changed files.
for pattern in "$@"; do
if echo "$changed_files" | grep -q "$pattern"; then
return 0 # Found a match.
fi
done

return 1 # No matches found.
}

printf "\n⏳ composer analyse\n"
vendor/bin/phpstan analyse --memory-limit 768M
is_php_changed=false
is_node_changed=false

printf "\n⏳ pnpm lint:eslint\n"
pnpm lint:eslint
# Check for PHP changes.
if check_changed_files "\.php$" "composer\.json$" "composer\.lock$" "phpstan\.neon$" "pint\.json$"; then
is_php_changed=true
fi

printf "\n⏳ pnpm tsc\n"
pnpm tsc
# Check for Node.js changes.
if check_changed_files "\.js$" "\.ts$" "\.tsx$" "package\.json$" "pnpm-lock\.yaml$" "eslint" "tailwind\.config\.json$" "lang/.*\.json$"; then
is_node_changed=true
fi

printf "\n⏳ pnpm test\n"
pnpm test
# If no relevant changes detected, exit early.
if [ "$is_php_changed" = false ] && [ "$is_node_changed" = false ]; then
printf "\n✅ No PHP or Node.js changes detected. Skipping checks.\n\n"
exit 0
fi

# Run PHP checks if needed.
if [ "$is_php_changed" = true ]; then
printf "\n🔍 PHP changes detected. Running PHP checks...\n"

printf "\n⏳ composer lint\n"
vendor/bin/pint --test

printf "\n⏳ composer analyse\n"
vendor/bin/phpstan analyse --memory-limit 768M

# Check the OS. Windows does not support the --parallel flag.
if [ "$(uname)" = "Linux" ] || [ "$(uname)" = "Darwin" ]; then
# Use --parallel if macOS or Linux are detected.
printf "\n⏳ composer test -- --parallel\n"
vendor/bin/paratest
else
# If neither of those are detected, don't use --parallel.
printf "\n⏳ composer test\n"
vendor/bin/phpunit
fi
fi

# Check the OS. Windows does not support the --parallel flag.
if [ "$(uname)" = "Linux" ] || [ "$(uname)" = "Darwin" ]; then
# Use --parallel if macOS or Linux are detected.
printf "\n⏳ composer test -- --parallel\n"
vendor/bin/paratest
else
# If neither of those are detected, don't use --parallel.
printf "\n⏳ composer test\n"
vendor/bin/phpunit
# Run Node.js checks if needed.
if [ "$is_node_changed" = true ]; then
printf "\n🔍 Node.js changes detected. Running Node.js checks...\n"

printf "\n⏳ pnpm lint:eslint\n"
pnpm lint:eslint

printf "\n⏳ pnpm tsc\n"
pnpm tsc

printf "\n⏳ pnpm test\n"
pnpm test
fi

printf "\n✅ pre-push OK\n\n"
50 changes: 50 additions & 0 deletions app/Community/Actions/BuildDisplayNameHistoryAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

declare(strict_types=1);

namespace App\Community\Actions;

use App\Models\User;
use Carbon\Carbon;

class BuildDisplayNameHistoryAction
{
public function execute(User $user): string
{
// Get all approved display_name changes in reverse chronological order.
$allChanges = $user->usernameRequests()
->approved()
->orderBy('approved_at', 'desc')
->get();

// If there are no changes and display_name matches the username, return an empty string.
if ($allChanges->isEmpty() && $user->display_name === $user->username) {
return '';
}

$entries = collect();

// Add current display_name if it came from a change request.
if ($user->display_name === $user->username) {
$entries->push($this->formatEntry($user->display_name, $user->created_at));
} elseif ($currentChange = $allChanges->firstWhere('username', $user->display_name)) {
$entries->push($this->formatEntry($user->display_name, $currentChange->approved_at));
}

// Add all previous display_name changes.
$allChanges->reject(fn ($change) => $change->username === $user->display_name)
->each(fn ($change) => $entries->push($this->formatEntry($change->username, $change->approved_at)));

// Add their original username if it's different from their current display_name and not already included.
if ($user->username !== $user->display_name && !$allChanges->contains('username', $user->username)) {
$entries->push($this->formatEntry($user->username, $user->created_at));
}

return $entries->join("\n");
}

private function formatEntry(string $username, Carbon $date): string
{
return $username . ' (' . $date->format('F j, Y') . ')';
}
}
2 changes: 2 additions & 0 deletions app/Community/AppServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use App\Community\Commands\SyncForums;
use App\Community\Commands\SyncTickets;
use App\Community\Commands\SyncUserRelations;
use App\Community\Commands\SyncUserUlids;
use App\Community\Components\DeveloperGameStatsTable;
use App\Community\Components\ForumRecentActivity;
use App\Community\Components\MessageIcon;
Expand Down Expand Up @@ -55,6 +56,7 @@ public function boot(): void
SyncForums::class,
SyncTickets::class,
SyncUserRelations::class,
SyncUserUlids::class,

GenerateAnnualRecap::class,
]);
Expand Down
67 changes: 67 additions & 0 deletions app/Community/Commands/SyncUserUlids.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

declare(strict_types=1);

namespace App\Community\Commands;

use App\Models\User;
use DB;
use Illuminate\Console\Command;
use Illuminate\Support\Str;

class SyncUserUlids extends Command
{
protected $signature = 'ra:sync:user-ulids';

protected $description = 'Sync user ulid field values';

public function handle(): void
{
$total = User::whereNull('ulid')->count();

if ($total === 0) {
$this->info('No records need ULIDs.');

return;
}

$progressBar = $this->output->createProgressBar($total);
$progressBar->start();

User::withTrashed()
->whereNull('ulid')
->chunkById(4000, function ($users) use ($progressBar) {
$updates = [];
$milliseconds = 0;

/** @var User $user */
foreach ($users as $user) {
$milliseconds += rand(1, 20);
$milliseconds %= 1000;

$timestamp = $user->Created->clone()->addMilliseconds($milliseconds);
$ulid = (string) Str::ulid($timestamp);

$updates[] = [
'ID' => $user->id,
'ulid' => $ulid,
];
}

// Perform a batch update for speed.
DB::table('UserAccounts')
->upsert(
$updates,
['ID'],
['ulid']
);

$progressBar->advance(count($updates));
});

$progressBar->finish();

$this->newLine();
$this->info('Done.');
}
}
9 changes: 9 additions & 0 deletions app/Community/Concerns/ActsAsCommunityMember.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use App\Models\UserComment;
use App\Models\UserGameListEntry;
use App\Models\UserRelation;
use App\Models\UserUsername;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
Expand Down Expand Up @@ -269,4 +270,12 @@ public function subscriptions(): HasMany
{
return $this->hasMany(Subscription::class, 'user_id', 'ID');
}

/**
* @return HasMany<UserUsername>
*/
public function usernameRequests(): HasMany
{
return $this->hasMany(UserUsername::class, 'user_id', 'ID');
}
}
17 changes: 17 additions & 0 deletions app/Policies/UserPolicy.php
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,23 @@ public function viewDeveloperFeed(User $user, User $model): bool
return true;
}

public function viewDisplayNameHistory(User $user, User $model): bool
{
if ($model->isBlocking($user)) {
return false;
}

return $user->hasAnyRole([
Role::ADMINISTRATOR,
Role::MODERATOR,
Role::DEV_COMPLIANCE,
Role::QUALITY_ASSURANCE,
Role::EVENT_MANAGER,
Role::GAME_EDITOR,
Role::CHEAT_INVESTIGATOR,
]);
}

private function requireAdministrativePrivileges(User $user, ?User $model = null): bool
{
if (!$model) {
Expand Down
1 change: 1 addition & 0 deletions database/factories/UserFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public function definition(): array
{
return [
// required
'ulid' => (string) Str::ulid(),
'User' => $this->fakeUsername(),
'EmailAddress' => fake()->unique()->safeEmail,
'email_verified_at' => now(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class() extends Migration {
public function up(): void
{
Schema::table('UserAccounts', function (Blueprint $table) {
$table->ulid('ulid')->after('ID')->unique()->nullable();
});
}

public function down(): void
{
Schema::table('UserAccounts', function (Blueprint $table) {
$table->dropColumn('ulid');
});
}
};
2 changes: 1 addition & 1 deletion public/API/API_GetGameLeaderboards.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,6 @@

return response()->json([
'Count' => count($leaderboards),
'Total' => $game->leaderboards()->count(),
'Total' => $game->leaderboards()->visible()->count(),
'Results' => $results,
]);
12 changes: 9 additions & 3 deletions public/API/API_GetUserProfile.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
/*
* API_GetUserProfile
* u : username
* i : ULID
*
* string User name of user
* string User non-stable name of user
* int ID unique identifier of the user
* string ULID queryable unique identifier of the user
* int TotalPoints number of hardcore points the user has
* int TotalSoftcorePoints number of softcore points the user has
* int TotalTruePoints number of RetroPoints ("white points") the user has
Expand All @@ -27,17 +29,21 @@
use Illuminate\Support\Facades\Validator;

$input = Validator::validate(Arr::wrap(request()->query()), [
'u' => ['required', 'min:2', 'max:20', new CtypeAlnum()],
'u' => ['required_without:i', 'min:2', 'max:20', new CtypeAlnum()],
'i' => ['required_without:u', 'string', 'size:26'],
]);

$user = User::whereName(request()->query('u'))->first();
$user = isset($input['i'])
? User::whereUlid($input['i'])->first()
: User::whereName($input['u'])->first();

if (!$user) {
return response()->json([], 404);
}

return response()->json([
'User' => $user->display_name,
'ULID' => $user->ulid,
'UserPic' => sprintf("/UserPic/%s.png", $user->username),
'MemberSince' => $user->created_at->toDateTimeString(),
'RichPresenceMsg' => empty($user->RichPresenceMsg) || $user->RichPresenceMsg === 'Unknown' ? null : $user->RichPresenceMsg,
Expand Down
6 changes: 4 additions & 2 deletions public/request/auth/register.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;

$input = Validator::validate(Arr::wrap(request()->post()), [
'username' => ValidNewUsername::get(),
Expand Down Expand Up @@ -41,10 +42,11 @@
}
}

$ulid = (string) Str::ulid();
$hashedPassword = Hash::make($pass);

$query = "INSERT INTO UserAccounts (User, display_name, Password, SaltedPass, EmailAddress, Permissions, RAPoints, fbUser, fbPrefs, cookie, appToken, appTokenExpiry, websitePrefs, LastLogin, LastActivityID, Motto, ContribCount, ContribYield, APIKey, APIUses, LastGameID, RichPresenceMsg, RichPresenceMsgDate, ManuallyVerified, UnreadMessageCount, TrueRAPoints, UserWallActive, PasswordResetToken, Untracked, email_backup)
VALUES ( '$username', '$username', '$hashedPassword', '', '$email', 0, 0, 0, 0, '', '', NULL, 127, null, 0, '', 0, 0, '', 0, 0, '', NULL, 0, 0, 0, 1, NULL, false, '$email')";
$query = "INSERT INTO UserAccounts (ulid, User, display_name, Password, SaltedPass, EmailAddress, Permissions, RAPoints, fbUser, fbPrefs, cookie, appToken, appTokenExpiry, websitePrefs, LastLogin, LastActivityID, Motto, ContribCount, ContribYield, APIKey, APIUses, LastGameID, RichPresenceMsg, RichPresenceMsgDate, ManuallyVerified, UnreadMessageCount, TrueRAPoints, UserWallActive, PasswordResetToken, Untracked, email_backup)
VALUES ('$ulid', '$username', '$username', '$hashedPassword', '', '$email', 0, 0, 0, 0, '', '', NULL, 127, null, 0, '', 0, 0, '', 0, 0, '', NULL, 0, 0, 0, 1, NULL, false, '$email')";
$dbResult = s_mysql_query($query);

if (!$dbResult) {
Expand Down
Loading

0 comments on commit 078f861

Please sign in to comment.