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 17f576111dSAndreas Gohr // FIXME find out what this is supposed to do and how it can be done better 18f576111dSAndreas Gohr function in_namespace($valid, $check) { 19f576111dSAndreas Gohr // PHP apparantly does not have closures - 20f576111dSAndreas Gohr // so we will parse $valid ourselves. Wasteful. 21f576111dSAndreas Gohr $valid = preg_split('/\s+/', $valid); 22f576111dSAndreas Gohr //if(count($valid) == 0) { return true; }//whole wiki matches 23f576111dSAndreas Gohr if((count($valid)==1) and ($valid[0]=="")) { return true; }//whole wiki matches 24f576111dSAndreas Gohr $check = trim($check, ':'); 25f576111dSAndreas Gohr $check = explode(':', $check); 26f576111dSAndreas Gohr 27f576111dSAndreas Gohr // Check against all possible namespaces 28f576111dSAndreas Gohr foreach($valid as $v) { 29f576111dSAndreas Gohr $v = explode(':', $v); 30f576111dSAndreas Gohr $n = 0; 31f576111dSAndreas Gohr $c = count($v); 32f576111dSAndreas Gohr $matching = 1; 33f576111dSAndreas Gohr 34f576111dSAndreas Gohr // Check each element, untill all elements of $v satisfied 35f576111dSAndreas Gohr while($n < $c) { 36f576111dSAndreas Gohr if($v[$n] != $check[$n]) { 37f576111dSAndreas Gohr // not a match 38f576111dSAndreas Gohr $matching = 0; 39f576111dSAndreas Gohr break; 40f576111dSAndreas Gohr } 41f576111dSAndreas Gohr $n += 1; 42f576111dSAndreas Gohr } 43f576111dSAndreas Gohr if($matching == 1) { return true; } // a match 44f576111dSAndreas Gohr } 45f576111dSAndreas Gohr return false; 46f576111dSAndreas Gohr } 47f576111dSAndreas Gohr 48f576111dSAndreas Gohr // FIXME find out what this is supposed to do and how it can be done better 49f576111dSAndreas Gohr function in_sub_namespace($valid, $check) { 50f576111dSAndreas Gohr // is check a dir which contains any valid? 51f576111dSAndreas Gohr // PHP apparantly does not have closures - 52f576111dSAndreas Gohr // so we will parse $valid ourselves. Wasteful. 53f576111dSAndreas Gohr $valid = preg_split('/\s+/', $valid); 54f576111dSAndreas Gohr //if(count($valid) == 0) { return true; }//whole wiki matches 55f576111dSAndreas Gohr if((count($valid)==1) and ($valid[0]=="")) { return true; }//whole wiki matches 56f576111dSAndreas Gohr $check = trim($check, ':'); 57f576111dSAndreas Gohr $check = explode(':', $check); 58f576111dSAndreas Gohr 59f576111dSAndreas Gohr // Check against all possible namespaces 60f576111dSAndreas Gohr foreach($valid as $v) { 61f576111dSAndreas Gohr $v = explode(':', $v); 62f576111dSAndreas Gohr $n = 0; 63f576111dSAndreas Gohr $c = count($check); //this is what is different from above! 64f576111dSAndreas Gohr $matching = 1; 65f576111dSAndreas Gohr 66f576111dSAndreas Gohr // Check each element, untill all elements of $v satisfied 67f576111dSAndreas Gohr while($n < $c) { 68f576111dSAndreas Gohr if($v[$n] != $check[$n]) { 69f576111dSAndreas Gohr // not a match 70f576111dSAndreas Gohr $matching = 0; 71f576111dSAndreas Gohr break; 72f576111dSAndreas Gohr } 73f576111dSAndreas Gohr $n += 1; 74f576111dSAndreas Gohr } 75f576111dSAndreas Gohr if($matching == 1) { return true; } // a match 76f576111dSAndreas Gohr } 77f576111dSAndreas Gohr return false; 78f576111dSAndreas Gohr } 79f576111dSAndreas Gohr 801794c5faSDominik Eckelmann function canApprove() { 811794c5faSDominik Eckelmann global $INFO; 821794c5faSDominik Eckelmann global $ID; 831794c5faSDominik Eckelmann 841794c5faSDominik Eckelmann if (!$this->in_namespace($this->getConf('apr_namespaces'), $ID)) { 851794c5faSDominik Eckelmann return false; 861794c5faSDominik Eckelmann } 871794c5faSDominik Eckelmann 881794c5faSDominik Eckelmann return ($INFO['perm'] >= AUTH_DELETE); 891794c5faSDominik Eckelmann } 901794c5faSDominik Eckelmann 9181e0fa51SDominik Eckelmann function getRevision($id = null) { 9281e0fa51SDominik Eckelmann global $REV; 9381e0fa51SDominik Eckelmann if (isset($REV) && !empty($REV)) { 9481e0fa51SDominik Eckelmann return $REV; 951794c5faSDominik Eckelmann } 9681e0fa51SDominik Eckelmann $meta = $this->getMeta($id); 9781e0fa51SDominik Eckelmann if (isset($meta['last_change']['date'])) { 9881e0fa51SDominik Eckelmann return $meta['last_change']['date']; 9981e0fa51SDominik Eckelmann } 10081e0fa51SDominik Eckelmann return $meta['date']['modified']; 1011794c5faSDominik Eckelmann } 1021794c5faSDominik Eckelmann 10314c32fa0SDominik Eckelmann function getApprovals($id = null) { 10414c32fa0SDominik Eckelmann $meta = $this->getMeta($id); 10581e0fa51SDominik Eckelmann if (!isset($meta['approval'])) { 1061794c5faSDominik Eckelmann return array(); 1071794c5faSDominik Eckelmann } 10881e0fa51SDominik Eckelmann $approvals = $meta['approval']; 1094e55e2a1SDominik Eckelmann if (!is_array($approvals)) { 1104e55e2a1SDominik Eckelmann return array(); 1114e55e2a1SDominik Eckelmann } 1121794c5faSDominik Eckelmann return $approvals; 1131794c5faSDominik Eckelmann } 1141794c5faSDominik Eckelmann 11514c32fa0SDominik Eckelmann function getMeta($id = null) { 11614c32fa0SDominik Eckelmann global $ID; 11714c32fa0SDominik Eckelmann global $INFO; 11871b30300SAndreas Gohr 11971b30300SAndreas Gohr if ($id === null) $id = $ID; 12071b30300SAndreas Gohr 12171b30300SAndreas Gohr if($ID === $id && $INFO['meta']) { 1221317c887SDominik Eckelmann $meta = $INFO['meta']; 12314c32fa0SDominik Eckelmann } else { 1241317c887SDominik Eckelmann $meta = p_get_metadata($id); 12514c32fa0SDominik Eckelmann } 1261317c887SDominik Eckelmann 1271317c887SDominik Eckelmann $this->checkApprovalFormat($meta, $id); 1281317c887SDominik Eckelmann 1291317c887SDominik Eckelmann return $meta; 1301317c887SDominik Eckelmann } 1311317c887SDominik Eckelmann 1321317c887SDominik Eckelmann function checkApprovalFormat($meta, $id) { 1331317c887SDominik Eckelmann if (isset($meta['approval_version']) && $meta['approval_version'] >= 2) { 1341317c887SDominik Eckelmann return; 1351317c887SDominik Eckelmann } 1361317c887SDominik Eckelmann 1371317c887SDominik Eckelmann if (!$this->hasApprovals($meta)) { 1381317c887SDominik Eckelmann return; 1391317c887SDominik Eckelmann } 1401317c887SDominik Eckelmann 1411317c887SDominik Eckelmann $approvals = $meta['approval']; 1421317c887SDominik Eckelmann foreach (array_keys($approvals) as $approvedId) { 1431317c887SDominik Eckelmann $keys = array_keys($approvals[$approvedId]); 1441317c887SDominik Eckelmann 1451317c887SDominik Eckelmann if (is_array($approvals[$approvedId][$keys[0]])) { 1461317c887SDominik Eckelmann continue; // current format 1471317c887SDominik Eckelmann } 1481317c887SDominik Eckelmann 1491317c887SDominik Eckelmann $newEntry = $approvals[$approvedId]; 1501317c887SDominik Eckelmann if (count($newEntry) !== 3) { 1511317c887SDominik Eckelmann //continue; // some messed up format... 1521317c887SDominik Eckelmann } 1531317c887SDominik Eckelmann $newEntry[] = intval($approvedId); // revision is the time of page edit 1541317c887SDominik Eckelmann 1551317c887SDominik Eckelmann $approvals[$approvedId] = array(); 1561317c887SDominik Eckelmann $approvals[$approvedId][$newEntry[0]] = $newEntry; 1571317c887SDominik Eckelmann } 1581317c887SDominik Eckelmann p_set_metadata($id, array('approval' => $approvals), true, true); 1591317c887SDominik Eckelmann p_set_metadata($id, array('approval_version' => 2), true, true); 1601317c887SDominik Eckelmann } 1611317c887SDominik Eckelmann 1621317c887SDominik Eckelmann function hasApprovals($meta) { 1631317c887SDominik Eckelmann return isset($meta['approval']) && !empty($meta['approval']); 16414c32fa0SDominik Eckelmann } 16514c32fa0SDominik Eckelmann 1661794c5faSDominik Eckelmann function getApprovalsOnRevision($revision) { 1671794c5faSDominik Eckelmann $approvals = $this->getApprovals(); 1681794c5faSDominik Eckelmann 1691794c5faSDominik Eckelmann if (isset($approvals[$revision])) { 1701794c5faSDominik Eckelmann return $approvals[$revision]; 1711794c5faSDominik Eckelmann } 1721794c5faSDominik Eckelmann return array(); 1731794c5faSDominik Eckelmann } 1741794c5faSDominik Eckelmann 1755eecc2e6SDominik Eckelmann function getSortedApprovedRevisions($id = null) { 1765eecc2e6SDominik Eckelmann if ($id === null) { 1775eecc2e6SDominik Eckelmann global $ID; 1785eecc2e6SDominik Eckelmann $id = $ID; 1791794c5faSDominik Eckelmann } 1805eecc2e6SDominik Eckelmann 1815eecc2e6SDominik Eckelmann static $sortedApprovedRevisions = array(); 1825eecc2e6SDominik Eckelmann if (!isset($sortedApprovedRevisions[$id])) { 1835eecc2e6SDominik Eckelmann $approvals = $this->getApprovals($id); 1845eecc2e6SDominik Eckelmann krsort($approvals); 1855eecc2e6SDominik Eckelmann $sortedApprovedRevisions[$id] = $approvals; 1865eecc2e6SDominik Eckelmann } 1875eecc2e6SDominik Eckelmann 1885eecc2e6SDominik Eckelmann return $sortedApprovedRevisions[$id]; 1891794c5faSDominik Eckelmann } 1901794c5faSDominik Eckelmann 19114c32fa0SDominik Eckelmann function isRevisionApproved($revision, $id = null) { 19214c32fa0SDominik Eckelmann $approvals = $this->getApprovals($id); 1931794c5faSDominik Eckelmann if (!isset($approvals[$revision])) { 1941794c5faSDominik Eckelmann return false; 1951794c5faSDominik Eckelmann } 1961794c5faSDominik Eckelmann return (count($approvals[$revision]) >= $this->getConf('number_of_approved')); 1971794c5faSDominik Eckelmann } 1981794c5faSDominik Eckelmann 19981e0fa51SDominik Eckelmann function isCurrentRevisionApproved($id = null) { 20081e0fa51SDominik Eckelmann return $this->isRevisionApproved($this->getRevision($id), $id); 2011794c5faSDominik Eckelmann } 2021794c5faSDominik Eckelmann 2035eecc2e6SDominik Eckelmann function getLatestApprovedRevision($id = null) { 2045eecc2e6SDominik Eckelmann $approvals = $this->getSortedApprovedRevisions($id); 2051794c5faSDominik Eckelmann foreach ($approvals as $revision => $ignored) { 2065eecc2e6SDominik Eckelmann if ($this->isRevisionApproved($revision, $id)) { 2071794c5faSDominik Eckelmann return $revision; 2081794c5faSDominik Eckelmann } 2091794c5faSDominik Eckelmann } 2101794c5faSDominik Eckelmann return 0; 2111794c5faSDominik Eckelmann } 2121794c5faSDominik Eckelmann 2131794c5faSDominik Eckelmann function getLastestRevision() { 2141794c5faSDominik Eckelmann global $INFO; 2151794c5faSDominik Eckelmann return $INFO['meta']['date']['modified']; 2161794c5faSDominik Eckelmann } 2171794c5faSDominik Eckelmann 2181794c5faSDominik Eckelmann function getApprovalDate() { 2191794c5faSDominik Eckelmann if (!$this->isCurrentRevisionApproved()) { 2201794c5faSDominik Eckelmann return -1; 2211794c5faSDominik Eckelmann } 2221794c5faSDominik Eckelmann 2231794c5faSDominik Eckelmann $approvals = $this->getApprovalsOnRevision($this->getRevision()); 2241794c5faSDominik Eckelmann uasort($approvals, array(&$this, 'cmpApprovals')); 2251794c5faSDominik Eckelmann $keys = array_keys($approvals); 2261794c5faSDominik Eckelmann return $approvals[$keys[$this->getConf('number_of_approved') -1]][3]; 2271794c5faSDominik Eckelmann 2281794c5faSDominik Eckelmann } 2291794c5faSDominik Eckelmann 2301794c5faSDominik Eckelmann function cmpApprovals($left, $right) { 2311794c5faSDominik Eckelmann if ($left[3] == $right[3]) { 2321794c5faSDominik Eckelmann return 0; 2331794c5faSDominik Eckelmann } 2341794c5faSDominik Eckelmann return ($left[3] < $right[3]) ? -1 : 1; 2351794c5faSDominik Eckelmann } 2361794c5faSDominik Eckelmann 2371794c5faSDominik Eckelmann function getApprovers() { 2381794c5faSDominik Eckelmann $approvers = $this->getApprovalsOnRevision($this->getRevision()); 2391317c887SDominik Eckelmann if (count($approvers) === 0) { 2401317c887SDominik Eckelmann return; 2411317c887SDominik Eckelmann } 2421317c887SDominik Eckelmann 2431794c5faSDominik Eckelmann $result = array(); 2441794c5faSDominik Eckelmann foreach ($approvers as $approver) { 2451794c5faSDominik Eckelmann $result[] = editorinfo($this->getApproverName($approver)); 2461794c5faSDominik Eckelmann } 2471794c5faSDominik Eckelmann return $result; 2481794c5faSDominik Eckelmann } 2491794c5faSDominik Eckelmann 2501794c5faSDominik Eckelmann function getApproverName($approver) { 2511794c5faSDominik Eckelmann if ($approver[1]) { 2521794c5faSDominik Eckelmann return $approver[1]; 2531794c5faSDominik Eckelmann } 2541794c5faSDominik Eckelmann if ($approver[2]) { 2551794c5faSDominik Eckelmann return $approver[2]; 2561794c5faSDominik Eckelmann } 2571794c5faSDominik Eckelmann return $approver[0]; 2581794c5faSDominik Eckelmann } 2591794c5faSDominik Eckelmann 2601794c5faSDominik Eckelmann function getPreviousApprovedRevision() { 2611794c5faSDominik Eckelmann $currentRevision = $this->getRevision(); 2621794c5faSDominik Eckelmann $approvals = $this->getSortedApprovedRevisions(); 2631794c5faSDominik Eckelmann foreach ($approvals as $revision => $ignored) { 2641794c5faSDominik Eckelmann if ($revision >= $currentRevision) { 2651794c5faSDominik Eckelmann continue; 2661794c5faSDominik Eckelmann } 2671794c5faSDominik Eckelmann if ($this->isRevisionApproved($revision)) { 2681794c5faSDominik Eckelmann return $revision; 2691794c5faSDominik Eckelmann } 2701794c5faSDominik Eckelmann } 2711794c5faSDominik Eckelmann return 0; 2721794c5faSDominik Eckelmann } 2731794c5faSDominik Eckelmann 2745eecc2e6SDominik Eckelmann function isHidden($id = null) { 275c2a737a8SDominik Eckelmann if (!$this->getConf('hide drafts')) { 276c2a737a8SDominik Eckelmann return false; 277c2a737a8SDominik Eckelmann } 278a178f455SRené Corinth 279a178f455SRené Corinth // needs to check if the actual namespace belongs to the apr_namespaces 28003cac644SChristopher Smith if ($id == null) { 281cf46f4c9SRené Corinth global $ID; 28203cac644SChristopher Smith $id = $ID; 28303cac644SChristopher Smith } 28403cac644SChristopher Smith if (!$this->isActive($id)) { 285a178f455SRené Corinth return false; 286a178f455SRené Corinth } 287a178f455SRené Corinth 2885eecc2e6SDominik Eckelmann if ($this->getLatestApprovedRevision($id)) { 289c2a737a8SDominik Eckelmann return false; 290c2a737a8SDominik Eckelmann } 2912b00c146SDominik Eckelmann return true; 2922b00c146SDominik Eckelmann } 293c2a737a8SDominik Eckelmann 2945eecc2e6SDominik Eckelmann function isHiddenForUser($id = null) { 2955eecc2e6SDominik Eckelmann if (!$this->isHidden($id)) { 2962b00c146SDominik Eckelmann return false; 2972b00c146SDominik Eckelmann } 2982b00c146SDominik Eckelmann 2995eecc2e6SDominik Eckelmann if ($id == null) { 3002b00c146SDominik Eckelmann global $ID; 3015eecc2e6SDominik Eckelmann $id = $ID; 3025eecc2e6SDominik Eckelmann } 3035eecc2e6SDominik Eckelmann 304c2a737a8SDominik Eckelmann $allowedGroups = array_filter(explode(' ', trim($this->getConf('author groups')))); 305c2a737a8SDominik Eckelmann if (empty($allowedGroups)) { 3065eecc2e6SDominik Eckelmann return auth_quickaclcheck($id) < AUTH_EDIT; 307c2a737a8SDominik Eckelmann } 308c2a737a8SDominik Eckelmann 309c2a737a8SDominik Eckelmann if (!$_SERVER['REMOTE_USER']) { 310c2a737a8SDominik Eckelmann return true; 311c2a737a8SDominik Eckelmann } 312c2a737a8SDominik Eckelmann 313c2a737a8SDominik Eckelmann global $USERINFO; 314c2a737a8SDominik Eckelmann foreach ($allowedGroups as $allowedGroup) { 315c2a737a8SDominik Eckelmann $allowedGroup = trim($allowedGroup); 316c2a737a8SDominik Eckelmann if (in_array($allowedGroup, $USERINFO['grps'])) { 317c2a737a8SDominik Eckelmann return false; 318c2a737a8SDominik Eckelmann } 319c2a737a8SDominik Eckelmann } 320c2a737a8SDominik Eckelmann return true; 321c2a737a8SDominik Eckelmann } 322d9258364SDominik Eckelmann 32303cac644SChristopher Smith function isActive($id = null) { 32403cac644SChristopher Smith if ($id == null) { 325d9258364SDominik Eckelmann global $ID; 32603cac644SChristopher Smith $id = $ID; 32703cac644SChristopher Smith } 32803cac644SChristopher Smith if (!$this->in_namespace($this->getConf('apr_namespaces'), $id)) { 329d9258364SDominik Eckelmann return false; 330d9258364SDominik Eckelmann } 331d9258364SDominik Eckelmann 332d9258364SDominik Eckelmann $no_apr_namespaces = $this->getConf('no_apr_namespaces'); 333d9258364SDominik Eckelmann if (!empty($no_apr_namespaces)) { 33403cac644SChristopher Smith if ($this->in_namespace($no_apr_namespaces, $id)) { 335d9258364SDominik Eckelmann return false; 336d9258364SDominik Eckelmann } 337d9258364SDominik Eckelmann } 338d9258364SDominik Eckelmann return true; 339d9258364SDominik Eckelmann } 340*bfc3639fSMichael Große 341*bfc3639fSMichael Große /** 342*bfc3639fSMichael Große * Create absolute diff-link between the two given revisions 343*bfc3639fSMichael Große * 344*bfc3639fSMichael Große * @param string $id 345*bfc3639fSMichael Große * @param int $rev1 346*bfc3639fSMichael Große * @param int $rev2 347*bfc3639fSMichael Große * @return string Diff-Link or empty string if $rev1 == $rev2 348*bfc3639fSMichael Große */ 349*bfc3639fSMichael Große public function getDifflink($id, $rev1, $rev2) { 350*bfc3639fSMichael Große if($rev1 == $rev2) { 351*bfc3639fSMichael Große return ''; 352*bfc3639fSMichael Große } 353*bfc3639fSMichael Große $params = 'do=diff,rev2[0]=' . $rev1 . ',rev2[1]=' . $rev2 . ',difftype=sidebyside'; 354*bfc3639fSMichael Große $difflink = wl($id, $params,true,'&'); 355*bfc3639fSMichael Große return $difflink; 356*bfc3639fSMichael Große } 357*bfc3639fSMichael Große 358f576111dSAndreas Gohr} 359