sdasd
All checks were successful
Deploy / deploy (push) Successful in 54s

This commit is contained in:
2026-08-17 00:34:41 +02:00
parent 0d384cee2d
commit 0f57f90568
9 changed files with 142 additions and 5 deletions

View File

@@ -938,9 +938,23 @@ final class AccountPages
$communityLevelRightDefinitions = Community::membershipRightDefinitions();
$communityRoles = $communityAccess ? $communityAccess->getUserRoles($userId) : [];
$systemRoleAssignments = $communityAccess && $canManageProfileLevels ? $communityAccess->listRoleAssignments() : [];
$recentHighLevelUsers = [];
$recentHighLevelThresholdLabel = '';
$profileLevelUserSearchQuery = '';
$profileLevelUserSearchResults = [];
if ($communityAccess && $community && $canManageProfileLevels) {
$highLevelThreshold = null;
foreach ($communityLevelDefinitions as $levelDefinition) {
if ((string)($levelDefinition['label'] ?? '') === 'Säule der Väter-Community') {
$highLevelThreshold = (float)($levelDefinition['min'] ?? 0.0);
$recentHighLevelThresholdLabel = (string)($levelDefinition['label'] ?? '');
break;
}
}
if ($highLevelThreshold !== null && $highLevelThreshold > 0) {
$recentHighLevelUsers = $community->listRecentlyReachedLevelUsers($highLevelThreshold, 30, 12);
}
$profileLevelUserSearchQuery = trim((string)($_GET['profile_level_user_query'] ?? ''));
if ($profileLevelUserSearchQuery !== '') {
foreach ($communityAccess->searchUsers($profileLevelUserSearchQuery, 12) as $searchRow) {
@@ -1031,6 +1045,8 @@ final class AccountPages
'communityLevelRightDefinitions',
'communityRoles',
'systemRoleAssignments',
'recentHighLevelUsers',
'recentHighLevelThresholdLabel',
'profileLevelUserSearchQuery',
'profileLevelUserSearchResults',
'communityApplication',

View File

@@ -447,6 +447,99 @@ final class Community
return $amount;
}
public function listRecentlyReachedLevelUsers(float $minPoints, int $days = 30, int $limit = 12): array
{
if ($minPoints <= 0) {
return [];
}
$days = max(1, min(365, $days));
$limit = max(1, min(100, $limit));
$cutoff = (new \DateTimeImmutable('today 23:59:59'))->modify('-' . $days . ' days');
$candidateStmt = $this->pdo->prepare(
'SELECT upt.user_id, upt.total, up.display_name, up.first_name, up.last_name
FROM user_points_totals upt
JOIN users u ON u.id = upt.user_id
LEFT JOIN user_profiles up ON up.user_id = upt.user_id
WHERE upt.total >= :minPoints
ORDER BY upt.total DESC, upt.updated_at DESC
LIMIT ' . $limit
);
$candidateStmt->execute(['minPoints' => $minPoints]);
$candidates = $candidateStmt->fetchAll(\PDO::FETCH_ASSOC) ?: [];
if ($candidates === []) {
return [];
}
$candidateIds = array_values(array_map(static fn(array $row): int => (int)($row['user_id'] ?? 0), $candidates));
$candidateIds = array_values(array_filter($candidateIds, static fn(int $id): bool => $id > 0));
if ($candidateIds === []) {
return [];
}
$placeholders = implode(',', array_fill(0, count($candidateIds), '?'));
$pointsStmt = $this->pdo->prepare(
"SELECT user_id, amount, created_at
FROM user_points
WHERE user_id IN ($placeholders)
ORDER BY user_id ASC, created_at ASC, id ASC"
);
$pointsStmt->execute($candidateIds);
$pointRows = $pointsStmt->fetchAll(\PDO::FETCH_ASSOC) ?: [];
$reachedAtByUser = [];
$runningTotals = [];
foreach ($pointRows as $pointRow) {
$entryUserId = (int)($pointRow['user_id'] ?? 0);
if ($entryUserId <= 0) {
continue;
}
$runningTotals[$entryUserId] = ($runningTotals[$entryUserId] ?? 0.0) + (float)($pointRow['amount'] ?? 0.0);
if (isset($reachedAtByUser[$entryUserId])) {
continue;
}
if ($runningTotals[$entryUserId] >= $minPoints) {
$reachedAtByUser[$entryUserId] = (string)($pointRow['created_at'] ?? '');
}
}
$recentUsers = [];
foreach ($candidates as $candidate) {
$candidateUserId = (int)($candidate['user_id'] ?? 0);
$reachedAtRaw = (string)($reachedAtByUser[$candidateUserId] ?? '');
if ($candidateUserId <= 0 || $reachedAtRaw === '') {
continue;
}
try {
$reachedAt = new \DateTimeImmutable($reachedAtRaw);
} catch (\Throwable) {
continue;
}
if ($reachedAt < $cutoff) {
continue;
}
$recentUsers[] = [
'user_id' => $candidateUserId,
'display_name' => (string)($candidate['display_name'] ?? ''),
'first_name' => (string)($candidate['first_name'] ?? ''),
'last_name' => (string)($candidate['last_name'] ?? ''),
'points' => (float)($candidate['total'] ?? 0.0),
'level' => $this->membershipLevel((float)($candidate['total'] ?? 0.0)),
'reached_at' => $reachedAt->format('Y-m-d H:i:s'),
];
}
usort($recentUsers, static function (array $left, array $right): int {
return strcmp((string)($right['reached_at'] ?? ''), (string)($left['reached_at'] ?? ''));
});
return array_slice($recentUsers, 0, $limit);
}
public function membershipLevel(float $points): array
{
$level = $this->membershipLevelMeta($points);

View File

@@ -323,14 +323,15 @@ final class CommunityAccess
WHERE ' . implode(' AND ', $conditions) . '
ORDER BY
CASE
WHEN LOWER(COALESCE(up.display_name, "")) = :exactQuery THEN 0
WHEN LOWER(COALESCE(u.email, "")) = :exactQuery THEN 1
WHEN LOWER(COALESCE(up.display_name, "")) = :exactDisplayQuery THEN 0
WHEN LOWER(COALESCE(u.email, "")) = :exactEmailQuery THEN 1
ELSE 2
END,
COALESCE(up.display_name, ""),
u.id DESC
LIMIT ' . $limit;
$params[':exactQuery'] = mb_strtolower($query);
$params[':exactDisplayQuery'] = mb_strtolower($query);
$params[':exactEmailQuery'] = mb_strtolower($query);
$stmt = $this->pdo->prepare($sql);
$stmt->execute($params);