Added support for disallowed bbcodes
authorAlexander Ebert <ebert@woltlab.com>
Wed, 20 Jul 2016 11:01:03 +0000 (13:01 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Wed, 20 Jul 2016 11:04:48 +0000 (13:04 +0200)
24 files changed:
com.woltlab.wcf/templates/wysiwygToolbar.tpl
wcfsetup/install/files/acp/templates/bbcodeList.tpl
wcfsetup/install/files/lib/data/bbcode/BBCode.class.php
wcfsetup/install/files/lib/data/bbcode/BBCodeAction.class.php
wcfsetup/install/files/lib/form/MessageForm.class.php
wcfsetup/install/files/lib/form/SignatureEditForm.class.php
wcfsetup/install/files/lib/system/bbcode/BBCodeHandler.class.php
wcfsetup/install/files/lib/system/bbcode/BBCodeParser.class.php
wcfsetup/install/files/lib/system/cache/builder/BBCodeCacheBuilder.class.php
wcfsetup/install/files/lib/system/html/input/HtmlInputProcessor.class.php
wcfsetup/install/files/lib/system/html/input/node/HtmlInputNodeImg.class.php
wcfsetup/install/files/lib/system/html/input/node/HtmlInputNodeProcessor.class.php
wcfsetup/install/files/lib/system/html/input/node/HtmlInputNodeTextParser.class.php
wcfsetup/install/files/lib/system/html/input/node/HtmlInputNodeWoltlabMention.class.php
wcfsetup/install/files/lib/system/html/input/node/HtmlInputNodeWoltlabMetacode.class.php
wcfsetup/install/files/lib/system/html/input/node/HtmlInputNodeWoltlabMetacodeMarker.class.php
wcfsetup/install/files/lib/system/html/node/AbstractHtmlNodeProcessor.class.php
wcfsetup/install/files/lib/system/html/node/IHtmlNode.class.php
wcfsetup/install/files/lib/system/html/output/node/AbstractHtmlOutputNode.class.php
wcfsetup/install/files/lib/system/message/QuickReplyManager.class.php
wcfsetup/install/files/lib/system/option/user/group/BBCodeSelectUserGroupOptionType.class.php
wcfsetup/install/lang/de.xml
wcfsetup/install/lang/en.xml
wcfsetup/setup/db/install.sql

index d0f180fcbe51ec04214ad843bf7415e4e590588a..706de872178deb65ce764eb97c53b57407e6098b 100644 (file)
@@ -53,9 +53,7 @@ buttons.push('alignment');
 {if $__wcf->getBBCodeHandler()->isAvailableBBCode('img')}
        buttons.push('woltlabImage');
 {/if}
-{if $__wcf->getBBCodeHandler()->isAvailableBBCode('table')}
-       buttons.push('table');
-{/if}
+buttons.push('table');
 
 buttons.push('wcfSeparator');
 
index b47145f7f4a2d1a7ccc1c19922d6f6f03539556c..61e44a54fd3e412abb7fb2416b293a1bc0de774d 100644 (file)
@@ -4,7 +4,6 @@
        //<![CDATA[
        $(function() {
                new WCF.Action.Delete('wcf\\data\\bbcode\\BBCodeAction', '.jsBBCodeRow');
-               new WCF.Action.Toggle('wcf\\data\\bbcode\\BBCodeAction', $('.jsBBCodeRow'));
        });
        //]]>
 </script>
@@ -46,7 +45,6 @@
                                {foreach from=$objects item=bbcode}
                                        <tr class="jsBBCodeRow">
                                                <td class="columnIcon">
-                                                       <span class="icon icon16 fa-{if !$bbcode->isDisabled}check-{/if}square-o jsToggleButton jsTooltip pointer" title="{lang}wcf.global.button.{if $bbcode->isDisabled}enable{else}disable{/if}{/lang}" data-object-id="{@$bbcode->bbcodeID}"></span>
                                                        <a href="{link controller='BBCodeEdit' object=$bbcode}{/link}" title="{lang}wcf.global.button.edit{/lang}" class="jsTooltip"><span class="icon icon16 fa-pencil"></span></a>
                                                        {if $bbcode->canDelete()}
                                                                <span class="icon icon16 fa-times jsDeleteButton jsTooltip pointer" title="{lang}wcf.global.button.delete{/lang}" data-object-id="{@$bbcode->bbcodeID}" data-confirm-message-html="{lang __encode=true}wcf.acp.bbcode.delete.sure{/lang}"></span>
index 85b4662c3d6577c32f5a94ecf4a8909a07aebaf8..0b42924d494b51697d5e558202fa971fcd6b5c0f 100644 (file)
@@ -24,11 +24,16 @@ use wcf\system\WCF;
  * @property-read      string          $wysiwygIcon
  * @property-read      string          $buttonLabel
  * @property-read      integer         $isSourceCode
- * @property-read      integer         $isDisabled
  * @property-read      integer         $showButton
  * @property-read      integer         $originIsSystem
  */
 class BBCode extends ProcessibleDatabaseObject implements IRouteController {
+       /**
+        * list of attributes
+        * @var BBCodeAttribute[]
+        */
+       protected $attributes;
+       
        /**
         * @inheritDoc
         */
@@ -51,12 +56,21 @@ class BBCode extends ProcessibleDatabaseObject implements IRouteController {
         */
        public function getAttributes() {
                if ($this->attributes === null) {
-                       $this->data['attributes'] = BBCodeCache::getInstance()->getBBCodeAttributes($this->bbcodeTag);
+                       $this->attributes = BBCodeCache::getInstance()->getBBCodeAttributes($this->bbcodeTag);
                }
                
                return $this->attributes;
        }
        
+       /**
+        * Sets the attributes of this bbcode.
+        * 
+        * @param       BBCodeAttribute[]       $attributes     list of attributes
+        */
+       public function setAttributes(array $attributes) {
+               $this->attributes = $attributes;
+       }
+       
        /**
         * @inheritDoc
         */
index c4f893d1653718b48d768c215bd01ba0b209cfab..6fd9f98c97e56ee269985b94039425c258de857b 100644 (file)
@@ -3,7 +3,6 @@ namespace wcf\data\bbcode;
 use wcf\data\user\group\UserGroup;
 use wcf\data\user\group\UserGroupEditor;
 use wcf\data\AbstractDatabaseObjectAction;
-use wcf\data\IToggleAction;
 use wcf\system\database\util\PreparedStatementConditionBuilder;
 use wcf\system\exception\PermissionDeniedException;
 use wcf\system\WCF;
@@ -19,7 +18,7 @@ use wcf\system\WCF;
  * @method     BBCodeEditor[]  getObjects()
  * @method     BBCodeEditor    getSingleObject()
  */
-class BBCodeAction extends AbstractDatabaseObjectAction implements IToggleAction {
+class BBCodeAction extends AbstractDatabaseObjectAction {
        /**
         * @inheritDoc
         */
@@ -38,7 +37,7 @@ class BBCodeAction extends AbstractDatabaseObjectAction implements IToggleAction
        /**
         * @inheritDoc
         */
-       protected $requireACP = ['delete', 'toggle', 'update'];
+       protected $requireACP = ['delete', 'update'];
        
        /**
         * @inheritDoc
@@ -110,22 +109,4 @@ class BBCodeAction extends AbstractDatabaseObjectAction implements IToggleAction
                        }
                }
        }
-       
-       /**
-        * @inheritDoc
-        */
-       public function validateToggle() {
-               parent::validateUpdate();
-       }
-       
-       /**
-        * @inheritDoc
-        */
-       public function toggle() {
-               foreach ($this->getObjects() as $bbcode) {
-                       $bbcode->update([
-                               'isDisabled' => $bbcode->isDisabled ? 0 : 1
-                       ]);
-               }
-       }
 }
index b79e89eb5d187bc2d058c105b01654cd5ad14e4e..4e7082229b1e9252a8f84d3b890dc62535b29a3e 100644 (file)
@@ -26,12 +26,6 @@ use wcf\util\StringUtil;
  * @package    WoltLabSuite\Core\Form
  */
 abstract class MessageForm extends AbstractCaptchaForm {
-       /**
-        * name of the permission which contains the allowed BBCodes
-        * @var string
-        */
-       public $allowedBBCodesPermission = 'user.message.allowedBBCodes';
-       
        /**
         * attachment handler
         * @var AttachmentHandler
@@ -68,6 +62,12 @@ abstract class MessageForm extends AbstractCaptchaForm {
         */
        public $defaultSmilies = [];
        
+       /**
+        * name of the permission which contains the disallowed BBCodes
+        * @var string
+        */
+       public $disallowedBBCodesPermission = 'user.message.disallowedBBCodes';
+       
        /**
         * enables multilingualism
         * @var boolean
@@ -213,28 +213,28 @@ abstract class MessageForm extends AbstractCaptchaForm {
                        throw new UserInputException('text');
                }
                
-               // check text length
-               if ($this->maxTextLength != 0 && mb_strlen($this->text) > $this->maxTextLength) {
-                       throw new UserInputException('text', 'tooLong');
+               if ($this->disallowedBBCodesPermission) {
+                       BBCodeHandler::getInstance()->setDisallowedBBCodes(explode(',', WCF::getSession()->getPermission($this->disallowedBBCodesPermission)));
                }
                
                $this->htmlInputProcessor = new HtmlInputProcessor();
                $this->htmlInputProcessor->process($this->text, $this->messageObjectType, 0);
                
-               // TODO: add checks for disallowed bbcodes and stuff
-               $this->htmlInputProcessor->validate();
+               // check text length
+               $message = $this->htmlInputProcessor->getTextContent();
+               if ($this->maxTextLength != 0 && mb_strlen($message) > $this->maxTextLength) {
+                       throw new UserInputException('text', 'tooLong');
+               }
                
-               /*if ($this->enableBBCodes && $this->allowedBBCodesPermission) {
-                       $disallowedBBCodes = BBCodeParser::getInstance()->validateBBCodes($this->text, ArrayUtil::trim(explode(',', WCF::getSession()->getPermission($this->allowedBBCodesPermission))));
-                       if (!empty($disallowedBBCodes)) {
-                               WCF::getTPL()->assign('disallowedBBCodes', $disallowedBBCodes);
-                               throw new UserInputException('text', 'disallowedBBCodes');
-                       }
-               }*/
+               $disallowedBBCodes = $this->htmlInputProcessor->validate();
+               if (!empty($disallowedBBCodes)) {
+                       WCF::getTPL()->assign('disallowedBBCodes', $disallowedBBCodes);
+                       throw new UserInputException('text', 'disallowedBBCodes');
+               }
                
                // search for censored words
                if (ENABLE_CENSORSHIP) {
-                       $result = Censorship::getInstance()->test($this->text);
+                       $result = Censorship::getInstance()->test($message);
                        if ($result) {
                                WCF::getTPL()->assign('censoredWords', $result);
                                throw new UserInputException('text', 'censoredWordsFound');
@@ -309,8 +309,8 @@ abstract class MessageForm extends AbstractCaptchaForm {
                        }
                }
                
-               if ($this->allowedBBCodesPermission) {
-                       BBCodeHandler::getInstance()->setAllowedBBCodes(explode(',', WCF::getSession()->getPermission($this->allowedBBCodesPermission)));
+               if ($this->disallowedBBCodesPermission) {
+                       BBCodeHandler::getInstance()->setDisallowedBBCodes(explode(',', WCF::getSession()->getPermission($this->disallowedBBCodesPermission)));
                }
        }
        
@@ -334,9 +334,5 @@ abstract class MessageForm extends AbstractCaptchaForm {
                        'text' => $this->text,
                        'tmpHash' => $this->tmpHash
                ]);
-               
-               if ($this->allowedBBCodesPermission) {
-                       WCF::getTPL()->assign('allowedBBCodes', explode(',', ArrayUtil::trim(WCF::getSession()->getPermission($this->allowedBBCodesPermission))));
-               }
        }
 }
index ece637f04fedaa040eb17b64c695ae81cb007574..b4ec37f299ed05a2f7d14393ab0c4b70510735f5 100644 (file)
@@ -16,6 +16,11 @@ use wcf\system\WCF;
  * @package    WoltLabSuite\Core\Form
  */
 class SignatureEditForm extends MessageForm {
+       /**
+        * @inheritDoc
+        */
+       public $disallowedBBCodesPermission = 'user.signature.disallowedBBCodes';
+       
        /**
         * @inheritDoc
         */
@@ -29,7 +34,7 @@ class SignatureEditForm extends MessageForm {
        /**
         * @inheritDoc
         */
-       public $templateName = 'signatureEdit';
+       public $showSignatureSetting = false;
        
        /**
         * parsed signature cache
@@ -38,15 +43,9 @@ class SignatureEditForm extends MessageForm {
        public $signatureCache;
        
        /**
-        * TODO: this is still missing
         * @inheritDoc
         */
-       public $allowedBBCodesPermission = 'user.signature.allowedBBCodes';
-       
-       /**
-        * @inheritDoc
-        */
-       public $showSignatureSetting = false;
+       public $templateName = 'signatureEdit';
        
        /**
         * @inheritDoc
index 2dcf58cbd9d3cd363360ebd041183808a855f2c6..80fdb7ac5f7d062c53021df6291fbdfd02ea3c17 100644 (file)
@@ -14,16 +14,16 @@ use wcf\system\SingletonFactory;
  */
 class BBCodeHandler extends SingletonFactory {
        /**
-        * list of BBCodes allowed for usage
+        * list of BBCodes displayed as buttons
         * @var BBCode[]
         */
-       protected $allowedBBCodes = [];
+       protected $buttonBBCodes = [];
        
        /**
-        * list of BBCodes displayed as buttons
+        * list of BBCodes disallowed for usage
         * @var BBCode[]
         */
-       protected $buttonBBCodes = [];
+       protected $disallowedBBCodes = [];
        
        /**
         * list of BBCodes which contain raw code (disabled BBCode parsing)
@@ -49,22 +49,7 @@ class BBCodeHandler extends SingletonFactory {
         * @return      boolean
         */
        public function isAvailableBBCode($bbCodeTag) {
-               // TODO
-               return true;
-               
-               $bbCode = BBCodeCache::getInstance()->getBBCodeByTag($bbCodeTag);
-               if ($bbCode === null || $bbCode->isDisabled) {
-                       return false;
-               }
-               
-               if (in_array('all', $this->allowedBBCodes)) {
-                       return true;
-               }
-               else if (in_array('none', $this->allowedBBCodes)) {
-                       return false;
-               }
-               
-               return in_array($bbCodeTag, $this->allowedBBCodes);
+               return !in_array($bbCodeTag, $this->disallowedBBCodes);
        }
        
        /**
@@ -98,13 +83,21 @@ class BBCodeHandler extends SingletonFactory {
                return $buttons;
        }
        
+       /**
+        * @param string[] $bbcodes
+        * @deprecated 3.0 - please use setDisallowedBBCodes() instead
+        */
+       public function setAllowedBBCodes(array $bbcodes) {
+               throw new \RuntimeException("setAllowedBBCodes() is no longer supported, please use setDisallowedBBCodes() instead.");
+       }
+       
        /**
         * Sets the allowed BBCodes.
         * 
         * @param       string[]        $bbCodes
         */
-       public function setAllowedBBCodes(array $bbCodes) {
-               $this->allowedBBCodes = $bbCodes;
+       public function setDisallowedBBCodes(array $bbCodes) {
+               $this->disallowedBBCodes = $bbCodes;
        }
        
        /**
index 9b8e5084069aac271f6c53d44510523f65dc7dde..0bc513e92ea37480c5b257504ea99b21cb8b15e4 100644 (file)
@@ -523,25 +523,10 @@ class BBCodeParser extends SingletonFactory {
         * @param       string                  $text
         * @param       string[]                $allowedBBCodes
         * @return      string[]
+        * @deprecated  3.0 - please use HtmlInputProcessor::validate() instead
         */
        public function validateBBCodes($text, array $allowedBBCodes) {
-               // if all BBCodes are allowed, return directly
-               if (in_array('all', $allowedBBCodes)) {
-                       return [];
-               }
-               
-               $this->setText($text);
-               $this->buildTagArray(false);
-               $this->buildXMLStructure();
-               
-               $usedDisallowedBBCodes = [];
-               foreach ($this->tagArray as $tag) {
-                       if (!in_array($tag['name'], $allowedBBCodes) && !isset($usedDisallowedBBCodes[$tag['name']])) {
-                               $usedDisallowedBBCodes[$tag['name']] = $tag['name'];
-                       }
-               }
-               
-               return $usedDisallowedBBCodes;
+               throw new \RuntimeException("validateBBCodes() is no longer supported, please use HtmlInputProcessor::validate() instead.");
        }
        
        /**
index f2c2fa74b6aa1587bc95575ed7e68ddab054f342..bd49634e480c7b2031de7b9b8250764fb243ff00 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 namespace wcf\system\cache\builder;
 use wcf\data\bbcode\attribute\BBCodeAttribute;
-use wcf\data\bbcode\BBCode;
+use wcf\data\bbcode\BBCodeList;
 use wcf\system\WCF;
 
 /**
@@ -25,7 +25,6 @@ class BBCodeCacheBuilder extends AbstractCacheBuilder {
                        FROM            wcf".WCF_N."_bbcode_attribute attribute
                        LEFT JOIN       wcf".WCF_N."_bbcode bbcode
                        ON              (bbcode.bbcodeID = attribute.bbcodeID)
-                       WHERE           bbcode.isDisabled = 0
                        ORDER BY        attribute.attributeNo";
                $statement = WCF::getDB()->prepareStatement($sql);
                $statement->execute();
@@ -36,14 +35,14 @@ class BBCodeCacheBuilder extends AbstractCacheBuilder {
                }
                
                // get bbcodes
-               $sql = "SELECT  *
-                       FROM    wcf".WCF_N."_bbcode
-                       WHERE   isDisabled = 0";
-               $statement = WCF::getDB()->prepareStatement($sql);
-               $statement->execute();
-               while ($row = $statement->fetchArray()) {
-                       $row['attributes'] = (isset($attributes[$row['bbcodeTag']]) ? $attributes[$row['bbcodeTag']] : []);
-                       $data['bbcodes'][$row['bbcodeTag']] = new BBCode(null, $row);
+               $bbcodeList = new BBCodeList();
+               $bbcodeList->readObjects();
+               foreach ($bbcodeList as $bbcode) {
+                       if (isset($attributes[$bbcode->bbcodeTag])) {
+                               $bbcode->setAttributes($attributes[$bbcode->bbcodeTag]);
+                       }
+                       
+                       $data['bbcodes'][$bbcode->bbcodeTag] = $bbcode;
                }
                
                // get code highlighters
index ee0cbc2eb76924dedc9a2ec45a8771032bfa0f5b..686d9a81f1755ab796926282de9b0ac3eb4a0d58 100644 (file)
@@ -5,6 +5,7 @@ use wcf\system\html\input\filter\IHtmlInputFilter;
 use wcf\system\html\input\filter\MessageHtmlInputFilter;
 use wcf\system\html\input\node\HtmlInputNodeProcessor;
 use wcf\system\html\AbstractHtmlProcessor;
+use wcf\system\WCF;
 use wcf\util\StringUtil;
 
 /**
@@ -82,8 +83,13 @@ class HtmlInputProcessor extends AbstractHtmlProcessor {
                $this->embeddedContent = $this->getHtmlInputNodeProcessor()->getEmbeddedContent();
        }
        
+       /**
+        * Checks the input html for disallowed bbcodes and returns any matches.
+        * 
+        * @return      string[]        list of matched disallowed bbcodes
+        */
        public function validate() {
-               // TODO
+               return $this->getHtmlInputNodeProcessor()->validate();
        }
        
        /**
@@ -95,6 +101,15 @@ class HtmlInputProcessor extends AbstractHtmlProcessor {
                return $this->getHtmlInputNodeProcessor()->getHtml();
        }
        
+       /**
+        * Returns the raw text content of current document.
+        * 
+        * @return      string          raw text content
+        */
+       public function getTextContent() {
+               return $this->getHtmlInputNodeProcessor()->getTextContent();
+       }
+       
        /**
         * Returns the all embedded content data.
         *
index f3c3de97832467982fa646e3d365f904579cec8a..c534df2415e102cfd9d22972303fb700cc042f3c 100644 (file)
@@ -1,5 +1,6 @@
 <?php
 namespace wcf\system\html\input\node;
+use wcf\system\bbcode\BBCodeHandler;
 use wcf\system\html\node\AbstractHtmlNodeProcessor;
 use wcf\util\DOMUtil;
 use wcf\util\JSON;
@@ -19,6 +20,13 @@ class HtmlInputNodeImg extends AbstractHtmlInputNode {
         */
        protected $tagName = 'img';
        
+       /**
+        * @inheritDoc
+        */
+       public function isAllowed(AbstractHtmlNodeProcessor $nodeProcessor) {
+               return (BBCodeHandler::getInstance()->isAvailableBBCode('img')) ? [] : ['img'];
+       }
+       
        /**
         * @inheritDoc
         */
index 90bc8478fc633e77c21f009a216bdffcc27a554e..ad13cd6b4c8be4ab2b18f821709b83d983901081 100644 (file)
@@ -1,7 +1,10 @@
 <?php
 namespace wcf\system\html\input\node;
+use wcf\system\bbcode\BBCodeHandler;
 use wcf\system\event\EventHandler;
 use wcf\system\html\node\AbstractHtmlNodeProcessor;
+use wcf\system\html\node\IHtmlNode;
+use wcf\util\StringUtil;
 
 /**
  * Processes HTML nodes and handles bbcodes.
@@ -50,6 +53,51 @@ class HtmlInputNodeProcessor extends AbstractHtmlNodeProcessor {
                EventHandler::getInstance()->fireAction($this, 'afterProcess');
        }
        
+       /**
+        * Checks the input html for disallowed bbcodes and returns any matches.
+        * 
+        * @return      string[]        list of matched disallowed bbcodes
+        */
+       public function validate() {
+               $result = [];
+               
+               $this->invokeNodeHandlers('wcf\system\html\input\node\HtmlInputNode', [], function(IHtmlNode $nodeHandler) use (&$result) {
+                       $disallowed = $nodeHandler->isAllowed($this);
+                       if ($disallowed) {
+                               $result[] = array_merge($result, $disallowed);
+                       }
+               });
+               
+               // handle custom nodes that have no dedicated handler
+               $customTags = [
+                       'color' => 'woltlab-color',
+                       'font' => 'woltlab-size',
+                       'size' => 'woltlab-size',
+                       'spoiler' => 'woltlab-spoiler'
+               ];
+               
+               foreach ($customTags as $bbcode => $tagName) {
+                       if (BBCodeHandler::getInstance()->isAvailableBBCode($bbcode)) {
+                               continue;
+                       }
+                       
+                       if ($this->getDocument()->getElementsByTagName($tagName)->length) {
+                               $result[] = $bbcode;
+                       }
+               }
+               
+               return $result;
+       }
+       
+       /**
+        * Returns the raw text content of current document.
+        * 
+        * @return      string          raw text content
+        */
+       public function getTextContent() {
+               return StringUtil::trim($this->getDocument()->getElementsByTagName('body')->item(0)->textContent);
+       }
+       
        /**
         * Processes embedded content.
         */
index 818fc04f4ad942f531555f06833a031ac64af553..0dd50488ade8e3376d837bcde0e487ac75a90940 100644 (file)
@@ -3,6 +3,7 @@ namespace wcf\system\html\input\node;
 use wcf\data\bbcode\media\provider\BBCodeMediaProvider;
 use wcf\data\smiley\Smiley;
 use wcf\data\smiley\SmileyCache;
+use wcf\system\bbcode\BBCodeHandler;
 use wcf\system\bbcode\HtmlBBCodeParser;
 use wcf\system\database\util\PreparedStatementConditionBuilder;
 use wcf\system\WCF;
@@ -146,6 +147,10 @@ class HtmlInputNodeTextParser {
                        $users = $this->lookupUsernames($usernames);
                }
                
+               $allowEmail = BBCodeHandler::getInstance()->isAvailableBBCode('email');
+               $allowMedia = BBCodeHandler::getInstance()->isAvailableBBCode('media');
+               $allowURL = BBCodeHandler::getInstance()->isAvailableBBCode('url');
+               
                for ($i = 0, $length = count($nodes); $i < $length; $i++) {
                        /** @var \DOMText $node */
                        $node = $nodes[$i];
@@ -155,7 +160,13 @@ class HtmlInputNodeTextParser {
                                $value = $this->parseMention($node, $value, $users);
                        }
                        
-                       $value = $this->parseURL($node, $value);
+                       if ($allowURL || $allowMedia) {
+                               $value = $this->parseURL($node, $value, $allowURL, $allowMedia);
+                       }
+                       
+                       if ($allowEmail) {
+                               $value = $this->parseEmail($node, $value);
+                       }
                        
                        $value = $this->parseSmiley($node, $value);
                        
@@ -304,9 +315,11 @@ class HtmlInputNodeTextParser {
         * 
         * @param       \DOMText        $text           text node
         * @param       string          $value          node value
+        * @param       boolean         $allowURL       url bbcode is allowed
+        * @param       boolean         $allowMedia     media bbcode is allowed
         * @return      string          modified node value with replacement placeholders
         */
-       protected function parseURL(\DOMText $text, $value) {
+       protected function parseURL(\DOMText $text, $value, $allowURL, $allowMedia) {
                static $urlPattern = '';
                if ($urlPattern === '') {
                        $urlPattern = '~
@@ -329,16 +342,26 @@ class HtmlInputNodeTextParser {
                        )?~ix';
                }
                
-               return preg_replace_callback($urlPattern, function($matches) use ($text) {
+               return preg_replace_callback($urlPattern, function($matches) use ($text, $allowURL, $allowMedia) {
                        $link = $matches[0];
                        
                        if (BBCodeMediaProvider::isMediaURL($link)) {
-                               $element = $this->htmlInputNodeProcessor->createMetacodeElement($text, 'media', [$link]);
+                               if ($allowMedia) {
+                                       $element = $this->htmlInputNodeProcessor->createMetacodeElement($text, 'media', [$link]);
+                               }
+                               else {
+                                       return $matches[0];
+                               }
                        }
                        else {
-                               $element = $text->ownerDocument->createElement('a');
-                               $element->setAttribute('href', $link);
-                               $element->textContent = $link;
+                               if ($allowURL) {
+                                       $element = $text->ownerDocument->createElement('a');
+                                       $element->setAttribute('href', $link);
+                                       $element->textContent = $link;
+                               }
+                               else {
+                                       return $matches[0];
+                               }
                        }
                        
                        return $this->addReplacement($text, $element);
@@ -353,7 +376,7 @@ class HtmlInputNodeTextParser {
         * @return      string          modified node value with replacement placeholders
         */
        protected function parseEmail(\DOMText $text, $value) {
-               if (mb_strpos($this->text, '@') === false) {
+               if (mb_strpos($value, '@') === false) {
                        return $value;
                }
                
index 3f520f9a7fad366eebfc4483691d3acdd712d396..91e37d82c2870a7ace5c78f84376d099bd81fa7a 100644 (file)
@@ -17,6 +17,14 @@ class HtmlInputNodeWoltlabMention extends AbstractHtmlInputNode {
         */
        protected $tagName = 'woltlab-mention';
        
+       /**
+        * @inheritDoc
+        */
+       public function isAllowed(AbstractHtmlNodeProcessor $htmlNodeProcessor) {
+               // mentions are always allowed
+               return [];
+       }
+       
        /**
         * @inheritDoc
         */
index 9311e2c91f4fdcadc362711d1c21a8b92df189ad..d0874ddc4afdb8940912dda11a153fd7da3c484a 100644 (file)
@@ -1,5 +1,6 @@
 <?php
 namespace wcf\system\html\input\node;
+use wcf\system\bbcode\BBCodeHandler;
 use wcf\system\html\metacode\converter\IMetacodeConverter;
 use wcf\system\html\node\AbstractHtmlNodeProcessor;
 use wcf\util\DOMUtil;
@@ -32,6 +33,28 @@ class HtmlInputNodeWoltlabMetacode extends AbstractHtmlInputNode {
         */
        protected $tagName = 'woltlab-metacode';
        
+       /**
+        * @inheritDoc
+        */
+       public function isAllowed(AbstractHtmlNodeProcessor $htmlNodeProcessor) {
+               $bbcodes = [];
+               /** @var \DOMElement $element */
+               foreach ($htmlNodeProcessor->getDocument()->getElementsByTagName($this->tagName) as $element) {
+                       $bbcodes[] = $element->getAttribute('data-name');
+               }
+               
+               $disallowedBBCodes = [];
+               foreach ($bbcodes as $bbcode) {
+                       if (BBCodeHandler::getInstance()->isAvailableBBCode($bbcode)) {
+                               continue;
+                       }
+                       
+                       $disallowedBBCodes[] = $bbcode;
+               }
+               
+               return $disallowedBBCodes;
+       }
+       
        /**
         * @inheritDoc
         */
index d8577a335ccfb82e4e029a1d1f640021bf144052..0028740a49570f179a5a9484369dc22c125ae724 100644 (file)
@@ -40,6 +40,14 @@ class HtmlInputNodeWoltlabMetacodeMarker extends AbstractHtmlInputNode {
                $this->sourceElements = HtmlBBCodeParser::getInstance()->getSourceBBCodes();
        }
        
+       /**
+        * @inheritDoc
+        */
+       public function isAllowed(AbstractHtmlNodeProcessor $htmlNodeProcessor) {
+               // metacode-marker isn't present at time of validation
+               return [];
+       }
+       
        /**
         * @inheritDoc
         */
index fa254f03debf13d87bcaa44b3e77ab5181a4973f..57a7f1466da086b56f86c31d2299dd55e0424d51 100644 (file)
@@ -242,8 +242,9 @@ abstract class AbstractHtmlNodeProcessor implements IHtmlNodeProcessor {
         * 
         * @param       string          $classNamePattern       full namespace pattern for class guessing
         * @param       string[]        $skipTags               list of tag names that should be ignored
+        * @param       callable        $callback               optional callback
         */
-       protected function invokeNodeHandlers($classNamePattern, array $skipTags = []) {
+       protected function invokeNodeHandlers($classNamePattern, array $skipTags = [], callable $callback = null) {
                $skipTags = array_merge($skipTags, ['html', 'head', 'title', 'meta', 'body', 'link']);
                
                $tags = [];
@@ -263,7 +264,12 @@ abstract class AbstractHtmlNodeProcessor implements IHtmlNodeProcessor {
                        }, $tagName);
                        $className = $classNamePattern . ucfirst($tagName);
                        if (class_exists($className)) {
-                               $this->invokeHtmlNode(new $className);
+                               if ($callback === null) {
+                                       $this->invokeHtmlNode(new $className);
+                               }
+                               else {
+                                       $callback(new $className);
+                               }
                        }
                }
        }
index 2f71694cf1902880d3c0de4d1fa15023d2fc65ef..a19289e12bb73e4ee4b61d48a55de9647e6a6330 100644 (file)
@@ -18,10 +18,18 @@ interface IHtmlNode {
         */
        public function getTagName();
        
+       /**
+        * Checks for disallowed bbcodes, must return the offending bbcode on match.
+        * 
+        * @param       AbstractHtmlNodeProcessor       $htmlNodeProcessor      node processor instance
+        * @return      string[]                        disallowed bbcodes on match or empty array
+        */
+       public function isAllowed(AbstractHtmlNodeProcessor $htmlNodeProcessor);
+       
        /**
         * Processes the provided elements and marks them for replacement if applicable.
         * 
-        * @param       \DOMElement[]           $elements               static list of matched elements, does not change when removing elements
+        * @param       \DOMElement[]                   $elements               static list of matched elements, does not change when removing elements
         * @param       AbstractHtmlNodeProcessor       $htmlNodeProcessor      node processor instance
         */
        public function process(array $elements, AbstractHtmlNodeProcessor $htmlNodeProcessor);
index fd5898ba393a9d8cb6e4c0afad97728fb3c703f2..9841fb0dd72dc6297cce488d46b58305e5ef5adc 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 namespace wcf\system\html\output\node;
 use wcf\system\html\node\AbstractHtmlNode;
+use wcf\system\html\node\AbstractHtmlNodeProcessor;
 
 /**
  * Default implementation for html output nodes.
@@ -18,6 +19,14 @@ abstract class AbstractHtmlOutputNode extends AbstractHtmlNode implements IHtmlO
         */
        protected $outputType = 'text/html';
        
+       /**
+        * @inheritDoc
+        */
+       public function isAllowed(AbstractHtmlNodeProcessor $htmlNodeProcessor) {
+               // there is no validation for output nodes
+               return [];
+       }
+       
        /**
         * @inheritDoc
         */
index 76b7a36bedc4d7abbcb9f6bfd6e1a267cf7a265b..59c98fbae46d319985e47bf6661c50435da1f6e5 100644 (file)
@@ -6,6 +6,7 @@ use wcf\data\IDatabaseObjectAction;
 use wcf\data\IMessage;
 use wcf\data\IMessageQuickReplyAction;
 use wcf\data\IVisitableObjectAction;
+use wcf\system\bbcode\BBCodeHandler;
 use wcf\system\bbcode\PreParser;
 use wcf\system\event\EventHandler;
 use wcf\system\exception\ParentClassException;
@@ -26,12 +27,6 @@ use wcf\util\StringUtil;
  * @package    WoltLabSuite\Core\System\Message
  */
 class QuickReplyManager extends SingletonFactory {
-       /**
-        * list of allowed bbcodes
-        * @var string[]
-        */
-       public $allowedBBodes = null;
-       
        /**
         * container object
         * @var \wcf\data\DatabaseObject
@@ -90,12 +85,12 @@ class QuickReplyManager extends SingletonFactory {
        }
        
        /**
-        * Sets the allowed bbcodes.
+        * Sets the disallowed bbcodes.
         * 
-        * @param       string[]                $allowedBBCodes
+        * @param       string[]                $disallowedBBCodes
         */
-       public function setAllowedBBCodes(array $allowedBBCodes = null) {
-               $this->allowedBBodes = $allowedBBCodes;
+       public function setDisallowedBBCodes(array $disallowedBBCodes) {
+               BBCodeHandler::getInstance()->setDisallowedBBCodes($disallowedBBCodes);
        }
        
        /**
index d54885176a3f0d7ec773d9ced39a39a9b59274f9..284d83cc5a427a2b92cfce1587cfd73e831ac344 100644 (file)
@@ -20,7 +20,13 @@ class BBCodeSelectUserGroupOptionType extends AbstractOptionType implements IUse
         * available BBCodes
         * @var string[]
         */
-       protected $bbCodes = null;
+       protected $bbCodes;
+       
+       /**
+        * list of bbcode tags that are always available
+        * @var string[]
+        */
+       protected static $alwaysAvailable = ['align', 'attach', 'b', 'code', 'i', 'list', 'quote', 's', 'sub', 'sup', 'table', 'td', 'tr', 'tt', 'u', 'wsm', 'wsmg', 'wsp'];
        
        /**
         * @inheritDoc
@@ -41,17 +47,10 @@ class BBCodeSelectUserGroupOptionType extends AbstractOptionType implements IUse
                        $this->loadBBCodeSelection();
                }
                
-               if ($value == 'all') {
-                       $selectedBBCodes = $this->bbCodes;
-               }
-               else {
-                       $selectedBBCodes = explode(',', $value);
-               }
-               
                WCF::getTPL()->assign([
                        'bbCodes' => $this->bbCodes,
                        'option' => $option,
-                       'selectedBBCodes' => $selectedBBCodes
+                       'selectedBBCodes' => explode(',', $value)
                ]);
                
                return WCF::getTPL()->fetch('bbCodeSelectOptionType');
@@ -64,6 +63,8 @@ class BBCodeSelectUserGroupOptionType extends AbstractOptionType implements IUse
         */
        protected function loadBBCodeSelection() {
                $this->bbCodes = array_keys(BBCodeCache::getInstance()->getBBCodes());
+               $this->bbCodes = array_diff($this->bbCodes, self::$alwaysAvailable);
+               
                asort($this->bbCodes);
        }
        
@@ -75,19 +76,14 @@ class BBCodeSelectUserGroupOptionType extends AbstractOptionType implements IUse
                        $this->loadBBCodeSelection();
                }
                
-               if ($defaultValue == 'all') {
-                       $defaultValue = $this->bbCodes;
-               }
-               else if (empty($defaultValue) || $defaultValue == 'none') {
+               if (empty($defaultValue)) {
                        $defaultValue = [];
                }
                else {
                        $defaultValue = explode(',', StringUtil::unifyNewlines($defaultValue));
                }
-               if ($groupValue == 'all') {
-                       $groupValue = $this->bbCodes;
-               }
-               else if (empty($groupValue) || $groupValue == 'none') {
+               
+               if (empty($groupValue)) {
                        $groupValue = [];
                }
                else {
@@ -123,6 +119,8 @@ class BBCodeSelectUserGroupOptionType extends AbstractOptionType implements IUse
         * @inheritDoc
         */
        public function compare($value1, $value2) {
+               // TODO: fix this
+               
                // handle special case where no allowed BBCodes have been set
                if (empty($value1)) {
                        if (empty($value2)) {
index 39f2f50d21c9c46b73676df19b3c6e51b70c329d..068938b7c673a9fa3a09e6c0f54681ee823e7349 100644 (file)
                <item name="wcf.acp.group.option.admin.content.smiley.canManageSmiley"><![CDATA[Kann Smileys verwalten]]></item>
                <item name="wcf.acp.group.option.user.comment.floodControlTime"><![CDATA[Mindestzeit zwischen zwei Kommentaren]]></item>
                <item name="wcf.acp.group.option.user.comment.floodControlTime.description"><![CDATA[Mindestzeit, die zwischen zwei hintereinander folgenden Kommentare oder Antworten vergehen muss. [Zeit in Sekunden, 0 für unbeschränkt]]]></item>
-               <item name="wcf.acp.group.option.user.message.canUseSmilies"><![CDATA[Kann Smileys benutzen]]></item>
-               <item name="wcf.acp.group.option.user.message.canUseHtml"><![CDATA[Kann HTML benutzen]]></item>
-               <item name="wcf.acp.group.option.user.message.canUseBBCodes"><![CDATA[Kann BBCodes benutzen]]></item>
-               <item name="wcf.acp.group.option.user.message.allowedBBCodes"><![CDATA[Erlaubte BBCodes]]></item>
-               <item name="wcf.acp.group.option.user.message.allowedBBCodes.description"><![CDATA[Die hier ausgewählten BBCodes dürfen von Mitgliedern dieser Benutzergruppe verwendet werden.]]></item>
+               <item name="wcf.acp.group.option.user.message.disallowedBBCodes"><![CDATA[Nicht erlaubte BBCodes]]></item>
+               <item name="wcf.acp.group.option.user.message.disallowedBBCodes.description"><![CDATA[Die hier ausgewählten BBCodes dürfen von Mitgliedern dieser Benutzergruppe <em>nicht</em> verwendet werden.]]></item>
                <item name="wcf.acp.group.option.admin.user.rank.canManageRank"><![CDATA[Kann Benutzerränge verwalten]]></item>
                <item name="wcf.acp.group.option.admin.user.canEditActivityPoints"><![CDATA[Kann Aktivitätspunkte bearbeiten]]></item>
                <item name="wcf.acp.group.option.admin.user.canViewInvisible"><![CDATA[Kann unsichtbare Benutzer sehen]]></item>
                <item name="wcf.acp.group.option.user.profile.canViewMembersList"><![CDATA[Kann Mitglieder-Liste sehen]]></item>
                <item name="wcf.acp.group.option.user.profile.canViewUserProfile"><![CDATA[Kann Benutzerprofile sehen]]></item>
                <item name="wcf.acp.group.option.user.profile.canViewUsersOnlineList"><![CDATA[Kann Benutzer-Online-Listen sehen]]></item>
-               <item name="wcf.acp.group.option.user.signature.canUseBBCodes"><![CDATA[Kann BBCodes in der Signatur verwenden]]></item>
-               <item name="wcf.acp.group.option.user.signature.canUseHtml"><![CDATA[Kann HTML in der Signatur verwenden]]></item>
-               <item name="wcf.acp.group.option.user.signature.canUseSmilies"><![CDATA[Kann Smileys in der Signatur verwenden]]></item>
-               <item name="wcf.acp.group.option.user.signature.allowedBBCodes"><![CDATA[Erlaubte BBCodes]]></item>
-               <item name="wcf.acp.group.option.user.signature.allowedBBCodes.description"><![CDATA[Die hier ausgewählten BBCodes dürfen von Mitgliedern dieser Benutzergruppe in ihrer Signatur verwendet werden.]]></item>
+               <item name="wcf.acp.group.option.user.signature.disallowedBBCodes"><![CDATA[Nicht erlaubte BBCodes]]></item>
+               <item name="wcf.acp.group.option.user.signature.disallowedBBCodes.description"><![CDATA[Die hier ausgewählten BBCodes dürfen von Mitgliedern dieser Benutzergruppe in ihrer Signatur <em>nicht</em> verwendet werden.]]></item>
                <item name="wcf.acp.group.priority"><![CDATA[Priorisierung]]></item>
                <item name="wcf.acp.group.priority.description"><![CDATA[Bestimmt u.a. die Reihenfolge auf der Team-Seite sowie die Auswahl von Benutzerrängen und „Wer ist online“-Darstellungen auf Basis der höchsten Priorität.]]></item>
                <item name="wcf.acp.group.userOnlineMarking"><![CDATA[„Benutzer online“-Darstellung]]></item>
index 682997bd66b5e4b2869558f70dc112965929b2c7..8d3446eefe0259f00e71386e11fa8977563a3633 100644 (file)
@@ -395,11 +395,8 @@ Examples for medium ID detection:
                <item name="wcf.acp.group.option.admin.content.smiley.canManageSmiley"><![CDATA[Can manage smilies]]></item>
                <item name="wcf.acp.group.option.user.comment.floodControlTime"><![CDATA[Delay for Comments]]></item>
                <item name="wcf.acp.group.option.user.comment.floodControlTime.description"><![CDATA[Seconds required between creating two comments or replies. Use 0 to disable.]]></item>
-               <item name="wcf.acp.group.option.user.message.canUseSmilies"><![CDATA[Can use smilies]]></item>
-               <item name="wcf.acp.group.option.user.message.canUseHtml"><![CDATA[Can use HTML]]></item>
-               <item name="wcf.acp.group.option.user.message.canUseBBCodes"><![CDATA[Can use BBCodes]]></item>
-               <item name="wcf.acp.group.option.user.message.allowedBBCodes"><![CDATA[Allowed BBCodes]]></item>
-               <item name="wcf.acp.group.option.user.message.allowedBBCodes.description"><![CDATA[All selected BBCodes can be used by the users of this user group.]]></item>
+               <item name="wcf.acp.group.option.user.message.disallowedBBCodes"><![CDATA[Disallowed BBCodes]]></item>
+               <item name="wcf.acp.group.option.user.message.disallowedBBCodes.description"><![CDATA[Selected BBCodes <em>cannot</em> be used by the users of this user group.]]></item>
                <item name="wcf.acp.group.option.admin.user.rank.canManageRank"><![CDATA[Can manage user ranks]]></item>
                <item name="wcf.acp.group.option.admin.user.canEditActivityPoints"><![CDATA[Can manage activity points]]></item>
                <item name="wcf.acp.group.option.admin.user.canViewInvisible"><![CDATA[Can see invisible users]]></item>
@@ -420,11 +417,8 @@ Examples for medium ID detection:
                <item name="wcf.acp.group.option.user.profile.canViewMembersList"><![CDATA[Can see members list]]></item>
                <item name="wcf.acp.group.option.user.profile.canViewUserProfile"><![CDATA[Can see user profiles]]></item>
                <item name="wcf.acp.group.option.user.profile.canViewUsersOnlineList"><![CDATA[Can see “Users Online” list]]></item>
-               <item name="wcf.acp.group.option.user.signature.canUseBBCodes"><![CDATA[Can use BBCodes in signature]]></item>
-               <item name="wcf.acp.group.option.user.signature.canUseHtml"><![CDATA[Can use HTML in signature]]></item>
-               <item name="wcf.acp.group.option.user.signature.canUseSmilies"><![CDATA[Can use smilies in signature]]></item>
-               <item name="wcf.acp.group.option.user.signature.allowedBBCodes"><![CDATA[Allowed BBCodes]]></item>
-               <item name="wcf.acp.group.option.user.signature.allowedBBCodes.description"><![CDATA[All selected BBCodes can be used in the signature.]]></item>
+               <item name="wcf.acp.group.option.user.signature.disallowedBBCodes"><![CDATA[Disallowed BBCodes]]></item>
+               <item name="wcf.acp.group.option.user.signature.disallowedBBCodes.description"><![CDATA[Selected BBCodes <em>cannot</em> be used in the signature.]]></item>
                <item name="wcf.acp.group.priority"><![CDATA[Priority]]></item>
                <item name="wcf.acp.group.priority.description"><![CDATA[Determines the display order on the team page, user rank, and “Users Online” marking based on highest priority.]]></item>
                <item name="wcf.acp.group.userOnlineMarking"><![CDATA[“Users Online” Marking]]></item>
index 772844eb003ede725ac67f20d1a3f215e1aa76fc..58ab336bd96234a97d1c2129b8a360407ae680d8 100644 (file)
@@ -240,7 +240,6 @@ CREATE TABLE wcf1_bbcode (
        buttonLabel VARCHAR(255) NOT NULL DEFAULT '',
        isBlockElement TINYINT(1) NOT NULL DEFAULT 0,
        isSourceCode TINYINT(1) NOT NULL DEFAULT 0,
-       isDisabled TINYINT(1) NOT NULL DEFAULT 0,
        showButton TINYINT(1) NOT NULL DEFAULT 0,
        originIsSystem TINYINT(1) NOT NULL DEFAULT 0,
        UNIQUE KEY bbcodeTag (bbcodeTag)