xref: /dokuwiki/lib/plugins/extension/Notice.php (revision d2d4b908d117b646962dcc1e17aec0fae72c60d3)
14fd6a1d7SAndreas Gohr<?php
24fd6a1d7SAndreas Gohr
34fd6a1d7SAndreas Gohrnamespace dokuwiki\plugin\extension;
44fd6a1d7SAndreas Gohr
54fd6a1d7SAndreas Gohrclass Notice
64fd6a1d7SAndreas Gohr{
77c184cfcSAndreas Gohr    public const INFO = 'info';
87c184cfcSAndreas Gohr    public const WARNING = 'warning';
97c184cfcSAndreas Gohr    public const ERROR = 'error';
107c184cfcSAndreas Gohr    public const SECURITY = 'security';
114fd6a1d7SAndreas Gohr
12*d2d4b908SAndreas Gohr    protected const ICONS = [
13*d2d4b908SAndreas Gohr        self::INFO => 'I',
14*d2d4b908SAndreas Gohr        self::WARNING => 'W',
15*d2d4b908SAndreas Gohr        self::ERROR => 'E',
16*d2d4b908SAndreas Gohr        self::SECURITY => 'S',
174fd6a1d7SAndreas Gohr    ];
184fd6a1d7SAndreas Gohr
194fd6a1d7SAndreas Gohr    protected $notices = [
204fd6a1d7SAndreas Gohr        self::INFO => [],
214fd6a1d7SAndreas Gohr        self::WARNING => [],
224fd6a1d7SAndreas Gohr        self::ERROR => [],
234fd6a1d7SAndreas Gohr        self::SECURITY => [],
244fd6a1d7SAndreas Gohr    ];
254fd6a1d7SAndreas Gohr
264fd6a1d7SAndreas Gohr    /** @var \helper_plugin_extension */
274fd6a1d7SAndreas Gohr    protected $helper;
284fd6a1d7SAndreas Gohr
294fd6a1d7SAndreas Gohr    /** @var Extension */
304fd6a1d7SAndreas Gohr    protected Extension $extension;
314fd6a1d7SAndreas Gohr
324fd6a1d7SAndreas Gohr    /**
334fd6a1d7SAndreas Gohr     * Not public, use list() instead
344fd6a1d7SAndreas Gohr     * @param Extension $extension
354fd6a1d7SAndreas Gohr     */
364fd6a1d7SAndreas Gohr    protected function __construct(Extension $extension)
374fd6a1d7SAndreas Gohr    {
384fd6a1d7SAndreas Gohr        $this->helper = plugin_load('helper', 'extension');
394fd6a1d7SAndreas Gohr        $this->extension = $extension;
404fd6a1d7SAndreas Gohr
414fd6a1d7SAndreas Gohr        $this->checkSecurity();
428fe483c9SAndreas Gohr        $this->checkURLChange();
434fd6a1d7SAndreas Gohr        $this->checkFolder();
444fd6a1d7SAndreas Gohr        $this->checkPHPVersion();
458fe483c9SAndreas Gohr        $this->checkDependencies();
468fe483c9SAndreas Gohr        $this->checkConflicts();
474fd6a1d7SAndreas Gohr        $this->checkUpdateMessage();
48981e70caSAndreas Gohr        $this->checkPermissions();
49981e70caSAndreas Gohr        $this->checkUnusedAuth();
50981e70caSAndreas Gohr        $this->checkGit();
514fd6a1d7SAndreas Gohr    }
524fd6a1d7SAndreas Gohr
534fd6a1d7SAndreas Gohr    /**
544fd6a1d7SAndreas Gohr     * Get all notices for the extension
554fd6a1d7SAndreas Gohr     *
564fd6a1d7SAndreas Gohr     * @return string[][] array of notices grouped by type
574fd6a1d7SAndreas Gohr     */
584fd6a1d7SAndreas Gohr    public static function list(Extension $extension): array
594fd6a1d7SAndreas Gohr    {
604fd6a1d7SAndreas Gohr        $self = new self($extension);
614fd6a1d7SAndreas Gohr        return $self->notices;
624fd6a1d7SAndreas Gohr    }
634fd6a1d7SAndreas Gohr
644fd6a1d7SAndreas Gohr    /**
65*d2d4b908SAndreas Gohr     * Return the icon path for a notice type
66*d2d4b908SAndreas Gohr     *
67*d2d4b908SAndreas Gohr     * @param string $type The notice type constant
68*d2d4b908SAndreas Gohr     * @return string
69*d2d4b908SAndreas Gohr     */
70*d2d4b908SAndreas Gohr    public static function icon($type): string
71*d2d4b908SAndreas Gohr    {
72*d2d4b908SAndreas Gohr        if (!isset(self::ICONS[$type])) throw new \RuntimeException('Unknown notice type: ' . $type);
73*d2d4b908SAndreas Gohr        return __DIR__ . '/images/' . $type . '.svg';
74*d2d4b908SAndreas Gohr    }
75*d2d4b908SAndreas Gohr
76*d2d4b908SAndreas Gohr    /**
77*d2d4b908SAndreas Gohr     * Return the character symbol for a notice type used on CLI
78*d2d4b908SAndreas Gohr     *
79*d2d4b908SAndreas Gohr     * @param string $type The notice type constant
80*d2d4b908SAndreas Gohr     * @return string
81*d2d4b908SAndreas Gohr     */
82*d2d4b908SAndreas Gohr    public static function symbol($type): string
83*d2d4b908SAndreas Gohr    {
84*d2d4b908SAndreas Gohr        if (!isset(self::ICONS[$type])) throw new \RuntimeException('Unknown notice type: ' . $type);
85*d2d4b908SAndreas Gohr        return self::ICONS[$type][0] ?? '';
86*d2d4b908SAndreas Gohr    }
87*d2d4b908SAndreas Gohr
88*d2d4b908SAndreas Gohr    /**
894fd6a1d7SAndreas Gohr     * Access a language string
904fd6a1d7SAndreas Gohr     *
914fd6a1d7SAndreas Gohr     * @param string $msg
924fd6a1d7SAndreas Gohr     * @return string
934fd6a1d7SAndreas Gohr     */
944fd6a1d7SAndreas Gohr    protected function getLang($msg)
954fd6a1d7SAndreas Gohr    {
96cf461f20SAndreas Gohr        return $this->helper->getLang($msg);
974fd6a1d7SAndreas Gohr    }
984fd6a1d7SAndreas Gohr
994fd6a1d7SAndreas Gohr    /**
1004fd6a1d7SAndreas Gohr     * Check that all dependencies are met
1014fd6a1d7SAndreas Gohr     * @return void
1024fd6a1d7SAndreas Gohr     */
1034fd6a1d7SAndreas Gohr    protected function checkDependencies()
1044fd6a1d7SAndreas Gohr    {
1054fd6a1d7SAndreas Gohr        if (!$this->extension->isInstalled()) return;
1064fd6a1d7SAndreas Gohr
1074fd6a1d7SAndreas Gohr        $dependencies = $this->extension->getDependencyList();
1084fd6a1d7SAndreas Gohr        $missing = [];
1094fd6a1d7SAndreas Gohr        foreach ($dependencies as $dependency) {
1104fd6a1d7SAndreas Gohr            $dep = Extension::createFromId($dependency);
1114fd6a1d7SAndreas Gohr            if (!$dep->isInstalled()) $missing[] = $dep;
1124fd6a1d7SAndreas Gohr        }
1134fd6a1d7SAndreas Gohr        if (!$missing) return;
1144fd6a1d7SAndreas Gohr
1154fd6a1d7SAndreas Gohr        $this->notices[self::ERROR][] = sprintf(
1164fd6a1d7SAndreas Gohr            $this->getLang('missing_dependency'),
1177c184cfcSAndreas Gohr            implode(', ', array_map(static fn(Extension $dep) => $dep->getId(true), $missing))
1184fd6a1d7SAndreas Gohr        );
1194fd6a1d7SAndreas Gohr    }
1204fd6a1d7SAndreas Gohr
1214fd6a1d7SAndreas Gohr    /**
1224fd6a1d7SAndreas Gohr     * Check if installed dependencies are conflicting
1234fd6a1d7SAndreas Gohr     * @return void
1244fd6a1d7SAndreas Gohr     */
1254fd6a1d7SAndreas Gohr    protected function checkConflicts()
1264fd6a1d7SAndreas Gohr    {
1274fd6a1d7SAndreas Gohr        $conflicts = $this->extension->getConflictList();
1284fd6a1d7SAndreas Gohr        $found = [];
1294fd6a1d7SAndreas Gohr        foreach ($conflicts as $conflict) {
1304fd6a1d7SAndreas Gohr            $dep = Extension::createFromId($conflict);
1314fd6a1d7SAndreas Gohr            if ($dep->isInstalled()) $found[] = $dep;
1324fd6a1d7SAndreas Gohr        }
1334fd6a1d7SAndreas Gohr        if (!$found) return;
1344fd6a1d7SAndreas Gohr
1354fd6a1d7SAndreas Gohr        $this->notices[self::WARNING][] = sprintf(
1364fd6a1d7SAndreas Gohr            $this->getLang('found_conflict'),
1377c184cfcSAndreas Gohr            implode(', ', array_map(static fn(Extension $dep) => $dep->getId(true), $found))
1384fd6a1d7SAndreas Gohr        );
1394fd6a1d7SAndreas Gohr    }
1404fd6a1d7SAndreas Gohr
1414fd6a1d7SAndreas Gohr    /**
1424fd6a1d7SAndreas Gohr     * Check for security issues
1434fd6a1d7SAndreas Gohr     * @return void
1444fd6a1d7SAndreas Gohr     */
1454fd6a1d7SAndreas Gohr    protected function checkSecurity()
1464fd6a1d7SAndreas Gohr    {
1474fd6a1d7SAndreas Gohr        if ($issue = $this->extension->getSecurityIssue()) {
1484fd6a1d7SAndreas Gohr            $this->notices[self::SECURITY][] = sprintf($this->getLang('security_issue'), $issue);
1494fd6a1d7SAndreas Gohr        }
1504fd6a1d7SAndreas Gohr        if ($issue = $this->extension->getSecurityWarning()) {
151cf461f20SAndreas Gohr            $this->notices[self::SECURITY][] = sprintf($this->getLang('security_warning'), $issue);
1524fd6a1d7SAndreas Gohr        }
1534fd6a1d7SAndreas Gohr    }
1544fd6a1d7SAndreas Gohr
1554fd6a1d7SAndreas Gohr    /**
1564fd6a1d7SAndreas Gohr     * Check if the extension is installed in correct folder
1574fd6a1d7SAndreas Gohr     * @return void
1584fd6a1d7SAndreas Gohr     */
1594fd6a1d7SAndreas Gohr    protected function checkFolder()
1604fd6a1d7SAndreas Gohr    {
1614fd6a1d7SAndreas Gohr        if (!$this->extension->isInWrongFolder()) return;
1624fd6a1d7SAndreas Gohr
1634fd6a1d7SAndreas Gohr        $this->notices[self::ERROR][] = sprintf(
1644fd6a1d7SAndreas Gohr            $this->getLang('wrong_folder'),
1654fd6a1d7SAndreas Gohr            basename($this->extension->getCurrentDir()),
1664fd6a1d7SAndreas Gohr            basename($this->extension->getInstallDir())
1674fd6a1d7SAndreas Gohr        );
1684fd6a1d7SAndreas Gohr    }
1694fd6a1d7SAndreas Gohr
1704fd6a1d7SAndreas Gohr    /**
1714fd6a1d7SAndreas Gohr     * Check PHP requirements
1724fd6a1d7SAndreas Gohr     * @return void
1734fd6a1d7SAndreas Gohr     */
1744fd6a1d7SAndreas Gohr    protected function checkPHPVersion()
1754fd6a1d7SAndreas Gohr    {
1764fd6a1d7SAndreas Gohr        try {
1774fd6a1d7SAndreas Gohr            Installer::ensurePhpCompatibility($this->extension);
1784fd6a1d7SAndreas Gohr        } catch (\Exception $e) {
1794fd6a1d7SAndreas Gohr            $this->notices[self::ERROR][] = $e->getMessage();
1804fd6a1d7SAndreas Gohr        }
1814fd6a1d7SAndreas Gohr    }
1824fd6a1d7SAndreas Gohr
1834fd6a1d7SAndreas Gohr    /**
1844fd6a1d7SAndreas Gohr     * Check for update message
1854fd6a1d7SAndreas Gohr     * @return void
1864fd6a1d7SAndreas Gohr     */
1874fd6a1d7SAndreas Gohr    protected function checkUpdateMessage()
1884fd6a1d7SAndreas Gohr    {
189d98308b7SAndreas Gohr        // only display this for installed extensions
190d98308b7SAndreas Gohr        if (!$this->extension->isInstalled()) return;
1914fd6a1d7SAndreas Gohr        if ($msg = $this->extension->getUpdateMessage()) {
1924fd6a1d7SAndreas Gohr            $this->notices[self::WARNING][] = sprintf($this->getLang('update_message'), $msg);
1934fd6a1d7SAndreas Gohr        }
1944fd6a1d7SAndreas Gohr    }
1954fd6a1d7SAndreas Gohr
1964fd6a1d7SAndreas Gohr    /**
1974fd6a1d7SAndreas Gohr     * Check for URL changes
1984fd6a1d7SAndreas Gohr     * @return void
1994fd6a1d7SAndreas Gohr     */
2004fd6a1d7SAndreas Gohr    protected function checkURLChange()
2014fd6a1d7SAndreas Gohr    {
2024fd6a1d7SAndreas Gohr        if (!$this->extension->hasChangedURL()) return;
2034fd6a1d7SAndreas Gohr        $this->notices[self::WARNING][] = sprintf(
2044fd6a1d7SAndreas Gohr            $this->getLang('url_change'),
2054fd6a1d7SAndreas Gohr            $this->extension->getDownloadURL(),
2064fd6a1d7SAndreas Gohr            $this->extension->getManager()->getDownloadURL()
2074fd6a1d7SAndreas Gohr        );
2084fd6a1d7SAndreas Gohr    }
2094fd6a1d7SAndreas Gohr
210981e70caSAndreas Gohr    /**
211981e70caSAndreas Gohr     * Check if the extension dir has the correct permissions to change
212981e70caSAndreas Gohr     *
213981e70caSAndreas Gohr     * @return void
214981e70caSAndreas Gohr     */
215981e70caSAndreas Gohr    protected function checkPermissions()
216981e70caSAndreas Gohr    {
217981e70caSAndreas Gohr        try {
218981e70caSAndreas Gohr            Installer::ensurePermissions($this->extension);
219981e70caSAndreas Gohr        } catch (\Exception $e) {
220981e70caSAndreas Gohr            $this->notices[self::ERROR][] = $e->getMessage();
221981e70caSAndreas Gohr        }
222981e70caSAndreas Gohr    }
223981e70caSAndreas Gohr
224981e70caSAndreas Gohr    /**
225981e70caSAndreas Gohr     * Hint about unused auth plugins
226981e70caSAndreas Gohr     *
227981e70caSAndreas Gohr     * @return void
228981e70caSAndreas Gohr     */
229981e70caSAndreas Gohr    protected function checkUnusedAuth()
230981e70caSAndreas Gohr    {
231981e70caSAndreas Gohr        global $conf;
232981e70caSAndreas Gohr        if (
233981e70caSAndreas Gohr            $this->extension->isEnabled() &&
234981e70caSAndreas Gohr            in_array('Auth', $this->extension->getComponentTypes()) &&
235981e70caSAndreas Gohr            $conf['authtype'] != $this->extension->getID()
236981e70caSAndreas Gohr        ) {
237981e70caSAndreas Gohr            $this->notices[self::INFO][] = $this->getLang('auth');
238981e70caSAndreas Gohr        }
239981e70caSAndreas Gohr    }
240981e70caSAndreas Gohr
241981e70caSAndreas Gohr    /**
242981e70caSAndreas Gohr     * Hint about installations by git
243981e70caSAndreas Gohr     *
244981e70caSAndreas Gohr     * @return void
245981e70caSAndreas Gohr     */
246981e70caSAndreas Gohr    protected function checkGit()
247981e70caSAndreas Gohr    {
248981e70caSAndreas Gohr        if ($this->extension->isGitControlled()) {
249981e70caSAndreas Gohr            $this->notices[self::INFO][] = $this->getLang('git');
250981e70caSAndreas Gohr        }
251981e70caSAndreas Gohr    }
2524fd6a1d7SAndreas Gohr}
253