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