Skip to content

Commit

Permalink
Merge branch 'master' into aggregate_recent_players
Browse files Browse the repository at this point in the history
  • Loading branch information
Jamiras authored Oct 27, 2023
2 parents a4058e0 + c2c2f9b commit 0940ea8
Show file tree
Hide file tree
Showing 28 changed files with 1,348 additions and 414 deletions.
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ DB_PORT=3306
DB_DATABASE=retroachievements-web
DB_USERNAME=retroachievements
DB_PASSWORD="${DB_USERNAME}"
# TODO remove after utf8mb4 conversion
#DB_CHARSET=latin1
#DB_COLLATION=latin1_general_ci

#LEGACY_MEDIA_PATH=

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/database/*.sql
/docker/nginx/logs
/docs/dist
/node_modules
Expand Down
177 changes: 73 additions & 104 deletions app/Helpers/database/achievement.php
Original file line number Diff line number Diff line change
Expand Up @@ -205,11 +205,6 @@ function UploadNewAchievement(
return false;
}

$dbAuthor = $author;
$rawDesc = $desc;
$rawTitle = $title;
sanitize_sql_inputs($title, $desc, $mem, $progress, $progressMax, $progressFmt, $dbAuthor, $type);

$typeValue = "";
if ($type === null || trim($type) === '' || $type === 'not-given') {
$typeValue = "NULL";
Expand All @@ -226,67 +221,84 @@ function UploadNewAchievement(
return false;
}

$query = "
INSERT INTO Achievements (
ID, GameID, Title, Description,
MemAddr, Progress, ProgressMax,
ProgressFormat, Points, Flags, type,
Author, DateCreated, DateModified,
Updated, VotesPos, VotesNeg,
BadgeName, DisplayOrder, AssocVideo,
TrueRatio
)
VALUES (
NULL, '$gameID', '$title', '$desc',
'$mem', '$progress', '$progressMax',
'$progressFmt', $points, $flag, $typeValue,
'$dbAuthor', NOW(), NOW(),
NOW(), 0, 0,
'$badge', 0, NULL,
0
)";
$db = getMysqliConnection();
if (mysqli_query($db, $query) !== false) {
$idInOut = mysqli_insert_id($db);
postActivity($author, ActivityType::UploadAchievement, $idInOut);

static_addnewachievement($idInOut);
addArticleComment(
"Server",
ArticleType::Achievement,
$idInOut,
"$author uploaded this achievement.",
$author
);

// uploaded new achievement
AchievementCreated::dispatch(Achievement::find($idInOut));

return true;
}
$achievement = new Achievement();
$achievement->GameID = $gameID;
$achievement->Title = $title;
$achievement->Description = $desc;
$achievement->MemAddr = $mem;
$achievement->Points = $points;
$achievement->Flags = $flag;
$achievement->type = ($typeValue == 'NULL') ? null : $type;
$achievement->Author = $author;
$achievement->BadgeName = $badge;

$achievement->save();
$idInOut = $achievement->ID;
postActivity($author, ActivityType::UploadAchievement, $idInOut);

static_addnewachievement($idInOut);
addArticleComment(
"Server",
ArticleType::Achievement,
$idInOut,
"$author uploaded this achievement.",
$author
);

// uploaded new achievement
AchievementCreated::dispatch($achievement);

// failed
return false;
return true;
}

// Achievement being updated
$query = "SELECT Flags, type, MemAddr, Points, Title, Description, BadgeName, Author FROM Achievements WHERE ID='$idInOut'";
$dbResult = s_mysql_query($query);
if ($dbResult !== false && mysqli_num_rows($dbResult) == 1) {
$data = mysqli_fetch_assoc($dbResult);
$achievement = Achievement::find($idInOut);
if ($achievement) {
$fields = [];

$changingPoints = ($achievement->Points != $points);
if ($changingPoints) {
$achievement->Points = $points;
$fields[] = "points";
}

if ($achievement->BadgeName !== $badge) {
$achievement->BadgeName = $badge;
$fields[] = "badge";
}

if ($achievement->Title !== $title) {
$achievement->Title = $title;
$fields[] = "title";
}

if ($achievement->Description !== $desc) {
$achievement->Description = $desc;
$fields[] = "description";
}

$changingType = ($achievement->type != $type && $type !== 'not-given');
if ($changingType) {
$achievement->type = $type;
$fields[] = "type";
}

$changingAchSet = ($data['Flags'] != $flag);
$changingType = ($data['type'] != $type && $type !== 'not-given');
$changingPoints = ($data['Points'] != $points);
$changingTitle = ($data['Title'] !== $rawTitle);
$changingDescription = ($data['Description'] !== $rawDesc);
$changingBadge = ($data['BadgeName'] !== $badge);
$changingLogic = ($data['MemAddr'] != $mem);
$changingLogic = ($achievement->MemAddr != $mem);
if ($changingLogic) {
$achievement->MemAddr = $mem;
$fields[] = "logic";
}

$changingAchSet = ($achievement->Flags != $flag);
if ($changingAchSet) {
$achievement->Flags = $flag;
}

if ($flag === AchievementFlag::OfficialCore || $changingAchSet) { // If modifying core or changing achievement state
// changing ach set detected; user is $author, permissions is $userPermissions, target set is $flag

// Only allow jr. devs to modify core achievements if they are the author and not updating logic or state
if ($userPermissions < Permissions::Developer && ($changingLogic || $changingAchSet || $data['Author'] !== $author)) {
if ($userPermissions < Permissions::Developer && ($changingLogic || $changingAchSet || $achievement->Author !== $author)) {
// Must be developer to modify core logic!
$errorOut = "You must be a developer to perform this action! Please drop a message in the forums to apply.";

Expand All @@ -296,42 +308,21 @@ function UploadNewAchievement(

if ($flag === AchievementFlag::Unofficial) { // If modifying unofficial
// Only allow jr. devs to modify unofficial if they are the author
if ($userPermissions == Permissions::JuniorDeveloper && $data['Author'] !== $author) {
if ($userPermissions == Permissions::JuniorDeveloper && $achievement->Author !== $author) {
$errorOut = "You must be a developer to perform this action! Please drop a message in the forums to apply.";

return false;
}
}

// `null` is a valid type value, so we use a different fallback value.
if ($type === 'not-given' && $data['type'] !== null) {
$typeValue = "'" . $data['type'] . "'";
}

$query = "UPDATE Achievements SET Title='$title', Description='$desc', Progress='$progress', ProgressMax='$progressMax', ProgressFormat='$progressFmt', MemAddr='$mem', Points=$points, Flags=$flag, type=$typeValue, DateModified=NOW(), Updated=NOW(), BadgeName='$badge' WHERE ID=$idInOut";

$db = getMysqliConnection();
if (mysqli_query($db, $query) !== false) {
// if ($changingAchSet || $changingPoints) {
// // When changing achievement set, all existing achievements that rely on this should be purged.
// // $query = "DELETE FROM Awarded WHERE ID='$idInOut'";
// // nah, that's a bit harsh... esp if you're changing something tiny like the badge!!
//
// // if (s_mysql_query($query) !== false) {
// // $rowsAffected = mysqli_affected_rows($db);
// // // great
// // } else {
// // //meh
// // }
// }
if ($achievement->isDirty()) {
$achievement->save();

static_setlastupdatedgame($gameID);
static_setlastupdatedachievement($idInOut);

postActivity($author, ActivityType::EditAchievement, $idInOut);

$achievement = Achievement::find($idInOut);

if ($changingAchSet) {
if ($flag === AchievementFlag::OfficialCore) {
addArticleComment(
Expand All @@ -354,25 +345,6 @@ function UploadNewAchievement(
}
expireGameTopAchievers($gameID);
} else {
$fields = [];
if ($changingPoints) {
$fields[] = "points";
}
if ($changingBadge) {
$fields[] = "badge";
}
if ($changingLogic) {
$fields[] = "logic";
}
if ($changingTitle) {
$fields[] = "title";
}
if ($changingDescription) {
$fields[] = "description";
}
if ($changingType) {
$fields[] = "type";
}
$editString = implode(', ', $fields);

if (!empty($editString)) {
Expand All @@ -392,12 +364,9 @@ function UploadNewAchievement(
if ($changingType) {
AchievementTypeChanged::dispatch($achievement);
}

return true;
}
log_sql_fail();

return false;
return true;
}

return false;
Expand Down
30 changes: 23 additions & 7 deletions app/Helpers/database/set-claim.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use App\Community\Enums\ClaimType;
use App\Community\Models\AchievementSetClaim;
use App\Site\Enums\Permissions;
use App\Support\Cache\CacheKey;
use Carbon\Carbon;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
Expand Down Expand Up @@ -468,23 +469,38 @@ function getExpiringClaim(string $username): array
return [];
}

$cacheKey = CacheKey::buildUserExpiringClaimsCacheKey($username);

$value = Cache::get($cacheKey);
if ($value !== null) {
return $value;
}

$claims = AchievementSetClaim::select(
DB::raw('COALESCE(SUM(CASE WHEN TIMESTAMPDIFF(MINUTE, NOW(), Finished) <= 0 THEN 1 ELSE 0 END), 0) AS Expired'),
DB::raw('COALESCE(SUM(CASE WHEN TIMESTAMPDIFF(MINUTE, NOW(), Finished) BETWEEN 0 AND 10080 THEN 1 ELSE 0 END), 0) AS Expiring')
DB::raw('COALESCE(SUM(CASE WHEN TIMESTAMPDIFF(MINUTE, NOW(), Finished) BETWEEN 0 AND 10080 THEN 1 ELSE 0 END), 0) AS Expiring'),
DB::raw('COUNT(*) AS Count')
)
->where('User', $username)
->whereIn('Status', [ClaimStatus::Active, ClaimStatus::InReview])
->where('Special', '!=', ClaimSpecial::ScheduledRelease)
->first();

if (!$claims) {
return [];
if (!$claims || $claims['Count'] == 0) {
$value = [];
// new claim expiration is 30 days and expiration warning is 7 days, so this guarantees a refresh before expiration
Cache::put($cacheKey, $value, Carbon::now()->addDays(20));
} else {
$value = [
'Expired' => $claims->Expired,
'Expiring' => $claims->Expiring,
];
// refresh once an hour. this query only takes about 2ms, so it's not super expensive, but
// we want to avoid doing it on every page load.
Cache::put($cacheKey, $value, Carbon::now()->addHours(1));
}

return [
'Expired' => $claims->Expired,
'Expiring' => $claims->Expiring,
];
return $value;
}

/**
Expand Down
25 changes: 7 additions & 18 deletions app/Helpers/database/static.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,9 @@
*/
function static_addnewachievement(int $id): void
{
$query = "UPDATE StaticData AS sd ";
$query .= "SET sd.NumAchievements=sd.NumAchievements+1, sd.LastCreatedAchievementID='$id'";
$dbResult = s_mysql_query($query);
if (!$dbResult) {
log_sql_fail();
}
$query = "UPDATE StaticData ";
$query .= "SET NumAchievements=NumAchievements+1, LastCreatedAchievementID=$id";
legacyDbStatement($query);
}

/**
Expand Down Expand Up @@ -113,23 +110,15 @@ function static_setlastearnedachievement(int $id, string $user, int $points): vo
*/
function static_setlastupdatedgame(int $id): void
{
$query = "UPDATE StaticData AS sd ";
$query .= "SET sd.LastUpdatedGameID = '$id'";
$dbResult = s_mysql_query($query);
if (!$dbResult) {
log_sql_fail();
}
$query = "UPDATE StaticData SET LastUpdatedGameID = $id";
legacyDbStatement($query);
}

/**
* @deprecated
*/
function static_setlastupdatedachievement(int $id): void
{
$query = "UPDATE StaticData AS sd ";
$query .= "SET sd.LastUpdatedAchievementID = '$id'";
$dbResult = s_mysql_query($query);
if (!$dbResult) {
log_sql_fail();
}
$query = "UPDATE StaticData SET LastUpdatedAchievementID = $id";
legacyDbStatement($query);
}
Loading

0 comments on commit 0940ea8

Please sign in to comment.