Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 71 additions & 47 deletions application/controllers/AnnouncementsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,27 @@

namespace Icinga\Controllers;

use GuzzleHttp\Psr7\ServerRequest;
use Icinga\Exception\NotFoundError;
use Icinga\Forms\Announcement\AcknowledgeAnnouncementForm;
use Icinga\Forms\Announcement\AnnouncementForm;
use Icinga\Repository\RepositoryMode;
use Icinga\Web\Announcement\AnnouncementIniRepository;
use Icinga\Web\Controller;
use Icinga\Web\Url;

class AnnouncementsController extends Controller
use Icinga\Web\Notification;
use Icinga\Web\Session;
use ipl\Web\Compat\CompatController;
use ipl\Web\Url;
use ipl\Html\Contract\Form;
use Throwable;

class AnnouncementsController extends CompatController
{
public function init()
{
$this->view->title = $this->translate('Announcements');

parent::init();
}

/**
* List all announcements
*/
public function indexAction()
{
$this->getTabs()->add(
'announcements',
[
'active' => true,
'label' => $this->translate('Announcements'),
'title' => $this->translate('List All Announcements'),
'url' => Url::fromPath('announcements')
]
);
$this->addTitleTab($this->translate('Announcements'));

$announcements = (new AnnouncementIniRepository())
->select([
Expand All @@ -61,45 +52,91 @@ public function indexAction()
/**
* Create an announcement
*/
public function newAction()
public function newAction(): void
{
$this->assertPermission('application/announcements');

$form = $this->prepareForm()->add();
$form->handleRequest();
$this->renderForm($form, $this->translate('New Announcement'));
$this->addTitleTab($this->translate('New Announcement'));

$form = (new AnnouncementForm(new AnnouncementIniRepository(), RepositoryMode::Insert))
->setCsrfCounterMeasureId(Session::getSession()->getId())
->setRedirectUrl(Url::fromPath('announcements'))
->on(Form::ON_SUBMIT, function (AnnouncementForm $form): void {
Notification::success($this->translate('Announcement created'));
$this->redirectNow($form->getRedirectUrl());
})
->on(Form::ON_ERROR, function (Throwable $_, AnnouncementForm $_form): void {
Notification::error($this->translate('Failed to create announcement'));
})
->handleRequest(ServerRequest::fromGlobals());

$this->addContent($form);
}

/**
* Update an announcement
*/
public function updateAction()
public function updateAction(): void
{
$this->assertPermission('application/announcements');

$form = $this->prepareForm()->edit($this->params->getRequired('id'));
$this->addTitleTab($this->translate('Update Announcement'));

$form = (new AnnouncementForm(
new AnnouncementIniRepository(),
RepositoryMode::Update,
$this->params->getRequired('id')
))
->setCsrfCounterMeasureId(Session::getSession()->getId())
->setRedirectUrl(Url::fromPath('announcements'))
->on(Form::ON_SUBMIT, function (AnnouncementForm $form): void {
Notification::success($this->translate('Announcement updated'));
$this->redirectNow($form->getRedirectUrl());
})
->on(Form::ON_ERROR, function (Throwable $_, AnnouncementForm $_form): void {
Notification::error($this->translate('Failed to update announcement'));
});

try {
$form->handleRequest();
} catch (NotFoundError $_) {
$form->handleRequest(ServerRequest::fromGlobals());
} catch (NotFoundError) {
$this->httpNotFound($this->translate('Announcement not found'));
}
$this->renderForm($form, $this->translate('Update Announcement'));

$this->addContent($form);
}

/**
* Remove an announcement
*/
public function removeAction()
public function removeAction(): void
{
$this->assertPermission('application/announcements');

$form = $this->prepareForm()->remove($this->params->getRequired('id'));
$this->addTitleTab($this->translate('Remove Announcement'));

$form = (new AnnouncementForm(
new AnnouncementIniRepository(),
RepositoryMode::Delete,
$this->params->getRequired('id')
))
->setCsrfCounterMeasureId(Session::getSession()->getId())
->setRedirectUrl(Url::fromPath('announcements'))
->on(Form::ON_SUBMIT, function (AnnouncementForm $form): void {
Notification::success($this->translate('Announcement removed'));
$this->redirectNow($form->getRedirectUrl());
})
->on(Form::ON_ERROR, function (Throwable $_, AnnouncementForm $_form): void {
Notification::error($this->translate('Failed to remove announcement'));
});

try {
$form->handleRequest();
} catch (NotFoundError $_) {
$form->handleRequest(ServerRequest::fromGlobals());
} catch (NotFoundError) {
$this->httpNotFound($this->translate('Announcement not found'));
}
$this->renderForm($form, $this->translate('Remove Announcement'));

$this->addContent($form);
}

public function acknowledgeAction()
Expand All @@ -109,17 +146,4 @@ public function acknowledgeAction()
$form = new AcknowledgeAnnouncementForm();
$form->handleRequest();
}

/**
* Assert permission admin and return a prepared RepositoryForm
*
* @return AnnouncementForm
*/
protected function prepareForm()
{
$form = new AnnouncementForm();
return $form
->setRepository(new AnnouncementIniRepository())
->setRedirectUrl(Url::fromPath('announcements'));
}
}
156 changes: 70 additions & 86 deletions application/forms/Announcement/AnnouncementForm.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,42 @@
namespace Icinga\Forms\Announcement;

use DateTime;
use Icinga\Application\Icinga;
use Icinga\Authentication\Auth;
use Icinga\Data\Filter\Filter;
use Icinga\Forms\RepositoryForm;
use Icinga\Repository\Repository;
use Icinga\Repository\RepositoryMode;
use Icinga\Web\Form\RepositoryForm;

/**
* Create, update and delete announcements
*/
class AnnouncementForm extends RepositoryForm
{
protected function fetchEntry()
/**
* Create a new AnnouncementForm
*
* @param Repository $repository The repository to work with
* @param RepositoryMode $mode How to interact with the repository
* @param ?string $identifier The id of the announcement to handle
*/
public function __construct(Repository $repository, RepositoryMode $mode, ?string $identifier = null)
{
parent::__construct($repository, $mode, $identifier);
$this->setAttribute('name', 'repo_form_announcement');
}

/**
* Fetch and transform the stored announcement into form-ready values
*
* In addition to fetching the raw entry, converts the stored `start` and
* `end` Unix timestamps into {@see DateTime} objects, as expected by the
* respective `localDateTime` elements.
*
* @return object|false The transformed announcement, or false if no
* matching entry exists
*/
protected function fetchEntry(): object|false
{
$entry = parent::fetchEntry();
if ($entry !== false) {
Expand All @@ -30,108 +56,66 @@ protected function fetchEntry()
return $entry;
}

/**
* {@inheritDoc}
*/
protected function createInsertElements(array $formData)
protected function assembleCommonElements(): void
{
$this->addElement(
'text',
'author',
[
'disabled' => ! $this->getRequest()->isApiRequest(),
'required' => true,
'value' => Auth::getInstance()->getUser()->getUsername()
]
);
$this->addElement(
'textarea',
'message',
[
'description' => $this->translate('The message to display to users'),
'label' => $this->translate('Message'),
'required' => true
]
);
$this->addElement(
'dateTimePicker',
'start',
[
'description' => $this->translate('The time to display the announcement from'),
'label' => $this->translate('Start'),
'placeholder' => new DateTime('tomorrow'),
'required' => true
]
);
$this->addElement(
'dateTimePicker',
'end',
[
'description' => $this->translate('The time to display the announcement until'),
'label' => $this->translate('End'),
'placeholder' => new DateTime('tomorrow +1day'),
'required' => true
]
);
$this->addElement('text', 'author', [
'disabled' => ! Icinga::app()->getRequest()->isApiRequest(),
'required' => true,
'value' => Auth::getInstance()->getUser()->getUsername(),
]);

$this->setTitle($this->translate('Create a new announcement'));
$this->setSubmitLabel($this->translate('Create'));
}
/**
* {@inheritDoc}
*/
protected function createUpdateElements(array $formData)
{
$this->createInsertElements($formData);
$this->setTitle(sprintf($this->translate('Edit announcement %s'), $this->getIdentifier()));
$this->setSubmitLabel($this->translate('Save'));
$this->addElement('textarea', 'message', [
'description' => $this->translate('The message to display to users'),
'label' => $this->translate('Message'),
'required' => true,
]);

$this->addElement('localDateTime', 'start', [
'description' => $this->translate('The time to display the announcement from'),
'label' => $this->translate('Start'),
'value' => (new DateTime('tomorrow')),
'required' => true,
]);

$this->addElement('localDateTime', 'end', [
'description' => $this->translate('The time to display the announcement until'),
'label' => $this->translate('End'),
'value' => (new DateTime('tomorrow +1day')),
'required' => true,
]);
}

/**
* {@inheritDoc}
*/
protected function createDeleteElements(array $formData)
protected function assembleInsertElements(): void
{
$this->setTitle(sprintf($this->translate('Remove announcement %s?'), $this->getIdentifier()));
$this->setSubmitLabel($this->translate('Confirm Removal'));
$this->setAttrib('class', 'icinga-controls');
$this->assembleCommonElements();
$this->addElement('submit', 'submit_add', ['label' => $this->translate('Create')]);
}

/**
* {@inheritDoc}
*/
protected function createFilter()
protected function assembleUpdateElements(): void
{
return Filter::where('id', $this->getIdentifier());
$this->assembleCommonElements();
$this->addElement('submit', 'submit_update', ['label' => $this->translate('Save')]);
}

/**
* {@inheritDoc}
*/
protected function getInsertMessage($success)
protected function assembleDeleteElements(): void
{
return $success
? $this->translate('Announcement created')
: $this->translate('Failed to create announcement');
$this->addElement('submit', 'submit_remove', ['label' => $this->translate('Confirm Removal')]);
}

/**
* {@inheritDoc}
*/
protected function getUpdateMessage($success)
protected function createFilter(): Filter
{
return $success
? $this->translate('Announcement updated')
: $this->translate('Failed to update announcement');
return Filter::where('id', $this->getIdentifier());
}

/**
* {@inheritDoc}
* Get the id of the announcement to handle
*
* @return ?string Narrower than the inherited contract, as this form
* accepts string identifiers only. Null only in
* {@see RepositoryMode::Insert} mode, where none is required.
*/
protected function getDeleteMessage($success)
public function getIdentifier(): ?string
{
return $success
? $this->translate('Announcement removed')
: $this->translate('Failed to remove announcement');
return $this->identifier;
}
}
Loading
Loading