mirror of
https://github.com/Icinga/icingaweb2.git
synced 2025-07-30 01:04:09 +02:00
Merge pull request #3814 from Icinga/feature/make-notes-and-comments-markdown-aware-3684
Make notes, comments and announcements markdown aware
This commit is contained in:
commit
36524bcd94
@ -154,6 +154,27 @@ class FileCache
|
|||||||
return $this->basedir . '/' . $file;
|
return $this->basedir . '/' . $file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare a sub directory with the given name and return its path
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
*
|
||||||
|
* @return string|false Returns FALSE in case the cache is not enabled or an error occurred
|
||||||
|
*/
|
||||||
|
public function directory($name)
|
||||||
|
{
|
||||||
|
if (! $this->enabled) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$path = $this->filename($name);
|
||||||
|
if (! is_dir($path) && ! @mkdir($path, octdec('1750'), true)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $path;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the given ETag matches a cached file
|
* Whether the given ETag matches a cached file
|
||||||
*
|
*
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
namespace Icinga\Web\Helper;
|
namespace Icinga\Web\Helper;
|
||||||
|
|
||||||
use Closure;
|
use Closure;
|
||||||
|
use Icinga\Web\FileCache;
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
|
|
||||||
class HtmlPurifier
|
class HtmlPurifier
|
||||||
@ -29,11 +30,16 @@ class HtmlPurifier
|
|||||||
$purifierConfig = \HTMLPurifier_Config::createDefault();
|
$purifierConfig = \HTMLPurifier_Config::createDefault();
|
||||||
$purifierConfig->set('Core.EscapeNonASCIICharacters', true);
|
$purifierConfig->set('Core.EscapeNonASCIICharacters', true);
|
||||||
$purifierConfig->set('Attr.AllowedFrameTargets', array('_blank'));
|
$purifierConfig->set('Attr.AllowedFrameTargets', array('_blank'));
|
||||||
|
|
||||||
|
if (($cachePath = FileCache::instance()->directory('htmlpurifier.cache')) !== false) {
|
||||||
|
$purifierConfig->set('Cache.SerializerPath', $cachePath);
|
||||||
|
} else {
|
||||||
|
$purifierConfig->set('Cache.DefinitionImpl', null);
|
||||||
|
}
|
||||||
|
|
||||||
// This avoids permission problems:
|
// This avoids permission problems:
|
||||||
// $purifierConfig->set('Core.DefinitionCache', null);
|
// $purifierConfig->set('Core.DefinitionCache', null);
|
||||||
$purifierConfig->set('Cache.DefinitionImpl', null);
|
|
||||||
// TODO: Use a cache directory:
|
|
||||||
// $purifierConfig->set('Cache.SerializerPath', '/var/spool/whatever');
|
|
||||||
// $purifierConfig->set('URI.Base', 'http://www.example.com');
|
// $purifierConfig->set('URI.Base', 'http://www.example.com');
|
||||||
// $purifierConfig->set('URI.MakeAbsolute', true);
|
// $purifierConfig->set('URI.MakeAbsolute', true);
|
||||||
|
|
||||||
|
15
library/Icinga/Web/Helper/Markdown.php
Normal file
15
library/Icinga/Web/Helper/Markdown.php
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2019 Icinga GmbH | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Web\Helper;
|
||||||
|
|
||||||
|
use Parsedown;
|
||||||
|
|
||||||
|
class Markdown
|
||||||
|
{
|
||||||
|
public static function text($content)
|
||||||
|
{
|
||||||
|
require_once 'Parsedown/Parsedown.php';
|
||||||
|
return HtmlPurifier::process(Parsedown::instance()->text($content));
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@
|
|||||||
namespace Icinga\Web\View;
|
namespace Icinga\Web\View;
|
||||||
|
|
||||||
use Icinga\Util\StringHelper;
|
use Icinga\Util\StringHelper;
|
||||||
|
use Icinga\Web\Helper\Markdown;
|
||||||
|
|
||||||
$this->addHelperFunction('ellipsis', function ($string, $maxLength, $ellipsis = '...') {
|
$this->addHelperFunction('ellipsis', function ($string, $maxLength, $ellipsis = '...') {
|
||||||
return StringHelper::ellipsis($string, $maxLength, $ellipsis);
|
return StringHelper::ellipsis($string, $maxLength, $ellipsis);
|
||||||
@ -12,3 +13,7 @@ $this->addHelperFunction('ellipsis', function ($string, $maxLength, $ellipsis =
|
|||||||
$this->addHelperFunction('nl2br', function ($string) {
|
$this->addHelperFunction('nl2br', function ($string) {
|
||||||
return nl2br(str_replace(array('\r\n', '\r', '\n'), '<br>', $string), false);
|
return nl2br(str_replace(array('\r\n', '\r', '\n'), '<br>', $string), false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$this->addHelperFunction('markdown', function ($content) {
|
||||||
|
return Markdown::text($content);
|
||||||
|
});
|
||||||
|
@ -8,7 +8,7 @@ use Icinga\Data\Filter\Filter;
|
|||||||
use Icinga\Forms\Announcement\AcknowledgeAnnouncementForm;
|
use Icinga\Forms\Announcement\AcknowledgeAnnouncementForm;
|
||||||
use Icinga\Web\Announcement\AnnouncementCookie;
|
use Icinga\Web\Announcement\AnnouncementCookie;
|
||||||
use Icinga\Web\Announcement\AnnouncementIniRepository;
|
use Icinga\Web\Announcement\AnnouncementIniRepository;
|
||||||
use Icinga\Web\Helper\HtmlPurifier;
|
use Icinga\Web\Helper\Markdown;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render announcements
|
* Render announcements
|
||||||
@ -36,13 +36,12 @@ class Announcements extends AbstractWidget
|
|||||||
$announcements = $repo->findActive();
|
$announcements = $repo->findActive();
|
||||||
$announcements->applyFilter($acked);
|
$announcements->applyFilter($acked);
|
||||||
if ($announcements->hasResult()) {
|
if ($announcements->hasResult()) {
|
||||||
$purifier = new HtmlPurifier(array('HTML.Allowed' => 'b,a[href|target],i,*[class]'));
|
|
||||||
$html = '<ul role="alert" id="announcements">';
|
$html = '<ul role="alert" id="announcements">';
|
||||||
foreach ($announcements as $announcement) {
|
foreach ($announcements as $announcement) {
|
||||||
$ackForm = new AcknowledgeAnnouncementForm();
|
$ackForm = new AcknowledgeAnnouncementForm();
|
||||||
$ackForm->populate(array('hash' => $announcement->hash));
|
$ackForm->populate(array('hash' => $announcement->hash));
|
||||||
$html .= '<li><div>'
|
$html .= '<li><div>'
|
||||||
. $purifier->purify($announcement->message)
|
. Markdown::text($announcement->message)
|
||||||
. '</div>'
|
. '</div>'
|
||||||
. $ackForm
|
. $ackForm
|
||||||
. '</li>';
|
. '</li>';
|
||||||
|
@ -8,7 +8,7 @@ use Icinga\Application\Hook\ApplicationStateHook;
|
|||||||
use Icinga\Authentication\Auth;
|
use Icinga\Authentication\Auth;
|
||||||
use Icinga\Forms\AcknowledgeApplicationStateMessageForm;
|
use Icinga\Forms\AcknowledgeApplicationStateMessageForm;
|
||||||
use Icinga\Web\ApplicationStateCookie;
|
use Icinga\Web\ApplicationStateCookie;
|
||||||
use Icinga\Web\Helper\HtmlPurifier;
|
use Icinga\Web\Helper\Markdown;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render application state messages
|
* Render application state messages
|
||||||
@ -27,12 +27,6 @@ class ApplicationStateMessages extends AbstractWidget
|
|||||||
return $active;
|
return $active;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected function getPurifier()
|
|
||||||
{
|
|
||||||
return new HtmlPurifier(['HTML.Allowed' => 'b,a[href|target],i,*[class]']);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function render()
|
public function render()
|
||||||
{
|
{
|
||||||
$enabled = Auth::getInstance()
|
$enabled = Auth::getInstance()
|
||||||
@ -55,8 +49,6 @@ class ApplicationStateMessages extends AbstractWidget
|
|||||||
return '<div style="display: none;"></div>';
|
return '<div style="display: none;"></div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
$purifier = $this->getPurifier();
|
|
||||||
|
|
||||||
$html = '<div>';
|
$html = '<div>';
|
||||||
|
|
||||||
reset($active);
|
reset($active);
|
||||||
@ -69,7 +61,7 @@ class ApplicationStateMessages extends AbstractWidget
|
|||||||
$ackForm = new AcknowledgeApplicationStateMessageForm();
|
$ackForm = new AcknowledgeApplicationStateMessageForm();
|
||||||
$ackForm->populate(['id' => $id]);
|
$ackForm->populate(['id' => $id]);
|
||||||
|
|
||||||
$html .= $purifier->purify($message) . $ackForm;
|
$html .= Markdown::text($message) . $ackForm;
|
||||||
|
|
||||||
$html .= '</div>';
|
$html .= '</div>';
|
||||||
|
|
||||||
|
@ -136,7 +136,7 @@ class EventController extends Controller
|
|||||||
*/
|
*/
|
||||||
protected function comment($message)
|
protected function comment($message)
|
||||||
{
|
{
|
||||||
return $this->view->nl2br($this->view->createTicketLinks($this->view->escapeComment($message)));
|
return $this->view->nl2br($this->view->createTicketLinks($this->view->markdown($message)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -45,7 +45,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
<tr title="<?= $this->translate('A comment, as entered by the author, associated with the scheduled downtime'); ?>">
|
<tr title="<?= $this->translate('A comment, as entered by the author, associated with the scheduled downtime'); ?>">
|
||||||
<th><?= $this->translate('Comment') ?></th>
|
<th><?= $this->translate('Comment') ?></th>
|
||||||
<td class="comment-text"><?= $this->nl2br($this->escapeComment($this->downtime->comment)) ?></td>
|
<td class="comment-text"><?= $this->nl2br($this->markdown($this->downtime->comment)) ?></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
@ -66,5 +66,5 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="comment-text"<?php if (isset($textId)): ?> id="<?= $textId ?>"<?php endif ?>>
|
<p class="comment-text"<?php if (isset($textId)): ?> id="<?= $textId ?>"<?php endif ?>>
|
||||||
<?= $this->nl2br($this->escapeComment($comment->comment)) ?>
|
<?= $this->nl2br($this->markdown($comment->comment)) ?>
|
||||||
</p>
|
</p>
|
||||||
|
@ -82,6 +82,6 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="comment-text"<?php if (isset($textId)): ?> id="<?= $textId ?>"<?php endif ?>>
|
<p class="comment-text"<?php if (isset($textId)): ?> id="<?= $textId ?>"<?php endif ?>>
|
||||||
<?= $this->nl2br($this->escapeComment($downtime->comment)) ?>
|
<?= $this->nl2br($this->markdown($downtime->comment)) ?>
|
||||||
</p>
|
</p>
|
||||||
</td>
|
</td>
|
||||||
|
@ -182,7 +182,7 @@ $rowAction = Url::fromPath('monitoring/event/show');
|
|||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
<p class="overview-plugin-output"><?php if ($icon) {
|
<p class="overview-plugin-output"><?php if ($icon) {
|
||||||
echo $this->icon($icon, $iconTitle);
|
echo $this->icon($icon, $iconTitle);
|
||||||
} ?><?= $this->nl2br($this->createTicketLinks($this->escapeComment($msg)))
|
} ?><?= $this->nl2br($this->createTicketLinks($this->markdown($msg)))
|
||||||
// TODO(ak): this allows only a[href] in messages, but plugin output allows more
|
// TODO(ak): this allows only a[href] in messages, but plugin output allows more
|
||||||
?></p>
|
?></p>
|
||||||
</td>
|
</td>
|
||||||
|
@ -44,7 +44,7 @@ $acknowledgement = $object->acknowledgement;
|
|||||||
} ?>
|
} ?>
|
||||||
</dt>
|
</dt>
|
||||||
<dd>
|
<dd>
|
||||||
<?= $this->nl2br($this->createTicketLinks($this->escapeComment($acknowledgement->getComment()))) ?>
|
<?= $this->nl2br($this->createTicketLinks($this->markdown($acknowledgement->getComment()))) ?>
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<?php elseif (isset($removeAckForm)): ?>
|
<?php elseif (isset($removeAckForm)): ?>
|
||||||
|
@ -68,7 +68,7 @@ if (empty($object->comments) && ! $addLink) {
|
|||||||
} ?>
|
} ?>
|
||||||
</dt>
|
</dt>
|
||||||
<dd>
|
<dd>
|
||||||
<?= $this->nl2br($this->createTicketLinks($this->escapeComment($comment->comment))) ?>
|
<?= $this->nl2br($this->createTicketLinks($this->markdown($comment->comment))) ?>
|
||||||
</dd>
|
</dd>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
</dl>
|
</dl>
|
||||||
|
@ -108,7 +108,7 @@ if (empty($object->comments) && ! $addLink) {
|
|||||||
} ?>
|
} ?>
|
||||||
</dt>
|
</dt>
|
||||||
<dd>
|
<dd>
|
||||||
<?= $this->nl2br($this->createTicketLinks($this->escapeComment($downtime->comment))) ?>
|
<?= $this->nl2br($this->createTicketLinks($this->markdown($downtime->comment))) ?>
|
||||||
</dd>
|
</dd>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
</dl>
|
</dl>
|
||||||
|
@ -38,7 +38,7 @@ if (($navigation->isEmpty() || ! $navigation->hasRenderableItems()) && $notes ==
|
|||||||
<td>
|
<td>
|
||||||
<?= $navigation->getRenderer() ?>
|
<?= $navigation->getRenderer() ?>
|
||||||
<?php if ($notes !== ''): ?>
|
<?php if ($notes !== ''): ?>
|
||||||
<p><?= $this->nl2br($this->escape($notes)) ?></p>
|
<section class="notes"><?= $this->markdown($notes) ?></section>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
Loading…
x
Reference in New Issue
Block a user