|
| 1 | +--- |
| 2 | +name: license-function |
| 3 | +description: Adds a new procedural license function to src/cpanel.inc.php following the existing pattern: create Cpanel instance, make API call, log with request_log and myadmin_log, return result. Use when user says 'add license function', 'new cpanel function', 'add API wrapper'. Do NOT use for Plugin.php class methods. |
| 4 | +--- |
| 5 | +# License Function |
| 6 | + |
| 7 | +Add a new procedural license function to `src/cpanel.inc.php` following the established patterns in this cPanel licensing plugin. |
| 8 | + |
| 9 | +## Critical |
| 10 | + |
| 11 | +- All functions go in `src/cpanel.inc.php` — NEVER in `src/Plugin.php` (that file is for event handlers only). |
| 12 | +- Every function that calls the cPanel API MUST log via `request_log()` with the exact 7-argument signature used in existing code. |
| 13 | +- Always instantiate `\Detain\Cpanel\Cpanel` with the constants `CPANEL_LICENSING_USERNAME` and `CPANEL_LICENSING_PASSWORD` — never hardcode or pass credentials. |
| 14 | +- If the function accepts an IP address, validate it with `validIp($ipAddress, false)` before making any API call, returning `false` on invalid input. |
| 15 | +- The module is always `'licenses'` — use `$module = 'licenses';` or the string literal directly. |
| 16 | +- After adding the function, register it in `Plugin.php` → `getRequirements()` so the lazy-loader can find it. |
| 17 | + |
| 18 | +## Instructions |
| 19 | + |
| 20 | +1. **Read existing functions in `src/cpanel.inc.php`** to confirm the current patterns and avoid name collisions. Every function in this file follows a naming convention: `{action}_cpanel` or `get_cpanel_{thing}`. Name your function to match. |
| 21 | + - Verify: your function name does not already exist in the file. |
| 22 | + |
| 23 | +2. **Write the PHPDoc block** above the function. Follow the existing format: |
| 24 | + ```php |
| 25 | + /** |
| 26 | + * function_name() |
| 27 | + * brief description of what it does |
| 28 | + * |
| 29 | + * @param type $paramName description |
| 30 | + * @return type description |
| 31 | + */ |
| 32 | + ``` |
| 33 | + - Verify: the `@param` and `@return` types match actual usage. |
| 34 | + |
| 35 | +3. **Write the function body** using this exact skeleton (derived from `activate_cpanel`, `verify_cpanel`, `get_cpanel_license_data_by_ip`): |
| 36 | + |
| 37 | + ```php |
| 38 | + function your_function_name($ipAddress) |
| 39 | + { |
| 40 | + // Step A: (If IP-based) Validate input |
| 41 | + if (!validIp($ipAddress, false)) { |
| 42 | + return false; |
| 43 | + } |
| 44 | + |
| 45 | + // Step B: Instantiate the cPanel API client |
| 46 | + $cpl = new \Detain\Cpanel\Cpanel(CPANEL_LICENSING_USERNAME, CPANEL_LICENSING_PASSWORD); |
| 47 | + |
| 48 | + // Step C: Build the request array |
| 49 | + $request = ['ip' => $ipAddress]; |
| 50 | + |
| 51 | + // Step D: Call the appropriate API method |
| 52 | + $response = $cpl->apiMethodName($request); |
| 53 | + |
| 54 | + // Step E: Log the API call with request_log |
| 55 | + request_log('licenses', false, __FUNCTION__, 'cpanel', 'apiMethodName', $request, $response); |
| 56 | + |
| 57 | + // Step F: (Optional) Log additional info with myadmin_log |
| 58 | + myadmin_log('licenses', 'info', json_encode($response), __LINE__, __FILE__); |
| 59 | + |
| 60 | + // Step G: Process and return the result |
| 61 | + return $response; |
| 62 | + } |
| 63 | + ``` |
| 64 | + |
| 65 | + Key details for each step: |
| 66 | + - **Step A**: Only needed for IP-based functions. Use `validIp($ipAddress, false)` — the `false` second arg disables IPv6-only check. |
| 67 | + - **Step B**: Always use `\Detain\Cpanel\Cpanel` with the two constant args. Never `use` import it at file level (this is a procedural file with no namespace). |
| 68 | + - **Step C**: Build request as associative array. Keys match cPanel Manage2 API parameters. |
| 69 | + - **Step E**: `request_log` signature: `request_log($module, $accountId, $functionName, $provider, $apiMethod, $request, $response)`. Use `$GLOBALS['tf']->session->account_id` for the account ID when the function runs in an authenticated user context, or `false` when it runs in admin/background context. |
| 70 | + - **Step F**: Use `myadmin_log('licenses', $level, $message, __LINE__, __FILE__)` — level is typically `'info'` or `'error'`. |
| 71 | + |
| 72 | + - Verify: the function uses `\Detain\Cpanel\Cpanel` (not `Cpanel` unqualified), calls `request_log` with all 7 args, and returns a value. |
| 73 | + |
| 74 | +4. **Register the function in `src/Plugin.php` → `getRequirements()`**. Add a line using the same path pattern as existing entries: |
| 75 | + |
| 76 | + ```php |
| 77 | + $loader->add_requirement('your_function_name', '/../vendor/detain/myadmin-cpanel-licensing/src/cpanel.inc.php'); |
| 78 | + ``` |
| 79 | + |
| 80 | + Use `add_requirement` for functions callable from other modules. Use `add_page_requirement` for functions that render pages or are only used in web context. |
| 81 | + |
| 82 | + - Verify: the string passed to `add_requirement` exactly matches the function name. |
| 83 | + |
| 84 | +5. **Run lint and tests**: |
| 85 | + ```bash |
| 86 | + php -l src/cpanel.inc.php |
| 87 | + php -l src/Plugin.php |
| 88 | + vendor/bin/phpunit |
| 89 | + ``` |
| 90 | + - Verify: no syntax errors and all tests pass. |
| 91 | + |
| 92 | +## Examples |
| 93 | + |
| 94 | +### User says: "Add a function to change the package of a cPanel license by IP" |
| 95 | + |
| 96 | +**Actions taken:** |
| 97 | + |
| 98 | +1. Read `src/cpanel.inc.php` to confirm no `change_cpanel_package` function exists. |
| 99 | +2. Add the function at the end of `src/cpanel.inc.php` (before the closing `?>` if present, or at end of file): |
| 100 | + |
| 101 | +```php |
| 102 | +/** |
| 103 | + * change_cpanel_package() |
| 104 | + * changes the package on an existing cpanel license |
| 105 | + * |
| 106 | + * @param string $ipAddress ip address of the license |
| 107 | + * @param integer $packageId the new package id |
| 108 | + * @return array|bool the response attributes or false on failure |
| 109 | + */ |
| 110 | +function change_cpanel_package($ipAddress, $packageId) |
| 111 | +{ |
| 112 | + if (!validIp($ipAddress, false)) { |
| 113 | + return false; |
| 114 | + } |
| 115 | + $packageId = (int) $packageId; |
| 116 | + $cpl = new \Detain\Cpanel\Cpanel(CPANEL_LICENSING_USERNAME, CPANEL_LICENSING_PASSWORD); |
| 117 | + $request = ['ip' => $ipAddress, 'packageid' => $packageId]; |
| 118 | + $response = $cpl->changePackage($request); |
| 119 | + request_log('licenses', false, __FUNCTION__, 'cpanel', 'changePackage', $request, $response); |
| 120 | + myadmin_log('licenses', 'info', "change_cpanel_package({$ipAddress}, {$packageId}) returned " . json_encode($response['attr']), __LINE__, __FILE__); |
| 121 | + if (isset($response['attr']['reason']) && $response['attr']['reason'] == 'OK') { |
| 122 | + return $response['attr']; |
| 123 | + } |
| 124 | + return false; |
| 125 | +} |
| 126 | +``` |
| 127 | + |
| 128 | +3. Register in `src/Plugin.php` → `getRequirements()`: |
| 129 | +```php |
| 130 | +$loader->add_requirement('change_cpanel_package', '/../vendor/detain/myadmin-cpanel-licensing/src/cpanel.inc.php'); |
| 131 | +``` |
| 132 | + |
| 133 | +4. Run `php -l src/cpanel.inc.php && php -l src/Plugin.php && vendor/bin/phpunit`. |
| 134 | + |
| 135 | +**Result:** New function follows exact project patterns — procedural, uses constants for auth, logs both via `request_log` and `myadmin_log`, validates IP input, casts integer params. |
| 136 | + |
| 137 | +## Common Issues |
| 138 | + |
| 139 | +- **`Fatal error: Class 'Detain\Cpanel\Cpanel' not found`**: The `detain/cpanel-licensing` package is not installed. Run `composer install` or `composer require detain/cpanel-licensing:dev-master`. |
| 140 | + |
| 141 | +- **`Call to undefined function request_log()`**: This function is defined in the main MyAdmin framework, not in this plugin. The function is only available when running within the full MyAdmin application context. Tests in this plugin use reflection/static analysis and do NOT bootstrap the framework — do not expect `request_log` to be callable in unit tests. |
| 142 | + |
| 143 | +- **`Call to undefined function validIp()`**: Same as above — `validIp()` is from `include/validations.php` in the main MyAdmin repo. Available at runtime but not in isolated plugin tests. |
| 144 | + |
| 145 | +- **`Undefined constant CPANEL_LICENSING_USERNAME`**: The constants are set via the settings system at runtime. For CLI scripts in `bin/`, ensure you include the appropriate bootstrap. For tests, mock or skip — existing tests use static file analysis to avoid needing these constants. |
| 146 | + |
| 147 | +- **Function not found at runtime after adding it**: You forgot to register it in `Plugin.php` → `getRequirements()`. The MyAdmin lazy-loader only knows about functions listed there. Also verify the `function_requirements('your_function_name')` call is made before invoking your function from Plugin event handlers. |
| 148 | + |
| 149 | +- **`request_log` second argument confusion**: Use `$GLOBALS['tf']->session->account_id` when the function is called during an authenticated user action (like `activate_cpanel` does). Use `false` when running in admin/background/CLI context (like `deactivate_cpanel`, `verify_cpanel` do). |
| 150 | + |
| 151 | +- **Tests fail after adding function**: The `SourceFileAnalysisTest.php` reads `src/` files via `file_get_contents` and checks for patterns. If your function has syntax errors or doesn't follow conventions, it may trigger test failures. Run `php -l src/cpanel.inc.php` first to catch syntax issues. |
0 commit comments