1c3437056SNickeau<?php 2c3437056SNickeau 3c3437056SNickeaurequire_once(__DIR__ . '/../ComboStrap/PluginUtility.php'); 4c3437056SNickeau 5*04fd306cSNickeauuse ComboStrap\ExceptionBadSyntax; 686ec4045Sgerardnicouse ComboStrap\Identity; 7c3437056SNickeauuse ComboStrap\Index; 8c3437056SNickeauuse ComboStrap\LogUtility; 9*04fd306cSNickeauuse ComboStrap\LinkMarkup; 10c3437056SNickeauuse ComboStrap\Message; 11*04fd306cSNickeauuse ComboStrap\MarkupPath; 12c3437056SNickeauuse dokuwiki\Extension\ActionPlugin; 13c3437056SNickeau 14c3437056SNickeau 15c3437056SNickeau/** 16c3437056SNickeau * 17c3437056SNickeau * To show a message after redirection or rewriting 18c3437056SNickeau * 19c3437056SNickeau * 20c3437056SNickeau * 21c3437056SNickeau */ 22c3437056SNickeauclass action_plugin_combo_routermessage extends ActionPlugin 23c3437056SNickeau{ 24c3437056SNickeau 25c3437056SNickeau // a class can not start with a number then webcomponent is not a valid class name 26c3437056SNickeau const REDIRECT_MANAGER_BOX_CLASS = "redirect-manager"; 27c3437056SNickeau 28c3437056SNickeau // Property key 29c3437056SNickeau const ORIGIN_PAGE = 'redirectId'; 30c3437056SNickeau const ORIGIN_TYPE = 'redirectOrigin'; 31c3437056SNickeau const CONF_SHOW_PAGE_NAME_IS_NOT_UNIQUE = 'ShowPageNameIsNotUnique'; 3286ec4045Sgerardnico const CONF_SHOW_MESSAGE_CLASSIC = 'ShowMessageClassic'; 3386ec4045Sgerardnico const CONF_SHOW_MESSAGE_CLASSIC_DEFAULT = 1; 34c3437056SNickeau 35c3437056SNickeau function __construct() 36c3437056SNickeau { 37c3437056SNickeau // enable direct access to language strings 38c3437056SNickeau // ie $this->lang 39c3437056SNickeau $this->setupLocale(); 40c3437056SNickeau } 41c3437056SNickeau 42c3437056SNickeau /** 43c3437056SNickeau * 44c3437056SNickeau * Return the message properties from a query string 45c3437056SNickeau * 46c3437056SNickeau * An internal HTTP redirect pass them via query string 47c3437056SNickeau */ 48c3437056SNickeau private static function getMessageQueryStringProperties(): array 49c3437056SNickeau { 50c3437056SNickeau 51c3437056SNickeau $returnValues = array(); 52c3437056SNickeau 53c3437056SNickeau global $INPUT; 54c3437056SNickeau $origin = $INPUT->str(self::ORIGIN_PAGE, null); 55c3437056SNickeau if ($origin != null) { 56c3437056SNickeau $returnValues = array( 57c3437056SNickeau $origin, 58c3437056SNickeau $INPUT->str(self::ORIGIN_TYPE, null) 59c3437056SNickeau ); 60c3437056SNickeau } 61c3437056SNickeau return $returnValues; 62c3437056SNickeau 63c3437056SNickeau } 64c3437056SNickeau 65c3437056SNickeau 66c3437056SNickeau function register(Doku_Event_Handler $controller) 67c3437056SNickeau { 68c3437056SNickeau 69c3437056SNickeau /* This will call the function _displayRedirectMessage */ 70c3437056SNickeau $controller->register_hook( 71c3437056SNickeau 'TPL_ACT_RENDER', 72c3437056SNickeau 'BEFORE', 73c3437056SNickeau $this, 74c3437056SNickeau '_displayRedirectMessage', 75c3437056SNickeau array() 76c3437056SNickeau ); 77c3437056SNickeau 78c3437056SNickeau 79c3437056SNickeau } 80c3437056SNickeau 81c3437056SNickeau 82c3437056SNickeau /** 83c3437056SNickeau * Main function; dispatches the visual comment actions 84c3437056SNickeau * @param $event Doku_Event 85c3437056SNickeau */ 86c3437056SNickeau function _displayRedirectMessage(&$event, $param) 87c3437056SNickeau { 88c3437056SNickeau 89c3437056SNickeau $pageIdOrigin = null; 90c3437056SNickeau $redirectSource = null; 91c3437056SNickeau 92c3437056SNickeau $messageQueryStringProperties = self::getMessageQueryStringProperties(); 93c3437056SNickeau if (!empty($messageQueryStringProperties)) { 94c3437056SNickeau list($pageIdOrigin, $redirectSource) = $messageQueryStringProperties; 95c3437056SNickeau } 96c3437056SNickeau 97c3437056SNickeau if ($pageIdOrigin) { 98c3437056SNickeau 99c3437056SNickeau switch ($redirectSource) { 100c3437056SNickeau 101c3437056SNickeau case action_plugin_combo_router::TARGET_ORIGIN_PAGE_RULES: 10286ec4045Sgerardnico if (!$this->showMessageIfPublicAndPlanned()) { 10386ec4045Sgerardnico return; 10486ec4045Sgerardnico } 105c3437056SNickeau $message = Message::createInfoMessage() 106c3437056SNickeau ->addHtmlContent("<p>" . sprintf($this->getLang('message_redirected_by_redirect'), hsc($pageIdOrigin)) . "</p>"); 107c3437056SNickeau break; 108c3437056SNickeau 109c3437056SNickeau case action_plugin_combo_router::TARGET_ORIGIN_START_PAGE: 110c3437056SNickeau $message = Message::createWarningMessage() 111c3437056SNickeau ->addHtmlContent("<p>" . sprintf($this->lang['message_redirected_to_startpage'], hsc($pageIdOrigin)) . "</p>"); 112c3437056SNickeau break; 113c3437056SNickeau case action_plugin_combo_router::TARGET_ORIGIN_BEST_PAGE_NAME: 114c3437056SNickeau $message = Message::createWarningMessage() 115c3437056SNickeau ->addHtmlContent("<p>" . sprintf($this->lang['message_redirected_to_bestpagename'], hsc($pageIdOrigin)) . "</p>"); 116c3437056SNickeau break; 117c3437056SNickeau case action_plugin_combo_router::TARGET_ORIGIN_BEST_NAMESPACE: 118c3437056SNickeau $message = Message::createWarningMessage() 119c3437056SNickeau ->addHtmlContent("<p>" . sprintf($this->lang['message_redirected_to_bestnamespace'], hsc($pageIdOrigin)) . "</p>"); 120c3437056SNickeau break; 121c3437056SNickeau 122c3437056SNickeau case action_plugin_combo_router::TARGET_ORIGIN_SEARCH_ENGINE: 123c3437056SNickeau $message = Message::createWarningMessage() 124c3437056SNickeau ->addHtmlContent("<p>" . sprintf($this->lang['message_redirected_to_searchengine'], hsc($pageIdOrigin)) . "</p>"); 125c3437056SNickeau break; 126c3437056SNickeau 127c3437056SNickeau case action_plugin_combo_router::GO_TO_EDIT_MODE: 128c3437056SNickeau $message = Message::createInfoMessage() 129c3437056SNickeau ->addHtmlContent("<p>" . $this->lang['message_redirected_to_edit_mode'] . "</p>"); 130c3437056SNickeau break; 131c3437056SNickeau case action_plugin_combo_router::TARGET_ORIGIN_PERMALINK_EXTENDED: 132c3437056SNickeau case action_plugin_combo_router::TARGET_ORIGIN_PERMALINK: 133c3437056SNickeau $message = Message::createInfoMessage() 134c3437056SNickeau ->addHtmlContent("<p>" . $this->lang['message_redirected_from_permalink'] . "</p>"); 135c3437056SNickeau break; 136561faa65Sgerardnico case action_plugin_combo_router::TARGET_ORIGIN_CANONICAL: 13786ec4045Sgerardnico if (!$this->showMessageIfPublicAndPlanned()) { 13886ec4045Sgerardnico return; 13986ec4045Sgerardnico } 140561faa65Sgerardnico $message = Message::createInfoMessage() 141561faa65Sgerardnico ->addHtmlContent("<p>" . $this->lang['message_redirected_from_canonical'] . "</p>"); 142561faa65Sgerardnico break; 143c3437056SNickeau default: 144c3437056SNickeau LogUtility::msg("The redirection source ($redirectSource) is unknown. It was not expected", LogUtility::LVL_MSG_ERROR, action_plugin_combo_router::CANONICAL); 145c3437056SNickeau return; 146c3437056SNickeau 147c3437056SNickeau } 148c3437056SNickeau 149c3437056SNickeau 150c3437056SNickeau // Add a list of page with the same name to the message 151c3437056SNickeau // if the redirections is not planned 152*04fd306cSNickeau if ($redirectSource != action_plugin_combo_router::TARGET_ORIGIN_PAGE_RULES) { 153*04fd306cSNickeau $pageOrigin = MarkupPath::createMarkupFromId($pageIdOrigin); 154*04fd306cSNickeau $this->addToMessagePagesWithSameName($message, $pageOrigin); 155c3437056SNickeau } 156c3437056SNickeau 157c3437056SNickeau if ($event->data === 'show' || $event->data === 'edit' || $event->data === 'search') { 158c3437056SNickeau $html = $message 159c3437056SNickeau ->setPlugin($this) 160c3437056SNickeau ->setClass(action_plugin_combo_routermessage::REDIRECT_MANAGER_BOX_CLASS) 161c3437056SNickeau ->setCanonical(action_plugin_combo_router::CANONICAL) 162c3437056SNickeau ->setSignatureName(action_plugin_combo_router::URL_MANAGER_NAME) 163c3437056SNickeau ->toHtmlBox(); 164*04fd306cSNickeau LogUtility::infoToPublic($html, action_plugin_combo_router::CANONICAL); 165c3437056SNickeau } 166c3437056SNickeau 167c3437056SNickeau 168c3437056SNickeau } 169c3437056SNickeau 170c3437056SNickeau 171c3437056SNickeau } 172c3437056SNickeau 173c3437056SNickeau 174c3437056SNickeau /** 175c3437056SNickeau * Add the page with the same page name but in an other location 176c3437056SNickeau * @param Message $message 177*04fd306cSNickeau * @param MarkupPath $pageOrigin 178c3437056SNickeau */ 179*04fd306cSNickeau function addToMessagePagesWithSameName(Message $message, MarkupPath $pageOrigin) 180c3437056SNickeau { 181c3437056SNickeau 18286ec4045Sgerardnico if (!$this->getConf(self::CONF_SHOW_PAGE_NAME_IS_NOT_UNIQUE) == 1) { 18386ec4045Sgerardnico return; 18486ec4045Sgerardnico } 185c3437056SNickeau 186c3437056SNickeau global $ID; 187c3437056SNickeau // The page name 188*04fd306cSNickeau $pageName = $pageOrigin->getNameOrDefault(); 189*04fd306cSNickeau $pagesWithSameName = Index::getOrCreate()->getPagesWithSameLastName($pageOrigin); 190*04fd306cSNickeau 191*04fd306cSNickeau if (count($pagesWithSameName) === 1) { 192*04fd306cSNickeau $page = $pagesWithSameName[0]; 193*04fd306cSNickeau if ($page->getWikiId() === $ID) { 194*04fd306cSNickeau // the page itself 195*04fd306cSNickeau return; 196*04fd306cSNickeau } 197*04fd306cSNickeau } 198c3437056SNickeau 199c3437056SNickeau if (count($pagesWithSameName) > 0) { 200c3437056SNickeau 201c3437056SNickeau $message->setType(Message::TYPE_WARNING); 202c3437056SNickeau 203c3437056SNickeau // Assign the value to a variable to be able to use the construct .= 204c3437056SNickeau if ($message->getPlainTextContent() <> '') { 205c3437056SNickeau $message->addHtmlContent('<br/><br/>'); 206c3437056SNickeau } 207c3437056SNickeau $message->addHtmlContent($this->lang['message_pagename_exist_one']); 208c3437056SNickeau $message->addHtmlContent('<ul>'); 209c3437056SNickeau 210c3437056SNickeau $i = 0; 211*04fd306cSNickeau $listPagesHtml = ""; 212*04fd306cSNickeau foreach ($pagesWithSameName as $page) { 213*04fd306cSNickeau 214*04fd306cSNickeau if ($page->getWikiId() === $ID) { 215c3437056SNickeau continue; 216c3437056SNickeau } 217c3437056SNickeau $i++; 218c3437056SNickeau if ($i > 10) { 219*04fd306cSNickeau $listPagesHtml .= '<li>' . 220c3437056SNickeau tpl_link( 221*04fd306cSNickeau "?do=search&q=" . rawurldecode($pageName), 222c3437056SNickeau "More ...", 223c3437056SNickeau 'class="" rel="nofollow" title="More..."', 224c3437056SNickeau $return = true 225*04fd306cSNickeau ) . '</li>'; 226c3437056SNickeau break; 227c3437056SNickeau } 228*04fd306cSNickeau 229*04fd306cSNickeau try { 230*04fd306cSNickeau $markupRef = LinkMarkup::createFromPageIdOrPath($page->getWikiId()); 231*04fd306cSNickeau $tagAttributes = $markupRef 232*04fd306cSNickeau ->toAttributes() 233*04fd306cSNickeau ->addOutputAttributeValue("rel", "nofollow"); 234*04fd306cSNickeau $listPagesHtml .= "<li>{$tagAttributes->toHtmlEnterTag("a")}{$markupRef->getDefaultLabel()}</a></li>"; 235*04fd306cSNickeau } catch (ExceptionBadSyntax $e) { 236*04fd306cSNickeau LogUtility::internalError("Internal Error: Unable to get a markup ref for the page ($page). Error: {$e->getMessage()}"); 237c3437056SNickeau } 23886ec4045Sgerardnico 239c3437056SNickeau } 240*04fd306cSNickeau $message->addHtmlContent($listPagesHtml); 241*04fd306cSNickeau $message->addHtmlContent('</ul>'); 242*04fd306cSNickeau 243*04fd306cSNickeau } 244*04fd306cSNickeau } 245c3437056SNickeau 246c3437056SNickeau 247c3437056SNickeau /** 248c3437056SNickeau * Set the redirect in a session that will be be read after the redirect 249c3437056SNickeau * in order to show a message to the user 250c3437056SNickeau * @param string $id 251c3437056SNickeau * @param string $redirectSource 252c3437056SNickeau */ 253c3437056SNickeau static function notify($id, $redirectSource) 254c3437056SNickeau { 255c3437056SNickeau // Msg via session 256c3437056SNickeau if (!defined('NOSESSION')) { 257c3437056SNickeau //reopen session, store data and close session again 258c3437056SNickeau self::sessionStart(); 259c3437056SNickeau $_SESSION[DOKU_COOKIE][self::ORIGIN_PAGE] = $id; 260c3437056SNickeau $_SESSION[DOKU_COOKIE][self::ORIGIN_TYPE] = $redirectSource; 261c3437056SNickeau self::sessionClose(); 262c3437056SNickeau 263c3437056SNickeau } 264c3437056SNickeau } 265c3437056SNickeau 266c3437056SNickeau 267c3437056SNickeau private static function sessionStart() 268c3437056SNickeau { 269c3437056SNickeau $sessionStatus = session_status(); 270c3437056SNickeau switch ($sessionStatus) { 271c3437056SNickeau case PHP_SESSION_DISABLED: 272c3437056SNickeau throw new RuntimeException("Sessions are disabled"); 273c3437056SNickeau 274c3437056SNickeau case PHP_SESSION_NONE: 275c3437056SNickeau $result = @session_start(); 276c3437056SNickeau if (!$result) { 277c3437056SNickeau throw new RuntimeException("The session was not successfully started"); 278c3437056SNickeau } 279c3437056SNickeau break; 280c3437056SNickeau case PHP_SESSION_ACTIVE: 281c3437056SNickeau break; 282c3437056SNickeau } 283c3437056SNickeau } 284c3437056SNickeau 285c3437056SNickeau private static function sessionClose() 286c3437056SNickeau { 287c3437056SNickeau // Close the session 288c3437056SNickeau $phpVersion = phpversion(); 289c3437056SNickeau if ($phpVersion > "7.2.0") { 290c3437056SNickeau $result = session_write_close(); 291c3437056SNickeau if (!$result) { 292c3437056SNickeau // Session is really not a well known mechanism 293c3437056SNickeau // Set this error in a info level to not fail the test 294c3437056SNickeau LogUtility::msg("Failure to write the session", LogUtility::LVL_MSG_INFO); 295c3437056SNickeau } 296c3437056SNickeau } else { 297c3437056SNickeau session_write_close(); 298c3437056SNickeau } 299c3437056SNickeau 300c3437056SNickeau } 301c3437056SNickeau 30286ec4045Sgerardnico /** 30386ec4045Sgerardnico * We don't saw the message if it was planned and 30486ec4045Sgerardnico * it's a reader 30586ec4045Sgerardnico * @return bool 30686ec4045Sgerardnico */ 30786ec4045Sgerardnico private function showMessageIfPublicAndPlanned(): bool 30886ec4045Sgerardnico { 30986ec4045Sgerardnico if (Identity::isWriter()){ 31086ec4045Sgerardnico return true; 31186ec4045Sgerardnico } 31286ec4045Sgerardnico return $this->getConf(self::CONF_SHOW_MESSAGE_CLASSIC, self::CONF_SHOW_MESSAGE_CLASSIC_DEFAULT) == 1; 31386ec4045Sgerardnico } 31486ec4045Sgerardnico 315c3437056SNickeau} 316