Skip to content
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
ba29270
feat(utils): add SetupCheckUtils trait
guilhermercarvalho Mar 3, 2026
3ab2f05
test: add test infrastructure for setup checks
guilhermercarvalho Mar 3, 2026
71abe0c
feat(setup-check): add JavaSetupCheck
guilhermercarvalho Mar 3, 2026
59ce235
feat(setup-check): add JSignPdfSetupCheck
guilhermercarvalho Mar 3, 2026
1ab95c9
feat(setup-check): add PDFtkSetupCheck
guilhermercarvalho Mar 3, 2026
39cef8b
feat(setup-check): add PopplerSetupCheck
guilhermercarvalho Mar 3, 2026
ef6695f
feat(setup-check): add ImagickSetupCheck
guilhermercarvalho Mar 3, 2026
67c627b
feat(setup-check): add CertificateEngineSetupCheck
guilhermercarvalho Mar 3, 2026
350323e
feat(application): register new setup checks
guilhermercarvalho Mar 3, 2026
2b31973
refactor: deprecate ConfigureCheckService
guilhermercarvalho Mar 3, 2026
3766c42
refactor(setup-check): reorganize mocks and apply code standards
guilhermercarvalho Mar 5, 2026
1a56510
style(setup-check): apply code style fixes and improve Psalm annotations
guilhermercarvalho Mar 5, 2026
ec70886
fix(setup-check): address Psalm issues and improve robustness
guilhermercarvalho Mar 5, 2026
453c15a
test(setup-check): update PDFtkSetupCheckTest to match new error message
guilhermercarvalho Mar 5, 2026
037da11
test(setupcheck): reorganize test mocks into dedicated namespace
guilhermercarvalho Mar 6, 2026
c06327f
feat(command): update configure:check to use ISetupCheckManager
guilhermercarvalho Mar 6, 2026
934b7ac
refactor: replace deprecated ConfigureCheckService with SetupCheckRes…
guilhermercarvalho Mar 7, 2026
03283ef
fix(api): ensure OU field is always returned as string in certificate…
guilhermercarvalho Mar 7, 2026
c640d0f
refactor(service): remove deprecated ConfigureCheckService
guilhermercarvalho Mar 7, 2026
db325bd
test(service): add unit tests for SetupCheckResultService
guilhermercarvalho Mar 7, 2026
0ac2fed
chore(service): remove redundant comment in SetupCheckResultService
guilhermercarvalho Mar 7, 2026
ebb17c5
test(handler): update OU filtering test to expect string
guilhermercarvalho Mar 7, 2026
502124e
chore(service): remove redundant comments
guilhermercarvalho Mar 7, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,5 +94,14 @@ public function register(IRegistrationContext $context): void {
$context->registerEventListener(UserDeletedEvent::class, UserDeletedListener::class);

$context->registerDashboardWidget(PendingSignaturesWidget::class);

$context->registerSetupCheck(\OCA\Libresign\SetupCheck\JavaSetupCheck::class);
$context->registerSetupCheck(\OCA\Libresign\SetupCheck\JSignPdfSetupCheck::class);
$context->registerSetupCheck(\OCA\Libresign\SetupCheck\PDFtkSetupCheck::class);

$context->registerSetupCheck(\OCA\Libresign\SetupCheck\PopplerSetupCheck::class);
$context->registerSetupCheck(\OCA\Libresign\SetupCheck\ImagickSetupCheck::class);

$context->registerSetupCheck(\OCA\Libresign\SetupCheck\CertificateEngineSetupCheck::class);
}
}
4 changes: 4 additions & 0 deletions lib/Service/Install/ConfigureCheckService.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
use OCP\IURLGenerator;
use Psr\Log\LoggerInterface;

/**
* @deprecated 13.0.4 Use the individual SetupCheck classes instead
* (JavaSetupCheck, JSignPdfSetupCheck, etc.).
*/
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this, and why not solve?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The @deprecated annotation was originally added to maintain backward compatibility as suggested in the issue discussion. However, after further analysis and the reviewer's comment, I realized that fully removing the class is cleaner and more aligned with the goal of this refactor. The old ConfigureCheckService is now completely replaced by the new SetupCheckResultService and the individual ISetupCheck implementations. There are no remaining usages of the old service in the codebase, so keeping a deprecated stub would only add unnecessary maintenance burden. Therefore, I removed the class entirely. This should resolve the concern – the service is gone, not just deprecated.

class ConfigureCheckService {
private string $architecture;
private bool $isCacheDisabled = false;
Expand Down
94 changes: 94 additions & 0 deletions lib/SetupCheck/CertificateEngineSetupCheck.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<?php

declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2026 LibreCode coop and contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\Libresign\SetupCheck;

use OCA\Libresign\Handler\CertificateEngine\CertificateEngineFactory;
use OCA\Libresign\Helper\ConfigureCheckHelper;
use OCP\IL10N;
use OCP\SetupCheck\ISetupCheck;
use OCP\SetupCheck\SetupResult;

class CertificateEngineSetupCheck implements ISetupCheck
{
private IL10N $l10n;
private CertificateEngineFactory $certificateEngineFactory;

public function __construct(
IL10N $l10n,
CertificateEngineFactory $certificateEngineFactory
) {
$this->l10n = $l10n;
$this->certificateEngineFactory = $certificateEngineFactory;
}

public function getName(): string
{
return $this->l10n->t('Certificate engine');
}

public function getCategory(): string
{
return 'security';
}

public function run(): SetupResult
{
try {
$engine = $this->certificateEngineFactory->getEngine();
$checkResults = $engine->configureCheck();
} catch (\Throwable $e) {
$engineName = $this->certificateEngineFactory->getEngine()->getName() ?? 'unknown';
return SetupResult::error(
$this->l10n->t('Define the certificate engine to use'),
$this->l10n->t('Run occ libresign:configure:%s --help', [$engineName])
);
}

// Process results: if any error, return error; else if any warning, return warning; else success
$hasError = false;
$hasWarning = false;
$messages = [];
$tips = [];

foreach ($checkResults as $result) {
if ($result instanceof ConfigureCheckHelper) {
$status = $result->getStatus();
$msg = $result->getMessage();
$tip = $result->getTip();

if ($status === 'error') {
$hasError = true;
$messages[] = "[ERROR] $msg";
} elseif ($status === 'warning') {
$hasWarning = true;
$messages[] = "[WARNING] $msg";
} else {
$messages[] = $msg;
}

if (!empty($tip)) {
$tips[] = $tip;
}
}
}

$tip = '';
if (!empty($tips)) {
$tip = implode("\n", array_unique($tips));
}

if ($hasError) {
return SetupResult::error(implode("\n", $messages), $tip);
} elseif ($hasWarning) {
return SetupResult::warning(implode("\n", $messages), $tip);
} else {
return SetupResult::success(implode("\n", $messages) ?: $this->l10n->t('Certificate engine is configured correctly'));
}
}
}
39 changes: 39 additions & 0 deletions lib/SetupCheck/ImagickSetupCheck.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2026 LibreCode coop and contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\Libresign\SetupCheck;

use OCP\IL10N;
use OCP\SetupCheck\ISetupCheck;
use OCP\SetupCheck\SetupResult;

class ImagickSetupCheck implements ISetupCheck {
private IL10N $l10n;

public function __construct(IL10N $l10n) {
$this->l10n = $l10n;
}

public function getName(): string {
return $this->l10n->t('Imagick PHP extension');
}

public function getCategory(): string {
return 'system';
}

public function run(): SetupResult {
if (!extension_loaded('imagick')) {
return SetupResult::info(
$this->l10n->t('Imagick extension is not loaded'),
$this->l10n->t('Install php-imagick to enable visible signatures, background images, and signature element rendering.')
);
}
return SetupResult::success($this->l10n->t('Imagick extension is loaded'));
}
}
133 changes: 133 additions & 0 deletions lib/SetupCheck/JSignPdfSetupCheck.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
<?php

declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2026 LibreCode coop and contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\Libresign\SetupCheck;

use OCA\Libresign\Helper\JavaHelper;
use OCA\Libresign\AppInfo\Application;
use OCA\Libresign\Handler\SignEngine\JSignPdfHandler;
use OCA\Libresign\Service\Install\SignSetupService;
use OCA\Libresign\Service\Install\InstallService;
use OCP\IL10N;
use OCP\IAppConfig;
use OCP\IURLGenerator;
use OCP\App\IAppManager;
use OCP\SetupCheck\ISetupCheck;
use OCP\SetupCheck\SetupResult;
use OCP\IConfig;
use Psr\Log\LoggerInterface;

class JSignPdfSetupCheck implements ISetupCheck
{
use SetupCheckUtils;

private IL10N $l10n;
private IAppConfig $appConfig;
private JSignPdfHandler $jSignPdfHandler;
private IConfig $systemConfig;
private JavaHelper $javaHelper;

private SignSetupService $signSetupService;
private IURLGenerator $urlGenerator;
private IAppManager $appManager;
private LoggerInterface $logger;

public function __construct(
IL10N $l10n,
IAppConfig $appConfig,
JSignPdfHandler $jSignPdfHandler,
SignSetupService $signSetupService,
IURLGenerator $urlGenerator,
IAppManager $appManager,
LoggerInterface $logger,
IConfig $systemConfig,
JavaHelper $javaHelper
) {
$this->l10n = $l10n;
$this->appConfig = $appConfig;
$this->jSignPdfHandler = $jSignPdfHandler;
$this->signSetupService = $signSetupService;
$this->urlGenerator = $urlGenerator;
$this->appManager = $appManager;
$this->logger = $logger;
$this->systemConfig = $systemConfig;
$this->javaHelper = $javaHelper;
}

public function getName(): string
{
return $this->l10n->t('JSignPdf');
}

public function getCategory(): string
{
return 'system';
}

public function run(): SetupResult
{
$debugEnabled = $this->systemConfig->getSystemValueBool('debug', false);
$jsignpdfJarPath = $this->appConfig->getValueString(Application::APP_ID, 'jsignpdf_jar_path');

if (!$jsignpdfJarPath) {
return SetupResult::error(
$this->l10n->t('JSignPdf not found'),
$this->l10n->t('Run occ libresign:install --jsignpdf')
);
}

$verifyResult = $this->verifyResourceIntegrity('jsignpdf', $debugEnabled);
if (!empty($verifyResult)) {
[$errorMsg, $tip] = $this->getErrorAndTipFromVerify($verifyResult, 'jsignpdf', $debugEnabled, $this->l10n);
return SetupResult::error($errorMsg, $tip);
}

if (!file_exists($jsignpdfJarPath)) {
return SetupResult::error(
$this->l10n->t('JSignPdf binary not found: %s', [$jsignpdfJarPath]),
$this->l10n->t('Run occ libresign:install --jsignpdf')
);
}

$javaPath = $this->javaHelper->getJavaPath();
if (!$javaPath || !file_exists($javaPath)) {
return SetupResult::error(
$this->l10n->t('Necessary Java to run JSignPdf'),
$this->l10n->t('Run occ libresign:install --java')
);
}

$jsignPdf = $this->jSignPdfHandler->getJSignPdf();
$jsignPdf->setParam($this->jSignPdfHandler->getJSignParam());
$currentVersion = $jsignPdf->getVersion();

if (!$currentVersion) {
$msg = $this->l10n->t('Necessary install the version %s', [InstallService::JSIGNPDF_VERSION]);
return SetupResult::error($msg, $this->l10n->t('Run occ libresign:install --jsignpdf'));
}

if (version_compare($currentVersion, InstallService::JSIGNPDF_VERSION, '<')) {
$msg = $this->l10n->t('Necessary bump JSignPdf version from %s to %s', [$currentVersion, InstallService::JSIGNPDF_VERSION]);
return SetupResult::error($msg, $this->l10n->t('Run occ libresign:install --jsignpdf'));
}

if (version_compare($currentVersion, InstallService::JSIGNPDF_VERSION, '>')) {
return SetupResult::error(
$this->l10n->t('Necessary downgrade JSignPdf version from %s to %s', [$currentVersion, InstallService::JSIGNPDF_VERSION]),
$this->l10n->t('Run occ libresign:install --jsignpdf')
);
}

$messages = [
$this->l10n->t('JSignPdf version: %s', [$currentVersion]),
$this->l10n->t('JSignPdf path: %s', [$jsignpdfJarPath])
];

return SetupResult::success(implode("\n", $messages));
}
}
Loading