diff --git a/src/domain/User/GroupService.php b/src/domain/User/GroupService.php index 5b51baca..3c173d70 100644 --- a/src/domain/User/GroupService.php +++ b/src/domain/User/GroupService.php @@ -13,16 +13,34 @@ class GroupService { private static $db = null; + /** + * Inject the database handler (dependency injection). + * + * @param object $db Database handler. + * @return void + */ public static function setDb($db): void { self::$db = $db; } + /** + * Get the injected database handler. + * + * @return object Database handler. + * @throws \RuntimeException If setDb() was not called first. + */ private static function db(): object { if (self::$db === null) { throw new \RuntimeException(static::class . '::setDb() must be called before use.'); } return self::$db; } + /** + * Create or update a user group from admin form data. + * + * @param array $rData Submitted form data (includes `edit` id when updating). + * @return array ['status' => STATUS_* constant, 'data' => insert_id or payload]. + */ public static function process($rData) { $db = self::db(); if (InputValidator::validate('processGroup', $rData)) { @@ -111,6 +129,11 @@ class GroupService { // ──────────── Из GroupRepository ──────────── + /** + * Fetch all user groups. + * + * @return array Group rows. + */ public static function getAll() { $db = self::db(); $rReturn = array(); @@ -126,6 +149,12 @@ class GroupService { return $rReturn; } + /** + * Fetch a single user group by id. + * + * @param int $rID Group id. + * @return array|false The group row, or false if not found. + */ public static function getById($rID) { $db = self::db(); $db->query('SELECT * FROM `users_groups` WHERE `group_id` = ?;', $rID); @@ -136,6 +165,12 @@ class GroupService { } } + /** + * Delete a user group. + * + * @param int $rID Group id. + * @return bool True on deletion, false if the group does not exist. + */ public static function deleteById($rID) { $db = self::db(); $rGroup = self::getById($rID); diff --git a/src/domain/User/ResellerAPI.php b/src/domain/User/ResellerAPI.php index 56cd2abb..eac535a8 100644 --- a/src/domain/User/ResellerAPI.php +++ b/src/domain/User/ResellerAPI.php @@ -13,10 +13,22 @@ class ResellerAPI { private static $db = null; + /** + * Inject the database handler (dependency injection). + * + * @param object $db Database handler. + * @return void + */ public static function setDb($db): void { self::$db = $db; } + /** + * Get the injected database handler. + * + * @return object Database handler. + * @throws \RuntimeException If setDb() was not called first. + */ private static function db(): object { if (self::$db === null) { throw new \RuntimeException(static::class . '::setDb() must be called before use.'); @@ -29,6 +41,13 @@ class ResellerAPI { public static $rUserInfo = array(); public static $rPermissions = array(); + /** + * Dispatch a reseller API action by type. + * + * @param string $rType Action type (line, mag, enigma, user, ticket, ...). + * @param array $rData Request payload. + * @return array Action result. + */ public static function processData($rType, $rData) { $rArray = array('line' => array('edit', 'trial', 'bouquets_selected', 'pair_id', 'username', 'password', 'member_id', 'package', 'contact', 'reseller_notes', 'allowed_ips', 'allowed_ua', 'bypass_ua', 'is_isplock', 'isp_clear'), 'mag' => array('edit', 'trial', 'bouquets_selected', 'pair_id', 'mac', 'member_id', 'package', 'parent_password', 'sn', 'stb_type', 'image_version', 'hw_version', 'device_id', 'device_id2', 'ver', 'reseller_notes', 'allowed_ips', 'is_isplock', 'isp_clear'), 'enigma' => array('edit', 'trial', 'bouquets_selected', 'pair_id', 'mac', 'member_id', 'package', 'modem_mac', 'local_ip', 'enigma_version', 'cpu', 'lversion', 'token', 'reseller_notes', 'allowed_ips', 'is_isplock', 'isp_clear'), 'user' => array('edit', 'username', 'password', 'owner_id', 'email', 'reseller_dns', 'notes', 'member_group_id'), 'ticket' => array('edit', 'message', 'title', 'respond'), 'profile' => array('email', 'password', 'api_key', 'reseller_dns', 'theme', 'hue', 'timezone')); @@ -42,6 +61,12 @@ class ResellerAPI { return $rData; } + /** + * Initialize the reseller API context (permissions, current user). + * + * @param int|null $rUserID Reseller user id, or null for the current session user. + * @return void + */ public static function init($rUserID = null) { $db = self::db(); global $rPermissions; @@ -61,6 +86,12 @@ class ResellerAPI { } } + /** + * Update the current reseller's own profile. + * + * @param array $rData Submitted profile fields. + * @return array Result status payload. + */ public static function editResellerProfile($rData) { $db = self::db(); global $rHues; @@ -105,10 +136,22 @@ class ResellerAPI { return array('status' => STATUS_INVALID_EMAIL); } + /** + * Handle a reseller login request. + * + * @param array $rData Login payload. + * @return array Result status payload. + */ public static function processLogin($rData) { return Authenticator::resellerLogin($rData); } + /** + * Create or update a MAG device line on behalf of a reseller. + * + * @param array $rData Submitted MAG/line data. + * @return array Result status payload. + */ public static function processMAG($rData) { $db = self::db(); $rData = self::processData('mag', $rData); @@ -390,6 +433,12 @@ class ResellerAPI { } } + /** + * Create or update an Enigma2 device line on behalf of a reseller. + * + * @param array $rData Submitted Enigma2/line data. + * @return array Result status payload. + */ public static function processEnigma($rData) { $db = self::db(); $rData = self::processData('enigma', $rData); @@ -669,6 +718,12 @@ class ResellerAPI { } } + /** + * Create or update a sub-user on behalf of a reseller. + * + * @param array $rData Submitted user data. + * @return array Result status payload. + */ public static function processUser($rData) { $db = self::db(); $rData = self::processData('user', $rData); @@ -791,6 +846,12 @@ class ResellerAPI { return false; } + /** + * Submit a support ticket on behalf of a reseller. + * + * @param array $rData Ticket payload. + * @return array Result status payload. + */ public static function submitTicket($rData) { $db = self::db(); $rData = self::processData('ticket', $rData); @@ -851,6 +912,12 @@ class ResellerAPI { return array('status' => STATUS_INVALID_DATA, 'data' => $rData); } + /** + * Create or update a line on behalf of a reseller. + * + * @param array $rData Submitted line data. + * @return array Result status payload. + */ public static function processLine($rData) { $db = self::db(); $rData = self::processData('line', $rData); diff --git a/src/domain/User/TicketRepository.php b/src/domain/User/TicketRepository.php index a96c2b53..4ba69f59 100644 --- a/src/domain/User/TicketRepository.php +++ b/src/domain/User/TicketRepository.php @@ -13,16 +13,34 @@ class TicketRepository { private static $db = null; + /** + * Inject the database handler (dependency injection). + * + * @param object $db Database handler. + * @return void + */ public static function setDb($db): void { self::$db = $db; } + /** + * Get the injected database handler. + * + * @return object Database handler. + * @throws \RuntimeException If setDb() was not called first. + */ private static function db(): object { if (self::$db === null) { throw new \RuntimeException(static::class . '::setDb() must be called before use.'); } return self::$db; } + /** + * Fetch a single ticket (with its messages) by id. + * + * @param int $rID Ticket id. + * @return array|false The ticket row, or false if not found. + */ public static function getById($rID) { $db = self::db(); $db->query('SELECT * FROM `tickets` WHERE `id` = ?;', $rID); @@ -50,6 +68,13 @@ class TicketRepository { return $rRow; } + /** + * List tickets, optionally scoped to a user or to the admin view. + * + * @param int|null $rID Owner user id, or null for all. + * @param bool $rAdmin Use admin scope (all tickets). + * @return array Ticket rows. + */ public static function getAll($rID = null, $rAdmin = false) { $db = self::db(); global $rUserInfo; @@ -124,6 +149,12 @@ class TicketRepository { return $rReturn; } + /** + * Delete a ticket and its messages. + * + * @param int $rID Ticket id. + * @return bool True on deletion, false if not found. + */ public static function deleteById($rID) { $db = self::db(); $db->query('SELECT `id` FROM `tickets` WHERE `id` = ?;', $rID); diff --git a/src/domain/User/UserRepository.php b/src/domain/User/UserRepository.php index e368084f..0b16432c 100644 --- a/src/domain/User/UserRepository.php +++ b/src/domain/User/UserRepository.php @@ -13,16 +13,35 @@ class UserRepository { private static $db = null; + /** + * Inject the database handler (dependency injection). + * + * @param object $db Database handler. + * @return void + */ public static function setDb($db): void { self::$db = $db; } + /** + * Get the injected database handler. + * + * @return object Database handler. + * @throws \RuntimeException If setDb() was not called first. + */ private static function db(): object { if (self::$db === null) { throw new \RuntimeException(static::class . '::setDb() must be called before use.'); } return self::$db; } + /** + * Fetch an admin/reseller user matching the given login credentials. + * + * @param string $rUsername Username. + * @param string $rPassword Plain-text password. + * @return array|null The user row, or null if credentials are invalid. + */ public static function getAuthUserByCredentials($rUsername, $rPassword) { $db = self::db(); $db->query('SELECT `id`, `username`, `password`, `member_group_id`, `status` FROM `users` WHERE `username` = ? LIMIT 1;', $rUsername); @@ -36,6 +55,13 @@ class UserRepository { } } + /** + * List resellers under a given owner. + * + * @param int $rOwner Owner user id. + * @param bool $rIncludeSelf Include the owner in the result. + * @return array Reseller rows. + */ public static function getResellers($rOwner, $rIncludeSelf = true) { $db = self::db(); if ($rIncludeSelf) { @@ -47,6 +73,14 @@ class UserRepository { return $db->get_rows(true, 'id'); } + /** + * Get the direct sub-users (reports) of the current user. + * + * @param array $rPermissions Effective permissions. + * @param array $rUserInfo Current user row. + * @param bool $rIncludeSelf Include the user themselves. + * @return array Direct report rows. + */ public static function getDirectReports($rPermissions, $rUserInfo, $rIncludeSelf = true) { $db = self::db(); $rUserIDs = $rPermissions['direct_reports']; @@ -73,6 +107,14 @@ class UserRepository { return $rReturn; } + /** + * Resolve the parent of a user within the permission scope. + * + * @param array $rPermissions Effective permissions. + * @param array $rUserInfo Current user row. + * @param int $rID Target user id. + * @return array|null Parent user row, or null. + */ public static function getParent($rPermissions, $rUserInfo, $rID) { if (!isset($rPermissions['users'][$rID]['parent']) || $rPermissions['users'][$rID]['parent'] == 0 || $rPermissions['users'][$rID]['parent'] == $rUserInfo['id']) { return $rID; @@ -81,6 +123,12 @@ class UserRepository { return self::getParent($rPermissions, $rUserInfo, $rPermissions['users'][$rID]['parent']); } + /** + * Get all descendant sub-users of a user (full report tree). + * + * @param int $rUser User id. + * @return array Sub-user rows keyed by id. + */ public static function getSubUsers($rUser) { $db = self::db(); $rReturn = array(); @@ -97,6 +145,12 @@ class UserRepository { return $rReturn; } + /** + * Fetch a line by id. + * + * @param int $rID Line id. + * @return array|null The line row, or null if not found. + */ public static function getLineById($rID) { $db = self::db(); $db->query('SELECT * FROM `lines` WHERE `id` = ?;', $rID); @@ -107,6 +161,12 @@ class UserRepository { } } + /** + * Fetch a registered (panel) user by id. + * + * @param int $rID User id. + * @return array|null The user row, or null if not found. + */ public static function getRegisteredUserById($rID) { $db = self::db(); $db->query('SELECT * FROM `users` WHERE `id` = ?;', $rID); @@ -117,6 +177,13 @@ class UserRepository { } } + /** + * List registered users under an owner. + * + * @param int|null $rOwner Owner id, or null for all. + * @param bool $rIncludeSelf Include the owner in the result. + * @return array Registered user rows. + */ public static function getRegisteredUsers($rOwner = null, $rIncludeSelf = true) { $db = self::db(); $rReturn = array(); @@ -139,6 +206,23 @@ class UserRepository { return $rReturn; } + /** + * Resolve a streaming user's info (auth + entitlements). + * + * Looks the user up by id or username/password, then assembles their + * bouquets and, optionally, allowed channel ids and active connections. + * + * @param array $rSettings Panel settings. + * @param bool $rCached Use cached lookups. + * @param array $rBouquets Bouquet definitions. + * @param int|null $rUserID User id (when known). + * @param string|null $rUsername Username (credential lookup). + * @param string|null $rPassword Password (credential lookup). + * @param bool $rGetChannelIDs Include allowed channel ids. + * @param bool $rGetConnections Include active connections. + * @param string $rIP Client IP. + * @return array|null User info, or null if not found. + */ public static function getStreamingUserInfo($rSettings, $rCached, $rBouquets, $rUserID = null, $rUsername = null, $rPassword = null, $rGetChannelIDs = false, $rGetConnections = false, $rIP = '') { global $rBlockedISP, $rBlockedServers; $db = self::db(); @@ -323,6 +407,17 @@ class UserRepository { return $rUserInfo; } + /** + * Resolve user info for streaming endpoints (wrapper over getStreamingUserInfo). + * + * @param int|null $rUserID User id (when known). + * @param string|null $rUsername Username (credential lookup). + * @param string|null $rPassword Password (credential lookup). + * @param bool $rGetChannelIDs Include allowed channel ids. + * @param bool $rGetConnections Include active connections. + * @param string $rIP Client IP. + * @return array|null User info, or null if not found. + */ public static function getUserInfo($rUserID = null, $rUsername = null, $rPassword = null, $rGetChannelIDs = false, $rGetConnections = false, $rIP = '') { global $rSettings; $db = self::db(); @@ -504,6 +599,15 @@ class UserRepository { return $rUserInfo; } + /** + * Resolve Enigma2 device user info. + * + * @param array $rDevice Device row (MAC etc.). + * @param bool $rGetChannelIDs Include allowed channel ids. + * @param bool $rGetBouquetInfo Include bouquet info. + * @param bool $rGetConnections Include active connections. + * @return array|null Device user info, or null if not found. + */ public static function getE2Info($rDevice, $rGetChannelIDs = false, $rGetBouquetInfo = false, $rGetConnections = false) { $db = self::db(); if (empty($rDevice['device_id'])) { diff --git a/src/domain/User/UserService.php b/src/domain/User/UserService.php index ef772a5e..a8a62fe4 100644 --- a/src/domain/User/UserService.php +++ b/src/domain/User/UserService.php @@ -13,16 +13,34 @@ class UserService { private static $db = null; + /** + * Inject the database handler (dependency injection). + * + * @param object $db Database handler. + * @return void + */ public static function setDb($db): void { self::$db = $db; } + /** + * Get the injected database handler. + * + * @return object Database handler. + * @throws \RuntimeException If setDb() was not called first. + */ private static function db(): object { if (self::$db === null) { throw new \RuntimeException(static::class . '::setDb() must be called before use.'); } return self::$db; } + /** + * Bulk delete a set of selected users. + * + * @param array $rData Selected user ids. + * @return array ['status' => STATUS_* constant, ...]. + */ public static function massDelete($rData) { set_time_limit(0); ini_set('mysql.connect_timeout', 0); @@ -35,6 +53,12 @@ class UserService { return array('status' => STATUS_SUCCESS); } + /** + * Apply bulk edits to a set of selected users. + * + * @param array $rData Selected ids plus the fields/values to apply. + * @return array ['status' => STATUS_* constant, ...]. + */ public static function massEdit($rData) { $db = self::db(); if (InputValidator::validate('massEditUsers', $rData)) { @@ -104,6 +128,13 @@ class UserService { } } + /** + * Create or update a user from admin form data. + * + * @param array $rData Submitted form data (includes `edit` id when updating). + * @param bool $rBypassAuth Skip permission checks (internal/trusted callers). + * @return array ['status' => STATUS_* constant, 'data' => insert_id or payload]. + */ public static function process($rData, $rBypassAuth = false) { $db = self::db(); if (InputValidator::validate('processUser', $rData)) { @@ -188,6 +219,14 @@ class UserService { } } + /** + * Update the current admin's own profile. + * + * @param array $rData Submitted profile fields. + * @param array $rUserInfo Current admin user row. + * @param array $allowedLangs Allowed UI languages. + * @return array Result status payload. + */ public static function editAdminProfile($rData, $rUserInfo, $allowedLangs) { $db = self::db(); if (!(0 >= strlen($rData['email']) || filter_var($rData['email'], FILTER_VALIDATE_EMAIL))) { @@ -213,6 +252,13 @@ class UserService { return array('status' => STATUS_SUCCESS); } + /** + * Submit a support ticket as an admin user. + * + * @param array $rData Ticket payload. + * @param array $rUserInfo Current admin user row. + * @return array Result status payload. + */ public static function submitTicket($rData, $rUserInfo) { $db = self::db(); if (isset($rData['edit'])) { @@ -255,6 +301,15 @@ class UserService { return array('status' => STATUS_SUCCESS, 'data' => array('insert_id' => $rData['respond'])); } + /** + * Delete a registered user with configurable cascade behavior. + * + * @param int $rID User id. + * @param bool $rDeleteSubUsers Also delete the user's sub-users. + * @param bool $rDeleteLines Also delete the user's lines. + * @param int|null $rReplaceWith Reassign sub-users/lines to this owner instead. + * @return bool True on success. + */ public static function deleteRegisteredUser($rID, $rDeleteSubUsers = false, $rDeleteLines = false, $rReplaceWith = null) { $db = self::db(); $rUser = UserRepository::getRegisteredUserById($rID); @@ -292,6 +347,12 @@ class UserService { return true; } + /** + * Bulk delete registered users. + * + * @param int[] $rIDs User ids. + * @return bool True on success. + */ public static function deleteRegisteredUsers($rIDs) { $db = self::db(); $rIDs = AdminHelpers::confirmIDs($rIDs);