You've already forked Atomcms-edit
Initial commit
This commit is contained in:
Executable
+255
@@ -0,0 +1,255 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\Miscellaneous\WebsiteSetting;
|
||||
use App\Models\RadioListenerPoint;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
readonly class PointsService
|
||||
{
|
||||
private const string POINTS_CACHE_KEY = 'user_points_';
|
||||
|
||||
private const string LEADERBOARD_CACHE_KEY = 'radio_leaderboard';
|
||||
|
||||
private const int LEADERBOARD_CACHE_DURATION = 300;
|
||||
|
||||
private const string SETTINGS_CACHE_KEY = 'points_service_settings';
|
||||
|
||||
private const int SETTINGS_CACHE_DURATION = 300;
|
||||
|
||||
private int $pointsPerMinute;
|
||||
|
||||
private int $maxPointsPerDay;
|
||||
|
||||
private int $requestPoints;
|
||||
|
||||
private int $votePoints;
|
||||
|
||||
private int $giveawayWinPoints;
|
||||
|
||||
private int $contestWinPoints;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$settings = $this->getSettings();
|
||||
$this->pointsPerMinute = (int) ($settings['points_per_minute'] ?? 1);
|
||||
$this->maxPointsPerDay = (int) ($settings['max_points_per_day'] ?? 100);
|
||||
$this->requestPoints = (int) ($settings['points_for_request'] ?? 5);
|
||||
$this->votePoints = (int) ($settings['points_for_vote'] ?? 2);
|
||||
$this->giveawayWinPoints = (int) ($settings['points_for_giveaway_win'] ?? 50);
|
||||
$this->contestWinPoints = (int) ($settings['points_for_contest_win'] ?? 100);
|
||||
}
|
||||
|
||||
public function awardPoints(User $user, int $points, string $reason): RadioListenerPoint
|
||||
{
|
||||
$pointRecord = RadioListenerPoint::awardPoints($user, $points, $reason);
|
||||
|
||||
$this->clearUserCache($user->id);
|
||||
$this->clearLeaderboardCache();
|
||||
|
||||
return $pointRecord;
|
||||
}
|
||||
|
||||
public function deductPoints(User $user, int $points, string $reason): RadioListenerPoint
|
||||
{
|
||||
$pointRecord = RadioListenerPoint::deductPoints($user, $points, $reason);
|
||||
|
||||
$this->clearUserCache($user->id);
|
||||
$this->clearLeaderboardCache();
|
||||
|
||||
return $pointRecord;
|
||||
}
|
||||
|
||||
public function getUserPoints(User $user): int
|
||||
{
|
||||
return Cache::remember(self::POINTS_CACHE_KEY . $user->id, 3600, fn (): int => (int) ($user->radio_points ?? 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, array<string, mixed>>
|
||||
*/
|
||||
public function getUserHistory(User $user, int $limit = 50): array
|
||||
{
|
||||
return RadioListenerPoint::where('user_id', $user->id)
|
||||
->orderBy('earned_at', 'desc')
|
||||
->limit($limit)
|
||||
->get()
|
||||
->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, array{rank: int, user_id: int, username: string, avatar: string|null, points: int}>
|
||||
*/
|
||||
public function getLeaderboard(int $limit = 100): array
|
||||
{
|
||||
return Cache::remember(self::LEADERBOARD_CACHE_KEY, self::LEADERBOARD_CACHE_DURATION, function () use ($limit): array {
|
||||
/** @var Collection $collection */
|
||||
$collection = User::where('radio_points', '>', 0)
|
||||
->orderBy('radio_points', 'desc')
|
||||
->limit($limit)
|
||||
->get(['id', 'username', 'avatar', 'radio_points']);
|
||||
|
||||
return $collection->map(fn (User $user, int $index): array => [
|
||||
'rank' => $index + 1,
|
||||
'user_id' => $user->id,
|
||||
'username' => $user->username,
|
||||
'avatar' => $user->avatar ?? null,
|
||||
'points' => (int) $user->radio_points,
|
||||
])->toArray();
|
||||
});
|
||||
}
|
||||
|
||||
public function getWeeklyLeaderboard(int $limit = 50): array
|
||||
{
|
||||
return Cache::remember(self::LEADERBOARD_CACHE_KEY . '_weekly', self::LEADERBOARD_CACHE_DURATION, function () use ($limit) {
|
||||
$weeklyPoints = RadioListenerPoint::where('earned_at', '>=', now()->subWeek())
|
||||
->selectRaw('user_id, SUM(points) as total_points')
|
||||
->groupBy('user_id')
|
||||
->orderBy('total_points', 'desc')
|
||||
->limit($limit)
|
||||
->get();
|
||||
|
||||
$userIds = $weeklyPoints->pluck('user_id')->unique()->values();
|
||||
$users = User::whereIn('id', $userIds)
|
||||
->get(['id', 'username', 'avatar'])
|
||||
->keyBy('id');
|
||||
|
||||
return $weeklyPoints->map(fn (object $item, int $index): array => [
|
||||
'rank' => $index + 1,
|
||||
'user_id' => $item->user_id,
|
||||
'username' => $users[$item->user_id]?->username ?? 'Unknown',
|
||||
'avatar' => $users[$item->user_id]?->avatar ?? null,
|
||||
'points' => $item->total_points,
|
||||
])->toArray();
|
||||
});
|
||||
}
|
||||
|
||||
public function getMonthlyLeaderboard(int $limit = 50): array
|
||||
{
|
||||
return Cache::remember(self::LEADERBOARD_CACHE_KEY . '_monthly', self::LEADERBOARD_CACHE_DURATION, function () use ($limit) {
|
||||
$monthlyPoints = RadioListenerPoint::where('earned_at', '>=', now()->subMonth())
|
||||
->selectRaw('user_id, SUM(points) as total_points')
|
||||
->groupBy('user_id')
|
||||
->orderBy('total_points', 'desc')
|
||||
->limit($limit)
|
||||
->get();
|
||||
|
||||
$userIds = $monthlyPoints->pluck('user_id')->unique()->values();
|
||||
$users = User::whereIn('id', $userIds)
|
||||
->get(['id', 'username', 'avatar'])
|
||||
->keyBy('id');
|
||||
|
||||
return $monthlyPoints->map(fn (object $item, int $index): array => [
|
||||
'rank' => $index + 1,
|
||||
'user_id' => $item->user_id,
|
||||
'username' => $users[$item->user_id]?->username ?? 'Unknown',
|
||||
'avatar' => $users[$item->user_id]?->avatar ?? null,
|
||||
'points' => $item->total_points,
|
||||
])->toArray();
|
||||
});
|
||||
}
|
||||
|
||||
public function getUserRank(User $user): int
|
||||
{
|
||||
/** @var int $count */
|
||||
$count = User::query()
|
||||
->where('radio_points', '>', $user->radio_points ?? 0)
|
||||
->count();
|
||||
|
||||
return $count + 1;
|
||||
}
|
||||
|
||||
public function awardListeningPoints(User $user, int $minutes): int
|
||||
{
|
||||
$todayPoints = RadioListenerPoint::where('user_id', $user->id)
|
||||
->where('earned_at', '>=', now()->startOfDay())
|
||||
->sum('points');
|
||||
|
||||
$availablePoints = max(0, $this->maxPointsPerDay - $todayPoints);
|
||||
$pointsToAward = min($minutes * $this->pointsPerMinute, $availablePoints);
|
||||
|
||||
if ($pointsToAward > 0) {
|
||||
$this->awardPoints($user, $pointsToAward, 'Luisteren');
|
||||
}
|
||||
|
||||
return $pointsToAward;
|
||||
}
|
||||
|
||||
public function awardRequestPoints(User $user): int
|
||||
{
|
||||
$this->awardPoints($user, $this->requestPoints, 'Song Request');
|
||||
|
||||
return $this->requestPoints;
|
||||
}
|
||||
|
||||
public function awardVotePoints(User $user): int
|
||||
{
|
||||
$this->awardPoints($user, $this->votePoints, 'Stemmen op Request');
|
||||
|
||||
return $this->votePoints;
|
||||
}
|
||||
|
||||
public function awardWinPoints(User $user, string $type): int
|
||||
{
|
||||
$winPoints = match ($type) {
|
||||
'giveaway' => $this->giveawayWinPoints,
|
||||
'contest' => $this->contestWinPoints,
|
||||
default => 10,
|
||||
};
|
||||
|
||||
$this->awardPoints($user, $winPoints, 'Winst: ' . $type);
|
||||
|
||||
return $winPoints;
|
||||
}
|
||||
|
||||
private function clearUserCache(int $userId): void
|
||||
{
|
||||
Cache::forget(self::POINTS_CACHE_KEY . $userId);
|
||||
}
|
||||
|
||||
public function clearLeaderboardCache(): void
|
||||
{
|
||||
Cache::forget(self::LEADERBOARD_CACHE_KEY);
|
||||
Cache::forget(self::LEADERBOARD_CACHE_KEY . '_weekly');
|
||||
Cache::forget(self::LEADERBOARD_CACHE_KEY . '_monthly');
|
||||
}
|
||||
|
||||
public function clearSettingsCache(): void
|
||||
{
|
||||
Cache::forget(self::SETTINGS_CACHE_KEY);
|
||||
CacheService::clearPointsSettings();
|
||||
}
|
||||
|
||||
public function getStats(): array
|
||||
{
|
||||
$totalPoints = RadioListenerPoint::sum('points');
|
||||
$totalUsers = User::where('radio_points', '>', 0)->count();
|
||||
|
||||
return [
|
||||
'total_points_awarded' => $totalPoints,
|
||||
'total_active_users' => $totalUsers,
|
||||
'points_per_minute' => $this->pointsPerMinute,
|
||||
'max_points_per_day' => $this->maxPointsPerDay,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string|null>
|
||||
*/
|
||||
private function getSettings(): array
|
||||
{
|
||||
return Cache::remember(self::SETTINGS_CACHE_KEY, self::SETTINGS_CACHE_DURATION, fn (): array => WebsiteSetting::whereIn('key', [
|
||||
'points_per_minute',
|
||||
'max_points_per_day',
|
||||
'points_for_request',
|
||||
'points_for_vote',
|
||||
'points_for_giveaway_win',
|
||||
'points_for_contest_win',
|
||||
])->pluck('value', 'key')->toArray());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user