xref: /dokuwiki/lib/plugins/usermanager/admin.php (revision 73dc0a8919857718a3b64a4c0741b57580a34b2a)
10440ff15Schris<?php
254cc7aa4SAndreas Gohr
38553d24dSAndreas Gohruse dokuwiki\Extension\AdminPlugin;
451ee2399SGerrit Uitslaguse dokuwiki\Extension\AuthPlugin;
5*73dc0a89SAndreas Gohruse dokuwiki\MailUtils;
654cc7aa4SAndreas Gohruse dokuwiki\Utf8\Clean;
753c68e5cSAndreas Gohruse dokuwiki\Utf8\Conversion;
8a664aabaSAndreas Gohr
90440ff15Schris/*
100440ff15Schris *  User Manager
110440ff15Schris *
120440ff15Schris *  Dokuwiki Admin Plugin
130440ff15Schris *
140440ff15Schris *  This version of the user manager has been modified to only work with
150440ff15Schris *  objectified version of auth system
160440ff15Schris *
170440ff15Schris *  @author  neolao <neolao@neolao.com>
180440ff15Schris *  @author  Chris Smith <chris@jalakai.co.uk>
190440ff15Schris */
20a664aabaSAndreas Gohr
210440ff15Schris/**
220440ff15Schris * All DokuWiki plugins to extend the admin function
230440ff15Schris * need to inherit from this class
240440ff15Schris */
258553d24dSAndreas Gohrclass admin_plugin_usermanager extends AdminPlugin
263a97d936SAndreas Gohr{
27bf9be0e3SAndreas Gohr    protected const IMAGE_DIR = DOKU_BASE . 'lib/plugins/usermanager/images/';
280440ff15Schris
2954cc7aa4SAndreas Gohr    protected $auth;        // auth object
303a97d936SAndreas Gohr    protected $users_total = 0;     // number of registered users
3154cc7aa4SAndreas Gohr    protected $filter = [];   // user selection filter(s)
323a97d936SAndreas Gohr    protected $start = 0;          // index of first user to be displayed
333a97d936SAndreas Gohr    protected $last = 0;           // index of the last user to be displayed
343a97d936SAndreas Gohr    protected $pagesize = 20;      // number of users to list on one page
353a97d936SAndreas Gohr    protected $edit_user = '';     // set to user selected for editing
3654cc7aa4SAndreas Gohr    protected $edit_userdata = [];
373a97d936SAndreas Gohr    protected $disabled = '';      // if disabled set to explanatory string
3854cc7aa4SAndreas Gohr    protected $import_failures = [];
393a97d936SAndreas Gohr    protected $lastdisabled = false; // set to true if last user is unknown and last button is hence buggy
400440ff15Schris
410440ff15Schris    /**
420440ff15Schris     * Constructor
430440ff15Schris     */
443a97d936SAndreas Gohr    public function __construct()
453a97d936SAndreas Gohr    {
4651ee2399SGerrit Uitslag        /** @var AuthPlugin $auth */
470440ff15Schris        global $auth;
480440ff15Schris
490440ff15Schris        $this->setupLocale();
5051d94d49Schris
516547cfc7SGerrit Uitslag        if (!$auth instanceof AuthPlugin) {
523a97d936SAndreas Gohr            $this->disabled = $this->lang['noauth'];
5382fd59b6SAndreas Gohr        } elseif (!$auth->canDo('getUsers')) {
543a97d936SAndreas Gohr            $this->disabled = $this->lang['nosupport'];
5551d94d49Schris        } else {
5651d94d49Schris            // we're good to go
573a97d936SAndreas Gohr            $this->auth = &$auth;
5851d94d49Schris        }
59ae1afd2fSChristopher Smith
60ae1afd2fSChristopher Smith        // attempt to retrieve any import failures from the session
610e80bb5eSChristopher Smith        if (!empty($_SESSION['import_failures'])) {
623a97d936SAndreas Gohr            $this->import_failures = $_SESSION['import_failures'];
63ae1afd2fSChristopher Smith        }
640440ff15Schris    }
650440ff15Schris
660440ff15Schris    /**
67c5a7c0c6SGerrit Uitslag     * Return prompt for admin menu
68253d4b48SGerrit Uitslag     *
69253d4b48SGerrit Uitslag     * @param string $language
70253d4b48SGerrit Uitslag     * @return string
710440ff15Schris     */
723a97d936SAndreas Gohr    public function getMenuText($language)
733a97d936SAndreas Gohr    {
740440ff15Schris
753a97d936SAndreas Gohr        if (!is_null($this->auth))
760440ff15Schris            return parent::getMenuText($language);
770440ff15Schris
783a97d936SAndreas Gohr        return $this->getLang('menu') . ' ' . $this->disabled;
790440ff15Schris    }
800440ff15Schris
810440ff15Schris    /**
820440ff15Schris     * return sort order for position in admin menu
83253d4b48SGerrit Uitslag     *
84253d4b48SGerrit Uitslag     * @return int
850440ff15Schris     */
863a97d936SAndreas Gohr    public function getMenuSort()
873a97d936SAndreas Gohr    {
880440ff15Schris        return 2;
890440ff15Schris    }
900440ff15Schris
910440ff15Schris    /**
9267a31a83SMichael Große     * @return int current start value for pageination
9367a31a83SMichael Große     */
943a97d936SAndreas Gohr    public function getStart()
953a97d936SAndreas Gohr    {
963a97d936SAndreas Gohr        return $this->start;
9767a31a83SMichael Große    }
9867a31a83SMichael Große
9967a31a83SMichael Große    /**
10067a31a83SMichael Große     * @return int number of users per page
10167a31a83SMichael Große     */
1023a97d936SAndreas Gohr    public function getPagesize()
1033a97d936SAndreas Gohr    {
1043a97d936SAndreas Gohr        return $this->pagesize;
10567a31a83SMichael Große    }
10667a31a83SMichael Große
10767a31a83SMichael Große    /**
108462e9e37SMichael Große     * @param boolean $lastdisabled
109462e9e37SMichael Große     */
1103a97d936SAndreas Gohr    public function setLastdisabled($lastdisabled)
1113a97d936SAndreas Gohr    {
1123a97d936SAndreas Gohr        $this->lastdisabled = $lastdisabled;
113462e9e37SMichael Große    }
114462e9e37SMichael Große
115462e9e37SMichael Große    /**
116c5a7c0c6SGerrit Uitslag     * Handle user request
117253d4b48SGerrit Uitslag     *
118253d4b48SGerrit Uitslag     * @return bool
1190440ff15Schris     */
1203a97d936SAndreas Gohr    public function handle()
1213a97d936SAndreas Gohr    {
12200d58927SMichael Hamann        global $INPUT;
1233a97d936SAndreas Gohr        if (is_null($this->auth)) return false;
1240440ff15Schris
1250440ff15Schris        // extract the command and any specific parameters
1260440ff15Schris        // submit button name is of the form - fn[cmd][param(s)]
12700d58927SMichael Hamann        $fn = $INPUT->param('fn');
1280440ff15Schris
1290440ff15Schris        if (is_array($fn)) {
1300440ff15Schris            $cmd = key($fn);
1310440ff15Schris            $param = is_array($fn[$cmd]) ? key($fn[$cmd]) : null;
1320440ff15Schris        } else {
1330440ff15Schris            $cmd = $fn;
1340440ff15Schris            $param = null;
1350440ff15Schris        }
1360440ff15Schris
1370440ff15Schris        if ($cmd != "search") {
1383a97d936SAndreas Gohr            $this->start = $INPUT->int('start', 0);
1393a97d936SAndreas Gohr            $this->filter = $this->retrieveFilter();
1400440ff15Schris        }
1410440ff15Schris
1420440ff15Schris        switch ($cmd) {
1433a97d936SAndreas Gohr            case "add":
1443a97d936SAndreas Gohr                $this->addUser();
1450440ff15Schris                break;
1463a97d936SAndreas Gohr            case "delete":
1473a97d936SAndreas Gohr                $this->deleteUser();
1483a97d936SAndreas Gohr                break;
1493a97d936SAndreas Gohr            case "modify":
1503a97d936SAndreas Gohr                $this->modifyUser();
1513a97d936SAndreas Gohr                break;
1523a97d936SAndreas Gohr            case "edit":
1533a97d936SAndreas Gohr                $this->editUser($param);
1543a97d936SAndreas Gohr                break;
1553a97d936SAndreas Gohr            case "search":
1563a97d936SAndreas Gohr                $this->setFilter($param);
1573a97d936SAndreas Gohr                $this->start = 0;
1583a97d936SAndreas Gohr                break;
1593a97d936SAndreas Gohr            case "export":
1603a97d936SAndreas Gohr                $this->exportCSV();
1613a97d936SAndreas Gohr                break;
1623a97d936SAndreas Gohr            case "import":
1633a97d936SAndreas Gohr                $this->importCSV();
1643a97d936SAndreas Gohr                break;
1653a97d936SAndreas Gohr            case "importfails":
1663a97d936SAndreas Gohr                $this->downloadImportFailures();
1673a97d936SAndreas Gohr                break;
1680440ff15Schris        }
1690440ff15Schris
1703a97d936SAndreas Gohr        $this->users_total = $this->auth->canDo('getUserCount') ? $this->auth->getUserCount($this->filter) : -1;
1710440ff15Schris
1720440ff15Schris        // page handling
1730440ff15Schris        switch ($cmd) {
1743a97d936SAndreas Gohr            case 'start':
1753a97d936SAndreas Gohr                $this->start = 0;
1763a97d936SAndreas Gohr                break;
1773a97d936SAndreas Gohr            case 'prev':
1783a97d936SAndreas Gohr                $this->start -= $this->pagesize;
1793a97d936SAndreas Gohr                break;
1803a97d936SAndreas Gohr            case 'next':
1813a97d936SAndreas Gohr                $this->start += $this->pagesize;
1823a97d936SAndreas Gohr                break;
1833a97d936SAndreas Gohr            case 'last':
1843a97d936SAndreas Gohr                $this->start = $this->users_total;
1853a97d936SAndreas Gohr                break;
1860440ff15Schris        }
1873a97d936SAndreas Gohr        $this->validatePagination();
188c5a7c0c6SGerrit Uitslag        return true;
1890440ff15Schris    }
1900440ff15Schris
1910440ff15Schris    /**
192c5a7c0c6SGerrit Uitslag     * Output appropriate html
193253d4b48SGerrit Uitslag     *
194253d4b48SGerrit Uitslag     * @return bool
195a664aabaSAndreas Gohr     * @todo split into smaller functions, use Form class
1960440ff15Schris     */
1973a97d936SAndreas Gohr    public function html()
1983a97d936SAndreas Gohr    {
1990440ff15Schris        global $ID;
2000440ff15Schris
2013a97d936SAndreas Gohr        if (is_null($this->auth)) {
20226dfc232SAndreas Gohr            echo $this->lang['badauth'];
2030440ff15Schris            return false;
2040440ff15Schris        }
2050440ff15Schris
2063a97d936SAndreas Gohr        $user_list = $this->auth->retrieveUsers($this->start, $this->pagesize, $this->filter);
2070440ff15Schris
2083a97d936SAndreas Gohr        $page_buttons = $this->pagination();
2093a97d936SAndreas Gohr        $delete_disable = $this->auth->canDo('delUser') ? '' : 'disabled="disabled"';
2100440ff15Schris
2113a97d936SAndreas Gohr        $editable = $this->auth->canDo('UserMod');
2123a97d936SAndreas Gohr        $export_label = empty($this->filter) ? $this->lang['export_all'] : $this->lang['export_filtered'];
2136154103cSmatthiasgrimm
21426dfc232SAndreas Gohr        echo $this->locale_xhtml('intro');
21526dfc232SAndreas Gohr        echo $this->locale_xhtml('list');
2160440ff15Schris
217a664aabaSAndreas Gohr        echo '<div id="user__manager">';
218a664aabaSAndreas Gohr        echo '<div class="level2">';
2190440ff15Schris
2203a97d936SAndreas Gohr        if ($this->users_total > 0) {
221a664aabaSAndreas Gohr            printf(
222a664aabaSAndreas Gohr                '<p>' . $this->lang['summary'] . '</p>',
2233a97d936SAndreas Gohr                $this->start + 1,
2243a97d936SAndreas Gohr                $this->last,
2253a97d936SAndreas Gohr                $this->users_total,
2263a97d936SAndreas Gohr                $this->auth->getUserCount()
22764159a61SAndreas Gohr            );
2280440ff15Schris        } else {
2293a97d936SAndreas Gohr            if ($this->users_total < 0) {
230a102b175SGerrit Uitslag                $allUserTotal = 0;
231a102b175SGerrit Uitslag            } else {
2323a97d936SAndreas Gohr                $allUserTotal = $this->auth->getUserCount();
233a102b175SGerrit Uitslag            }
234a664aabaSAndreas Gohr            printf('<p>%s</p>', sprintf($this->lang['nonefound'], $allUserTotal));
2350440ff15Schris        }
236a664aabaSAndreas Gohr        printf('<form action="%s" method="post">', wl($ID));
237634d7150SAndreas Gohr        formSecurityToken();
238a664aabaSAndreas Gohr        echo '<div class="table">';
239a664aabaSAndreas Gohr        echo '<table class="inline">';
240a664aabaSAndreas Gohr        echo '<thead>';
241a664aabaSAndreas Gohr        echo '<tr>';
242a664aabaSAndreas Gohr        echo '<th>&#160;</th>';
243a664aabaSAndreas Gohr        echo '<th>' . $this->lang["user_id"] . '</th>';
244a664aabaSAndreas Gohr        echo '<th>' . $this->lang["user_name"] . '</th>';
245a664aabaSAndreas Gohr        echo '<th>' . $this->lang["user_mail"] . '</th>';
246a664aabaSAndreas Gohr        echo '<th>' . $this->lang["user_groups"] . '</th>';
247a664aabaSAndreas Gohr        echo '</tr>';
2480440ff15Schris
249a664aabaSAndreas Gohr        echo '<tr>';
250a664aabaSAndreas Gohr        echo '<td class="rightalign"><input type="image" src="' .
251a664aabaSAndreas Gohr            self::IMAGE_DIR . 'search.png" name="fn[search][new]" title="' .
252a664aabaSAndreas Gohr            $this->lang['search_prompt'] . '" alt="' . $this->lang['search'] . '" class="button" /></td>';
253a664aabaSAndreas Gohr        echo '<td><input type="text" name="userid" class="edit" value="' . $this->htmlFilter('user') . '" /></td>';
254a664aabaSAndreas Gohr        echo '<td><input type="text" name="username" class="edit" value="' . $this->htmlFilter('name') . '" /></td>';
255a664aabaSAndreas Gohr        echo '<td><input type="text" name="usermail" class="edit" value="' . $this->htmlFilter('mail') . '" /></td>';
256a664aabaSAndreas Gohr        echo '<td><input type="text" name="usergroups" class="edit" value="' . $this->htmlFilter('grps') . '" /></td>';
257a664aabaSAndreas Gohr        echo '</tr>';
258a664aabaSAndreas Gohr        echo '</thead>';
2590440ff15Schris
2603a97d936SAndreas Gohr        if ($this->users_total) {
261a664aabaSAndreas Gohr            echo '<tbody>';
2620440ff15Schris            foreach ($user_list as $user => $userinfo) {
2630440ff15Schris                extract($userinfo);
264c5a7c0c6SGerrit Uitslag                /**
265c5a7c0c6SGerrit Uitslag                 * @var string $name
266c5a7c0c6SGerrit Uitslag                 * @var string $pass
267c5a7c0c6SGerrit Uitslag                 * @var string $mail
268c5a7c0c6SGerrit Uitslag                 * @var array $grps
269c5a7c0c6SGerrit Uitslag                 */
27054cc7aa4SAndreas Gohr                $groups = implode(', ', $grps);
271a664aabaSAndreas Gohr                echo '<tr class="user_info">';
272a664aabaSAndreas Gohr                echo '<td class="centeralign"><input type="checkbox" name="delete[' . hsc($user) .
273a664aabaSAndreas Gohr                    ']" ' . $delete_disable . ' /></td>';
2742365d73dSAnika Henke                if ($editable) {
275a664aabaSAndreas Gohr                    echo '<td><a href="' . wl($ID, ['fn[edit][' . $user . ']' => 1,
27677d19185SAndreas Gohr                            'do' => 'admin',
27777d19185SAndreas Gohr                            'page' => 'usermanager',
27854cc7aa4SAndreas Gohr                            'sectok' => getSecurityToken()]) .
279a664aabaSAndreas Gohr                        '" title="' . $this->lang['edit_prompt'] . '">' . hsc($user) . '</a></td>';
2802365d73dSAnika Henke                } else {
281a664aabaSAndreas Gohr                    echo '<td>' . hsc($user) . '</td>';
2822365d73dSAnika Henke                }
283a664aabaSAndreas Gohr                echo '<td>' . hsc($name) . '</td><td>' . hsc($mail) . '</td><td>' . hsc($groups) . '</td>';
284a664aabaSAndreas Gohr                echo '</tr>';
2850440ff15Schris            }
286a664aabaSAndreas Gohr            echo '</tbody>';
2870440ff15Schris        }
2880440ff15Schris
289a664aabaSAndreas Gohr        echo '<tbody>';
290a664aabaSAndreas Gohr        echo '<tr><td colspan="5" class="centeralign">';
291a664aabaSAndreas Gohr        echo '<span class="medialeft">';
292a664aabaSAndreas Gohr        echo '<button type="submit" name="fn[delete]" id="usrmgr__del" ' . $delete_disable . '>' .
293a664aabaSAndreas Gohr            $this->lang['delete_selected'] . '</button>';
294a664aabaSAndreas Gohr        echo '</span>';
295a664aabaSAndreas Gohr        echo '<span class="mediaright">';
296a664aabaSAndreas Gohr        echo '<button type="submit" name="fn[start]" ' . $page_buttons['start'] . '>' .
297a664aabaSAndreas Gohr            $this->lang['start'] . '</button>';
298a664aabaSAndreas Gohr        echo '<button type="submit" name="fn[prev]" ' . $page_buttons['prev'] . '>' .
299a664aabaSAndreas Gohr            $this->lang['prev'] . "</button>";
300a664aabaSAndreas Gohr        echo '<button type="submit" name="fn[next]" ' . $page_buttons['next'] . '>' .
301a664aabaSAndreas Gohr            $this->lang['next'] . '</button>';
302a664aabaSAndreas Gohr        echo '<button type="submit" name="fn[last]" ' . $page_buttons['last'] . '>' .
303a664aabaSAndreas Gohr            $this->lang['last'] . '</button>';
304a664aabaSAndreas Gohr        echo '</span>';
3053a97d936SAndreas Gohr        if (!empty($this->filter)) {
306a664aabaSAndreas Gohr            echo '<button type="submit" name="fn[search][clear]">' . $this->lang['clear'] . '</button>';
3075c967d3dSChristopher Smith        }
308a664aabaSAndreas Gohr        echo '<button type="submit" name="fn[export]">' . $export_label . '</button>';
309a664aabaSAndreas Gohr        echo '<input type="hidden" name="do"    value="admin" />';
310a664aabaSAndreas Gohr        echo '<input type="hidden" name="page"  value="usermanager" />';
311daf4ca4eSAnika Henke
3123a97d936SAndreas Gohr        $this->htmlFilterSettings(2);
313daf4ca4eSAnika Henke
314a664aabaSAndreas Gohr        echo '</td></tr>';
315a664aabaSAndreas Gohr        echo '</tbody>';
316a664aabaSAndreas Gohr        echo '</table>';
317a664aabaSAndreas Gohr        echo '</div>';
3180440ff15Schris
319a664aabaSAndreas Gohr        echo '</form>';
320a664aabaSAndreas Gohr        echo '</div>';
3210440ff15Schris
322a664aabaSAndreas Gohr        $style = $this->edit_user ? ' class="edit_user"' : '';
3230440ff15Schris
3243a97d936SAndreas Gohr        if ($this->auth->canDo('addUser')) {
325a664aabaSAndreas Gohr            echo '<div' . $style . '>';
32626dfc232SAndreas Gohr            echo $this->locale_xhtml('add');
327a664aabaSAndreas Gohr            echo '<div class="level2">';
3280440ff15Schris
32954cc7aa4SAndreas Gohr            $this->htmlUserForm('add', null, [], 4);
3300440ff15Schris
331a664aabaSAndreas Gohr            echo '</div>';
332a664aabaSAndreas Gohr            echo '</div>';
3330440ff15Schris        }
3340440ff15Schris
3353a97d936SAndreas Gohr        if ($this->edit_user && $this->auth->canDo('UserMod')) {
336a664aabaSAndreas Gohr            echo '<div' . $style . ' id="scroll__here">';
33726dfc232SAndreas Gohr            echo $this->locale_xhtml('edit');
338a664aabaSAndreas Gohr            echo '<div class="level2">';
3390440ff15Schris
3403a97d936SAndreas Gohr            $this->htmlUserForm('modify', $this->edit_user, $this->edit_userdata, 4);
3410440ff15Schris
342a664aabaSAndreas Gohr            echo '</div>';
343a664aabaSAndreas Gohr            echo '</div>';
3440440ff15Schris        }
345ae1afd2fSChristopher Smith
3463a97d936SAndreas Gohr        if ($this->auth->canDo('addUser')) {
3473a97d936SAndreas Gohr            $this->htmlImportForm();
348ae1afd2fSChristopher Smith        }
349a664aabaSAndreas Gohr        echo '</div>';
350c5a7c0c6SGerrit Uitslag        return true;
3510440ff15Schris    }
3520440ff15Schris
35382fd59b6SAndreas Gohr    /**
35464cdf779SAndreas Gohr     * User Manager is only available if the auth backend supports it
35564cdf779SAndreas Gohr     *
35664cdf779SAndreas Gohr     * @inheritdoc
35764cdf779SAndreas Gohr     * @return bool
35864cdf779SAndreas Gohr     */
35964cdf779SAndreas Gohr    public function isAccessibleByCurrentUser()
36064cdf779SAndreas Gohr    {
36151ee2399SGerrit Uitslag        /** @var AuthPlugin $auth */
36264cdf779SAndreas Gohr        global $auth;
3636547cfc7SGerrit Uitslag        if (!$auth instanceof AuthPlugin || !$auth->canDo('getUsers')) {
36464cdf779SAndreas Gohr            return false;
36564cdf779SAndreas Gohr        }
36664cdf779SAndreas Gohr
36764cdf779SAndreas Gohr        return parent::isAccessibleByCurrentUser();
36864cdf779SAndreas Gohr    }
36964cdf779SAndreas Gohr
37064cdf779SAndreas Gohr
37164cdf779SAndreas Gohr    /**
372c5a7c0c6SGerrit Uitslag     * Display form to add or modify a user
373c5a7c0c6SGerrit Uitslag     *
374c5a7c0c6SGerrit Uitslag     * @param string $cmd 'add' or 'modify'
375c5a7c0c6SGerrit Uitslag     * @param string $user id of user
376c5a7c0c6SGerrit Uitslag     * @param array $userdata array with name, mail, pass and grps
377c5a7c0c6SGerrit Uitslag     * @param int $indent
378a664aabaSAndreas Gohr     * @todo use Form class
37982fd59b6SAndreas Gohr     */
38054cc7aa4SAndreas Gohr    protected function htmlUserForm($cmd, $user = '', $userdata = [], $indent = 0)
3813a97d936SAndreas Gohr    {
382a6858c6aSchris        global $conf;
383bb4866bdSchris        global $ID;
384be9008d3SChristopher Smith        global $lang;
38554cc7aa4SAndreas Gohr        $name = '';
38654cc7aa4SAndreas Gohr        $mail = '';
38754cc7aa4SAndreas Gohr        $groups = '';
38854cc7aa4SAndreas Gohr        $notes = [];
3890440ff15Schris
3900440ff15Schris        if ($user) {
39178c7c8c9Schris            extract($userdata);
39254cc7aa4SAndreas Gohr            if (!empty($grps)) $groups = implode(',', $grps);
393a6858c6aSchris        } else {
394a6858c6aSchris            $notes[] = sprintf($this->lang['note_group'], $conf['defaultgroup']);
3950440ff15Schris        }
3960440ff15Schris
397a664aabaSAndreas Gohr        printf('<form action="%s" method="post">', wl($ID));
398634d7150SAndreas Gohr        formSecurityToken();
399a664aabaSAndreas Gohr        echo '<div class="table">';
400a664aabaSAndreas Gohr        echo '<table class="inline">';
401a664aabaSAndreas Gohr        echo '<thead>';
402a664aabaSAndreas Gohr        echo '<tr><th>' . $this->lang["field"] . "</th><th>" . $this->lang["value"] . "</th></tr>";
403a664aabaSAndreas Gohr        echo '</thead>';
404a664aabaSAndreas Gohr        echo '<tbody>';
40526fb387bSchris
4063a97d936SAndreas Gohr        $this->htmlInputField(
40764159a61SAndreas Gohr            $cmd . "_userid",
40864159a61SAndreas Gohr            "userid",
40964159a61SAndreas Gohr            $this->lang["user_id"],
41064159a61SAndreas Gohr            $user,
4113a97d936SAndreas Gohr            $this->auth->canDo("modLogin"),
41264159a61SAndreas Gohr            true,
41364159a61SAndreas Gohr            $indent + 6
41464159a61SAndreas Gohr        );
4153a97d936SAndreas Gohr        $this->htmlInputField(
41664159a61SAndreas Gohr            $cmd . "_userpass",
41764159a61SAndreas Gohr            "userpass",
41864159a61SAndreas Gohr            $this->lang["user_pass"],
41964159a61SAndreas Gohr            "",
4203a97d936SAndreas Gohr            $this->auth->canDo("modPass"),
42164159a61SAndreas Gohr            false,
42264159a61SAndreas Gohr            $indent + 6
42364159a61SAndreas Gohr        );
4243a97d936SAndreas Gohr        $this->htmlInputField(
42564159a61SAndreas Gohr            $cmd . "_userpass2",
42664159a61SAndreas Gohr            "userpass2",
42764159a61SAndreas Gohr            $lang["passchk"],
42864159a61SAndreas Gohr            "",
4293a97d936SAndreas Gohr            $this->auth->canDo("modPass"),
43064159a61SAndreas Gohr            false,
43164159a61SAndreas Gohr            $indent + 6
43264159a61SAndreas Gohr        );
4333a97d936SAndreas Gohr        $this->htmlInputField(
43464159a61SAndreas Gohr            $cmd . "_username",
43564159a61SAndreas Gohr            "username",
43664159a61SAndreas Gohr            $this->lang["user_name"],
43764159a61SAndreas Gohr            $name,
4383a97d936SAndreas Gohr            $this->auth->canDo("modName"),
43964159a61SAndreas Gohr            true,
44064159a61SAndreas Gohr            $indent + 6
44164159a61SAndreas Gohr        );
4423a97d936SAndreas Gohr        $this->htmlInputField(
44364159a61SAndreas Gohr            $cmd . "_usermail",
44464159a61SAndreas Gohr            "usermail",
44564159a61SAndreas Gohr            $this->lang["user_mail"],
44664159a61SAndreas Gohr            $mail,
4473a97d936SAndreas Gohr            $this->auth->canDo("modMail"),
44864159a61SAndreas Gohr            true,
44964159a61SAndreas Gohr            $indent + 6
45064159a61SAndreas Gohr        );
4513a97d936SAndreas Gohr        $this->htmlInputField(
45264159a61SAndreas Gohr            $cmd . "_usergroups",
45364159a61SAndreas Gohr            "usergroups",
45464159a61SAndreas Gohr            $this->lang["user_groups"],
45564159a61SAndreas Gohr            $groups,
4563a97d936SAndreas Gohr            $this->auth->canDo("modGroups"),
45764159a61SAndreas Gohr            false,
45864159a61SAndreas Gohr            $indent + 6
45964159a61SAndreas Gohr        );
46026fb387bSchris
4613a97d936SAndreas Gohr        if ($this->auth->canDo("modPass")) {
462ee9498f5SChristopher Smith            if ($cmd == 'add') {
463c3f4fb63SGina Haeussge                $notes[] = $this->lang['note_pass'];
464ee9498f5SChristopher Smith            }
465a6858c6aSchris            if ($user) {
466a6858c6aSchris                $notes[] = $this->lang['note_notify'];
467a6858c6aSchris            }
468a6858c6aSchris
469a664aabaSAndreas Gohr            echo '<tr><td><label for="' . $cmd . "_usernotify\" >" .
470a664aabaSAndreas Gohr                $this->lang["user_notify"] . ': </label></td>
471a664aabaSAndreas Gohr                 <td><input type="checkbox" id="' . $cmd . '_usernotify" name="usernotify" value="1" />
472a664aabaSAndreas Gohr                 </td></tr>';
473a6858c6aSchris        }
474a6858c6aSchris
475a664aabaSAndreas Gohr        echo '</tbody>';
476a664aabaSAndreas Gohr        echo '<tbody>';
477a664aabaSAndreas Gohr        echo '<tr>';
478a664aabaSAndreas Gohr        echo '<td colspan="2">';
479a664aabaSAndreas Gohr        echo '<input type="hidden" name="do"    value="admin" />';
480a664aabaSAndreas Gohr        echo '<input type="hidden" name="page"  value="usermanager" />';
4810440ff15Schris
4820440ff15Schris        // save current $user, we need this to access details if the name is changed
483a664aabaSAndreas Gohr        if ($user) {
484a664aabaSAndreas Gohr            echo '<input type="hidden" name="userid_old"  value="' . hsc($user) . "\" />";
485a664aabaSAndreas Gohr        }
4860440ff15Schris
4873a97d936SAndreas Gohr        $this->htmlFilterSettings($indent + 10);
4880440ff15Schris
489a664aabaSAndreas Gohr        echo '<button type="submit" name="fn[' . $cmd . ']">' . $this->lang[$cmd] . '</button>';
490a664aabaSAndreas Gohr        echo '</td>';
491a664aabaSAndreas Gohr        echo '</tr>';
492a664aabaSAndreas Gohr        echo '</tbody>';
493a664aabaSAndreas Gohr        echo '</table>';
49445c19902SChristopher Smith
49545c19902SChristopher Smith        if ($notes) {
496a664aabaSAndreas Gohr            echo '<ul class="notes">';
49745c19902SChristopher Smith            foreach ($notes as $note) {
498a664aabaSAndreas Gohr                echo '<li><span class="li">' . $note . '</li>';
49945c19902SChristopher Smith            }
500a664aabaSAndreas Gohr            echo '</ul>';
50145c19902SChristopher Smith        }
502a664aabaSAndreas Gohr        echo '</div>';
503a664aabaSAndreas Gohr        echo '</form>';
5040440ff15Schris    }
5050440ff15Schris
506c5a7c0c6SGerrit Uitslag    /**
507c5a7c0c6SGerrit Uitslag     * Prints a inputfield
508c5a7c0c6SGerrit Uitslag     *
509c5a7c0c6SGerrit Uitslag     * @param string $id
510c5a7c0c6SGerrit Uitslag     * @param string $name
511c5a7c0c6SGerrit Uitslag     * @param string $label
512c5a7c0c6SGerrit Uitslag     * @param string $value
513c5a7c0c6SGerrit Uitslag     * @param bool $cando whether auth backend is capable to do this action
5149b82d43fSAndreas Gohr     * @param bool $required is this field required?
515c5a7c0c6SGerrit Uitslag     * @param int $indent
516a664aabaSAndreas Gohr     * @todo obsolete when Form class is used
517c5a7c0c6SGerrit Uitslag     */
5183a97d936SAndreas Gohr    protected function htmlInputField($id, $name, $label, $value, $cando, $required, $indent = 0)
5193a97d936SAndreas Gohr    {
5207de12fceSAndreas Gohr        $class = $cando ? '' : ' class="disabled"';
5217de12fceSAndreas Gohr        echo str_pad('', $indent);
5227de12fceSAndreas Gohr
523359e9417SChristopher Smith        if ($name == 'userpass' || $name == 'userpass2') {
524d796a891SAndreas Gohr            $fieldtype = 'password';
525d796a891SAndreas Gohr            $autocomp = 'autocomplete="off"';
5267b3674bdSChristopher Smith        } elseif ($name == 'usermail') {
5277b3674bdSChristopher Smith            $fieldtype = 'email';
5287b3674bdSChristopher Smith            $autocomp = '';
529d796a891SAndreas Gohr        } else {
530d796a891SAndreas Gohr            $fieldtype = 'text';
531d796a891SAndreas Gohr            $autocomp = '';
532d796a891SAndreas Gohr        }
533f23f9594SAndreas Gohr        $value = hsc($value);
534d796a891SAndreas Gohr
5357de12fceSAndreas Gohr        echo "<tr $class>";
5367de12fceSAndreas Gohr        echo "<td><label for=\"$id\" >$label: </label></td>";
537a664aabaSAndreas Gohr        echo '<td>';
5387de12fceSAndreas Gohr        if ($cando) {
5399b82d43fSAndreas Gohr            $req = '';
5409b82d43fSAndreas Gohr            if ($required) $req = 'required="required"';
54164159a61SAndreas Gohr            echo "<input type=\"$fieldtype\" id=\"$id\" name=\"$name\"
54264159a61SAndreas Gohr                  value=\"$value\" class=\"edit\" $autocomp $req />";
5437de12fceSAndreas Gohr        } else {
5447de12fceSAndreas Gohr            echo "<input type=\"hidden\" name=\"$name\" value=\"$value\" />";
54564159a61SAndreas Gohr            echo "<input type=\"$fieldtype\" id=\"$id\" name=\"$name\"
54664159a61SAndreas Gohr                  value=\"$value\" class=\"edit disabled\" disabled=\"disabled\" />";
5477de12fceSAndreas Gohr        }
548a664aabaSAndreas Gohr        echo '</td>';
549a664aabaSAndreas Gohr        echo '</tr>';
55026fb387bSchris    }
55126fb387bSchris
552c5a7c0c6SGerrit Uitslag    /**
553c5a7c0c6SGerrit Uitslag     * Returns htmlescaped filter value
554c5a7c0c6SGerrit Uitslag     *
555c5a7c0c6SGerrit Uitslag     * @param string $key name of search field
556c5a7c0c6SGerrit Uitslag     * @return string html escaped value
557c5a7c0c6SGerrit Uitslag     */
5583a97d936SAndreas Gohr    protected function htmlFilter($key)
5593a97d936SAndreas Gohr    {
5603a97d936SAndreas Gohr        if (empty($this->filter)) return '';
5613a97d936SAndreas Gohr        return (isset($this->filter[$key]) ? hsc($this->filter[$key]) : '');
5620440ff15Schris    }
5630440ff15Schris
564c5a7c0c6SGerrit Uitslag    /**
565c5a7c0c6SGerrit Uitslag     * Print hidden inputs with the current filter values
566c5a7c0c6SGerrit Uitslag     *
567c5a7c0c6SGerrit Uitslag     * @param int $indent
568c5a7c0c6SGerrit Uitslag     */
5693a97d936SAndreas Gohr    protected function htmlFilterSettings($indent = 0)
5703a97d936SAndreas Gohr    {
5710440ff15Schris
572a664aabaSAndreas Gohr        echo '<input type="hidden" name="start" value="' . $this->start . '" />';
5730440ff15Schris
5743a97d936SAndreas Gohr        foreach ($this->filter as $key => $filter) {
575a664aabaSAndreas Gohr            echo '<input type="hidden" name="filter[' . $key . ']" value="' . hsc($filter) . '" />';
5760440ff15Schris        }
5770440ff15Schris    }
5780440ff15Schris
579c5a7c0c6SGerrit Uitslag    /**
580c5a7c0c6SGerrit Uitslag     * Print import form and summary of previous import
581c5a7c0c6SGerrit Uitslag     *
582c5a7c0c6SGerrit Uitslag     * @param int $indent
583c5a7c0c6SGerrit Uitslag     */
5843a97d936SAndreas Gohr    protected function htmlImportForm($indent = 0)
5853a97d936SAndreas Gohr    {
586ae1afd2fSChristopher Smith        global $ID;
587ae1afd2fSChristopher Smith
58854cc7aa4SAndreas Gohr        $failure_download_link = wl($ID, ['do' => 'admin', 'page' => 'usermanager', 'fn[importfails]' => 1]);
589ae1afd2fSChristopher Smith
590a664aabaSAndreas Gohr        echo '<div class="level2 import_users">';
59126dfc232SAndreas Gohr        echo $this->locale_xhtml('import');
592a664aabaSAndreas Gohr        echo '<form action="' . wl($ID) . '" method="post" enctype="multipart/form-data">';
593ae1afd2fSChristopher Smith        formSecurityToken();
594a664aabaSAndreas Gohr        echo '<label>' . $this->lang['import_userlistcsv'] . '<input type="file" name="import" /></label>';
595a664aabaSAndreas Gohr        echo '<button type="submit" name="fn[import]">' . $this->lang['import'] . '</button>';
596a664aabaSAndreas Gohr        echo '<input type="hidden" name="do"    value="admin" />';
597a664aabaSAndreas Gohr        echo '<input type="hidden" name="page"  value="usermanager" />';
598ae1afd2fSChristopher Smith
5993a97d936SAndreas Gohr        $this->htmlFilterSettings($indent + 4);
600a664aabaSAndreas Gohr        echo '</form>';
601a664aabaSAndreas Gohr        echo '</div>';
602ae1afd2fSChristopher Smith
603ae1afd2fSChristopher Smith        // list failures from the previous import
6043a97d936SAndreas Gohr        if ($this->import_failures) {
6053a97d936SAndreas Gohr            $digits = strlen(count($this->import_failures));
606a664aabaSAndreas Gohr            echo '<div class="level3 import_failures">';
607a664aabaSAndreas Gohr            echo '<h3>' . $this->lang['import_header'] . '</h3>';
608a664aabaSAndreas Gohr            echo '<table class="import_failures">';
609a664aabaSAndreas Gohr            echo '<thead>';
610a664aabaSAndreas Gohr            echo '<tr>';
611a664aabaSAndreas Gohr            echo '<th class="line">' . $this->lang['line'] . '</th>';
612a664aabaSAndreas Gohr            echo '<th class="error">' . $this->lang['error'] . '</th>';
613a664aabaSAndreas Gohr            echo '<th class="userid">' . $this->lang['user_id'] . '</th>';
614a664aabaSAndreas Gohr            echo '<th class="username">' . $this->lang['user_name'] . '</th>';
615a664aabaSAndreas Gohr            echo '<th class="usermail">' . $this->lang['user_mail'] . '</th>';
616a664aabaSAndreas Gohr            echo '<th class="usergroups">' . $this->lang['user_groups'] . '</th>';
617a664aabaSAndreas Gohr            echo '</tr>';
618a664aabaSAndreas Gohr            echo '</thead>';
619a664aabaSAndreas Gohr            echo '<tbody>';
6203a97d936SAndreas Gohr            foreach ($this->import_failures as $line => $failure) {
621a664aabaSAndreas Gohr                echo '<tr>';
622a664aabaSAndreas Gohr                echo '<td class="lineno"> ' . sprintf('%0' . $digits . 'd', $line) . ' </td>';
623a664aabaSAndreas Gohr                echo '<td class="error">' . $failure['error'] . ' </td>';
624a664aabaSAndreas Gohr                echo '<td class="field userid"> ' . hsc($failure['user'][0]) . ' </td>';
625a664aabaSAndreas Gohr                echo '<td class="field username"> ' . hsc($failure['user'][2]) . ' </td>';
626a664aabaSAndreas Gohr                echo '<td class="field usermail"> ' . hsc($failure['user'][3]) . ' </td>';
627a664aabaSAndreas Gohr                echo '<td class="field usergroups"> ' . hsc($failure['user'][4]) . ' </td>';
628a664aabaSAndreas Gohr                echo '</tr>';
629ae1afd2fSChristopher Smith            }
630a664aabaSAndreas Gohr            echo '</tbody>';
631a664aabaSAndreas Gohr            echo '</table>';
632a664aabaSAndreas Gohr            echo '<p><a href="' . $failure_download_link . '">' . $this->lang['import_downloadfailures'] . '</a></p>';
633a664aabaSAndreas Gohr            echo '</div>';
634ae1afd2fSChristopher Smith        }
635ae1afd2fSChristopher Smith    }
636ae1afd2fSChristopher Smith
637c5a7c0c6SGerrit Uitslag    /**
638c5a7c0c6SGerrit Uitslag     * Add an user to auth backend
639c5a7c0c6SGerrit Uitslag     *
640c5a7c0c6SGerrit Uitslag     * @return bool whether succesful
641c5a7c0c6SGerrit Uitslag     */
6423a97d936SAndreas Gohr    protected function addUser()
6433a97d936SAndreas Gohr    {
64400d58927SMichael Hamann        global $INPUT;
645634d7150SAndreas Gohr        if (!checkSecurityToken()) return false;
6463a97d936SAndreas Gohr        if (!$this->auth->canDo('addUser')) return false;
6470440ff15Schris
64854cc7aa4SAndreas Gohr        [$user, $pass, $name, $mail, $grps, $passconfirm] = $this->retrieveUser();
6490440ff15Schris        if (empty($user)) return false;
6506733c4d7SChris Smith
6513a97d936SAndreas Gohr        if ($this->auth->canDo('modPass')) {
652c3f4fb63SGina Haeussge            if (empty($pass)) {
65300d58927SMichael Hamann                if ($INPUT->has('usernotify')) {
6548a285f7fSAndreas Gohr                    $pass = auth_pwgen($user);
655c3f4fb63SGina Haeussge                } else {
65660b9901bSAndreas Gohr                    msg($this->lang['add_fail'], -1);
65709a5dcd6SMichael Große                    msg($this->lang['addUser_error_missing_pass'], -1);
65860b9901bSAndreas Gohr                    return false;
65960b9901bSAndreas Gohr                }
66054cc7aa4SAndreas Gohr            } elseif (!$this->verifyPassword($pass, $passconfirm)) {
66109a5dcd6SMichael Große                msg($this->lang['add_fail'], -1);
66209a5dcd6SMichael Große                msg($this->lang['addUser_error_pass_not_identical'], -1);
663359e9417SChristopher Smith                return false;
664359e9417SChristopher Smith            }
66554cc7aa4SAndreas Gohr        } elseif (!empty($pass)) {
6666733c4d7SChris Smith            msg($this->lang['add_fail'], -1);
66709a5dcd6SMichael Große            msg($this->lang['addUser_error_modPass_disabled'], -1);
6686733c4d7SChris Smith            return false;
6696733c4d7SChris Smith        }
6706733c4d7SChris Smith
6713a97d936SAndreas Gohr        if ($this->auth->canDo('modName')) {
6726733c4d7SChris Smith            if (empty($name)) {
6736733c4d7SChris Smith                msg($this->lang['add_fail'], -1);
67409a5dcd6SMichael Große                msg($this->lang['addUser_error_name_missing'], -1);
6756733c4d7SChris Smith                return false;
6766733c4d7SChris Smith            }
67754cc7aa4SAndreas Gohr        } elseif (!empty($name)) {
67809a5dcd6SMichael Große            msg($this->lang['add_fail'], -1);
67909a5dcd6SMichael Große            msg($this->lang['addUser_error_modName_disabled'], -1);
6806733c4d7SChris Smith            return false;
6816733c4d7SChris Smith        }
6826733c4d7SChris Smith
6833a97d936SAndreas Gohr        if ($this->auth->canDo('modMail')) {
6846733c4d7SChris Smith            if (empty($mail)) {
6856733c4d7SChris Smith                msg($this->lang['add_fail'], -1);
68609a5dcd6SMichael Große                msg($this->lang['addUser_error_mail_missing'], -1);
6876733c4d7SChris Smith                return false;
6886733c4d7SChris Smith            }
68954cc7aa4SAndreas Gohr        } elseif (!empty($mail)) {
69009a5dcd6SMichael Große            msg($this->lang['add_fail'], -1);
69109a5dcd6SMichael Große            msg($this->lang['addUser_error_modMail_disabled'], -1);
6926733c4d7SChris Smith            return false;
6936733c4d7SChris Smith        }
6940440ff15Schris
69554cc7aa4SAndreas Gohr        if ($ok = $this->auth->triggerUserMod('create', [$user, $pass, $name, $mail, $grps])) {
696a6858c6aSchris            msg($this->lang['add_ok'], 1);
697a6858c6aSchris
69800d58927SMichael Hamann            if ($INPUT->has('usernotify') && $pass) {
6993a97d936SAndreas Gohr                $this->notifyUser($user, $pass);
700a6858c6aSchris            }
701a6858c6aSchris        } else {
70260b9901bSAndreas Gohr            msg($this->lang['add_fail'], -1);
70309a5dcd6SMichael Große            msg($this->lang['addUser_error_create_event_failed'], -1);
704a6858c6aSchris        }
705a6858c6aSchris
706a6858c6aSchris        return $ok;
7070440ff15Schris    }
7080440ff15Schris
7090440ff15Schris    /**
710c5a7c0c6SGerrit Uitslag     * Delete user from auth backend
711c5a7c0c6SGerrit Uitslag     *
712c5a7c0c6SGerrit Uitslag     * @return bool whether succesful
7130440ff15Schris     */
7143a97d936SAndreas Gohr    protected function deleteUser()
7153a97d936SAndreas Gohr    {
71600d58927SMichael Hamann        global $conf, $INPUT;
7179ec82636SAndreas Gohr
718634d7150SAndreas Gohr        if (!checkSecurityToken()) return false;
7193a97d936SAndreas Gohr        if (!$this->auth->canDo('delUser')) return false;
7200440ff15Schris
72100d58927SMichael Hamann        $selected = $INPUT->arr('delete');
72200d58927SMichael Hamann        if (empty($selected)) return false;
7230440ff15Schris        $selected = array_keys($selected);
7240440ff15Schris
725c9a8f912SMichael Klier        if (in_array($_SERVER['REMOTE_USER'], $selected)) {
726c8f55459SDamien Regad            msg($this->lang['delete_fail_self'], -1);
727c9a8f912SMichael Klier            return false;
728c9a8f912SMichael Klier        }
729c9a8f912SMichael Klier
73054cc7aa4SAndreas Gohr        $count = $this->auth->triggerUserMod('delete', [$selected]);
7310440ff15Schris        if ($count == count($selected)) {
7320440ff15Schris            $text = str_replace('%d', $count, $this->lang['delete_ok']);
7330440ff15Schris            msg("$text.", 1);
7340440ff15Schris        } else {
7350440ff15Schris            $part1 = str_replace('%d', $count, $this->lang['delete_ok']);
7360440ff15Schris            $part2 = str_replace('%d', (count($selected) - $count), $this->lang['delete_fail']);
7370440ff15Schris            msg("$part1, $part2", -1);
7380440ff15Schris        }
73978c7c8c9Schris
7409ec82636SAndreas Gohr        // invalidate all sessions
7419ec82636SAndreas Gohr        io_saveFile($conf['cachedir'] . '/sessionpurge', time());
7429ec82636SAndreas Gohr
74378c7c8c9Schris        return true;
74478c7c8c9Schris    }
74578c7c8c9Schris
74678c7c8c9Schris    /**
74778c7c8c9Schris     * Edit user (a user has been selected for editing)
748c5a7c0c6SGerrit Uitslag     *
749c5a7c0c6SGerrit Uitslag     * @param string $param id of the user
750c5a7c0c6SGerrit Uitslag     * @return bool whether succesful
75178c7c8c9Schris     */
7523a97d936SAndreas Gohr    protected function editUser($param)
7533a97d936SAndreas Gohr    {
754634d7150SAndreas Gohr        if (!checkSecurityToken()) return false;
7553a97d936SAndreas Gohr        if (!$this->auth->canDo('UserMod')) return false;
7563a97d936SAndreas Gohr        $user = $this->auth->cleanUser(preg_replace('/.*[:\/]/', '', $param));
7573a97d936SAndreas Gohr        $userdata = $this->auth->getUserData($user);
75878c7c8c9Schris
75978c7c8c9Schris        // no user found?
76078c7c8c9Schris        if (!$userdata) {
76178c7c8c9Schris            msg($this->lang['edit_usermissing'], -1);
76278c7c8c9Schris            return false;
76378c7c8c9Schris        }
76478c7c8c9Schris
7653a97d936SAndreas Gohr        $this->edit_user = $user;
7663a97d936SAndreas Gohr        $this->edit_userdata = $userdata;
76778c7c8c9Schris
76878c7c8c9Schris        return true;
7690440ff15Schris    }
7700440ff15Schris
7710440ff15Schris    /**
772c5a7c0c6SGerrit Uitslag     * Modify user in the auth backend (modified user data has been recieved)
773c5a7c0c6SGerrit Uitslag     *
774c5a7c0c6SGerrit Uitslag     * @return bool whether succesful
7750440ff15Schris     */
7763a97d936SAndreas Gohr    protected function modifyUser()
7773a97d936SAndreas Gohr    {
77800d58927SMichael Hamann        global $conf, $INPUT;
7799ec82636SAndreas Gohr
780634d7150SAndreas Gohr        if (!checkSecurityToken()) return false;
7813a97d936SAndreas Gohr        if (!$this->auth->canDo('UserMod')) return false;
7820440ff15Schris
78326fb387bSchris        // get currently valid  user data
7843a97d936SAndreas Gohr        $olduser = $this->auth->cleanUser(preg_replace('/.*[:\/]/', '', $INPUT->str('userid_old')));
7853a97d936SAndreas Gohr        $oldinfo = $this->auth->getUserData($olduser);
786073766c6Smatthiasgrimm
78726fb387bSchris        // get new user data subject to change
78854cc7aa4SAndreas Gohr        [$newuser, $newpass, $newname, $newmail, $newgrps, $passconfirm] = $this->retrieveUser();
789073766c6Smatthiasgrimm        if (empty($newuser)) return false;
7900440ff15Schris
79154cc7aa4SAndreas Gohr        $changes = [];
792073766c6Smatthiasgrimm        if ($newuser != $olduser) {
7933a97d936SAndreas Gohr            if (!$this->auth->canDo('modLogin')) {        // sanity check, shouldn't be possible
79426fb387bSchris                msg($this->lang['update_fail'], -1);
79526fb387bSchris                return false;
79626fb387bSchris            }
79726fb387bSchris
79826fb387bSchris            // check if $newuser already exists
7993a97d936SAndreas Gohr            if ($this->auth->getUserData($newuser)) {
800073766c6Smatthiasgrimm                msg(sprintf($this->lang['update_exists'], $newuser), -1);
801a6858c6aSchris                $re_edit = true;
8020440ff15Schris            } else {
803073766c6Smatthiasgrimm                $changes['user'] = $newuser;
8040440ff15Schris            }
80593eefc2fSAndreas Gohr        }
8063a97d936SAndreas Gohr        if ($this->auth->canDo('modPass')) {
8072400ddcbSChristopher Smith            if ($newpass || $passconfirm) {
8083a97d936SAndreas Gohr                if ($this->verifyPassword($newpass, $passconfirm)) {
809359e9417SChristopher Smith                    $changes['pass'] = $newpass;
810359e9417SChristopher Smith                } else {
811359e9417SChristopher Smith                    return false;
812359e9417SChristopher Smith                }
81354cc7aa4SAndreas Gohr            } elseif ($INPUT->has('usernotify')) {
814359e9417SChristopher Smith                // no new password supplied, check if we need to generate one (or it stays unchanged)
815359e9417SChristopher Smith                $changes['pass'] = auth_pwgen($olduser);
816359e9417SChristopher Smith            }
817359e9417SChristopher Smith        }
8180440ff15Schris
8193a97d936SAndreas Gohr        if (!empty($newname) && $this->auth->canDo('modName') && $newname != $oldinfo['name']) {
820073766c6Smatthiasgrimm            $changes['name'] = $newname;
82140d72af6SChristopher Smith        }
8223a97d936SAndreas Gohr        if (!empty($newmail) && $this->auth->canDo('modMail') && $newmail != $oldinfo['mail']) {
823073766c6Smatthiasgrimm            $changes['mail'] = $newmail;
82440d72af6SChristopher Smith        }
8253a97d936SAndreas Gohr        if (!empty($newgrps) && $this->auth->canDo('modGroups') && $newgrps != $oldinfo['grps']) {
826073766c6Smatthiasgrimm            $changes['grps'] = $newgrps;
82740d72af6SChristopher Smith        }
8280440ff15Schris
82954cc7aa4SAndreas Gohr        if ($ok = $this->auth->triggerUserMod('modify', [$olduser, $changes])) {
8300440ff15Schris            msg($this->lang['update_ok'], 1);
831a6858c6aSchris
8326ed3476bSChristopher Smith            if ($INPUT->has('usernotify') && !empty($changes['pass'])) {
833a6858c6aSchris                $notify = empty($changes['user']) ? $olduser : $newuser;
8343a97d936SAndreas Gohr                $this->notifyUser($notify, $changes['pass']);
835a6858c6aSchris            }
836a6858c6aSchris
8379ec82636SAndreas Gohr            // invalidate all sessions
8389ec82636SAndreas Gohr            io_saveFile($conf['cachedir'] . '/sessionpurge', time());
8390440ff15Schris        } else {
8400440ff15Schris            msg($this->lang['update_fail'], -1);
8410440ff15Schris        }
84278c7c8c9Schris
843a6858c6aSchris        if (!empty($re_edit)) {
8443a97d936SAndreas Gohr            $this->editUser($olduser);
8450440ff15Schris        }
8460440ff15Schris
847a6858c6aSchris        return $ok;
848a6858c6aSchris    }
849a6858c6aSchris
850a6858c6aSchris    /**
851c5a7c0c6SGerrit Uitslag     * Send password change notification email
852c5a7c0c6SGerrit Uitslag     *
853c5a7c0c6SGerrit Uitslag     * @param string $user id of user
854c5a7c0c6SGerrit Uitslag     * @param string $password plain text
855c5a7c0c6SGerrit Uitslag     * @param bool $status_alert whether status alert should be shown
856c5a7c0c6SGerrit Uitslag     * @return bool whether succesful
857a6858c6aSchris     */
8583a97d936SAndreas Gohr    protected function notifyUser($user, $password, $status_alert = true)
8593a97d936SAndreas Gohr    {
860a6858c6aSchris
861a6858c6aSchris        if ($sent = auth_sendPassword($user, $password)) {
862328143f8SChristopher Smith            if ($status_alert) {
863a6858c6aSchris                msg($this->lang['notify_ok'], 1);
864328143f8SChristopher Smith            }
86554cc7aa4SAndreas Gohr        } elseif ($status_alert) {
866a6858c6aSchris            msg($this->lang['notify_fail'], -1);
867a6858c6aSchris        }
868a6858c6aSchris
869a6858c6aSchris        return $sent;
870a6858c6aSchris    }
871a6858c6aSchris
872a6858c6aSchris    /**
873359e9417SChristopher Smith     * Verify password meets minimum requirements
874359e9417SChristopher Smith     * :TODO: extend to support password strength
875359e9417SChristopher Smith     *
876359e9417SChristopher Smith     * @param string $password candidate string for new password
877359e9417SChristopher Smith     * @param string $confirm repeated password for confirmation
878359e9417SChristopher Smith     * @return bool   true if meets requirements, false otherwise
879359e9417SChristopher Smith     */
8803a97d936SAndreas Gohr    protected function verifyPassword($password, $confirm)
8813a97d936SAndreas Gohr    {
882be9008d3SChristopher Smith        global $lang;
883359e9417SChristopher Smith
8842400ddcbSChristopher Smith        if (empty($password) && empty($confirm)) {
885359e9417SChristopher Smith            return false;
886359e9417SChristopher Smith        }
887359e9417SChristopher Smith
888359e9417SChristopher Smith        if ($password !== $confirm) {
889be9008d3SChristopher Smith            msg($lang['regbadpass'], -1);
890359e9417SChristopher Smith            return false;
891359e9417SChristopher Smith        }
892359e9417SChristopher Smith
893359e9417SChristopher Smith        // :TODO: test password for required strength
894359e9417SChristopher Smith
895359e9417SChristopher Smith        // if we make it this far the password is good
896359e9417SChristopher Smith        return true;
897359e9417SChristopher Smith    }
898359e9417SChristopher Smith
899359e9417SChristopher Smith    /**
900c5a7c0c6SGerrit Uitslag     * Retrieve & clean user data from the form
901a6858c6aSchris     *
902c5a7c0c6SGerrit Uitslag     * @param bool $clean whether the cleanUser method of the authentication backend is applied
903a6858c6aSchris     * @return array (user, password, full name, email, array(groups))
9040440ff15Schris     */
9053a97d936SAndreas Gohr    protected function retrieveUser($clean = true)
9063a97d936SAndreas Gohr    {
90751ee2399SGerrit Uitslag        /** @var AuthPlugin $auth */
9087441e340SAndreas Gohr        global $auth;
909fbfbbe8aSHakan Sandell        global $INPUT;
9100440ff15Schris
91154cc7aa4SAndreas Gohr        $user = [];
912fbfbbe8aSHakan Sandell        $user[0] = ($clean) ? $auth->cleanUser($INPUT->str('userid')) : $INPUT->str('userid');
913fbfbbe8aSHakan Sandell        $user[1] = $INPUT->str('userpass');
914fbfbbe8aSHakan Sandell        $user[2] = $INPUT->str('username');
915fbfbbe8aSHakan Sandell        $user[3] = $INPUT->str('usermail');
916fbfbbe8aSHakan Sandell        $user[4] = explode(',', $INPUT->str('usergroups'));
917359e9417SChristopher Smith        $user[5] = $INPUT->str('userpass2'); // repeated password for confirmation
9180440ff15Schris
919093fe67eSAndreas Gohr        $user[4] = array_map(trim(...), $user[4]);
9206547cfc7SGerrit Uitslag        if ($clean) {
921093fe67eSAndreas Gohr            $user[4] = array_map($auth->cleanGroup(...), $user[4]);
9226547cfc7SGerrit Uitslag        }
9237441e340SAndreas Gohr        $user[4] = array_filter($user[4]);
9247441e340SAndreas Gohr        $user[4] = array_unique($user[4]);
9256547cfc7SGerrit Uitslag        if ($user[4] === []) {
9266547cfc7SGerrit Uitslag            $user[4] = null;
9276547cfc7SGerrit Uitslag        }
9280440ff15Schris
9290440ff15Schris        return $user;
9300440ff15Schris    }
9310440ff15Schris
932c5a7c0c6SGerrit Uitslag    /**
933c5a7c0c6SGerrit Uitslag     * Set the filter with the current search terms or clear the filter
934c5a7c0c6SGerrit Uitslag     *
935c5a7c0c6SGerrit Uitslag     * @param string $op 'new' or 'clear'
936c5a7c0c6SGerrit Uitslag     */
9373a97d936SAndreas Gohr    protected function setFilter($op)
9383a97d936SAndreas Gohr    {
9390440ff15Schris
94054cc7aa4SAndreas Gohr        $this->filter = [];
9410440ff15Schris
9420440ff15Schris        if ($op == 'new') {
943a19c9aa0SGerrit Uitslag            [$user, /* pass */, $name, $mail, $grps] = $this->retrieveUser(false);
9440440ff15Schris
9453a97d936SAndreas Gohr            if (!empty($user)) $this->filter['user'] = $user;
9463a97d936SAndreas Gohr            if (!empty($name)) $this->filter['name'] = $name;
9473a97d936SAndreas Gohr            if (!empty($mail)) $this->filter['mail'] = $mail;
94854cc7aa4SAndreas Gohr            if (!empty($grps)) $this->filter['grps'] = implode('|', $grps);
9490440ff15Schris        }
9500440ff15Schris    }
9510440ff15Schris
952c5a7c0c6SGerrit Uitslag    /**
953c5a7c0c6SGerrit Uitslag     * Get the current search terms
954c5a7c0c6SGerrit Uitslag     *
955c5a7c0c6SGerrit Uitslag     * @return array
956c5a7c0c6SGerrit Uitslag     */
9573a97d936SAndreas Gohr    protected function retrieveFilter()
9583a97d936SAndreas Gohr    {
959fbfbbe8aSHakan Sandell        global $INPUT;
9600440ff15Schris
961fbfbbe8aSHakan Sandell        $t_filter = $INPUT->arr('filter');
9620440ff15Schris
9630440ff15Schris        // messy, but this way we ensure we aren't getting any additional crap from malicious users
96454cc7aa4SAndreas Gohr        $filter = [];
9650440ff15Schris
9660440ff15Schris        if (isset($t_filter['user'])) $filter['user'] = $t_filter['user'];
9670440ff15Schris        if (isset($t_filter['name'])) $filter['name'] = $t_filter['name'];
9680440ff15Schris        if (isset($t_filter['mail'])) $filter['mail'] = $t_filter['mail'];
9690440ff15Schris        if (isset($t_filter['grps'])) $filter['grps'] = $t_filter['grps'];
9700440ff15Schris
9710440ff15Schris        return $filter;
9720440ff15Schris    }
9730440ff15Schris
974c5a7c0c6SGerrit Uitslag    /**
975c5a7c0c6SGerrit Uitslag     * Validate and improve the pagination values
976c5a7c0c6SGerrit Uitslag     */
9773a97d936SAndreas Gohr    protected function validatePagination()
9783a97d936SAndreas Gohr    {
9790440ff15Schris
9803a97d936SAndreas Gohr        if ($this->start >= $this->users_total) {
9813a97d936SAndreas Gohr            $this->start = $this->users_total - $this->pagesize;
9820440ff15Schris        }
9833a97d936SAndreas Gohr        if ($this->start < 0) $this->start = 0;
9840440ff15Schris
9853a97d936SAndreas Gohr        $this->last = min($this->users_total, $this->start + $this->pagesize);
9860440ff15Schris    }
9870440ff15Schris
988c5a7c0c6SGerrit Uitslag    /**
989c5a7c0c6SGerrit Uitslag     * Return an array of strings to enable/disable pagination buttons
990c5a7c0c6SGerrit Uitslag     *
991c5a7c0c6SGerrit Uitslag     * @return array with enable/disable attributes
9920440ff15Schris     */
9933a97d936SAndreas Gohr    protected function pagination()
9943a97d936SAndreas Gohr    {
9950440ff15Schris
99651d94d49Schris        $disabled = 'disabled="disabled"';
99751d94d49Schris
99854cc7aa4SAndreas Gohr        $buttons = [];
9993a97d936SAndreas Gohr        $buttons['start'] = $buttons['prev'] = ($this->start == 0) ? $disabled : '';
100051d94d49Schris
10013a97d936SAndreas Gohr        if ($this->users_total == -1) {
100251d94d49Schris            $buttons['last'] = $disabled;
100351d94d49Schris            $buttons['next'] = '';
100451d94d49Schris        } else {
100564159a61SAndreas Gohr            $buttons['last'] = $buttons['next'] =
10063a97d936SAndreas Gohr                (($this->start + $this->pagesize) >= $this->users_total) ? $disabled : '';
100751d94d49Schris        }
10080440ff15Schris
10093a97d936SAndreas Gohr        if ($this->lastdisabled) {
1010462e9e37SMichael Große            $buttons['last'] = $disabled;
1011462e9e37SMichael Große        }
1012462e9e37SMichael Große
10130440ff15Schris        return $buttons;
10140440ff15Schris    }
10155c967d3dSChristopher Smith
1016c5a7c0c6SGerrit Uitslag    /**
1017c5a7c0c6SGerrit Uitslag     * Export a list of users in csv format using the current filter criteria
10185c967d3dSChristopher Smith     */
10193a97d936SAndreas Gohr    protected function exportCSV()
10203a97d936SAndreas Gohr    {
10215c967d3dSChristopher Smith        // list of users for export - based on current filter criteria
10223a97d936SAndreas Gohr        $user_list = $this->auth->retrieveUsers(0, 0, $this->filter);
102354cc7aa4SAndreas Gohr        $column_headings = [
10245c967d3dSChristopher Smith            $this->lang["user_id"],
10255c967d3dSChristopher Smith            $this->lang["user_name"],
10265c967d3dSChristopher Smith            $this->lang["user_mail"],
10275c967d3dSChristopher Smith            $this->lang["user_groups"]
102854cc7aa4SAndreas Gohr        ];
10295c967d3dSChristopher Smith
10305c967d3dSChristopher Smith        // ==============================================================================================
10315c967d3dSChristopher Smith        // GENERATE OUTPUT
10325c967d3dSChristopher Smith        // normal headers for downloading...
10335c967d3dSChristopher Smith        header('Content-type: text/csv;charset=utf-8');
10345c967d3dSChristopher Smith        header('Content-Disposition: attachment; filename="wikiusers.csv"');
10355c967d3dSChristopher Smith#       // for debugging assistance, send as text plain to the browser
10365c967d3dSChristopher Smith#       header('Content-type: text/plain;charset=utf-8');
10375c967d3dSChristopher Smith
10385c967d3dSChristopher Smith        // output the csv
10395c967d3dSChristopher Smith        $fd = fopen('php://output', 'w');
1040abc2dfe1SAndreas Gohr        fputcsv($fd, $column_headings, ',', '"', "\\");
10415c967d3dSChristopher Smith        foreach ($user_list as $user => $info) {
104254cc7aa4SAndreas Gohr            $line = [$user, $info['name'], $info['mail'], implode(',', $info['grps'])];
1043abc2dfe1SAndreas Gohr            fputcsv($fd, $line, ',', '"', "\\");
10445c967d3dSChristopher Smith        }
10455c967d3dSChristopher Smith        fclose($fd);
10463a97d936SAndreas Gohr        if (defined('DOKU_UNITTEST')) {
10473a97d936SAndreas Gohr            return;
10483a97d936SAndreas Gohr        }
1049b2c01466SChristopher Smith
10505c967d3dSChristopher Smith        die;
10515c967d3dSChristopher Smith    }
1052ae1afd2fSChristopher Smith
1053c5a7c0c6SGerrit Uitslag    /**
1054c5a7c0c6SGerrit Uitslag     * Import a file of users in csv format
1055ae1afd2fSChristopher Smith     *
1056ae1afd2fSChristopher Smith     * csv file should have 4 columns, user_id, full name, email, groups (comma separated)
1057c5a7c0c6SGerrit Uitslag     *
10585ba64050SChristopher Smith     * @return bool whether successful
1059ae1afd2fSChristopher Smith     */
10603a97d936SAndreas Gohr    protected function importCSV()
10613a97d936SAndreas Gohr    {
1062ae1afd2fSChristopher Smith        // check we are allowed to add users
1063ae1afd2fSChristopher Smith        if (!checkSecurityToken()) return false;
10643a97d936SAndreas Gohr        if (!$this->auth->canDo('addUser')) return false;
1065ae1afd2fSChristopher Smith
1066ae1afd2fSChristopher Smith        // check file uploaded ok.
10677d34963bSAndreas Gohr        if (
10687d34963bSAndreas Gohr            empty($_FILES['import']['size']) ||
10693a97d936SAndreas Gohr            !empty($_FILES['import']['error']) && $this->isUploadedFile($_FILES['import']['tmp_name'])
107064159a61SAndreas Gohr        ) {
1071ae1afd2fSChristopher Smith            msg($this->lang['import_error_upload'], -1);
1072ae1afd2fSChristopher Smith            return false;
1073ae1afd2fSChristopher Smith        }
1074ae1afd2fSChristopher Smith        // retrieve users from the file
107554cc7aa4SAndreas Gohr        $this->import_failures = [];
1076ae1afd2fSChristopher Smith        $import_success_count = 0;
1077ae1afd2fSChristopher Smith        $import_fail_count = 0;
1078ae1afd2fSChristopher Smith        $line = 0;
1079ae1afd2fSChristopher Smith        $fd = fopen($_FILES['import']['tmp_name'], 'r');
1080ae1afd2fSChristopher Smith        if ($fd) {
1081ae1afd2fSChristopher Smith            while ($csv = fgets($fd)) {
108254cc7aa4SAndreas Gohr                if (!Clean::isUtf8($csv)) {
108353c68e5cSAndreas Gohr                    $csv = Conversion::fromLatin1($csv);
1084efcec72bSChristopher Smith                }
1085abc2dfe1SAndreas Gohr                $raw = str_getcsv($csv, ',', '"', "\\");
1086ae1afd2fSChristopher Smith                $error = '';                        // clean out any errors from the previous line
1087ae1afd2fSChristopher Smith                // data checks...
1088ae1afd2fSChristopher Smith                if (1 == ++$line) {
1089ae1afd2fSChristopher Smith                    if ($raw[0] == 'user_id' || $raw[0] == $this->lang['user_id']) continue;    // skip headers
1090ae1afd2fSChristopher Smith                }
1091ae1afd2fSChristopher Smith                if (count($raw) < 4) {                                        // need at least four fields
1092ae1afd2fSChristopher Smith                    $import_fail_count++;
1093ae1afd2fSChristopher Smith                    $error = sprintf($this->lang['import_error_fields'], count($raw));
109454cc7aa4SAndreas Gohr                    $this->import_failures[$line] = ['error' => $error, 'user' => $raw, 'orig' => $csv];
1095ae1afd2fSChristopher Smith                    continue;
1096ae1afd2fSChristopher Smith                }
1097ae1afd2fSChristopher Smith                array_splice($raw, 1, 0, auth_pwgen());                          // splice in a generated password
10983a97d936SAndreas Gohr                $clean = $this->cleanImportUser($raw, $error);
10993a97d936SAndreas Gohr                if ($clean && $this->importUser($clean, $error)) {
11003a97d936SAndreas Gohr                    $sent = $this->notifyUser($clean[0], $clean[1], false);
1101328143f8SChristopher Smith                    if (!$sent) {
1102328143f8SChristopher Smith                        msg(sprintf($this->lang['import_notify_fail'], $clean[0], $clean[3]), -1);
1103328143f8SChristopher Smith                    }
1104ae1afd2fSChristopher Smith                    $import_success_count++;
1105ae1afd2fSChristopher Smith                } else {
1106ae1afd2fSChristopher Smith                    $import_fail_count++;
1107e73725baSChristopher Smith                    array_splice($raw, 1, 1);                                  // remove the spliced in password
110854cc7aa4SAndreas Gohr                    $this->import_failures[$line] = ['error' => $error, 'user' => $raw, 'orig' => $csv];
1109ae1afd2fSChristopher Smith                }
1110ae1afd2fSChristopher Smith            }
111164159a61SAndreas Gohr            msg(
111264159a61SAndreas Gohr                sprintf(
111364159a61SAndreas Gohr                    $this->lang['import_success_count'],
111464159a61SAndreas Gohr                    ($import_success_count + $import_fail_count),
111564159a61SAndreas Gohr                    $import_success_count
111664159a61SAndreas Gohr                ),
111764159a61SAndreas Gohr                ($import_success_count ? 1 : -1)
111864159a61SAndreas Gohr            );
1119ae1afd2fSChristopher Smith            if ($import_fail_count) {
1120ae1afd2fSChristopher Smith                msg(sprintf($this->lang['import_failure_count'], $import_fail_count), -1);
1121ae1afd2fSChristopher Smith            }
1122ae1afd2fSChristopher Smith        } else {
1123ae1afd2fSChristopher Smith            msg($this->lang['import_error_readfail'], -1);
1124ae1afd2fSChristopher Smith        }
1125ae1afd2fSChristopher Smith
1126ae1afd2fSChristopher Smith        // save import failures into the session
1127ae1afd2fSChristopher Smith        if (!headers_sent()) {
1128ae1afd2fSChristopher Smith            session_start();
11293a97d936SAndreas Gohr            $_SESSION['import_failures'] = $this->import_failures;
1130ae1afd2fSChristopher Smith            session_write_close();
1131ae1afd2fSChristopher Smith        }
1132c5a7c0c6SGerrit Uitslag        return true;
1133ae1afd2fSChristopher Smith    }
1134ae1afd2fSChristopher Smith
1135c5a7c0c6SGerrit Uitslag    /**
1136786dfb0eSGerrit Uitslag     * Returns cleaned user data
1137c5a7c0c6SGerrit Uitslag     *
1138c5a7c0c6SGerrit Uitslag     * @param array $candidate raw values of line from input file
1139253d4b48SGerrit Uitslag     * @param string $error
1140253d4b48SGerrit Uitslag     * @return array|false cleaned data or false
1141c5a7c0c6SGerrit Uitslag     */
11423a97d936SAndreas Gohr    protected function cleanImportUser($candidate, &$error)
11433a97d936SAndreas Gohr    {
1144ae1afd2fSChristopher Smith        global $INPUT;
1145ae1afd2fSChristopher Smith
11463a97d936SAndreas Gohr        // FIXME kludgy ....
1147ae1afd2fSChristopher Smith        $INPUT->set('userid', $candidate[0]);
1148ae1afd2fSChristopher Smith        $INPUT->set('userpass', $candidate[1]);
1149ae1afd2fSChristopher Smith        $INPUT->set('username', $candidate[2]);
1150ae1afd2fSChristopher Smith        $INPUT->set('usermail', $candidate[3]);
1151ae1afd2fSChristopher Smith        $INPUT->set('usergroups', $candidate[4]);
1152ae1afd2fSChristopher Smith
11533a97d936SAndreas Gohr        $cleaned = $this->retrieveUser();
115454cc7aa4SAndreas Gohr        [$user, /* pass */, $name, $mail, /* grps */] = $cleaned;
1155ae1afd2fSChristopher Smith        if (empty($user)) {
1156ae1afd2fSChristopher Smith            $error = $this->lang['import_error_baduserid'];
1157ae1afd2fSChristopher Smith            return false;
1158ae1afd2fSChristopher Smith        }
1159ae1afd2fSChristopher Smith
1160ae1afd2fSChristopher Smith        // no need to check password, handled elsewhere
1161ae1afd2fSChristopher Smith
11623a97d936SAndreas Gohr        if (!($this->auth->canDo('modName') xor empty($name))) {
1163ae1afd2fSChristopher Smith            $error = $this->lang['import_error_badname'];
1164ae1afd2fSChristopher Smith            return false;
1165ae1afd2fSChristopher Smith        }
1166ae1afd2fSChristopher Smith
11673a97d936SAndreas Gohr        if ($this->auth->canDo('modMail')) {
1168*73dc0a89SAndreas Gohr            if (empty($mail) || !MailUtils::isValid($mail)) {
1169ae1afd2fSChristopher Smith                $error = $this->lang['import_error_badmail'];
1170ae1afd2fSChristopher Smith                return false;
1171ae1afd2fSChristopher Smith            }
117254cc7aa4SAndreas Gohr        } elseif (!empty($mail)) {
1173328143f8SChristopher Smith            $error = $this->lang['import_error_badmail'];
1174328143f8SChristopher Smith            return false;
1175328143f8SChristopher Smith        }
1176ae1afd2fSChristopher Smith
1177ae1afd2fSChristopher Smith        return $cleaned;
1178ae1afd2fSChristopher Smith    }
1179ae1afd2fSChristopher Smith
1180c5a7c0c6SGerrit Uitslag    /**
1181c5a7c0c6SGerrit Uitslag     * Adds imported user to auth backend
1182c5a7c0c6SGerrit Uitslag     *
1183c5a7c0c6SGerrit Uitslag     * Required a check of canDo('addUser') before
1184c5a7c0c6SGerrit Uitslag     *
1185c5a7c0c6SGerrit Uitslag     * @param array $user data of user
1186c5a7c0c6SGerrit Uitslag     * @param string &$error reference catched error message
11875ba64050SChristopher Smith     * @return bool whether successful
1188c5a7c0c6SGerrit Uitslag     */
11893a97d936SAndreas Gohr    protected function importUser($user, &$error)
11903a97d936SAndreas Gohr    {
11913a97d936SAndreas Gohr        if (!$this->auth->triggerUserMod('create', $user)) {
1192ae1afd2fSChristopher Smith            $error = $this->lang['import_error_create'];
1193ae1afd2fSChristopher Smith            return false;
1194ae1afd2fSChristopher Smith        }
1195ae1afd2fSChristopher Smith
1196ae1afd2fSChristopher Smith        return true;
1197ae1afd2fSChristopher Smith    }
1198ae1afd2fSChristopher Smith
1199c5a7c0c6SGerrit Uitslag    /**
1200c5a7c0c6SGerrit Uitslag     * Downloads failures as csv file
1201c5a7c0c6SGerrit Uitslag     */
12023a97d936SAndreas Gohr    protected function downloadImportFailures()
12033a97d936SAndreas Gohr    {
1204ae1afd2fSChristopher Smith
1205ae1afd2fSChristopher Smith        // ==============================================================================================
1206ae1afd2fSChristopher Smith        // GENERATE OUTPUT
1207ae1afd2fSChristopher Smith        // normal headers for downloading...
1208ae1afd2fSChristopher Smith        header('Content-type: text/csv;charset=utf-8');
1209ae1afd2fSChristopher Smith        header('Content-Disposition: attachment; filename="importfails.csv"');
1210ae1afd2fSChristopher Smith#       // for debugging assistance, send as text plain to the browser
1211ae1afd2fSChristopher Smith#       header('Content-type: text/plain;charset=utf-8');
1212ae1afd2fSChristopher Smith
1213ae1afd2fSChristopher Smith        // output the csv
1214ae1afd2fSChristopher Smith        $fd = fopen('php://output', 'w');
12153a97d936SAndreas Gohr        foreach ($this->import_failures as $fail) {
121654cc7aa4SAndreas Gohr            fwrite($fd, $fail['orig']);
1217ae1afd2fSChristopher Smith        }
1218ae1afd2fSChristopher Smith        fclose($fd);
1219ae1afd2fSChristopher Smith        die;
1220ae1afd2fSChristopher Smith    }
1221ae1afd2fSChristopher Smith
1222b2c01466SChristopher Smith    /**
1223b2c01466SChristopher Smith     * wrapper for is_uploaded_file to facilitate overriding by test suite
1224253d4b48SGerrit Uitslag     *
1225253d4b48SGerrit Uitslag     * @param string $file filename
1226253d4b48SGerrit Uitslag     * @return bool
1227b2c01466SChristopher Smith     */
12283a97d936SAndreas Gohr    protected function isUploadedFile($file)
12293a97d936SAndreas Gohr    {
1230b2c01466SChristopher Smith        return is_uploaded_file($file);
1231b2c01466SChristopher Smith    }
12320440ff15Schris}
1233