Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
29 changes: 29 additions & 0 deletions app/Actions/FindUserByIdentifierAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace App\Actions;

use App\Models\User;

class FindUserByIdentifierAction
{
public function execute(?string $identifier): ?User
{
if ($identifier === null) {
return null;
}

$ulidLength = 26;
if (mb_strlen($identifier) === $ulidLength) {
return User::whereUlid($identifier)->first();
}

return User::query()
->where(function ($query) use ($identifier) {
$query->where('display_name', $identifier)
->orWhere('User', $identifier);
})
->first();
}
}
49 changes: 49 additions & 0 deletions app/Support/Rules/ValidUserIdentifier.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

declare(strict_types=1);

namespace App\Support\Rules;

use Closure;
use Illuminate\Contracts\Validation\ValidationRule;

class ValidUserIdentifier implements ValidationRule
{
/**
* Validate the given input is either a valid ULID (26 chars) or username (2-20 chars).
*/
public function validate(string $attribute, mixed $value, Closure $fail): void
{
if (!is_string($value)) {
$fail('The :attribute must be a string.');

return;
}

$length = mb_strlen($value);
$ulidLength = 26;

if ($length === $ulidLength) {
// ULIDs are base32 encoded - verify.
if (!preg_match('/^[0-9A-Z]{26}$/i', $value)) {
$fail('The :attribute must be a valid ULID.');
}

return;
}

// Otherwise, validate as a username (2-20 chars).
if ($length < 2 || $length > 20) {
$fail('The :attribute must be between 2 and 20 characters when providing a username.');

return;
}

// A username must also strictly use alphanumeric chars.
if (!ctype_alnum($value)) {
$fail('The :attribute may only contain letters and numbers.');

return;
}
}
}
15 changes: 5 additions & 10 deletions public/API/API_GetAchievementsEarnedBetween.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

/*
* API_GetAchievementsEarnedBetween - returns achievements earned by a user between two timestamps
* u : username
* i : user ULID
* u : username or user ULID
* f : from (time_t)
* t : to (time_t)
*
Expand All @@ -28,20 +27,16 @@
* string GameURL site-relative path to the game page
*/

use App\Models\User;
use App\Support\Rules\CtypeAlnum;
use App\Actions\FindUserByIdentifierAction;
use App\Support\Rules\ValidUserIdentifier;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Validator;

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

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

$user = (new FindUserByIdentifierAction())->execute($input['u']);
if (!$user) {
return response()->json([]);
}
Expand Down
15 changes: 5 additions & 10 deletions public/API/API_GetAchievementsEarnedOnDay.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

/*
* API_GetAchievementsEarnedOnDay - returns achievements earned by a user between two timestamps
* u : username
* i : user ULID
* u : username or user ULID
* d : date (YYYY-MM-DD)
*
* array
Expand All @@ -26,21 +25,17 @@
* string GameURL site-relative path to the game page
*/

use App\Models\User;
use App\Support\Rules\CtypeAlnum;
use App\Actions\FindUserByIdentifierAction;
use App\Support\Rules\ValidUserIdentifier;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Validator;

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

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

$user = (new FindUserByIdentifierAction())->execute($input['u']);
if (!$user) {
return response()->json([]);
}
Expand Down
6 changes: 2 additions & 4 deletions public/API/API_GetComments.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?php

use App\Actions\FindUserByIdentifierAction;
use App\Models\Comment;
use App\Models\User;
use App\Policies\CommentPolicy;
Expand Down Expand Up @@ -66,10 +67,7 @@
$userPolicy = new UserCommentPolicy();

if ($usernameOrUlid) {
$user = User::whereName($usernameOrUlid)
->orWhere('ulid', $usernameOrUlid)
->first();

$user = (new FindUserByIdentifierAction())->execute($usernameOrUlid);
if (!$user || !$userPolicy->viewAny(null, $user)) {
return response()->json([], 404);
}
Expand Down
15 changes: 5 additions & 10 deletions public/API/API_GetGameInfoAndUserProgress.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
/*
* API_GetGameInfoAndUserProgress
* g : game id
* u : username
* i : user ULID
* u : username or user ULID
* a : if 1, include highest award metadata (default: 0)
*
* int ID unique identifier of the game
Expand Down Expand Up @@ -55,25 +54,21 @@
* ?datetime HighestAwardDate an ISO8601 timestamp string, or null, for when the HighestAwardKind was granted. requires the 'a' query param to be 1.
*/

use App\Actions\FindUserByIdentifierAction;
use App\Models\PlayerBadge;
use App\Models\User;
use App\Support\Rules\CtypeAlnum;
use App\Support\Rules\ValidUserIdentifier;
use Illuminate\Support\Arr;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Validator;

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

$gameID = (int) $input['g'];

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

$targetUser = (new FindUserByIdentifierAction())->execute($input['u']);
if (!$targetUser) {
return response()->json([]);
}
Expand Down
6 changes: 3 additions & 3 deletions public/API/API_GetTicketData.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,7 @@

/*
* API_GetTicketData - returns ticket statistics for the specified user
* u : username
* i : user ULID
* u : username or user ULID
*
* string User non-stable unique identifier of the user
* string ULID queryable stable unique identifier of the user
Expand Down Expand Up @@ -146,6 +145,7 @@
* string URL URL to the list of tickets associated to the game
*/

use App\Actions\FindUserByIdentifierAction;
use App\Community\Enums\TicketState;
use App\Community\Enums\TicketType;
use App\Models\Achievement;
Expand Down Expand Up @@ -190,7 +190,7 @@
// getting ticket info for a specific user
$assignedToUser = request()->query('u');
if (!empty($assignedToUser)) {
$foundUser = User::whereName($assignedToUser)->orWhere('ulid', $assignedToUser)->first();
$foundUser = (new FindUserByIdentifierAction())->execute($assignedToUser);
if (!$foundUser) {
return response()->json(['error' => "User $assignedToUser not found"], 404);
}
Expand Down
14 changes: 5 additions & 9 deletions public/API/API_GetUserAwards.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

/*
* API_GetUserAwards - returns information about the user's earned awards
* u : username
* i : user ULID
* u : username or user ULID
*
* int TotalAwardsCount number of awards earned by the user, including hidden
* int HiddenAwardsCount number of awards hidden by the user
Expand All @@ -27,22 +26,19 @@

declare(strict_types=1);

use App\Actions\FindUserByIdentifierAction;
use App\Community\Enums\AwardType;
use App\Models\User;
use App\Platform\Enums\UnlockMode;
use App\Support\Rules\CtypeAlnum;
use App\Support\Rules\ValidUserIdentifier;
use Illuminate\Support\Arr;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Validator;

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

$userModel = isset($input['i'])
? User::whereUlid($input['i'])->first()
: User::whereName($input['u'])->first();
$userModel = (new FindUserByIdentifierAction())->execute($input['u']);

$userAwards = getUsersSiteAwards($userModel);
[$gameMasteryAwards, $eventAwards, $siteAwards] = SeparateAwards($userAwards);
Expand Down
15 changes: 5 additions & 10 deletions public/API/API_GetUserClaims.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

/*
* API_GetUserClaims - returns information about a all users set claims
* u : username
* i : user ULID
* u : username or user ULID
*
* array
* object [value]
Expand All @@ -28,20 +27,16 @@
* int MinutesLeft time in minutes left until the claim expires
*/

use App\Models\User;
use App\Support\Rules\CtypeAlnum;
use App\Actions\FindUserByIdentifierAction;
use App\Support\Rules\ValidUserIdentifier;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Validator;

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

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

$user = (new FindUserByIdentifierAction())->execute($input['u']);
if (!$user) {
return response()->json([], 404);
}
Expand Down
14 changes: 5 additions & 9 deletions public/API/API_GetUserCompletedGames.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

/*
* API_GetUserCompletedGames - gets all game progress for a user
* u : username
* i : user ULID
* u : username or user ULID
*
* NOTE: each game may appear in the list twice - once for Hardcore and once for Casual
*
Expand All @@ -20,19 +19,16 @@
* string HardcoreMode "1" if the data is for hardcore, otherwise "0"
*/

use App\Models\User;
use App\Support\Rules\CtypeAlnum;
use App\Actions\FindUserByIdentifierAction;
use App\Support\Rules\ValidUserIdentifier;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Validator;

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

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

$result = [];
$completedGames = getUsersCompletedGamesAndMax($user?->username ?? "");
Expand Down
14 changes: 5 additions & 9 deletions public/API/API_GetUserCompletionProgress.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
* API_GetUserCompletionProgress - gets the entire completion progress (eg: /user/{username}/progress) for a user
* similar to `GetUserCompletedGames`, but only includes a single record for each game
* and also includes the game's current award level as shown on the "Completion Progress" page.
* u : username
* i : user ULID
* u : username or user ULID
* o : offset - number of entries to skip (default: 0)
* c : count - number of entries to return (default: 100, max: 500)
*
Expand All @@ -26,26 +25,23 @@
* ?datetime HighestAwardDate an ISO8601 timestamp string, or null, for when the HighestAwardKind was granted
*/

use App\Models\User;
use App\Actions\FindUserByIdentifierAction;
use App\Platform\Services\PlayerProgressionService;
use App\Support\Rules\CtypeAlnum;
use App\Support\Rules\ValidUserIdentifier;
use Illuminate\Support\Arr;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Validator;

$input = Validator::validate(Arr::wrap(request()->query()), [
'u' => ['required_without:i', 'min:2', 'max:20', new CtypeAlnum()],
'i' => ['required_without:u', 'string', 'size:26'],
'u' => ['required', new ValidUserIdentifier()],
'o' => ['sometimes', 'integer', 'min:0', 'nullable'],
'c' => ['sometimes', 'integer', 'min:1', 'max:500', 'nullable'],
]);

$offset = $input['o'] ?? 0;
$count = $input['c'] ?? 100;

$userModel = isset($input['i'])
? User::whereUlid($input['i'])->first()
: User::whereName($input['u'])->first();
$userModel = (new FindUserByIdentifierAction())->execute($input['u']);

$playerProgressionService = new PlayerProgressionService();

Expand Down
Loading
Loading