<?php if (!defined('STORE_ROOT')) { http_response_code(403); exit; } if (!defined('PUBLIC_ROOT') && !defined('DASHBOARD_ROOT')) { http_response_code(403); exit; } class Trust { const DEFAULT_LEVEL = 3; const MAX_LEVEL = 30; const POINTS = [ 'purchase' => 10, 'review' => 5, 'rate_review' => 1, 'referral' => 10, ]; const LEVEL_BUMPS = [ 'purchase' => 1, 'review' => 0, 'rate_review' => 0, 'referral' => 1, ]; public static function getLevel(int $userId): array { $row = DB::one( "SELECT trust_level, trust_points, total_purchases FROM users WHERE id = :id", [':id' => $userId] ); if (!$row) return ['level' => self::DEFAULT_LEVEL, 'points' => 0, 'purchases' => 0, 'max_units' => self::DEFAULT_LEVEL]; $level = max(self::DEFAULT_LEVEL, min(self::MAX_LEVEL, (int)($row['trust_level'] ?? self::DEFAULT_LEVEL))); return [ 'level' => $level, 'points' => (int)($row['trust_points'] ?? 0), 'purchases' => (int)($row['total_purchases'] ?? 0), 'max_units' => $level, ]; } public static function record(int $userId, string $action, ?int $refId = null, ?string $note = null, int $customPoints = 0, int $customDelta = 0): bool { $points = ($action === 'admin_adjust') ? $customPoints : (self::POINTS[$action] ?? 0); $delta = ($action === 'admin_adjust') ? $customDelta : (self::LEVEL_BUMPS[$action] ?? 0); $current = self::getLevel($userId); $newLevel = max(self::DEFAULT_LEVEL, min(self::MAX_LEVEL, $current['level'] + $delta)); $purchaseInc = ($action === 'purchase') ? 1 : 0; DB::run( "UPDATE users SET trust_level = :level, trust_points = trust_points + :points, total_purchases = total_purchases + :pinc WHERE id = :id", [':level' => $newLevel, ':points' => $points, ':pinc' => $purchaseInc, ':id' => $userId] ); DB::run( "INSERT INTO trust_history (user_id, action, points, trust_delta, reference_id, note) VALUES (:uid, :act, :pts, :delta, :ref, :note)", [':uid' => $userId, ':act' => $action, ':pts' => $points, ':delta' => $delta, ':ref' => $refId, ':note' => $note] ); if ($newLevel <= 0) { self::serverBan($userId); } return true; } public static function serverBan(int $userId): void { try { $row = DB::one( "SELECT ip_address FROM sec_visitor_sessions WHERE user_id = :uid ORDER BY last_seen DESC LIMIT 1", [':uid' => $userId] ); if (!$row || empty($row['ip_address'])) return; $ip = $row['ip_address']; DB::run( "INSERT IGNORE INTO blacklist (ip_address, reason, created_at) VALUES (:ip, :reason, NOW())", [':ip' => $ip, ':reason' => "trust_level_zero user_id={$userId}"] ); if (class_exists('ShieldRelay')) { ShieldRelay::exec('filter', "blackhole ban {$ip}", 10); } } catch (\Throwable $e) { } } public static function history(int $userId, int $limit = 20): array { return DB::all( "SELECT action, points, trust_delta, reference_id, note, created_at FROM trust_history WHERE user_id = :uid ORDER BY created_at DESC LIMIT " . (int)$limit, [':uid' => $userId] ); } public static function isExcluded(int $userId): bool { $row = DB::one( "SELECT id FROM self_exclusions WHERE user_id = :uid AND (expires_at IS NULL OR expires_at > NOW()) LIMIT 1", [':uid' => $userId] ); return (bool)$row; } public static function isIpExcluded(string $ip): bool { $row = DB::one( "SELECT id FROM self_exclusions WHERE ip_address = :ip AND (expires_at IS NULL OR expires_at > NOW()) LIMIT 1", [':ip' => $ip] ); return (bool)$row; } public static function selfExclude(?int $userId, string $ip, ?string $reason = null, ?string $duration = null): bool { $expires = null; $days = null; if ($duration === '24h') { $expires = date('Y-m-d H:i:s', strtotime('+24 hours')); $days = 1; } if ($duration === '7d') { $expires = date('Y-m-d H:i:s', strtotime('+7 days')); $days = 7; } if ($duration === '30d') { $expires = date('Y-m-d H:i:s', strtotime('+30 days')); $days = 30; } $ipHash = hash('sha256', $ip); $userAgent = $_SERVER['HTTP_USER_AGENT'] ?? null; DB::run( "INSERT INTO self_exclusions (user_id, ip_address, ip_hash, user_agent, reason, exclusion_type, duration_days, expires_at, created_at)              VALUES (:uid, :ip, :iph, :ua, :reason, 'self_requested', :days, :exp, NOW())              ON DUPLICATE KEY UPDATE expires_at = VALUES(expires_at), duration_days = VALUES(duration_days), reason = VALUES(reason)", [':uid' => $userId, ':ip' => $ip, ':iph' => $ipHash, ':ua' => $userAgent, ':reason' => $reason, ':days' => $days, ':exp' => $expires] ); return true; } } 
