$domains * @return array{risk_score:int,score_modifier:int,signals:array} */ public function assess(?int $userId, array $domains = []): array { if (! $userId) { return ['risk_score' => 0, 'score_modifier' => 0, 'signals' => []]; } $user = User::query()->with('statistics:user_id,uploads_count')->find($userId); if (! $user) { return ['risk_score' => 0, 'score_modifier' => 0, 'signals' => []]; } $summary = ContentModerationFinding::query() ->where('user_id', $userId) ->selectRaw('COUNT(*) as total_findings') ->selectRaw("SUM(CASE WHEN status = ? THEN 1 ELSE 0 END) as confirmed_spam_count", [ModerationStatus::ConfirmedSpam->value]) ->selectRaw("SUM(CASE WHEN status = ? THEN 1 ELSE 0 END) as safe_count", [ModerationStatus::ReviewedSafe->value]) ->selectRaw("SUM(CASE WHEN status = ? THEN 1 ELSE 0 END) as pending_count", [ModerationStatus::Pending->value]) ->first(); $confirmedSpam = (int) ($summary?->confirmed_spam_count ?? 0); $safeCount = (int) ($summary?->safe_count ?? 0); $pendingCount = (int) ($summary?->pending_count ?? 0); $domainRepeatCount = ContentModerationFinding::query() ->where('user_id', $userId) ->whereNotNull('matched_domains_json') ->get(['matched_domains_json']) ->reduce(function (int $carry, ContentModerationFinding $finding) use ($domains): int { return $carry + (empty(array_intersect((array) $finding->matched_domains_json, $domains)) ? 0 : 1); }, 0); $accountAgeDays = max(0, \now()->diffInDays($user->created_at)); $uploadsCount = (int) ($user->statistics?->uploads_count ?? 0); $riskScore = 0; $riskScore += $confirmedSpam * 18; $riskScore += $pendingCount * 5; $riskScore += min(20, $domainRepeatCount * 6); $riskScore -= min(18, $safeCount * 4); $riskScore -= $accountAgeDays >= 365 ? 8 : ($accountAgeDays >= 90 ? 4 : 0); $riskScore -= $uploadsCount >= 25 ? 6 : ($uploadsCount >= 10 ? 3 : 0); $riskScore = max(0, min(100, $riskScore)); $modifier = 0; if ($riskScore >= 75) { $modifier = (int) \app('config')->get('content_moderation.user_risk.high_modifier', 18); } elseif ($riskScore >= 50) { $modifier = (int) \app('config')->get('content_moderation.user_risk.medium_modifier', 10); } elseif ($riskScore >= 25) { $modifier = (int) \app('config')->get('content_moderation.user_risk.low_modifier', 4); } elseif ($riskScore <= 5 && $accountAgeDays >= 180 && $uploadsCount >= 10) { $modifier = (int) \app('config')->get('content_moderation.user_risk.trusted_modifier', -6); } elseif ($riskScore <= 12 && $safeCount >= 2) { $modifier = -3; } return [ 'risk_score' => $riskScore, 'score_modifier' => $modifier, 'signals' => [ 'confirmed_spam_count' => $confirmedSpam, 'safe_count' => $safeCount, 'pending_count' => $pendingCount, 'domain_repeat_count' => $domainRepeatCount, 'account_age_days' => $accountAgeDays, 'uploads_count' => $uploadsCount, ], ]; } }