xref: /template/strap/action/qualitymessage.php (revision c3437056399326d621a01da73b649707fbb0ae69)
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