Skip to content

Commit a7063ca

Browse files
committed
Add UI log for internal PDF generation
1 parent 0ad04a9 commit a7063ca

4 files changed

Lines changed: 191 additions & 5 deletions

File tree

Packages/Application/Sfi.Umo/Classes/Controller/BackendController.php

Lines changed: 142 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,14 @@ class BackendController extends AbstractModuleController
138138
/**
139139
* @return void
140140
*/
141-
public function indexAction() {}
141+
public function indexAction()
142+
{
143+
$logPath = $this->getInternalSignedPdfsLogPath();
144+
145+
$this->view->assign('internalSignedPdfsBasePath', $this->getInternalSignedPdfsBasePath());
146+
$this->view->assign('internalSignedPdfsLogPath', $logPath);
147+
$this->view->assign('internalSignedPdfsLog', $this->readLogTail($logPath));
148+
}
142149

143150
/**
144151
* Trigger background generation of watermarked signed PDFs
@@ -159,11 +166,144 @@ public function generateSignedPdfsAction()
159166
*/
160167
public function generateInternalSignedPdfsAction()
161168
{
169+
$basePath = $this->getInternalSignedPdfsBasePath();
170+
$logPath = $this->getInternalSignedPdfsLogPath();
171+
172+
if (!$this->appendInternalSignedPdfsLog(sprintf('Запуск генерации внутренних подписанных PDF из интерфейса. Папка: %s', $basePath))) {
173+
$this->addFlashMessage(
174+
'Не удалось записать лог внутренних подписанных PDF: %s',
175+
'Ошибка записи лога',
176+
\Neos\Error\Messages\Message::SEVERITY_WARNING,
177+
[$logPath]
178+
);
179+
}
180+
162181
Scripts::executeCommandAsync('sfi.sfi:signature:generateinternalsignedpdfs', $this->flowSettings, []);
163-
$this->addFlashMessage('Генерация внутренних подписанных PDF запущена в фоновом режиме. Результаты будут сохранены в /data/www-provisioned/Web/umo/internal/*/signed/');
182+
$this->addFlashMessage(sprintf('Генерация внутренних подписанных PDF запущена в фоновом режиме. Результаты будут сохранены в %s/*/signed/. Лог: %s', $basePath, $logPath));
164183
$this->redirect('index');
165184
}
166185

186+
/**
187+
* Check internal signed PDF input folders without generating files
188+
*
189+
* @return void
190+
*/
191+
public function dryRunInternalSignedPdfsAction()
192+
{
193+
$basePath = $this->getInternalSignedPdfsBasePath();
194+
$logPath = $this->getInternalSignedPdfsLogPath();
195+
196+
$this->appendInternalSignedPdfsLog(sprintf('Проверка внутренних PDF без генерации запущена из интерфейса. Папка: %s', $basePath));
197+
198+
$bufferLevel = ob_get_level();
199+
ob_start();
200+
201+
try {
202+
Scripts::executeCommand('sfi.sfi:signature:generateinternalsignedpdfs', $this->flowSettings, true, ['dry-run' => 'true']);
203+
$output = trim($this->collectOutputBuffer($bufferLevel));
204+
205+
$this->appendInternalSignedPdfsLog($output !== '' ? "Результат проверки:\n" . $output : 'Результат проверки: команда не вернула вывода.');
206+
$this->addFlashMessage(sprintf('Проверка внутренних PDF завершена. Результат записан в лог: %s', $logPath));
207+
} catch (\Exception $exception) {
208+
$output = trim($this->collectOutputBuffer($bufferLevel));
209+
$message = 'Ошибка проверки внутренних PDF: ' . $exception->getMessage();
210+
if ($output !== '') {
211+
$message .= "\nВывод команды:\n" . $output;
212+
}
213+
$this->appendInternalSignedPdfsLog($message);
214+
$this->addFlashMessage(
215+
'Проверка внутренних PDF завершилась с ошибкой. Подробности записаны в лог: %s',
216+
'Ошибка проверки',
217+
\Neos\Error\Messages\Message::SEVERITY_ERROR,
218+
[$logPath]
219+
);
220+
}
221+
222+
$this->redirect('index');
223+
}
224+
225+
protected function getInternalSignedPdfsBasePath(): string
226+
{
227+
return rtrim(FLOW_PATH_WEB, '/') . '/umo/internal';
228+
}
229+
230+
protected function getInternalSignedPdfsLogPath(): string
231+
{
232+
return $this->getInternalSignedPdfsBasePath() . '/generation.log';
233+
}
234+
235+
protected function appendInternalSignedPdfsLog(string $message): bool
236+
{
237+
$message = trim($message);
238+
if ($message === '') {
239+
return true;
240+
}
241+
242+
$basePath = $this->getInternalSignedPdfsBasePath();
243+
if (!is_dir($basePath) && !@mkdir($basePath, 0775, true) && !is_dir($basePath)) {
244+
return false;
245+
}
246+
247+
$timestamp = date('Y-m-d H:i:s');
248+
$entry = '';
249+
foreach (preg_split('/\r\n|\r|\n/', $message) as $line) {
250+
$entry .= $timestamp . ' ' . $line . PHP_EOL;
251+
}
252+
253+
return @file_put_contents($this->getInternalSignedPdfsLogPath(), $entry, FILE_APPEND | LOCK_EX) !== false;
254+
}
255+
256+
protected function readLogTail(string $logPath, int $maxBytes = 65536): string
257+
{
258+
if (!is_file($logPath)) {
259+
return '';
260+
}
261+
262+
$size = filesize($logPath);
263+
if ($size === false) {
264+
return '';
265+
}
266+
267+
$handle = fopen($logPath, 'rb');
268+
if ($handle === false) {
269+
return '';
270+
}
271+
272+
if ($size > $maxBytes) {
273+
fseek($handle, -$maxBytes, SEEK_END);
274+
}
275+
276+
$contents = stream_get_contents($handle);
277+
fclose($handle);
278+
279+
if ($contents === false) {
280+
return '';
281+
}
282+
283+
if ($size > $maxBytes) {
284+
$firstLineBreak = strpos($contents, "\n");
285+
if ($firstLineBreak !== false) {
286+
$contents = substr($contents, $firstLineBreak + 1);
287+
}
288+
$contents = "... показаны последние строки лога\n" . $contents;
289+
}
290+
291+
return $contents;
292+
}
293+
294+
protected function collectOutputBuffer(int $bufferLevel): string
295+
{
296+
$output = '';
297+
while (ob_get_level() > $bufferLevel) {
298+
$buffer = ob_get_clean();
299+
if ($buffer !== false) {
300+
$output = $buffer . $output;
301+
}
302+
}
303+
304+
return $output;
305+
}
306+
167307
protected $collectionByType = [
168308
'W' => 'assetRpd',
169309
'P' => 'assetsPracticeAnnotations',

Packages/Application/Sfi.Umo/README.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,17 @@ PDF-файлы должны лежать прямо в той же папке,
5252
## Как запустить генерацию
5353

5454
1. Откройте модуль импорта УМО в административной части сайта.
55-
2. Нажмите кнопку `Генерировать внутренние подписанные PDF`.
56-
3. Генерация запустится в фоновом режиме.
55+
2. Если нужно сначала проверить, какие файлы будут найдены, нажмите кнопку `Проверить внутренние PDF без генерации`.
56+
3. Для запуска генерации нажмите кнопку `Генерировать внутренние подписанные PDF`.
57+
4. Генерация запустится в фоновом режиме.
58+
59+
Внизу страницы модуля показывается путь к рабочей папке, путь к логу и последние строки лога. После запуска генерации можно нажимать `Обновить лог`, чтобы увидеть текущий результат.
60+
61+
Лог записывается в файл:
62+
63+
```text
64+
/data/www-provisioned/Web/umo/internal/generation.log
65+
```
5766

5867
## Что появится в результате
5968

@@ -102,6 +111,7 @@ umo/
102111

103112
Проверьте:
104113

114+
- есть ли записи в логе на странице модуля;
105115
- папка находится внутри `umo/internal`;
106116
- в папке есть `index.csv`;
107117
- в `index.csv` есть заголовок и одна строка данных;

Packages/Application/Sfi.Umo/Resources/Private/Templates/Backend/Index.html

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,30 @@
3333
>
3434
<div><f:form.submit class="button" value="Генерировать внутренние подписанные PDF"/></div>
3535
</f:form>
36+
37+
<br/>
38+
39+
<f:form
40+
method="post"
41+
action="dryRunInternalSignedPdfs"
42+
controller="Backend"
43+
package="Sfi.Umo"
44+
>
45+
<div><f:form.submit class="button" value="Проверить внутренние PDF без генерации"/></div>
46+
</f:form>
47+
48+
<h2>Внутренние подписанные PDF</h2>
49+
<p>Папка с исходными файлами: <code>{internalSignedPdfsBasePath}</code></p>
50+
<p>Лог генерации: <code>{internalSignedPdfsLogPath}</code></p>
51+
52+
<f:link.action action="index" class="button">Обновить лог</f:link.action>
53+
54+
<f:if condition="{internalSignedPdfsLog}">
55+
<f:then>
56+
<pre style="margin-top: 16px; padding: 12px; max-height: 480px; overflow: auto; background: #f7f7f7; border: 1px solid #ccc; white-space: pre-wrap;">{internalSignedPdfsLog}</pre>
57+
</f:then>
58+
<f:else>
59+
<p>Лог пока пуст. Нажмите кнопку проверки или генерации, чтобы создать первую запись.</p>
60+
</f:else>
61+
</f:if>
3662
</f:section>

Packages/Sites/Sfi.Sfi/Classes/Sfi/Sfi/Command/SignatureCommandController.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,8 @@ public function generateInternalSignedPdfsCommand(bool $force = false, bool $dry
188188
return;
189189
}
190190

191+
$this->log($logFile, $dryRun, 'Starting internal signed PDF generation. Base path: %s', [$internalBasePath]);
192+
191193
$items = $this->collectInternalSignatureItems($internalBasePath, $logFile, $dryRun);
192194
$total = count($items);
193195
$this->log($logFile, $dryRun, 'Found %d internal PDF files to process.', [$total]);
@@ -599,7 +601,15 @@ protected function log(string $logFile, bool $dryRun, string $format, array $arg
599601
$message = vsprintf($format, $args);
600602
$this->outputLine($message);
601603
if (!$dryRun && $logFile) {
602-
file_put_contents($logFile, date('Y-m-d H:i:s') . ' ' . $message . "\n", FILE_APPEND);
604+
$logDirectory = dirname($logFile);
605+
if (!is_dir($logDirectory) && !mkdir($logDirectory, 0775, true) && !is_dir($logDirectory)) {
606+
$this->outputLine('Could not create log directory: %s', [$logDirectory]);
607+
return;
608+
}
609+
610+
if (file_put_contents($logFile, date('Y-m-d H:i:s') . ' ' . $message . "\n", FILE_APPEND | LOCK_EX) === false) {
611+
$this->outputLine('Could not write log file: %s', [$logFile]);
612+
}
603613
}
604614
}
605615

0 commit comments

Comments
 (0)