1*910e7e15SAnna Dabrowska<?php 2*910e7e15SAnna Dabrowska 3*910e7e15SAnna Dabrowskanamespace dokuwiki\plugin\structpublish\meta; 4*910e7e15SAnna Dabrowska 5*910e7e15SAnna Dabrowska/** 6*910e7e15SAnna Dabrowska * Class Assignments 7*910e7e15SAnna Dabrowska * 8*910e7e15SAnna Dabrowska * Manages the assignment of users to pages and namespaces 9*910e7e15SAnna Dabrowska * This is a singleton. Assignment data is only loaded once per request. 10*910e7e15SAnna Dabrowska * 11*910e7e15SAnna Dabrowska * @see \dokuwiki\plugin\struct\meta\Assignments 12*910e7e15SAnna Dabrowska */ 13*910e7e15SAnna Dabrowskaclass Assignments 14*910e7e15SAnna Dabrowska{ 15*910e7e15SAnna Dabrowska /** @var \helper_plugin_sqlite|null */ 16*910e7e15SAnna Dabrowska protected $sqlite; 17*910e7e15SAnna Dabrowska 18*910e7e15SAnna Dabrowska /** @var array All the assignments patterns */ 19*910e7e15SAnna Dabrowska protected $patterns; 20*910e7e15SAnna Dabrowska 21*910e7e15SAnna Dabrowska /** @var Assignments */ 22*910e7e15SAnna Dabrowska protected static $instance = null; 23*910e7e15SAnna Dabrowska 24*910e7e15SAnna Dabrowska /** 25*910e7e15SAnna Dabrowska * Get the singleton instance of the Assignments 26*910e7e15SAnna Dabrowska * 27*910e7e15SAnna Dabrowska * @param bool $forcereload create a new instace to reload the assignment data 28*910e7e15SAnna Dabrowska * @return Assignments 29*910e7e15SAnna Dabrowska */ 30*910e7e15SAnna Dabrowska public static function getInstance($forcereload = false) 31*910e7e15SAnna Dabrowska { 32*910e7e15SAnna Dabrowska if (is_null(self::$instance) or $forcereload) { 33*910e7e15SAnna Dabrowska $class = get_called_class(); 34*910e7e15SAnna Dabrowska self::$instance = new $class(); 35*910e7e15SAnna Dabrowska } 36*910e7e15SAnna Dabrowska return self::$instance; 37*910e7e15SAnna Dabrowska } 38*910e7e15SAnna Dabrowska 39*910e7e15SAnna Dabrowska /** 40*910e7e15SAnna Dabrowska * Assignments constructor. 41*910e7e15SAnna Dabrowska * 42*910e7e15SAnna Dabrowska * Not public. Use Assignments::getInstance() instead 43*910e7e15SAnna Dabrowska */ 44*910e7e15SAnna Dabrowska protected function __construct() 45*910e7e15SAnna Dabrowska { 46*910e7e15SAnna Dabrowska /** @var \helper_plugin_structpublish_db $helper */ 47*910e7e15SAnna Dabrowska $helper = plugin_load('helper', 'struct_db'); 48*910e7e15SAnna Dabrowska $this->sqlite = $helper->getDB(); 49*910e7e15SAnna Dabrowska 50*910e7e15SAnna Dabrowska $this->loadPatterns(); 51*910e7e15SAnna Dabrowska } 52*910e7e15SAnna Dabrowska /** 53*910e7e15SAnna Dabrowska * Load existing assignment patterns 54*910e7e15SAnna Dabrowska */ 55*910e7e15SAnna Dabrowska protected function loadPatterns() 56*910e7e15SAnna Dabrowska { 57*910e7e15SAnna Dabrowska $sql = 'SELECT * FROM structpublish_assignments_patterns ORDER BY pattern'; 58*910e7e15SAnna Dabrowska $res = $this->sqlite->query($sql); 59*910e7e15SAnna Dabrowska $this->patterns = $this->sqlite->res2arr($res); 60*910e7e15SAnna Dabrowska $this->sqlite->res_close($res); 61*910e7e15SAnna Dabrowska } 62*910e7e15SAnna Dabrowska 63*910e7e15SAnna Dabrowska /** 64*910e7e15SAnna Dabrowska * Add a new assignment pattern to the pattern table 65*910e7e15SAnna Dabrowska * 66*910e7e15SAnna Dabrowska * @param string $pattern 67*910e7e15SAnna Dabrowska * @param string $user 68*910e7e15SAnna Dabrowska * @param string $status 69*910e7e15SAnna Dabrowska * @return bool 70*910e7e15SAnna Dabrowska */ 71*910e7e15SAnna Dabrowska public function addPattern($pattern, $user, $status) 72*910e7e15SAnna Dabrowska { 73*910e7e15SAnna Dabrowska // add the pattern 74*910e7e15SAnna Dabrowska $sql = 'REPLACE INTO structpublish_assignments_patterns (pattern, user, status) VALUES (?,?,?)'; 75*910e7e15SAnna Dabrowska $ok = (bool)$this->sqlite->query($sql, [$pattern, $user, $status]); 76*910e7e15SAnna Dabrowska 77*910e7e15SAnna Dabrowska // reload patterns 78*910e7e15SAnna Dabrowska $this->loadPatterns(); 79*910e7e15SAnna Dabrowska 80*910e7e15SAnna Dabrowska // FIXME how to update / propagate assignments? 81*910e7e15SAnna Dabrowska 82*910e7e15SAnna Dabrowska return $ok; 83*910e7e15SAnna Dabrowska } 84*910e7e15SAnna Dabrowska 85*910e7e15SAnna Dabrowska /** 86*910e7e15SAnna Dabrowska * Remove an existing assignment pattern from the pattern table 87*910e7e15SAnna Dabrowska * 88*910e7e15SAnna Dabrowska * @param string $pattern 89*910e7e15SAnna Dabrowska * @param string $user 90*910e7e15SAnna Dabrowska * @param string $status 91*910e7e15SAnna Dabrowska * @return bool 92*910e7e15SAnna Dabrowska */ 93*910e7e15SAnna Dabrowska public function removePattern($pattern, $user, $status) 94*910e7e15SAnna Dabrowska { 95*910e7e15SAnna Dabrowska // remove the pattern 96*910e7e15SAnna Dabrowska $sql = 'DELETE FROM structpublish_assignments_patterns WHERE pattern = ? AND user = ? AND status = ?'; 97*910e7e15SAnna Dabrowska $ok = (bool)$this->sqlite->query($sql, [$pattern, $user, $status]); 98*910e7e15SAnna Dabrowska 99*910e7e15SAnna Dabrowska // reload patterns 100*910e7e15SAnna Dabrowska $this->loadPatterns(); 101*910e7e15SAnna Dabrowska 102*910e7e15SAnna Dabrowska // fetch possibly affected pages 103*910e7e15SAnna Dabrowska $sql = 'SELECT pid FROM structpublish_assignments WHERE user = ? AND status = ?'; 104*910e7e15SAnna Dabrowska $res = $this->sqlite->query($sql, [$user, $status]); 105*910e7e15SAnna Dabrowska $pagerows = $this->sqlite->res2arr($res); 106*910e7e15SAnna Dabrowska $this->sqlite->res_close($res); 107*910e7e15SAnna Dabrowska 108*910e7e15SAnna Dabrowska // reevalute the pages and unassign when needed 109*910e7e15SAnna Dabrowska foreach ($pagerows as $row) { 110*910e7e15SAnna Dabrowska $rules = $this->getPageAssignments($row['pid'], true); 111*910e7e15SAnna Dabrowska // remove assignments matching the rule 112*910e7e15SAnna Dabrowska foreach ($rules as $status => $users) { 113*910e7e15SAnna Dabrowska foreach ($users as $user) { 114*910e7e15SAnna Dabrowska $this->deassignPage($row['pid'], $user, $status); 115*910e7e15SAnna Dabrowska } 116*910e7e15SAnna Dabrowska } 117*910e7e15SAnna Dabrowska } 118*910e7e15SAnna Dabrowska 119*910e7e15SAnna Dabrowska return $ok; 120*910e7e15SAnna Dabrowska } 121*910e7e15SAnna Dabrowska 122*910e7e15SAnna Dabrowska /** 123*910e7e15SAnna Dabrowska * Updates all assignments of a given page against the current patterns 124*910e7e15SAnna Dabrowska * 125*910e7e15SAnna Dabrowska * @param string $pid 126*910e7e15SAnna Dabrowska */ 127*910e7e15SAnna Dabrowska public function updatePageAssignments($pid) 128*910e7e15SAnna Dabrowska { 129*910e7e15SAnna Dabrowska // reload patterns 130*910e7e15SAnna Dabrowska $this->loadPatterns(); 131*910e7e15SAnna Dabrowska $rules = $this->getPageAssignments($pid, true); 132*910e7e15SAnna Dabrowska 133*910e7e15SAnna Dabrowska foreach ($rules as $status => $users) { 134*910e7e15SAnna Dabrowska foreach ($users as $user) { 135*910e7e15SAnna Dabrowska $this->assignPage($pid, $user, $status); 136*910e7e15SAnna Dabrowska } 137*910e7e15SAnna Dabrowska } 138*910e7e15SAnna Dabrowska 139*910e7e15SAnna Dabrowska // fetch known pages 140*910e7e15SAnna Dabrowska /** @var \helper_plugin_structpublish_db $helper */ 141*910e7e15SAnna Dabrowska $helper = plugin_load('helper', 'structpublish_db'); 142*910e7e15SAnna Dabrowska $pages = $helper->getPages($pid); 143*910e7e15SAnna Dabrowska 144*910e7e15SAnna Dabrowska // FIXME reevalute existing assignments 145*910e7e15SAnna Dabrowska } 146*910e7e15SAnna Dabrowska 147*910e7e15SAnna Dabrowska /** 148*910e7e15SAnna Dabrowska * Clear all patterns - deassigns all pages 149*910e7e15SAnna Dabrowska * 150*910e7e15SAnna Dabrowska * This is mostly useful for testing and not used in the interface currently 151*910e7e15SAnna Dabrowska * 152*910e7e15SAnna Dabrowska * @param bool $full fully delete all previous assignments 153*910e7e15SAnna Dabrowska * @return bool 154*910e7e15SAnna Dabrowska */ 155*910e7e15SAnna Dabrowska public function clear($full = false) 156*910e7e15SAnna Dabrowska { 157*910e7e15SAnna Dabrowska $sql = 'DELETE FROM structpublish_assignments_patterns'; 158*910e7e15SAnna Dabrowska $ok = (bool)$this->sqlite->query($sql); 159*910e7e15SAnna Dabrowska 160*910e7e15SAnna Dabrowska if ($full) { 161*910e7e15SAnna Dabrowska $sql = 'DELETE FROM structpublish_assignments'; 162*910e7e15SAnna Dabrowska } else { 163*910e7e15SAnna Dabrowska $sql = 'UPDATE structpublish_assignments SET assigned = 0'; 164*910e7e15SAnna Dabrowska } 165*910e7e15SAnna Dabrowska $ok = $ok && (bool)$this->sqlite->query($sql); 166*910e7e15SAnna Dabrowska 167*910e7e15SAnna Dabrowska // reload patterns 168*910e7e15SAnna Dabrowska $this->loadPatterns(); 169*910e7e15SAnna Dabrowska 170*910e7e15SAnna Dabrowska return $ok; 171*910e7e15SAnna Dabrowska } 172*910e7e15SAnna Dabrowska 173*910e7e15SAnna Dabrowska /** 174*910e7e15SAnna Dabrowska * Add page to assignments 175*910e7e15SAnna Dabrowska * 176*910e7e15SAnna Dabrowska * @param string $page 177*910e7e15SAnna Dabrowska * @param string $user 178*910e7e15SAnna Dabrowska * @param string $status 179*910e7e15SAnna Dabrowska * @return bool 180*910e7e15SAnna Dabrowska */ 181*910e7e15SAnna Dabrowska public function assignPage($page, $user = null, $status = null) 182*910e7e15SAnna Dabrowska { 183*910e7e15SAnna Dabrowska $sql = 'REPLACE INTO structpublish_assignments (pid, user, status, assigned) VALUES (?, ?, ?, 1)'; 184*910e7e15SAnna Dabrowska return (bool)$this->sqlite->query($sql, [$page, $user, $status]); 185*910e7e15SAnna Dabrowska } 186*910e7e15SAnna Dabrowska 187*910e7e15SAnna Dabrowska /** 188*910e7e15SAnna Dabrowska * Remove page from assignments 189*910e7e15SAnna Dabrowska * 190*910e7e15SAnna Dabrowska * @param string $page 191*910e7e15SAnna Dabrowska * @param string $user 192*910e7e15SAnna Dabrowska * @return bool 193*910e7e15SAnna Dabrowska */ 194*910e7e15SAnna Dabrowska public function deassignPage($page, $user, $status) 195*910e7e15SAnna Dabrowska { 196*910e7e15SAnna Dabrowska $sql = 'REPLACE INTO structpublish_assignments (pid, user, status, assigned) VALUES (?, ?, ?, 0)'; 197*910e7e15SAnna Dabrowska return (bool)$this->sqlite->query($sql, [$page, $user, $status]); 198*910e7e15SAnna Dabrowska } 199*910e7e15SAnna Dabrowska 200*910e7e15SAnna Dabrowska /** 201*910e7e15SAnna Dabrowska * Get the whole pattern table 202*910e7e15SAnna Dabrowska * 203*910e7e15SAnna Dabrowska * @return array 204*910e7e15SAnna Dabrowska */ 205*910e7e15SAnna Dabrowska public function getAllPatterns() 206*910e7e15SAnna Dabrowska { 207*910e7e15SAnna Dabrowska return $this->patterns; 208*910e7e15SAnna Dabrowska } 209*910e7e15SAnna Dabrowska 210*910e7e15SAnna Dabrowska /** 211*910e7e15SAnna Dabrowska * Returns a list of users per status assigned to the given page 212*910e7e15SAnna Dabrowska * 213*910e7e15SAnna Dabrowska * @param string $page 214*910e7e15SAnna Dabrowska * @param bool $checkpatterns Should the current patterns be re-evaluated? 215*910e7e15SAnna Dabrowska * @return array users assigned 216*910e7e15SAnna Dabrowska */ 217*910e7e15SAnna Dabrowska public function getPageAssignments($page, $checkpatterns = true) 218*910e7e15SAnna Dabrowska { 219*910e7e15SAnna Dabrowska $rules = []; 220*910e7e15SAnna Dabrowska $page = cleanID($page); 221*910e7e15SAnna Dabrowska 222*910e7e15SAnna Dabrowska if ($checkpatterns) { 223*910e7e15SAnna Dabrowska $helper = plugin_load('helper', 'structpublish_assignments'); 224*910e7e15SAnna Dabrowska // evaluate patterns 225*910e7e15SAnna Dabrowska $pns = ':' . getNS($page) . ':'; 226*910e7e15SAnna Dabrowska foreach ($this->patterns as $row) { 227*910e7e15SAnna Dabrowska if ($helper->matchPagePattern($row['pattern'], $page, $pns)) { 228*910e7e15SAnna Dabrowska $rules[$row['status']][] = $row['user']; 229*910e7e15SAnna Dabrowska } 230*910e7e15SAnna Dabrowska } 231*910e7e15SAnna Dabrowska } else { 232*910e7e15SAnna Dabrowska // just select 233*910e7e15SAnna Dabrowska $sql = 'SELECT user, status FROM structpublish_assignments WHERE pid = ? AND assigned = 1'; 234*910e7e15SAnna Dabrowska $res = $this->sqlite->query($sql, [$page]); 235*910e7e15SAnna Dabrowska $list = $this->sqlite->res2arr($res); 236*910e7e15SAnna Dabrowska $this->sqlite->res_close($res); 237*910e7e15SAnna Dabrowska foreach ($list as $row) { 238*910e7e15SAnna Dabrowska $rules[$row['status']][] = $row['user']; 239*910e7e15SAnna Dabrowska } 240*910e7e15SAnna Dabrowska } 241*910e7e15SAnna Dabrowska 242*910e7e15SAnna Dabrowska return $rules; 243*910e7e15SAnna Dabrowska } 244*910e7e15SAnna Dabrowska 245*910e7e15SAnna Dabrowska /** 246*910e7e15SAnna Dabrowska * Get the pages known to struct and their assignment state 247*910e7e15SAnna Dabrowska * 248*910e7e15SAnna Dabrowska * @param bool $assignedonly limit results to currently assigned only 249*910e7e15SAnna Dabrowska * @return array 250*910e7e15SAnna Dabrowska */ 251*910e7e15SAnna Dabrowska public function getPages($assignedOnly = false) 252*910e7e15SAnna Dabrowska { 253*910e7e15SAnna Dabrowska $sql = 'SELECT pid, user, status, assigned FROM structpublish_assignments WHERE 1=1'; 254*910e7e15SAnna Dabrowska 255*910e7e15SAnna Dabrowska $opts = array(); 256*910e7e15SAnna Dabrowska 257*910e7e15SAnna Dabrowska if ($assignedOnly) { 258*910e7e15SAnna Dabrowska $sql .= ' AND assigned = 1'; 259*910e7e15SAnna Dabrowska } 260*910e7e15SAnna Dabrowska 261*910e7e15SAnna Dabrowska $sql .= ' ORDER BY pid, user, status'; 262*910e7e15SAnna Dabrowska 263*910e7e15SAnna Dabrowska $res = $this->sqlite->query($sql, $opts); 264*910e7e15SAnna Dabrowska $list = $this->sqlite->res2arr($res); 265*910e7e15SAnna Dabrowska $this->sqlite->res_close($res); 266*910e7e15SAnna Dabrowska 267*910e7e15SAnna Dabrowska $result = array(); 268*910e7e15SAnna Dabrowska foreach ($list as $row) { 269*910e7e15SAnna Dabrowska $pid = $row['pid']; 270*910e7e15SAnna Dabrowska $user = $row['user']; 271*910e7e15SAnna Dabrowska $status = $row['status']; 272*910e7e15SAnna Dabrowska if (!isset($result[$pid])) $result[$pid] = array(); 273*910e7e15SAnna Dabrowska $result[$pid][$user][$status] = (bool)$row['assigned']; 274*910e7e15SAnna Dabrowska } 275*910e7e15SAnna Dabrowska 276*910e7e15SAnna Dabrowska return $result; 277*910e7e15SAnna Dabrowska } 278*910e7e15SAnna Dabrowska} 279