Files
XC_VM/src/Infrastructure/ResellerTableRenderer.php
T

2051 lines
100 KiB
PHP
Raw Normal View History

<?php
namespace XcVm\Infrastructure;
use XcVm\Core\Config\SettingsManager;
use XcVm\Core\Database\Database;
use XcVm\Core\Http\RequestManager;
use XcVm\Core\Util\TimeUtils;
use XcVm\Domain\Device\EnigmaService;
use XcVm\Domain\Device\MagService;
use XcVm\Domain\Line\PackageService;
use XcVm\Domain\Server\ServerRepository;
use XcVm\Domain\Stream\CategoryService;
use XcVm\Domain\Stream\ConnectionTracker;
use XcVm\Domain\User\UserRepository;
use XcVm\Infrastructure\Redis\RedisManager;
/**
* ResellerTableRenderer — DataTables handler for reseller panel.
*
* All $rType branches are private static handler methods.
*
* @package XC_VM_Infrastructure
* @author Divarion_D <https://github.com/Divarion-D>
* @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 = '<i class="text-danger fas fa-square tooltip" title="Banned"></i>';
} else {
if (!$rRow['enabled']) {
$rStatus = '<i class="text-secondary fas fa-square tooltip" title="Disabled"></i>';
} else {
if ($rRow['exp_date'] && $rRow['exp_date'] < time()) {
$rStatus = '<i class="text-warning far fa-square tooltip" title="Expired"></i>';
} else {
$rStatus = '<i class="text-success fas fa-square tooltip" title="Active"></i>';
}
}
}
if (0 < $rRow['active_connections']) {
$rActive = '<i class="text-success fas fa-square"></i>';
} else {
$rActive = '<i class="text-secondary far fa-square"></i>';
}
if ($rRow['is_trial']) {
$rTrial = '<i class="text-warning fas fa-square"></i>';
} else {
$rTrial = '<i class="text-secondary far fa-square"></i>';
}
if ($rRow['exp_date']) {
if ($rRow['exp_date'] < time()) {
$rExpDate = '<span class="expired">' . date($rSettings['date_format'], $rRow['exp_date']) . '<br/><small>' . date('H:i:s', $rRow['exp_date']) . '</small></span>';
} else {
$rExpDate = date($rSettings['date_format'], $rRow['exp_date']) . "<br/><small class='text-secondary'>" . date('H:i:s', $rRow['exp_date']) . '</small>';
}
} else {
$rExpDate = '&infin;';
}
if (0 < $rRow['active_connections']) {
if ($rPermissions['reseller_client_connection_logs']) {
$rActiveConnections = "<a href='javascript: void(0);' onClick='viewLiveConnections(" . intval($rRow['id']) . ");'><button type='button' class='btn btn-info btn-xs waves-effect waves-light'>" . $rRow['active_connections'] . '</button></a>';
} else {
$rActiveConnections = "<button type='button' class='btn btn-info btn-xs waves-effect waves-light'>" . $rRow['active_connections'] . '</button>';
}
} else {
$rActiveConnections = "<button type='button' class='btn btn-secondary btn-xs waves-effect waves-light'>0</button>";
}
if ($rRow['max_connections'] == 0) {
$rMaxConnections = "<button type='button' class='btn btn-dark text-white btn-xs waves-effect waves-light'>&infin;</button>";
} else {
$rMaxConnections = "<button type='button' class='btn btn-secondary btn-xs waves-effect waves-light'>" . $rRow['max_connections'] . '</button>';
}
$rButtons = '<div class="btn-group">';
$rNotes = '';
if (0 >= strlen($rRow['reseller_notes'])) {
} else {
if (strlen($rNotes) == 0) {
} else {
$rNotes .= "\n";
}
$rNotes .= $rRow['reseller_notes'];
}
if (0 < strlen($rNotes)) {
$rButtons .= '<button type="button" class="btn btn-light waves-effect waves-light btn-xs tooltip" title="' . $rNotes . '"><i class="mdi mdi-note"></i></button>';
} else {
$rButtons .= '<button type="button" disabled class="btn btn-light waves-effect waves-light btn-xs"><i class="mdi mdi-note"></i></button>';
}
$rButtons .= '<a href="line?id=' . $rRow['id'] . '"><button title="Edit" type="button" class="btn btn-light waves-effect waves-light btn-xs tooltip"><i class="mdi mdi-pencil-outline"></i></button></a>';
if (!$rPermissions['allow_download']) {
} else {
$rButtons .= "<button type=\"button\" title=\"Download Playlist\" class=\"btn btn-light waves-effect waves-light btn-xs tooltip\" onClick=\"download('" . $rRow['username'] . "', '" . $rRow['password'] . "');\"><i class=\"mdi mdi-download\"></i></button>";
}
$rWhatsAppContact = !empty($rRow['contact']) ? addslashes($rRow['contact']) : '';
$rWhatsAppExp = $rRow['exp_date'] ? $rRow['exp_date'] : 'null';
$rButtons .= "<button type=\"button\" title=\"WhatsApp Renewal\" class=\"btn btn-success waves-effect waves-light btn-xs tooltip\" onClick=\"openWhatsApp('" . addslashes($rRow['username']) . "', '" . $rWhatsAppContact . "', " . $rWhatsAppExp . ");\"><i class=\"mdi mdi-whatsapp\"></i></button>";
if (!$rPermissions['reseller_client_connection_logs']) {
} else {
if (0 < $rRow['active_connections']) {
$rButtons .= '<button title="Kill Connections" type="button" class="btn btn-light waves-effect waves-light btn-xs tooltip" onClick="api(' . $rRow['id'] . ", 'kill_line');\"><i class=\"fas fa-hammer\"></i></button>";
} else {
$rButtons .= '<button disabled type="button" class="btn btn-light waves-effect waves-light btn-xs"><i class="fas fa-hammer"></i></button>';
}
}
if (!$rRow['is_isplock']) {
} else {
$rButtons .= '<button title="Reset ISP Lock" type="button" class="btn btn-light waves-effect waves-light btn-xs tooltip" onClick="api(' . $rRow['id'] . ", 'reset_isp');\"><i class=\"mdi mdi-lock-reset\"></i></button>";
}
if ($rRow['enabled']) {
$rButtons .= '<button title="Disable" type="button" class="btn btn-light waves-effect waves-light btn-xs tooltip" onClick="api(' . $rRow['id'] . ", 'disable');\"><i class=\"mdi mdi-lock\"></i></button>";
} else {
$rButtons .= '<button title="Enable" type="button" class="btn btn-light waves-effect waves-light btn-xs tooltip" onClick="api(' . $rRow['id'] . ", 'enable');\"><i class=\"mdi mdi-lock\"></i></button>";
}
$rButtons .= '<button title="Delete" type="button" class="btn btn-light waves-effect waves-light btn-xs tooltip" onClick="api(' . $rRow['id'] . ", 'delete');\"><i class=\"mdi mdi-close\"></i></button>";
$rButtons .= '</div>';
if ($rRow['active_connections'] && $rRow['last_active']) {
$rLastActive = "<a href='stream_view?id=" . $rRow['stream_id'] . "'>" . $rRow['stream_display_name'] . "</a><br/><small class='text-secondary'>Online: " . TimeUtils::secondsToTime(time() - $rRow['last_active']) . '</small>';
} else {
if ($rRow['last_active']) {
$rLastActive = date($rSettings['date_format'], $rRow['last_active']) . "<br/><small class='text-secondary'>" . date('H:i:s', $rRow['last_active']) . '</small>';
} else {
$rLastActive = 'Never';
}
}
if (in_array($rRow['member_id'], array_merge($rPermissions['direct_reports'], array($rUserInfo['id'])))) {
$rOwner = "<a href='user?id=" . intval($rRow['member_id']) . "'>" . $rRow['owner_name'] . '</a>';
} else {
$rOwner = "<a href='user?id=" . intval($rRow['member_id']) . "'>" . $rRow['owner_name'] . "<br/><small class='text-pink'>(indirect)</small></a>";
}
$rReturn['data'][] = array("<a href='line?id=" . $rRow['id'] . "'>" . $rRow['id'] . '</a>', "<a href='line?id=" . $rRow['id'] . "'>" . $rRow['username'] . '</a>', $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 = '<i class="text-danger fas fa-square"></i>';
} else {
if (!$rRow['enabled']) {
$rStatus = '<i class="text-secondary fas fa-square"></i>';
} else {
if ($rRow['exp_date'] && $rRow['exp_date'] < time()) {
$rStatus = '<i class="text-warning far fa-square"></i>';
} else {
$rStatus = '<i class="text-success fas fa-square"></i>';
}
}
}
if (0 < $rRow['active_connections']) {
$rActive = '<i class="text-success fas fa-square"></i>';
} else {
$rActive = '<i class="text-warning far fa-square"></i>';
}
if ($rRow['is_trial']) {
$rTrial = '<i class="text-warning fas fa-square"></i>';
} else {
$rTrial = '<i class="text-secondary far fa-square"></i>';
}
if ($rRow['exp_date']) {
if ($rRow['exp_date'] < time()) {
$rExpDate = '<span class="expired">' . date($rSettings['date_format'], $rRow['exp_date']) . '<br/><small>' . date('H:i:s', $rRow['exp_date']) . '</small></span>';
} else {
$rExpDate = date($rSettings['date_format'], $rRow['exp_date']) . "<br/><small class='text-secondary'>" . date('H:i:s', $rRow['exp_date']) . '</small>';
}
} else {
$rExpDate = '&infin;';
}
$rButtons = '<div class="btn-group">';
$rNotes = '';
if (0 >= strlen($rRow['reseller_notes'])) {
} else {
if (strlen($rNotes) == 0) {
} else {
$rNotes .= "\n";
}
$rNotes .= $rRow['reseller_notes'];
}
if (0 < strlen($rNotes)) {
$rButtons .= '<button type="button" class="btn btn-light waves-effect waves-light btn-xs tooltip" title="' . $rNotes . '"><i class="mdi mdi-note"></i></button>';
} else {
$rButtons .= '<button type="button" disabled class="btn btn-light waves-effect waves-light btn-xs"><i class="mdi mdi-note"></i></button>';
}
$rButtons .= '<button title="MAG Event" type="button" class="btn btn-light waves-effect waves-light btn-xs tooltip" onClick="message(' . $rRow['mag_id'] . ", '" . $rRow['mac'] . "');\"><i class=\"mdi mdi-message-alert\"></i></button>";
$rButtons .= '<a href="mag?id=' . $rRow['mag_id'] . '"><button title="Edit" type="button" class="btn btn-light waves-effect waves-light btn-xs tooltip"><i class="mdi mdi-pencil-outline"></i></button></a>';
if (!$rRow['is_isplock']) {
} else {
$rButtons .= '<button title="Reset ISP Lock" type="button" class="btn btn-light waves-effect waves-light btn-xs tooltip" onClick="api(' . $rRow['mag_id'] . ", 'reset_isp');\"><i class=\"mdi mdi-lock-reset\"></i></button>";
}
if (!$rPermissions['create_line']) {
} else {
$rButtons .= '<button title="Convert to User Line" type="button" class="btn btn-light waves-effect waves-light btn-xs tooltip" onClick="api(' . $rRow['mag_id'] . ", 'convert');\"><i class=\"fas fa-retweet\"></i></button>";
}
if (!$rPermissions['reseller_client_connection_logs']) {
} else {
if (0 < $rRow['active_connections']) {
$rButtons .= '<button title="Kill Connections" type="button" class="btn btn-light waves-effect waves-light btn-xs tooltip" onClick="api(' . $rRow['mag_id'] . ", 'kill_line');\"><i class=\"fas fa-hammer\"></i></button>";
} else {
$rButtons .= '<button disabled type="button" class="btn btn-light waves-effect waves-light btn-xs"><i class="fas fa-hammer"></i></button>';
}
}
if ($rRow['enabled'] == 1) {
$rButtons .= '<button title="Disable" type="button" class="btn btn-light waves-effect waves-light btn-xs tooltip" onClick="api(' . $rRow['mag_id'] . ", 'disable');\"><i class=\"mdi mdi-lock\"></i></button>";
} else {
$rButtons .= '<button title="Enable" type="button" class="btn btn-light waves-effect waves-light btn-xs tooltip" onClick="api(' . $rRow['mag_id'] . ", 'enable');\"><i class=\"mdi mdi-lock\"></i></button>";
}
$rButtons .= '<button title="Delete" type="button" class="btn btn-light waves-effect waves-light btn-xs tooltip" onClick="api(' . $rRow['mag_id'] . ", 'delete');\"><i class=\"mdi mdi-close\"></i></button>";
$rButtons .= '</div>';
if (in_array($rRow['member_id'], array_merge($rPermissions['direct_reports'], array($rUserInfo['id'])))) {
$rOwner = "<a href='user?id=" . intval($rRow['member_id']) . "'>" . $rRow['owner_name'] . '</a>';
} else {
$rOwner = "<a href='user?id=" . intval($rRow['member_id']) . "'>" . $rRow['owner_name'] . "<br/><small class='text-pink'>(indirect)</small></a>";
}
$rReturn['data'][] = array("<a href='mag?id=" . $rRow['mag_id'] . "'>" . $rRow['mag_id'] . '</a>', $rRow['username'], "<a href='mag?id=" . $rRow['mag_id'] . "'>" . $rRow['mac'] . '</a>', $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 = '<i class="text-danger fas fa-square"></i>';
} else {
if (!$rRow['enabled']) {
$rStatus = '<i class="text-secondary fas fa-square"></i>';
} else {
if ($rRow['exp_date'] && $rRow['exp_date'] < time()) {
$rStatus = '<i class="text-warning far fa-square"></i>';
} else {
$rStatus = '<i class="text-success fas fa-square"></i>';
}
}
}
if (0 < $rRow['active_connections']) {
$rActive = '<i class="text-success fas fa-square"></i>';
} else {
$rActive = '<i class="text-warning far fa-square"></i>';
}
if ($rRow['is_trial']) {
$rTrial = '<i class="text-warning fas fa-square"></i>';
} else {
$rTrial = '<i class="text-secondary far fa-square"></i>';
}
if ($rRow['exp_date']) {
if ($rRow['exp_date'] < time()) {
$rExpDate = '<span class="expired">' . date($rSettings['date_format'], $rRow['exp_date']) . '<br/><small>' . date('H:i:s', $rRow['exp_date']) . '</small></span>';
} else {
$rExpDate = date($rSettings['date_format'], $rRow['exp_date']) . "<br/><small class='text-secondary'>" . date('H:i:s', $rRow['exp_date']) . '</small>';
}
} else {
$rExpDate = '&infin;';
}
$rButtons = '<div class="btn-group">';
$rNotes = '';
if (0 >= strlen($rRow['reseller_notes'])) {
} else {
if (strlen($rNotes) == 0) {
} else {
$rNotes .= "\n";
}
$rNotes .= $rRow['reseller_notes'];
}
if (0 < strlen($rNotes)) {
$rButtons .= '<button type="button" class="btn btn-light waves-effect waves-light btn-xs tooltip" title="' . $rNotes . '"><i class="mdi mdi-note"></i></button>';
} else {
$rButtons .= '<button type="button" disabled class="btn btn-light waves-effect waves-light btn-xs"><i class="mdi mdi-note"></i></button>';
}
$rButtons .= '<a href="enigma?id=' . $rRow['device_id'] . '"><button title="Edit" type="button" class="btn btn-light waves-effect waves-light btn-xs tooltip"><i class="mdi mdi-pencil-outline"></i></button></a>';
if (!$rRow['is_isplock']) {
} else {
$rButtons .= '<button title="Reset ISP Lock" type="button" class="btn btn-light waves-effect waves-light btn-xs tooltip" onClick="api(' . $rRow['device_id'] . ", 'reset_isp');\"><i class=\"mdi mdi-lock-reset\"></i></button>";
}
if (!$rPermissions['create_line']) {
} else {
$rButtons .= '<button title="Convert to User Line" type="button" class="btn btn-light waves-effect waves-light btn-xs tooltip" onClick="api(' . $rRow['device_id'] . ", 'convert');\"><i class=\"fas fa-retweet\"></i></button>";
}
if (!$rPermissions['reseller_client_connection_logs']) {
} else {
if (0 < $rRow['active_connections']) {
$rButtons .= '<button title="Kill Connections" type="button" class="btn btn-light waves-effect waves-light btn-xs tooltip" onClick="api(' . $rRow['device_id'] . ", 'kill_line');\"><i class=\"fas fa-hammer\"></i></button>";
} else {
$rButtons .= '<button disabled type="button" class="btn btn-light waves-effect waves-light btn-xs"><i class="fas fa-hammer"></i></button>';
}
}
if ($rRow['enabled'] == 1) {
$rButtons .= '<button title="Disable" type="button" class="btn btn-light waves-effect waves-light btn-xs tooltip" onClick="api(' . $rRow['device_id'] . ", 'disable');\"><i class=\"mdi mdi-lock\"></i></button>";
} else {
$rButtons .= '<button title="Enable" type="button" class="btn btn-light waves-effect waves-light btn-xs tooltip" onClick="api(' . $rRow['device_id'] . ", 'enable');\"><i class=\"mdi mdi-lock\"></i></button>";
}
$rButtons .= '<button title="Delete" type="button" class="btn btn-light waves-effect waves-light btn-xs tooltip" onClick="api(' . $rRow['device_id'] . ", 'delete');\"><i class=\"mdi mdi-close\"></i></button>";
$rButtons .= '</div>';
if (in_array($rRow['member_id'], array_merge($rPermissions['direct_reports'], array($rUserInfo['id'])))) {
$rOwner = "<a href='user?id=" . intval($rRow['member_id']) . "'>" . $rRow['owner_name'] . '</a>';
} else {
$rOwner = "<a href='user?id=" . intval($rRow['member_id']) . "'>" . $rRow['owner_name'] . "<br/><small class='text-pink'>(indirect)</small></a>";
}
$rReturn['data'][] = array("<a href='enigma?id=" . $rRow['device_id'] . "'>" . $rRow['device_id'] . '</a>', $rRow['username'], "<a href='enigma?id=" . $rRow['device_id'] . "'>" . $rRow['mac'] . '</a>', "<a onClick=\"whois('" . $rRow['public_ip'] . "');\" href='javascript: void(0);'>" . $rRow['public_ip'] . '</a>', $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'] .= " <i class='text-danger mdi mdi-record'></i>";
}
if (0 < $rRow['clients']) {
if ($rPermissions['reseller_client_connection_logs']) {
$rButtons = '<button title="Kill Connections" type="button" class="btn btn-light waves-effect waves-light btn-xs tooltip" onClick="api(' . $rRow['id'] . ", 'purge');\"><i class=\"mdi mdi-hammer\"></i></button>";
$rClients = "<a href='javascript: void(0);' onClick='viewLiveConnections(" . intval($rRow['id']) . ");'><button type='button' class='btn btn-info btn-xs waves-effect waves-light'>" . $rRow['clients'] . '</button></a>';
} else {
$rButtons = '<button type="button" disabled class="btn btn-light waves-effect waves-light btn-xs"><i class="mdi mdi-hammer"></i></button>';
$rClients = "<button type='button' class='btn btn-info btn-xs waves-effect waves-light'>" . $rRow['clients'] . '</button>';
}
} else {
$rButtons = '<button type="button" disabled class="btn btn-light waves-effect waves-light btn-xs"><i class="mdi mdi-hammer"></i></button>';
$rClients = "<button type='button' class='btn btn-secondary btn-xs waves-effect waves-light'>0</button>";
}
if (0 < strlen($rRow['stream_icon'])) {
$rIcon = "<a href='javascript: void(0);' onClick='openImage(this);' data-src='resize?maxw=512&maxh=512&url=" . $rRow['stream_icon'] . "'><img loading='lazy' src='resize?maxw=96&maxh=32&url=" . $rRow['stream_icon'] . "' /></a>";
} 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 = '<button title="Kill Connections" type="button" class="btn btn-light waves-effect waves-light btn-xs tooltip" onClick="api(' . $rRow['id'] . ", 'purge');\"><i class=\"mdi mdi-hammer\"></i></button>";
$rClients = "<a href='javascript: void(0);' onClick='viewLiveConnections(" . intval($rRow['id']) . ");'><button type='button' class='btn btn-info btn-xs waves-effect waves-light'>" . $rRow['clients'] . '</button></a>';
} else {
$rButtons = '<button type="button" disabled class="btn btn-light waves-effect waves-light btn-xs"><i class="mdi mdi-hammer"></i></button>';
$rClients = "<button type='button' class='btn btn-info btn-xs waves-effect waves-light'>" . $rRow['clients'] . '</button>';
}
} else {
$rButtons = '<button type="button" disabled class="btn btn-light waves-effect waves-light btn-xs"><i class="mdi mdi-hammer"></i></button>';
$rClients = "<button type='button' class='btn btn-secondary btn-xs waves-effect waves-light'>0</button>";
}
if (0 < strlen($rRow['stream_icon'])) {
$rIcon = "<a href='javascript: void(0);' onClick='openImage(this);' data-src='resize?maxw=512&maxh=512&url=" . $rRow['stream_icon'] . "'><img loading='lazy' src='resize?maxw=96&maxh=32&url=" . $rRow['stream_icon'] . "' /></a>";
} 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 = '<button title="Kill Connections" type="button" class="btn btn-light waves-effect waves-light btn-xs tooltip" onClick="api(' . $rRow['id'] . ", 'purge');\"><i class=\"mdi mdi-hammer\"></i></button>";
$rClients = "<a href='javascript: void(0);' onClick='viewLiveConnections(" . intval($rRow['id']) . ");'><button type='button' class='btn btn-info btn-xs waves-effect waves-light'>" . $rRow['clients'] . '</button></a>';
} else {
$rButtons = '<button type="button" disabled class="btn btn-light waves-effect waves-light btn-xs"><i class="mdi mdi-hammer"></i></button>';
$rClients = "<button type='button' class='btn btn-info btn-xs waves-effect waves-light'>" . $rRow['clients'] . '</button>';
}
} else {
$rButtons = '<button type="button" disabled class="btn btn-light waves-effect waves-light btn-xs"><i class="mdi mdi-hammer"></i></button>';
$rClients = "<button type='button' class='btn btn-secondary btn-xs waves-effect waves-light'>0</button>";
}
$rProperties = json_decode($rRow['movie_properties'], true);
if (0 < strlen($rProperties['movie_image'])) {
$rImage = "<a href='javascript: void(0);' onClick='openImage(this);' data-src='resize?maxw=512&maxh=512&url=" . $rProperties['movie_image'] . "'><img loading='lazy' src='resize?maxh=58&maxw=32&url=" . $rProperties['movie_image'] . "' /></a>";
} 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 = '<b>' . $rRow['stream_display_name'] . "</b><br><span style='font-size:11px;'>" . $rSeriesName . '</span>';
$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 = '<button title="Kill Connections" type="button" class="btn btn-light waves-effect waves-light btn-xs tooltip" onClick="api(' . $rRow['id'] . ", 'purge');\"><i class=\"mdi mdi-hammer\"></i></button>";
$rClients = "<a href='javascript: void(0);' onClick='viewLiveConnections(" . intval($rRow['id']) . ");'><button type='button' class='btn btn-info btn-xs waves-effect waves-light'>" . $rRow['clients'] . '</button></a>';
} else {
$rButtons = '<button type="button" disabled class="btn btn-light waves-effect waves-light btn-xs"><i class="mdi mdi-hammer"></i></button>';
$rClients = "<button type='button' class='btn btn-info btn-xs waves-effect waves-light'>" . $rRow['clients'] . '</button>';
}
} else {
$rButtons = '<button type="button" disabled class="btn btn-light waves-effect waves-light btn-xs"><i class="mdi mdi-hammer"></i></button>';
$rClients = "<button type='button' class='btn btn-secondary btn-xs waves-effect waves-light'>0</button>";
}
$rProperties = json_decode($rRow['movie_properties'], true);
if (0 < strlen($rProperties['movie_image'])) {
$rImage = "<a href='javascript: void(0);' onClick='openImage(this);' data-src='resize?maxw=512&maxh=512&url=" . $rProperties['movie_image'] . "'><img loading='lazy' src='resize?maxh=58&maxw=32&url=" . $rProperties['movie_image'] . "' /></a>";
} 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 = "<a href='mag?id=" . $rRow['mag_id'] . "'>" . $rRow['username'] . '</a>';
} else {
if ($rRow['is_e2']) {
$rUsername = "<a href='enigma?id=" . $rRow['device_id'] . "'>" . $rRow['username'] . '</a>';
} else {
$rUsername = "<a href='line?id=" . $rRow['user_id'] . "'>" . $rRow['username'] . '</a>';
}
}
$rChannel = $rRow['stream_display_name'];
if (0 < strlen($rRow['geoip_country_code'])) {
$rGeoCountry = "<img loading='lazy' src='assets/images/countries/" . strtolower($rRow['geoip_country_code']) . ".png'></img> &nbsp;";
} else {
$rGeoCountry = '';
}
if ($rRow['user_ip']) {
$rIP = $rGeoCountry . "<a onClick=\"whois('" . $rRow['user_ip'] . "');\" href='javascript: void(0);'>" . $rRow['user_ip'] . '</a>';
} 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 = "<button type='button' class='btn btn-" . $rColour . " btn-xs waves-effect waves-light btn-fixed'>" . $rDuration . '</button>';
$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 = '<i class="text-success fas fa-square tooltip" title="' . intval(100 - $rRow['divergence']) . '%"></i>';
} else {
if ($rRow['divergence'] <= 80) {
$rDivergence = '<i class="text-warning fas fa-square tooltip" title="' . intval(100 - $rRow['divergence']) . '%"></i>';
} else {
$rDivergence = '<i class="text-danger fas fa-square tooltip" title="' . intval(100 - $rRow['divergence']) . '%"></i>';
}
}
if ($rRow['is_mag']) {
$rUsername = "<a href='mag?id=" . $rRow['mag_id'] . "'>" . $rRow['username'] . '</a>';
} else {
if ($rRow['is_e2']) {
$rUsername = "<a href='enigma?id=" . $rRow['device_id'] . "'>" . $rRow['username'] . '</a>';
} else {
$rUsername = "<a href='line?id=" . $rRow['user_id'] . "'>" . $rRow['username'] . '</a>';
}
}
$rChannel = $rRow['stream_display_name'];
if (0 < strlen($rRow['geoip_country_code'])) {
$rGeoCountry = "<img loading='lazy' src='assets/images/countries/" . strtolower($rRow['geoip_country_code']) . ".png'></img> &nbsp;";
} else {
$rGeoCountry = '';
}
if ($rRow['user_ip']) {
$rIP = $rGeoCountry . "<a onClick=\"whois('" . $rRow['user_ip'] . "');\" href='javascript: void(0);'>" . $rRow['user_ip'] . '</a>';
} 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 = "<button type='button' class='btn btn-" . $rColour . " btn-xs waves-effect waves-light btn-fixed'>" . $rDuration . '</button>';
$rButtons = "<button title=\"Kill Connection\" type=\"button\" class=\"btn btn-light waves-effect waves-light btn-xs tooltip\" onClick=\"api('" . $rRow['uuid'] . "', 'kill');\"><i class=\"fas fa-hammer\"></i></button>";
$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 = "<a href='user?id=" . intval($rRow['owner']) . "'>" . $rRow['username'] . '</a>';
} else {
$rOwner = "<a href='user?id=" . intval($rRow['owner']) . "'>" . $rRow['username'] . "<br/><small class='text-pink'>(indirect)</small></a>";
}
$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 = "<a href='line?id=" . $rRow['log_id'] . "'>" . $rLine['username'] . '</a>';
}
break;
case 'user':
$rLine = UserRepository::getRegisteredUserById($rRow['log_id']);
if (!$rLine) {
} else {
$rLineInfo = "<a href='user?id=" . $rRow['log_id'] . "'>" . $rLine['username'] . '</a>';
}
break;
case 'mag':
$rLine = MagService::getById($rRow['log_id']);
if (!$rLine) {
} else {
$rLineInfo = "<a href='mag?id=" . $rRow['log_id'] . "'>" . $rLine['mac'] . '</a>';
}
break;
case 'enigma':
$rLine = EnigmaService::getById($rRow['log_id']);
if (!$rLine) {
} else {
$rLineInfo = "<a href='enigma?id=" . $rRow['log_id'] . "'>" . $rLine['mac'] . '</a>';
}
break;
}
if ($rLineInfo) {
} else {
$rDeletedInfo = json_decode($rRow['deleted_info'], true);
if (is_array($rDeletedInfo)) {
if (isset($rDeletedInfo['mac'])) {
$rLineInfo = "<span class='text-secondary'>" . $rDeletedInfo['mac'] . '</span>';
} else {
$rLineInfo = "<span class='text-secondary'>" . $rDeletedInfo['username'] . '</span>';
}
} else {
$rLineInfo = "<span class='text-secondary'>DELETED</span>";
}
}
$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 = '<i class="text-success fas fa-square"></i>';
} else {
$rStatus = '<i class="text-secondary fas fa-square"></i>';
}
if ($rRow['last_login']) {
} else {
$rRow['last_login'] = 'NEVER';
}
$rButtons = '<div class="btn-group">';
if (0 < strlen($rRow['notes'])) {
$rButtons .= '<button type="button" class="btn btn-light waves-effect waves-light btn-xs tooltip" title="' . $rRow['notes'] . '"><i class="mdi mdi-note"></i></button>';
} else {
$rButtons .= '<button disabled type="button" class="btn btn-light waves-effect waves-light btn-xs"><i class="mdi mdi-note"></i></button>';
}
if (in_array($rRow['id'], array_merge($rPermissions['direct_reports'], array($rUserInfo['id'])))) {
$rButtons .= '<button title="Adjust Credits" type="button" class="btn btn-light waves-effect waves-light btn-xs tooltip" onClick="addCredits(' . $rRow['id'] . ", '" . addslashes($rRow['username']) . "', " . intval($rRow['credits']) . ');"><i class="mdi mdi-coin"></i></button>';
$rUsername = "<a href='user?id=" . intval($rRow['id']) . "'>" . $rRow['username'] . '</a>';
} else {
$rButtons .= '<button title="Adjust Credits" type="button" class="btn btn-light waves-effect waves-light btn-xs tooltip" onClick="addCredits(' . $rRow['id'] . ", '" . addslashes($rRow['username']) . "', " . intval($rRow['credits']) . ', true);"><i class="mdi mdi-coin"></i></button>';
$rUsername = "<a href='user?id=" . intval($rRow['id']) . "'>" . $rRow['username'] . "<br/><small class='text-pink'>(indirect)</small></a>";
}
$rButtons .= '<a href="user?id=' . $rRow['id'] . '"><button title="Edit" type="button" class="btn btn-light waves-effect waves-light btn-xs tooltip"><i class="mdi mdi-pencil-outline"></i></button></a>';
if ($rRow['status'] == 1) {
$rButtons .= '<button title="Disable" type="button" class="btn btn-light waves-effect waves-light btn-xs tooltip" onClick="api(' . $rRow['id'] . ", 'disable');\"><i class=\"mdi mdi-lock\"></i></button>";
} else {
$rButtons .= '<button title="Enable" type="button" class="btn btn-light waves-effect waves-light btn-xs tooltip" onClick="api(' . $rRow['id'] . ", 'enable');\"><i class=\"mdi mdi-lock\"></i></button>";
}
if (!$rPermissions['delete_users']) {
} else {
$rButtons .= '<button title="Delete" type="button" class="btn btn-light waves-effect waves-light btn-xs tooltip" onClick="api(' . $rRow['id'] . ", 'delete');\"><i class=\"mdi mdi-close\"></i></button>";
}
$rButtons .= '</div>';
if (0 < strlen($rRow['ip'])) {
$rIP = "<a onClick=\"whois('" . $rRow['ip'] . "');\" href='javascript: void(0);'>" . $rRow['ip'] . '</a>';
} else {
$rIP = '';
}
if ($rRow['is_reseller']) {
$rCredits = '<button type="button" class="btn btn-info btn-xs waves-effect waves-light">' . number_format($rRow['credits'], 0) . '</button>';
} else {
$rCredits = '<button type="button" class="btn btn-secondary btn-xs waves-effect waves-light">-</button>';
}
if (0 < $rRow['user_count']) {
$rUserCount = '<button type="button" class="btn btn-info btn-xs waves-effect waves-light">' . number_format($rRow['user_count'], 0) . '</button>';
} else {
$rUserCount = '<button type="button" class="btn btn-secondary btn-xs waves-effect waves-light">0</button>';
}
if (in_array($rRow['owner_id'], array_merge($rPermissions['direct_reports'], array($rUserInfo['id'])))) {
$rOwner = "<a href='user?id=" . intval($rRow['owner_id']) . "'>" . $rRow['owner_username'] . '</a>';
} else {
$rOwner = "<a href='user?id=" . intval($rRow['owner_id']) . "'>" . $rRow['owner_username'] . "<br/><small class='text-pink'>(indirect)</small></a>";
}
$rReturn['data'][] = array("<a href='user?id=" . intval($rRow['id']) . "'>" . $rRow['id'] . '</a>', $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;
}
}
}