mirror of
https://github.com/FOSSBilling/FOSSBilling.git
synced 2026-11-09 05:24:58 +09:00
* Replace Custom Twig components Replace custom Twig components with native Twig components, remove unused custom Twig components, and move functionality to macros where appropriate. m Update partial_extensions.html.twig * Update Twig components and migrate to FOSSBilling namespace * Update Currency module... * Refactor Twig environment config and loading * Switch CSRF to cookie-based double-submit * Add Api Twig extension and restore widget/svg helpers * Cast language flags; improve JSON parsing * Add markdown DI service and use in Admin API * Refactor Twig extensions and markdown, simplify APIs * Add sandboxed email Twig env, update render APIs * Fix pagination URL usage and menu class * Fix HTML markup in email templates * Use macro for avatars and status badges * Fix Twig spacing and pagination URL filter order * Replace Custom Twig components Replace custom Twig components with native Twig components, remove unused custom Twig components, and move functionality to macros where appropriate. m Update partial_extensions.html.twig * Update Twig components and migrate to FOSSBilling namespace * Refactor Twig environment config and loading * Add Api Twig extension and restore widget/svg helpers * Cast language flags; improve JSON parsing * Add markdown DI service and use in Admin API * Refactor Twig extensions and markdown, simplify APIs * Fix pagination URL usage and menu class * Fix Twig spacing and pagination URL filter order * Use `current_theme` global and refactor `period_title` * Allow markdown and date in email Twig sandbox * Update email template examples * Fix Twig URLs, quoting, and logo alt text * Fix Twig templates: URLs, i18n, search params * Use `templates/*` directories for module templates * Tighten Twig sandbox and add tests * Add Twig environment and template docs to `AGENTS.md` * Use Symfony Filesystem/Finder and assorted fixes * Fix ticket reply link fragment concatenation * Close missing divs in dashboard template * Use detailed `toApiArray` for client * Fix module name resolution for email templates * Regenerate `composer.lock` * Use `markdown_to_html` filter in admin macro * Handle null price/quantity and rename test method * Use `Tools::isHTTPS()` for HTTPS checks * Add 'area' param to `url` filter and update templates * Use client area URLs in admin templates * Use client area and guest API URLs in templates * Remove client-side invoice delete feature * Create Twig env via `TwigFactory` for PDF rendering * Add embedded orderbutton JS and update render * Add 'srclink' to cspell allowlist * Use `renderEmailTplString` for email rendering * Bump twig/markdown-extra to v3.24 * Use `markdown_to_html` for privacy policy * Escape API JSON, handle null IP, client URLs * Remove initial admin creation flow * Handle HTTP failures and make tests robust * Use `api_url` helper in admin templates * Use `url` filter for footer link 5 * Add patch53 to remove legacy html templates * Bump setting last_patch to 53 * Add patch54 to restore legacy email templates * Use renderEmailTplString for email templating * Remove redundant else/endif in order template * Add file-hash cache buster for asset URLs * Remove raw Twig filter and handle missing modules dir * Return '-' for future timestamps * Register and reuse TwigFactory and add CSRF cookie * Adjust API URL helper and add Twig error handling * Update composer.lock and package-lock.json * Add twig_factory to ServiceTest DI * Use url filter for link_page in template * Composer - update deps and add markdown-extra * Remove docblocks and inline comments in `TwigFactory` * Add patches 53-55 and update `last_patch` * Add `has_permission` Twig function; exclude `href` * Remove duplicate network interface form * Guard removal of legacy dirs; add network input * Handle null category descriptions in template * Add Twig adapter env and sandbox policy * Add 'striptags' to cspell word list * Update composer.lock (deps updated/removed) * Sanitize custom payment adapter templates * Remove redundant legacy API tests * Bump `last_patch` setting to 56 * Coalesce null before `markdown_to_html` * Move update patcher to system CLI command * Remove stray `endif` from recaptcha macro * Update composer.lock * Fix extra closing brace in Api ServiceTest * Fix test errors from main merge - Remove testGetRequestCount tests (method moved to RateLimiter) - Remove testGetDi from Staff and System GuestTest (protected method) - Fix IP error message in testLoginCheckIpException - Add rate_limiter mock to Staff GuestTest tests that need it * Fix remaining Staff GuestTest issues - Add extension service mock for captcha check - Fix error message from 'User not found' to 'Admin not found' * Fix Staff GuestTest: update query and add logger mock * Fix Staff GuestTest: set admin status to active for password reset flow * Fix stale API calls and inverted required condition - Notification: replace removed system_string_render with direct output - Antispam settings: replace |alink/|link with |url/|api_url filters - build_form macro: fix inverted required condition for non-textarea inputs * Sanitize JS/data URIs and disable buttons by permission * Use client login/profile links in support emails * Encode fb-api JSON and tighten URL sanitization * Prefer session auth for API key methods * Remove stray endif and fix template formatting * Add CSRF token to CSV exports; fix template * Remove stray endif in currency template * Make invoice PDF generation return Response * Fix Twig filters, templates, and form handling * Remove readonly from anonymous class in test * Inline DebugBar CSS/JS in renderHead * Add Bootstrap Tab to global bootstrap * Capitalize template UI strings * Use CKEditor API for reply quotes * Remove WYSIWYG module and move CKEditor to themes * Bump `last_patch` in install SQL to 59 * Remove Spamchecker module * Run domain management script only for active orders * Standardize UI text capitalization & minor fixes * Remove Spamchecker legacy tests; fix period test * Rename Spamchecker tests to Antispam * Restore antispam config in tests; remove fixture * Refactor Antispam Guest tests for config checks * Update theme build docs; remove Wysiwyg module * Remove spamchecker from cspell and tweak comment * Add spamchecker to cspell word list * Capitalize 'Update Graphs' button label
132 lines
4.1 KiB
PHP
132 lines
4.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace APIHelper;
|
|
|
|
use Symfony\Component\Filesystem\Filesystem;
|
|
use Symfony\Component\Filesystem\Path;
|
|
|
|
class Request
|
|
{
|
|
/**
|
|
* Handles making a request to the FOSSBilling server.
|
|
*
|
|
* @param string $endpoint the API endpoint to call (Example: `guest/system/company`)
|
|
* @param string $method set to POST to have cURL make a POST request to the server
|
|
* @param array $payload when using POST, this array will be sent as the POST fields
|
|
* @param string|null $apiKey (optional) the API key to authenticate with
|
|
* @param string|null $baseUrl (optional) the base instance URL to make requests against (Example: `http://localhost/`)
|
|
*/
|
|
public static function makeRequest(string $endpoint, array $payload = [], ?string $role = null, ?string $apiKey = null, string $method = 'POST', ?string $baseUrl = null): Response
|
|
{
|
|
$cookie = Path::join(sys_get_temp_dir(), 'cookie.txt');
|
|
if (!$role) {
|
|
$role = str_starts_with($endpoint, 'admin') ? 'admin' : 'client';
|
|
}
|
|
|
|
if (!$apiKey) {
|
|
$apiKey = getenv('TEST_API_KEY');
|
|
}
|
|
|
|
if (!$baseUrl) {
|
|
$baseUrl = getenv('APP_URL');
|
|
}
|
|
|
|
$ch = curl_init($baseUrl . 'api/' . $endpoint);
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
|
|
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
|
|
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie);
|
|
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie);
|
|
curl_setopt($ch, CURLOPT_USERPWD, "$role:$apiKey");
|
|
|
|
if (strcasecmp($method, 'POST') === 0) {
|
|
curl_setopt($ch, CURLOPT_POST, true);
|
|
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($payload));
|
|
}
|
|
|
|
$output = curl_exec($ch);
|
|
if ($output === false) {
|
|
$error = curl_error($ch);
|
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
curl_close($ch);
|
|
|
|
throw new \RuntimeException('cURL request failed: ' . $error . ' (HTTP ' . $httpCode . ')');
|
|
}
|
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
curl_close($ch);
|
|
|
|
return new Response($httpCode, $output);
|
|
}
|
|
|
|
public static function resetCookies(): void
|
|
{
|
|
$filesystem = new Filesystem();
|
|
$filesystem->remove(Path::join(sys_get_temp_dir(), 'cookie.txt'));
|
|
}
|
|
}
|
|
|
|
class Response
|
|
{
|
|
private array $decodedResponse;
|
|
|
|
public function __construct(private readonly int $code, private readonly string $rawResponse)
|
|
{
|
|
$decoded = json_decode($this->rawResponse, true);
|
|
if (json_last_error() !== JSON_ERROR_NONE || !is_array($decoded)) {
|
|
$preview = strlen($this->rawResponse) > 500 ? substr($this->rawResponse, 0, 500) . '...' : $this->rawResponse;
|
|
|
|
throw new \RuntimeException('Invalid JSON response: ' . json_last_error_msg() . ' (HTTP ' . $this->code . '). Response: ' . $preview);
|
|
}
|
|
$this->decodedResponse = $decoded;
|
|
}
|
|
|
|
public function getHttpCode(): int
|
|
{
|
|
return $this->code;
|
|
}
|
|
|
|
public function getResponse(): array
|
|
{
|
|
return $this->decodedResponse;
|
|
}
|
|
|
|
public function getRawResponse(): string
|
|
{
|
|
return $this->rawResponse;
|
|
}
|
|
|
|
public function wasSuccessful(): bool
|
|
{
|
|
return !empty($this->decodedResponse)
|
|
&& array_key_exists('error', $this->decodedResponse)
|
|
&& empty($this->decodedResponse['error']);
|
|
}
|
|
|
|
public function getErrorMessage(): string
|
|
{
|
|
return $this->decodedResponse['error']['message'] ?? 'None';
|
|
}
|
|
|
|
public function getErrorCode(): int
|
|
{
|
|
return intval($this->decodedResponse['error']['code'] ?? 0);
|
|
}
|
|
|
|
public function getError(): string
|
|
{
|
|
return $this->getErrorMessage() . ' (Code ' . $this->getErrorCode() . ')';
|
|
}
|
|
|
|
public function generatePHPUnitMessage(): string
|
|
{
|
|
return 'The API request failed with the following message: ' . $this->getError();
|
|
}
|
|
|
|
public function getResult(): mixed
|
|
{
|
|
return $this->decodedResponse['result'] ?? '';
|
|
}
|
|
}
|