mirror of
https://github.com/FOSSBilling/FOSSBilling.git
synced 2026-11-08 21:15:33 +09:00
Hand-extracted fromb364588f3(#4166), same rationale as the Plesk fix in 3848e6258 -- this piece is unrelated to everything else that huge commit bundled together and stands on its own. Two bugs in Server_Manager_Directadmin, both against the same Server_Package::__call() silent-failure trap (undefined method calls error_log and return '' rather than fail loudly): - modifyAccount() built its own separate $fields array instead of reusing getCustomPackageFields() (the array createAccount() already builds correctly). It called getHasAnonymousFtp(), getHasCatchAll(), getHasCgi(), getHasCron(), getHasPhp(), getHasSpamFilter(), getHasShell(), getHasSsl(), getMaxEmailForwarders(), getMaxEmailLists(), and getMaxEmailAutoresponders() -- none of which exist on Server_Package. Every DirectAdmin account update through FOSSBilling silently reset aftp/catchall/cgi/cron/php/spam/ssh/ssl to OFF and email quotas to 0/empty, regardless of the hosting plan's actual configuration. - getCustomPackageFields() itself (used by createAccount(), and now reused by modifyAccount()) had already been fixed for most fields but still called getMaxEmailForwarders()/getMaxEmailLists()/ getMaxEmailAutoresponders() for nemailf/nemailml/nemailr, hitting the same silent-empty trap for those three on account creation too. modifyAccount() now calls getCustomPackageFields($package) and layers its own dnscontrol/sysinfo/action/ns1/ns2/user fields on top, instead of maintaining a second, drifted-out-of-sync copy. nemailf/nemailml/ nemailr now read getCustomValue() like every other field in that method. Introduces getCustomPackageFlag(), matching the equivalent helper in the Plesk fix: treats a missing custom value as $default (so already-covered flags like dnscontrol/sysinfo can default to 'ON' without every other flag having to), and runs a present value through FOSSBilling\Tools::normalizeBoolean() so a stored 'false'/'0' string isn't truthy under a plain PHP ?: check. createDirectadminManager() (an HTTP-client-injecting test double) and the two tests exercising modifyAccount() are ported from the same upstream commit; that helper's own origin (adcd85f52, "Improve overdue order suspension handling") was declined earlier in this branch's triage as feature-shaped, so it's recreated here rather than pulled in via that commit. composer test: 2471 passed. composer phpstan: no errors.
136 lines
4.4 KiB
PHP
136 lines
4.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use Symfony\Component\HttpClient\MockHttpClient;
|
|
use Symfony\Component\HttpClient\Response\MockResponse;
|
|
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
|
|
|
function invokeDirectadminParseResponse(Server_Manager_Directadmin $manager, string $data): array
|
|
{
|
|
$reflection = new ReflectionClass($manager);
|
|
$method = $reflection->getMethod('parseResponse');
|
|
|
|
return $method->invokeArgs($manager, [$data]);
|
|
}
|
|
|
|
function createDirectadminManager(HttpClientInterface $httpClient): Server_Manager_Directadmin
|
|
{
|
|
return new class(['host' => 'directadmin.example.com', 'username' => 'admin', 'password' => 'secret'], $httpClient) extends Server_Manager_Directadmin {
|
|
public function __construct(array $options, private readonly HttpClientInterface $httpClient)
|
|
{
|
|
parent::__construct($options);
|
|
}
|
|
|
|
public function getHttpClient(): HttpClientInterface
|
|
{
|
|
return $this->httpClient;
|
|
}
|
|
};
|
|
}
|
|
|
|
beforeEach(function (): void {
|
|
$this->manager = new Server_Manager_Directadmin([
|
|
'host' => 'directadmin.example.com',
|
|
'username' => 'admin',
|
|
'password' => 'secret',
|
|
]);
|
|
});
|
|
|
|
test('parseResponse decodes the fully-terminated apostrophe entity without a trailing semicolon', function (): void {
|
|
$result = invokeDirectadminParseResponse($this->manager, 'name=O'Brien');
|
|
|
|
expect($result['name'])->toBe("O'Brien");
|
|
});
|
|
|
|
test('parseResponse decodes the legacy unterminated apostrophe entity', function (): void {
|
|
$result = invokeDirectadminParseResponse($this->manager, 'name=O'Brien');
|
|
|
|
expect($result['name'])->toBe("O'Brien");
|
|
});
|
|
|
|
test('modifyAccount sends custom package values to DirectAdmin', function (): void {
|
|
$requests = [];
|
|
$httpClient = new MockHttpClient(function (string $method, string $url, array $options) use (&$requests): MockResponse {
|
|
$requests[] = ['method' => $method, 'url' => $url, 'options' => $options];
|
|
|
|
return new MockResponse('');
|
|
});
|
|
$manager = createDirectadminManager($httpClient);
|
|
$package = (new Server_Package())
|
|
->setBandwidth('1024')
|
|
->setQuota('2048')
|
|
->setMaxDomains('3')
|
|
->setMaxSubdomains('4')
|
|
->setMaxParkedDomains('5')
|
|
->setMaxFtp('6')
|
|
->setMaxSql('7')
|
|
->setMaxPop('8')
|
|
->setCustomValues([
|
|
'aftp' => '1',
|
|
'catchall' => 'false',
|
|
'cgi' => 'yes',
|
|
'cron' => 'true',
|
|
'nemailf' => '5',
|
|
'nemailml' => 'unlimited',
|
|
'nemailr' => '7',
|
|
'php' => 'on',
|
|
'spam' => 'false',
|
|
'ssh' => '1',
|
|
'ssl' => 'yes',
|
|
]);
|
|
$account = (new Server_Account())
|
|
->setUsername('example')
|
|
->setNs1('ns1.example.com')
|
|
->setNs2('ns2.example.com')
|
|
->setPackage($package);
|
|
|
|
expect($manager->modifyAccount($account))->toBeTrue()
|
|
->and($requests)->toHaveCount(1);
|
|
|
|
parse_str((string) parse_url($requests[0]['url'], PHP_URL_QUERY), $fields);
|
|
|
|
expect($fields)->toMatchArray([
|
|
'action' => 'customize',
|
|
'aftp' => 'ON',
|
|
'catchall' => 'OFF',
|
|
'cgi' => 'ON',
|
|
'cron' => 'ON',
|
|
'dnscontrol' => 'ON',
|
|
'nemailf' => '5',
|
|
'nemailml' => 'unlimited',
|
|
'nemailr' => '7',
|
|
'php' => 'ON',
|
|
'spam' => 'OFF',
|
|
'ssh' => 'ON',
|
|
'ssl' => 'ON',
|
|
'sysinfo' => 'ON',
|
|
'unemailml' => 'ON',
|
|
'user' => 'example',
|
|
]);
|
|
});
|
|
|
|
test('modifyAccount honors explicit false DNS and system information permissions', function (): void {
|
|
$requests = [];
|
|
$httpClient = new MockHttpClient(function (string $method, string $url, array $options) use (&$requests): MockResponse {
|
|
$requests[] = ['method' => $method, 'url' => $url, 'options' => $options];
|
|
|
|
return new MockResponse('');
|
|
});
|
|
$manager = createDirectadminManager($httpClient);
|
|
$package = (new Server_Package())->setCustomValues([
|
|
'dnscontrol' => 'false',
|
|
'sysinfo' => '0',
|
|
]);
|
|
$account = (new Server_Account())
|
|
->setUsername('example')
|
|
->setPackage($package);
|
|
|
|
expect($manager->modifyAccount($account))->toBeTrue();
|
|
|
|
parse_str((string) parse_url($requests[0]['url'], PHP_URL_QUERY), $fields);
|
|
|
|
expect($fields['dnscontrol'])->toBe('OFF')
|
|
->and($fields['sysinfo'])->toBe('OFF');
|
|
});
|