summaryrefslogtreecommitdiffstats
path: root/library/Reporting/Web/Forms
diff options
context:
space:
mode:
Diffstat (limited to 'library/Reporting/Web/Forms')
-rw-r--r--library/Reporting/Web/Forms/DecoratedElement.php17
-rw-r--r--library/Reporting/Web/Forms/Decorator/CompatDecorator.php63
-rw-r--r--library/Reporting/Web/Forms/ReportForm.php179
-rw-r--r--library/Reporting/Web/Forms/ScheduleForm.php195
-rw-r--r--library/Reporting/Web/Forms/SendForm.php8
-rw-r--r--library/Reporting/Web/Forms/TemplateForm.php190
-rw-r--r--library/Reporting/Web/Forms/TimeframeForm.php195
7 files changed, 507 insertions, 340 deletions
diff --git a/library/Reporting/Web/Forms/DecoratedElement.php b/library/Reporting/Web/Forms/DecoratedElement.php
deleted file mode 100644
index 2578681..0000000
--- a/library/Reporting/Web/Forms/DecoratedElement.php
+++ /dev/null
@@ -1,17 +0,0 @@
-<?php
-// Icinga Reporting | (c) 2019 Icinga GmbH | GPLv2
-
-namespace Icinga\Module\Reporting\Web\Forms;
-
-use ipl\Html\Contract\FormElementDecorator;
-
-trait DecoratedElement
-{
- protected function addDecoratedElement(FormElementDecorator $decorator, $type, $name, array $attributes)
- {
- $element = $this->createElement($type, $name, $attributes);
- $decorator->decorate($element);
- $this->registerElement($element);
- $this->add($element);
- }
-}
diff --git a/library/Reporting/Web/Forms/Decorator/CompatDecorator.php b/library/Reporting/Web/Forms/Decorator/CompatDecorator.php
deleted file mode 100644
index b2eb536..0000000
--- a/library/Reporting/Web/Forms/Decorator/CompatDecorator.php
+++ /dev/null
@@ -1,63 +0,0 @@
-<?php
-// Icinga Reporting | (c) 2021 Icinga GmbH | GPLv2
-
-namespace Icinga\Module\Reporting\Web\Forms\Decorator;
-
-use Icinga\Application\Version;
-use ipl\Html\Attributes;
-use ipl\Html\FormElement\CheckboxElement;
-use ipl\Html\HtmlElement;
-
-class CompatDecorator extends \ipl\Web\Compat\CompatDecorator
-{
- protected function createCheckboxCompat(CheckboxElement $checkbox)
- {
- if (! $checkbox->getAttributes()->has('id')) {
- $checkbox->setAttribute('id', base64_encode(random_bytes(8)));
- }
-
- $checkbox->getAttributes()->add('class', 'sr-only');
-
- $classes = ['toggle-switch'];
- if ($checkbox->getAttributes()->get('disabled')->getValue()) {
- $classes[] = 'disabled';
- }
-
- return [
- $checkbox,
- new HtmlElement('label', Attributes::create([
- 'class' => $classes,
- 'aria-hidden' => 'true',
- 'for' => $checkbox->getAttributes()->get('id')->getValue()
- ]), new HtmlElement('span', Attributes::create(['class' => 'toggle-slider'])))
- ];
- }
-
- protected function assembleElementCompat()
- {
- if ($this->formElement instanceof CheckboxElement) {
- return $this->createCheckboxCompat($this->formElement);
- }
-
- return $this->formElement;
- }
-
- protected function assemble()
- {
- if (version_compare(Version::VERSION, '2.9.0', '>=')) {
- parent::assemble();
- return;
- }
-
- if ($this->formElement->hasBeenValidated() && ! $this->formElement->isValid()) {
- $this->getAttributes()->add('class', 'has-error');
- }
-
- $this->add(array_filter([
- $this->assembleLabel(),
- $this->assembleElementCompat(),
- $this->assembleDescription(),
- $this->assembleErrors()
- ]));
- }
-}
diff --git a/library/Reporting/Web/Forms/ReportForm.php b/library/Reporting/Web/Forms/ReportForm.php
index 6b1e692..40e376e 100644
--- a/library/Reporting/Web/Forms/ReportForm.php
+++ b/library/Reporting/Web/Forms/ReportForm.php
@@ -1,4 +1,5 @@
<?php
+
// Icinga Reporting | (c) 2018 Icinga GmbH | GPLv2
namespace Icinga\Module\Reporting\Web\Forms;
@@ -6,54 +7,143 @@ namespace Icinga\Module\Reporting\Web\Forms;
use Icinga\Authentication\Auth;
use Icinga\Module\Reporting\Database;
use Icinga\Module\Reporting\ProvidedReports;
-use Icinga\Module\Reporting\Web\Forms\Decorator\CompatDecorator;
use ipl\Html\Contract\FormSubmitElement;
use ipl\Html\Form;
+use ipl\Html\HtmlDocument;
+use ipl\Validator\CallbackValidator;
use ipl\Web\Compat\CompatForm;
class ReportForm extends CompatForm
{
- use Database;
use ProvidedReports;
- /** @var bool Hack to disable the {@link onSuccess()} code upon deletion of the report */
- protected $callOnSuccess;
-
protected $id;
- public function setId($id)
+ /** @var string Label to use for the submit button */
+ protected $submitButtonLabel;
+
+ /** @var bool Whether to render the create and show submit button (is only used from DB Web's object detail) */
+ protected $renderCreateAndShowButton = false;
+
+ /**
+ * Create a new form instance with the given report id
+ *
+ * @param $id
+ *
+ * @return static
+ */
+ public static function fromId($id): self
{
- $this->id = $id;
+ $form = new static();
+ $form->id = $id;
+
+ return $form;
+ }
+
+ public function getId(): ?int
+ {
+ return $this->id;
+ }
+
+ /**
+ * Set the label of the submit button
+ *
+ * @param string $label
+ *
+ * @return $this
+ */
+ public function setSubmitButtonLabel(string $label): self
+ {
+ $this->submitButtonLabel = $label;
return $this;
}
- protected function assemble()
+ /**
+ * Get the label of the submit button
+ *
+ * @return string
+ */
+ public function getSubmitButtonLabel(): string
+ {
+ if ($this->submitButtonLabel !== null) {
+ return $this->submitButtonLabel;
+ }
+
+ return $this->id === null ? $this->translate('Create Report') : $this->translate('Update Report');
+ }
+
+ /**
+ * Set whether the create and show submit button should be rendered
+ *
+ * @param bool $renderCreateAndShowButton
+ *
+ * @return $this
+ */
+ public function setRenderCreateAndShowButton(bool $renderCreateAndShowButton): self
{
- $this->setDefaultElementDecorator(new CompatDecorator());
+ $this->renderCreateAndShowButton = $renderCreateAndShowButton;
+ return $this;
+ }
+
+ public function hasBeenSubmitted(): bool
+ {
+ return $this->hasBeenSent() && (
+ $this->getPopulatedValue('submit')
+ || $this->getPopulatedValue('create_show')
+ || $this->getPopulatedValue('remove')
+ );
+ }
+
+ protected function assemble()
+ {
$this->addElement('text', 'name', [
- 'required' => true,
- 'label' => 'Name'
+ 'required' => true,
+ 'label' => $this->translate('Name'),
+ 'description' => $this->translate(
+ 'A unique name of this report. It is used when exporting to pdf, json or csv format'
+ . ' and also when listing the reports in the cli'
+ ),
+ 'validators' => [
+ 'Callback' => function ($value, CallbackValidator $validator) {
+ if ($value !== null && strpos($value, '..') !== false) {
+ $validator->addMessage(
+ $this->translate('Double dots are not allowed in the report name')
+ );
+
+ return false;
+ }
+
+ return true;
+ }
+ ]
]);
$this->addElement('select', 'timeframe', [
- 'required' => true,
- 'label' => 'Timeframe',
- 'options' => [null => 'Please choose'] + $this->listTimeframes(),
- 'class' => 'autosubmit'
+ 'required' => true,
+ 'class' => 'autosubmit',
+ 'label' => $this->translate('Timeframe'),
+ 'options' => [null => $this->translate('Please choose')] + Database::listTimeframes(),
+ 'description' => $this->translate(
+ 'Specifies the time frame in which this report is to be generated'
+ )
]);
$this->addElement('select', 'template', [
- 'label' => 'Template',
- 'options' => [null => 'Please choose'] + $this->listTemplates()
+ 'label' => $this->translate('Template'),
+ 'options' => [null => $this->translate('Please choose')] + Database::listTemplates(),
+ 'description' => $this->translate(
+ 'Specifies the template to use when exporting this report to pdf. (Default Icinga template)'
+ )
]);
$this->addElement('select', 'reportlet', [
- 'required' => true,
- 'label' => 'Report',
- 'options' => [null => 'Please choose'] + $this->listReports(),
- 'class' => 'autosubmit'
+ 'required' => true,
+ 'class' => 'autosubmit',
+ 'label' => $this->translate('Report'),
+ 'options' => [null => $this->translate('Please choose')] + $this->listReports(),
+ 'description' => $this->translate('Specifies the type of the reportlet to be generated')
]);
$values = $this->getValues();
@@ -63,7 +153,7 @@ class ReportForm extends CompatForm
// $config->populate($this->getValues());
/** @var \Icinga\Module\Reporting\Hook\ReportHook $reportlet */
- $reportlet = new $values['reportlet'];
+ $reportlet = new $values['reportlet']();
$reportlet->initConfigForm($config);
@@ -73,40 +163,43 @@ class ReportForm extends CompatForm
}
$this->addElement('submit', 'submit', [
- 'label' => $this->id === null ? 'Create Report' : 'Update Report'
+ 'label' => $this->getSubmitButtonLabel()
]);
if ($this->id !== null) {
/** @var FormSubmitElement $removeButton */
$removeButton = $this->createElement('submit', 'remove', [
- 'label' => 'Remove Report',
+ 'label' => $this->translate('Remove Report'),
'class' => 'btn-remove',
'formnovalidate' => true
]);
$this->registerElement($removeButton);
- $this->getElement('submit')->getWrapper()->prepend($removeButton);
-
- if ($removeButton->hasBeenPressed()) {
- $this->getDb()->delete('report', ['id = ?' => $this->id]);
- // Stupid cheat because ipl/html is not capable of multiple submit buttons
- $this->getSubmitButton()->setValue($this->getSubmitButton()->getButtonLabel());
- $this->callOnSuccess = false;
- $this->valid = true;
+ /** @var HtmlDocument $wrapper */
+ $wrapper = $this->getElement('submit')->getWrapper();
+ $wrapper->prepend($removeButton);
+ } elseif ($this->renderCreateAndShowButton) {
+ $createAndShow = $this->createElement('submit', 'create_show', [
+ 'label' => $this->translate('Create and Show'),
+ ]);
+ $this->registerElement($createAndShow);
- return;
- }
+ /** @var HtmlDocument $wrapper */
+ $wrapper = $this->getElement('submit')->getWrapper();
+ $wrapper->prepend($createAndShow);
}
}
public function onSuccess()
{
- if ($this->callOnSuccess === false) {
+ $db = Database::get();
+
+ if ($this->getPopulatedValue('remove')) {
+ $db->delete('report', ['id = ?' => $this->id]);
+
return;
}
- $db = $this->getDb();
-
$values = $this->getValues();
$now = time() * 1000;
@@ -155,14 +248,16 @@ class ReportForm extends CompatForm
foreach ($values as $name => $value) {
$db->insert('config', [
- 'reportlet_id' => $reportletId,
- 'name' => $name,
- 'value' => $value,
- 'ctime' => $now,
- 'mtime' => $now
+ 'reportlet_id' => $reportletId,
+ 'name' => $name,
+ 'value' => $value,
+ 'ctime' => $now,
+ 'mtime' => $now
]);
}
$db->commitTransaction();
+
+ $this->id = $reportId;
}
}
diff --git a/library/Reporting/Web/Forms/ScheduleForm.php b/library/Reporting/Web/Forms/ScheduleForm.php
index 47f3ee3..72c4767 100644
--- a/library/Reporting/Web/Forms/ScheduleForm.php
+++ b/library/Reporting/Web/Forms/ScheduleForm.php
@@ -1,96 +1,98 @@
<?php
+
// Icinga Reporting | (c) 2018 Icinga GmbH | GPLv2
namespace Icinga\Module\Reporting\Web\Forms;
use DateTime;
-use Icinga\Application\Version;
+use Icinga\Application\Icinga;
+use Icinga\Application\Web;
use Icinga\Authentication\Auth;
use Icinga\Module\Reporting\Database;
+use Icinga\Module\Reporting\Hook\ActionHook;
use Icinga\Module\Reporting\ProvidedActions;
use Icinga\Module\Reporting\Report;
-use Icinga\Module\Reporting\Web\Flatpickr;
-use Icinga\Module\Reporting\Web\Forms\Decorator\CompatDecorator;
+use Icinga\Util\Json;
use ipl\Html\Contract\FormSubmitElement;
use ipl\Html\Form;
+use ipl\Html\HtmlDocument;
+use ipl\Html\HtmlElement;
+use ipl\Scheduler\Contract\Frequency;
use ipl\Web\Compat\CompatForm;
+use ipl\Web\FormElement\ScheduleElement;
+
+use function ipl\Stdlib\get_php_type;
class ScheduleForm extends CompatForm
{
- use Database;
- use DecoratedElement;
use ProvidedActions;
/** @var Report */
protected $report;
- protected $id;
+ /** @var ScheduleElement */
+ protected $scheduleElement;
- public function setReport(Report $report)
+ public function __construct()
{
- $this->report = $report;
+ $this->scheduleElement = new ScheduleElement('schedule_element');
+ /** @var Web $app */
+ $app = Icinga::app();
+ $this->scheduleElement->setIdProtector([$app->getRequest(), 'protectId']);
+ }
- $schedule = $report->getSchedule();
+ public function getPartUpdates(): array
+ {
+ return $this->scheduleElement->prepareMultipartUpdate($this->getRequest());
+ }
+
+ /**
+ * Create a new form instance with the given report
+ *
+ * @param Report $report
+ *
+ * @return static
+ */
+ public static function fromReport(Report $report): self
+ {
+ $form = new static();
+ $form->report = $report;
+ $schedule = $report->getSchedule();
if ($schedule !== null) {
- $this->setId($schedule->getId());
+ $config = $schedule->getConfig();
+ $config['action'] = $schedule->getAction();
+
+ /** @var Frequency $type */
+ $type = $config['frequencyType'];
+ $config['schedule_element'] = $type::fromJson($config['frequency']);
- $values = [
- 'start' => $schedule->getStart()->format('Y-m-d\\TH:i:s'),
- 'frequency' => $schedule->getFrequency(),
- 'action' => $schedule->getAction()
- ] + $schedule->getConfig();
+ unset($config['frequency']);
+ unset($config['frequencyType']);
- $this->populate($values);
+ $form->populate($config);
}
- return $this;
+ return $form;
}
- public function setId($id)
+ public function hasBeenSubmitted(): bool
{
- $this->id = $id;
-
- return $this;
+ return $this->hasBeenSent() && (
+ $this->getPopulatedValue('submit')
+ || $this->getPopulatedValue('remove')
+ || $this->getPopulatedValue('send')
+ );
}
protected function assemble()
{
- $this->setDefaultElementDecorator(new CompatDecorator());
-
- $frequency = [
- 'minutely' => 'Minutely',
- 'hourly' => 'Hourly',
- 'daily' => 'Daily',
- 'weekly' => 'Weekly',
- 'monthly' => 'Monthly'
- ];
-
- if (version_compare(Version::VERSION, '2.9.0', '>=')) {
- $this->addElement('localDateTime', 'start', [
- 'required' => true,
- 'label' => t('Start'),
- 'placeholder' => t('Choose date and time')
- ]);
- } else {
- $this->addDecoratedElement((new Flatpickr())->setAllowInput(false), 'text', 'start', [
- 'required' => true,
- 'label' => t('Start'),
- 'placeholder' => t('Choose date and time')
- ]);
- }
-
- $this->addElement('select', 'frequency', [
- 'required' => true,
- 'label' => 'Frequency',
- 'options' => [null => 'Please choose'] + $frequency,
- ]);
-
$this->addElement('select', 'action', [
- 'required' => true,
- 'label' => 'Action',
- 'options' => [null => 'Please choose'] + $this->listActions(),
- 'class' => 'autosubmit'
+ 'required' => true,
+ 'class' => 'autosubmit',
+ 'options' => array_merge([null => $this->translate('Please choose')], $this->listActions()),
+ 'label' => $this->translate('Action'),
+ 'description' => $this->translate('Specifies an action to be triggered by the scheduler')
]);
$values = $this->getValues();
@@ -99,8 +101,8 @@ class ScheduleForm extends CompatForm
$config = new Form();
// $config->populate($this->getValues());
- /** @var \Icinga\Module\Reporting\Hook\ActionHook $action */
- $action = new $values['action'];
+ /** @var ActionHook $action */
+ $action = new $values['action']();
$action->initConfigForm($config, $this->report);
@@ -109,67 +111,80 @@ class ScheduleForm extends CompatForm
}
}
+ $this->addHtml(HtmlElement::create('div', ['class' => 'schedule-element-separator']));
+ $this->addElement($this->scheduleElement);
+
+ $schedule = $this->report->getSchedule();
$this->addElement('submit', 'submit', [
- 'label' => $this->id === null ? 'Create Schedule' : 'Update Schedule'
+ 'label' => $schedule === null ? $this->translate('Create Schedule') : $this->translate('Update Schedule')
]);
- if ($this->id !== null) {
+ if ($schedule !== null) {
+ $sendButton = $this->createElement('submit', 'send', [
+ 'label' => $this->translate('Send Report Now'),
+ 'formnovalidate' => true
+ ]);
+ $this->registerElement($sendButton);
+
+ /** @var HtmlDocument $wrapper */
+ $wrapper = $this->getElement('submit')->getWrapper();
+ $wrapper->prepend($sendButton);
+
/** @var FormSubmitElement $removeButton */
$removeButton = $this->createElement('submit', 'remove', [
- 'label' => 'Remove Schedule',
+ 'label' => $this->translate('Remove Schedule'),
'class' => 'btn-remove',
'formnovalidate' => true
]);
$this->registerElement($removeButton);
- $this->getElement('submit')->getWrapper()->prepend($removeButton);
-
- if ($removeButton->hasBeenPressed()) {
- $this->getDb()->delete('schedule', ['id = ?' => $this->id]);
-
- // Stupid cheat because ipl/html is not capable of multiple submit buttons
- $this->getSubmitButton()->setValue($this->getSubmitButton()->getButtonLabel());
- $this->valid = true;
-
- return;
- }
+ $wrapper->prepend($removeButton);
}
}
public function onSuccess()
{
- $db = $this->getDb();
+ $db = Database::get();
+ $schedule = $this->report->getSchedule();
+ if ($this->getPopulatedValue('remove')) {
+ $db->delete('schedule', ['id = ?' => $schedule->getId()]);
- $values = $this->getValues();
+ return;
+ }
- $now = time() * 1000;
+ $values = $this->getValues();
+ if ($this->getPopulatedValue('send')) {
+ $action = new $values['action']();
+ $action->execute($this->report, $values);
- if (! $values['start'] instanceof DateTime) {
- $values['start'] = DateTime::createFromFormat('Y-m-d H:i:s', $values['start']);
+ return;
}
- $data = [
- 'start' => $values['start']->getTimestamp() * 1000,
- 'frequency' => $values['frequency'],
- 'action' => $values['action'],
- 'mtime' => $now
- ];
-
- unset($values['start']);
- unset($values['frequency']);
+ $action = $values['action'];
unset($values['action']);
+ unset($values['schedule_element']);
- $data['config'] = json_encode($values);
+ $frequency = $this->scheduleElement->getValue();
+ $values['frequency'] = Json::encode($frequency);
+ $values['frequencyType'] = get_php_type($frequency);
+ $config = Json::encode($values);
$db->beginTransaction();
- if ($this->id === null) {
- $db->insert('schedule', $data + [
+ if ($schedule === null) {
+ $now = (new DateTime())->getTimestamp() * 1000;
+ $db->insert('schedule', [
'author' => Auth::getInstance()->getUser()->getUsername(),
'report_id' => $this->report->getId(),
- 'ctime' => $now
+ 'ctime' => $now,
+ 'mtime' => $now,
+ 'action' => $action,
+ 'config' => $config
]);
} else {
- $db->update('schedule', $data, ['id = ?' => $this->id]);
+ $db->update('schedule', [
+ 'action' => $action,
+ 'config' => $config
+ ], ['id = ?' => $schedule->getId()]);
}
$db->commitTransaction();
diff --git a/library/Reporting/Web/Forms/SendForm.php b/library/Reporting/Web/Forms/SendForm.php
index 03b691c..e3cf3ec 100644
--- a/library/Reporting/Web/Forms/SendForm.php
+++ b/library/Reporting/Web/Forms/SendForm.php
@@ -1,18 +1,16 @@
<?php
+
// Icinga Reporting | (c) 2018 Icinga GmbH | GPLv2
namespace Icinga\Module\Reporting\Web\Forms;
use Icinga\Module\Reporting\Actions\SendMail;
-use Icinga\Module\Reporting\Database;
use Icinga\Module\Reporting\ProvidedReports;
use Icinga\Module\Reporting\Report;
-use Icinga\Module\Reporting\Web\Forms\Decorator\CompatDecorator;
use ipl\Web\Compat\CompatForm;
class SendForm extends CompatForm
{
- use Database;
use ProvidedReports;
/** @var Report */
@@ -27,12 +25,10 @@ class SendForm extends CompatForm
protected function assemble()
{
- $this->setDefaultElementDecorator(new CompatDecorator());
-
(new SendMail())->initConfigForm($this, $this->report);
$this->addElement('submit', 'submit', [
- 'label' => 'Send Report'
+ 'label' => $this->translate('Send Report')
]);
}
diff --git a/library/Reporting/Web/Forms/TemplateForm.php b/library/Reporting/Web/Forms/TemplateForm.php
index bb062bb..4cd44a9 100644
--- a/library/Reporting/Web/Forms/TemplateForm.php
+++ b/library/Reporting/Web/Forms/TemplateForm.php
@@ -1,23 +1,21 @@
<?php
+
// Icinga Reporting | (c) 2019 Icinga GmbH | GPLv2
namespace Icinga\Module\Reporting\Web\Forms;
+use Exception;
+use GuzzleHttp\Psr7\UploadedFile;
use Icinga\Authentication\Auth;
use Icinga\Module\Reporting\Database;
-use Icinga\Module\Reporting\Web\Forms\Decorator\CompatDecorator;
+use Icinga\Util\Json;
use ipl\Html\Contract\FormSubmitElement;
use ipl\Html\Html;
+use ipl\Html\HtmlDocument;
use ipl\Web\Compat\CompatForm;
-use reportingipl\Html\FormElement\FileElement;
class TemplateForm extends CompatForm
{
- use Database;
-
- /** @var bool Hack to disable the {@link onSuccess()} code upon deletion of the template */
- protected $callOnSuccess;
-
protected $template;
public function getTemplate()
@@ -25,126 +23,141 @@ class TemplateForm extends CompatForm
return $this->template;
}
- public function setTemplate($template)
+ /**
+ * Create a new form instance with the given report
+ *
+ * @param $template
+ *
+ * @return static
+ */
+ public static function fromTemplate($template): self
{
- $this->template = $template;
+ $form = new static();
+
+ $template->settings = Json::decode($template->settings, true);
+ $form->template = $template;
if ($template->settings) {
- $this->populate(array_filter($template->settings, function ($value) {
+ /** @var array<string, mixed> $settings */
+ $settings = $template->settings;
+ $form->populate(array_filter($settings, function ($value) {
// Don't populate files
return ! is_array($value);
}));
}
- return $this;
+ return $form;
}
- protected function assemble()
+ public function hasBeenSubmitted(): bool
{
- $this->setDefaultElementDecorator(new CompatDecorator());
+ return $this->hasBeenSent() && ($this->getPopulatedValue('submit') || $this->getPopulatedValue('remove'));
+ }
+ protected function assemble()
+ {
$this->setAttribute('enctype', 'multipart/form-data');
$this->add(Html::tag('h2', 'Template Settings'));
$this->addElement('text', 'name', [
- 'label' => 'Name',
- 'placeholder' => 'Template name',
+ 'label' => $this->translate('Name'),
+ 'placeholder' => $this->translate('Template name'),
'required' => true
]);
- $this->add(Html::tag('h2', 'Cover Page Settings'));
+ $this->add(Html::tag('h2', $this->translate('Cover Page Settings')));
- $this->addElement(new FileElement('cover_page_background_image', [
- 'label' => 'Background Image',
- 'accept' => 'image/png, image/jpeg'
- ]));
+ $this->addElement('file', 'cover_page_background_image', [
+ 'label' => $this->translate('Background Image'),
+ 'accept' => ['image/png', 'image/jpeg', 'image/jpg'],
+ 'destination' => sys_get_temp_dir()
+ ]);
- if ($this->template !== null
- && isset($this->template->settings['cover_page_background_image'])
+ if (
+ $this->template !== null
+ && isset($this->template->settings['cover_page_background_image'])
) {
$this->add(Html::tag(
'p',
- ['style' => ['margin-left: 14em;']],
- 'Upload a new background image to override the existing one'
+ ['class' => 'override-uploaded-file-hint'],
+ $this->translate('Upload a new background image to override the existing one')
));
$this->addElement('checkbox', 'remove_cover_page_background_image', [
- 'label' => 'Remove background image'
+ 'label' => $this->translate('Remove background image')
]);
}
- $this->addElement(new FileElement('cover_page_logo', [
- 'label' => 'Logo',
- 'accept' => 'image/png, image/jpeg'
- ]));
+ $this->addElement('file', 'cover_page_logo', [
+ 'label' => $this->translate('Logo'),
+ 'accept' => ['image/png', 'image/jpeg', 'image/jpg'],
+ 'destination' => sys_get_temp_dir()
+ ]);
- if ($this->template !== null
+ if (
+ $this->template !== null
&& isset($this->template->settings['cover_page_logo'])
) {
$this->add(Html::tag(
'p',
- ['style' => ['margin-left: 14em;']],
- 'Upload a new logo to override the existing one'
+ ['class' => 'override-uploaded-file-hint'],
+ $this->translate('Upload a new logo to override the existing one')
));
$this->addElement('checkbox', 'remove_cover_page_logo', [
- 'label' => 'Remove Logo'
+ 'label' => $this->translate('Remove Logo')
]);
}
$this->addElement('textarea', 'title', [
- 'label' => 'Title',
- 'placeholder' => 'Report title'
+ 'label' => $this->translate('Title'),
+ 'placeholder' => $this->translate('Report title')
]);
$this->addElement('text', 'color', [
- 'label' => 'Color',
- 'placeholder' => 'CSS color code'
+ 'label' => $this->translate('Color'),
+ 'placeholder' => $this->translate('CSS color code')
]);
- $this->add(Html::tag('h2', 'Header Settings'));
+ $this->add(Html::tag('h2', $this->translate('Header Settings')));
- $this->addColumnSettings('header_column1', 'Column 1');
- $this->addColumnSettings('header_column2', 'Column 2');
- $this->addColumnSettings('header_column3', 'Column 3');
+ $this->addColumnSettings('header_column1', $this->translate('Column 1'));
+ $this->addColumnSettings('header_column2', $this->translate('Column 2'));
+ $this->addColumnSettings('header_column3', $this->translate('Column 3'));
- $this->add(Html::tag('h2', 'Footer Settings'));
+ $this->add(Html::tag('h2', $this->translate('Footer Settings')));
- $this->addColumnSettings('footer_column1', 'Column 1');
- $this->addColumnSettings('footer_column2', 'Column 2');
- $this->addColumnSettings('footer_column3', 'Column 3');
+ $this->addColumnSettings('footer_column1', $this->translate('Column 1'));
+ $this->addColumnSettings('footer_column2', $this->translate('Column 2'));
+ $this->addColumnSettings('footer_column3', $this->translate('Column 3'));
$this->addElement('submit', 'submit', [
- 'label' => $this->template === null ? 'Create Template' : 'Update Template'
+ 'label' => $this->template === null
+ ? $this->translate('Create Template')
+ : $this->translate('Update Template')
]);
if ($this->template !== null) {
/** @var FormSubmitElement $removeButton */
$removeButton = $this->createElement('submit', 'remove', [
- 'label' => 'Remove Template',
+ 'label' => $this->translate('Remove Template'),
'class' => 'btn-remove',
'formnovalidate' => true
]);
$this->registerElement($removeButton);
- $this->getElement('submit')->getWrapper()->prepend($removeButton);
- if ($removeButton->hasBeenPressed()) {
- $this->getDb()->delete('template', ['id = ?' => $this->template->id]);
-
- // Stupid cheat because ipl/html is not capable of multiple submit buttons
- $this->getSubmitButton()->setValue($this->getSubmitButton()->getButtonLabel());
- $this->callOnSuccess = false;
- $this->valid = true;
-
- return;
- }
+ /** @var HtmlDocument $wrapper */
+ $wrapper = $this->getElement('submit')->getWrapper();
+ $wrapper->prepend($removeButton);
}
}
public function onSuccess()
{
- if ($this->callOnSuccess === false) {
+ if ($this->getPopulatedValue('remove')) {
+ Database::get()->delete('template', ['id = ?' => $this->template->id]);
+
return;
}
@@ -153,20 +166,17 @@ class TemplateForm extends CompatForm
$settings = $this->getValues();
try {
- /** @var $uploadedFile \GuzzleHttp\Psr7\UploadedFile */
- foreach ($this->getRequest()->getUploadedFiles() as $name => $uploadedFile) {
- if ($uploadedFile->getError() === UPLOAD_ERR_NO_FILE) {
- continue;
+ foreach ($settings as $name => $setting) {
+ if ($setting instanceof UploadedFile) {
+ $settings[$name] = [
+ 'mime_type' => $setting->getClientMediaType(),
+ 'size' => $setting->getSize(),
+ 'content' => base64_encode((string) $setting->getStream())
+ ];
}
-
- $settings[$name] = [
- 'mime_type' => $uploadedFile->getClientMediaType(),
- 'size' => $uploadedFile->getSize(),
- 'content' => base64_encode((string) $uploadedFile->getStream())
- ];
}
- $db = $this->getDb();
+ $db = Database::get();
$now = time() * 1000;
@@ -179,19 +189,21 @@ class TemplateForm extends CompatForm
'mtime' => $now
]);
} else {
- if (isset($settings['remove_cover_page_background_image'])) {
+ if ($this->getValue('remove_cover_page_background_image', 'n') === 'y') {
unset($settings['cover_page_background_image']);
unset($settings['remove_cover_page_background_image']);
- } elseif (! isset($settings['cover_page_background_image'])
+ } elseif (
+ ! isset($settings['cover_page_background_image'])
&& isset($this->template->settings['cover_page_background_image'])
) {
$settings['cover_page_background_image'] = $this->template->settings['cover_page_background_image'];
}
- if (isset($settings['remove_cover_page_logo'])) {
+ if ($this->getValue('remove_cover_page_logo', 'n') === 'y') {
unset($settings['cover_page_logo']);
unset($settings['remove_cover_page_logo']);
- } elseif (! isset($settings['cover_page_logo'])
+ } elseif (
+ ! isset($settings['cover_page_logo'])
&& isset($this->template->settings['cover_page_logo'])
) {
$settings['cover_page_logo'] = $this->template->settings['cover_page_logo'];
@@ -204,7 +216,8 @@ class TemplateForm extends CompatForm
if ($settings[$type] === 'image') {
$value = "{$headerOrFooter}_column{$i}_value";
- if (! isset($settings[$value])
+ if (
+ ! isset($settings[$value])
&& isset($this->template->settings[$value])
) {
$settings[$value] = $this->template->settings[$value];
@@ -219,7 +232,7 @@ class TemplateForm extends CompatForm
'mtime' => $now
], ['id = ?' => $this->template->id]);
}
- } catch (\Exception $e) {
+ } catch (Exception $e) {
die($e->getMessage());
}
}
@@ -240,20 +253,31 @@ class TemplateForm extends CompatForm
]
]);
+ $valueType = $this->getValue($type, 'none');
+ $populated = $this->getPopulatedValue($value);
+ if (
+ ($valueType === 'image' && ! $populated instanceof UploadedFile)
+ || ($valueType !== 'image' && $populated instanceof UploadedFile)
+ ) {
+ $this->clearPopulatedValue($value);
+ }
+
switch ($this->getValue($type, 'none')) {
case 'image':
- $this->addElement(new FileElement($value, [
- 'label' => 'Image',
- 'accept' => 'image/png, image/jpeg'
- ]));
+ $this->addElement('file', $value, [
+ 'label' => 'Image',
+ 'accept' => ['image/png', 'image/jpeg', 'image/jpg'],
+ 'destination' => sys_get_temp_dir()
+ ]);
- if ($this->template !== null
+ if (
+ $this->template !== null
&& $this->template->settings[$type] === 'image'
&& isset($this->template->settings[$value])
) {
$this->add(Html::tag(
'p',
- ['style' => ['margin-left: 14em;']],
+ ['class' => 'override-uploaded-file-hint'],
'Upload a new image to override the existing one'
));
}
@@ -270,7 +294,7 @@ class TemplateForm extends CompatForm
'page_of' => 'Page Number + Total Number of Pages',
'date' => 'Date'
],
- 'value' => 'report_title'
+ 'value' => 'report_title'
]);
break;
case 'text':
diff --git a/library/Reporting/Web/Forms/TimeframeForm.php b/library/Reporting/Web/Forms/TimeframeForm.php
index 3d78709..37ea34f 100644
--- a/library/Reporting/Web/Forms/TimeframeForm.php
+++ b/library/Reporting/Web/Forms/TimeframeForm.php
@@ -1,86 +1,203 @@
<?php
+
// Icinga Reporting | (c) 2019 Icinga GmbH | GPLv2
namespace Icinga\Module\Reporting\Web\Forms;
+use DateTime;
+use Exception;
use Icinga\Module\Reporting\Database;
-use Icinga\Module\Reporting\Web\Flatpickr;
-use Icinga\Module\Reporting\Web\Forms\Decorator\CompatDecorator;
use ipl\Html\Contract\FormSubmitElement;
+use ipl\Html\FormElement\LocalDateTimeElement;
+use ipl\Html\HtmlDocument;
+use ipl\Validator\CallbackValidator;
use ipl\Web\Compat\CompatForm;
class TimeframeForm extends CompatForm
{
- use Database;
- use DecoratedElement;
-
+ /** @var int */
protected $id;
- public function setId($id)
+ /**
+ * Create a new form instance with the given report
+ *
+ * @param int $id
+ *
+ * @return static
+ */
+ public static function fromId(int $id): self
{
- $this->id = $id;
+ $form = new static();
+
+ $form->id = $id;
- return $this;
+ return $form;
}
- protected function assemble()
+ public function hasBeenSubmitted(): bool
{
- $this->setDefaultElementDecorator(new CompatDecorator());
+ return $this->hasBeenSent() && ($this->getPopulatedValue('submit') || $this->getPopulatedValue('remove'));
+ }
+ protected function assemble()
+ {
$this->addElement('text', 'name', [
- 'required' => true,
- 'label' => 'Name'
+ 'required' => true,
+ 'label' => $this->translate('Name'),
+ 'description' => $this->translate('A unique name of this timeframe')
]);
- $flatpickr = new Flatpickr();
+ $default = new DateTime('00:00:00');
+ $start = $this->getPopulatedValue('start', $default);
+ if (! $start instanceof DateTime) {
+ $datetime = DateTime::createFromFormat(LocalDateTimeElement::FORMAT, $start);
+ if ($datetime) {
+ $start = $datetime;
+ }
+ }
- $this->addDecoratedElement($flatpickr, 'text', 'start', [
- 'required' => true,
- 'label' => 'Start',
- 'placeholder' => 'Select a start date or provide a textual datetime description',
- 'data-flatpickr-default-hour' => '00'
+ $relativeStart = $this->getPopulatedValue('relative-start', $start instanceof DateTime ? 'n' : 'y');
+ $this->addElement('checkbox', 'relative-start', [
+ 'required' => false,
+ 'class' => 'autosubmit',
+ 'value' => $relativeStart,
+ 'label' => $this->translate('Relative Start')
]);
- $this->addDecoratedElement($flatpickr, 'text', 'end', [
- 'required' => true,
- 'label' => 'End',
- 'placeholder' => 'Select a end date or provide a textual datetime description',
- 'data-flatpickrDefaultHour' => '23',
- 'data-flatpickrDefaultMinute' => '59',
- 'data-flatpickrDefaultSeconds' => '59'
- ]);
+ if ($relativeStart === 'n') {
+ if (! $start instanceof DateTime) {
+ $start = $default;
+ $this->clearPopulatedValue('start');
+ }
+
+ $this->addElement(
+ new LocalDateTimeElement('start', [
+ 'required' => true,
+ 'value' => $start,
+ 'label' => $this->translate('Start'),
+ 'description' => $this->translate('Specifies the start time of this timeframe')
+ ])
+ );
+ } else {
+ $this->addElement('text', 'start', [
+ 'required' => true,
+ 'label' => $this->translate('Start'),
+ 'placeholder' => $this->translate('First day of this month'),
+ 'description' => $this->translate('Specifies the start time of this timeframe'),
+ 'validators' => [
+ new CallbackValidator(function ($value, CallbackValidator $validator) {
+ if ($value !== null) {
+ try {
+ new DateTime($value);
+ } catch (Exception $_) {
+ $validator->addMessage($this->translate('Invalid textual date time'));
+
+ return false;
+ }
+ }
+
+ return true;
+ })
+ ]
+ ]);
+ }
+
+ $default = new DateTime('23:59:59');
+ $end = $this->getPopulatedValue('end', $default);
+ if (! $end instanceof DateTime) {
+ $datetime = DateTime::createFromFormat(LocalDateTimeElement::FORMAT, $end);
+ if ($datetime) {
+ $end = $datetime;
+ }
+ }
+
+ $relativeEnd = $this->getPopulatedValue('relative-end', $end instanceof DateTime ? 'n' : 'y');
+ if ($relativeStart === 'y') {
+ $this->addElement('checkbox', 'relative-end', [
+ 'required' => false,
+ 'class' => 'autosubmit',
+ 'value' => $relativeEnd,
+ 'label' => $this->translate('Relative End')
+ ]);
+ }
+
+ if ($relativeEnd === 'n' || $relativeStart === 'n') {
+ if (! $end instanceof DateTime) {
+ $end = $default;
+ $this->clearPopulatedValue('end');
+ }
+
+ $this->addElement(
+ new LocalDateTimeElement('end', [
+ 'required' => true,
+ 'value' => $end,
+ 'label' => $this->translate('End'),
+ 'description' => $this->translate('Specifies the end time of this timeframe')
+ ])
+ );
+ } else {
+ $this->addElement('text', 'end', [
+ 'required' => true,
+ 'label' => $this->translate('End'),
+ 'placeholder' => $this->translate('Last day of this month'),
+ 'description' => $this->translate('Specifies the end time of this timeframe'),
+ 'validators' => [
+ new CallbackValidator(function ($value, CallbackValidator $validator) {
+ if ($value !== null) {
+ try {
+ new DateTime($value);
+ } catch (Exception $_) {
+ $validator->addMessage($this->translate('Invalid textual date time'));
+
+ return false;
+ }
+ }
+
+ return true;
+ })
+ ]
+ ]);
+ }
$this->addElement('submit', 'submit', [
- 'label' => $this->id === null ? 'Create Time Frame' : 'Update Time Frame'
+ 'label' => $this->id === null
+ ? $this->translate('Create Time Frame')
+ : $this->translate('Update Time Frame')
]);
if ($this->id !== null) {
/** @var FormSubmitElement $removeButton */
$removeButton = $this->createElement('submit', 'remove', [
- 'label' => 'Remove Time Frame',
+ 'label' => $this->translate('Remove Time Frame'),
'class' => 'btn-remove',
'formnovalidate' => true
]);
$this->registerElement($removeButton);
- $this->getElement('submit')->getWrapper()->prepend($removeButton);
- if ($removeButton->hasBeenPressed()) {
- $this->getDb()->delete('timeframe', ['id = ?' => $this->id]);
-
- // Stupid cheat because ipl/html is not capable of multiple submit buttons
- $this->getSubmitButton()->setValue($this->getSubmitButton()->getButtonLabel());
- $this->valid = true;
-
- return;
- }
+ /** @var HtmlDocument $wrapper */
+ $wrapper = $this->getElement('submit')->getWrapper();
+ $wrapper->prepend($removeButton);
}
}
public function onSuccess()
{
- $db = $this->getDb();
+ $db = Database::get();
+
+ if ($this->getPopulatedValue('remove')) {
+ $db->delete('timeframe', ['id = ?' => $this->id]);
+
+ return;
+ }
$values = $this->getValues();
+ if ($values['start'] instanceof DateTime) {
+ $values['start'] = $values['start']->format(LocalDateTimeElement::FORMAT);
+ }
+
+ if ($values['end'] instanceof DateTime) {
+ $values['end'] = $values['end']->format(LocalDateTimeElement::FORMAT);
+ }
$now = time() * 1000;