1910e7e15SAnna Dabrowska<?php 2910e7e15SAnna Dabrowska 3910e7e15SAnna Dabrowskanamespace dokuwiki\plugin\structpublish\meta; 4910e7e15SAnna Dabrowska 5910e7e15SAnna Dabrowska/** 6910e7e15SAnna Dabrowska * Class Assignments 7910e7e15SAnna Dabrowska * 8910e7e15SAnna Dabrowska * Manages the assignment of users to pages and namespaces 9910e7e15SAnna Dabrowska * This is a singleton. Assignment data is only loaded once per request. 10910e7e15SAnna Dabrowska * 11910e7e15SAnna Dabrowska * @see \dokuwiki\plugin\struct\meta\Assignments 12910e7e15SAnna Dabrowska */ 13910e7e15SAnna Dabrowskaclass Assignments 14910e7e15SAnna Dabrowska{ 15910e7e15SAnna Dabrowska /** @var \helper_plugin_sqlite|null */ 16910e7e15SAnna Dabrowska protected $sqlite; 17910e7e15SAnna Dabrowska 18910e7e15SAnna Dabrowska /** @var array All the assignments patterns */ 19910e7e15SAnna Dabrowska protected $patterns; 20910e7e15SAnna Dabrowska 21910e7e15SAnna Dabrowska /** @var Assignments */ 22910e7e15SAnna Dabrowska protected static $instance = null; 23910e7e15SAnna Dabrowska 24910e7e15SAnna Dabrowska /** 25910e7e15SAnna Dabrowska * Get the singleton instance of the Assignments 26910e7e15SAnna Dabrowska * 27910e7e15SAnna Dabrowska * @param bool $forcereload create a new instace to reload the assignment data 28910e7e15SAnna Dabrowska * @return Assignments 29910e7e15SAnna Dabrowska */ 30910e7e15SAnna Dabrowska public static function getInstance($forcereload = false) 31910e7e15SAnna Dabrowska { 32910e7e15SAnna Dabrowska if (is_null(self::$instance) or $forcereload) { 33910e7e15SAnna Dabrowska $class = get_called_class(); 34910e7e15SAnna Dabrowska self::$instance = new $class(); 35910e7e15SAnna Dabrowska } 36910e7e15SAnna Dabrowska return self::$instance; 37910e7e15SAnna Dabrowska } 38910e7e15SAnna Dabrowska 39910e7e15SAnna Dabrowska /** 40910e7e15SAnna Dabrowska * Assignments constructor. 41910e7e15SAnna Dabrowska * 42910e7e15SAnna Dabrowska * Not public. Use Assignments::getInstance() instead 43910e7e15SAnna Dabrowska */ 44910e7e15SAnna Dabrowska protected function __construct() 45910e7e15SAnna Dabrowska { 46910e7e15SAnna Dabrowska /** @var \helper_plugin_structpublish_db $helper */ 47910e7e15SAnna Dabrowska $helper = plugin_load('helper', 'struct_db'); 48910e7e15SAnna Dabrowska $this->sqlite = $helper->getDB(); 49910e7e15SAnna Dabrowska 50910e7e15SAnna Dabrowska $this->loadPatterns(); 51910e7e15SAnna Dabrowska } 52910e7e15SAnna Dabrowska /** 53910e7e15SAnna Dabrowska * Load existing assignment patterns 54910e7e15SAnna Dabrowska */ 55910e7e15SAnna Dabrowska protected function loadPatterns() 56910e7e15SAnna Dabrowska { 57910e7e15SAnna Dabrowska $sql = 'SELECT * FROM structpublish_assignments_patterns ORDER BY pattern'; 58910e7e15SAnna Dabrowska $res = $this->sqlite->query($sql); 59910e7e15SAnna Dabrowska $this->patterns = $this->sqlite->res2arr($res); 60910e7e15SAnna Dabrowska $this->sqlite->res_close($res); 61910e7e15SAnna Dabrowska } 62910e7e15SAnna Dabrowska 63910e7e15SAnna Dabrowska /** 64910e7e15SAnna Dabrowska * Add a new assignment pattern to the pattern table 65910e7e15SAnna Dabrowska * 66910e7e15SAnna Dabrowska * @param string $pattern 67910e7e15SAnna Dabrowska * @param string $user 68910e7e15SAnna Dabrowska * @param string $status 69910e7e15SAnna Dabrowska * @return bool 70910e7e15SAnna Dabrowska */ 71910e7e15SAnna Dabrowska public function addPattern($pattern, $user, $status) 72910e7e15SAnna Dabrowska { 73910e7e15SAnna Dabrowska // add the pattern 74910e7e15SAnna Dabrowska $sql = 'REPLACE INTO structpublish_assignments_patterns (pattern, user, status) VALUES (?,?,?)'; 75910e7e15SAnna Dabrowska $ok = (bool)$this->sqlite->query($sql, [$pattern, $user, $status]); 76910e7e15SAnna Dabrowska 77910e7e15SAnna Dabrowska // reload patterns 78910e7e15SAnna Dabrowska $this->loadPatterns(); 79910e7e15SAnna Dabrowska 80910e7e15SAnna Dabrowska // FIXME how to update / propagate assignments? 81910e7e15SAnna Dabrowska 82910e7e15SAnna Dabrowska return $ok; 83910e7e15SAnna Dabrowska } 84910e7e15SAnna Dabrowska 85910e7e15SAnna Dabrowska /** 86910e7e15SAnna Dabrowska * Remove an existing assignment pattern from the pattern table 87910e7e15SAnna Dabrowska * 88910e7e15SAnna Dabrowska * @param string $pattern 89910e7e15SAnna Dabrowska * @param string $user 90910e7e15SAnna Dabrowska * @param string $status 91910e7e15SAnna Dabrowska * @return bool 92910e7e15SAnna Dabrowska */ 93910e7e15SAnna Dabrowska public function removePattern($pattern, $user, $status) 94910e7e15SAnna Dabrowska { 95910e7e15SAnna Dabrowska // remove the pattern 96910e7e15SAnna Dabrowska $sql = 'DELETE FROM structpublish_assignments_patterns WHERE pattern = ? AND user = ? AND status = ?'; 97910e7e15SAnna Dabrowska $ok = (bool)$this->sqlite->query($sql, [$pattern, $user, $status]); 98910e7e15SAnna Dabrowska 99910e7e15SAnna Dabrowska // reload patterns 100910e7e15SAnna Dabrowska $this->loadPatterns(); 101910e7e15SAnna Dabrowska 102910e7e15SAnna Dabrowska // fetch possibly affected pages 103910e7e15SAnna Dabrowska $sql = 'SELECT pid FROM structpublish_assignments WHERE user = ? AND status = ?'; 104910e7e15SAnna Dabrowska $res = $this->sqlite->query($sql, [$user, $status]); 105910e7e15SAnna Dabrowska $pagerows = $this->sqlite->res2arr($res); 106910e7e15SAnna Dabrowska $this->sqlite->res_close($res); 107910e7e15SAnna Dabrowska 108910e7e15SAnna Dabrowska // reevalute the pages and unassign when needed 109910e7e15SAnna Dabrowska foreach ($pagerows as $row) { 110910e7e15SAnna Dabrowska $rules = $this->getPageAssignments($row['pid'], true); 111910e7e15SAnna Dabrowska // remove assignments matching the rule 112910e7e15SAnna Dabrowska foreach ($rules as $status => $users) { 113910e7e15SAnna Dabrowska foreach ($users as $user) { 114910e7e15SAnna Dabrowska $this->deassignPage($row['pid'], $user, $status); 115910e7e15SAnna Dabrowska } 116910e7e15SAnna Dabrowska } 117910e7e15SAnna Dabrowska } 118910e7e15SAnna Dabrowska 119910e7e15SAnna Dabrowska return $ok; 120910e7e15SAnna Dabrowska } 121910e7e15SAnna Dabrowska 122910e7e15SAnna Dabrowska /** 123910e7e15SAnna Dabrowska * Updates all assignments of a given page against the current patterns 124910e7e15SAnna Dabrowska * 125910e7e15SAnna Dabrowska * @param string $pid 126910e7e15SAnna Dabrowska */ 127910e7e15SAnna Dabrowska public function updatePageAssignments($pid) 128910e7e15SAnna Dabrowska { 129910e7e15SAnna Dabrowska // reload patterns 130910e7e15SAnna Dabrowska $this->loadPatterns(); 131910e7e15SAnna Dabrowska $rules = $this->getPageAssignments($pid, true); 132910e7e15SAnna Dabrowska 133910e7e15SAnna Dabrowska foreach ($rules as $status => $users) { 134910e7e15SAnna Dabrowska foreach ($users as $user) { 135910e7e15SAnna Dabrowska $this->assignPage($pid, $user, $status); 136910e7e15SAnna Dabrowska } 137910e7e15SAnna Dabrowska } 138910e7e15SAnna Dabrowska 139910e7e15SAnna Dabrowska // fetch known pages 140910e7e15SAnna Dabrowska /** @var \helper_plugin_structpublish_db $helper */ 141910e7e15SAnna Dabrowska $helper = plugin_load('helper', 'structpublish_db'); 142910e7e15SAnna Dabrowska $pages = $helper->getPages($pid); 143910e7e15SAnna Dabrowska 144910e7e15SAnna Dabrowska // FIXME reevalute existing assignments 145910e7e15SAnna Dabrowska } 146910e7e15SAnna Dabrowska 147910e7e15SAnna Dabrowska /** 148910e7e15SAnna Dabrowska * Clear all patterns - deassigns all pages 149910e7e15SAnna Dabrowska * 150910e7e15SAnna Dabrowska * This is mostly useful for testing and not used in the interface currently 151910e7e15SAnna Dabrowska * 152910e7e15SAnna Dabrowska * @param bool $full fully delete all previous assignments 153910e7e15SAnna Dabrowska * @return bool 154910e7e15SAnna Dabrowska */ 155910e7e15SAnna Dabrowska public function clear($full = false) 156910e7e15SAnna Dabrowska { 157910e7e15SAnna Dabrowska $sql = 'DELETE FROM structpublish_assignments_patterns'; 158910e7e15SAnna Dabrowska $ok = (bool)$this->sqlite->query($sql); 159910e7e15SAnna Dabrowska 160910e7e15SAnna Dabrowska if ($full) { 161910e7e15SAnna Dabrowska $sql = 'DELETE FROM structpublish_assignments'; 162910e7e15SAnna Dabrowska } else { 163910e7e15SAnna Dabrowska $sql = 'UPDATE structpublish_assignments SET assigned = 0'; 164910e7e15SAnna Dabrowska } 165910e7e15SAnna Dabrowska $ok = $ok && (bool)$this->sqlite->query($sql); 166910e7e15SAnna Dabrowska 167910e7e15SAnna Dabrowska // reload patterns 168910e7e15SAnna Dabrowska $this->loadPatterns(); 169910e7e15SAnna Dabrowska 170910e7e15SAnna Dabrowska return $ok; 171910e7e15SAnna Dabrowska } 172910e7e15SAnna Dabrowska 173910e7e15SAnna Dabrowska /** 174910e7e15SAnna Dabrowska * Add page to assignments 175910e7e15SAnna Dabrowska * 176910e7e15SAnna Dabrowska * @param string $page 177910e7e15SAnna Dabrowska * @param string $user 178910e7e15SAnna Dabrowska * @param string $status 179910e7e15SAnna Dabrowska * @return bool 180910e7e15SAnna Dabrowska */ 181910e7e15SAnna Dabrowska public function assignPage($page, $user = null, $status = null) 182910e7e15SAnna Dabrowska { 183910e7e15SAnna Dabrowska $sql = 'REPLACE INTO structpublish_assignments (pid, user, status, assigned) VALUES (?, ?, ?, 1)'; 184910e7e15SAnna Dabrowska return (bool)$this->sqlite->query($sql, [$page, $user, $status]); 185910e7e15SAnna Dabrowska } 186910e7e15SAnna Dabrowska 187910e7e15SAnna Dabrowska /** 188910e7e15SAnna Dabrowska * Remove page from assignments 189910e7e15SAnna Dabrowska * 190910e7e15SAnna Dabrowska * @param string $page 191910e7e15SAnna Dabrowska * @param string $user 192910e7e15SAnna Dabrowska * @return bool 193910e7e15SAnna Dabrowska */ 194910e7e15SAnna Dabrowska public function deassignPage($page, $user, $status) 195910e7e15SAnna Dabrowska { 196910e7e15SAnna Dabrowska $sql = 'REPLACE INTO structpublish_assignments (pid, user, status, assigned) VALUES (?, ?, ?, 0)'; 197910e7e15SAnna Dabrowska return (bool)$this->sqlite->query($sql, [$page, $user, $status]); 198910e7e15SAnna Dabrowska } 199910e7e15SAnna Dabrowska 200910e7e15SAnna Dabrowska /** 201910e7e15SAnna Dabrowska * Get the whole pattern table 202910e7e15SAnna Dabrowska * 203910e7e15SAnna Dabrowska * @return array 204910e7e15SAnna Dabrowska */ 205910e7e15SAnna Dabrowska public function getAllPatterns() 206910e7e15SAnna Dabrowska { 207910e7e15SAnna Dabrowska return $this->patterns; 208910e7e15SAnna Dabrowska } 209910e7e15SAnna Dabrowska 210910e7e15SAnna Dabrowska /** 211*e31c94d7SAndreas Gohr * Returns a list of user/group string lists per status assigned to the given page 212910e7e15SAnna Dabrowska * 213910e7e15SAnna Dabrowska * @param string $page 214910e7e15SAnna Dabrowska * @param bool $checkpatterns Should the current patterns be re-evaluated? 215*e31c94d7SAndreas Gohr * @return array users assigned [role => [user, ...], ...] 216910e7e15SAnna Dabrowska */ 217910e7e15SAnna Dabrowska public function getPageAssignments($page, $checkpatterns = true) 218910e7e15SAnna Dabrowska { 219910e7e15SAnna Dabrowska $rules = []; 220910e7e15SAnna Dabrowska $page = cleanID($page); 221910e7e15SAnna Dabrowska 222910e7e15SAnna Dabrowska if ($checkpatterns) { 223910e7e15SAnna Dabrowska $helper = plugin_load('helper', 'structpublish_assignments'); 224910e7e15SAnna Dabrowska // evaluate patterns 225910e7e15SAnna Dabrowska $pns = ':' . getNS($page) . ':'; 226910e7e15SAnna Dabrowska foreach ($this->patterns as $row) { 227910e7e15SAnna Dabrowska if ($helper->matchPagePattern($row['pattern'], $page, $pns)) { 228910e7e15SAnna Dabrowska $rules[$row['status']][] = $row['user']; 229910e7e15SAnna Dabrowska } 230910e7e15SAnna Dabrowska } 231910e7e15SAnna Dabrowska } else { 232910e7e15SAnna Dabrowska // just select 233910e7e15SAnna Dabrowska $sql = 'SELECT user, status FROM structpublish_assignments WHERE pid = ? AND assigned = 1'; 234910e7e15SAnna Dabrowska $res = $this->sqlite->query($sql, [$page]); 235910e7e15SAnna Dabrowska $list = $this->sqlite->res2arr($res); 236910e7e15SAnna Dabrowska $this->sqlite->res_close($res); 237910e7e15SAnna Dabrowska foreach ($list as $row) { 238910e7e15SAnna Dabrowska $rules[$row['status']][] = $row['user']; 239910e7e15SAnna Dabrowska } 240910e7e15SAnna Dabrowska } 241910e7e15SAnna Dabrowska 242910e7e15SAnna Dabrowska return $rules; 243910e7e15SAnna Dabrowska } 244910e7e15SAnna Dabrowska 245910e7e15SAnna Dabrowska /** 246910e7e15SAnna Dabrowska * Get the pages known to struct and their assignment state 247910e7e15SAnna Dabrowska * 248910e7e15SAnna Dabrowska * @param bool $assignedonly limit results to currently assigned only 249910e7e15SAnna Dabrowska * @return array 250910e7e15SAnna Dabrowska */ 251910e7e15SAnna Dabrowska public function getPages($assignedOnly = false) 252910e7e15SAnna Dabrowska { 253910e7e15SAnna Dabrowska $sql = 'SELECT pid, user, status, assigned FROM structpublish_assignments WHERE 1=1'; 254910e7e15SAnna Dabrowska 255910e7e15SAnna Dabrowska $opts = array(); 256910e7e15SAnna Dabrowska 257910e7e15SAnna Dabrowska if ($assignedOnly) { 258910e7e15SAnna Dabrowska $sql .= ' AND assigned = 1'; 259910e7e15SAnna Dabrowska } 260910e7e15SAnna Dabrowska 261910e7e15SAnna Dabrowska $sql .= ' ORDER BY pid, user, status'; 262910e7e15SAnna Dabrowska 263910e7e15SAnna Dabrowska $res = $this->sqlite->query($sql, $opts); 264910e7e15SAnna Dabrowska $list = $this->sqlite->res2arr($res); 265910e7e15SAnna Dabrowska $this->sqlite->res_close($res); 266910e7e15SAnna Dabrowska 267910e7e15SAnna Dabrowska $result = array(); 268910e7e15SAnna Dabrowska foreach ($list as $row) { 269910e7e15SAnna Dabrowska $pid = $row['pid']; 270910e7e15SAnna Dabrowska $user = $row['user']; 271910e7e15SAnna Dabrowska $status = $row['status']; 272910e7e15SAnna Dabrowska if (!isset($result[$pid])) $result[$pid] = array(); 273910e7e15SAnna Dabrowska $result[$pid][$user][$status] = (bool)$row['assigned']; 274910e7e15SAnna Dabrowska } 275910e7e15SAnna Dabrowska 276910e7e15SAnna Dabrowska return $result; 277910e7e15SAnna Dabrowska } 278910e7e15SAnna Dabrowska} 279