Skip to content

Commit

Permalink
Merge pull request #3798 from nextcloud/feat/pdf-template-workflow
Browse files Browse the repository at this point in the history
feat: Template fields workflow
  • Loading branch information
elzody authored Jul 25, 2024
2 parents ddc4802 + 940feb4 commit 09f4c56
Show file tree
Hide file tree
Showing 10 changed files with 261 additions and 16 deletions.
3 changes: 3 additions & 0 deletions appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,5 +75,8 @@

['name' => 'Target#getTargets', 'url' => '/api/v1/targets', 'verb' => 'GET'],
['name' => 'Target#getPreview', 'url' => '/api/v1/targets/preview', 'verb' => 'GET'],

['name' => 'TemplateField#extractFields', 'url' => '/api/v1/template/fields/extract/{fileId}', 'verb' => 'GET'],
['name' => 'TemplateField#fillFields', 'url' => '/api/v1/template/fields/fill', 'verb' => 'POST'],
],
];
8 changes: 4 additions & 4 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions composer/composer/autoload_classmap.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
'OCA\\Richdocuments\\Controller\\OCSController' => $baseDir . '/../lib/Controller/OCSController.php',
'OCA\\Richdocuments\\Controller\\SettingsController' => $baseDir . '/../lib/Controller/SettingsController.php',
'OCA\\Richdocuments\\Controller\\TargetController' => $baseDir . '/../lib/Controller/TargetController.php',
'OCA\\Richdocuments\\Controller\\TemplateFieldController' => $baseDir . '/../lib/Controller/TemplateFieldController.php',
'OCA\\Richdocuments\\Controller\\TemplatesController' => $baseDir . '/../lib/Controller/TemplatesController.php',
'OCA\\Richdocuments\\Controller\\WopiController' => $baseDir . '/../lib/Controller/WopiController.php',
'OCA\\Richdocuments\\Db\\Asset' => $baseDir . '/../lib/Db/Asset.php',
Expand All @@ -42,6 +43,7 @@
'OCA\\Richdocuments\\Listener\\AddContentSecurityPolicyListener' => $baseDir . '/../lib/Listener/AddContentSecurityPolicyListener.php',
'OCA\\Richdocuments\\Listener\\AddFeaturePolicyListener' => $baseDir . '/../lib/Listener/AddFeaturePolicyListener.php',
'OCA\\Richdocuments\\Listener\\BeforeFetchPreviewListener' => $baseDir . '/../lib/Listener/BeforeFetchPreviewListener.php',
'OCA\\Richdocuments\\Listener\\BeforeGetTemplatesListener' => $baseDir . '/../lib/Listener/BeforeGetTemplatesListener.php',
'OCA\\Richdocuments\\Listener\\BeforeTemplateRenderedListener' => $baseDir . '/../lib/Listener/BeforeTemplateRenderedListener.php',
'OCA\\Richdocuments\\Listener\\FileCreatedFromTemplateListener' => $baseDir . '/../lib/Listener/FileCreatedFromTemplateListener.php',
'OCA\\Richdocuments\\Listener\\LoadAdditionalListener' => $baseDir . '/../lib/Listener/LoadAdditionalListener.php',
Expand Down Expand Up @@ -77,6 +79,7 @@
'OCA\\Richdocuments\\Service\\InitialStateService' => $baseDir . '/../lib/Service/InitialStateService.php',
'OCA\\Richdocuments\\Service\\RemoteOptionsService' => $baseDir . '/../lib/Service/RemoteOptionsService.php',
'OCA\\Richdocuments\\Service\\RemoteService' => $baseDir . '/../lib/Service/RemoteService.php',
'OCA\\Richdocuments\\Service\\TemplateFieldService' => $baseDir . '/../lib/Service/TemplateFieldService.php',
'OCA\\Richdocuments\\Service\\UserScopeService' => $baseDir . '/../lib/Service/UserScopeService.php',
'OCA\\Richdocuments\\Settings\\Admin' => $baseDir . '/../lib/Settings/Admin.php',
'OCA\\Richdocuments\\Settings\\Personal' => $baseDir . '/../lib/Settings/Personal.php',
Expand Down
3 changes: 3 additions & 0 deletions composer/composer/autoload_static.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class ComposerStaticInitRichdocuments
'OCA\\Richdocuments\\Controller\\OCSController' => __DIR__ . '/..' . '/../lib/Controller/OCSController.php',
'OCA\\Richdocuments\\Controller\\SettingsController' => __DIR__ . '/..' . '/../lib/Controller/SettingsController.php',
'OCA\\Richdocuments\\Controller\\TargetController' => __DIR__ . '/..' . '/../lib/Controller/TargetController.php',
'OCA\\Richdocuments\\Controller\\TemplateFieldController' => __DIR__ . '/..' . '/../lib/Controller/TemplateFieldController.php',
'OCA\\Richdocuments\\Controller\\TemplatesController' => __DIR__ . '/..' . '/../lib/Controller/TemplatesController.php',
'OCA\\Richdocuments\\Controller\\WopiController' => __DIR__ . '/..' . '/../lib/Controller/WopiController.php',
'OCA\\Richdocuments\\Db\\Asset' => __DIR__ . '/..' . '/../lib/Db/Asset.php',
Expand All @@ -57,6 +58,7 @@ class ComposerStaticInitRichdocuments
'OCA\\Richdocuments\\Listener\\AddContentSecurityPolicyListener' => __DIR__ . '/..' . '/../lib/Listener/AddContentSecurityPolicyListener.php',
'OCA\\Richdocuments\\Listener\\AddFeaturePolicyListener' => __DIR__ . '/..' . '/../lib/Listener/AddFeaturePolicyListener.php',
'OCA\\Richdocuments\\Listener\\BeforeFetchPreviewListener' => __DIR__ . '/..' . '/../lib/Listener/BeforeFetchPreviewListener.php',
'OCA\\Richdocuments\\Listener\\BeforeGetTemplatesListener' => __DIR__ . '/..' . '/../lib/Listener/BeforeGetTemplatesListener.php',
'OCA\\Richdocuments\\Listener\\BeforeTemplateRenderedListener' => __DIR__ . '/..' . '/../lib/Listener/BeforeTemplateRenderedListener.php',
'OCA\\Richdocuments\\Listener\\FileCreatedFromTemplateListener' => __DIR__ . '/..' . '/../lib/Listener/FileCreatedFromTemplateListener.php',
'OCA\\Richdocuments\\Listener\\LoadAdditionalListener' => __DIR__ . '/..' . '/../lib/Listener/LoadAdditionalListener.php',
Expand Down Expand Up @@ -92,6 +94,7 @@ class ComposerStaticInitRichdocuments
'OCA\\Richdocuments\\Service\\InitialStateService' => __DIR__ . '/..' . '/../lib/Service/InitialStateService.php',
'OCA\\Richdocuments\\Service\\RemoteOptionsService' => __DIR__ . '/..' . '/../lib/Service/RemoteOptionsService.php',
'OCA\\Richdocuments\\Service\\RemoteService' => __DIR__ . '/..' . '/../lib/Service/RemoteService.php',
'OCA\\Richdocuments\\Service\\TemplateFieldService' => __DIR__ . '/..' . '/../lib/Service/TemplateFieldService.php',
'OCA\\Richdocuments\\Service\\UserScopeService' => __DIR__ . '/..' . '/../lib/Service/UserScopeService.php',
'OCA\\Richdocuments\\Settings\\Admin' => __DIR__ . '/..' . '/../lib/Settings/Admin.php',
'OCA\\Richdocuments\\Settings\\Personal' => __DIR__ . '/..' . '/../lib/Settings/Personal.php',
Expand Down
3 changes: 3 additions & 0 deletions lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use OCA\Richdocuments\Listener\AddContentSecurityPolicyListener;
use OCA\Richdocuments\Listener\AddFeaturePolicyListener;
use OCA\Richdocuments\Listener\BeforeFetchPreviewListener;
use OCA\Richdocuments\Listener\BeforeGetTemplatesListener;
use OCA\Richdocuments\Listener\BeforeTemplateRenderedListener;
use OCA\Richdocuments\Listener\FileCreatedFromTemplateListener;
use OCA\Richdocuments\Listener\LoadAdditionalListener;
Expand All @@ -38,6 +39,7 @@
use OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent;
use OCP\Collaboration\Reference\RenderReferenceEvent;
use OCP\Collaboration\Resources\LoadAdditionalScriptsEvent;
use OCP\Files\Template\BeforeGetTemplatesEvent;
use OCP\Files\Template\FileCreatedFromTemplateEvent;
use OCP\Files\Template\RegisterTemplateCreatorEvent;
use OCP\Preview\BeforePreviewFetchedEvent;
Expand Down Expand Up @@ -65,6 +67,7 @@ public function register(IRegistrationContext $context): void {
$context->registerEventListener(BeforePreviewFetchedEvent::class, BeforeFetchPreviewListener::class);
$context->registerEventListener(RenderReferenceEvent::class, ReferenceListener::class);
$context->registerEventListener(BeforeTemplateRenderedEvent::class, BeforeTemplateRenderedListener::class);
$context->registerEventListener(BeforeGetTemplatesEvent::class, BeforeGetTemplatesListener::class);
$context->registerReferenceProvider(OfficeTargetReferenceProvider::class);
$context->registerSensitiveMethods(WopiMapper::class, [
'getPathForToken',
Expand Down
72 changes: 72 additions & 0 deletions lib/Controller/TemplateFieldController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php

/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\Richdocuments\Controller;

use OCA\Richdocuments\Service\TemplateFieldService;
use OCA\Richdocuments\TemplateManager;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCSController;
use OCP\IRequest;

class TemplateFieldController extends OCSController {
private TemplateFieldService $templateFieldService;
private TemplateManager $templateManager;

/**
* Template fields controller
*
* @param string $appName,
* @param IRequest $request,
* @param TemplateFieldService $templateFieldService
* @param TemplateManager $templateManager
*/
public function __construct(
string $appName,
IRequest $request,
TemplateFieldService $templateFieldService,
TemplateManager $templateManager
) {
parent::__construct($appName, $request);

$this->templateFieldService = $templateFieldService;
$this->templateManager = $templateManager;
}

/**
* @param int $fileId
* @return DataResponse
*/
#[NoAdminRequired]
public function extractFields(int $fileId): DataResponse {
try {
$fields = $this->templateFieldService->extractFields($fileId);

return new DataResponse($fields, Http::STATUS_OK);
} catch (\Exception $e) {
return new DataResponse(["Unable to extract fields from given file"], Http::STATUS_INTERNAL_SERVER_ERROR);
}
}

/**
* @param int $fileId
* @param array $fields
* @return DataResponse
*/
#[NoAdminRequired]
public function fillFields(int $fileId, array $fields): DataResponse {
try {
$this->templateFieldService->fillFields($fileId, $fields);

return new DataResponse([], Http::STATUS_OK);
} catch (\Exception $e) {
return new DataResponse(["Unable to fill fields into the given file"], Http::STATUS_INTERNAL_SERVER_ERROR);
}
}
}
34 changes: 34 additions & 0 deletions lib/Listener/BeforeGetTemplatesListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\Richdocuments\Listener;

use OCA\Richdocuments\Service\TemplateFieldService;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
use OCP\Files\Template\BeforeGetTemplatesEvent;

/** @template-implements IEventListener<BeforeGetTemplatesEvent|Event> */
class BeforeGetTemplatesListener implements IEventListener {
public function __construct(
private TemplateFieldService $templateFieldService
) {
}

public function handle(Event $event): void {
if (!$event instanceof BeforeGetTemplatesEvent) {
return;
}

foreach($event->getTemplates() as $template) {
$templateFileId = $template->jsonSerialize()["fileid"];
$fields = $this->templateFieldService->extractFields($templateFileId);

$template->setFields($fields);
}
}
}
10 changes: 9 additions & 1 deletion lib/Listener/FileCreatedFromTemplateListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

namespace OCA\Richdocuments\Listener;

use OCA\Richdocuments\Service\TemplateFieldService;
use OCA\Richdocuments\TemplateManager;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
Expand All @@ -18,11 +19,15 @@
class FileCreatedFromTemplateListener implements IEventListener {
/** @var TemplateManager */
private $templateManager;
/** @var TemplateFieldService */
private $templateFieldService;

public function __construct(
TemplateManager $templateManager
TemplateManager $templateManager,
TemplateFieldService $templateFieldService
) {
$this->templateManager = $templateManager;
$this->templateFieldService = $templateFieldService;
}

public function handle(Event $event): void {
Expand Down Expand Up @@ -50,6 +55,9 @@ public function handle(Event $event): void {
$this->templateManager->setTemplateSource($event->getTarget()->getId(), $templateFile->getId());
}

$filledTemplate = $this->templateFieldService->fillFields($templateFile, $event->getTemplateFields());
$event->getTarget()->putContent($filledTemplate);

// Avoid having the mimetype of the source file set
$event->getTarget()->getStorage()->getCache()->update($event->getTarget()->getId(), [
'mimetype' => $event->getTarget()->getMimeType()
Expand Down
125 changes: 125 additions & 0 deletions lib/Service/TemplateFieldService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
<?php

/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\Richdocuments\Service;

use OCA\Richdocuments\AppConfig;
use OCP\Files\IRootFolder;
use OCP\Files\Node;
use OCP\Files\Template\Field;
use OCP\Files\Template\FieldType;
use OCP\Http\Client\IClientService;
use Psr\Log\LoggerInterface;

class TemplateFieldService {
public function __construct(
private IClientService $clientService,
private AppConfig $appConfig,
private IRootFolder $rootFolder,
private LoggerInterface $logger
) {
}

/**
* @param Node|int $file
* @return array|string
*/
public function extractFields(Node|int $file) {
if (is_int($file)) {
$file = $this->rootFolder->getFirstNodeById($file);
}

$collaboraUrl = $this->appConfig->getCollaboraUrlInternal();
$httpClient = $this->clientService->newClient();

$form = RemoteOptionsService::getDefaultOptions();
$form['query'] = ['limit' => 'content-control'];
$form['multipart'] = [[
'name' => 'data',
'contents' => $file->getStorage()->fopen($file->getInternalPath(), 'r'),
'headers' => ['Content-Type' => 'multipart/form-data'],
]];

try {
$response = $httpClient->post(
$collaboraUrl . "/cool/extract-document-structure",
$form
);

$documentStructure = json_decode($response->getBody(), true)['DocStructure'];
$fields = [];

foreach ($documentStructure as $index => $attr) {
$fieldType = FieldType::tryFrom($attr['type']) ?? null;
if ($fieldType === null) {
continue;
}

$fields[] = [
new Field(
$index,
$attr["content"],
$fieldType,
$attr["alias"],
$attr["id"],
$attr["tag"]
)
];
}

return array_merge([], ...$fields);
} catch (\Exception $e) {
$this->logger->error($e->getMessage());
return [];
}
}

/**
* @param Node|int $file
* @param array $fields
* @return string|resource
*/
public function fillFields(Node|int $file, array $fields = []) {
if (is_int($file)) {
$file = $this->rootFolder->getFirstNodeById($file);
}

$collaboraUrl = $this->appConfig->getCollaboraUrlInternal();
$httpClient = $this->clientService->newClient();

$formData = [
'name' => 'data',
'contents' => $file->getStorage()->fopen($file->getInternalPath(), 'r'),
'headers' => ['Content-Type' => 'multipart/form-data'],
];

$formTransform = [
'name' => 'transform',
'contents' => '{"Transforms": ' . json_encode($fields) . '}',
];

$formFormat = [
'name' => 'format',
'contents' => $file->getExtension(),
];

$form = RemoteOptionsService::getDefaultOptions();
$form['multipart'] = [$formData, $formTransform, $formFormat];

try {
$response = $httpClient->post(
$collaboraUrl . '/cool/transform-document-structure',
$form
);

return $response->getBody();
} catch (\Exception $e) {
$this->logger->error($e->getMessage());
throw $e;
}
}
}
16 changes: 5 additions & 11 deletions lib/Template/CollaboraTemplateProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,11 @@
use OCP\IURLGenerator;

class CollaboraTemplateProvider implements ICustomTemplateProvider {
/** @var TemplateManager */
private $templateManager;
/** @var IURLGenerator */
private $urlGenerator;
/** @var ITemplateManager */
private $coreTemplateManager;

public function __construct(TemplateManager $templateManager, IURLGenerator $urlGenerator, ITemplateManager $coreTemplateManager) {
$this->templateManager = $templateManager;
$this->urlGenerator = $urlGenerator;
$this->coreTemplateManager = $coreTemplateManager;
public function __construct(
private TemplateManager $templateManager,
private IURLGenerator $urlGenerator,
private ITemplateManager $coreTemplateManager
) {
}

public function getTemplateType(): string {
Expand Down

0 comments on commit 09f4c56

Please sign in to comment.