You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

309 lines
8.9 KiB

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