1<?php 2 3use ComboStrap\DokuwikiId; 4use ComboStrap\ExceptionNotFound; 5use ComboStrap\ExceptionReporter; 6use ComboStrap\ExecutionContext; 7use ComboStrap\FetcherAppPages; 8use ComboStrap\FetcherPage; 9use ComboStrap\FetcherRailBar; 10use ComboStrap\FileSystems; 11use ComboStrap\HttpResponseStatus; 12use ComboStrap\Identity; 13use ComboStrap\IFetcher; 14use ComboStrap\LogUtility; 15use ComboStrap\MarkupPath; 16use ComboStrap\Mime; 17use ComboStrap\PluginUtility; 18use ComboStrap\Site; 19use ComboStrap\SiteConfig; 20use ComboStrap\Web\Url; 21use ComboStrap\Web\UrlRewrite; 22 23/** 24 * Implementation of custom do (ie ACT) to output {@link \ComboStrap\IFetcherString} 25 * 26 * 27 * 28 */ 29class action_plugin_combo_docustom extends DokuWiki_Action_Plugin 30{ 31 32 const DO_PREFIX = "combo_"; 33 34 const TEMPLATE_CANONICAL = "template"; 35 36 /** 37 * @var bool to avoid recursion that may happen using {@link tpl_content()} 38 */ 39 private bool $doCustomActuallyExecuting = false; 40 41 /** 42 * @return bool 43 */ 44 public static function isThemeSystemEnabled(): bool 45 { 46 $confValue = SiteConfig::getConfValue(SiteConfig::CONF_ENABLE_THEME_SYSTEM, SiteConfig::CONF_ENABLE_THEME_SYSTEM_DEFAULT); 47 return $confValue === 1; 48 } 49 50 public static function getDoParameterValue(string $fetcherName): string 51 { 52 return self::DO_PREFIX . $fetcherName; 53 } 54 55 /** 56 * 57 * @param Doku_Event_Handler $controller 58 * @return void 59 */ 60 61 public function register(\Doku_Event_Handler $controller) 62 { 63 /** 64 * Execute the combo action via an ACTION_ACT_PREPROCESS 65 * 66 * Not via the [TPL_ACT_UNKNOWN](https://www.dokuwiki.org/devel:event:tpl_act_unknown) 67 * because it would otherwise put the content in the middle of the page 68 * as an admin page. 69 * 70 * Not really useful if you want your own layout or do an export 71 */ 72 $controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'executeComboDoAction'); 73 74 } 75 76 /** 77 * @param Doku_Event $event 78 * @param $param 79 * @return void 80 * 81 */ 82 public function executeComboDoAction(Doku_Event $event, $param) 83 { 84 85 if ($this->doCustomActuallyExecuting) { 86 return; 87 } 88 89 /** 90 * The router may have done a redirection 91 * (The Dokuwiki testRequest does not stop unfortunately) 92 */ 93 $executionContext = ExecutionContext::getActualOrCreateFromEnv(); 94 $hasEnded = $executionContext 95 ->response() 96 ->hasEnded(); 97 if ($hasEnded) { 98 if ($executionContext->isTestRun()) { 99 /** 100 * This info helps the developer to see 101 * why nothing happens when it sends two dokuwiki {@link TestRequest} 102 * 103 * And not two {@link \ComboStrap\HttpResponse} 104 * that reinitialize the global scope 105 */ 106 LogUtility::info("ExecuteDoAction: The response has already be send (ended)."); 107 } 108 return; 109 } 110 111 $urlRewrite = Site::getUrlRewrite(); 112 if ($urlRewrite == UrlRewrite::VALUE_DOKU_REWRITE) { 113 UrlRewrite::sendErrorMessage(); 114 return; 115 } 116 117 $action = $event->data; 118 119 $privateRailbar = $executionContext->getConfig()->getBooleanValue(FetcherRailBar::CONF_PRIVATE_RAIL_BAR, FetcherRailBar::CONF_PRIVATE_RAIL_BAR_DEFAULT); 120 $isAnonymous = Identity::isAnonymous(); 121 if ($privateRailbar && $isAnonymous) { 122 /** 123 * To avoid the google console error: `Excluded by ‘noindex’ tag` 124 * Example of URL 125 * https://example.com/dat/bobj/central_management_server?tab_files=upload&do=media&tab_details=history&image=db:hana:hdb_thread_stat_systemdb.png&ns=web/resource 126 */ 127 $privateAction = [ExecutionContext::MEDIA_ACTION, ExecutionContext::DIFF_ACTION, ExecutionContext::RECENT_ACTION]; 128 if (in_array($action, $privateAction)) { 129 $executionContext->response() 130 ->setStatus(HttpResponseStatus::NOT_AUTHORIZED) 131 ->end(); 132 return; 133 } 134 } 135 136 if (self::isThemeSystemEnabled()) { 137 switch ($action) { 138 case ExecutionContext::SHOW_ACTION: 139 try { 140 $id = Url::createFromGetOrPostGlobalVariable()->getPropertyValue(DokuwikiId::DOKUWIKI_ID_ATTRIBUTE); 141 } catch (ExceptionNotFound $e) { 142 // should not happen but yeah 143 return; 144 } 145 $path = MarkupPath::createMarkupFromId($id); 146 if (!FileSystems::exists($path)) { 147 return; 148 } 149 $action = self::getDoParameterValue(FetcherPage::NAME); 150 break; 151 case ExecutionContext::LOGIN_ACTION: 152 case ExecutionContext::REGISTER_ACTION: 153 case ExecutionContext::RESEND_PWD_ACTION: 154 case ExecutionContext::PROFILE_ACTION: 155 case ExecutionContext::EDIT_ACTION: 156 case ExecutionContext::PREVIEW_ACTION: 157 case ExecutionContext::SEARCH_ACTION: 158 case ExecutionContext::INDEX_ACTION: 159 //case ExecutionContext::REVISIONS_ACTION: 160 //case ExecutionContext::DIFF_ACTION: needs styling 161 $action = self::getDoParameterValue(FetcherAppPages::NAME); 162 break; 163 } 164 } 165 166 167 if (!$this->isComboDoAction($action)) return; 168 169 /** 170 * To avoid recursion 171 */ 172 $this->doCustomActuallyExecuting = true; 173 174 175 try { 176 $fetcherName = $this->getFetcherNameFromAction($action); 177 $url = Url::createFromGetOrPostGlobalVariable() 178 ->addQueryParameter(IFetcher::FETCHER_KEY, $fetcherName); 179 $fetcher = $executionContext->createStringMainFetcherFromRequestedUrl($url); 180 $body = $fetcher->getFetchString(); 181 $mime = $fetcher->getMime(); 182 $executionContext->response() 183 ->setStatus(HttpResponseStatus::ALL_GOOD) 184 ->setBody($body, $mime) 185 ->end(); 186 } catch (\Exception $e) { 187 188 189 $reporterMessage = "An error has occurred during the execution of the action ($action)"; 190 $html = ExceptionReporter::createForException($e) 191 ->getHtmlPage($reporterMessage); 192 if (PluginUtility::isDevOrTest()) { 193 // Permits to throw the error to get the stack trace 194 LogUtility::warning($reporterMessage, self::TEMPLATE_CANONICAL, $e); 195 } 196 $executionContext->response() 197 ->setException($e) 198 ->setBody($html, Mime::getHtml()) 199 ->end(); 200 201 } finally { 202 $this->doCustomActuallyExecuting = false; 203 } 204 205 } 206 207 208 private function isComboDoAction($actionName): bool 209 { 210 return strpos($actionName, self::DO_PREFIX) === 0; 211 } 212 213 private function getFetcherNameFromAction($actionName) 214 { 215 return substr($actionName, strlen(self::DO_PREFIX)); 216 } 217 218 219} 220