1<?php 2 3use ComboStrap\AnalyticsDocument; 4use ComboStrap\ExceptionCombo; 5use ComboStrap\Identity; 6use ComboStrap\LogUtility; 7use ComboStrap\Message; 8use ComboStrap\Mime; 9use ComboStrap\Page; 10use ComboStrap\PluginUtility; 11use ComboStrap\QualityMenuItem; 12use ComboStrap\HttpResponse; 13 14if (!defined('DOKU_INC')) die(); 15if (!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN', DOKU_INC . 'lib/plugins/'); 16 17 18require_once(__DIR__ . '/../ComboStrap/PluginUtility.php'); 19 20/** 21 * 22 * Show a quality message 23 * 24 * 25 * 26 */ 27class action_plugin_combo_qualitymessage extends DokuWiki_Action_Plugin 28{ 29 30 // a class can not start with a number 31 const QUALITY_BOX_CLASS = "quality-message"; 32 33 /** 34 * The quality rules that will not show 35 * up in the messages 36 */ 37 const CONF_EXCLUDED_QUALITY_RULES_FROM_DYNAMIC_MONITORING = "excludedQualityRulesFromDynamicMonitoring"; 38 /** 39 * Disable the message totally 40 */ 41 const CONF_DISABLE_QUALITY_MONITORING = "disableDynamicQualityMonitoring"; 42 43 const CANONICAL = "quality:dynamic_monitoring"; 44 45 const META_MANAGER_CALL_ID = "combo-quality-message"; 46 47 48 function __construct() 49 { 50 // enable direct access to language strings 51 // ie $this->lang 52 $this->setupLocale(); 53 } 54 55 public static function createHtmlQualityNote(Page $page): Message 56 { 57 if ($page->isSlot()) { 58 return Message::createErrorMessage("A has no quality metrics"); 59 60 } 61 62 if (!$page->isDynamicQualityMonitored()) { 63 return Message::createErrorMessage("This page is not quality monitored. Change the configuration if you want to."); 64 } 65 66 if (!$page->exists()) { 67 return Message::createInfoMessage("The page does not exist"); 68 } 69 70 71 try { 72 $analyticsArray = $page->getAnalyticsDocument()->getJson()->toArray(); 73 } catch (ExceptionCombo $e) { 74 return Message::createErrorMessage("Error while trying to read the JSON analytics document. {$e->getMessage()}") 75 ->setStatus(HttpResponse::STATUS_INTERNAL_ERROR); 76 } 77 78 $rules = $analyticsArray[AnalyticsDocument::QUALITY][AnalyticsDocument::RULES]; 79 80 81 /** 82 * We may got null 83 * array_key_exists() expects parameter 2 to be array, 84 * null given in /opt/www/datacadamia.com/lib/plugins/combo/action/qualitymessage.php on line 113 85 */ 86 if ($rules == null) { 87 return Message::createInfoMessage("No rules found in the analytics document"); 88 } 89 90 /** 91 * If there is no info, nothing to show 92 */ 93 if (!array_key_exists(AnalyticsDocument::INFO, $rules)) { 94 return Message::createInfoMessage("No quality rules information to show"); 95 } 96 97 /** 98 * The error info 99 */ 100 $qualityInfoRules = $rules[AnalyticsDocument::INFO]; 101 102 /** 103 * Excluding the excluded rules 104 */ 105 global $conf; 106 $excludedRulesConf = $conf['plugin'][PluginUtility::PLUGIN_BASE_NAME][self::CONF_EXCLUDED_QUALITY_RULES_FROM_DYNAMIC_MONITORING]; 107 $excludedRules = preg_split("/,/", $excludedRulesConf); 108 foreach ($excludedRules as $excludedRule) { 109 if (array_key_exists($excludedRule, $qualityInfoRules)) { 110 unset($qualityInfoRules[$excludedRule]); 111 } 112 } 113 114 if (sizeof($qualityInfoRules) <= 0) { 115 return Message::createInfoMessage("No quality rules information to show"); 116 } 117 118 $qualityScore = $analyticsArray[AnalyticsDocument::QUALITY][renderer_plugin_combo_analytics::SCORING][renderer_plugin_combo_analytics::SCORE]; 119 $message = "<p>The page has a " . PluginUtility::getDocumentationHyperLink("quality:score", "quality score") . " of {$qualityScore}.</p>"; 120 121 $lowQuality = $analyticsArray[AnalyticsDocument::QUALITY][AnalyticsDocument::LOW]; 122 if ($lowQuality) { 123 124 $mandatoryFailedRules = $analyticsArray[AnalyticsDocument::QUALITY][AnalyticsDocument::FAILED_MANDATORY_RULES]; 125 $rulesUrl = PluginUtility::getDocumentationHyperLink("quality:rule", "rules"); 126 $lqPageUrl = PluginUtility::getDocumentationHyperLink("low_quality_page", "low quality page"); 127 $message .= "<div class='alert alert-warning'>This is a {$lqPageUrl} because it has failed the following mandatory {$rulesUrl}:"; 128 $message .= "<ul style='margin-bottom: 0'>"; 129 /** 130 * A low quality page should have 131 * failed mandatory rules 132 * but due to the asycn nature, sometimes 133 * we don't have an array 134 */ 135 if (is_array($mandatoryFailedRules)) { 136 foreach ($mandatoryFailedRules as $mandatoryFailedRule) { 137 $message .= "<li>" . PluginUtility::getDocumentationHyperLink("quality:rule#list", $mandatoryFailedRule) . "</li>"; 138 } 139 } 140 $message .= "</ul>"; 141 $message .= "</div>"; 142 } 143 $message .= "<p>You can still win a couple of points.</p>"; 144 $message .= "<ul>"; 145 foreach ($qualityInfoRules as $qualityRule => $qualityInfo) { 146 $message .= "<li>$qualityInfo</li>"; 147 } 148 $message .= "</ul>"; 149 return Message::createInfoMessage($message); 150 151 } 152 153 154 function register(Doku_Event_Handler $controller) 155 { 156 157 158 /** 159 * Add a icon in the page tools menu 160 * https://www.dokuwiki.org/devel:event:menu_items_assembly 161 */ 162 $controller->register_hook('MENU_ITEMS_ASSEMBLY', 'AFTER', $this, 'addMenuItem'); 163 164 165 /** 166 * The ajax api to return data 167 */ 168 $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'ajaxCall'); 169 170 } 171 172 173 function addMenuItem(Doku_Event $event, $param) 174 { 175 176 if (!Identity::isWriter()) { 177 return; 178 } 179 180 /** 181 * The `view` property defines the menu that is currently built 182 * https://www.dokuwiki.org/devel:menus 183 * If this is not the page menu, return 184 */ 185 if ($event->data['view'] != 'page') return; 186 187 global $INFO; 188 if (!$INFO['exists']) { 189 return; 190 } 191 array_splice($event->data['items'], -1, 0, array(new QualityMenuItem())); 192 193 } 194 195 /** 196 * Main function; dispatches the visual comment actions 197 * @param $event Doku_Event 198 */ 199 function ajaxCall(&$event, $param): void 200 { 201 $call = $event->data; 202 if ($call != self::META_MANAGER_CALL_ID) { 203 return; 204 } 205 //no other ajax call handlers needed 206 $event->stopPropagation(); 207 $event->preventDefault(); 208 209 /** 210 * Shared check between post and get HTTP method 211 */ 212 $id = $_GET["id"]; 213 if ($id === null) { 214 /** 215 * With {@link TestRequest} 216 * for instance 217 */ 218 $id = $_REQUEST["id"]; 219 } 220 221 if (empty($id)) { 222 HttpResponse::create(HttpResponse::STATUS_BAD_REQUEST) 223 ->setEvent($event) 224 ->setCanonical(self::CANONICAL) 225 ->send("The page id should not be empty", Mime::HTML); 226 return; 227 } 228 229 /** 230 * Quality is just for the writers 231 */ 232 if (!Identity::isWriter($id)) { 233 HttpResponse::create(HttpResponse::STATUS_NOT_AUTHORIZED) 234 ->setEvent($event) 235 ->send("Quality is only for writer", Mime::HTML); 236 return; 237 } 238 239 240 $page = Page::createPageFromId($id); 241 242 $message = self::createHtmlQualityNote($page); 243 244 $status = $message->getStatus(); 245 if ($status === null) { 246 $status = HttpResponse::STATUS_ALL_GOOD; 247 } 248 249 HttpResponse::create($status) 250 ->setEvent($event) 251 ->setCanonical(self::CANONICAL) 252 ->send($message->getContent(), Mime::HTML); 253 254 } 255} 256