2026-04-20 20:35:18 +03:00
<? php
2026-06-25 18:45:19 +03:00
namespace XcVm\Infrastructure ;
2026-06-24 20:52:00 +03:00
use XcVm\Core\Config\SettingsManager ;
2026-06-25 20:24:36 +03:00
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 ;
2026-04-20 20:35:18 +03:00
/**
* 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
2026-06-25 20:32:18 +03:00
* @link https://github.com/Vateron-Media/XC_VM
2026-04-20 20:35:18 +03:00
* @license AGPL-3.0 https://www.gnu.org/licenses/agpl-3.0.html
*/
class ResellerTableRenderer {
2026-06-22 16:18:44 +03:00
/**
* 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
*/
2026-04-20 20:35:18 +03:00
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 ;
}
}
2026-06-22 16:18:44 +03:00
/**
* 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.
2026-06-24 21:15:06 +03:00
* @param \XcVm\Core\Database\DatabaseHandler $db Database handler.
2026-06-22 16:18:44 +03:00
* @param int $rStart Pagination offset.
* @param int $rLimit Page size.
* @return void
*/
2026-04-20 20:35:18 +03:00
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 = '∞' ;
}
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'>∞</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 ();
}
2026-06-22 16:18:44 +03:00
/**
* 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.
2026-06-24 21:15:06 +03:00
* @param \XcVm\Core\Database\DatabaseHandler $db Database handler.
2026-06-22 16:18:44 +03:00
* @param int $rStart Pagination offset.
* @param int $rLimit Page size.
* @return void
*/
2026-04-20 20:35:18 +03:00
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 = '∞' ;
}
$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 ();
}
2026-06-22 16:18:44 +03:00
/**
* 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.
2026-06-24 21:15:06 +03:00
* @param \XcVm\Core\Database\DatabaseHandler $db Database handler.
2026-06-22 16:18:44 +03:00
* @param int $rStart Pagination offset.
* @param int $rLimit Page size.
* @return void
*/
2026-04-20 20:35:18 +03:00
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 = '∞' ;
}
$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 ();
}
2026-06-22 16:18:44 +03:00
/**
* 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.
2026-06-24 21:15:06 +03:00
* @param \XcVm\Core\Database\DatabaseHandler $db Database handler.
2026-06-22 16:18:44 +03:00
* @param int $rStart Pagination offset.
* @param int $rLimit Page size.
* @return void
*/
2026-04-20 20:35:18 +03:00
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 ();
}
2026-06-22 16:18:44 +03:00
/**
* 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.
2026-06-24 21:15:06 +03:00
* @param \XcVm\Core\Database\DatabaseHandler $db Database handler.
2026-06-22 16:18:44 +03:00
* @param int $rStart Pagination offset.
* @param int $rLimit Page size.
* @return void
*/
2026-04-20 20:35:18 +03:00
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 ();
}
2026-06-22 16:18:44 +03:00
/**
* 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.
2026-06-24 21:15:06 +03:00
* @param \XcVm\Core\Database\DatabaseHandler $db Database handler.
2026-06-22 16:18:44 +03:00
* @param int $rStart Pagination offset.
* @param int $rLimit Page size.
* @return void
*/
2026-04-20 20:35:18 +03:00
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 ();
}
2026-06-22 16:18:44 +03:00
/**
* 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.
2026-06-24 21:15:06 +03:00
* @param \XcVm\Core\Database\DatabaseHandler $db Database handler.
2026-06-22 16:18:44 +03:00
* @param int $rStart Pagination offset.
* @param int $rLimit Page size.
* @return void
*/
2026-04-20 20:35:18 +03:00
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 ();
}
2026-06-22 16:18:44 +03:00
/**
* 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.
2026-06-24 21:15:06 +03:00
* @param \XcVm\Core\Database\DatabaseHandler $db Database handler.
2026-06-22 16:18:44 +03:00
* @param int $rStart Pagination offset.
* @param int $rLimit Page size.
* @return void
*/
2026-04-20 20:35:18 +03:00
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> " ;
} 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 ();
}
2026-06-22 16:18:44 +03:00
/**
* 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.
2026-06-24 21:15:06 +03:00
* @param \XcVm\Core\Database\DatabaseHandler $db Database handler.
2026-06-22 16:18:44 +03:00
* @param int $rStart Pagination offset.
* @param int $rLimit Page size.
* @return void
*/
2026-04-20 20:35:18 +03:00
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> " ;
} 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 ();
}
2026-06-22 16:18:44 +03:00
/**
* 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.
2026-06-24 21:15:06 +03:00
* @param \XcVm\Core\Database\DatabaseHandler $db Database handler.
2026-06-22 16:18:44 +03:00
* @param int $rStart Pagination offset.
* @param int $rLimit Page size.
* @return void
*/
2026-04-20 20:35:18 +03:00
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 ();
}
2026-06-22 16:18:44 +03:00
/**
* 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.
2026-06-24 21:15:06 +03:00
* @param \XcVm\Core\Database\DatabaseHandler $db Database handler.
2026-06-22 16:18:44 +03:00
* @param int $rStart Pagination offset.
* @param int $rLimit Page size.
* @return void
*/
2026-04-20 20:35:18 +03:00
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 ();
}
2026-06-22 16:18:44 +03:00
/**
* 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.
*/
2026-04-20 20:35:18 +03:00
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 ;
}
}
}