summaryrefslogtreecommitdiffstats
path: root/application
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--application/clicommands/ScheduleCommand.php24
-rw-r--r--application/controllers/ConfigController.php41
-rw-r--r--application/controllers/PlugController.php.disabled72
-rw-r--r--application/controllers/ReportController.php208
-rw-r--r--application/controllers/ReportController.php.modal126
-rw-r--r--application/controllers/ReportsController.php104
-rw-r--r--application/controllers/TemplateController.php89
-rw-r--r--application/controllers/TemplatesController.php106
-rw-r--r--application/controllers/TestController.php47
-rw-r--r--application/controllers/TimeframeController.php47
-rw-r--r--application/controllers/TimeframesController.php103
-rw-r--r--application/forms/ConfigureMailForm.php23
-rw-r--r--application/forms/SelectBackendForm.php35
-rw-r--r--application/views/scripts/config/backend.phtml6
-rw-r--r--application/views/scripts/config/mail.phtml6
15 files changed, 1037 insertions, 0 deletions
diff --git a/application/clicommands/ScheduleCommand.php b/application/clicommands/ScheduleCommand.php
new file mode 100644
index 0000000..e554138
--- /dev/null
+++ b/application/clicommands/ScheduleCommand.php
@@ -0,0 +1,24 @@
+<?php
+// Icinga Reporting | (c) 2018 Icinga GmbH | GPLv2
+
+namespace Icinga\Module\Reporting\Clicommands;
+
+use Icinga\Module\Reporting\Cli\Command;
+use Icinga\Module\Reporting\Scheduler;
+
+class ScheduleCommand extends Command
+{
+ /**
+ * Run all configured reports based on their schedule
+ *
+ * USAGE:
+ *
+ * icingacli reporting schedule run
+ */
+ public function runAction()
+ {
+ $scheduler = new Scheduler($this->getDb());
+
+ $scheduler->run();
+ }
+}
diff --git a/application/controllers/ConfigController.php b/application/controllers/ConfigController.php
new file mode 100644
index 0000000..30fcc67
--- /dev/null
+++ b/application/controllers/ConfigController.php
@@ -0,0 +1,41 @@
+<?php
+// Icinga Reporting | (c) 2018 Icinga GmbH | GPLv2
+
+namespace Icinga\Module\Reporting\Controllers;
+
+use Icinga\Application\Config;
+use Icinga\Module\Reporting\Forms\ConfigureMailForm;
+use Icinga\Module\Reporting\Forms\SelectBackendForm;
+use Icinga\Web\Controller;
+
+class ConfigController extends Controller
+{
+ public function init()
+ {
+ $this->assertPermission('config/modules');
+
+ parent::init();
+ }
+
+ public function backendAction()
+ {
+ $form = (new SelectBackendForm())
+ ->setIniConfig(Config::module('reporting'));
+
+ $form->handleRequest();
+
+ $this->view->tabs = $this->Module()->getConfigTabs()->activate('backend');
+ $this->view->form = $form;
+ }
+
+ public function mailAction()
+ {
+ $form = (new ConfigureMailForm())
+ ->setIniConfig(Config::module('reporting'));
+
+ $form->handleRequest();
+
+ $this->view->tabs = $this->Module()->getConfigTabs()->activate('mail');
+ $this->view->form = $form;
+ }
+}
diff --git a/application/controllers/PlugController.php.disabled b/application/controllers/PlugController.php.disabled
new file mode 100644
index 0000000..a2c6453
--- /dev/null
+++ b/application/controllers/PlugController.php.disabled
@@ -0,0 +1,72 @@
+<?php
+
+namespace Icinga\Module\Reporting\Controllers;
+
+use GuzzleHttp\Psr7\ServerRequest;
+use Icinga\Module\Reporting\Hook\ReportHook;
+use Icinga\Module\Reporting\Web\Forms\ReportForm;
+use Icinga\Module\Reporting\Web\Controller;
+use Icinga\Web\Hook;
+use Icinga\Web\Url;
+use ipl\Html\Html;
+
+class PlugController extends Controller
+{
+ public function indexAction()
+ {
+ $moduleToShow = strtolower($this->params->get('module', 'reporting'));
+
+ $reportsByModule = [];
+
+ foreach (ReportHook::getReports() as $class => $report) {
+ $moduleName = $report->getModuleName();
+
+ if (! isset($reportsByModule[$moduleName])) {
+ $reportsByModule[$moduleName] = [];
+ }
+
+ $reportsByModule[$moduleName][$class] = $report;
+ }
+
+ $editor = Html::tag('div', ['class' => 'editor']);
+
+ $nav = [];
+
+ $cards = [];
+
+ foreach ($reportsByModule as $moduleName => $reports) {
+ $link = Html::tag('a', ['href' => Url::fromRequest(['module' => $moduleName])], $moduleName);
+
+ $nav[] = $link;
+
+ if ($moduleName !== $moduleToShow) {
+ continue;
+ }
+
+ $link->getAttributes()->add('class', 'active');
+
+ foreach ($reports as $report) {
+ $cards[] = Html::tag(
+ 'div',
+ ['class' => 'card'],
+ [
+ Html::tag('div', ['class' => 'card-top'], $report->getPreview()),
+ Html::tag(
+ 'div',
+ ['class' => 'card-content'],
+ Html::tag('h5', ['class' => 'card-title'], $report->getName()),
+ Html::tag('p', ['class' => 'card-text'], $report->getDescription())
+ )
+ ]
+ );
+ }
+ }
+
+ $editor->add(Html::tag('div', ['class' => 'editor-nav'], $nav));
+ $editor->add(Html::tag('div', ['class' => 'editor-content'], $cards));
+
+ $this->addContent($editor);
+
+ $this->addContent(Html::tag('a', ['href' => 'plug', 'class' => 'modal-toggle', 'data-base-target' => 'modal-container'], 'Modal'));
+ }
+}
diff --git a/application/controllers/ReportController.php b/application/controllers/ReportController.php
new file mode 100644
index 0000000..090c759
--- /dev/null
+++ b/application/controllers/ReportController.php
@@ -0,0 +1,208 @@
+<?php
+// Icinga Reporting | (c) 2018 Icinga GmbH | GPLv2
+
+namespace Icinga\Module\Reporting\Controllers;
+
+use GuzzleHttp\Psr7\ServerRequest;
+use Icinga\Application\Hook;
+use Icinga\Module\Pdfexport\ProvidedHook\Pdfexport;
+use Icinga\Module\Reporting\Database;
+use Icinga\Module\Reporting\Report;
+use Icinga\Module\Reporting\Web\Controller;
+use Icinga\Module\Reporting\Web\Forms\ReportForm;
+use Icinga\Module\Reporting\Web\Forms\ScheduleForm;
+use Icinga\Module\Reporting\Web\Forms\SendForm;
+use Icinga\Module\Reporting\Web\Widget\CompatDropdown;
+use ipl\Html\Error;
+use ipl\Web\Url;
+use ipl\Web\Widget\ActionBar;
+use Icinga\Util\Environment;
+
+class ReportController extends Controller
+{
+ use Database;
+
+ /** @var Report */
+ protected $report;
+
+ public function init()
+ {
+ $this->report = Report::fromDb($this->params->getRequired('id'));
+ }
+
+ public function indexAction()
+ {
+ $this->addTitleTab($this->report->getName());
+
+ $this->addControl($this->assembleActions());
+
+ Environment::raiseExecutionTime();
+ Environment::raiseMemoryLimit();
+
+ try {
+ $this->addContent($this->report->toHtml());
+ } catch (\Exception $e) {
+ $this->addContent(Error::show($e));
+ }
+ }
+
+ public function editAction()
+ {
+ $this->assertPermission('reporting/reports');
+ $this->addTitleTab('Edit Report');
+
+ $values = [
+ 'name' => $this->report->getName(),
+ // TODO(el): Must cast to string here because ipl/html does not
+ // support integer return values for attribute callbacks
+ 'timeframe' => (string) $this->report->getTimeframe()->getId(),
+ ];
+
+ $reportlet = $this->report->getReportlets()[0];
+
+ $values['reportlet'] = $reportlet->getClass();
+
+ foreach ($reportlet->getConfig() as $name => $value) {
+ $values[$name] = $value;
+ }
+
+ $form = new ReportForm();
+ $form->setId($this->report->getId());
+ $form->populate($values);
+ $form->handleRequest(ServerRequest::fromGlobals());
+
+ $this->redirectForm($form, 'reporting/reports');
+
+ $this->addContent($form);
+ }
+
+ public function sendAction()
+ {
+ $this->addTitleTab('Send Report');
+
+ Environment::raiseExecutionTime();
+ Environment::raiseMemoryLimit();
+
+ $form = new SendForm();
+ $form
+ ->setReport($this->report)
+ ->handleRequest(ServerRequest::fromGlobals());
+
+ $this->redirectForm($form, "reporting/report?id={$this->report->getId()}");
+
+ $this->addContent($form);
+ }
+
+ public function scheduleAction()
+ {
+ $this->assertPermission('reporting/schedules');
+ $this->addTitleTab('Schedule');
+
+ $form = new ScheduleForm();
+ $form
+ ->setReport($this->report)
+ ->handleRequest(ServerRequest::fromGlobals());
+
+ $this->redirectForm($form, "reporting/report?id={$this->report->getId()}");
+
+ $this->addContent($form);
+ }
+
+ public function downloadAction()
+ {
+ $type = $this->params->getRequired('type');
+
+ Environment::raiseExecutionTime();
+ Environment::raiseMemoryLimit();
+
+ $name = sprintf(
+ '%s (%s) %s',
+ $this->report->getName(),
+ $this->report->getTimeframe()->getName(),
+ date('Y-m-d H:i')
+ );
+
+ switch ($type) {
+ case 'pdf':
+ /** @var Hook\PdfexportHook */
+ Pdfexport::first()->streamPdfFromHtml($this->report->toPdf(), $name);
+ exit;
+ case 'csv':
+ $response = $this->getResponse();
+ $response
+ ->setHeader('Content-Type', 'text/csv')
+ ->setHeader('Cache-Control', 'no-store')
+ ->setHeader(
+ 'Content-Disposition',
+ 'attachment; filename=' . $name . '.csv'
+ )
+ ->appendBody($this->report->toCsv())
+ ->sendResponse();
+ exit;
+ case 'json':
+ $response = $this->getResponse();
+ $response
+ ->setHeader('Content-Type', 'application/json')
+ ->setHeader('Cache-Control', 'no-store')
+ ->setHeader(
+ 'Content-Disposition',
+ 'inline; filename=' . $name . '.json'
+ )
+ ->appendBody($this->report->toJson())
+ ->sendResponse();
+ exit;
+ }
+ }
+
+ protected function assembleActions()
+ {
+ $reportId = $this->report->getId();
+
+ $download = (new CompatDropdown('Download'))
+ ->addLink(
+ 'PDF',
+ Url::fromPath('reporting/report/download?type=pdf', ['id' => $reportId]),
+ null,
+ ['target' => '_blank']
+ );
+
+ if ($this->report->providesData()) {
+ $download->addLink(
+ 'CSV',
+ Url::fromPath('reporting/report/download?type=csv', ['id' => $reportId]),
+ null,
+ ['target' => '_blank']
+ );
+ $download->addLink(
+ 'JSON',
+ Url::fromPath('reporting/report/download?type=json', ['id' => $reportId]),
+ null,
+ ['target' => '_blank']
+ );
+ }
+
+ $actions = new ActionBar();
+
+ if ($this->hasPermission('reporting/reports')) {
+ $actions->addLink(
+ 'Modify',
+ Url::fromPath('reporting/report/edit', ['id' => $reportId]),
+ 'edit'
+ );
+ }
+
+ if ($this->hasPermission('reporting/schedules')) {
+ $actions->addLink(
+ 'Schedule',
+ Url::fromPath('reporting/report/schedule', ['id' => $reportId]),
+ 'calendar-empty'
+ );
+ }
+
+ $actions
+ ->add($download)
+ ->addLink('Send', Url::fromPath('reporting/report/send', ['id' => $reportId]), 'forward');
+
+ return $actions;
+ }
+}
diff --git a/application/controllers/ReportController.php.modal b/application/controllers/ReportController.php.modal
new file mode 100644
index 0000000..915bf2b
--- /dev/null
+++ b/application/controllers/ReportController.php.modal
@@ -0,0 +1,126 @@
+<?php
+
+namespace Icinga\Module\Reporting\Controllers;
+
+use GuzzleHttp\Psr7\ServerRequest;
+use Icinga\Module\Reporting\Database;
+use Icinga\Module\Reporting\Report;
+use Icinga\Module\Reporting\Web\Controller;
+use Icinga\Module\Reporting\Web\Forms\ReportForm;
+use Icinga\Module\Reporting\Web\Forms\ScheduleForm;
+use Icinga\Module\Reporting\Web\Forms\SendForm;
+use ipl\Web\Widget\ModalToggle;
+use ipl\Web\Widget\Modal;
+use reportingipl\Web\Url;
+use reportingipl\Web\Widget\ActionBar;
+use reportingipl\Web\Widget\DropdownLink;
+
+class ReportController extends Controller
+{
+ use Database;
+
+ /** @var Report */
+ protected $report;
+
+ public function init()
+ {
+ $this->report = Report::fromDb($this->params->getRequired('id'));
+ }
+
+ public function indexAction()
+ {
+ $this->setTitle($this->report->getName());
+
+ $this->addControl($this->assembleActions());
+
+ $this->addContent($this->report->toHtml());
+ }
+
+ public function editAction()
+ {
+ $this->setTitle('Edit Report');
+
+ $values = [
+ 'name' => $this->report->getName(),
+ 'timeframe' => $this->report->getTimeframe()->getId(),
+ ];
+
+ $reportlet = $this->report->getReportlets()[0];
+
+ $values['reportlet'] = $reportlet->getClass();
+
+ foreach ($reportlet->getConfig() as $name => $value) {
+ $values[$name] = $value;
+ }
+
+ $form = new ReportForm();
+ $form->setId($this->report->getId());
+ $form->populate($values);
+ $form->handleRequest(ServerRequest::fromGlobals());
+
+ $this->redirectForm($form, 'reporting/reports');
+
+ $this->addContent($form);
+ }
+
+ public function sendAction()
+ {
+ $this->setTitle('Send Report');
+
+ $form = new SendForm();
+ $form
+ ->setReport($this->report)
+ ->handleRequest(ServerRequest::fromGlobals());
+
+ $this->redirectForm($form, "reporting/report?id={$this->report->getId()}");
+
+ $this->addContent(new Modal($form));
+ }
+
+ public function scheduleAction()
+ {
+ $this->setTitle('Schedule');
+
+ $form = new ScheduleForm();
+ $form
+ ->setReport($this->report)
+ ->handleRequest(ServerRequest::fromGlobals());
+
+ $this->redirectForm($form, "reporting/report?id={$this->report->getId()}");
+
+ $this->addContent(new Modal($form));
+
+ $this->getResponse()->setHeader('X-Icinga-History', 'no', true);
+ }
+
+ protected function assembleActions()
+ {
+ $reportId = $this->report->getId();
+
+ $download = (new DropdownLink('Download'))
+ ->addLink('PDF', Url::fromPath('reporting/report/download?type=pdf', ['id' => $reportId]));
+
+ $send = (new DropdownLink('Send', 'forward'))
+ ->addLink('PDF', Url::fromPath('reporting/report/send?type=pdf', ['id' => $reportId]));
+
+ if ($this->report->providesCsv()) {
+ $download->addLink('CSV', Url::fromPath('reporting/report/download?type=csv', ['id' => $reportId]));
+ $send->addLink('CSV', Url::fromPath('reporting/report/send?type=csv', ['id' => $reportId]));
+ }
+
+ if ($this->report->providesJson()) {
+ $download->addLink('JSON', Url::fromPath('reporting/report/download?type=json', ['id' => $reportId]));
+ $send->addLink('JSON', Url::fromPath('reporting/report/send?type=json', ['id' => $reportId]));
+ }
+
+ $actions = new ActionBar();
+
+ $actions
+ ->addLink('Modify', Url::fromPath('reporting/report/edit', ['id' => $reportId]), 'edit')
+ ->add(new ModalToggle('Schedule', Url::fromPath('reporting/report/schedule', ['id' => $reportId]), 'calendar-empty'))
+ ->add($download)
+ ->addLink('Send', Url::fromPath('reporting/report/send', ['id' => $reportId]), 'forward');
+
+ return $actions;
+ }
+}
diff --git a/application/controllers/ReportsController.php b/application/controllers/ReportsController.php
new file mode 100644
index 0000000..7971897
--- /dev/null
+++ b/application/controllers/ReportsController.php
@@ -0,0 +1,104 @@
+<?php
+// Icinga Reporting | (c) 2018 Icinga GmbH | GPLv2
+
+namespace Icinga\Module\Reporting\Controllers;
+
+use GuzzleHttp\Psr7\ServerRequest;
+use Icinga\Module\Reporting\Database;
+use Icinga\Module\Reporting\Web\Controller;
+use Icinga\Module\Reporting\Web\Forms\ReportForm;
+use Icinga\Module\Reporting\Web\ReportsTimeframesAndTemplatesTabs;
+use ipl\Html\Html;
+use ipl\Sql\Select;
+use ipl\Web\Url;
+use ipl\Web\Widget\ButtonLink;
+use ipl\Web\Widget\Icon;
+use ipl\Web\Widget\Link;
+
+class ReportsController extends Controller
+{
+ use Database;
+ use ReportsTimeframesAndTemplatesTabs;
+
+ public function indexAction()
+ {
+ $this->createTabs()->activate('reports');
+
+ if ($this->hasPermission('reporting/reports')) {
+ $this->addControl(new ButtonLink(
+ $this->translate('New Report'),
+ Url::fromPath('reporting/reports/new'),
+ 'plus'
+ ));
+ }
+
+ $tableRows = [];
+
+ $select = (new Select())
+ ->from('report r')
+ ->columns(['r.*', 'timeframe' => 't.name'])
+ ->join('timeframe t', 'r.timeframe_id = t.id')
+ ->orderBy('r.mtime', SORT_DESC);
+
+ foreach ($this->getDb()->select($select) as $report) {
+ $url = Url::fromPath('reporting/report', ['id' => $report->id])->getAbsoluteUrl('&');
+
+ $tableRows[] = Html::tag('tr', ['href' => $url], [
+ Html::tag('td', null, $report->name),
+ Html::tag('td', null, $report->author),
+ Html::tag('td', null, $report->timeframe),
+ Html::tag('td', null, date('Y-m-d H:i', $report->ctime / 1000)),
+ Html::tag('td', null, date('Y-m-d H:i', $report->mtime / 1000)),
+ Html::tag('td', ['class' => 'icon-col'], [
+ new Link(
+ new Icon('edit'),
+ Url::fromPath('reporting/report/edit', ['id' => $report->id])
+ )
+ ])
+ ]);
+ }
+
+ if (! empty($tableRows)) {
+ $table = Html::tag(
+ 'table',
+ ['class' => 'common-table table-row-selectable', 'data-base-target' => '_next'],
+ [
+ Html::tag(
+ 'thead',
+ null,
+ Html::tag(
+ 'tr',
+ null,
+ [
+ Html::tag('th', null, 'Name'),
+ Html::tag('th', null, 'Author'),
+ Html::tag('th', null, 'Timeframe'),
+ Html::tag('th', null, 'Date Created'),
+ Html::tag('th', null, 'Date Modified'),
+ Html::tag('th')
+ ]
+ )
+ ),
+ Html::tag('tbody', null, $tableRows)
+ ]
+ );
+
+ $this->addContent($table);
+ } else {
+ $this->addContent(Html::tag('p', null, 'No reports created yet.'));
+ }
+ }
+
+ public function newAction()
+ {
+ $this->assertPermission('reporting/reports');
+ $this->addTitleTab($this->translate('New Report'));
+
+ $form = new ReportForm();
+ $form->handleRequest(ServerRequest::fromGlobals());
+
+ $this->redirectForm($form, 'reporting/reports');
+
+ $this->addContent($form);
+ }
+}
diff --git a/application/controllers/TemplateController.php b/application/controllers/TemplateController.php
new file mode 100644
index 0000000..bb37b3c
--- /dev/null
+++ b/application/controllers/TemplateController.php
@@ -0,0 +1,89 @@
+<?php
+// Icinga Reporting | (c) 2019 Icinga GmbH | GPLv2
+
+namespace Icinga\Module\Reporting\Controllers;
+
+use DateTime;
+use GuzzleHttp\Psr7\ServerRequest;
+use Icinga\Module\Reporting\Database;
+use Icinga\Module\Reporting\Web\Controller;
+use Icinga\Module\Reporting\Web\Forms\TemplateForm;
+use Icinga\Module\Reporting\Web\Widget\Template;
+use ipl\Sql\Select;
+
+class TemplateController extends Controller
+{
+ use Database;
+
+ public function indexAction()
+ {
+ $this->createTabs()->activate('preview');
+
+ $template = Template::fromDb($this->params->getRequired('id'));
+
+ if ($template === null) {
+ throw new \Exception('Template not found');
+ }
+
+ $template
+ ->setMacros([
+ 'date' => (new DateTime())->format('jS M, Y'),
+ 'time_frame' => 'Time Frame',
+ 'time_frame_absolute' => 'Time Frame (absolute)',
+ 'title' => 'Icinga Report Preview'
+ ])
+ ->setPreview(true);
+
+ $this->addContent($template);
+ }
+
+ public function editAction()
+ {
+ $this->assertPermission('reporting/templates');
+
+ $this->createTabs()->activate('edit');
+
+ $select = (new Select())
+ ->from('template')
+ ->columns(['id', 'settings'])
+ ->where(['id = ?' => $this->params->getRequired('id')]);
+
+ $template = $this->getDb()->select($select)->fetch();
+
+ if ($template === false) {
+ throw new \Exception('Template not found');
+ }
+
+ $template->settings = json_decode($template->settings, true);
+
+ $form = (new TemplateForm())
+ ->setTemplate($template);
+
+ $form->handleRequest(ServerRequest::fromGlobals());
+
+ $this->redirectForm($form, 'reporting/templates');
+
+ $this->addContent($form);
+ }
+
+ protected function createTabs()
+ {
+ $tabs = $this->getTabs();
+
+ if ($this->hasPermission('reporting/templates')) {
+ $tabs->add('edit', [
+ 'title' => $this->translate('Edit template'),
+ 'label' => $this->translate('Edit Template'),
+ 'url' => 'reporting/template/edit?id=' . $this->params->getRequired('id')
+ ]);
+ }
+
+ $tabs->add('preview', [
+ 'title' => $this->translate('Preview template'),
+ 'label' => $this->translate('Preview'),
+ 'url' => 'reporting/template?id=' . $this->params->getRequired('id')
+ ]);
+
+ return $tabs;
+ }
+}
diff --git a/application/controllers/TemplatesController.php b/application/controllers/TemplatesController.php
new file mode 100644
index 0000000..91a82b1
--- /dev/null
+++ b/application/controllers/TemplatesController.php
@@ -0,0 +1,106 @@
+<?php
+// Icinga Reporting | (c) 2019 Icinga GmbH | GPLv2
+
+namespace Icinga\Module\Reporting\Controllers;
+
+use GuzzleHttp\Psr7\ServerRequest;
+use Icinga\Module\Reporting\Database;
+use Icinga\Module\Reporting\Web\Controller;
+use Icinga\Module\Reporting\Web\Forms\TemplateForm;
+use Icinga\Module\Reporting\Web\ReportsTimeframesAndTemplatesTabs;
+use ipl\Html\Html;
+use ipl\Sql\Select;
+use ipl\Web\Url;
+use ipl\Web\Widget\ButtonLink;
+use ipl\Web\Widget\Link;
+
+class TemplatesController extends Controller
+{
+ use Database;
+ use ReportsTimeframesAndTemplatesTabs;
+
+ public function indexAction()
+ {
+ $this->createTabs()->activate('templates');
+
+ $canManage = $this->hasPermission('reporting/templates');
+
+ if ($canManage) {
+ $this->addControl(new ButtonLink(
+ $this->translate('New Template'),
+ Url::fromPath('reporting/templates/new'),
+ 'plus'
+ ));
+ }
+
+ $select = (new Select())
+ ->from('template')
+ ->columns(['id', 'name', 'author', 'ctime', 'mtime'])
+ ->orderBy('mtime', SORT_DESC);
+
+ foreach ($this->getDb()->select($select) as $template) {
+ if ($canManage) {
+ // Edit URL
+ $subjectUrl = Url::fromPath(
+ 'reporting/template/edit',
+ ['id' => $template->id]
+ );
+ } else {
+ // Preview URL
+ $subjectUrl = Url::fromPath(
+ 'reporting/template',
+ ['id' => $template->id]
+ );
+ }
+
+ $tableRows[] = Html::tag('tr', null, [
+ Html::tag('td', null, new Link($template->name, $subjectUrl)),
+ Html::tag('td', null, $template->author),
+ Html::tag('td', null, date('Y-m-d H:i', $template->ctime / 1000)),
+ Html::tag('td', null, date('Y-m-d H:i', $template->mtime / 1000))
+ ]);
+ }
+
+ if (! empty($tableRows)) {
+ $table = Html::tag(
+ 'table',
+ ['class' => 'common-table table-row-selectable', 'data-base-target' => '_next'],
+ [
+ Html::tag(
+ 'thead',
+ null,
+ Html::tag(
+ 'tr',
+ null,
+ [
+ Html::tag('th', null, 'Name'),
+ Html::tag('th', null, 'Author'),
+ Html::tag('th', null, 'Date Created'),
+ Html::tag('th', null, 'Date Modified')
+ ]
+ )
+ ),
+ Html::tag('tbody', null, $tableRows)
+ ]
+ );
+
+ $this->addContent($table);
+ } else {
+ $this->addContent(Html::tag('p', null, 'No templates created yet.'));
+ }
+ }
+
+ public function newAction()
+ {
+ $this->assertPermission('reporting/templates');
+ $this->addTitleTab('New Template');
+
+ $form = new TemplateForm();
+
+ $form->handleRequest(ServerRequest::fromGlobals());
+
+ $this->redirectForm($form, 'reporting/templates');
+
+ $this->addContent($form);
+ }
+}
diff --git a/application/controllers/TestController.php b/application/controllers/TestController.php
new file mode 100644
index 0000000..f666085
--- /dev/null
+++ b/application/controllers/TestController.php
@@ -0,0 +1,47 @@
+<?php
+// Icinga Reporting | (c) 2018 Icinga GmbH | GPLv2
+
+namespace Icinga\Module\Reporting\Controllers;
+
+use Icinga\Module\Reporting\Database;
+use Icinga\Module\Reporting\Timeframe;
+use Icinga\Module\Reporting\Web\Controller;
+use ipl\Html\Table;
+use ipl\Sql\Select;
+
+class TestController extends Controller
+{
+ use Database;
+
+ public function timeframesAction()
+ {
+ $select = (new Select())
+ ->from('timeframe')
+ ->columns('*');
+
+ $table = new Table();
+
+ $table->getAttributes()->add('class', 'common-table');
+
+ $table->getHeader()->add(Table::row(['Name', 'Title', 'Start', 'End'], null, 'th'));
+
+ foreach ($this->getDb()->select($select) as $row) {
+ $timeframe = (new Timeframe())
+ ->setName($row->name)
+ ->setTitle($row->title)
+ ->setStart($row->start)
+ ->setEnd($row->end);
+
+ $table->getBody()->add(Table::row([
+ $timeframe->getName(),
+ $timeframe->getTitle(),
+ $timeframe->getTimerange()->getStart()->format('Y-m-d H:i:s'),
+ $timeframe->getTimerange()->getEnd()->format('Y-m-d H:i:s')
+ ]));
+ }
+
+ $this->addTitleTab('Timeframes');
+
+ $this->addContent($table);
+ }
+}
diff --git a/application/controllers/TimeframeController.php b/application/controllers/TimeframeController.php
new file mode 100644
index 0000000..ca67b0b
--- /dev/null
+++ b/application/controllers/TimeframeController.php
@@ -0,0 +1,47 @@
+<?php
+// Icinga Reporting | (c) 2019 Icinga GmbH | GPLv2
+
+namespace Icinga\Module\Reporting\Controllers;
+
+use GuzzleHttp\Psr7\ServerRequest;
+use Icinga\Module\Reporting\Database;
+use Icinga\Module\Reporting\Timeframe;
+use Icinga\Module\Reporting\Web\Controller;
+use Icinga\Module\Reporting\Web\Forms\TimeframeForm;
+
+class TimeframeController extends Controller
+{
+ use Database;
+
+ /** @var Timeframe */
+ protected $timeframe;
+
+ public function init()
+ {
+ $this->timeframe = Timeframe::fromDb($this->params->getRequired('id'));
+ }
+
+ public function editAction()
+ {
+ $this->assertPermission('reporting/timeframes');
+ $this->addTitleTab($this->translate('Edit Time Frame'));
+
+ $values = [
+ 'name' => $this->timeframe->getName(),
+ 'start' => $this->timeframe->getStart(),
+ 'end' => $this->timeframe->getEnd()
+ ];
+
+
+ $form = (new TimeframeForm())
+ ->setId($this->timeframe->getId());
+
+ $form->populate($values);
+
+ $form->handleRequest(ServerRequest::fromGlobals());
+
+ $this->redirectForm($form, 'reporting/timeframes');
+
+ $this->addContent($form);
+ }
+}
diff --git a/application/controllers/TimeframesController.php b/application/controllers/TimeframesController.php
new file mode 100644
index 0000000..505d8d9
--- /dev/null
+++ b/application/controllers/TimeframesController.php
@@ -0,0 +1,103 @@
+<?php
+// Icinga Reporting | (c) 2019 Icinga GmbH | GPLv2
+
+namespace Icinga\Module\Reporting\Controllers;
+
+use GuzzleHttp\Psr7\ServerRequest;
+use Icinga\Module\Reporting\Database;
+use Icinga\Module\Reporting\Web\Controller;
+use Icinga\Module\Reporting\Web\Forms\TimeframeForm;
+use Icinga\Module\Reporting\Web\ReportsTimeframesAndTemplatesTabs;
+use ipl\Html\Html;
+use ipl\Sql\Select;
+use ipl\Web\Url;
+use ipl\Web\Widget\ButtonLink;
+use ipl\Web\Widget\Link;
+
+class TimeframesController extends Controller
+{
+ use Database;
+ use ReportsTimeframesAndTemplatesTabs;
+
+ public function indexAction()
+ {
+ $this->createTabs()->activate('timeframes');
+
+ $canManage = $this->hasPermission('reporting/timeframes');
+
+ if ($canManage) {
+ $this->addControl(new ButtonLink(
+ $this->translate('New Timeframe'),
+ Url::fromPath('reporting/timeframes/new'),
+ 'plus'
+ ));
+ }
+
+ $tableRows = [];
+
+ $select = (new Select())
+ ->from('timeframe t')
+ ->columns('*');
+
+ foreach ($this->getDb()->select($select) as $timeframe) {
+ $subject = $timeframe->name;
+
+ if ($canManage) {
+ $subject = new Link($timeframe->name, Url::fromPath(
+ 'reporting/timeframe/edit',
+ ['id' => $timeframe->id]
+ ));
+ }
+
+ $tableRows[] = Html::tag('tr', null, [
+ Html::tag('td', null, $subject),
+ Html::tag('td', null, $timeframe->start),
+ Html::tag('td', null, $timeframe->end),
+ Html::tag('td', null, date('Y-m-d H:i', $timeframe->ctime / 1000)),
+ Html::tag('td', null, date('Y-m-d H:i', $timeframe->mtime / 1000))
+ ]);
+ }
+
+ if (! empty($tableRows)) {
+ $table = Html::tag(
+ 'table',
+ ['class' => 'common-table table-row-selectable', 'data-base-target' => '_next'],
+ [
+ Html::tag(
+ 'thead',
+ null,
+ Html::tag(
+ 'tr',
+ null,
+ [
+ Html::tag('th', null, 'Name'),
+ Html::tag('th', null, 'Start'),
+ Html::tag('th', null, 'End'),
+ Html::tag('th', null, 'Date Created'),
+ Html::tag('th', null, 'Date Modified')
+ ]
+ )
+ ),
+ Html::tag('tbody', null, $tableRows)
+ ]
+ );
+
+ $this->addContent($table);
+ } else {
+ $this->addContent(Html::tag('p', null, 'No timeframes created yet.'));
+ }
+ }
+
+ public function newAction()
+ {
+ $this->assertPermission('reporting/timeframes');
+ $this->addTitleTab($this->translate('New Timeframe'));
+
+ $form = new TimeframeForm();
+ $form->handleRequest(ServerRequest::fromGlobals());
+
+ $this->redirectForm($form, 'reporting/timeframes');
+
+ $this->addContent($form);
+ }
+}
diff --git a/application/forms/ConfigureMailForm.php b/application/forms/ConfigureMailForm.php
new file mode 100644
index 0000000..c27c934
--- /dev/null
+++ b/application/forms/ConfigureMailForm.php
@@ -0,0 +1,23 @@
+<?php
+// Icinga Reporting | (c) 2019 Icinga GmbH | GPLv2
+
+namespace Icinga\Module\Reporting\Forms;
+
+use Icinga\Forms\ConfigForm;
+
+class ConfigureMailForm extends ConfigForm
+{
+ public function init()
+ {
+ $this->setName('reporting_mail');
+ $this->setSubmitLabel($this->translate('Save Changes'));
+ }
+
+ public function createElements(array $formData)
+ {
+ $this->addElement('text', 'mail_from', [
+ 'label' => $this->translate('From'),
+ 'placeholder' => 'reporting@icinga'
+ ]);
+ }
+}
diff --git a/application/forms/SelectBackendForm.php b/application/forms/SelectBackendForm.php
new file mode 100644
index 0000000..4ba9610
--- /dev/null
+++ b/application/forms/SelectBackendForm.php
@@ -0,0 +1,35 @@
+<?php
+// Icinga Reporting | (c) 2018 Icinga GmbH | GPLv2
+
+namespace Icinga\Module\Reporting\Forms;
+
+use Icinga\Data\ResourceFactory;
+use Icinga\Forms\ConfigForm;
+
+class SelectBackendForm extends ConfigForm
+{
+ public function init()
+ {
+ $this->setName('reporting_backend');
+ $this->setSubmitLabel($this->translate('Save Changes'));
+ }
+
+ public function createElements(array $formData)
+ {
+ $dbResources = ResourceFactory::getResourceConfigs('db')->keys();
+ $options = array_combine($dbResources, $dbResources);
+
+ $default = null;
+ if (isset($options['reporting'])) {
+ $default = 'reporting';
+ }
+
+ $this->addElement('select', 'backend_resource', [
+ 'label' => $this->translate('Database'),
+ 'description' => $this->translate('Database resource'),
+ 'multiOptions' => $options,
+ 'value' => $default,
+ 'required' => true
+ ]);
+ }
+}
diff --git a/application/views/scripts/config/backend.phtml b/application/views/scripts/config/backend.phtml
new file mode 100644
index 0000000..2574402
--- /dev/null
+++ b/application/views/scripts/config/backend.phtml
@@ -0,0 +1,6 @@
+<div class="controls">
+ <?= /** @var \Icinga\Web\Widget\Tabs $tabs */ $tabs ?>
+</div>
+<div class="content">
+ <?= /** @var \Icinga\Module\Reporting\Forms\SelectBackendForm $form */ $form ?>
+</div>
diff --git a/application/views/scripts/config/mail.phtml b/application/views/scripts/config/mail.phtml
new file mode 100644
index 0000000..d647a82
--- /dev/null
+++ b/application/views/scripts/config/mail.phtml
@@ -0,0 +1,6 @@
+<div class="controls">
+ <?= /** @var \Icinga\Web\Widget\Tabs $tabs */ $tabs ?>
+</div>
+<div class="content">
+ <?= /** @var \Icinga\Module\Reporting\Forms\ConfigureMailForm $form */ $form ?>
+</div>