1<?php 2 3use dokuwiki\Subscriptions\SubscriberManager; 4 5/** 6 * DokuWiki Plugin submgr (Helper Component) 7 * 8 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 9 * @author Andreas Gohr <dokuwiki@cosmocode.de> 10 */ 11class helper_plugin_submgr extends DokuWiki_Plugin 12{ 13 14 /** 15 * @var array stores the current rules 16 */ 17 protected $rules = array(); 18 19 /** 20 * helper_plugin_submgr constructor. 21 */ 22 public function __construct() 23 { 24 $this->loadRules(); 25 } 26 27 /** 28 * Returns the currently defined rules 29 * 30 * item => (type, members) 31 * 32 * @return array 33 */ 34 public function getRules() 35 { 36 return $this->rules; 37 } 38 39 /** 40 * Add a new rule 41 * 42 * @param string $item page or namespace 43 * @param string $type every|digest|list 44 * @param string $members user/group list 45 * @throws Exception 46 */ 47 public function addRule($item, $type, $members) 48 { 49 $isns = $this->cleanItem($item); 50 $members = trim($members); 51 if (!in_array($type, array('every', 'digest', 'list'))) { 52 throw new Exception('bad subscription type'); 53 } 54 if (!$isns && $type == 'list') { 55 throw new Exception('list subscription is not supported for single pages'); 56 } 57 if (!$item) { 58 throw new Exception('no page or namespace given'); 59 } 60 if (!$members) { 61 throw new Exception('no users or groups given'); 62 } 63 64 // remove existing (will be ignored if doesn't exist) 65 $this->removeRule($item); 66 67 $this->rules[$item] = array($type, $members); 68 $this->writeRules(); 69 70 $this->applyRule($item, $type, $members); 71 } 72 73 /** 74 * Removes an existing rule 75 * 76 * @param string $item page or namespace 77 * @throws Exception 78 */ 79 public function removeRule($item) 80 { 81 if (!isset($this->rules[$item])) return; 82 83 list($type, $members) = $this->rules[$item]; 84 unset($this->rules[$item]); 85 $this->writeRules(); 86 87 $this->ceaseRule($item, $type, $members); 88 } 89 90 /** 91 * Applies all rules that match the given user/group combo 92 * 93 * @param string $user 94 * @param string[] $groups 95 * @throws Exception 96 */ 97 public function runRules($user, $groups) 98 { 99 $sub = new SubscriberManager(); 100 101 foreach ($this->rules as $item => $data) { 102 if (auth_isMember($data[1], $user, $groups)) { 103 $sub->add($item, $user, $data[0]); 104 } 105 } 106 } 107 108 /** 109 * loads the current rules 110 */ 111 protected function loadRules() 112 { 113 $lines = confToHash(DOKU_CONF . 'subscription.rules'); 114 115 foreach ($lines as $key => $val) { 116 $val = preg_split('/\s+/', $val, 2); 117 $val = array_map('trim', $val); 118 $val = array_filter($val); 119 $val = array_unique($val); 120 $lines[$key] = $val; 121 } 122 123 $this->rules = $lines; 124 ksort($this->rules); 125 } 126 127 /** 128 * saves the current rules 129 * 130 * @return bool true on success 131 */ 132 protected function writeRules() 133 { 134 $out = "# auto subscription rules\n"; 135 foreach ($this->rules as $item => $data) { 136 $out .= "$item\t$data[0]\t$data[1]\n"; 137 } 138 139 return io_saveFile(DOKU_CONF . 'subscription.rules', $out); 140 } 141 142 /** 143 * Applies a rule by subscribing all affected users 144 * 145 * @param string $item page or namespace 146 * @param string $type every|digest|list 147 * @param string $members user/group list 148 * @throws Exception 149 */ 150 protected function applyRule($item, $type, $members) 151 { 152 $users = $this->getAffectedUsers($members); 153 $sub = new SubscriberManager(); 154 foreach ($users as $user) { 155 $sub->add($item, $user, $type); 156 } 157 msg(sprintf($this->getLang('appliedrule'), count($users))); 158 } 159 160 /** 161 * Removes a rule by unsubscribing all affected users 162 * 163 * @param string $item page or namespace 164 * @param string $type every|digest|list 165 * @param string $members user/group list 166 * @throws Exception 167 */ 168 protected function ceaseRule($item, $type, $members) 169 { 170 $users = $this->getAffectedUsers($members); 171 172 $sub = new SubscriberManager(); 173 foreach ($users as $user) { 174 $sub->remove($item, $user, $type); 175 } 176 msg(sprintf($this->getLang('removedrule'), count($users))); 177 } 178 179 /** 180 * Gets all users affected by a member string 181 * 182 * @param string $members comma separated list of users and groups 183 * @return array 184 */ 185 protected function getAffectedUsers($members) 186 { 187 /** @var DokuWiki_Auth_Plugin $auth */ 188 global $auth; 189 190 $members = explode(',', $members); 191 $members = array_map('trim', $members); 192 $members = array_filter($members); 193 $members = array_unique($members); 194 195 // get all users directly specified or from specified groups 196 $users = array(); 197 foreach ($members as $one) { 198 if (substr($one, 0, 1) == '@') { 199 // passing 0 for all users is broken in some backends (#1630), limiting to 5000 should be good enough 200 $found = $auth->retrieveUsers(0, 5000, array('grps' => substr($one, 1))); 201 if ($found) { 202 $users = array_merge($users, array_keys($found)); 203 } 204 } else { 205 $users[] = $one; 206 } 207 } 208 209 $users = array_unique($users); 210 211 return $users; 212 } 213 214 /** 215 * Clean the item and return if it is a namespace 216 * 217 * @param string &$item reference to the item to clear 218 * @return bool is the given item a namespace? (trailing colon) 219 */ 220 protected function cleanItem(&$item) 221 { 222 $isns = false; 223 $item = trim($item); 224 if (substr($item, -1) == ':') { 225 $isns = true; 226 } 227 $item = cleanID($item); 228 if ($isns) $item = "$item:"; 229 230 return $isns; 231 } 232 233} 234