From bd0ea3cd81ec9e894fc789f033f5a775dc160169 Mon Sep 17 00:00:00 2001 From: Robin Windey Date: Sun, 29 Dec 2024 17:44:41 +0000 Subject: [PATCH] Introduce Setup Check * Do some basic check if OCRMyPDF CLI is working * Fixes #83 --- README.md | 8 ++ doc/img/setup_checks.jpg | Bin 0 -> 45537 bytes lib/AppInfo/Application.php | 2 + lib/SetupChecks/OcrMyPdfCheck.php | 60 +++++++++++ tests/Unit/SetupChecks/OcrMyPdfCheckTest.php | 103 +++++++++++++++++++ 5 files changed, 173 insertions(+) create mode 100644 doc/img/setup_checks.jpg create mode 100644 lib/SetupChecks/OcrMyPdfCheck.php create mode 100644 tests/Unit/SetupChecks/OcrMyPdfCheckTest.php diff --git a/README.md b/README.md index 43f1a4d..07dfecc 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,14 @@ apt-get install tesseract-ocr-deu apt-get install tesseract-ocr-chi-sim ``` +### Setup Checks + +The app will perform some [Setup Checks](https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/security_setup_warnings.html) to verify your installation. If there is any problem with your backend setup, you'll see an error printed in Nextcloud under `Administration Settings` → `Overview` → `Security & setup warnings`. + +

+ Setup checks +

+ ## Usage You can configure the OCR processing via Nextcloud's workflow engine. Therefore configure a new flow via `Settings` → `Flow` → `Add new flow` (if you don't see `OCR file` here the app isn't installed properly or you forgot to activate it). diff --git a/doc/img/setup_checks.jpg b/doc/img/setup_checks.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bd257def68ff8acd5ea5b7d1f27c389cdb4453f8 GIT binary patch literal 45537 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 z

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.D-}Vx@eF`+cOJ`$FfG+DhCyA=Oe^HpnHiVZ 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 z4MJZkcUAMX1`j+&a=PJ-+%eSQZTB6jaregisterEventListener(RegisterOperationsEvent::class, RegisterFlowOperationsListener::class); $context->registerNotifierService(Notifier::class); + $context->registerSetupCheck(OcrMyPdfCheck::class); } /** diff --git a/lib/SetupChecks/OcrMyPdfCheck.php b/lib/SetupChecks/OcrMyPdfCheck.php new file mode 100644 index 0000000..c8d8d73 --- /dev/null +++ b/lib/SetupChecks/OcrMyPdfCheck.php @@ -0,0 +1,60 @@ + + * + * @author Robin Windey + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\WorkflowOcr\SetupChecks; + +use OCA\WorkflowOcr\Wrapper\ICommand; +use OCP\IL10N; +use OCP\SetupCheck\ISetupCheck; +use OCP\SetupCheck\SetupResult; + +class OcrMyPdfCheck implements ISetupCheck { + public function __construct( + private IL10N $l10n, + private ICommand $command, + ) { + } + + public function getCategory(): string { + return 'system'; + } + + public function getName(): string { + return $this->l10n->t('Is OCRmyPDF installed'); + } + + public function run(): SetupResult { + $this->command->setCommand('ocrmypdf --version')->execute(); + if ($this->command->getExitCode() === 127) { + return SetupResult::error($this->l10n->t('OCRmyPDF CLI is not installed.'), 'https://github.com/R0Wi-DEV/workflow_ocr?tab=readme-ov-file#backend'); + } + if ($this->command->getExitCode() !== 0) { + return SetupResult::error($this->l10n->t('OCRmyPDF CLI is not working correctly. Error was: %1$s', [$this->command->getError()])); + } + $versionOutput = $this->command->getOutput(); + return SetupResult::success($this->l10n->t('OCRmyPDF is installed and has version %1$s.', [$versionOutput])); + } +} diff --git a/tests/Unit/SetupChecks/OcrMyPdfCheckTest.php b/tests/Unit/SetupChecks/OcrMyPdfCheckTest.php new file mode 100644 index 0000000..9125ad1 --- /dev/null +++ b/tests/Unit/SetupChecks/OcrMyPdfCheckTest.php @@ -0,0 +1,103 @@ + + * + * @author Robin Windey + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\WorkflowOcr\Tests\Unit\SetupChecks; + +use OCA\WorkflowOcr\SetupChecks\OcrMyPdfCheck; +use OCA\WorkflowOcr\Wrapper\ICommand; +use OCP\IL10N; +use OCP\SetupCheck\SetupResult; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class OcrMyPdfCheckTest extends TestCase { + /** @var IL10N|MockObject */ + private $l10n; + /** @var ICommand|MockObject */ + private $command; + /** @var OcrMyPdfCheck */ + private $ocrMyPdfCheck; + + protected function setUp(): void { + $this->l10n = $this->createMock(IL10N::class); + $this->command = $this->createMock(ICommand::class); + $this->ocrMyPdfCheck = new OcrMyPdfCheck($this->l10n, $this->command); + } + + public function testGetCategory(): void { + $this->assertEquals('system', $this->ocrMyPdfCheck->getCategory()); + } + + public function testGetName(): void { + $this->l10n->method('t')->willReturn('Is OCRmyPDF installed'); + $this->assertEquals('Is OCRmyPDF installed', $this->ocrMyPdfCheck->getName()); + } + + public function testRunOcrMyPdfNotInstalled(): void { + $this->command->method('setCommand')->willReturnSelf(); + $this->command->method('execute')->willReturn(true); + $this->command->method('getExitCode')->willReturn(127); + + $this->l10n->method('t')->willReturn('OCRmyPDF CLI is not installed.'); + + $result = $this->ocrMyPdfCheck->run(); + $this->assertInstanceOf(SetupResult::class, $result); + $this->assertEquals(SetupResult::ERROR, $result->getSeverity()); + $this->assertEquals('OCRmyPDF CLI is not installed.', $result->getDescription()); + } + + public function testRunOcrMyPdfNotWorkingCorrectly(): void { + $this->command->method('setCommand')->willReturnSelf(); + $this->command->method('execute')->willReturn(true); + $this->command->method('getExitCode')->willReturn(1); + $this->command->method('getError')->willReturn('Some error'); + + $this->l10n->expects($this->once())->method('t') + ->with('OCRmyPDF CLI is not working correctly. Error was: %1$s', ['Some error']) + ->willReturn('OCRmyPDF CLI is not working correctly. Error was: Some error'); + + $result = $this->ocrMyPdfCheck->run(); + $this->assertInstanceOf(SetupResult::class, $result); + $this->assertEquals(SetupResult::ERROR, $result->getSeverity()); + $this->assertEquals('OCRmyPDF CLI is not working correctly. Error was: Some error', $result->getDescription()); + } + + public function testRunOcrMyPdfInstalled(): void { + $this->command->method('setCommand')->willReturnSelf(); + $this->command->method('execute')->willReturn(true); + $this->command->method('getExitCode')->willReturn(0); + $this->command->method('getOutput')->willReturn('12.0.0'); + + $this->l10n->expects($this->once())->method('t') + ->with('OCRmyPDF is installed and has version %1$s.', ['12.0.0']) + ->willReturn('OCRmyPDF is installed and has version 12.0.0.'); + + $result = $this->ocrMyPdfCheck->run(); + $this->assertInstanceOf(SetupResult::class, $result); + $this->assertEquals(SetupResult::SUCCESS, $result->getSeverity()); + $this->assertEquals('OCRmyPDF is installed and has version 12.0.0.', $result->getDescription()); + } +}