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