xref: /plugin/publish/helper.php (revision 3a8f43c6d83821f2d2afd7db12b025e41c71c1da)
1f576111dSAndreas Gohr<?php
2f576111dSAndreas Gohr/**
3f576111dSAndreas Gohr * DokuWiki Plugin publish (Helper Component)
4f576111dSAndreas Gohr *
5f576111dSAndreas Gohr * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
6f576111dSAndreas Gohr * @author  Jarrod Lowe <dokuwiki@rrod.net>
7f576111dSAndreas Gohr * @author  Andreas Gohr <gohr@cosmocode.de>
8f576111dSAndreas Gohr */
9f576111dSAndreas Gohr
10f576111dSAndreas Gohr// must be run within Dokuwiki
11f576111dSAndreas Gohrif (!defined('DOKU_INC')) die();
12f576111dSAndreas Gohr
13f576111dSAndreas Gohrclass helper_plugin_publish extends DokuWiki_Plugin {
14f576111dSAndreas Gohr
151794c5faSDominik Eckelmann    private $sortedApprovedRevisions = null;
161794c5faSDominik Eckelmann
17*3a8f43c6SMichael Große    /**
18*3a8f43c6SMichael Große     * checks if an id is within one of the namespaces in $namespace_list
19*3a8f43c6SMichael Große     *
20*3a8f43c6SMichael Große     * @param string $namespace_list
21*3a8f43c6SMichael Große     * @param string $id
22*3a8f43c6SMichael Große     *
23*3a8f43c6SMichael Große     * @return bool
24*3a8f43c6SMichael Große     */
25338dbf1cSMichael Große    function in_namespace($namespace_list, $id) {
26f576111dSAndreas Gohr        // PHP apparantly does not have closures -
27f576111dSAndreas Gohr        // so we will parse $valid ourselves. Wasteful.
28338dbf1cSMichael Große        $namespace_list = preg_split('/\s+/', $namespace_list);
29f576111dSAndreas Gohr        //if(count($valid) == 0) { return true; }//whole wiki matches
30338dbf1cSMichael Große        if((count($namespace_list)==1) and ($namespace_list[0]=="")) { return true; }//whole wiki matches
31338dbf1cSMichael Große        $id = trim($id, ':');
32338dbf1cSMichael Große        $id = explode(':', $id);
33f576111dSAndreas Gohr
34f576111dSAndreas Gohr        // Check against all possible namespaces
35338dbf1cSMichael Große        foreach($namespace_list as $namespace) {
36338dbf1cSMichael Große            $namespace = explode(':', $namespace);
37338dbf1cSMichael Große            $current_ns_depth = 0;
38338dbf1cSMichael Große            $total_ns_depth = count($namespace);
39338dbf1cSMichael Große            $matching = true;
40f576111dSAndreas Gohr
41f576111dSAndreas Gohr            // Check each element, untill all elements of $v satisfied
42338dbf1cSMichael Große            while($current_ns_depth < $total_ns_depth) {
43338dbf1cSMichael Große                if($namespace[$current_ns_depth] != $id[$current_ns_depth]) {
44f576111dSAndreas Gohr                    // not a match
45338dbf1cSMichael Große                    $matching = false;
46f576111dSAndreas Gohr                    break;
47f576111dSAndreas Gohr                }
48338dbf1cSMichael Große                $current_ns_depth += 1;
49f576111dSAndreas Gohr            }
50338dbf1cSMichael Große            if($matching) { return true; } // a match
51f576111dSAndreas Gohr        }
52f576111dSAndreas Gohr        return false;
53f576111dSAndreas Gohr    }
54f576111dSAndreas Gohr
55f576111dSAndreas Gohr    // FIXME find out what this is supposed to do and how it can be done better
56f576111dSAndreas Gohr    function in_sub_namespace($valid, $check) {
57f576111dSAndreas Gohr        // is check a dir which contains any valid?
58f576111dSAndreas Gohr        // PHP apparantly does not have closures -
59f576111dSAndreas Gohr        // so we will parse $valid ourselves. Wasteful.
60f576111dSAndreas Gohr        $valid = preg_split('/\s+/', $valid);
61f576111dSAndreas Gohr        //if(count($valid) == 0) { return true; }//whole wiki matches
62f576111dSAndreas Gohr        if((count($valid)==1) and ($valid[0]=="")) { return true; }//whole wiki matches
63f576111dSAndreas Gohr        $check = trim($check, ':');
64f576111dSAndreas Gohr        $check = explode(':', $check);
65f576111dSAndreas Gohr
66f576111dSAndreas Gohr        // Check against all possible namespaces
67f576111dSAndreas Gohr        foreach($valid as $v) {
68f576111dSAndreas Gohr            $v = explode(':', $v);
69f576111dSAndreas Gohr            $n = 0;
70f576111dSAndreas Gohr            $c = count($check); //this is what is different from above!
71f576111dSAndreas Gohr            $matching = 1;
72f576111dSAndreas Gohr
73f576111dSAndreas Gohr            // Check each element, untill all elements of $v satisfied
74f576111dSAndreas Gohr            while($n < $c) {
75f576111dSAndreas Gohr                if($v[$n] != $check[$n]) {
76f576111dSAndreas Gohr                    // not a match
77f576111dSAndreas Gohr                    $matching = 0;
78f576111dSAndreas Gohr                    break;
79f576111dSAndreas Gohr                }
80f576111dSAndreas Gohr                $n += 1;
81f576111dSAndreas Gohr            }
82f576111dSAndreas Gohr            if($matching == 1) { return true; } // a match
83f576111dSAndreas Gohr        }
84f576111dSAndreas Gohr        return false;
85f576111dSAndreas Gohr    }
86f576111dSAndreas Gohr
871794c5faSDominik Eckelmann    function canApprove() {
881794c5faSDominik Eckelmann        global $INFO;
891794c5faSDominik Eckelmann        global $ID;
901794c5faSDominik Eckelmann
911794c5faSDominik Eckelmann        if (!$this->in_namespace($this->getConf('apr_namespaces'), $ID)) {
921794c5faSDominik Eckelmann            return false;
931794c5faSDominik Eckelmann        }
941794c5faSDominik Eckelmann
951794c5faSDominik Eckelmann        return ($INFO['perm'] >= AUTH_DELETE);
961794c5faSDominik Eckelmann    }
971794c5faSDominik Eckelmann
9881e0fa51SDominik Eckelmann    function getRevision($id = null) {
9981e0fa51SDominik Eckelmann        global $REV;
10081e0fa51SDominik Eckelmann        if (isset($REV) && !empty($REV)) {
10181e0fa51SDominik Eckelmann            return $REV;
1021794c5faSDominik Eckelmann        }
10381e0fa51SDominik Eckelmann        $meta = $this->getMeta($id);
10481e0fa51SDominik Eckelmann        if (isset($meta['last_change']['date'])) {
10581e0fa51SDominik Eckelmann            return $meta['last_change']['date'];
10681e0fa51SDominik Eckelmann        }
10781e0fa51SDominik Eckelmann        return $meta['date']['modified'];
1081794c5faSDominik Eckelmann    }
1091794c5faSDominik Eckelmann
11014c32fa0SDominik Eckelmann    function getApprovals($id = null) {
11114c32fa0SDominik Eckelmann        $meta = $this->getMeta($id);
11281e0fa51SDominik Eckelmann        if (!isset($meta['approval'])) {
1131794c5faSDominik Eckelmann            return array();
1141794c5faSDominik Eckelmann        }
11581e0fa51SDominik Eckelmann        $approvals = $meta['approval'];
1164e55e2a1SDominik Eckelmann        if (!is_array($approvals)) {
1174e55e2a1SDominik Eckelmann            return array();
1184e55e2a1SDominik Eckelmann        }
1191794c5faSDominik Eckelmann        return $approvals;
1201794c5faSDominik Eckelmann    }
1211794c5faSDominik Eckelmann
12214c32fa0SDominik Eckelmann    function getMeta($id = null) {
12314c32fa0SDominik Eckelmann        global $ID;
12414c32fa0SDominik Eckelmann        global $INFO;
12571b30300SAndreas Gohr
12671b30300SAndreas Gohr        if ($id === null) $id = $ID;
12771b30300SAndreas Gohr
12871b30300SAndreas Gohr        if($ID === $id && $INFO['meta']) {
1291317c887SDominik Eckelmann            $meta = $INFO['meta'];
13014c32fa0SDominik Eckelmann        } else {
1311317c887SDominik Eckelmann            $meta = p_get_metadata($id);
13214c32fa0SDominik Eckelmann        }
1331317c887SDominik Eckelmann
1341317c887SDominik Eckelmann        $this->checkApprovalFormat($meta, $id);
1351317c887SDominik Eckelmann
1361317c887SDominik Eckelmann        return $meta;
1371317c887SDominik Eckelmann    }
1381317c887SDominik Eckelmann
1391317c887SDominik Eckelmann    function checkApprovalFormat($meta, $id) {
1401317c887SDominik Eckelmann        if (isset($meta['approval_version']) && $meta['approval_version'] >= 2) {
1411317c887SDominik Eckelmann            return;
1421317c887SDominik Eckelmann        }
1431317c887SDominik Eckelmann
1441317c887SDominik Eckelmann        if (!$this->hasApprovals($meta)) {
1451317c887SDominik Eckelmann            return;
1461317c887SDominik Eckelmann        }
1471317c887SDominik Eckelmann
1481317c887SDominik Eckelmann        $approvals = $meta['approval'];
1491317c887SDominik Eckelmann        foreach (array_keys($approvals) as $approvedId) {
1501317c887SDominik Eckelmann            $keys = array_keys($approvals[$approvedId]);
1511317c887SDominik Eckelmann
1521317c887SDominik Eckelmann            if (is_array($approvals[$approvedId][$keys[0]])) {
1531317c887SDominik Eckelmann                continue; // current format
1541317c887SDominik Eckelmann            }
1551317c887SDominik Eckelmann
1561317c887SDominik Eckelmann            $newEntry = $approvals[$approvedId];
1571317c887SDominik Eckelmann            if (count($newEntry) !== 3) {
1581317c887SDominik Eckelmann                //continue; // some messed up format...
1591317c887SDominik Eckelmann            }
1601317c887SDominik Eckelmann            $newEntry[] = intval($approvedId); // revision is the time of page edit
1611317c887SDominik Eckelmann
1621317c887SDominik Eckelmann            $approvals[$approvedId] = array();
1631317c887SDominik Eckelmann            $approvals[$approvedId][$newEntry[0]] = $newEntry;
1641317c887SDominik Eckelmann        }
1651317c887SDominik Eckelmann        p_set_metadata($id, array('approval' => $approvals), true, true);
1661317c887SDominik Eckelmann        p_set_metadata($id, array('approval_version' => 2), true, true);
1671317c887SDominik Eckelmann    }
1681317c887SDominik Eckelmann
1691317c887SDominik Eckelmann    function hasApprovals($meta) {
1701317c887SDominik Eckelmann        return isset($meta['approval']) && !empty($meta['approval']);
17114c32fa0SDominik Eckelmann    }
17214c32fa0SDominik Eckelmann
1731794c5faSDominik Eckelmann    function getApprovalsOnRevision($revision) {
1741794c5faSDominik Eckelmann        $approvals = $this->getApprovals();
1751794c5faSDominik Eckelmann
1761794c5faSDominik Eckelmann        if (isset($approvals[$revision])) {
1771794c5faSDominik Eckelmann            return $approvals[$revision];
1781794c5faSDominik Eckelmann        }
1791794c5faSDominik Eckelmann        return array();
1801794c5faSDominik Eckelmann    }
1811794c5faSDominik Eckelmann
1825eecc2e6SDominik Eckelmann    function getSortedApprovedRevisions($id = null) {
1835eecc2e6SDominik Eckelmann        if ($id === null) {
1845eecc2e6SDominik Eckelmann            global $ID;
1855eecc2e6SDominik Eckelmann            $id = $ID;
1861794c5faSDominik Eckelmann        }
1875eecc2e6SDominik Eckelmann
1885eecc2e6SDominik Eckelmann        static $sortedApprovedRevisions = array();
1895eecc2e6SDominik Eckelmann        if (!isset($sortedApprovedRevisions[$id])) {
1905eecc2e6SDominik Eckelmann            $approvals = $this->getApprovals($id);
1915eecc2e6SDominik Eckelmann            krsort($approvals);
1925eecc2e6SDominik Eckelmann            $sortedApprovedRevisions[$id] = $approvals;
1935eecc2e6SDominik Eckelmann        }
1945eecc2e6SDominik Eckelmann
1955eecc2e6SDominik Eckelmann        return $sortedApprovedRevisions[$id];
1961794c5faSDominik Eckelmann    }
1971794c5faSDominik Eckelmann
19814c32fa0SDominik Eckelmann    function isRevisionApproved($revision, $id = null) {
19914c32fa0SDominik Eckelmann        $approvals = $this->getApprovals($id);
2001794c5faSDominik Eckelmann        if (!isset($approvals[$revision])) {
2011794c5faSDominik Eckelmann            return false;
2021794c5faSDominik Eckelmann        }
2031794c5faSDominik Eckelmann        return (count($approvals[$revision]) >= $this->getConf('number_of_approved'));
2041794c5faSDominik Eckelmann    }
2051794c5faSDominik Eckelmann
20681e0fa51SDominik Eckelmann    function isCurrentRevisionApproved($id = null) {
20781e0fa51SDominik Eckelmann        return $this->isRevisionApproved($this->getRevision($id), $id);
2081794c5faSDominik Eckelmann    }
2091794c5faSDominik Eckelmann
2105eecc2e6SDominik Eckelmann    function getLatestApprovedRevision($id = null) {
2115eecc2e6SDominik Eckelmann        $approvals = $this->getSortedApprovedRevisions($id);
2121794c5faSDominik Eckelmann        foreach ($approvals as $revision => $ignored) {
2135eecc2e6SDominik Eckelmann            if ($this->isRevisionApproved($revision, $id)) {
2141794c5faSDominik Eckelmann                return $revision;
2151794c5faSDominik Eckelmann            }
2161794c5faSDominik Eckelmann        }
2171794c5faSDominik Eckelmann        return 0;
2181794c5faSDominik Eckelmann    }
2191794c5faSDominik Eckelmann
2201794c5faSDominik Eckelmann    function getLastestRevision() {
2211794c5faSDominik Eckelmann        global $INFO;
2221794c5faSDominik Eckelmann        return $INFO['meta']['date']['modified'];
2231794c5faSDominik Eckelmann    }
2241794c5faSDominik Eckelmann
2251794c5faSDominik Eckelmann    function getApprovalDate() {
2261794c5faSDominik Eckelmann        if (!$this->isCurrentRevisionApproved()) {
2271794c5faSDominik Eckelmann            return -1;
2281794c5faSDominik Eckelmann        }
2291794c5faSDominik Eckelmann
2301794c5faSDominik Eckelmann        $approvals = $this->getApprovalsOnRevision($this->getRevision());
2311794c5faSDominik Eckelmann        uasort($approvals, array(&$this, 'cmpApprovals'));
2321794c5faSDominik Eckelmann        $keys = array_keys($approvals);
2331794c5faSDominik Eckelmann        return $approvals[$keys[$this->getConf('number_of_approved') -1]][3];
2341794c5faSDominik Eckelmann
2351794c5faSDominik Eckelmann    }
2361794c5faSDominik Eckelmann
2371794c5faSDominik Eckelmann    function cmpApprovals($left, $right) {
2381794c5faSDominik Eckelmann        if ($left[3] == $right[3]) {
2391794c5faSDominik Eckelmann            return 0;
2401794c5faSDominik Eckelmann        }
2411794c5faSDominik Eckelmann        return ($left[3] < $right[3]) ? -1 : 1;
2421794c5faSDominik Eckelmann    }
2431794c5faSDominik Eckelmann
2441794c5faSDominik Eckelmann    function getApprovers() {
2451794c5faSDominik Eckelmann        $approvers = $this->getApprovalsOnRevision($this->getRevision());
2461317c887SDominik Eckelmann        if (count($approvers) === 0) {
2471317c887SDominik Eckelmann            return;
2481317c887SDominik Eckelmann        }
2491317c887SDominik Eckelmann
2501794c5faSDominik Eckelmann        $result = array();
2511794c5faSDominik Eckelmann        foreach ($approvers as $approver) {
2521794c5faSDominik Eckelmann            $result[] = editorinfo($this->getApproverName($approver));
2531794c5faSDominik Eckelmann        }
2541794c5faSDominik Eckelmann        return $result;
2551794c5faSDominik Eckelmann    }
2561794c5faSDominik Eckelmann
2571794c5faSDominik Eckelmann    function getApproverName($approver) {
2581794c5faSDominik Eckelmann        if ($approver[1]) {
2591794c5faSDominik Eckelmann            return $approver[1];
2601794c5faSDominik Eckelmann        }
2611794c5faSDominik Eckelmann        if ($approver[2]) {
2621794c5faSDominik Eckelmann            return $approver[2];
2631794c5faSDominik Eckelmann        }
2641794c5faSDominik Eckelmann        return $approver[0];
2651794c5faSDominik Eckelmann    }
2661794c5faSDominik Eckelmann
2671794c5faSDominik Eckelmann    function getPreviousApprovedRevision() {
2681794c5faSDominik Eckelmann        $currentRevision = $this->getRevision();
2691794c5faSDominik Eckelmann        $approvals = $this->getSortedApprovedRevisions();
2701794c5faSDominik Eckelmann        foreach ($approvals as $revision => $ignored) {
2711794c5faSDominik Eckelmann            if ($revision >= $currentRevision) {
2721794c5faSDominik Eckelmann                continue;
2731794c5faSDominik Eckelmann            }
2741794c5faSDominik Eckelmann            if ($this->isRevisionApproved($revision)) {
2751794c5faSDominik Eckelmann                return $revision;
2761794c5faSDominik Eckelmann            }
2771794c5faSDominik Eckelmann        }
2781794c5faSDominik Eckelmann        return 0;
2791794c5faSDominik Eckelmann    }
2801794c5faSDominik Eckelmann
2815eecc2e6SDominik Eckelmann    function isHidden($id = null) {
282c2a737a8SDominik Eckelmann        if (!$this->getConf('hide drafts')) {
283c2a737a8SDominik Eckelmann            return false;
284c2a737a8SDominik Eckelmann        }
285a178f455SRené Corinth
286a178f455SRené Corinth        // needs to check if the actual namespace belongs to the apr_namespaces
28703cac644SChristopher Smith        if ($id == null) {
288cf46f4c9SRené Corinth            global $ID;
28903cac644SChristopher Smith            $id = $ID;
29003cac644SChristopher Smith        }
29103cac644SChristopher Smith        if (!$this->isActive($id)) {
292a178f455SRené Corinth            return false;
293a178f455SRené Corinth        }
294a178f455SRené Corinth
2955eecc2e6SDominik Eckelmann        if ($this->getLatestApprovedRevision($id)) {
296c2a737a8SDominik Eckelmann            return false;
297c2a737a8SDominik Eckelmann        }
2982b00c146SDominik Eckelmann        return true;
2992b00c146SDominik Eckelmann    }
300c2a737a8SDominik Eckelmann
3015eecc2e6SDominik Eckelmann    function isHiddenForUser($id = null) {
3025eecc2e6SDominik Eckelmann        if (!$this->isHidden($id)) {
3032b00c146SDominik Eckelmann            return false;
3042b00c146SDominik Eckelmann        }
3052b00c146SDominik Eckelmann
3065eecc2e6SDominik Eckelmann        if ($id == null) {
3072b00c146SDominik Eckelmann            global $ID;
3085eecc2e6SDominik Eckelmann            $id = $ID;
3095eecc2e6SDominik Eckelmann        }
3105eecc2e6SDominik Eckelmann
311c2a737a8SDominik Eckelmann        $allowedGroups = array_filter(explode(' ', trim($this->getConf('author groups'))));
312c2a737a8SDominik Eckelmann        if (empty($allowedGroups)) {
3135eecc2e6SDominik Eckelmann            return auth_quickaclcheck($id) < AUTH_EDIT;
314c2a737a8SDominik Eckelmann        }
315c2a737a8SDominik Eckelmann
316c2a737a8SDominik Eckelmann        if (!$_SERVER['REMOTE_USER']) {
317c2a737a8SDominik Eckelmann            return true;
318c2a737a8SDominik Eckelmann        }
319c2a737a8SDominik Eckelmann
320c2a737a8SDominik Eckelmann        global $USERINFO;
321c2a737a8SDominik Eckelmann        foreach ($allowedGroups as $allowedGroup) {
322c2a737a8SDominik Eckelmann            $allowedGroup = trim($allowedGroup);
323c2a737a8SDominik Eckelmann            if (in_array($allowedGroup, $USERINFO['grps'])) {
324c2a737a8SDominik Eckelmann                return false;
325c2a737a8SDominik Eckelmann            }
326c2a737a8SDominik Eckelmann        }
327c2a737a8SDominik Eckelmann        return true;
328c2a737a8SDominik Eckelmann    }
329d9258364SDominik Eckelmann
33003cac644SChristopher Smith    function isActive($id = null) {
33103cac644SChristopher Smith        if ($id == null) {
332d9258364SDominik Eckelmann            global $ID;
33303cac644SChristopher Smith            $id = $ID;
33403cac644SChristopher Smith        }
33503cac644SChristopher Smith        if (!$this->in_namespace($this->getConf('apr_namespaces'), $id)) {
336d9258364SDominik Eckelmann            return false;
337d9258364SDominik Eckelmann        }
338d9258364SDominik Eckelmann
339d9258364SDominik Eckelmann        $no_apr_namespaces = $this->getConf('no_apr_namespaces');
340d9258364SDominik Eckelmann        if (!empty($no_apr_namespaces)) {
34103cac644SChristopher Smith            if ($this->in_namespace($no_apr_namespaces, $id)) {
342d9258364SDominik Eckelmann                return false;
343d9258364SDominik Eckelmann            }
344d9258364SDominik Eckelmann        }
345d9258364SDominik Eckelmann        return true;
346d9258364SDominik Eckelmann    }
347bfc3639fSMichael Große
348bfc3639fSMichael Große    /**
349bfc3639fSMichael Große     * Create absolute diff-link between the two given revisions
350bfc3639fSMichael Große     *
351bfc3639fSMichael Große     * @param string $id
352bfc3639fSMichael Große     * @param int $rev1
353bfc3639fSMichael Große     * @param int $rev2
354bfc3639fSMichael Große     * @return string Diff-Link or empty string if $rev1 == $rev2
355bfc3639fSMichael Große     */
356bfc3639fSMichael Große    public function getDifflink($id, $rev1, $rev2) {
357bfc3639fSMichael Große        if($rev1 == $rev2) {
358bfc3639fSMichael Große            return '';
359bfc3639fSMichael Große        }
360bfc3639fSMichael Große        $params = 'do=diff,rev2[0]=' . $rev1 . ',rev2[1]=' . $rev2 . ',difftype=sidebyside';
361bfc3639fSMichael Große        $difflink = wl($id, $params,true,'&');
362bfc3639fSMichael Große        return $difflink;
363bfc3639fSMichael Große    }
364bfc3639fSMichael Große
365f576111dSAndreas Gohr}
366