Commit 347f8bbd authored by Matthias Larisch's avatar Matthias Larisch

Forum fixes

parent 5d55c515
Pipeline #26100584 passed with stages
in 17 minutes and 2 seconds
......@@ -37,6 +37,7 @@
- fixes user autocomplete fetching for conversation creation
- fix profile sleeping hat variable #243
- fix bug in region dynatree loading #244 !444 @nicksellen
- Only show forum post removal button when the user is allowed to delete a post !456 @NerdyProjects
## Refactoring
- Extract StoreUser module javascript !358 @nicksellen
......@@ -59,6 +60,7 @@
- refactor Map module to webpack !435 @nicksellen
- all entrypoints load most JS/CSS via webpack now !432 @NerdyProjects
- Refactor forum logic to Gateway/Service/PermissionService !442 @NerdyProjects
- Refactor reactions to be more forum specific !456 @NerdyProjects
## Dev/Test/CI stuff
- Fix cache clearing during test/deploy !414 @nicksellen
......@@ -67,6 +69,7 @@
- Add ./scripts/dev for running webpack dev env !437 @nicksellen
- Improve linting config more (add vue linting) !441 @nicksellen
- Implement basic dev docs content, make shinier readme with contributors !443 @nicksellen
- Add tests for SanitizerService !456 @NerdyProjects
# 2018-05-24
......
CREATE TABLE `fs_reaction` (
`target` VARCHAR(63) NOT NULL,
CREATE TABLE `fs_post_reaction` (
`post_id` INT UNSIGNED NOT NULL,
`time` DATETIME NOT NULL,
`foodsaver_id` INT NOT NULL,
`key` VARCHAR(63),
INDEX (`target`),
UNIQUE KEY `target-foodsaver-key` (`target`, `foodsaver_id`, `key`)
INDEX (`post_id`),
UNIQUE KEY `post-foodsaver-key` (`post_id`, `foodsaver_id`, `key`)
)
ENGINE = InnoDB;
ALTER TABLE `fs_post_reaction`
ADD CONSTRAINT `fs_theme_post_idfk` FOREIGN KEY (`post_id`) REFERENCES `fs_theme_post` (`id`)
ON DELETE CASCADE
ON UPDATE CASCADE;
......@@ -23,6 +23,7 @@ dirs="\
data/visite \
cache \
cache/searchindex \
cache/htmlpurifier-cache \
tmp \
"
......
......@@ -6,7 +6,7 @@ use Foodsharing\Lib\Session;
use Foodsharing\Modules\Region\ForumGateway;
use Foodsharing\Permissions\ForumPermissions;
use Foodsharing\Services\ForumService;
use Foodsharing\Services\OutputSanitizerService;
use Foodsharing\Services\SanitizerService;
use FOS\RestBundle\Controller\Annotations as Rest;
use FOS\RestBundle\Controller\FOSRestController;
use FOS\RestBundle\Request\ParamFetcher;
......@@ -18,15 +18,15 @@ class ForumRestController extends FOSRestController
private $forumGateway;
private $forumPermissions;
private $forumService;
private $outputSanitizerService;
private $sanitizerService;
public function __construct(Session $session, ForumGateway $forumGateway, ForumPermissions $forumPermissions, ForumService $forumService, OutputSanitizerService $outputSanitizerService)
public function __construct(Session $session, ForumGateway $forumGateway, ForumPermissions $forumPermissions, ForumService $forumService, SanitizerService $sanitizerService)
{
$this->session = $session;
$this->forumGateway = $forumGateway;
$this->forumPermissions = $forumPermissions;
$this->forumService = $forumService;
$this->outputSanitizerService = $outputSanitizerService;
$this->sanitizerService = $sanitizerService;
}
private function normalizeThread($thread)
......@@ -48,7 +48,7 @@ class ForumRestController extends FOSRestController
];
if (isset($thread['post_time'])) {
$res['lastPost']['createdAt'] = $thread['post_time'];
$res['lastPost']['body'] = $this->outputSanitizerService->sanitizeForHtml($thread['post_body']);
$res['lastPost']['body'] = $this->sanitizerService->markdownToHtml($thread['post_body']);
$res['lastPost']['author'] = [
'id' => $thread['foodsaver_id'],
'name' => $thread['foodsaver_name'],
......@@ -68,11 +68,11 @@ class ForumRestController extends FOSRestController
return $res;
}
private function normalizePost($post, $reactions)
private function normalizePost($post)
{
return [
'id' => $post['id'],
'body' => $this->outputSanitizerService->sanitizeForHtml($post['body']),
'body' => $this->sanitizerService->markdownToHtml($post['body']),
'createdAt' => $post['time'],
'author' => [
'id' => $post['author_id'],
......@@ -80,7 +80,7 @@ class ForumRestController extends FOSRestController
'avatar' => '/images/130_q_' . $post['author_photo'],
'sleepStatus' => $post['author_sleep_status']
],
'reactions' => $reactions[$post['id']] ?? new \ArrayObject(),
'reactions' => $post['reactions'] ?: new \ArrayObject(),
'mayDelete' => $this->forumPermissions->mayDeletePost($post)
];
}
......@@ -118,12 +118,11 @@ class ForumRestController extends FOSRestController
$thread = $this->forumGateway->getThread($threadId);
$posts = $this->forumGateway->listPosts($threadId);
$reactions = $this->forumService->getReactionsForThread($threadId);
$thread = $this->normalizeThread($thread);
$thread['isFollowing'] = $this->forumGateway->isFollowing($this->session->id(), $threadId);
$thread['mayModerate'] = $this->forumPermissions->mayModerate($threadId);
$thread['posts'] = array_map(function ($post) use ($reactions) { return $this->normalizePost($post, $reactions); }, $posts);
$thread['posts'] = array_map(function ($post) { return $this->normalizePost($post); }, $posts);
$view = $this->view([
'data' => $thread
......@@ -224,7 +223,7 @@ class ForumRestController extends FOSRestController
{
$post = $this->forumGateway->getPost($postId);
if (!$this->forumPermissions->mayDeletePost($post)) {
return new HttpException(403);
throw new HttpException(403);
}
$this->forumGateway->deletePost($postId);
......@@ -238,9 +237,9 @@ class ForumRestController extends FOSRestController
{
$threadId = $this->forumGateway->getThreadForPost($postId);
if (!$this->forumPermissions->mayAccessThread($threadId)) {
return new HttpException(403);
throw new HttpException(403);
}
$this->forumService->addReaction($this->session->id(), $threadId, $postId, $emoji);
$this->forumService->addReaction($this->session->id(), $postId, $emoji);
return $this->handleView($this->view([]));
}
......@@ -251,7 +250,7 @@ class ForumRestController extends FOSRestController
public function deleteReactionAction($postId, $emoji)
{
$threadId = $this->forumGateway->getThreadForPost($postId);
$this->forumService->removeReaction($this->session->id(), $threadId, $postId, $emoji);
$this->forumService->removeReaction($this->session->id(), $postId, $emoji);
return $this->handleView($this->view([]));
}
......
......@@ -13,7 +13,7 @@ use Foodsharing\Lib\View\Utils;
use Foodsharing\Modules\Core\DBConstants\Region\Type;
use Foodsharing\Modules\EmailTemplateAdmin\EmailTemplateGateway;
use Foodsharing\Modules\Region\RegionGateway;
use Foodsharing\Services\OutputSanitizerService;
use Foodsharing\Services\SanitizerService;
use JSMin\JSMin;
class Func
......@@ -35,7 +35,7 @@ class Func
private $stylesheets;
private $add_css;
private $viewUtils;
private $outputSanitizerService;
private $sanitizerService;
private $webpackScripts;
private $webpackStylesheets;
......@@ -52,10 +52,10 @@ class Func
*/
private $session;
public function __construct(Utils $viewUtils, OutputSanitizerService $outputSanitizerService)
public function __construct(Utils $viewUtils, SanitizerService $sanitizerService)
{
$this->viewUtils = $viewUtils;
$this->outputSanitizerService = $outputSanitizerService;
$this->sanitizerService = $sanitizerService;
$this->content_main = '';
$this->content_right = '';
$this->content_left = '';
......@@ -643,12 +643,12 @@ Verantwortlich für den Inhalt nach § 55 Abs. 2 RStV:<br />
$message['subject'] = 'Foodsharing-Mail';
}
$mail->setSubject($this->outputSanitizerService->sanitizeForText($message['subject']));
$mail->setSubject($this->sanitizerService->htmlToPlain($message['subject']));
$htmlBody = $this->emailBodyTpl($message['body']);
$mail->setHTMLBody($htmlBody);
// playintext body
$plainBody = $this->outputSanitizerService->sanitizeForText($htmlBody);
$plainBody = $this->sanitizerService->htmlToPlain($htmlBody);
$mail->setBody($plainBody);
$mail->addRecipient($to);
......@@ -1348,7 +1348,7 @@ Verantwortlich für den Inhalt nach § 55 Abs. 2 RStV:<br />
$htmlBody = $this->emailBodyTpl($message, $email, $token);
$mail->setHTMLBody($htmlBody);
$plainBody = $this->outputSanitizerService->sanitizeForText($htmlBody);
$plainBody = $this->sanitizerService->htmlToPlain($htmlBody);
$mail->setBody($message);
if ($attach !== false) {
......
......@@ -4,20 +4,20 @@ namespace Foodsharing\Modules\Activity;
use Foodsharing\Modules\Core\Model;
use Foodsharing\Modules\Mailbox\MailboxModel;
use Foodsharing\Services\OutputSanitizerService;
use Foodsharing\Services\SanitizerService;
class ActivityModel extends Model
{
private $mailboxModel;
private $activityGateway;
private $outputSanitizerService;
private $sanitizerService;
public function __construct(MailboxModel $mailboxModel, ActivityGateway $activityGateway, OutputSanitizerService $outputSanitzierService)
public function __construct(MailboxModel $mailboxModel, ActivityGateway $activityGateway, SanitizerService $sanitizerService)
{
parent::__construct();
$this->mailboxModel = $mailboxModel;
$this->activityGateway = $activityGateway;
$this->outputSanitizerService = $outputSanitzierService;
$this->sanitizerService = $sanitizerService;
}
public function loadBasketWallUpdates($page = 0)
......@@ -68,10 +68,10 @@ class ActivityModel extends Model
private function textPrepare($txt): ?string
{
$txt = trim($txt);
$sanitized = $this->outputSanitizerService->sanitizeForHtml($txt);
$sanitized = $this->sanitizerService->markdownToHtml($txt);
if (strlen($txt) > 100) {
return '<span class="txt">' . $this->outputSanitizerService->sanitizeForHtml($this->func->tt($txt, 90)) . ' <a href="#" onclick="$(this).parent().hide().next().show();return false;">alles zeigen <i class="fa fa-angle-down"></i></a></span><span class="txt" style="display:none;">' . $sanitized . ' <a href="#" onclick="$(this).parent().hide().prev().show();return false;">weniger <i class="fa fa-angle-up"></i></a></span>';
return '<span class="txt">' . $this->sanitizerService->markdownToHtml($this->func->tt($txt, 90)) . ' <a href="#" onclick="$(this).parent().hide().next().show();return false;">alles zeigen <i class="fa fa-angle-down"></i></a></span><span class="txt" style="display:none;">' . $sanitized . ' <a href="#" onclick="$(this).parent().hide().prev().show();return false;">weniger <i class="fa fa-angle-up"></i></a></span>';
}
return '<span class="txt">' . $sanitized . '</span>';
......
......@@ -5,17 +5,17 @@ namespace Foodsharing\Modules\Mailbox;
use Foodsharing\Lib\Db\Mem;
use Foodsharing\Lib\Mail\AsyncMail;
use Foodsharing\Modules\Core\Control;
use Foodsharing\Services\OutputSanitizerService;
use Foodsharing\Services\SanitizerService;
class MailboxXhr extends Control
{
private $outputSanitizerService;
private $sanitizerService;
public function __construct(MailboxModel $model, MailboxView $view, OutputSanitizerService $outputSanitizerService)
public function __construct(MailboxModel $model, MailboxView $view, SanitizerService $sanitizerService)
{
$this->model = $model;
$this->view = $view;
$this->outputSanitizerService = $outputSanitizerService;
$this->sanitizerService = $sanitizerService;
parent::__construct();
......@@ -168,7 +168,7 @@ class MailboxXhr extends Control
$mail->setSubject($subject);
$html = nl2br($body);
$mail->setHTMLBody($html);
$plainBody = $this->outputSanitizerService->sanitizeForText($html);
$plainBody = $this->sanitizerService->htmlToPlain($html);
$mail->setBody($body);
$mail->send();
......@@ -409,7 +409,7 @@ class MailboxXhr extends Control
$html = nl2br($message);
$mail->setHTMLBody($html);
$plainBody = $this->outputSanitizerService->sanitizeForText($html);
$plainBody = $this->sanitizerService->htmlToPlain($html);
$mail->setBody($plainBody);
if ($attach !== false) {
......
<?php
namespace Foodsharing\Modules\Reaction;
use Foodsharing\Modules\Core\BaseGateway;
use Foodsharing\Modules\Core\Database;
class ReactionGateway extends BaseGateway
{
public function __construct(Database $db)
{
parent::__construct($db);
}
/**
* returns all reactions for a given target.
* if isPrefix is true, target is evaluated as a prefix search, e.g. to get reactions on all sub objects of an object
* when target is composed like module-obj-subobj.
*/
public function getReactions($target, $isPrefix = false)
{
$q = '
SELECT
r.target,
r.`key`,
r.time,
r.foodsaver_id,
fs.name as foodsaver_name
FROM
fs_reaction r
LEFT JOIN
fs_foodsaver fs
ON
fs.id = r.foodsaver_id';
if ($isPrefix) {
$q .= '
WHERE r.target LIKE :target';
$target .= '%';
} else {
$q .= '
WHERE r.target = :target';
}
$res = $this->db->fetchAll($q, [
'target' => $target
]);
return $res;
}
public function addReaction($target, $fsId, $key): bool
{
$this->db->insert(
'fs_reaction',
[
'target' => $target,
'foodsaver_id' => $fsId,
'key' => $key,
'time' => $this->db->now()
]
);
return true;
}
public function removeReaction($target, $fsId, $key)
{
$this->db->delete(
'fs_reaction',
[
'target' => $target,
'foodsaver_id' => $fsId,
'key' => $key
]
);
}
}
......@@ -262,14 +262,89 @@ class ForumGateway extends BaseGateway
ON b.id = ht.bezirk_id';
}
private function getReactionsForPosts($postIds)
{
/* This message is private because we currently trust the given postIds to exist as well as be not-harmful */
$postIdClause = implode(',', $postIds);
$reactions = $this->db->fetchAll('
SELECT
r.post_id,
r.`key`,
r.time,
r.foodsaver_id,
fs.name as foodsaver_name
FROM
fs_post_reaction r
LEFT JOIN
fs_foodsaver fs
ON
fs.id = r.foodsaver_id
WHERE r.post_id IN (' . $postIdClause . ')'
);
$out = [];
foreach ($postIds as $id) {
$out[$id] = [];
}
foreach ($reactions as $r) {
$user = [
'id' => $r['foodsaver_id'],
'name' => $r['foodsaver_name']
];
if (!isset($out[$r['post_id']][$r['key']])) {
$out[$r['post_id']][$r['key']] = [$user];
} else {
$out[$r['post_id']][$r['key']][] = $user;
}
}
return $out;
}
public function addReaction($postId, $fsId, $key): bool
{
$this->db->insert(
'fs_post_reaction',
[
'post_id' => $postId,
'foodsaver_id' => $fsId,
'key' => $key,
'time' => $this->db->now()
]
);
return true;
}
public function removeReaction($postId, $fsId, $key)
{
$this->db->delete(
'fs_post_reaction',
[
'post_id' => $postId,
'foodsaver_id' => $fsId,
'key' => $key
]
);
}
public function listPosts($threadId)
{
return $this->db->fetchAll(
$posts = $this->db->fetchAll(
$this->getPostSelect() . '
WHERE p.theme_id = :threadId
ORDER BY p.`time`
', ['threadId' => $threadId]);
$postIds = array_column($posts, 'id');
$reactions = $this->getReactionsForPosts($postIds);
$mergeReactions = function ($post) use ($reactions) {
$post['reactions'] = $reactions[$post['id']];
return $post;
};
return array_map($mergeReactions, $posts);
}
public function getPost($postId)
......
......@@ -58,8 +58,8 @@
:author="post.author"
:body="post.body"
:reactions="post.reactions"
:may-delete="true"
:may-edit="true"
:may-delete="post.mayDelete"
:may-edit="false"
:is-loading="loadingPosts.indexOf(post.id) != -1"
:created-at="new Date(post.createdAt)"
@delete="deletePost(post)"
......@@ -128,6 +128,7 @@ export default {
isSticky: true,
isActive: true,
mayModerate: false,
mayDelete: false,
isFollowing: true,
isLoading: false,
......@@ -155,6 +156,7 @@ export default {
isSticky: res.isSticky,
isActive: res.isActive,
mayModerate: res.mayModerate,
mayDelete: res.mayDelete,
isFollowing: res.isFollowing
})
this.isLoading = false
......
......@@ -6,19 +6,19 @@ use Foodsharing\Lib\Mail\AsyncMail;
use Foodsharing\Lib\Xhr\Xhr;
use Foodsharing\Modules\Core\Control;
use Foodsharing\Modules\Core\Model;
use Foodsharing\Services\OutputSanitizerService;
use Foodsharing\Services\SanitizerService;
class TeamXhr extends Control
{
private $gateway;
private $outputSanitizerService;
private $sanitizerService;
public function __construct(TeamGateway $gateway, Model $model, TeamView $view, OutputSanitizerService $outputSanitizerService)
public function __construct(TeamGateway $gateway, Model $model, TeamView $view, SanitizerService $sanitizerService)
{
$this->gateway = $gateway;
$this->model = $model;
$this->view = $view;
$this->outputSanitizerService = $outputSanitizerService;
$this->sanitizerService = $sanitizerService;
parent::__construct();
}
......@@ -48,7 +48,7 @@ class TeamXhr extends Control
$msg = 'Name: ' . $name . "\n\n" . $msg;
$mail->setBody($msg);
$mail->setHtmlBody($this->outputSanitizerService->sanitizeForHtmlNoMarkup($msg));
$mail->setHtmlBody($this->sanitizerService->plainToHtml($msg));
$mail->setSubject('foodsharing.de Kontaktformular Anfrage von ' . $name);
$mail->addRecipient($user['email']);
......
......@@ -8,14 +8,12 @@ use Foodsharing\Modules\Bell\BellGateway;
use Foodsharing\Modules\Core\Model;
use Foodsharing\Modules\EmailTemplateAdmin\EmailTemplateGateway;
use Foodsharing\Modules\Foodsaver\FoodsaverGateway;
use Foodsharing\Modules\Reaction\ReactionGateway;
use Foodsharing\Modules\Region\ForumGateway;
use Foodsharing\Modules\Region\RegionGateway;
class ForumService
{
private $forumGateway;
private $reactionGateway;
private $regionGateway;
private $foodsaverGateway;
private $bellGateway;
......@@ -24,7 +22,7 @@ class ForumService
private $model;
private $func;
private $session;
private $outputSanitizerService;
private $sanitizerService;
public function __construct(
BellGateway $bellGateway,
......@@ -35,8 +33,7 @@ class ForumService
Session $session,
Model $model,
RegionGateway $regionGateway,
ReactionGateway $reactionGateway,
OutputSanitizerService $outputSanitizerService
SanitizerService $sanitizerService
) {
$this->bellGateway = $bellGateway;
$this->emailTemplateGateway = $emailTemplateGateway;
......@@ -46,8 +43,7 @@ class ForumService
$this->session = $session;
$this->model = $model;
$this->regionGateway = $regionGateway;
$this->reactionGateway = $reactionGateway;
$this->outputSanitizerService = $outputSanitizerService;
$this->sanitizerService = $sanitizerService;
}
public function url($regionId, $ambassadorForum, $threadId = null, $postId = null)
......@@ -136,7 +132,7 @@ class ForumService
array_merge($data,
[
'anrede' => $this->func->genderWord($recipient['geschlecht'], 'Lieber', 'Liebe', 'Liebe/r'),
'name' => $this->outputSanitizerService->sanitizeForHtmlNoMarkup($recipient['name'])
'name' => $this->sanitizerService->plainToHtml($recipient['name'])
])
);
}
......@@ -149,9 +145,9 @@ class ForumService
$poster = $this->model->getVal('name', 'foodsaver', $this->session->id());
$data = [
'link' => BASE_URL . $this->url($info['region_id'], $info['ambassador_forum'], $threadId, $postId),
'theme' => $this->outputSanitizerService->sanitizeForHtmlNoMarkup($info['title']),
'post' => $this->outputSanitizerService->sanitizeForHtml($rawPostBody),
'poster' => $this->outputSanitizerService->sanitizeForHtmlNoMarkup($poster)
'theme' => $this->sanitizerService->plainToHtml($info['title']),
'post' => $this->sanitizerService->markdownToHtml($rawPostBody),
'poster' => $this->sanitizerService->plainToHtml($poster)
];
$this->notificationMail($follower, 19, $data);
}
......@@ -165,9 +161,9 @@ class ForumService
if ($foodsaver = $this->foodsaverGateway->getBotschafter($region['id'])) {
$data = [
'link' => BASE_URL . $this->url($region['id'], false, $threadId),
'thread' => $this->outputSanitizerService->sanitizeForHtmlNoMarkup($theme['name']),
'poster' => $this->outputSanitizerService->sanitizeForHtmlNoMarkup($poster),
'bezirk' => $this->outputSanitizerService->sanitizeForHtmlNoMarkup($region['name']),
'thread' => $this->sanitizerService->plainToHtml($theme['name']),
'poster' => $this->sanitizerService->plainToHtml($poster),
'bezirk' => $this->sanitizerService->plainToHtml($region['name']),
];
$this->notificationMail($foodsaver, 20, $data);
......@@ -188,65 +184,28 @@ class ForumService
}
$data = [
'bezirk' => $this->outputSanitizerService->sanitizeForHtmlNoMarkup($region['name']),
'poster' => $this->outputSanitizerService->sanitizeForHtmlNoMarkup($poster),
'thread' => $this->outputSanitizerService->sanitizeForHtmlNoMarkup($theme['name']),
'bezirk' => $this->sanitizerService->plainToHtml($region['name']),
'poster' => $this->sanitizerService->plainToHtml($poster),
'thread' => $this->sanitizerService->plainToHtml($theme['name']),
'link' => BASE_URL . $this->url($region['id'], $ambassadorForum, $threadId),
'post' => $this->outputSanitizerService->sanitizeForHtml($body),
'post' => $this->sanitizerService->markdownToHtml($body),
];
$this->notificationMail($foodsaver, $ambassadorForum ? 13 : 12, $data);
}
private function getReactionTarget($threadId, $postId = null)
public function addReaction($fsId, $postId, $key)
{
$target = 'forum-' . $threadId . '-';
if ($postId) {
$target .= $postId;
}
return $target;
}
public function addReaction($fsId, $threadId, $postId, $key)
{
if (!$fsId || !$threadId || !$postId || !$key) {
if (!$fsId || !$postId || !$key) {
throw new \InvalidArgumentException();
}
$this->reactionGateway->addReaction($this->getReactionTarget($threadId, $postId), $fsId, $key);
$this->forumGateway->addReaction($postId, $fsId, $key);
}
public function removeReaction($fsId, $threadId, $postId, $key)
public function removeReaction($fsId, $postId, $key)
{
if (!$fsId || !$threadId || !$postId || !$key) {
if (!$fsId || !$postId || !$key) {
throw new \InvalidArgumentException();
}
$this->reactionGateway->removeReaction($this->getReactionTarget($threadId, $postId), $fsId, $key);
}
public function getReactionsForThread($threadId)
{
$target = $this->getReactionTarget($threadId);
$res = $this->reactionGateway->getReactions($target, true);
$reactions = [];
foreach ($res as $r) {
$id = explode($target, $r['target']);
if (count($id) !== 2) {
continue;
} else {
$postId = $id[1];
}
if (!isset($reactions[$postId])) {
$reactions[$postId] = [];
}
if (!isset($reactions[$postId][$r['key']])) {
$reactions[$postId][$r['key']] = [];
}
$reactions[$postId][$r['key']][] = [
'id' => $r['foodsaver_id'],
'name' => $r['foodsaver_name']
];
}
return $reactions;
$this->forumGateway->removeReaction($postId, $fsId, $key);
}
}
......@@ -4,7 +4,7 @@ namespace Foodsharing\Services;
use Html2Text\Html2Text;
class OutputSanitizerService
class SanitizerService
{
private $parsedown;
private $htmlPurifier;
......@@ -15,23 +15,21 @@ class OutputSanitizerService
$this->htmlPurifier = $HTMLPurifier;
}
public function sanitizeForHtmlNoMarkup($text)
public function plainToHtml($text)
{
return nl2br(htmlspecialchars($text));
}
public function sanitizeForHtml($html, $containsMarkdown = true)
public function markdownToHtml($text)
{
if ($containsMarkdown) {
$html = $this->parsedown->text(strip_tags($html));
}
$html = $this->parsedown->text(strip_tags($text));
$purified = $this->htmlPurifier->purify($html);
return $purified;
}
public function sanitizeForText($html)
public function htmlToPlain($html)
{
$html = new Html2Text($html);
......
<?php
class SanitizerTest extends \Codeception\Test\Unit
{
/**
* @var \UnitTester
*/
protected $tester;
/**
* @var \Foodsharing\Services\SanitizerService