* @copyright 2025-2026 Vateron Media * @link https://github.com/Vateron-Media/XC_VM * @license AGPL-3.0 https://www.gnu.org/licenses/agpl-3.0.html */ class ResellerTableRenderer { /** * Render a reseller DataTables view for the requested type. * * Dispatches to the matching private handler based on the request type. * * @param array $rReturn DataTables request payload. * @param bool $rIsAPI Whether the request came via the API. * @param array|null $rUserInfo Authenticated reseller user (or null). * @param array $rPermissions Effective permissions. * @param array $rSettings Panel settings. * @return void */ public static function render(array $rReturn, bool $rIsAPI, ?array $rUserInfo, array $rPermissions, array $rSettings): void { global $db; if (!isset($rUserInfo['reports'])) { echo json_encode($rReturn); exit(); } $rType = RequestManager::getAll()['id']; $rStart = intval(RequestManager::getAll()['start']); $rLimit = intval(RequestManager::getAll()['length']); if (1000 < $rLimit || $rLimit <= 0) { $rLimit = 1000; } switch ($rType) { case 'lines': self::handleLines($rReturn, $rIsAPI, $rUserInfo, $rPermissions, $rSettings, $db, $rStart, $rLimit); break; case 'mags': self::handleMags($rReturn, $rIsAPI, $rUserInfo, $rPermissions, $rSettings, $db, $rStart, $rLimit); break; case 'enigmas': self::handleEnigmas($rReturn, $rIsAPI, $rUserInfo, $rPermissions, $rSettings, $db, $rStart, $rLimit); break; case 'streams': self::handleStreams($rReturn, $rIsAPI, $rUserInfo, $rPermissions, $rSettings, $db, $rStart, $rLimit); break; case 'radios': self::handleRadios($rReturn, $rIsAPI, $rUserInfo, $rPermissions, $rSettings, $db, $rStart, $rLimit); break; case 'movies': self::handleMovies($rReturn, $rIsAPI, $rUserInfo, $rPermissions, $rSettings, $db, $rStart, $rLimit); break; case 'episodes': self::handleEpisodes($rReturn, $rIsAPI, $rUserInfo, $rPermissions, $rSettings, $db, $rStart, $rLimit); break; case 'line_activity': self::handleLineActivity($rReturn, $rIsAPI, $rUserInfo, $rPermissions, $rSettings, $db, $rStart, $rLimit); break; case 'live_connections': self::handleLiveConnections($rReturn, $rIsAPI, $rUserInfo, $rPermissions, $rSettings, $db, $rStart, $rLimit); break; case 'reg_user_logs': self::handleRegUserLogs($rReturn, $rIsAPI, $rUserInfo, $rPermissions, $rSettings, $db, $rStart, $rLimit); break; case 'reg_users': self::handleRegUsers($rReturn, $rIsAPI, $rUserInfo, $rPermissions, $rSettings, $db, $rStart, $rLimit); break; } } /** * Render the reseller "lines" table. * * @param array $rReturn DataTables request/response payload. * @param bool $rIsAPI Whether the request came via the API. * @param array $rUserInfo Authenticated reseller user. * @param array $rPermissions Effective permissions. * @param array $rSettings Panel settings. * @param \XcVm\Core\Database\DatabaseHandler $db Database handler. * @param int $rStart Pagination offset. * @param int $rLimit Page size. * @return void */ private static function handleLines(array $rReturn, bool $rIsAPI, array $rUserInfo, array $rPermissions, array $rSettings, $db, int $rStart, int $rLimit): void { if (!$rPermissions['create_line']) { exit(); } $rOrderBy = ''; $rOrder = array('`lines`.`id`', '`lines`.`username`', '`lines`.`password`', '`users`.`username`', '`lines`.`enabled` - `lines`.`admin_enabled`', '`active_connections` > 0', '`lines`.`is_trial`', '`active_connections`', '`lines`.`max_connections`', '`lines`.`exp_date`', '`last_activity`', false); if (isset(RequestManager::getAll()['order']) && 0 < strlen(RequestManager::getAll()['order'][0]['column'])) { $rOrderRow = intval(RequestManager::getAll()['order'][0]['column']); } else { $rOrderRow = 0; } $rWhere = $rWhereV = array(); $rWhere[] = '`lines`.`is_mag` = 0 AND `lines`.`is_e2` = 0'; $rWhere[] = '`lines`.`member_id` IN (' . implode(',', $rUserInfo['reports']) . ')'; if (0 >= strlen(RequestManager::getAll()['search']['value'])) { } else { foreach (range(1, 6) as $rInt) { $rWhereV[] = '%' . RequestManager::getAll()['search']['value'] . '%'; } $rWhere[] = '(`lines`.`username` LIKE ? OR `lines`.`password` LIKE ? OR `users`.`username` LIKE ? OR FROM_UNIXTIME(`exp_date`) LIKE ? OR `lines`.`max_connections` LIKE ? OR `lines`.`reseller_notes` LIKE ?)'; } if (0 >= strlen(RequestManager::getAll()['filter'])) { } else { if (RequestManager::getAll()['filter'] == 1) { $rWhere[] = '(`lines`.`admin_enabled` = 1 AND `lines`.`enabled` = 1 AND (`lines`.`exp_date` IS NULL OR `lines`.`exp_date` > UNIX_TIMESTAMP()))'; } else { if (RequestManager::getAll()['filter'] == 2) { $rWhere[] = '`lines`.`enabled` = 0'; } else { if (RequestManager::getAll()['filter'] == 3) { $rWhere[] = '`lines`.`admin_enabled` = 0'; } else { if (RequestManager::getAll()['filter'] == 4) { $rWhere[] = '(`lines`.`exp_date` IS NOT NULL AND `lines`.`exp_date` <= UNIX_TIMESTAMP())'; } else { if (RequestManager::getAll()['filter'] != 5) { } else { $rWhere[] = '`lines`.`is_trial` = 1'; } } } } } } if (0 >= strlen(RequestManager::getAll()['reseller'])) { } else { $rWhere[] = '`lines`.`member_id` = ?'; $rWhereV[] = RequestManager::getAll()['reseller']; } if (0 < count($rWhere)) { $rWhereString = 'WHERE ' . implode(' AND ', $rWhere); } else { $rWhereString = ''; } $rCountQuery = 'SELECT COUNT(`lines`.`id`) AS `count` FROM `lines` LEFT JOIN `users` ON `users`.`id` = `lines`.`member_id` ' . $rWhereString . ';'; if (!$rOrder[$rOrderRow]) { } else { $rOrderDirection = (strtolower(RequestManager::getAll()['order'][0]['dir']) === 'desc' ? 'desc' : 'asc'); $rOrderBy = 'ORDER BY ' . $rOrder[$rOrderRow] . ' ' . $rOrderDirection; } $db->query($rCountQuery, ...$rWhereV); if ($db->num_rows() == 1) { $rReturn['recordsTotal'] = $db->get_row()['count']; } else { $rReturn['recordsTotal'] = 0; } $rReturn['recordsFiltered'] = $rReturn['recordsTotal']; if (0 >= $rReturn['recordsTotal']) { } else { $rQuery = 'SELECT `lines`.`id`, `lines`.`member_id`, `lines`.`last_activity`, `lines`.`last_activity_array`, `lines`.`username`, `lines`.`password`, `lines`.`exp_date`, `lines`.`admin_enabled`, `lines`.`is_restreamer`, `lines`.`enabled`, `lines`.`admin_notes`, `lines`.`reseller_notes`, `lines`.`max_connections`, `lines`.`is_trial`, `lines`.`contact`, `lines`.`is_isplock`, (SELECT COUNT(*) AS `active_connections` FROM `lines_live` WHERE `user_id` = `lines`.`id` AND `hls_end` = 0) AS `active_connections` FROM `lines` LEFT JOIN `users` ON `users`.`id` = `lines`.`member_id` ' . $rWhereString . ' ' . $rOrderBy . ' LIMIT ' . $rStart . ', ' . $rLimit . ';'; $db->query($rQuery, ...$rWhereV); if (0 >= $db->num_rows()) { } else { $rRows = $db->get_rows(); $rActivityIDs = $rLineInfo = $rLineIDs = array(); foreach ($rRows as $rRow) { $rLineIDs[] = intval($rRow['id']); $rLineInfo[intval($rRow['id'])] = array('owner_name' => null, 'stream_display_name' => null, 'stream_id' => null, 'last_active' => null); if ($rLastInfo = json_decode($rRow['last_activity_array'], true)) { $rLineInfo[intval($rRow['id'])]['stream_id'] = $rLastInfo['stream_id']; $rLineInfo[intval($rRow['id'])]['last_active'] = $rLastInfo['date_end']; } else { if (!$rRow['last_activity']) { } else { $rActivityIDs[] = intval($rRow['last_activity']); } } } if (0 >= count($rLineIDs)) { } else { $db->query('SELECT `users`.`username`, `lines`.`id` FROM `users` LEFT JOIN `lines` ON `lines`.`member_id` = `users`.`id` WHERE `lines`.`id` IN (' . implode(',', $rLineIDs) . ');'); foreach ($db->get_rows() as $rRow) { $rLineInfo[$rRow['id']]['owner_name'] = $rRow['username']; } if (SettingsManager::getAll()['redis_handler']) { $rConnectionCount = array(); $rConnectionMap = ConnectionTracker::getUserConnections($rLineIDs, false); $rStreamIDs = array(); foreach ($rConnectionMap as $rUserID => $rConnections) { foreach ($rConnections as $rConnection) { if (in_array($rConnection['stream_id'], $rStreamIDs)) { } else { $rStreamIDs[] = intval($rConnection['stream_id']); } } } $rStreamMap = array(); if (0 >= count($rStreamIDs)) { } else { $db->query('SELECT `id`, `stream_display_name` FROM `streams` WHERE `id` IN (' . implode(',', $rStreamIDs) . ');'); foreach ($db->get_rows() as $rRow) { $rStreamMap[$rRow['id']] = $rRow['stream_display_name']; } } foreach (array_keys($rConnectionMap) as $rUserID) { $rDates = array_column($rConnectionMap[$rUserID], 'date_start'); if (count($rDates) === count($rConnectionMap[$rUserID])) { array_multisort($rDates, SORT_DESC, $rConnectionMap[$rUserID]); } $rLineInfo[$rUserID]['stream_display_name'] = $rStreamMap[$rConnectionMap[$rUserID][0]['stream_id']]; $rLineInfo[$rUserID]['stream_id'] = $rConnectionMap[$rUserID][0]['stream_id']; $rLineInfo[$rUserID]['last_active'] = $rConnectionMap[$rUserID][0]['date_start']; $rConnectionCount[$rUserID] = count($rConnectionMap[$rUserID]); } unset($rConnectionMap); } else { $db->query('SELECT `lines_live`.`user_id`, `lines_live`.`stream_id`, `lines_live`.`date_start` AS `last_active`, `streams`.`stream_display_name` FROM `lines_live` LEFT JOIN `streams` ON `streams`.`id` = `lines_live`.`stream_id` INNER JOIN (SELECT `user_id`, MAX(`date_start`) AS `ts` FROM `lines_live` GROUP BY `user_id`) `maxt` ON (`lines_live`.`user_id` = `maxt`.`user_id` AND `lines_live`.`date_start` = `maxt`.`ts`) WHERE `lines_live`.`user_id` IN (' . implode(',', $rLineIDs) . ');'); foreach ($db->get_rows() as $rRow) { $rLineInfo[$rRow['user_id']]['stream_display_name'] = $rRow['stream_display_name']; $rLineInfo[$rRow['user_id']]['stream_id'] = $rRow['stream_id']; $rLineInfo[$rRow['user_id']]['last_active'] = $rRow['last_active']; } } } if (0 >= count($rActivityIDs)) { } else { $db->query('SELECT `user_id`, `stream_id`, `date_end` AS `last_active` FROM `lines_activity` WHERE `activity_id` IN (' . implode(',', $rActivityIDs) . ');'); foreach ($db->get_rows() as $rRow) { if (isset($rLineInfo[$rRow['user_id']]['stream_id'])) { } else { $rLineInfo[$rRow['user_id']]['stream_id'] = $rRow['stream_id']; $rLineInfo[$rRow['user_id']]['last_active'] = $rRow['last_active']; } } } foreach ($rRows as $rRow) { $rRow = array_merge($rRow, $rLineInfo[$rRow['id']]); if (!SettingsManager::getAll()['redis_handler']) { } else { $rRow['active_connections'] = (isset($rConnectionCount[$rRow['id']]) ? $rConnectionCount[$rRow['id']] : 0); } if (!$rIsAPI) { if (!$rRow['admin_enabled']) { $rStatus = ''; } else { if (!$rRow['enabled']) { $rStatus = ''; } else { if ($rRow['exp_date'] && $rRow['exp_date'] < time()) { $rStatus = ''; } else { $rStatus = ''; } } } if (0 < $rRow['active_connections']) { $rActive = ''; } else { $rActive = ''; } if ($rRow['is_trial']) { $rTrial = ''; } else { $rTrial = ''; } if ($rRow['exp_date']) { if ($rRow['exp_date'] < time()) { $rExpDate = '' . date($rSettings['date_format'], $rRow['exp_date']) . '
' . date('H:i:s', $rRow['exp_date']) . '
'; } else { $rExpDate = date($rSettings['date_format'], $rRow['exp_date']) . "
" . date('H:i:s', $rRow['exp_date']) . ''; } } else { $rExpDate = '∞'; } if (0 < $rRow['active_connections']) { if ($rPermissions['reseller_client_connection_logs']) { $rActiveConnections = "'; } else { $rActiveConnections = "'; } } else { $rActiveConnections = ""; } if ($rRow['max_connections'] == 0) { $rMaxConnections = ""; } else { $rMaxConnections = "'; } $rButtons = '
'; $rNotes = ''; if (0 >= strlen($rRow['reseller_notes'])) { } else { if (strlen($rNotes) == 0) { } else { $rNotes .= "\n"; } $rNotes .= $rRow['reseller_notes']; } if (0 < strlen($rNotes)) { $rButtons .= ''; } else { $rButtons .= ''; } $rButtons .= ''; if (!$rPermissions['allow_download']) { } else { $rButtons .= ""; } $rWhatsAppContact = !empty($rRow['contact']) ? addslashes($rRow['contact']) : ''; $rWhatsAppExp = $rRow['exp_date'] ? $rRow['exp_date'] : 'null'; $rButtons .= ""; if (!$rPermissions['reseller_client_connection_logs']) { } else { if (0 < $rRow['active_connections']) { $rButtons .= '"; } else { $rButtons .= ''; } } if (!$rRow['is_isplock']) { } else { $rButtons .= '"; } if ($rRow['enabled']) { $rButtons .= '"; } else { $rButtons .= '"; } $rButtons .= '"; $rButtons .= '
'; if ($rRow['active_connections'] && $rRow['last_active']) { $rLastActive = "" . $rRow['stream_display_name'] . "
Online: " . TimeUtils::secondsToTime(time() - $rRow['last_active']) . ''; } else { if ($rRow['last_active']) { $rLastActive = date($rSettings['date_format'], $rRow['last_active']) . "
" . date('H:i:s', $rRow['last_active']) . ''; } else { $rLastActive = 'Never'; } } if (in_array($rRow['member_id'], array_merge($rPermissions['direct_reports'], array($rUserInfo['id'])))) { $rOwner = "" . $rRow['owner_name'] . ''; } else { $rOwner = "" . $rRow['owner_name'] . "
(indirect)
"; } $rReturn['data'][] = array("" . $rRow['id'] . '', "" . $rRow['username'] . '', $rRow['password'], $rOwner, $rStatus, $rActive, $rTrial, $rActiveConnections, $rMaxConnections, $rExpDate, $rLastActive, $rButtons); } else { $rReturn['data'][] = self::filterRow($rRow, RequestManager::getAll()['show_columns'], RequestManager::getAll()['hide_columns']); } } } } echo json_encode($rReturn); exit(); } /** * Render the reseller "MAG devices" table. * * @param array $rReturn DataTables request/response payload. * @param bool $rIsAPI Whether the request came via the API. * @param array $rUserInfo Authenticated reseller user. * @param array $rPermissions Effective permissions. * @param array $rSettings Panel settings. * @param \XcVm\Core\Database\DatabaseHandler $db Database handler. * @param int $rStart Pagination offset. * @param int $rLimit Page size. * @return void */ private static function handleMags(array $rReturn, bool $rIsAPI, array $rUserInfo, array $rPermissions, array $rSettings, $db, int $rStart, int $rLimit): void { if (!$rPermissions['create_mag']) { exit(); } $rOrderBy = ''; $rOrder = array('`lines`.`id`', '`lines`.`username`', '`mag_devices`.`mac`', '`mag_devices`.`stb_type`', '`users`.`username`', '`lines`.`enabled`', '`active_connections`', '`lines`.`is_trial`', '`lines`.`exp_date`', false); if (isset(RequestManager::getAll()['order']) && 0 < strlen(RequestManager::getAll()['order'][0]['column'])) { $rOrderRow = intval(RequestManager::getAll()['order'][0]['column']); } else { $rOrderRow = 0; } $rWhere = $rWhereV = array(); $rWhere[] = '`lines`.`member_id` IN (' . implode(',', $rUserInfo['reports']) . ')'; if (0 >= strlen(RequestManager::getAll()['search']['value'])) { } else { foreach (range(1, 6) as $rInt) { $rWhereV[] = '%' . RequestManager::getAll()['search']['value'] . '%'; } $rWhere[] = '(`lines`.`username` LIKE ? OR `mag_devices`.`mac` LIKE ? OR `mag_devices`.`stb_type` LIKE ? OR `users`.`username` LIKE ? OR FROM_UNIXTIME(`exp_date`) LIKE ? OR `lines`.`reseller_notes` LIKE ?)'; } if (0 >= strlen(RequestManager::getAll()['filter'])) { } else { if (RequestManager::getAll()['filter'] == 1) { $rWhere[] = '(`lines`.`admin_enabled` = 1 AND `lines`.`enabled` = 1 AND (`lines`.`exp_date` IS NULL OR `lines`.`exp_date` > UNIX_TIMESTAMP()))'; } else { if (RequestManager::getAll()['filter'] == 2) { $rWhere[] = '`lines`.`enabled` = 0'; } else { if (RequestManager::getAll()['filter'] == 3) { $rWhere[] = '(`lines`.`exp_date` IS NOT NULL AND `lines`.`exp_date` <= UNIX_TIMESTAMP())'; } else { if (RequestManager::getAll()['filter'] != 4) { } else { $rWhere[] = '`lines`.`is_trial` = 1'; } } } } } if (0 >= strlen(RequestManager::getAll()['reseller'])) { } else { $rWhere[] = '`lines`.`member_id` = ?'; $rWhereV[] = RequestManager::getAll()['reseller']; } if (0 < count($rWhere)) { $rWhereString = 'WHERE ' . implode(' AND ', $rWhere); } else { $rWhereString = ''; } if (!$rOrder[$rOrderRow]) { } else { $rOrderDirection = (strtolower(RequestManager::getAll()['order'][0]['dir']) === 'desc' ? 'desc' : 'asc'); $rOrderBy = 'ORDER BY ' . $rOrder[$rOrderRow] . ' ' . $rOrderDirection; } $rCountQuery = 'SELECT COUNT(`lines`.`id`) AS `count` FROM `lines` LEFT JOIN `users` ON `users`.`id` = `lines`.`member_id` INNER JOIN `mag_devices` ON `mag_devices`.`user_id` = `lines`.`id` ' . $rWhereString . ';'; $db->query($rCountQuery, ...$rWhereV); if ($db->num_rows() == 1) { $rReturn['recordsTotal'] = $db->get_row()['count']; } else { $rReturn['recordsTotal'] = 0; } $rReturn['recordsFiltered'] = $rReturn['recordsTotal']; if (0 >= $rReturn['recordsTotal']) { } else { $rQuery = 'SELECT `lines`.`id`, `lines`.`username`, `lines`.`member_id`, `lines`.`is_isplock`, `mag_devices`.`mac`, `mag_devices`.`stb_type`, `mag_devices`.`mag_id`, `lines`.`exp_date`, `lines`.`admin_enabled`, `lines`.`enabled`, `lines`.`reseller_notes`, `lines`.`max_connections`, `lines`.`is_trial`, `users`.`username` AS `owner_name`, (SELECT count(*) FROM `lines_live` WHERE `lines`.`id` = `lines_live`.`user_id` AND `hls_end` = 0) AS `active_connections` FROM `lines` LEFT JOIN `users` ON `users`.`id` = `lines`.`member_id` INNER JOIN `mag_devices` ON `mag_devices`.`user_id` = `lines`.`id` ' . $rWhereString . ' ' . $rOrderBy . ' LIMIT ' . $rStart . ', ' . $rLimit . ';'; $db->query($rQuery, ...$rWhereV); if (0 >= $db->num_rows()) { } else { $rRows = $db->get_rows(); $rLineIDs = array(); foreach ($rRows as $rRow) { if (!$rRow['id']) { } else { $rLineIDs[] = intval($rRow['id']); } } if (0 >= count($rLineIDs)) { } else { if (!SettingsManager::getAll()['redis_handler']) { } else { $rConnectionCount = array(); $rConnectionMap = ConnectionTracker::getUserConnections($rLineIDs, false); foreach (array_keys($rConnectionMap) as $rUserID) { $rConnectionCount[$rUserID] = count($rConnectionMap[$rUserID]); } unset($rConnectionMap); } } foreach ($rRows as $rRow) { if (!SettingsManager::getAll()['redis_handler']) { } else { $rRow['active_connections'] = (isset($rConnectionCount[$rRow['id']]) ? $rConnectionCount[$rRow['id']] : 0); } if (!$rIsAPI) { if (!$rRow['admin_enabled']) { $rStatus = ''; } else { if (!$rRow['enabled']) { $rStatus = ''; } else { if ($rRow['exp_date'] && $rRow['exp_date'] < time()) { $rStatus = ''; } else { $rStatus = ''; } } } if (0 < $rRow['active_connections']) { $rActive = ''; } else { $rActive = ''; } if ($rRow['is_trial']) { $rTrial = ''; } else { $rTrial = ''; } if ($rRow['exp_date']) { if ($rRow['exp_date'] < time()) { $rExpDate = '' . date($rSettings['date_format'], $rRow['exp_date']) . '
' . date('H:i:s', $rRow['exp_date']) . '
'; } else { $rExpDate = date($rSettings['date_format'], $rRow['exp_date']) . "
" . date('H:i:s', $rRow['exp_date']) . ''; } } else { $rExpDate = '∞'; } $rButtons = '
'; $rNotes = ''; if (0 >= strlen($rRow['reseller_notes'])) { } else { if (strlen($rNotes) == 0) { } else { $rNotes .= "\n"; } $rNotes .= $rRow['reseller_notes']; } if (0 < strlen($rNotes)) { $rButtons .= ''; } else { $rButtons .= ''; } $rButtons .= '"; $rButtons .= ''; if (!$rRow['is_isplock']) { } else { $rButtons .= '"; } if (!$rPermissions['create_line']) { } else { $rButtons .= '"; } if (!$rPermissions['reseller_client_connection_logs']) { } else { if (0 < $rRow['active_connections']) { $rButtons .= '"; } else { $rButtons .= ''; } } if ($rRow['enabled'] == 1) { $rButtons .= '"; } else { $rButtons .= '"; } $rButtons .= '"; $rButtons .= '
'; if (in_array($rRow['member_id'], array_merge($rPermissions['direct_reports'], array($rUserInfo['id'])))) { $rOwner = "" . $rRow['owner_name'] . ''; } else { $rOwner = "" . $rRow['owner_name'] . "
(indirect)
"; } $rReturn['data'][] = array("" . $rRow['mag_id'] . '', $rRow['username'], "" . $rRow['mac'] . '', $rRow['stb_type'], $rOwner, $rStatus, $rActive, $rTrial, $rExpDate, $rButtons); } else { $rReturn['data'][] = self::filterRow($rRow, RequestManager::getAll()['show_columns'], RequestManager::getAll()['hide_columns']); } } } } echo json_encode($rReturn); exit(); } /** * Render the reseller "Enigma2 devices" table. * * @param array $rReturn DataTables request/response payload. * @param bool $rIsAPI Whether the request came via the API. * @param array $rUserInfo Authenticated reseller user. * @param array $rPermissions Effective permissions. * @param array $rSettings Panel settings. * @param \XcVm\Core\Database\DatabaseHandler $db Database handler. * @param int $rStart Pagination offset. * @param int $rLimit Page size. * @return void */ private static function handleEnigmas(array $rReturn, bool $rIsAPI, array $rUserInfo, array $rPermissions, array $rSettings, $db, int $rStart, int $rLimit): void { if (!$rPermissions['create_enigma']) { exit(); } $rOrderBy = ''; $rOrder = array('`lines`.`id`', '`lines`.`username`', '`enigma2_devices`.`mac`', '`enigma2_devices`.`public_ip`', '`users`.`username`', '`lines`.`enabled`', '`active_connections`', '`lines`.`is_trial`', '`lines`.`exp_date`', false); if (isset(RequestManager::getAll()['order']) && 0 < strlen(RequestManager::getAll()['order'][0]['column'])) { $rOrderRow = intval(RequestManager::getAll()['order'][0]['column']); } else { $rOrderRow = 0; } $rWhere = $rWhereV = array(); $rWhere[] = '`lines`.`member_id` IN (' . implode(',', $rUserInfo['reports']) . ')'; if (0 >= strlen(RequestManager::getAll()['search']['value'])) { } else { foreach (range(1, 6) as $rInt) { $rWhereV[] = '%' . RequestManager::getAll()['search']['value'] . '%'; } $rWhere[] = '(`lines`.`username` LIKE ? OR `enigma2_devices`.`mac` LIKE ? OR `enigma2_devices`.`public_ip` LIKE ? OR `users`.`username` LIKE ? OR FROM_UNIXTIME(`exp_date`) LIKE ? OR `lines`.`reseller_notes` LIKE ?)'; } if (0 >= strlen(RequestManager::getAll()['filter'])) { } else { if (RequestManager::getAll()['filter'] == 1) { $rWhere[] = '(`lines`.`admin_enabled` = 1 AND `lines`.`enabled` = 1 AND (`lines`.`exp_date` IS NULL OR `lines`.`exp_date` > UNIX_TIMESTAMP()))'; } else { if (RequestManager::getAll()['filter'] == 2) { $rWhere[] = '`lines`.`enabled` = 0'; } else { if (RequestManager::getAll()['filter'] == 3) { $rWhere[] = '(`lines`.`exp_date` IS NOT NULL AND `lines`.`exp_date` <= UNIX_TIMESTAMP())'; } else { if (RequestManager::getAll()['filter'] != 4) { } else { $rWhere[] = '`lines`.`is_trial` = 1'; } } } } } if (0 >= strlen(RequestManager::getAll()['reseller'])) { } else { $rWhere[] = '`lines`.`member_id` = ?'; $rWhereV[] = RequestManager::getAll()['reseller']; } if (0 < count($rWhere)) { $rWhereString = 'WHERE ' . implode(' AND ', $rWhere); } else { $rWhereString = ''; } if (!$rOrder[$rOrderRow]) { } else { $rOrderDirection = (strtolower(RequestManager::getAll()['order'][0]['dir']) === 'desc' ? 'desc' : 'asc'); $rOrderBy = 'ORDER BY ' . $rOrder[$rOrderRow] . ' ' . $rOrderDirection; } $rCountQuery = 'SELECT COUNT(`lines`.`id`) AS `count` FROM `lines` LEFT JOIN `users` ON `users`.`id` = `lines`.`member_id` INNER JOIN `enigma2_devices` ON `enigma2_devices`.`user_id` = `lines`.`id` ' . $rWhereString . ';'; $db->query($rCountQuery, ...$rWhereV); if ($db->num_rows() == 1) { $rReturn['recordsTotal'] = $db->get_row()['count']; } else { $rReturn['recordsTotal'] = 0; } $rReturn['recordsFiltered'] = $rReturn['recordsTotal']; if (0 >= $rReturn['recordsTotal']) { } else { $rQuery = 'SELECT `lines`.`id`, `lines`.`username`, `lines`.`member_id`, `lines`.`is_isplock`, `enigma2_devices`.`mac`, `enigma2_devices`.`public_ip`, `enigma2_devices`.`device_id`, `lines`.`exp_date`, `lines`.`admin_enabled`, `lines`.`enabled`, `lines`.`reseller_notes`, `lines`.`max_connections`, `lines`.`is_trial`, `users`.`username` AS `owner_name`, (SELECT count(*) FROM `lines_live` WHERE `lines`.`id` = `lines_live`.`user_id` AND `hls_end` = 0) AS `active_connections` FROM `lines` LEFT JOIN `users` ON `users`.`id` = `lines`.`member_id` INNER JOIN `enigma2_devices` ON `enigma2_devices`.`user_id` = `lines`.`id` ' . $rWhereString . ' ' . $rOrderBy . ' LIMIT ' . $rStart . ', ' . $rLimit . ';'; $db->query($rQuery, ...$rWhereV); if (0 >= $db->num_rows()) { } else { $rRows = $db->get_rows(); $rLineIDs = array(); foreach ($rRows as $rRow) { if (!$rRow['id']) { } else { $rLineIDs[] = intval($rRow['id']); } } if (0 >= count($rLineIDs)) { } else { if (!SettingsManager::getAll()['redis_handler']) { } else { $rConnectionCount = array(); $rConnectionMap = ConnectionTracker::getUserConnections($rLineIDs, false); foreach (array_keys($rConnectionMap) as $rUserID) { $rConnectionCount[$rUserID] = count($rConnectionMap[$rUserID]); } unset($rConnectionMap); } } foreach ($rRows as $rRow) { if (!SettingsManager::getAll()['redis_handler']) { } else { $rRow['active_connections'] = (isset($rConnectionCount[$rRow['id']]) ? $rConnectionCount[$rRow['id']] : 0); } if (!$rIsAPI) { if (!$rRow['admin_enabled']) { $rStatus = ''; } else { if (!$rRow['enabled']) { $rStatus = ''; } else { if ($rRow['exp_date'] && $rRow['exp_date'] < time()) { $rStatus = ''; } else { $rStatus = ''; } } } if (0 < $rRow['active_connections']) { $rActive = ''; } else { $rActive = ''; } if ($rRow['is_trial']) { $rTrial = ''; } else { $rTrial = ''; } if ($rRow['exp_date']) { if ($rRow['exp_date'] < time()) { $rExpDate = '' . date($rSettings['date_format'], $rRow['exp_date']) . '
' . date('H:i:s', $rRow['exp_date']) . '
'; } else { $rExpDate = date($rSettings['date_format'], $rRow['exp_date']) . "
" . date('H:i:s', $rRow['exp_date']) . ''; } } else { $rExpDate = '∞'; } $rButtons = '
'; $rNotes = ''; if (0 >= strlen($rRow['reseller_notes'])) { } else { if (strlen($rNotes) == 0) { } else { $rNotes .= "\n"; } $rNotes .= $rRow['reseller_notes']; } if (0 < strlen($rNotes)) { $rButtons .= ''; } else { $rButtons .= ''; } $rButtons .= ''; if (!$rRow['is_isplock']) { } else { $rButtons .= '"; } if (!$rPermissions['create_line']) { } else { $rButtons .= '"; } if (!$rPermissions['reseller_client_connection_logs']) { } else { if (0 < $rRow['active_connections']) { $rButtons .= '"; } else { $rButtons .= ''; } } if ($rRow['enabled'] == 1) { $rButtons .= '"; } else { $rButtons .= '"; } $rButtons .= '"; $rButtons .= '
'; if (in_array($rRow['member_id'], array_merge($rPermissions['direct_reports'], array($rUserInfo['id'])))) { $rOwner = "" . $rRow['owner_name'] . ''; } else { $rOwner = "" . $rRow['owner_name'] . "
(indirect)
"; } $rReturn['data'][] = array("" . $rRow['device_id'] . '', $rRow['username'], "" . $rRow['mac'] . '', "" . $rRow['public_ip'] . '', $rOwner, $rStatus, $rActive, $rTrial, $rExpDate, $rButtons); } else { $rReturn['data'][] = self::filterRow($rRow, RequestManager::getAll()['show_columns'], RequestManager::getAll()['hide_columns']); } } } } echo json_encode($rReturn); exit(); } /** * Render the reseller "streams" table. * * @param array $rReturn DataTables request/response payload. * @param bool $rIsAPI Whether the request came via the API. * @param array $rUserInfo Authenticated reseller user. * @param array $rPermissions Effective permissions. * @param array $rSettings Panel settings. * @param \XcVm\Core\Database\DatabaseHandler $db Database handler. * @param int $rStart Pagination offset. * @param int $rLimit Page size. * @return void */ private static function handleStreams(array $rReturn, bool $rIsAPI, array $rUserInfo, array $rPermissions, array $rSettings, $db, int $rStart, int $rLimit): void { if (!$rPermissions['can_view_vod']) { exit(); } $rCategories = CategoryService::getAllByType('live'); $rOrderBy = ''; $rOrder = array('`id`', false, '`stream_display_name`', '`category_id`', '`clients`', false); if (isset(RequestManager::getAll()['order']) && 0 < strlen(RequestManager::getAll()['order'][0]['column'])) { $rOrderRow = intval(RequestManager::getAll()['order'][0]['column']); } else { $rOrderRow = 0; } $rCreated = isset(RequestManager::getAll()['created']); $rWhere = $rWhereV = array(); if (0 < count($rPermissions['stream_ids'])) { $rWhere[] = '`streams`.`id` IN (' . implode(',', array_map('intval', $rPermissions['stream_ids'])) . ')'; if ($rCreated) { $rWhere[] = '`type` = 3'; } else { $rWhere[] = '`type` = 1'; } if (0 >= strlen(RequestManager::getAll()['search']['value'])) { } else { foreach (range(1, 2) as $rInt) { $rWhereV[] = '%' . RequestManager::getAll()['search']['value'] . '%'; } $rWhere[] = '(`id` LIKE ? OR `stream_display_name` LIKE ?)'; } if (0 >= strlen(RequestManager::getAll()['category'])) { } else { $rWhere[] = "JSON_CONTAINS(`category_id`, ?, '\$')"; $rWhereV[] = RequestManager::getAll()['category']; } if (!$rOrder[$rOrderRow]) { } else { $rOrderDirection = (strtolower(RequestManager::getAll()['order'][0]['dir']) === 'desc' ? 'desc' : 'asc'); $rOrderBy = 'ORDER BY ' . $rOrder[$rOrderRow] . ' ' . $rOrderDirection; } if (0 < count($rWhere)) { $rWhereString = 'WHERE ' . implode(' AND ', $rWhere); } else { $rWhereString = ''; } $rCountQuery = 'SELECT COUNT(`streams`.`id`) AS `count` FROM `streams` ' . $rWhereString . ';'; $db->query($rCountQuery, ...$rWhereV); if ($db->num_rows() == 1) { $rReturn['recordsTotal'] = $db->get_row()['count']; } else { $rReturn['recordsTotal'] = 0; } $rReturn['recordsFiltered'] = $rReturn['recordsTotal']; if (0 >= $rReturn['recordsTotal']) { } else { $rQuery = 'SELECT `id`, `stream_icon`, `stream_display_name`, `tv_archive_duration`, `tv_archive_server_id`, `category_id`, (SELECT COUNT(*) FROM `lines_live` LEFT JOIN `lines` ON `lines`.`id` = `lines_live`.`user_id` WHERE `lines_live`.`stream_id` = `streams`.`id` AND `hls_end` = 0 AND `lines`.`member_id` IN (' . implode(',', $rUserInfo['reports']) . ')) AS `clients` FROM `streams` ' . $rWhereString . ' ' . $rOrderBy . ' LIMIT ' . $rStart . ', ' . $rLimit . ';'; $db->query($rQuery, ...$rWhereV); if ($db->num_rows() > 0) { $rRows = $db->get_rows(); if (SettingsManager::getAll()['redis_handler']) { $rConnectionCount = $rReports = array(); $db->query('SELECT `id` FROM `lines` WHERE `member_id` IN (' . implode(',', $rUserInfo['reports']) . ');'); foreach ($db->get_rows() as $rRow) { $rReports[] = $rRow['id']; } if (0 >= count($rReports)) { } else { foreach (ConnectionTracker::getUserConnections($rReports, false) as $rUserID => $rConnections) { foreach ($rConnections as $rConnection) { $rConnectionCount[$rConnection['stream_id']]++; } } } } foreach ($rRows as $rRow) { if (!SettingsManager::getAll()['redis_handler']) { } else { $rRow['clients'] = ($rConnectionCount[$rRow['id']] ?: 0); } if (!$rIsAPI) { $rCategoryIDs = json_decode($rRow['category_id'], true); if (0 < strlen(RequestManager::getAll()['category'])) { $rCategory = ($rCategories[intval(RequestManager::getAll()['category'])]['category_name'] ?: 'No Category'); } else { $rCategory = ($rCategories[$rCategoryIDs[0]]['category_name'] ?: 'No Category'); } if (1 >= count($rCategoryIDs)) { } else { $rCategory .= ' (+' . (count($rCategoryIDs) - 1) . ' others)'; } if (!(0 < $rRow['tv_archive_duration'] && 0 < $rRow['tv_archive_server_id'])) { } else { $rRow['stream_display_name'] .= " "; } if (0 < $rRow['clients']) { if ($rPermissions['reseller_client_connection_logs']) { $rButtons = '"; $rClients = "'; } else { $rButtons = ''; $rClients = "'; } } else { $rButtons = ''; $rClients = ""; } if (0 < strlen($rRow['stream_icon'])) { $rIcon = ""; } else { $rIcon = ''; } $rReturn['data'][] = array($rRow['id'], $rIcon, $rRow['stream_display_name'], $rCategory, $rClients, $rButtons); } else { $rReturn['data'][] = self::filterRow($rRow, RequestManager::getAll()['show_columns'], RequestManager::getAll()['hide_columns']); } } } } echo json_encode($rReturn); exit(); } echo json_encode($rReturn); exit(); } /** * Render the reseller "radios" table. * * @param array $rReturn DataTables request/response payload. * @param bool $rIsAPI Whether the request came via the API. * @param array $rUserInfo Authenticated reseller user. * @param array $rPermissions Effective permissions. * @param array $rSettings Panel settings. * @param \XcVm\Core\Database\DatabaseHandler $db Database handler. * @param int $rStart Pagination offset. * @param int $rLimit Page size. * @return void */ private static function handleRadios(array $rReturn, bool $rIsAPI, array $rUserInfo, array $rPermissions, array $rSettings, $db, int $rStart, int $rLimit): void { if (!$rPermissions['can_view_vod']) { exit(); } $rCategories = CategoryService::getAllByType('radio'); $rOrderBy = ''; $rOrder = array('`id`', false, '`stream_display_name`', '`category_id`', '`clients`', false); if (isset(RequestManager::getAll()['order']) && 0 < strlen(RequestManager::getAll()['order'][0]['column'])) { $rOrderRow = intval(RequestManager::getAll()['order'][0]['column']); } else { $rOrderRow = 0; } $rCreated = isset(RequestManager::getAll()['created']); $rWhere = $rWhereV = array(); if (0 < count($rPermissions['stream_ids'])) { $rWhere[] = '`streams`.`id` IN (' . implode(',', array_map('intval', $rPermissions['stream_ids'])) . ')'; $rWhere[] = '`type` = 4'; if (0 >= strlen(RequestManager::getAll()['search']['value'])) { } else { foreach (range(1, 2) as $rInt) { $rWhereV[] = '%' . RequestManager::getAll()['search']['value'] . '%'; } $rWhere[] = '(`id` LIKE ? OR `stream_display_name` LIKE ?)'; } if (0 >= strlen(RequestManager::getAll()['category'])) { } else { $rWhere[] = "JSON_CONTAINS(`category_id`, ?, '\$')"; $rWhereV[] = RequestManager::getAll()['category']; } if (!$rOrder[$rOrderRow]) { } else { $rOrderDirection = (strtolower(RequestManager::getAll()['order'][0]['dir']) === 'desc' ? 'desc' : 'asc'); $rOrderBy = 'ORDER BY ' . $rOrder[$rOrderRow] . ' ' . $rOrderDirection; } if (0 < count($rWhere)) { $rWhereString = 'WHERE ' . implode(' AND ', $rWhere); } else { $rWhereString = ''; } $rCountQuery = 'SELECT COUNT(`streams`.`id`) AS `count` FROM `streams` ' . $rWhereString . ';'; $db->query($rCountQuery, ...$rWhereV); if ($db->num_rows() == 1) { $rReturn['recordsTotal'] = $db->get_row()['count']; } else { $rReturn['recordsTotal'] = 0; } $rReturn['recordsFiltered'] = $rReturn['recordsTotal']; if (0 >= $rReturn['recordsTotal']) { } else { $rQuery = 'SELECT `id`, `stream_icon`, `stream_display_name`, `category_id`, (SELECT COUNT(*) FROM `lines_live` LEFT JOIN `lines` ON `lines`.`id` = `lines_live`.`user_id` WHERE `lines_live`.`stream_id` = `streams`.`id` AND `hls_end` = 0 AND `lines`.`member_id` IN (' . implode(',', $rUserInfo['reports']) . ')) AS `clients` FROM `streams` ' . $rWhereString . ' ' . $rOrderBy . ' LIMIT ' . $rStart . ', ' . $rLimit . ';'; $db->query($rQuery, ...$rWhereV); if (0 >= $db->num_rows()) { } else { $rRows = $db->get_rows(); if (!SettingsManager::getAll()['redis_handler']) { } else { $rConnectionCount = $rReports = array(); $db->query('SELECT `id` FROM `lines` WHERE `member_id` IN (' . implode(',', $rUserInfo['reports']) . ');'); foreach ($db->get_rows() as $rRow) { $rReports[] = $rRow['id']; } if (0 >= count($rReports)) { } else { foreach (ConnectionTracker::getUserConnections($rReports, false) as $rUserID => $rConnections) { foreach ($rConnections as $rConnection) { $rConnectionCount[$rConnection['stream_id']]++; } } } } foreach ($rRows as $rRow) { if (!SettingsManager::getAll()['redis_handler']) { } else { $rRow['clients'] = ($rConnectionCount[$rRow['id']] ?: 0); } if (!$rIsAPI) { $rCategoryIDs = json_decode($rRow['category_id'], true); if (0 < strlen(RequestManager::getAll()['category'])) { $rCategory = ($rCategories[intval(RequestManager::getAll()['category'])]['category_name'] ?: 'No Category'); } else { $rCategory = ($rCategories[$rCategoryIDs[0]]['category_name'] ?: 'No Category'); } if (1 >= count($rCategoryIDs)) { } else { $rCategory .= ' (+' . (count($rCategoryIDs) - 1) . ' others)'; } if (0 < $rRow['clients']) { if ($rPermissions['reseller_client_connection_logs']) { $rButtons = '"; $rClients = "'; } else { $rButtons = ''; $rClients = "'; } } else { $rButtons = ''; $rClients = ""; } if (0 < strlen($rRow['stream_icon'])) { $rIcon = ""; } else { $rIcon = ''; } $rReturn['data'][] = array($rRow['id'], $rIcon, $rRow['stream_display_name'], $rCategory, $rClients, $rButtons); } else { $rReturn['data'][] = self::filterRow($rRow, RequestManager::getAll()['show_columns'], RequestManager::getAll()['hide_columns']); } } } } echo json_encode($rReturn); exit(); } echo json_encode($rReturn); exit(); } /** * Render the reseller "movies" table. * * @param array $rReturn DataTables request/response payload. * @param bool $rIsAPI Whether the request came via the API. * @param array $rUserInfo Authenticated reseller user. * @param array $rPermissions Effective permissions. * @param array $rSettings Panel settings. * @param \XcVm\Core\Database\DatabaseHandler $db Database handler. * @param int $rStart Pagination offset. * @param int $rLimit Page size. * @return void */ private static function handleMovies(array $rReturn, bool $rIsAPI, array $rUserInfo, array $rPermissions, array $rSettings, $db, int $rStart, int $rLimit): void { if (!$rPermissions['can_view_vod']) { exit(); } $rCategories = CategoryService::getAllByType('movie'); $rOrderBy = ''; $rOrder = array('`id`', false, '`stream_display_name`', '`category_id`', '`clients`', false); if (isset(RequestManager::getAll()['order']) && 0 < strlen(RequestManager::getAll()['order'][0]['column'])) { $rOrderRow = intval(RequestManager::getAll()['order'][0]['column']); } else { $rOrderRow = 0; } $rCreated = isset(RequestManager::getAll()['created']); $rWhere = $rWhereV = array(); if (0 < count($rPermissions['stream_ids'])) { $rWhere[] = '`streams`.`id` IN (' . implode(',', array_map('intval', $rPermissions['stream_ids'])) . ')'; $rWhere[] = '`type` = 2'; if (0 >= strlen(RequestManager::getAll()['search']['value'])) { } else { foreach (range(1, 2) as $rInt) { $rWhereV[] = '%' . RequestManager::getAll()['search']['value'] . '%'; } $rWhere[] = '(`id` LIKE ? OR `stream_display_name` LIKE ?)'; } if (0 >= strlen(RequestManager::getAll()['category'])) { } else { $rWhere[] = "JSON_CONTAINS(`category_id`, ?, '\$')"; $rWhereV[] = RequestManager::getAll()['category']; } if (!$rOrder[$rOrderRow]) { } else { $rOrderDirection = (strtolower(RequestManager::getAll()['order'][0]['dir']) === 'desc' ? 'desc' : 'asc'); $rOrderBy = 'ORDER BY ' . $rOrder[$rOrderRow] . ' ' . $rOrderDirection; } if (0 < count($rWhere)) { $rWhereString = 'WHERE ' . implode(' AND ', $rWhere); } else { $rWhereString = ''; } $rCountQuery = 'SELECT COUNT(`streams`.`id`) AS `count` FROM `streams` ' . $rWhereString . ';'; $db->query($rCountQuery, ...$rWhereV); if ($db->num_rows() == 1) { $rReturn['recordsTotal'] = $db->get_row()['count']; } else { $rReturn['recordsTotal'] = 0; } $rReturn['recordsFiltered'] = $rReturn['recordsTotal']; if (0 >= $rReturn['recordsTotal']) { } else { $rQuery = 'SELECT `id`, `stream_icon`, `stream_display_name`, `movie_properties`, `category_id`, (SELECT COUNT(*) FROM `lines_live` LEFT JOIN `lines` ON `lines`.`id` = `lines_live`.`user_id` WHERE `lines_live`.`stream_id` = `streams`.`id` AND `hls_end` = 0 AND `lines`.`member_id` IN (' . implode(',', $rUserInfo['reports']) . ')) AS `clients` FROM `streams` ' . $rWhereString . ' ' . $rOrderBy . ' LIMIT ' . $rStart . ', ' . $rLimit . ';'; $db->query($rQuery, ...$rWhereV); if (0 >= $db->num_rows()) { } else { $rRows = $db->get_rows(); if (!SettingsManager::getAll()['redis_handler']) { } else { $rConnectionCount = $rReports = array(); $db->query('SELECT `id` FROM `lines` WHERE `member_id` IN (' . implode(',', $rUserInfo['reports']) . ');'); foreach ($db->get_rows() as $rRow) { $rReports[] = $rRow['id']; } if (0 >= count($rReports)) { } else { foreach (ConnectionTracker::getUserConnections($rReports, false) as $rUserID => $rConnections) { foreach ($rConnections as $rConnection) { $rConnectionCount[$rConnection['stream_id']]++; } } } } foreach ($rRows as $rRow) { if (!SettingsManager::getAll()['redis_handler']) { } else { $rRow['clients'] = ($rConnectionCount[$rRow['id']] ?: 0); } if (!$rIsAPI) { $rCategoryIDs = json_decode($rRow['category_id'], true); if (0 < strlen(RequestManager::getAll()['category'])) { $rCategory = ($rCategories[intval(RequestManager::getAll()['category'])]['category_name'] ?: 'No Category'); } else { $rCategory = ($rCategories[$rCategoryIDs[0]]['category_name'] ?: 'No Category'); } if (1 >= count($rCategoryIDs)) { } else { $rCategory .= ' (+' . (count($rCategoryIDs) - 1) . ' others)'; } if (0 < $rRow['clients']) { if ($rPermissions['reseller_client_connection_logs']) { $rButtons = '"; $rClients = "'; } else { $rButtons = ''; $rClients = "'; } } else { $rButtons = ''; $rClients = ""; } $rProperties = json_decode($rRow['movie_properties'], true); if (0 < strlen($rProperties['movie_image'])) { $rImage = ""; } else { $rImage = ''; } $rReturn['data'][] = array($rRow['id'], $rImage, $rRow['stream_display_name'], $rCategory, $rClients, $rButtons); } else { $rReturn['data'][] = self::filterRow($rRow, RequestManager::getAll()['show_columns'], RequestManager::getAll()['hide_columns']); } } } } echo json_encode($rReturn); exit(); } echo json_encode($rReturn); exit(); } /** * Render the reseller "episodes" table. * * @param array $rReturn DataTables request/response payload. * @param bool $rIsAPI Whether the request came via the API. * @param array $rUserInfo Authenticated reseller user. * @param array $rPermissions Effective permissions. * @param array $rSettings Panel settings. * @param \XcVm\Core\Database\DatabaseHandler $db Database handler. * @param int $rStart Pagination offset. * @param int $rLimit Page size. * @return void */ private static function handleEpisodes(array $rReturn, bool $rIsAPI, array $rUserInfo, array $rPermissions, array $rSettings, $db, int $rStart, int $rLimit): void { if (!$rPermissions['can_view_vod']) { exit(); } $rCategories = CategoryService::getAllByType('series'); $rOrderBy = ''; $rOrder = array('`id`', false, '`stream_display_name`', '`category_id`', '`clients`', false); if (isset(RequestManager::getAll()['order']) && 0 < strlen(RequestManager::getAll()['order'][0]['column'])) { $rOrderRow = intval(RequestManager::getAll()['order'][0]['column']); } else { $rOrderRow = 0; } $rCreated = isset(RequestManager::getAll()['created']); $rWhere = $rWhereV = array(); if (0 < count($rPermissions['stream_ids'])) { $rWhere[] = '`streams`.`id` IN (' . implode(',', array_map('intval', $rPermissions['stream_ids'])) . ')'; $rWhere[] = '`type` = 5'; if (0 >= strlen(RequestManager::getAll()['search']['value'])) { } else { foreach (range(1, 3) as $rInt) { $rWhereV[] = '%' . RequestManager::getAll()['search']['value'] . '%'; } $rWhere[] = '(`streams`.`id` LIKE ? OR `stream_display_name` LIKE ? OR `streams_series`.`title` LIKE ?)'; } if (0 >= strlen(RequestManager::getAll()['category'])) { } else { $rWhere[] = "JSON_CONTAINS(`streams_series`.`category_id`, ?, '\$')"; $rWhereV[] = RequestManager::getAll()['category']; } if (0 >= strlen(RequestManager::getAll()['series'])) { } else { $rWhere[] = '`streams_series`.`id` = ?'; $rWhereV[] = RequestManager::getAll()['series']; } if (!$rOrder[$rOrderRow]) { } else { $rOrderDirection = (strtolower(RequestManager::getAll()['order'][0]['dir']) === 'desc' ? 'desc' : 'asc'); $rOrderBy = 'ORDER BY ' . $rOrder[$rOrderRow] . ' ' . $rOrderDirection; } if (0 < count($rWhere)) { $rWhereString = 'WHERE ' . implode(' AND ', $rWhere); } else { $rWhereString = ''; } $rCountQuery = 'SELECT COUNT(`streams`.`id`) AS `count` FROM `streams` LEFT JOIN `streams_episodes` ON `streams_episodes`.`stream_id` = `streams`.`id` LEFT JOIN `streams_series` ON `streams_series`.`id` = `streams_episodes`.`series_id` ' . $rWhereString . ';'; $db->query($rCountQuery, ...$rWhereV); if ($db->num_rows() == 1) { $rReturn['recordsTotal'] = $db->get_row()['count']; } else { $rReturn['recordsTotal'] = 0; } $rReturn['recordsFiltered'] = $rReturn['recordsTotal']; if (0 >= $rReturn['recordsTotal']) { } else { $rQuery = 'SELECT `streams`.`id`, `stream_icon`, `stream_display_name`, `movie_properties`, `streams_series`.`category_id`, `streams_series`.`title`, `streams_episodes`.`season_num`, (SELECT COUNT(*) FROM `lines_live` LEFT JOIN `lines` ON `lines`.`id` = `lines_live`.`user_id` WHERE `lines_live`.`stream_id` = `streams`.`id` AND `hls_end` = 0 AND `lines`.`member_id` IN (' . implode(',', $rUserInfo['reports']) . ')) AS `clients` FROM `streams` LEFT JOIN `streams_episodes` ON `streams_episodes`.`stream_id` = `streams`.`id` LEFT JOIN `streams_series` ON `streams_series`.`id` = `streams_episodes`.`series_id` ' . $rWhereString . ' ' . $rOrderBy . ' LIMIT ' . $rStart . ', ' . $rLimit . ';'; $db->query($rQuery, ...$rWhereV); if (0 >= $db->num_rows()) { } else { $rRows = $db->get_rows(); if (!SettingsManager::getAll()['redis_handler']) { } else { $rConnectionCount = $rReports = array(); $db->query('SELECT `id` FROM `lines` WHERE `member_id` IN (' . implode(',', $rUserInfo['reports']) . ');'); foreach ($db->get_rows() as $rRow) { $rReports[] = $rRow['id']; } if (0 >= count($rReports)) { } else { foreach (ConnectionTracker::getUserConnections($rReports, false) as $rUserID => $rConnections) { foreach ($rConnections as $rConnection) { $rConnectionCount[$rConnection['stream_id']]++; } } } } foreach ($rRows as $rRow) { if (!SettingsManager::getAll()['redis_handler']) { } else { $rRow['clients'] = ($rConnectionCount[$rRow['id']] ?: 0); } if (!$rIsAPI) { $rSeriesName = $rRow['title'] . ' - Season ' . $rRow['season_num']; $rStreamName = '' . $rRow['stream_display_name'] . "
" . $rSeriesName . ''; $rCategoryIDs = json_decode($rRow['category_id'], true); if (0 < strlen(RequestManager::getAll()['category'])) { $rCategory = ($rCategories[intval(RequestManager::getAll()['category'])]['category_name'] ?: 'No Category'); } else { $rCategory = ($rCategories[$rCategoryIDs[0]]['category_name'] ?: 'No Category'); } if (1 >= count($rCategoryIDs)) { } else { $rCategory .= ' (+' . (count($rCategoryIDs) - 1) . ' others)'; } if (0 < $rRow['clients']) { if ($rPermissions['reseller_client_connection_logs']) { $rButtons = '"; $rClients = "'; } else { $rButtons = ''; $rClients = "'; } } else { $rButtons = ''; $rClients = ""; } $rProperties = json_decode($rRow['movie_properties'], true); if (0 < strlen($rProperties['movie_image'])) { $rImage = ""; } else { $rImage = ''; } $rReturn['data'][] = array($rRow['id'], $rImage, $rStreamName, $rCategory, $rClients, $rButtons); } else { $rReturn['data'][] = self::filterRow($rRow, RequestManager::getAll()['show_columns'], RequestManager::getAll()['hide_columns']); } } } } echo json_encode($rReturn); exit(); } echo json_encode($rReturn); exit(); } /** * Render the reseller "line activity" table. * * @param array $rReturn DataTables request/response payload. * @param bool $rIsAPI Whether the request came via the API. * @param array $rUserInfo Authenticated reseller user. * @param array $rPermissions Effective permissions. * @param array $rSettings Panel settings. * @param \XcVm\Core\Database\DatabaseHandler $db Database handler. * @param int $rStart Pagination offset. * @param int $rLimit Page size. * @return void */ private static function handleLineActivity(array $rReturn, bool $rIsAPI, array $rUserInfo, array $rPermissions, array $rSettings, $db, int $rStart, int $rLimit): void { if (!$rPermissions['reseller_client_connection_logs']) { exit(); } $rOrderBy = ''; $rOrder = array('`username`', '`streams`.`stream_display_name`', '`lines_activity`.`user_agent`', '`lines_activity`.`isp`', '`lines_activity`.`user_ip`', '`lines_activity`.`date_start`', '`lines_activity`.`date_end`', '`lines_activity`.`date_end` - `lines_activity`.`date_start`', '`lines_activity`.`container`'); if (isset(RequestManager::getAll()['order']) && 0 < strlen(RequestManager::getAll()['order'][0]['column'])) { $rOrderRow = intval(RequestManager::getAll()['order'][0]['column']); } else { $rOrderRow = 0; } $rWhere = $rWhereV = array(); $rWhere[] = '`lines`.`member_id` IN (' . implode(',', $rUserInfo['reports']) . ')'; if (0 >= strlen(RequestManager::getAll()['search']['value'])) { } else { foreach (range(1, 10) as $rInt) { $rWhereV[] = '%' . RequestManager::getAll()['search']['value'] . '%'; } $rWhere[] = '(`lines_activity`.`user_agent` LIKE ? OR `lines_activity`.`user_ip` LIKE ? OR `lines_activity`.`container` LIKE ? OR FROM_UNIXTIME(`lines_activity`.`date_start`) LIKE ? OR FROM_UNIXTIME(`lines_activity`.`date_end`) LIKE ? OR `lines_activity`.`geoip_country_code` LIKE ? OR `lines`.`username` LIKE ? OR `mag_devices`.`mac` LIKE ? OR `enigma2_devices`.`mac` LIKE ? OR `streams`.`stream_display_name` LIKE ?)'; } if (0 >= strlen(RequestManager::getAll()['range'])) { } else { $rStartTime = substr(RequestManager::getAll()['range'], 0, 10); $rEndTime = substr(RequestManager::getAll()['range'], strlen(RequestManager::getAll()['range']) - 10, 10); if ($rStartTime = strtotime($rStartTime . ' 00:00:00')) { } else { $rStartTime = null; } if ($rEndTime = strtotime($rEndTime . ' 23:59:59')) { } else { $rEndTime = null; } if (!($rStartTime && $rEndTime)) { } else { $rWhere[] = '(`lines_activity`.`date_start` >= ? AND `lines_activity`.`date_end` <= ?)'; $rWhereV[] = $rStartTime; $rWhereV[] = $rEndTime; } } if (0 >= strlen(RequestManager::getAll()['stream'])) { } else { $rWhere[] = '`lines_activity`.`stream_id` = ?'; $rWhereV[] = RequestManager::getAll()['stream']; } if (0 >= strlen(RequestManager::getAll()['user'])) { } else { $rWhere[] = '`lines`.`member_id` = ?'; $rWhereV[] = RequestManager::getAll()['user']; } if (0 >= strlen(RequestManager::getAll()['line'])) { } else { $rWhere[] = '`lines_activity`.`user_id` = ?'; $rWhereV[] = RequestManager::getAll()['line']; } if (0 < count($rWhere)) { $rWhereString = 'WHERE ' . implode(' AND ', $rWhere); } else { $rWhereString = ''; } if (!$rOrder[$rOrderRow]) { } else { $rOrderDirection = (strtolower(RequestManager::getAll()['order'][0]['dir']) === 'desc' ? 'desc' : 'asc'); $rOrderBy = 'ORDER BY ' . $rOrder[$rOrderRow] . ' ' . $rOrderDirection; } $rCountQuery = 'SELECT COUNT(*) AS `count` FROM `lines_activity` LEFT JOIN `lines` ON `lines_activity`.`user_id` = `lines`.`id` LEFT JOIN `streams` ON `lines_activity`.`stream_id` = `streams`.`id` LEFT JOIN `mag_devices` ON `mag_devices`.`user_id` = `lines_activity`.`user_id` LEFT JOIN `enigma2_devices` ON `enigma2_devices`.`user_id` = `lines_activity`.`user_id` ' . $rWhereString . ';'; $db->query($rCountQuery, ...$rWhereV); if ($db->num_rows() == 1) { $rReturn['recordsTotal'] = $db->get_row()['count']; } else { $rReturn['recordsTotal'] = 0; } $rReturn['recordsFiltered'] = $rReturn['recordsTotal']; if (0 >= $rReturn['recordsTotal']) { } else { $rQuery = 'SELECT `mag_devices`.`mag_id`, `enigma2_devices`.`device_id`, `lines`.`is_e2`, `lines`.`is_mag`, `lines_activity`.`activity_id`, `lines_activity`.`container`, `lines_activity`.`isp`, `lines_activity`.`user_id`, `lines_activity`.`stream_id`, `streams`.`series_no`, `lines_activity`.`server_id`, `lines_activity`.`user_agent`, `lines_activity`.`user_ip`, `lines_activity`.`container`, `lines_activity`.`date_start`, `lines_activity`.`date_end`, `lines_activity`.`geoip_country_code`, IF(`lines`.`is_mag`, `mag_devices`.`mac`, IF(`lines`.`is_e2`, `enigma2_devices`.`mac`, `lines`.`username`)) AS `username`, `streams`.`stream_display_name`, `streams`.`type`, `lines`.`is_restreamer` FROM `lines_activity` LEFT JOIN `lines` ON `lines_activity`.`user_id` = `lines`.`id` LEFT JOIN `streams` ON `lines_activity`.`stream_id` = `streams`.`id` LEFT JOIN `mag_devices` ON `mag_devices`.`user_id` = `lines_activity`.`user_id` LEFT JOIN `enigma2_devices` ON `enigma2_devices`.`user_id` = `lines_activity`.`user_id` ' . $rWhereString . ' ' . $rOrderBy . ' LIMIT ' . $rStart . ', ' . $rLimit . ';'; $db->query($rQuery, ...$rWhereV); if (0 >= $db->num_rows()) { } else { foreach ($db->get_rows() as $rRow) { if (!$rIsAPI) { if ($rRow['is_mag']) { $rUsername = "" . $rRow['username'] . ''; } else { if ($rRow['is_e2']) { $rUsername = "" . $rRow['username'] . ''; } else { $rUsername = "" . $rRow['username'] . ''; } } $rChannel = $rRow['stream_display_name']; if (0 < strlen($rRow['geoip_country_code'])) { $rGeoCountry = "  "; } else { $rGeoCountry = ''; } if ($rRow['user_ip']) { $rIP = $rGeoCountry . "" . $rRow['user_ip'] . ''; } else { $rIP = ''; } if ($rRow['date_start']) { $rStart = date($rSettings['datetime_format'], $rRow['date_start']); } else { $rStart = ''; } if ($rRow['date_end']) { $rStop = date($rSettings['datetime_format'], $rRow['date_end']); } else { $rStop = ''; } $rPlayer = trim(explode('(', $rRow['user_agent'])[0]); $rDuration = $rRow['date_end'] - $rRow['date_start']; $rColour = 'success'; if (86400 <= $rDuration) { $rDuration = sprintf('%02dd %02dh', $rDuration / 86400, ($rDuration / 3600) % 24); $rColour = 'danger'; } else { if (3600 <= $rDuration) { if (14400 < $rDuration) { $rColour = 'warning'; } else { if (43200 >= $rDuration) { } else { $rColour = 'danger'; } } $rDuration = sprintf('%02dh %02dm', $rDuration / 3600, ($rDuration / 60) % 60); } else { $rDuration = sprintf('%02dm %02ds', ($rDuration / 60) % 60, $rDuration % 60); } } $rDuration = "'; $rReturn['data'][] = array($rUsername, $rChannel, $rPlayer, $rRow['isp'], $rIP, $rStart, $rStop, $rDuration, strtoupper($rRow['container'])); } else { $rReturn['data'][] = self::filterRow($rRow, RequestManager::getAll()['show_columns'], RequestManager::getAll()['hide_columns']); } } } } echo json_encode($rReturn); exit(); } /** * Render the reseller "live connections" table. * * @param array $rReturn DataTables payload (by reference). * @param bool $rIsAPI Whether the request came via the API. * @param array $rUserInfo Authenticated reseller user. * @param array $rPermissions Effective permissions. * @param array $rSettings Panel settings. * @param \XcVm\Core\Database\DatabaseHandler $db Database handler. * @param int $rStart Pagination offset. * @param int $rLimit Page size. * @return void */ private static function handleLiveConnections(array &$rReturn, bool $rIsAPI, array $rUserInfo, array $rPermissions, array $rSettings, $db, int $rStart, int $rLimit): void { if (!$rPermissions['reseller_client_connection_logs']) { exit(); } $rOrderBy = ''; $rRows = array(); if (SettingsManager::getAll()['redis_handler']) { $rOrderDirection = (strtolower(RequestManager::getAll()['order'][0]['dir']) === 'desc' ? false : true); $rReports = array(); $rUserID = (0 < intval(RequestManager::getAll()['user']) ? intval(RequestManager::getAll()['user']) : null); $rStreamID = (0 < intval(RequestManager::getAll()['stream_id']) ? intval(RequestManager::getAll()['stream_id']) : null); if ($rUserID && in_array($rUserID, $rUserInfo['reports'])) { $db->query('SELECT `id` FROM `lines` WHERE `member_id` = ?;', $rUserID); } else { $db->query('SELECT `id` FROM `lines` WHERE `member_id` IN (' . implode(',', $rUserInfo['reports']) . ');'); } foreach ($db->get_rows() as $rRow) { $rReports[] = $rRow['id']; } $rKeys = ConnectionTracker::getUserConnections($rReports, false, true); if (!$rOrderDirection) { } else { $rKeys = array_reverse($rKeys); } $rKeyCount = count($rKeys); foreach (RedisManager::instance()->mGet($rKeys) as $rRow) { $rRow = igbinary_unserialize($rRow); if (is_array($rRow)) { if ($rFilterBefore) { } else { if (!($rStreamID && $rStreamID != $rRow['stream_id'])) { if (in_array($rRow['user_id'], $rReports)) { } else { $rKeyCount--; } } else { $rKeyCount--; } } $rRow['activity_id'] = $rRow['uuid']; $rRow['identifier'] = ($rRow['user_id'] ?: $rRow['hmac_id'] . '_' . $rRow['hmac_identifier']); $rRow['active_time'] = time() - $rRow['date_start']; $rRow['server_name'] = (ServerRepository::getAll()[$rRow['server_id']]['server_name'] ?: ''); $rRows[] = $rRow; } else { $rKeyCount--; } } $rOrder = array('uuid', 'divergence', 'identifier', 'stream_display_name', 'user_agent', 'isp', 'user_ip', 'active_time', 'container', null); if (isset(RequestManager::getAll()['order']) && 0 < strlen(RequestManager::getAll()['order'][0]['column'])) { $rOrderRow = intval(RequestManager::getAll()['order'][0]['column']); } else { $rOrderRow = 0; } if (!$rOrder[$rOrderRow]) { } else { array_multisort(array_column($rRows, $rOrder[$rOrderRow]), ($rOrderDirection ? SORT_ASC : SORT_DESC), $rRows); } $rRows = array_slice($rRows, $rStart, $rLimit); $rUUIDs = $rStreamIDs = $rUserIDs = array(); foreach ($rRows as $rRow) { if (!$rRow['stream_id']) { } else { $rStreamIDs[] = intval($rRow['stream_id']); } if (!$rRow['user_id']) { } else { $rUserIDs[] = intval($rRow['user_id']); } if (!$rRow['uuid']) { } else { $rUUIDs[] = $rRow['uuid']; } } $rStreamNames = $rDivergenceMap = $rSeriesMap = $rUserMap = array(); if (0 >= count($rUserIDs)) { } else { $db->query('SELECT `lines`.`id`, `lines`.`is_mag`, `lines`.`is_e2`, `lines`.`is_restreamer`, `lines`.`username`, `mag_devices`.`mag_id`, `enigma2_devices`.`device_id` FROM `lines` LEFT JOIN `mag_devices` ON `mag_devices`.`user_id` = `lines`.`id` LEFT JOIN `enigma2_devices` ON `enigma2_devices`.`user_id` = `lines`.`id` WHERE `lines`.`id` IN (' . implode(',', $rUserIDs) . ');'); foreach ($db->get_rows() as $rRow) { $rUserID = $rRow['id']; unset($rRow['id']); $rUserMap[$rUserID] = $rRow; } } if (0 >= count($rStreamIDs)) { } else { $db->query('SELECT `stream_id`, `series_id` FROM `streams_episodes` WHERE `stream_id` IN (' . implode(',', $rStreamIDs) . ');'); foreach ($db->get_rows() as $rRow) { $rSeriesMap[$rRow['stream_id']] = $rRow['series_id']; } $db->query('SELECT `id`, `type`, `stream_display_name` FROM `streams` WHERE `id` IN (' . implode(',', $rStreamIDs) . ');'); foreach ($db->get_rows() as $rRow) { $rStreamNames[$rRow['id']] = array($rRow['stream_display_name'], $rRow['type']); } } if (0 >= count($rUUIDs)) { } else { $db->query("SELECT `uuid`, `divergence` FROM `lines_divergence` WHERE `uuid` IN ('" . implode("','", $rUUIDs) . "');"); foreach ($db->get_rows() as $rRow) { $rDivergenceMap[$rRow['uuid']] = $rRow['divergence']; } } $i = 0; while ($i < count($rRows)) { $rRows[$i]['divergence'] = ($rDivergenceMap[$rRows[$i]['uuid']] ?: 0); $rRows[$i]['series_no'] = ($rSeriesMap[$rRows[$i]['stream_id']] ?: null); $rRows[$i]['stream_display_name'] = ($rStreamNames[$rRows[$i]['stream_id']][0] ?: ''); $rRows[$i]['type'] = ($rStreamNames[$rRows[$i]['stream_id']][1] ?: 1); $rRows[$i] = array_merge($rRows[$i], ($rUserMap[$rRows[$i]['user_id']] ?: array())); $i++; } $rReturn['recordsTotal'] = $rKeyCount; $rReturn['recordsFiltered'] = ($rIsAPI ? ($rReturn['recordsTotal'] < $rLimit ? $rReturn['recordsTotal'] : $rLimit) : $rReturn['recordsTotal']); } else { $rOrderDirection = (strtolower(RequestManager::getAll()['order'][0]['dir']) === 'desc' ? 'desc' : 'asc'); $rOrder = array('`lines_live`.`activity_id`', '`lines_live`.`divergence`', '`username`', '`streams`.`stream_display_name`', '`lines_live`.`user_agent`', '`lines_live`.`isp`', '`lines_live`.`user_ip`', 'UNIX_TIMESTAMP() - `lines_live`.`date_start`', '`lines_live`.`container`', false); if (isset(RequestManager::getAll()['order']) && 0 < strlen(RequestManager::getAll()['order'][0]['column'])) { $rOrderRow = intval(RequestManager::getAll()['order'][0]['column']); } else { $rOrderRow = 0; } $rWhere = $rWhereV = array(); $rWhere[] = '`hls_end` = 0'; $rWhere[] = '`lines`.`member_id` IN (' . implode(',', $rUserInfo['reports']) . ')'; if (0 >= strlen(RequestManager::getAll()['search']['value'])) { } else { foreach (range(1, 9) as $rInt) { $rWhereV[] = '%' . RequestManager::getAll()['search']['value'] . '%'; } $rWhere[] = '(`lines_live`.`user_agent` LIKE ? OR `lines_live`.`user_ip` LIKE ? OR `lines_live`.`container` LIKE ? OR FROM_UNIXTIME(`lines_live`.`date_start`) LIKE ? OR `lines_live`.`geoip_country_code` LIKE ? OR `lines`.`username` LIKE ? OR `mag_devices`.`mac` LIKE ? OR `enigma2_devices`.`mac` LIKE ? OR `streams`.`stream_display_name` LIKE ?)'; } if (0 >= intval(RequestManager::getAll()['stream'])) { } else { $rWhere[] = '`lines_live`.`stream_id` = ?'; $rWhereV[] = RequestManager::getAll()['stream']; } if (0 >= intval(RequestManager::getAll()['user'])) { } else { $rWhere[] = '`lines`.`member_id` = ?'; $rWhereV[] = RequestManager::getAll()['user']; } if (0 >= intval(RequestManager::getAll()['line'])) { } else { $rWhere[] = '`lines_live`.`user_id` = ?'; $rWhereV[] = RequestManager::getAll()['line']; } $rWhereString = 'WHERE ' . implode(' AND ', $rWhere); if (!$rOrder[$rOrderRow]) { } else { $rOrderBy = 'ORDER BY ' . $rOrder[$rOrderRow] . ' ' . $rOrderDirection; } $rCountQuery = 'SELECT COUNT(*) AS `count` FROM `lines_live` LEFT JOIN `lines` ON `lines_live`.`user_id` = `lines`.`id` LEFT JOIN `streams` ON `lines_live`.`stream_id` = `streams`.`id` LEFT JOIN `mag_devices` ON `mag_devices`.`user_id` = `lines_live`.`user_id` LEFT JOIN `enigma2_devices` ON `enigma2_devices`.`user_id` = `lines_live`.`user_id` ' . $rWhereString . ';'; $db->query($rCountQuery, ...$rWhereV); if ($db->num_rows() == 1) { $rReturn['recordsTotal'] = $db->get_row()['count']; } else { $rReturn['recordsTotal'] = 0; } $rReturn['recordsFiltered'] = $rReturn['recordsTotal']; if (0 >= $rReturn['recordsTotal']) { } else { $rQuery = 'SELECT `mag_devices`.`mag_id`, `enigma2_devices`.`device_id`, `lines`.`is_e2`, `lines`.`is_mag`, `lines_live`.`activity_id`, `lines_live`.`divergence`, `lines_live`.`user_id`, `lines_live`.`stream_id`, `streams`.`series_no`, `lines`.`is_restreamer`, `lines_live`.`isp`, `lines_live`.`server_id`, `lines_live`.`user_agent`, `lines_live`.`user_ip`, `lines_live`.`container`, `lines_live`.`uuid`, `lines_live`.`date_start`, `lines_live`.`geoip_country_code`, IF(`lines`.`is_mag`, `mag_devices`.`mac`, IF(`lines`.`is_e2`, `enigma2_devices`.`mac`, `lines`.`username`)) AS `username`, `streams`.`stream_display_name`, `streams`.`type` FROM `lines_live` LEFT JOIN `lines` ON `lines_live`.`user_id` = `lines`.`id` LEFT JOIN `streams` ON `lines_live`.`stream_id` = `streams`.`id` LEFT JOIN `mag_devices` ON `mag_devices`.`user_id` = `lines_live`.`user_id` LEFT JOIN `enigma2_devices` ON `enigma2_devices`.`user_id` = `lines_live`.`user_id` ' . $rWhereString . ' ' . $rOrderBy . ' LIMIT ' . $rStart . ', ' . $rLimit . ';'; $db->query($rQuery, ...$rWhereV); if (0 >= $db->num_rows()) { } else { $rRows = $db->get_rows(); } } } if (0 >= count($rRows)) { } else { foreach ($rRows as $rRow) { if (!$rIsAPI) { if ($rRow['divergence'] <= 50) { $rDivergence = ''; } else { if ($rRow['divergence'] <= 80) { $rDivergence = ''; } else { $rDivergence = ''; } } if ($rRow['is_mag']) { $rUsername = "" . $rRow['username'] . ''; } else { if ($rRow['is_e2']) { $rUsername = "" . $rRow['username'] . ''; } else { $rUsername = "" . $rRow['username'] . ''; } } $rChannel = $rRow['stream_display_name']; if (0 < strlen($rRow['geoip_country_code'])) { $rGeoCountry = "  "; } else { $rGeoCountry = ''; } if ($rRow['user_ip']) { $rIP = $rGeoCountry . "" . $rRow['user_ip'] . ''; } else { $rIP = ''; } $rPlayer = trim(explode('(', $rRow['user_agent'])[0]); $rDuration = intval(time()) - intval($rRow['date_start']); $rColour = 'success'; if (86400 <= $rDuration) { $rDuration = sprintf('%02dd %02dh', $rDuration / 86400, ($rDuration / 3600) % 24); $rColour = 'danger'; } else { if (3600 <= $rDuration) { if (14400 < $rDuration) { $rColour = 'warning'; } else { if (43200 >= $rDuration) { } else { $rColour = 'danger'; } } $rDuration = sprintf('%02dh %02dm', $rDuration / 3600, ($rDuration / 60) % 60); } else { $rDuration = sprintf('%02dm %02ds', ($rDuration / 60) % 60, $rDuration % 60); } } $rDuration = "'; $rButtons = ""; $rReturn['data'][] = array($rRow['activity_id'], $rDivergence, $rUsername, $rChannel, $rPlayer, $rRow['isp'], $rIP, $rDuration, strtoupper($rRow['container']), $rButtons); } else { $rReturn['data'][] = self::filterRow($rRow, RequestManager::getAll()['show_columns'], RequestManager::getAll()['hide_columns']); } } } echo json_encode($rReturn); exit(); } /** * Render the reseller "registered user logs" table. * * @param array $rReturn DataTables payload (by reference). * @param bool $rIsAPI Whether the request came via the API. * @param array $rUserInfo Authenticated reseller user. * @param array $rPermissions Effective permissions. * @param array $rSettings Panel settings. * @param \XcVm\Core\Database\DatabaseHandler $db Database handler. * @param int $rStart Pagination offset. * @param int $rLimit Page size. * @return void */ private static function handleRegUserLogs(array &$rReturn, bool $rIsAPI, array $rUserInfo, array $rPermissions, array $rSettings, $db, int $rStart, int $rLimit): void { $rOrderBy = ''; $rOrder = array('`users_logs`.`id`', '`users`.`username`', '`users_logs`.`log_id`', '`users_logs`.`type`, `users_logs`.`action`', '`users_logs`.`cost`', '`users_logs`.`credits_after`', '`users_logs`.`date`'); if (isset(RequestManager::getAll()['order']) && 0 < strlen(RequestManager::getAll()['order'][0]['column'])) { $rOrderRow = intval(RequestManager::getAll()['order'][0]['column']); } else { $rOrderRow = 0; } $rWhere = $rWhereV = array(); $rWhere[] = '`users_logs`.`owner` IN (' . implode(',', $rUserInfo['reports']) . ')'; if (0 >= strlen(RequestManager::getAll()['search']['value'])) { } else { foreach (range(1, 3) as $rInt) { $rWhereV[] = '%' . RequestManager::getAll()['search']['value'] . '%'; } $rWhere[] = '(`users`.`username` LIKE ? OR `users_logs`.`type` LIKE ? OR `users_logs`.`action` LIKE ?)'; } if (0 >= strlen(RequestManager::getAll()['range'])) { } else { $rStartTime = substr(RequestManager::getAll()['range'], 0, 10); $rEndTime = substr(RequestManager::getAll()['range'], strlen(RequestManager::getAll()['range']) - 10, 10); if ($rStartTime = strtotime($rStartTime . ' 00:00:00')) { } else { $rStartTime = null; } if ($rEndTime = strtotime($rEndTime . ' 23:59:59')) { } else { $rEndTime = null; } if (!($rStartTime && $rEndTime)) { } else { $rWhere[] = '(`users_logs`.`date` >= ? AND `users_logs`.`date` <= ?)'; $rWhereV[] = $rStartTime; $rWhereV[] = $rEndTime; } } if (0 >= strlen(RequestManager::getAll()['reseller'])) { } else { $rWhere[] = '`users_logs`.`owner` = ?'; $rWhereV[] = RequestManager::getAll()['reseller']; } if (0 < count($rWhere)) { $rWhereString = 'WHERE ' . implode(' AND ', $rWhere); } else { $rWhereString = ''; } if (!$rOrder[$rOrderRow]) { } else { $rOrderDirection = (strtolower(RequestManager::getAll()['order'][0]['dir']) === 'desc' ? 'desc' : 'asc'); $rOrderBy = 'ORDER BY ' . $rOrder[$rOrderRow] . ' ' . $rOrderDirection; } $rCountQuery = 'SELECT COUNT(*) AS `count` FROM `users_logs` LEFT JOIN `users` ON `users`.`id` = `users_logs`.`owner` ' . $rWhereString . ';'; $db->query($rCountQuery, ...$rWhereV); if ($db->num_rows() == 1) { $rReturn['recordsTotal'] = $db->get_row()['count']; } else { $rReturn['recordsTotal'] = 0; } $rReturn['recordsFiltered'] = $rReturn['recordsTotal']; if (0 >= $rReturn['recordsTotal']) { } else { $rPackages = PackageService::getAll(); $rQuery = 'SELECT `users`.`username`, `users_logs`.`id`, `users_logs`.`owner`, `users_logs`.`type`, `users_logs`.`action`, `users_logs`.`log_id`, `users_logs`.`package_id`, `users_logs`.`cost`, `users_logs`.`credits_after`, `users_logs`.`date`, `users_logs`.`deleted_info` FROM `users_logs` LEFT JOIN `users` ON `users`.`id` = `users_logs`.`owner` ' . $rWhereString . ' ' . $rOrderBy . ' LIMIT ' . $rStart . ', ' . $rLimit . ';'; $db->query($rQuery, ...$rWhereV); if (0 >= $db->num_rows()) { } else { foreach ($db->get_rows() as $rRow) { if (!$rIsAPI) { if (in_array($rRow['owner'], array_merge($rPermissions['direct_reports'], array($rUserInfo['id'])))) { $rOwner = "" . $rRow['username'] . ''; } else { $rOwner = "" . $rRow['username'] . "
(indirect)
"; } $rDevice = array('line' => 'User Line', 'mag' => 'MAG Device', 'enigma' => 'Enigma2 Device', 'user' => 'Reseller')[$rRow['type']]; switch ($rRow['action']) { case 'new': if ($rRow['package_id']) { $rText = 'Created New ' . $rDevice . ' with Package: ' . $rPackages[$rRow['package_id']]['package_name']; } else { $rText = 'Created New ' . $rDevice; } break; case 'extend': if ($rRow['package_id']) { $rText = 'Extended ' . $rDevice . ' with Package: ' . $rPackages[$rRow['package_id']]['package_name']; } else { $rText = 'Extended ' . $rDevice; } break; case 'edit': $rText = 'Edited ' . $rDevice; break; case 'enable': $rText = 'Enabled ' . $rDevice; break; case 'disable': $rText = 'Disabled ' . $rDevice; break; case 'delete': $rText = 'Deleted ' . $rDevice; break; case 'send_event': $rText = 'Sent Event to ' . $rDevice; break; case 'adjust_credits': $rText = 'Adjusted Credits by ' . $rRow['cost']; break; } $rLineInfo = null; switch ($rRow['type']) { case 'line': $rLine = UserRepository::getLineById($rRow['log_id']); if (!$rLine) { } else { $rLineInfo = "" . $rLine['username'] . ''; } break; case 'user': $rLine = UserRepository::getRegisteredUserById($rRow['log_id']); if (!$rLine) { } else { $rLineInfo = "" . $rLine['username'] . ''; } break; case 'mag': $rLine = MagService::getById($rRow['log_id']); if (!$rLine) { } else { $rLineInfo = "" . $rLine['mac'] . ''; } break; case 'enigma': $rLine = EnigmaService::getById($rRow['log_id']); if (!$rLine) { } else { $rLineInfo = "" . $rLine['mac'] . ''; } break; } if ($rLineInfo) { } else { $rDeletedInfo = json_decode($rRow['deleted_info'], true); if (is_array($rDeletedInfo)) { if (isset($rDeletedInfo['mac'])) { $rLineInfo = "" . $rDeletedInfo['mac'] . ''; } else { $rLineInfo = "" . $rDeletedInfo['username'] . ''; } } else { $rLineInfo = "DELETED"; } } $rReturn['data'][] = array($rRow['id'], $rOwner, $rLineInfo, $rText, number_format($rRow['cost'], 0), number_format($rRow['credits_after'], 0), date($rSettings['datetime_format'], $rRow['date'])); } else { unset($rRow['deleted_info']); $rReturn['data'][] = self::filterRow($rRow, RequestManager::getAll()['show_columns'], RequestManager::getAll()['hide_columns']); } } } } echo json_encode($rReturn); exit(); } /** * Render the reseller "registered users" table. * * @param array $rReturn DataTables payload (by reference). * @param bool $rIsAPI Whether the request came via the API. * @param array $rUserInfo Authenticated reseller user. * @param array $rPermissions Effective permissions. * @param array $rSettings Panel settings. * @param \XcVm\Core\Database\DatabaseHandler $db Database handler. * @param int $rStart Pagination offset. * @param int $rLimit Page size. * @return void */ private static function handleRegUsers(array &$rReturn, bool $rIsAPI, array $rUserInfo, array $rPermissions, array $rSettings, $db, int $rStart, int $rLimit): void { if (!$rPermissions['create_sub_resellers']) { exit(); } $rOrderBy = ''; $rOrder = array('`users`.`id`', '`users`.`username`', '`r`.`username`', '`users`.`ip`', '`users`.`status`', '`users`.`credits`', '`user_count`', '`users`.`last_login`', false); if (isset(RequestManager::getAll()['order']) && 0 < strlen(RequestManager::getAll()['order'][0]['column'])) { $rOrderRow = intval(RequestManager::getAll()['order'][0]['column']); } else { $rOrderRow = 0; } $rWhere = $rWhereV = array(); $rWhere[] = '`users`.`owner_id` IN (' . implode(',', $rUserInfo['reports']) . ')'; if (0 >= strlen(RequestManager::getAll()['search']['value'])) { } else { foreach (range(1, 9) as $rInt) { $rWhereV[] = '%' . RequestManager::getAll()['search']['value'] . '%'; } $rWhere[] = '(`users`.`id` LIKE ? OR `users`.`username` LIKE ? OR `users`.`notes` LIKE ? OR `r`.`username` LIKE ? OR FROM_UNIXTIME(`users`.`date_registered`) LIKE ? OR FROM_UNIXTIME(`users`.`last_login`) LIKE ? OR `users`.`email` LIKE ? OR `users`.`ip` LIKE ? OR `users_groups`.`group_name` LIKE ?)'; } if (0 >= strlen(RequestManager::getAll()['filter'])) { } else { if (RequestManager::getAll()['filter'] == 1) { $rWhere[] = '`users`.`status` = 1'; } else { if (RequestManager::getAll()['filter'] != 2) { } else { $rWhere[] = '`users`.`status` = 0'; } } } if (0 >= strlen(RequestManager::getAll()['reseller'])) { } else { $rWhere[] = '`users`.`owner_id` = ?'; $rWhereV[] = RequestManager::getAll()['reseller']; } if (0 < count($rWhere)) { $rWhereString = 'WHERE ' . implode(' AND ', $rWhere); } else { $rWhereString = ''; } if (!$rOrder[$rOrderRow]) { } else { $rOrderDirection = (strtolower(RequestManager::getAll()['order'][0]['dir']) === 'desc' ? 'desc' : 'asc'); $rOrderBy = 'ORDER BY ' . $rOrder[$rOrderRow] . ' ' . $rOrderDirection; } $rCountQuery = 'SELECT COUNT(*) AS `count` FROM `users` LEFT JOIN `users_groups` ON `users_groups`.`group_id` = `users`.`member_group_id` LEFT JOIN `users` AS `r` on `r`.`id` = `users`.`owner_id` ' . $rWhereString . ';'; $db->query($rCountQuery, ...$rWhereV); if ($db->num_rows() == 1) { $rReturn['recordsTotal'] = $db->get_row()['count']; } else { $rReturn['recordsTotal'] = 0; } $rReturn['recordsFiltered'] = $rReturn['recordsTotal']; if (0 >= $rReturn['recordsTotal']) { } else { $rQuery = 'SELECT `users`.`id`, `users`.`status`, `users_groups`.`is_reseller`, `users`.`notes`, `users`.`owner_id`, `users`.`credits`, `users`.`username`, `users`.`email`, `users`.`ip`, FROM_UNIXTIME(`users`.`date_registered`) AS `date_registered`, FROM_UNIXTIME(`users`.`last_login`) AS `last_login`, `r`.`username` as `owner_username`, `users_groups`.`group_name`, `users`.`status`, (SELECT COUNT(`id`) FROM `lines` WHERE `member_id` = `users`.`id`) AS `user_count` FROM `users` LEFT JOIN `users_groups` ON `users_groups`.`group_id` = `users`.`member_group_id` LEFT JOIN `users` AS `r` on `r`.`id` = `users`.`owner_id` ' . $rWhereString . ' ' . $rOrderBy . ' LIMIT ' . $rStart . ', ' . $rLimit . ';'; $db->query($rQuery, ...$rWhereV); if (0 >= $db->num_rows()) { } else { foreach ($db->get_rows() as $rRow) { if (!$rIsAPI) { if ($rRow['status'] == 1) { $rStatus = ''; } else { $rStatus = ''; } if ($rRow['last_login']) { } else { $rRow['last_login'] = 'NEVER'; } $rButtons = '
'; if (0 < strlen($rRow['notes'])) { $rButtons .= ''; } else { $rButtons .= ''; } if (in_array($rRow['id'], array_merge($rPermissions['direct_reports'], array($rUserInfo['id'])))) { $rButtons .= ''; $rUsername = "" . $rRow['username'] . ''; } else { $rButtons .= ''; $rUsername = "" . $rRow['username'] . "
(indirect)
"; } $rButtons .= ''; if ($rRow['status'] == 1) { $rButtons .= '"; } else { $rButtons .= '"; } if (!$rPermissions['delete_users']) { } else { $rButtons .= '"; } $rButtons .= '
'; if (0 < strlen($rRow['ip'])) { $rIP = "" . $rRow['ip'] . ''; } else { $rIP = ''; } if ($rRow['is_reseller']) { $rCredits = ''; } else { $rCredits = ''; } if (0 < $rRow['user_count']) { $rUserCount = ''; } else { $rUserCount = ''; } if (in_array($rRow['owner_id'], array_merge($rPermissions['direct_reports'], array($rUserInfo['id'])))) { $rOwner = "" . $rRow['owner_username'] . ''; } else { $rOwner = "" . $rRow['owner_username'] . "
(indirect)
"; } $rReturn['data'][] = array("" . $rRow['id'] . '', $rUsername, $rOwner, $rIP, $rStatus, $rCredits, $rUserCount, $rRow['last_login'], $rButtons); } else { $rReturn['data'][] = self::filterRow($rRow, RequestManager::getAll()['show_columns'], RequestManager::getAll()['hide_columns']); } } } } echo json_encode($rReturn); exit(); } /** * Filter a row's columns by show/hide lists. * * @param array $rRow Row data. * @param array $rShow Columns to keep (whitelist), or empty for all. * @param array $rHide Columns to remove (blacklist). * @return array The filtered row. */ private static function filterRow($rRow, $rShow, $rHide) { if ($rShow || $rHide) { $rReturn = array(); foreach (array_keys($rRow) as $rKey) { if ($rShow) { if (!in_array($rKey, $rShow)) { } else { $rReturn[$rKey] = $rRow[$rKey]; } } else { if (!$rHide) { } else { if (in_array($rKey, $rHide)) { } else { $rReturn[$rKey] = $rRow[$rKey]; } } } } return $rReturn; } else { return $rRow; } } }