fix(user): serialize level experience awards

This commit is contained in:
2026-07-30 09:44:32 +08:00
parent 20c19dfe31
commit a57b44bd61
+63 -2
View File
@@ -232,6 +232,21 @@ class Level {
* @return int|false Granted amount or false.
*/
public static function add(int $user_id, string $key, int $points = 0, bool $bypass_day_max = false) {
if ($user_id <= 0) {
return false;
}
$lock = self::acquire_lock('user:' . $user_id);
if ($lock === '') {
return false;
}
try {
return self::add_locked($user_id, $key, $points, $bypass_day_max);
} finally {
self::release_lock($lock);
}
}
private static function add_locked(int $user_id, string $key, int $points, bool $bypass_day_max) {
$cfg = self::settings();
$key = sanitize_key($key);
if ($user_id <= 0 || !$cfg['enabled'] || $key === '' || $key === 'day_max') {
@@ -282,10 +297,34 @@ class Level {
return $points;
}
private static function acquire_lock(string $scope): string {
global $wpdb;
$name = substr($wpdb->prefix . 'aksrt_level_' . md5($scope), 0, 64);
$acquired = (int) $wpdb->get_var($wpdb->prepare('SELECT GET_LOCK(%s, %d)', $name, 5));
return $acquired === 1 ? $name : '';
}
private static function release_lock(string $name): void {
global $wpdb;
$wpdb->get_var($wpdb->prepare('SELECT RELEASE_LOCK(%s)', $name));
}
private static function award_once(int $user_id, string $key, string $meta_type, int $entity_id, string $marker, int $limit = 1, int $actor_id = 0): void {
if ($user_id <= 0 || $entity_id <= 0) {
return;
}
$lock = self::acquire_lock($meta_type . ':' . $entity_id . ':' . $marker);
if ($lock === '') {
return;
}
try {
self::award_once_locked($user_id, $key, $meta_type, $entity_id, $marker, $limit, $actor_id);
} finally {
self::release_lock($lock);
}
}
private static function award_once_locked(int $user_id, string $key, string $meta_type, int $entity_id, string $marker, int $limit, int $actor_id): void {
$get = $meta_type === 'comment' ? 'get_comment_meta' : 'get_post_meta';
$update = $meta_type === 'comment' ? 'update_comment_meta' : 'update_post_meta';
$awarded = $get($entity_id, $marker, true);
@@ -310,12 +349,23 @@ class Level {
public function on_login($user_login, $user): void {
$user_id = $user instanceof \WP_User ? (int) $user->ID : 0;
$today = current_time('Ymd');
if ($user_id <= 0 || get_user_meta($user_id, self::META_LOGIN_DAY, true) === $today) {
if ($user_id <= 0) {
return;
}
$lock = self::acquire_lock('login:' . $user_id . ':' . $today);
if ($lock === '') {
return;
}
try {
if (get_user_meta($user_id, self::META_LOGIN_DAY, true) === $today) {
return;
}
if (self::add($user_id, 'sign_in')) {
update_user_meta($user_id, self::META_LOGIN_DAY, $today);
}
} finally {
self::release_lock($lock);
}
}
public function on_checkin(int $user_id): void {
@@ -367,15 +417,26 @@ class Level {
public function on_followed($follower_id, $followed_id): void {
$follower_id = (int) $follower_id;
$followed_id = (int) $followed_id;
if ($follower_id <= 0 || $followed_id <= 0) {
return;
}
$lock = self::acquire_lock('follow:' . $followed_id);
if ($lock === '') {
return;
}
try {
$awarded = get_user_meta($followed_id, self::META_FOLLOWED, true);
$awarded = is_array($awarded) ? array_map('intval', $awarded) : [];
if ($follower_id <= 0 || $followed_id <= 0 || in_array($follower_id, $awarded, true)) {
if (in_array($follower_id, $awarded, true)) {
return;
}
if (self::add($followed_id, 'followed')) {
$awarded[] = $follower_id;
update_user_meta($followed_id, self::META_FOLLOWED, array_values(array_unique($awarded)));
}
} finally {
self::release_lock($lock);
}
}
public function on_post_like($post_id, $user_id, $active = true): void {