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