1<?php 2 3use dokuwiki\Extension\CLIPlugin; 4use dokuwiki\Extension\AuthPlugin; 5use splitbrain\phpcli\Options; 6use splitbrain\phpcli\TableFormatter; 7 8/** 9 * Class cli_plugin_usermanager 10 * 11 * Command Line component for the usermanager 12 * 13 * @license GPL2 14 * @author Karsten Kosmala <karsten.kosmala@gmail.com> 15 */ 16class cli_plugin_usermanager extends CLIPlugin 17{ 18 /** @inheritdoc */ 19 protected function setup(Options $options) 20 { 21 // general setup 22 $options->setHelp( 23 "Manage users for this DokuWiki instance\n" 24 ); 25 26 // list 27 $options->registerCommand('list', 'List users'); 28 $options->registerOption('verbose', 'Show detailed user information', 'v', false, 'list'); 29 30 // add 31 $options->registerCommand('add', 'Add an user to auth backend'); 32 $options->registerArgument('login', 'Username', true, 'add'); 33 $options->registerArgument('mail', 'Email address', true, 'add'); 34 $options->registerArgument('name', 'Full name', false, 'add'); 35 $options->registerArgument('groups', 'Groups to be added, comma-seperated', false, 'add'); 36 $options->registerArgument('password', 'Password to set', false, 'add'); 37 $options->registerOption('notify', 'Notify user', 'n', false, 'add'); 38 39 // delete 40 $options->registerCommand('delete', 'Deletes user(s) from auth backend'); 41 $options->registerArgument('name', 'Username(s), comma-seperated', true, 'delete'); 42 43 // add to group 44 $options->registerCommand('addtogroup', 'Add user to group(s)'); 45 $options->registerArgument('name', 'Username', true, 'addtogroup'); 46 $options->registerArgument('group', 'Group(s), comma-seperated', true, 'addtogroup'); 47 48 // remove from group 49 $options->registerCommand('removefromgroup', 'Remove user from group(s)'); 50 $options->registerArgument('name', 'Username', true, 'removefromgroup'); 51 $options->registerArgument('group', 'Group(s), comma-separated', true, 'removefromgroup'); 52 } 53 54 /** @inheritdoc */ 55 protected function main(Options $options) 56 { 57 auth_setup(); 58 59 /** @var AuthPlugin $auth */ 60 global $auth; 61 62 if (!$auth instanceof AuthPlugin) { 63 $this->error($this->getLang('noauth')); 64 return 1; 65 } 66 67 switch ($options->getCmd()) { 68 case 'list': 69 $ret = $this->cmdList($options->getOpt('verbose')); 70 break; 71 case 'add': 72 $ret = $this->cmdAdd($options->getOpt('notify'), $options->getArgs()); 73 break; 74 case 'delete': 75 $ret = $this->cmdDelete($options->getArgs()); 76 break; 77 case 'addtogroup': 78 $ret = $this->cmdAddToGroup($options->getArgs()); 79 break; 80 case 'removefromgroup': 81 $ret = $this->cmdRemoveFromGroup($options->getArgs()); 82 break; 83 84 default: 85 echo $options->help(); 86 $ret = 0; 87 } 88 89 exit($ret); 90 } 91 92 /** 93 * @param bool $showdetails 94 * @return int 95 */ 96 protected function cmdList(bool $showdetails) 97 { 98 /** @var AuthPlugin $auth */ 99 global $auth; 100 101 if (!$auth->canDo('getUsers')) { 102 $this->error($this->getLang('nosupport')); 103 return 1; 104 } else { 105 $this->listUsers($showdetails); 106 } 107 108 return 0; 109 } 110 111 /** 112 * List the given users 113 * 114 * @param bool $details display details 115 */ 116 protected function listUsers(bool $details = false) 117 { 118 /** @var AuthPlugin $auth */ 119 global $auth; 120 $list = $auth->retrieveUsers(); 121 122 $tr = new TableFormatter($this->colors); 123 124 foreach ($list as $username => $user) { 125 $content = [$username]; 126 if ($details) { 127 $content[] = $user['name']; 128 $content[] = $user['mail']; 129 $content[] = implode(", ", $user['grps']); 130 } 131 echo $tr->format( 132 [15, 25, 25, 15], 133 $content 134 ); 135 } 136 } 137 138 /** 139 * Adds an user 140 * 141 * @param bool $notify display details 142 * @param array $args 143 * @return int 144 */ 145 protected function cmdAdd(bool $notify, array $args) 146 { 147 /** @var AuthPlugin $auth */ 148 global $auth; 149 150 if (!$auth->canDo('addUser')) { 151 $this->error($this->getLang('nosupport')); 152 return 1; 153 } 154 155 [$login, $mail, $name, $grps, $pass] = $args; 156 $grps = array_filter(array_map('trim', explode(',', $grps))); 157 158 if ($auth->canDo('modPass')) { 159 if (empty($pass)) { 160 if ($notify) { 161 $pass = auth_pwgen($login); 162 } else { 163 $this->error($this->getLang('add_fail')); 164 $this->error($this->getLang('addUser_error_missing_pass')); 165 return 1; 166 } 167 } 168 } elseif (!empty($pass)) { 169 $this->error($this->getLang('add_fail')); 170 $this->error($this->getLang('addUser_error_modPass_disabled')); 171 return 1; 172 } 173 174 if ($auth->triggerUserMod('create', [$login, $pass, $name, $mail, $grps])) { 175 $this->success($this->getLang('add_ok')); 176 } else { 177 $this->printErrorMessages(); 178 $this->error($this->getLang('add_fail')); 179 $this->error($this->getLang('addUser_error_create_event_failed')); 180 return 1; 181 } 182 183 return 0; 184 } 185 186 /** 187 * Deletes users 188 * @param array $args 189 * @return int 190 */ 191 protected function cmdDelete(array $args) 192 { 193 /** @var AuthPlugin $auth */ 194 global $auth; 195 196 if (!$auth->canDo('delUser')) { 197 $this->error($this->getLang('nosupport')); 198 return 1; 199 } 200 201 $users = explode(',', $args[0]); 202 $count = $auth->triggerUserMod('delete', [$users]); 203 204 if ($count != count($users)) { 205 $this->printErrorMessages(); 206 $part1 = str_replace('%d', $count, $this->getLang('delete_ok')); 207 $part2 = str_replace('%d', (count($users) - $count), $this->getLang('delete_fail')); 208 $this->error("$part1, $part2"); 209 return 1; 210 } 211 212 return 0; 213 } 214 215 /** 216 * Adds an user to group(s) 217 * 218 * @param array $args 219 * @return int 220 */ 221 protected function cmdAddToGroup(array $args) 222 { 223 /** @var AuthPlugin $auth */ 224 global $auth; 225 226 [$name, $newgrps] = $args; 227 $newgrps = array_filter(array_map('trim', explode(',', $newgrps))); 228 $oldinfo = $auth->getUserData($name); 229 $changes = []; 230 231 if ($newgrps !== [] && $auth->canDo('modGroups')) { 232 $changes['grps'] = $oldinfo['grps']; 233 foreach ($newgrps as $group) { 234 if (!in_array($group, $oldinfo['grps'])) { 235 $changes['grps'][] = $group; 236 } 237 } 238 } 239 240 if (!empty(array_diff($changes['grps'], $oldinfo['grps']))) { 241 if ($auth->triggerUserMod('modify', [$name, $changes])) { 242 $this->success($this->getLang('update_ok')); 243 } else { 244 $this->printErrorMessages(); 245 $this->error($this->getLang('update_fail')); 246 return 1; 247 } 248 } 249 250 return 0; 251 } 252 253 /** 254 * Removes an user from group(s) 255 * 256 * @param array $args 257 * @return int 258 */ 259 protected function cmdRemoveFromGroup(array $args) 260 { 261 /** @var AuthPlugin $auth */ 262 global $auth; 263 264 [$name, $grps] = $args; 265 $grps = array_filter(array_map('trim', explode(',', $grps))); 266 $oldinfo = $auth->getUserData($name); 267 $changes = []; 268 269 if ($grps !== [] && $auth->canDo('modGroups')) { 270 $changes['grps'] = $oldinfo['grps']; 271 foreach ($grps as $group) { 272 if (($pos = array_search($group, $changes['grps'])) == !false) { 273 unset($changes['grps'][$pos]); 274 } 275 } 276 } 277 278 if (!empty(array_diff($oldinfo['grps'], $changes['grps']))) { 279 if ($auth->triggerUserMod('modify', [$name, $changes])) { 280 $this->success($this->getLang('update_ok')); 281 } else { 282 $this->printErrorMessages(); 283 $this->error($this->getLang('update_fail')); 284 return 1; 285 } 286 } 287 288 return 0; 289 } 290 291 /** 292 * Plugins triggered during user modification may cause failures and output messages via 293 * DokuWiki's msg() function 294 */ 295 protected function printErrorMessages() 296 { 297 global $MSG; 298 if (isset($MSG)) { 299 foreach ($MSG as $msg) { 300 if ($msg['lvl'] === 'error') $this->error($msg['msg']); 301 } 302 } 303 } 304} 305