Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions app/Helpers/database/achievement.php
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ function GetAchievementData(int $achievementId): ?array
'Flags' => $achievement->Flags,
'type' => $achievement->type,
'Author' => $achievement->developer?->display_name,
'AuthorULID' => $achievement->developer?->ulid,
'DateCreated' => $achievement->DateCreated->format('Y-m-d H:i:s'),
'DateModified' => $achievement->DateModified->format('Y-m-d H:i:s'),
'BadgeName' => $achievement->badge_name,
Expand Down
1 change: 1 addition & 0 deletions app/Helpers/database/game.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ function getGameMetadata(
ach.Points,
ach.TrueRatio,
COALESCE(ua.display_name, ua.User) AS Author,
ua.ulid AS AuthorULID,
ach.DateModified,
ach.DateCreated,
ach.BadgeName,
Expand Down
1 change: 1 addition & 0 deletions app/Helpers/database/leaderboard.php
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ function GetLeaderboardData(

$retVal['Entries'][] = [
'User' => $entry->user->display_name,
'ULID' => $entry->user->ulid,
'AvatarUrl' => $entry->user->avatar_url,
'DateSubmitted' => $entry->updated_at->unix(),
'Score' => $entry->score,
Expand Down
3 changes: 2 additions & 1 deletion app/Helpers/database/player-achievement.php
Original file line number Diff line number Diff line change
Expand Up @@ -147,13 +147,14 @@ function getAchievementUnlocksData(
return PlayerAchievement::where('achievement_id', $achievementId)
->join('UserAccounts', 'UserAccounts.ID', '=', 'user_id')
->orderByRaw('COALESCE(unlocked_hardcore_at, unlocked_at) DESC')
->select(['UserAccounts.User', 'UserAccounts.display_name', 'UserAccounts.RAPoints', 'UserAccounts.RASoftcorePoints', 'unlocked_at', 'unlocked_hardcore_at'])
->select(['UserAccounts.ulid', 'UserAccounts.User', 'UserAccounts.display_name', 'UserAccounts.RAPoints', 'UserAccounts.RASoftcorePoints', 'unlocked_at', 'unlocked_hardcore_at'])
->offset($offset)
->limit($limit)
->get()
->map(function ($row) {
return [
'User' => !empty($row->display_name) ? $row->display_name : $row->User,
'ULID' => $row->ulid,
'RAPoints' => $row->RAPoints,
'RASoftcorePoints' => $row->RASoftcorePoints,
'DateAwarded' => $row->unlocked_hardcore_at ?? $row->unlocked_at,
Expand Down
2 changes: 1 addition & 1 deletion app/Helpers/database/player-game.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ function getGameRankAndScore(int $gameID, User $user): array
}

$query = "WITH data
AS (SELECT ua.User, $rankClause, pg.Points AS TotalScore, $dateClause AS LastAward
AS (SELECT ua.User, ua.ulid AS ULID, $rankClause, pg.Points AS TotalScore, $dateClause AS LastAward
FROM player_games AS pg
INNER JOIN UserAccounts AS ua ON ua.ID = pg.user_id
WHERE pg.game_id = $gameID $untrackedClause
Expand Down
2 changes: 1 addition & 1 deletion app/Helpers/database/player-history.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ function getAchievementsEarnedBetween(string $dateStart, string $dateEnd, User $
CASE WHEN pa.unlocked_hardcore_at IS NOT NULL THEN 1 ELSE 0 END AS HardcoreMode,
ach.ID AS AchievementID, ach.Title, ach.Description,
ach.BadgeName, ach.Points, ach.TrueRatio, ach.type as Type,
COALESCE(ua.display_name, ua.User) AS Author,
COALESCE(ua.display_name, ua.User) AS Author, ua.ulid AS AuthorULID,
gd.Title AS GameTitle, gd.ImageIcon AS GameIcon, ach.GameID,
c.Name AS ConsoleName
FROM player_achievements pa
Expand Down
3 changes: 2 additions & 1 deletion app/Helpers/database/player-rank.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ function () use ($type) {

function getTopUsersByScore(int $count): array
{
return User::select(['display_name', 'User', 'RAPoints', 'TrueRAPoints'])
return User::select(['ulid', 'display_name', 'User', 'RAPoints', 'TrueRAPoints'])
->where('Untracked', false)
->orderBy('RAPoints', 'desc')
->orderBy('TrueRAPoints', 'desc')
Expand All @@ -55,6 +55,7 @@ function getTopUsersByScore(int $count): array
1 => $user->display_name ?? $user->User,
2 => $user->RAPoints,
3 => $user->TrueRAPoints,
4 => $user->ulid,
])
->toArray();
}
Expand Down
1 change: 1 addition & 0 deletions app/Helpers/database/set-claim.php
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ function getFilteredClaims(
// Get either the filtered count or the filtered data
$selectCondition = "
sc.ID AS ID,
ua.ulid as ULID,
COALESCE(ua.display_name, ua.User) AS User,
sc.game_id AS GameID,
gd.Title AS GameTitle,
Expand Down
4 changes: 2 additions & 2 deletions app/Helpers/database/ticket.php
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,8 @@ function getExistingTicketID(User $user, int $achievementID): int
function getTicket(int $ticketID): ?array
{
$query = "SELECT tick.ID, tick.AchievementID, ach.Title AS AchievementTitle, ach.Description AS AchievementDesc, ach.type AS AchievementType, ach.Points, ach.BadgeName,
COALESCE(ua3.display_name, ua3.User) AS AchievementAuthor, ach.GameID, c.Name AS ConsoleName, gd.Title AS GameTitle, gd.ImageIcon AS GameIcon,
tick.ReportedAt, tick.ReportType, tick.ReportState, tick.Hardcore, tick.ReportNotes, COALESCE(ua.display_name, ua.User) AS ReportedBy, tick.ResolvedAt, COALESCE(ua2.display_name, ua2.User) AS ResolvedBy
COALESCE(ua3.display_name, ua3.User) AS AchievementAuthor, ua3.ulid AS AchievementAuthorULID, ach.GameID, c.Name AS ConsoleName, gd.Title AS GameTitle, gd.ImageIcon AS GameIcon,
tick.ReportedAt, tick.ReportType, tick.ReportState, tick.Hardcore, tick.ReportNotes, COALESCE(ua.display_name, ua.User) AS ReportedBy, ua.ulid AS ReportedByULID, tick.ResolvedAt, COALESCE(ua2.display_name, ua2.User) AS ResolvedBy, ua2.ulid AS ResolvedByULID
FROM Ticket AS tick
LEFT JOIN Achievements AS ach ON ach.ID = tick.AchievementID
LEFT JOIN GameData AS gd ON gd.ID = ach.GameID
Expand Down
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;
}
}
}
4 changes: 4 additions & 0 deletions public/API/API_GetAchievementOfTheWeek.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* int TrueRatio number of RetroPoints ("white points") the achievement is worth
* string Type null, "progression", "win_condition", or "missable"
* string Author user who first created the achievement
* string AuthorULID stable unique identifier of the user who first created the achievement
* string BadgeName unique identifier of the badge image for the achievement
* string BadgeURL site-relative path to the badge image for the achievement
* datetime DateCreated when the achievement was created
Expand All @@ -34,6 +35,7 @@
* int TotalPlayers number of players who have played the game associated to the achievement
* array Unlocks requested unlock information
* string User user who unlocked the achievement
* string ULID stable unique identifier of the user who unlocked the achievement
* int RAPoints number of points the user has
* int RASoftcorePoints number of softcore points the user has
* datetime DateAwarded when the achievement was unlocked
Expand Down Expand Up @@ -68,6 +70,7 @@
'TrueRatio' => $sourceAchievement->TrueRatio ?? null,
'Type' => $sourceAchievement->type ?? null,
'Author' => $sourceAchievement->author->display_name ?? null,
'AuthorULID' => $sourceAchievement->author->ulid ?? null,
'BadgeName' => $sourceAchievement->BadgeName,
'BadgeURL' => "/Badge/" . $sourceAchievement->BadgeName . ".png",
'DateCreated' => $sourceAchievement->DateCreated?->format('Y-m-d'),
Expand Down Expand Up @@ -101,6 +104,7 @@
foreach ($playerAchievements as $playerAchievement) {
$unlocks[] = [
'User' => $playerAchievement->user->display_name,
'ULID' => $playerAchievement->user->ulid,
'RAPoints' => $playerAchievement->user->RAPoints,
'RASoftcorePoints' => $playerAchievement->user->RASoftcorePoints,
'HardcoreMode' => $playerAchievement->unlocked_hardcore_at !== null ? 1 : 0,
Expand Down
3 changes: 3 additions & 0 deletions public/API/API_GetAchievementUnlocks.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
* string Points number of points the achievement is worth
* string TrueRatio number of RetroPoints ("white points") the achievement is worth
* string Author user who first created the achievement
* string AuthorULID queryable stable unique identifier of the user who first created the achievement
* datetime DateCreated when the achievement was created
* datetime DateModified when the achievement was last modified
* string Type null, "progression", "win_condition", or "missable"
Expand All @@ -27,6 +28,7 @@
* int TotalPlayers number of players who have played the game associated to the achievement
* array Unlocks requested unlock information
* string User user who unlocked the achievement
* string ULID queryable stable unique identifier of the user
* string RAPoints number of points the user has
* string RASoftcorePoints number of softcore points the user has
* datetime DateAwarded when the achievement was unlocked
Expand Down Expand Up @@ -61,6 +63,7 @@
'Points' => $achievementData['Points'] ?? null,
'TrueRatio' => $achievementData['TrueRatio'] ?? null,
'Author' => $achievementData['Author'] ?? null,
'AuthorULID' => $achievementData['AuthorULID'] ?? null,
'DateCreated' => $achievementData['DateCreated'] ?? null,
'DateModified' => $achievementData['DateModified'] ?? null,
'Type' => $achievementData['type'] ?? null,
Expand Down
13 changes: 10 additions & 3 deletions public/API/API_GetAchievementsEarnedBetween.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

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

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

$user = User::whereName(request()->query('u'))->first();
$input = Validator::validate(Arr::wrap(request()->query()), [
'u' => ['required', new ValidUserIdentifier()],
]);

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

/*
* API_GetAchievementsEarnedOnDay - returns achievements earned by a user between two timestamps
* u : user
* u : username or user ULID
* d : date (YYYY-MM-DD)
*
* array
Expand All @@ -25,17 +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', 'min:2', 'max:20', new CtypeAlnum()],
'u' => ['required', new ValidUserIdentifier()],
'd' => ['required', 'date'],
]);

$user = User::whereName(request()->query('u'))->first();
$user = (new FindUserByIdentifierAction())->execute($input['u']);
if (!$user) {
return response()->json([]);
}
Expand Down
1 change: 1 addition & 0 deletions public/API/API_GetActiveClaims.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
* object [value]
* int ID unique ID of the claim
* string User user who made the claim
* string ULID queryable stable unique identifier of the user
* int GameID id of the claimed game
* string GameTitle title of the claimed game
* string GameIcon site-relative path to the game's icon image
Expand Down
1 change: 1 addition & 0 deletions public/API/API_GetClaims.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
* object [value]
* int ID unique ID of the claim
* string User user who made the claim
* string ULID queryable stable unique identifier of the user
* int GameID id of the claimed game
* string GameTitle title of the claimed game
* string GameIcon site-relative path to the game's icon image
Expand Down
19 changes: 10 additions & 9 deletions public/API/API_GetComments.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

use App\Models\Achievement;
use App\Actions\FindUserByIdentifierAction;
use App\Models\Comment;
use App\Models\User;
use App\Policies\CommentPolicy;
Expand All @@ -10,8 +10,8 @@
use Illuminate\Validation\Rule;

/*
* API_GetComments - returns the comments associated to a game or achievement
* i : game or achievement id or username
* API_GetComments - returns the comments associated to a game, achievement, or user wall
* i : game id, achievement id, username, or user ulid
* t : 1 = game, 2 = achievement, 3 = user
* o : offset - number of entries to skip (default: 0)
* c : count - number of entries to return (default: 100, max: 500)
Expand All @@ -20,7 +20,8 @@
* int Total number of comment records the game/achievement/user actually has overall
* array Results
* object [value]
* int User username of the commenter
* string User username of the commenter
* string ULID queryable stable unique identifier of the commenter
* string Submitted date time the comment was submitted
* string CommentText text of the comment
*/
Expand Down Expand Up @@ -50,24 +51,23 @@
$offset = $input['o'] ?? 0;
$count = $input['c'] ?? 100;

$username = null;
$usernameOrUlid = null;
$gameOrAchievementId = 0;
$commentType = 0;

if ($inputIsGameOrAchievement()) {
$gameOrAchievementId = $query['i'];
$commentType = $query['t'];
} else {
$username = $query['i'];
$usernameOrUlid = $query['i'];
$commentType = 3;
}

$user = null;
$userPolicy = new UserCommentPolicy();

if ($username) {
$user = User::whereName($username)->first();

if ($usernameOrUlid) {
$user = (new FindUserByIdentifierAction())->execute($usernameOrUlid);
if (!$user || !$userPolicy->viewAny(null, $user)) {
return response()->json([], 404);
}
Expand Down Expand Up @@ -105,6 +105,7 @@
})->map(function ($nextComment) {
return [
'User' => $nextComment->user->display_name,
'ULID' => $nextComment->user->ulid,
'Submitted' => $nextComment->Submitted,
'CommentText' => $nextComment->Payload,
];
Expand Down
4 changes: 4 additions & 0 deletions public/API/API_GetGameExtended.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
* int NumAwardedHardcore number of times the achievement has been awarded in hardcore
* int DisplayOrder field used for determining which order to display the achievements
* string Author user who originally created the achievement
* string AuthorULID queryable stable unique identifier of the user who first created the achievement
* datetime DateCreated when the achievement was created
* datetime DateModified when the achievement was last modified
* string MemAddr md5 of the logic for the achievement
Expand All @@ -45,6 +46,7 @@
* array Claims
* object [value]
* string User user holding the claim
* string ULID queryable stable unique identifier of the user holding the claim
* int SetType set type claimed: 0 - new set, 1 - revision
* int ClaimType claim type: 0 - primary, 1 - collaboration
* string Created date the claim was made
Expand Down Expand Up @@ -104,6 +106,7 @@
'Points' => $am->Points,
'TrueRatio' => $am->TrueRatio,
'Author' => $am->developer?->display_name,
'AuthorULID' => $am->developer?->ulid,
'DateModified' => Carbon::parse($am->DateModified)->format('Y-m-d H:i:s'),
'DateCreated' => Carbon::parse($am->DateCreated)->format('Y-m-d H:i:s'),
'BadgeName' => $am->BadgeName,
Expand All @@ -122,6 +125,7 @@
$gameClaims = $gameAchievementSetClaims->map(function ($gc) {
return [
'User' => $gc->user->display_name,
'ULID' => $gc->user->ulid,
'SetType' => $gc->SetType,
'GameID' => $gc->game_id,
'ClaimType' => $gc->ClaimType,
Expand Down
Loading