xref: /dokuwiki/lib/plugins/usermanager/admin.php (revision 54cc7aa41e0f453bd6887b0e79242a139d84a47a)
10440ff15Schris<?php
2*54cc7aa4SAndreas Gohr
3*54cc7aa4SAndreas Gohruse dokuwiki\Utf8\Clean;
40440ff15Schris/*
50440ff15Schris *  User Manager
60440ff15Schris *
70440ff15Schris *  Dokuwiki Admin Plugin
80440ff15Schris *
90440ff15Schris *  This version of the user manager has been modified to only work with
100440ff15Schris *  objectified version of auth system
110440ff15Schris *
120440ff15Schris *  @author  neolao <neolao@neolao.com>
130440ff15Schris *  @author  Chris Smith <chris@jalakai.co.uk>
140440ff15Schris */
150440ff15Schris/**
160440ff15Schris * All DokuWiki plugins to extend the admin function
170440ff15Schris * need to inherit from this class
180440ff15Schris */
193a97d936SAndreas Gohrclass admin_plugin_usermanager extends DokuWiki_Admin_Plugin
203a97d936SAndreas Gohr{
213a97d936SAndreas Gohr    const IMAGE_DIR = DOKU_BASE.'lib/plugins/usermanager/images/';
220440ff15Schris
23*54cc7aa4SAndreas Gohr    protected $auth;        // auth object
243a97d936SAndreas Gohr    protected $users_total = 0;     // number of registered users
25*54cc7aa4SAndreas Gohr    protected $filter = [];   // user selection filter(s)
263a97d936SAndreas Gohr    protected $start = 0;          // index of first user to be displayed
273a97d936SAndreas Gohr    protected $last = 0;           // index of the last user to be displayed
283a97d936SAndreas Gohr    protected $pagesize = 20;      // number of users to list on one page
293a97d936SAndreas Gohr    protected $edit_user = '';     // set to user selected for editing
30*54cc7aa4SAndreas Gohr    protected $edit_userdata = [];
313a97d936SAndreas Gohr    protected $disabled = '';      // if disabled set to explanatory string
32*54cc7aa4SAndreas Gohr    protected $import_failures = [];
333a97d936SAndreas Gohr    protected $lastdisabled = false; // set to true if last user is unknown and last button is hence buggy
340440ff15Schris
350440ff15Schris    /**
360440ff15Schris     * Constructor
370440ff15Schris     */
383a97d936SAndreas Gohr    public function __construct()
393a97d936SAndreas Gohr    {
40c5a7c0c6SGerrit Uitslag        /** @var DokuWiki_Auth_Plugin $auth */
410440ff15Schris        global $auth;
420440ff15Schris
430440ff15Schris        $this->setupLocale();
4451d94d49Schris
4551d94d49Schris        if (!isset($auth)) {
463a97d936SAndreas Gohr            $this->disabled = $this->lang['noauth'];
4782fd59b6SAndreas Gohr        } elseif (!$auth->canDo('getUsers')) {
483a97d936SAndreas Gohr            $this->disabled = $this->lang['nosupport'];
4951d94d49Schris        } else {
5051d94d49Schris            // we're good to go
513a97d936SAndreas Gohr            $this->auth = & $auth;
5251d94d49Schris        }
53ae1afd2fSChristopher Smith
54ae1afd2fSChristopher Smith        // attempt to retrieve any import failures from the session
550e80bb5eSChristopher Smith        if (!empty($_SESSION['import_failures'])) {
563a97d936SAndreas Gohr            $this->import_failures = $_SESSION['import_failures'];
57ae1afd2fSChristopher Smith        }
580440ff15Schris    }
590440ff15Schris
600440ff15Schris    /**
61c5a7c0c6SGerrit Uitslag     * Return prompt for admin menu
62253d4b48SGerrit Uitslag     *
63253d4b48SGerrit Uitslag     * @param string $language
64253d4b48SGerrit Uitslag     * @return string
650440ff15Schris     */
663a97d936SAndreas Gohr    public function getMenuText($language)
673a97d936SAndreas Gohr    {
680440ff15Schris
693a97d936SAndreas Gohr        if (!is_null($this->auth))
700440ff15Schris          return parent::getMenuText($language);
710440ff15Schris
723a97d936SAndreas Gohr        return $this->getLang('menu').' '.$this->disabled;
730440ff15Schris    }
740440ff15Schris
750440ff15Schris    /**
760440ff15Schris     * return sort order for position in admin menu
77253d4b48SGerrit Uitslag     *
78253d4b48SGerrit Uitslag     * @return int
790440ff15Schris     */
803a97d936SAndreas Gohr    public function getMenuSort()
813a97d936SAndreas Gohr    {
820440ff15Schris        return 2;
830440ff15Schris    }
840440ff15Schris
850440ff15Schris    /**
8667a31a83SMichael Große     * @return int current start value for pageination
8767a31a83SMichael Große     */
883a97d936SAndreas Gohr    public function getStart()
893a97d936SAndreas Gohr    {
903a97d936SAndreas Gohr        return $this->start;
9167a31a83SMichael Große    }
9267a31a83SMichael Große
9367a31a83SMichael Große    /**
9467a31a83SMichael Große     * @return int number of users per page
9567a31a83SMichael Große     */
963a97d936SAndreas Gohr    public function getPagesize()
973a97d936SAndreas Gohr    {
983a97d936SAndreas Gohr        return $this->pagesize;
9967a31a83SMichael Große    }
10067a31a83SMichael Große
10167a31a83SMichael Große    /**
102462e9e37SMichael Große     * @param boolean $lastdisabled
103462e9e37SMichael Große     */
1043a97d936SAndreas Gohr    public function setLastdisabled($lastdisabled)
1053a97d936SAndreas Gohr    {
1063a97d936SAndreas Gohr        $this->lastdisabled = $lastdisabled;
107462e9e37SMichael Große    }
108462e9e37SMichael Große
109462e9e37SMichael Große    /**
110c5a7c0c6SGerrit Uitslag     * Handle user request
111253d4b48SGerrit Uitslag     *
112253d4b48SGerrit Uitslag     * @return bool
1130440ff15Schris     */
1143a97d936SAndreas Gohr    public function handle()
1153a97d936SAndreas Gohr    {
11600d58927SMichael Hamann        global $INPUT;
1173a97d936SAndreas Gohr        if (is_null($this->auth)) return false;
1180440ff15Schris
1190440ff15Schris        // extract the command and any specific parameters
1200440ff15Schris        // submit button name is of the form - fn[cmd][param(s)]
12100d58927SMichael Hamann        $fn   = $INPUT->param('fn');
1220440ff15Schris
1230440ff15Schris        if (is_array($fn)) {
1240440ff15Schris            $cmd = key($fn);
1250440ff15Schris            $param = is_array($fn[$cmd]) ? key($fn[$cmd]) : null;
1260440ff15Schris        } else {
1270440ff15Schris            $cmd = $fn;
1280440ff15Schris            $param = null;
1290440ff15Schris        }
1300440ff15Schris
1310440ff15Schris        if ($cmd != "search") {
1323a97d936SAndreas Gohr            $this->start = $INPUT->int('start', 0);
1333a97d936SAndreas Gohr            $this->filter = $this->retrieveFilter();
1340440ff15Schris        }
1350440ff15Schris
1360440ff15Schris        switch ($cmd) {
1373a97d936SAndreas Gohr            case "add":
1383a97d936SAndreas Gohr                $this->addUser();
1390440ff15Schris                break;
1403a97d936SAndreas Gohr            case "delete":
1413a97d936SAndreas Gohr                $this->deleteUser();
1423a97d936SAndreas Gohr                break;
1433a97d936SAndreas Gohr            case "modify":
1443a97d936SAndreas Gohr                $this->modifyUser();
1453a97d936SAndreas Gohr                break;
1463a97d936SAndreas Gohr            case "edit":
1473a97d936SAndreas Gohr                $this->editUser($param);
1483a97d936SAndreas Gohr                break;
1493a97d936SAndreas Gohr            case "search":
1503a97d936SAndreas Gohr                $this->setFilter($param);
1513a97d936SAndreas Gohr                            $this->start = 0;
1523a97d936SAndreas Gohr                break;
1533a97d936SAndreas Gohr            case "export":
1543a97d936SAndreas Gohr                $this->exportCSV();
1553a97d936SAndreas Gohr                break;
1563a97d936SAndreas Gohr            case "import":
1573a97d936SAndreas Gohr                $this->importCSV();
1583a97d936SAndreas Gohr                break;
1593a97d936SAndreas Gohr            case "importfails":
1603a97d936SAndreas Gohr                $this->downloadImportFailures();
1613a97d936SAndreas Gohr                break;
1620440ff15Schris        }
1630440ff15Schris
1643a97d936SAndreas Gohr        $this->users_total = $this->auth->canDo('getUserCount') ? $this->auth->getUserCount($this->filter) : -1;
1650440ff15Schris
1660440ff15Schris        // page handling
1670440ff15Schris        switch ($cmd) {
1683a97d936SAndreas Gohr            case 'start':
1693a97d936SAndreas Gohr                $this->start = 0;
1703a97d936SAndreas Gohr                break;
1713a97d936SAndreas Gohr            case 'prev':
1723a97d936SAndreas Gohr                $this->start -= $this->pagesize;
1733a97d936SAndreas Gohr                break;
1743a97d936SAndreas Gohr            case 'next':
1753a97d936SAndreas Gohr                $this->start += $this->pagesize;
1763a97d936SAndreas Gohr                break;
1773a97d936SAndreas Gohr            case 'last':
1783a97d936SAndreas Gohr                $this->start = $this->users_total;
1793a97d936SAndreas Gohr                break;
1800440ff15Schris        }
1813a97d936SAndreas Gohr        $this->validatePagination();
182c5a7c0c6SGerrit Uitslag        return true;
1830440ff15Schris    }
1840440ff15Schris
1850440ff15Schris    /**
186c5a7c0c6SGerrit Uitslag     * Output appropriate html
187253d4b48SGerrit Uitslag     *
188253d4b48SGerrit Uitslag     * @return bool
1890440ff15Schris     */
1903a97d936SAndreas Gohr    public function html()
1913a97d936SAndreas Gohr    {
1920440ff15Schris        global $ID;
1930440ff15Schris
1943a97d936SAndreas Gohr        if (is_null($this->auth)) {
1950440ff15Schris            print $this->lang['badauth'];
1960440ff15Schris            return false;
1970440ff15Schris        }
1980440ff15Schris
1993a97d936SAndreas Gohr        $user_list = $this->auth->retrieveUsers($this->start, $this->pagesize, $this->filter);
2000440ff15Schris
2013a97d936SAndreas Gohr        $page_buttons = $this->pagination();
2023a97d936SAndreas Gohr        $delete_disable = $this->auth->canDo('delUser') ? '' : 'disabled="disabled"';
2030440ff15Schris
2043a97d936SAndreas Gohr        $editable = $this->auth->canDo('UserMod');
2053a97d936SAndreas Gohr        $export_label = empty($this->filter) ? $this->lang['export_all'] : $this->lang['export_filtered'];
2066154103cSmatthiasgrimm
2070440ff15Schris        print $this->locale_xhtml('intro');
2080440ff15Schris        print $this->locale_xhtml('list');
2090440ff15Schris
21058dde80dSAnika Henke        ptln("<div id=\"user__manager\">");
21158dde80dSAnika Henke        ptln("<div class=\"level2\">");
2120440ff15Schris
2133a97d936SAndreas Gohr        if ($this->users_total > 0) {
21464159a61SAndreas Gohr            ptln(
21564159a61SAndreas Gohr                "<p>" . sprintf(
21664159a61SAndreas Gohr                    $this->lang['summary'],
2173a97d936SAndreas Gohr                    $this->start + 1,
2183a97d936SAndreas Gohr                    $this->last,
2193a97d936SAndreas Gohr                    $this->users_total,
2203a97d936SAndreas Gohr                    $this->auth->getUserCount()
22164159a61SAndreas Gohr                ) . "</p>"
22264159a61SAndreas Gohr            );
2230440ff15Schris        } else {
2243a97d936SAndreas Gohr            if ($this->users_total < 0) {
225a102b175SGerrit Uitslag                $allUserTotal = 0;
226a102b175SGerrit Uitslag            } else {
2273a97d936SAndreas Gohr                $allUserTotal = $this->auth->getUserCount();
228a102b175SGerrit Uitslag            }
229a102b175SGerrit Uitslag            ptln("<p>".sprintf($this->lang['nonefound'], $allUserTotal)."</p>");
2300440ff15Schris        }
2310440ff15Schris        ptln("<form action=\"".wl($ID)."\" method=\"post\">");
232634d7150SAndreas Gohr        formSecurityToken();
233c7b28ffdSAnika Henke        ptln("  <div class=\"table\">");
2340440ff15Schris        ptln("  <table class=\"inline\">");
2350440ff15Schris        ptln("    <thead>");
2360440ff15Schris        ptln("      <tr>");
23764159a61SAndreas Gohr        ptln("        <th>&#160;</th>
23864159a61SAndreas Gohr            <th>".$this->lang["user_id"]."</th>
23964159a61SAndreas Gohr            <th>".$this->lang["user_name"]."</th>
24064159a61SAndreas Gohr            <th>".$this->lang["user_mail"]."</th>
24164159a61SAndreas Gohr            <th>".$this->lang["user_groups"]."</th>");
2420440ff15Schris        ptln("      </tr>");
2430440ff15Schris
2440440ff15Schris        ptln("      <tr>");
24564159a61SAndreas Gohr        ptln("        <td class=\"rightalign\"><input type=\"image\" src=\"".
2463a97d936SAndreas Gohr             self::IMAGE_DIR."search.png\" name=\"fn[search][new]\" title=\"".
24764159a61SAndreas Gohr             $this->lang['search_prompt']."\" alt=\"".$this->lang['search']."\" class=\"button\" /></td>");
24864159a61SAndreas Gohr        ptln("        <td><input type=\"text\" name=\"userid\" class=\"edit\" value=\"".
2493a97d936SAndreas Gohr             $this->htmlFilter('user')."\" /></td>");
25064159a61SAndreas Gohr        ptln("        <td><input type=\"text\" name=\"username\" class=\"edit\" value=\"".
2513a97d936SAndreas Gohr             $this->htmlFilter('name')."\" /></td>");
25264159a61SAndreas Gohr        ptln("        <td><input type=\"text\" name=\"usermail\" class=\"edit\" value=\"".
2533a97d936SAndreas Gohr             $this->htmlFilter('mail')."\" /></td>");
25464159a61SAndreas Gohr        ptln("        <td><input type=\"text\" name=\"usergroups\" class=\"edit\" value=\"".
2553a97d936SAndreas Gohr             $this->htmlFilter('grps')."\" /></td>");
2560440ff15Schris        ptln("      </tr>");
2570440ff15Schris        ptln("    </thead>");
2580440ff15Schris
2593a97d936SAndreas Gohr        if ($this->users_total) {
2600440ff15Schris            ptln("    <tbody>");
2610440ff15Schris            foreach ($user_list as $user => $userinfo) {
2620440ff15Schris                extract($userinfo);
263c5a7c0c6SGerrit Uitslag                /**
264c5a7c0c6SGerrit Uitslag                 * @var string $name
265c5a7c0c6SGerrit Uitslag                 * @var string $pass
266c5a7c0c6SGerrit Uitslag                 * @var string $mail
267c5a7c0c6SGerrit Uitslag                 * @var array  $grps
268c5a7c0c6SGerrit Uitslag                 */
269*54cc7aa4SAndreas Gohr                $groups = implode(', ', $grps);
270a2c0246eSAnika Henke                ptln("    <tr class=\"user_info\">");
27164159a61SAndreas Gohr                ptln("      <td class=\"centeralign\"><input type=\"checkbox\" name=\"delete[".hsc($user).
27264159a61SAndreas Gohr                     "]\" ".$delete_disable." /></td>");
2732365d73dSAnika Henke                if ($editable) {
274*54cc7aa4SAndreas Gohr                    ptln("    <td><a href=\"".wl($ID, ['fn[edit]['.$user.']' => 1,
27577d19185SAndreas Gohr                            'do' => 'admin',
27677d19185SAndreas Gohr                            'page' => 'usermanager',
277*54cc7aa4SAndreas Gohr                            'sectok' => getSecurityToken()]).
27877d19185SAndreas Gohr                         "\" title=\"".$this->lang['edit_prompt']."\">".hsc($user)."</a></td>");
2792365d73dSAnika Henke                } else {
2802365d73dSAnika Henke                    ptln("    <td>".hsc($user)."</td>");
2812365d73dSAnika Henke                }
2822365d73dSAnika Henke                ptln("      <td>".hsc($name)."</td><td>".hsc($mail)."</td><td>".hsc($groups)."</td>");
2830440ff15Schris                ptln("    </tr>");
2840440ff15Schris            }
2850440ff15Schris            ptln("    </tbody>");
2860440ff15Schris        }
2870440ff15Schris
2880440ff15Schris        ptln("    <tbody>");
2892365d73dSAnika Henke        ptln("      <tr><td colspan=\"5\" class=\"centeralign\">");
290a2c0246eSAnika Henke        ptln("        <span class=\"medialeft\">");
29164159a61SAndreas Gohr        ptln("          <button type=\"submit\" name=\"fn[delete]\" id=\"usrmgr__del\" ".$delete_disable.">".
29264159a61SAndreas Gohr             $this->lang['delete_selected']."</button>");
29376c49356SMike Wilmes        ptln("        </span>");
29476c49356SMike Wilmes        ptln("        <span class=\"mediaright\">");
29564159a61SAndreas Gohr        ptln("          <button type=\"submit\" name=\"fn[start]\" ".$page_buttons['start'].">".
29664159a61SAndreas Gohr             $this->lang['start']."</button>");
29764159a61SAndreas Gohr        ptln("          <button type=\"submit\" name=\"fn[prev]\" ".$page_buttons['prev'].">".
29864159a61SAndreas Gohr             $this->lang['prev']."</button>");
29964159a61SAndreas Gohr        ptln("          <button type=\"submit\" name=\"fn[next]\" ".$page_buttons['next'].">".
30064159a61SAndreas Gohr             $this->lang['next']."</button>");
30164159a61SAndreas Gohr        ptln("          <button type=\"submit\" name=\"fn[last]\" ".$page_buttons['last'].">".
30264159a61SAndreas Gohr             $this->lang['last']."</button>");
30376c49356SMike Wilmes        ptln("        </span>");
3043a97d936SAndreas Gohr        if (!empty($this->filter)) {
305ae614416SAnika Henke            ptln("    <button type=\"submit\" name=\"fn[search][clear]\">".$this->lang['clear']."</button>");
3065c967d3dSChristopher Smith        }
307ae614416SAnika Henke        ptln("        <button type=\"submit\" name=\"fn[export]\">".$export_label."</button>");
3085164d9c9SAnika Henke        ptln("        <input type=\"hidden\" name=\"do\"    value=\"admin\" />");
3095164d9c9SAnika Henke        ptln("        <input type=\"hidden\" name=\"page\"  value=\"usermanager\" />");
310daf4ca4eSAnika Henke
3113a97d936SAndreas Gohr        $this->htmlFilterSettings(2);
312daf4ca4eSAnika Henke
3130440ff15Schris        ptln("      </td></tr>");
3140440ff15Schris        ptln("    </tbody>");
3150440ff15Schris        ptln("  </table>");
316c7b28ffdSAnika Henke        ptln("  </div>");
3170440ff15Schris
3180440ff15Schris        ptln("</form>");
3190440ff15Schris        ptln("</div>");
3200440ff15Schris
3213a97d936SAndreas Gohr        $style = $this->edit_user ? " class=\"edit_user\"" : "";
3220440ff15Schris
3233a97d936SAndreas Gohr        if ($this->auth->canDo('addUser')) {
3240440ff15Schris            ptln("<div".$style.">");
3250440ff15Schris            print $this->locale_xhtml('add');
3260440ff15Schris            ptln("  <div class=\"level2\">");
3270440ff15Schris
328*54cc7aa4SAndreas Gohr            $this->htmlUserForm('add', null, [], 4);
3290440ff15Schris
3300440ff15Schris            ptln("  </div>");
3310440ff15Schris            ptln("</div>");
3320440ff15Schris        }
3330440ff15Schris
3343a97d936SAndreas Gohr        if ($this->edit_user  && $this->auth->canDo('UserMod')) {
335c632fc69SAndreas Gohr            ptln("<div".$style." id=\"scroll__here\">");
3360440ff15Schris            print $this->locale_xhtml('edit');
3370440ff15Schris            ptln("  <div class=\"level2\">");
3380440ff15Schris
3393a97d936SAndreas Gohr            $this->htmlUserForm('modify', $this->edit_user, $this->edit_userdata, 4);
3400440ff15Schris
3410440ff15Schris            ptln("  </div>");
3420440ff15Schris            ptln("</div>");
3430440ff15Schris        }
344ae1afd2fSChristopher Smith
3453a97d936SAndreas Gohr        if ($this->auth->canDo('addUser')) {
3463a97d936SAndreas Gohr            $this->htmlImportForm();
347ae1afd2fSChristopher Smith        }
34858dde80dSAnika Henke        ptln("</div>");
349c5a7c0c6SGerrit Uitslag        return true;
3500440ff15Schris    }
3510440ff15Schris
35282fd59b6SAndreas Gohr    /**
35364cdf779SAndreas Gohr     * User Manager is only available if the auth backend supports it
35464cdf779SAndreas Gohr     *
35564cdf779SAndreas Gohr     * @inheritdoc
35664cdf779SAndreas Gohr     * @return bool
35764cdf779SAndreas Gohr     */
35864cdf779SAndreas Gohr    public function isAccessibleByCurrentUser()
35964cdf779SAndreas Gohr    {
36064cdf779SAndreas Gohr        /** @var DokuWiki_Auth_Plugin $auth */
36164cdf779SAndreas Gohr        global $auth;
36264cdf779SAndreas Gohr        if(!$auth || !$auth->canDo('getUsers') ) {
36364cdf779SAndreas Gohr            return false;
36464cdf779SAndreas Gohr        }
36564cdf779SAndreas Gohr
36664cdf779SAndreas Gohr        return parent::isAccessibleByCurrentUser();
36764cdf779SAndreas Gohr    }
36864cdf779SAndreas Gohr
36964cdf779SAndreas Gohr
37064cdf779SAndreas Gohr    /**
371c5a7c0c6SGerrit Uitslag     * Display form to add or modify a user
372c5a7c0c6SGerrit Uitslag     *
373c5a7c0c6SGerrit Uitslag     * @param string $cmd 'add' or 'modify'
374c5a7c0c6SGerrit Uitslag     * @param string $user id of user
375c5a7c0c6SGerrit Uitslag     * @param array  $userdata array with name, mail, pass and grps
376c5a7c0c6SGerrit Uitslag     * @param int    $indent
37782fd59b6SAndreas Gohr     */
378*54cc7aa4SAndreas Gohr    protected function htmlUserForm($cmd, $user = '', $userdata = [], $indent = 0)
3793a97d936SAndreas Gohr    {
380a6858c6aSchris        global $conf;
381bb4866bdSchris        global $ID;
382be9008d3SChristopher Smith        global $lang;
383*54cc7aa4SAndreas Gohr        $name = '';
384*54cc7aa4SAndreas Gohr        $mail = '';
385*54cc7aa4SAndreas Gohr        $groups = '';
386*54cc7aa4SAndreas Gohr        $notes = [];
3870440ff15Schris
3880440ff15Schris        if ($user) {
38978c7c8c9Schris            extract($userdata);
390*54cc7aa4SAndreas Gohr            if (!empty($grps)) $groups = implode(',', $grps);
391a6858c6aSchris        } else {
392a6858c6aSchris            $notes[] = sprintf($this->lang['note_group'], $conf['defaultgroup']);
3930440ff15Schris        }
3940440ff15Schris
3950440ff15Schris        ptln("<form action=\"".wl($ID)."\" method=\"post\">", $indent);
396634d7150SAndreas Gohr        formSecurityToken();
397c7b28ffdSAnika Henke        ptln("  <div class=\"table\">", $indent);
3980440ff15Schris        ptln("  <table class=\"inline\">", $indent);
3990440ff15Schris        ptln("    <thead>", $indent);
4000440ff15Schris        ptln("      <tr><th>".$this->lang["field"]."</th><th>".$this->lang["value"]."</th></tr>", $indent);
4010440ff15Schris        ptln("    </thead>", $indent);
4020440ff15Schris        ptln("    <tbody>", $indent);
40326fb387bSchris
4043a97d936SAndreas Gohr        $this->htmlInputField(
40564159a61SAndreas Gohr            $cmd . "_userid",
40664159a61SAndreas Gohr            "userid",
40764159a61SAndreas Gohr            $this->lang["user_id"],
40864159a61SAndreas Gohr            $user,
4093a97d936SAndreas Gohr            $this->auth->canDo("modLogin"),
41064159a61SAndreas Gohr            true,
41164159a61SAndreas Gohr            $indent + 6
41264159a61SAndreas Gohr        );
4133a97d936SAndreas Gohr        $this->htmlInputField(
41464159a61SAndreas Gohr            $cmd . "_userpass",
41564159a61SAndreas Gohr            "userpass",
41664159a61SAndreas Gohr            $this->lang["user_pass"],
41764159a61SAndreas Gohr            "",
4183a97d936SAndreas Gohr            $this->auth->canDo("modPass"),
41964159a61SAndreas Gohr            false,
42064159a61SAndreas Gohr            $indent + 6
42164159a61SAndreas Gohr        );
4223a97d936SAndreas Gohr        $this->htmlInputField(
42364159a61SAndreas Gohr            $cmd . "_userpass2",
42464159a61SAndreas Gohr            "userpass2",
42564159a61SAndreas Gohr            $lang["passchk"],
42664159a61SAndreas Gohr            "",
4273a97d936SAndreas Gohr            $this->auth->canDo("modPass"),
42864159a61SAndreas Gohr            false,
42964159a61SAndreas Gohr            $indent + 6
43064159a61SAndreas Gohr        );
4313a97d936SAndreas Gohr        $this->htmlInputField(
43264159a61SAndreas Gohr            $cmd . "_username",
43364159a61SAndreas Gohr            "username",
43464159a61SAndreas Gohr            $this->lang["user_name"],
43564159a61SAndreas Gohr            $name,
4363a97d936SAndreas Gohr            $this->auth->canDo("modName"),
43764159a61SAndreas Gohr            true,
43864159a61SAndreas Gohr            $indent + 6
43964159a61SAndreas Gohr        );
4403a97d936SAndreas Gohr        $this->htmlInputField(
44164159a61SAndreas Gohr            $cmd . "_usermail",
44264159a61SAndreas Gohr            "usermail",
44364159a61SAndreas Gohr            $this->lang["user_mail"],
44464159a61SAndreas Gohr            $mail,
4453a97d936SAndreas Gohr            $this->auth->canDo("modMail"),
44664159a61SAndreas Gohr            true,
44764159a61SAndreas Gohr            $indent + 6
44864159a61SAndreas Gohr        );
4493a97d936SAndreas Gohr        $this->htmlInputField(
45064159a61SAndreas Gohr            $cmd . "_usergroups",
45164159a61SAndreas Gohr            "usergroups",
45264159a61SAndreas Gohr            $this->lang["user_groups"],
45364159a61SAndreas Gohr            $groups,
4543a97d936SAndreas Gohr            $this->auth->canDo("modGroups"),
45564159a61SAndreas Gohr            false,
45664159a61SAndreas Gohr            $indent + 6
45764159a61SAndreas Gohr        );
45826fb387bSchris
4593a97d936SAndreas Gohr        if ($this->auth->canDo("modPass")) {
460ee9498f5SChristopher Smith            if ($cmd == 'add') {
461c3f4fb63SGina Haeussge                $notes[] = $this->lang['note_pass'];
462ee9498f5SChristopher Smith            }
463a6858c6aSchris            if ($user) {
464a6858c6aSchris                $notes[] = $this->lang['note_notify'];
465a6858c6aSchris            }
466a6858c6aSchris
46764159a61SAndreas Gohr            ptln("<tr><td><label for=\"".$cmd."_usernotify\" >".
46864159a61SAndreas Gohr                 $this->lang["user_notify"].": </label></td>
46964159a61SAndreas Gohr                 <td><input type=\"checkbox\" id=\"".$cmd."_usernotify\" name=\"usernotify\" value=\"1\" />
47064159a61SAndreas Gohr                 </td></tr>", $indent);
471a6858c6aSchris        }
472a6858c6aSchris
4730440ff15Schris        ptln("    </tbody>", $indent);
4740440ff15Schris        ptln("    <tbody>", $indent);
4750440ff15Schris        ptln("      <tr>", $indent);
4760440ff15Schris        ptln("        <td colspan=\"2\">", $indent);
4770440ff15Schris        ptln("          <input type=\"hidden\" name=\"do\"    value=\"admin\" />", $indent);
4780440ff15Schris        ptln("          <input type=\"hidden\" name=\"page\"  value=\"usermanager\" />", $indent);
4790440ff15Schris
4800440ff15Schris        // save current $user, we need this to access details if the name is changed
4810440ff15Schris        if ($user)
482f23f9594SAndreas Gohr          ptln("          <input type=\"hidden\" name=\"userid_old\"  value=\"".hsc($user)."\" />", $indent);
4830440ff15Schris
4843a97d936SAndreas Gohr        $this->htmlFilterSettings($indent+10);
4850440ff15Schris
486ae614416SAnika Henke        ptln("          <button type=\"submit\" name=\"fn[".$cmd."]\">".$this->lang[$cmd]."</button>", $indent);
4870440ff15Schris        ptln("        </td>", $indent);
4880440ff15Schris        ptln("      </tr>", $indent);
4890440ff15Schris        ptln("    </tbody>", $indent);
4900440ff15Schris        ptln("  </table>", $indent);
49145c19902SChristopher Smith
49245c19902SChristopher Smith        if ($notes) {
49345c19902SChristopher Smith            ptln("    <ul class=\"notes\">");
49445c19902SChristopher Smith            foreach ($notes as $note) {
495ae614416SAnika Henke                ptln("      <li><span class=\"li\">".$note."</li>", $indent);
49645c19902SChristopher Smith            }
49745c19902SChristopher Smith            ptln("    </ul>");
49845c19902SChristopher Smith        }
499c7b28ffdSAnika Henke        ptln("  </div>", $indent);
5000440ff15Schris        ptln("</form>", $indent);
5010440ff15Schris    }
5020440ff15Schris
503c5a7c0c6SGerrit Uitslag    /**
504c5a7c0c6SGerrit Uitslag     * Prints a inputfield
505c5a7c0c6SGerrit Uitslag     *
506c5a7c0c6SGerrit Uitslag     * @param string $id
507c5a7c0c6SGerrit Uitslag     * @param string $name
508c5a7c0c6SGerrit Uitslag     * @param string $label
509c5a7c0c6SGerrit Uitslag     * @param string $value
510c5a7c0c6SGerrit Uitslag     * @param bool   $cando whether auth backend is capable to do this action
5119b82d43fSAndreas Gohr     * @param bool   $required is this field required?
512c5a7c0c6SGerrit Uitslag     * @param int $indent
513c5a7c0c6SGerrit Uitslag     */
5143a97d936SAndreas Gohr    protected function htmlInputField($id, $name, $label, $value, $cando, $required, $indent = 0)
5153a97d936SAndreas Gohr    {
5167de12fceSAndreas Gohr        $class = $cando ? '' : ' class="disabled"';
5177de12fceSAndreas Gohr        echo str_pad('', $indent);
5187de12fceSAndreas Gohr
519359e9417SChristopher Smith        if ($name == 'userpass' || $name == 'userpass2') {
520d796a891SAndreas Gohr            $fieldtype = 'password';
521d796a891SAndreas Gohr            $autocomp  = 'autocomplete="off"';
5227b3674bdSChristopher Smith        } elseif ($name == 'usermail') {
5237b3674bdSChristopher Smith            $fieldtype = 'email';
5247b3674bdSChristopher Smith            $autocomp  = '';
525d796a891SAndreas Gohr        } else {
526d796a891SAndreas Gohr            $fieldtype = 'text';
527d796a891SAndreas Gohr            $autocomp  = '';
528d796a891SAndreas Gohr        }
529f23f9594SAndreas Gohr        $value = hsc($value);
530d796a891SAndreas Gohr
5317de12fceSAndreas Gohr        echo "<tr $class>";
5327de12fceSAndreas Gohr        echo "<td><label for=\"$id\" >$label: </label></td>";
5337de12fceSAndreas Gohr        echo "<td>";
5347de12fceSAndreas Gohr        if ($cando) {
5359b82d43fSAndreas Gohr            $req = '';
5369b82d43fSAndreas Gohr            if ($required) $req = 'required="required"';
53764159a61SAndreas Gohr            echo "<input type=\"$fieldtype\" id=\"$id\" name=\"$name\"
53864159a61SAndreas Gohr                  value=\"$value\" class=\"edit\" $autocomp $req />";
5397de12fceSAndreas Gohr        } else {
5407de12fceSAndreas Gohr            echo "<input type=\"hidden\" name=\"$name\" value=\"$value\" />";
54164159a61SAndreas Gohr            echo "<input type=\"$fieldtype\" id=\"$id\" name=\"$name\"
54264159a61SAndreas Gohr                  value=\"$value\" class=\"edit disabled\" disabled=\"disabled\" />";
5437de12fceSAndreas Gohr        }
5447de12fceSAndreas Gohr        echo "</td>";
5457de12fceSAndreas Gohr        echo "</tr>";
54626fb387bSchris    }
54726fb387bSchris
548c5a7c0c6SGerrit Uitslag    /**
549c5a7c0c6SGerrit Uitslag     * Returns htmlescaped filter value
550c5a7c0c6SGerrit Uitslag     *
551c5a7c0c6SGerrit Uitslag     * @param string $key name of search field
552c5a7c0c6SGerrit Uitslag     * @return string html escaped value
553c5a7c0c6SGerrit Uitslag     */
5543a97d936SAndreas Gohr    protected function htmlFilter($key)
5553a97d936SAndreas Gohr    {
5563a97d936SAndreas Gohr        if (empty($this->filter)) return '';
5573a97d936SAndreas Gohr        return (isset($this->filter[$key]) ? hsc($this->filter[$key]) : '');
5580440ff15Schris    }
5590440ff15Schris
560c5a7c0c6SGerrit Uitslag    /**
561c5a7c0c6SGerrit Uitslag     * Print hidden inputs with the current filter values
562c5a7c0c6SGerrit Uitslag     *
563c5a7c0c6SGerrit Uitslag     * @param int $indent
564c5a7c0c6SGerrit Uitslag     */
5653a97d936SAndreas Gohr    protected function htmlFilterSettings($indent = 0)
5663a97d936SAndreas Gohr    {
5670440ff15Schris
5683a97d936SAndreas Gohr        ptln("<input type=\"hidden\" name=\"start\" value=\"".$this->start."\" />", $indent);
5690440ff15Schris
5703a97d936SAndreas Gohr        foreach ($this->filter as $key => $filter) {
5710440ff15Schris            ptln("<input type=\"hidden\" name=\"filter[".$key."]\" value=\"".hsc($filter)."\" />", $indent);
5720440ff15Schris        }
5730440ff15Schris    }
5740440ff15Schris
575c5a7c0c6SGerrit Uitslag    /**
576c5a7c0c6SGerrit Uitslag     * Print import form and summary of previous import
577c5a7c0c6SGerrit Uitslag     *
578c5a7c0c6SGerrit Uitslag     * @param int $indent
579c5a7c0c6SGerrit Uitslag     */
5803a97d936SAndreas Gohr    protected function htmlImportForm($indent = 0)
5813a97d936SAndreas Gohr    {
582ae1afd2fSChristopher Smith        global $ID;
583ae1afd2fSChristopher Smith
584*54cc7aa4SAndreas Gohr        $failure_download_link = wl($ID, ['do'=>'admin', 'page'=>'usermanager', 'fn[importfails]'=>1]);
585ae1afd2fSChristopher Smith
586ae1afd2fSChristopher Smith        ptln('<div class="level2 import_users">', $indent);
587ae1afd2fSChristopher Smith        print $this->locale_xhtml('import');
588ae1afd2fSChristopher Smith        ptln('  <form action="'.wl($ID).'" method="post" enctype="multipart/form-data">', $indent);
589ae1afd2fSChristopher Smith        formSecurityToken();
590b59cff8bSGerrit Uitslag        ptln('    <label>'.$this->lang['import_userlistcsv'].'<input type="file" name="import" /></label>', $indent);
591ae614416SAnika Henke        ptln('    <button type="submit" name="fn[import]">'.$this->lang['import'].'</button>', $indent);
592ae1afd2fSChristopher Smith        ptln('    <input type="hidden" name="do"    value="admin" />', $indent);
593ae1afd2fSChristopher Smith        ptln('    <input type="hidden" name="page"  value="usermanager" />', $indent);
594ae1afd2fSChristopher Smith
5953a97d936SAndreas Gohr        $this->htmlFilterSettings($indent+4);
596ae1afd2fSChristopher Smith        ptln('  </form>', $indent);
597ae1afd2fSChristopher Smith        ptln('</div>');
598ae1afd2fSChristopher Smith
599ae1afd2fSChristopher Smith        // list failures from the previous import
6003a97d936SAndreas Gohr        if ($this->import_failures) {
6013a97d936SAndreas Gohr            $digits = strlen(count($this->import_failures));
602ae1afd2fSChristopher Smith            ptln('<div class="level3 import_failures">', $indent);
603b59cff8bSGerrit Uitslag            ptln('  <h3>'.$this->lang['import_header'].'</h3>');
604ae1afd2fSChristopher Smith            ptln('  <table class="import_failures">', $indent);
605ae1afd2fSChristopher Smith            ptln('    <thead>', $indent);
606ae1afd2fSChristopher Smith            ptln('      <tr>', $indent);
607ae1afd2fSChristopher Smith            ptln('        <th class="line">'.$this->lang['line'].'</th>', $indent);
608ae1afd2fSChristopher Smith            ptln('        <th class="error">'.$this->lang['error'].'</th>', $indent);
609ae1afd2fSChristopher Smith            ptln('        <th class="userid">'.$this->lang['user_id'].'</th>', $indent);
610ae1afd2fSChristopher Smith            ptln('        <th class="username">'.$this->lang['user_name'].'</th>', $indent);
611ae1afd2fSChristopher Smith            ptln('        <th class="usermail">'.$this->lang['user_mail'].'</th>', $indent);
612ae1afd2fSChristopher Smith            ptln('        <th class="usergroups">'.$this->lang['user_groups'].'</th>', $indent);
613ae1afd2fSChristopher Smith            ptln('      </tr>', $indent);
614ae1afd2fSChristopher Smith            ptln('    </thead>', $indent);
615ae1afd2fSChristopher Smith            ptln('    <tbody>', $indent);
6163a97d936SAndreas Gohr            foreach ($this->import_failures as $line => $failure) {
617ae1afd2fSChristopher Smith                ptln('      <tr>', $indent);
618ae1afd2fSChristopher Smith                ptln('        <td class="lineno"> '.sprintf('%0'.$digits.'d', $line).' </td>', $indent);
619ae1afd2fSChristopher Smith                ptln('        <td class="error">' .$failure['error'].' </td>', $indent);
620ae1afd2fSChristopher Smith                ptln('        <td class="field userid"> '.hsc($failure['user'][0]).' </td>', $indent);
621ae1afd2fSChristopher Smith                ptln('        <td class="field username"> '.hsc($failure['user'][2]).' </td>', $indent);
622ae1afd2fSChristopher Smith                ptln('        <td class="field usermail"> '.hsc($failure['user'][3]).' </td>', $indent);
623ae1afd2fSChristopher Smith                ptln('        <td class="field usergroups"> '.hsc($failure['user'][4]).' </td>', $indent);
624ae1afd2fSChristopher Smith                ptln('      </tr>', $indent);
625ae1afd2fSChristopher Smith            }
626ae1afd2fSChristopher Smith            ptln('    </tbody>', $indent);
627ae1afd2fSChristopher Smith            ptln('  </table>', $indent);
628b59cff8bSGerrit Uitslag            ptln('  <p><a href="'.$failure_download_link.'">'.$this->lang['import_downloadfailures'].'</a></p>');
629ae1afd2fSChristopher Smith            ptln('</div>');
630ae1afd2fSChristopher Smith        }
631ae1afd2fSChristopher Smith    }
632ae1afd2fSChristopher Smith
633c5a7c0c6SGerrit Uitslag    /**
634c5a7c0c6SGerrit Uitslag     * Add an user to auth backend
635c5a7c0c6SGerrit Uitslag     *
636c5a7c0c6SGerrit Uitslag     * @return bool whether succesful
637c5a7c0c6SGerrit Uitslag     */
6383a97d936SAndreas Gohr    protected function addUser()
6393a97d936SAndreas Gohr    {
64000d58927SMichael Hamann        global $INPUT;
641634d7150SAndreas Gohr        if (!checkSecurityToken()) return false;
6423a97d936SAndreas Gohr        if (!$this->auth->canDo('addUser')) return false;
6430440ff15Schris
644*54cc7aa4SAndreas Gohr        [$user, $pass, $name, $mail, $grps, $passconfirm] = $this->retrieveUser();
6450440ff15Schris        if (empty($user)) return false;
6466733c4d7SChris Smith
6473a97d936SAndreas Gohr        if ($this->auth->canDo('modPass')) {
648c3f4fb63SGina Haeussge            if (empty($pass)) {
64900d58927SMichael Hamann                if ($INPUT->has('usernotify')) {
6508a285f7fSAndreas Gohr                    $pass = auth_pwgen($user);
651c3f4fb63SGina Haeussge                } else {
65260b9901bSAndreas Gohr                    msg($this->lang['add_fail'], -1);
65309a5dcd6SMichael Große                    msg($this->lang['addUser_error_missing_pass'], -1);
65460b9901bSAndreas Gohr                    return false;
65560b9901bSAndreas Gohr                }
656*54cc7aa4SAndreas Gohr            } elseif (!$this->verifyPassword($pass, $passconfirm)) {
65709a5dcd6SMichael Große                msg($this->lang['add_fail'], -1);
65809a5dcd6SMichael Große                msg($this->lang['addUser_error_pass_not_identical'], -1);
659359e9417SChristopher Smith                return false;
660359e9417SChristopher Smith            }
661*54cc7aa4SAndreas Gohr        } elseif (!empty($pass)) {
6626733c4d7SChris Smith            msg($this->lang['add_fail'], -1);
66309a5dcd6SMichael Große            msg($this->lang['addUser_error_modPass_disabled'], -1);
6646733c4d7SChris Smith            return false;
6656733c4d7SChris Smith        }
6666733c4d7SChris Smith
6673a97d936SAndreas Gohr        if ($this->auth->canDo('modName')) {
6686733c4d7SChris Smith            if (empty($name)) {
6696733c4d7SChris Smith                msg($this->lang['add_fail'], -1);
67009a5dcd6SMichael Große                msg($this->lang['addUser_error_name_missing'], -1);
6716733c4d7SChris Smith                return false;
6726733c4d7SChris Smith            }
673*54cc7aa4SAndreas Gohr        } elseif (!empty($name)) {
67409a5dcd6SMichael Große            msg($this->lang['add_fail'], -1);
67509a5dcd6SMichael Große            msg($this->lang['addUser_error_modName_disabled'], -1);
6766733c4d7SChris Smith            return false;
6776733c4d7SChris Smith        }
6786733c4d7SChris Smith
6793a97d936SAndreas Gohr        if ($this->auth->canDo('modMail')) {
6806733c4d7SChris Smith            if (empty($mail)) {
6816733c4d7SChris Smith                msg($this->lang['add_fail'], -1);
68209a5dcd6SMichael Große                msg($this->lang['addUser_error_mail_missing'], -1);
6836733c4d7SChris Smith                return false;
6846733c4d7SChris Smith            }
685*54cc7aa4SAndreas Gohr        } elseif (!empty($mail)) {
68609a5dcd6SMichael Große            msg($this->lang['add_fail'], -1);
68709a5dcd6SMichael Große            msg($this->lang['addUser_error_modMail_disabled'], -1);
6886733c4d7SChris Smith            return false;
6896733c4d7SChris Smith        }
6900440ff15Schris
691*54cc7aa4SAndreas Gohr        if ($ok = $this->auth->triggerUserMod('create', [$user, $pass, $name, $mail, $grps])) {
692a6858c6aSchris            msg($this->lang['add_ok'], 1);
693a6858c6aSchris
69400d58927SMichael Hamann            if ($INPUT->has('usernotify') && $pass) {
6953a97d936SAndreas Gohr                $this->notifyUser($user, $pass);
696a6858c6aSchris            }
697a6858c6aSchris        } else {
69860b9901bSAndreas Gohr            msg($this->lang['add_fail'], -1);
69909a5dcd6SMichael Große            msg($this->lang['addUser_error_create_event_failed'], -1);
700a6858c6aSchris        }
701a6858c6aSchris
702a6858c6aSchris        return $ok;
7030440ff15Schris    }
7040440ff15Schris
7050440ff15Schris    /**
706c5a7c0c6SGerrit Uitslag     * Delete user from auth backend
707c5a7c0c6SGerrit Uitslag     *
708c5a7c0c6SGerrit Uitslag     * @return bool whether succesful
7090440ff15Schris     */
7103a97d936SAndreas Gohr    protected function deleteUser()
7113a97d936SAndreas Gohr    {
71200d58927SMichael Hamann        global $conf, $INPUT;
7139ec82636SAndreas Gohr
714634d7150SAndreas Gohr        if (!checkSecurityToken()) return false;
7153a97d936SAndreas Gohr        if (!$this->auth->canDo('delUser')) return false;
7160440ff15Schris
71700d58927SMichael Hamann        $selected = $INPUT->arr('delete');
71800d58927SMichael Hamann        if (empty($selected)) return false;
7190440ff15Schris        $selected = array_keys($selected);
7200440ff15Schris
721c9a8f912SMichael Klier        if (in_array($_SERVER['REMOTE_USER'], $selected)) {
722c9a8f912SMichael Klier            msg("You can't delete yourself!", -1);
723c9a8f912SMichael Klier            return false;
724c9a8f912SMichael Klier        }
725c9a8f912SMichael Klier
726*54cc7aa4SAndreas Gohr        $count = $this->auth->triggerUserMod('delete', [$selected]);
7270440ff15Schris        if ($count == count($selected)) {
7280440ff15Schris            $text = str_replace('%d', $count, $this->lang['delete_ok']);
7290440ff15Schris            msg("$text.", 1);
7300440ff15Schris        } else {
7310440ff15Schris            $part1 = str_replace('%d', $count, $this->lang['delete_ok']);
7320440ff15Schris            $part2 = str_replace('%d', (count($selected)-$count), $this->lang['delete_fail']);
7330440ff15Schris            msg("$part1, $part2", -1);
7340440ff15Schris        }
73578c7c8c9Schris
7369ec82636SAndreas Gohr        // invalidate all sessions
7379ec82636SAndreas Gohr        io_saveFile($conf['cachedir'].'/sessionpurge', time());
7389ec82636SAndreas Gohr
73978c7c8c9Schris        return true;
74078c7c8c9Schris    }
74178c7c8c9Schris
74278c7c8c9Schris    /**
74378c7c8c9Schris     * Edit user (a user has been selected for editing)
744c5a7c0c6SGerrit Uitslag     *
745c5a7c0c6SGerrit Uitslag     * @param string $param id of the user
746c5a7c0c6SGerrit Uitslag     * @return bool whether succesful
74778c7c8c9Schris     */
7483a97d936SAndreas Gohr    protected function editUser($param)
7493a97d936SAndreas Gohr    {
750634d7150SAndreas Gohr        if (!checkSecurityToken()) return false;
7513a97d936SAndreas Gohr        if (!$this->auth->canDo('UserMod')) return false;
7523a97d936SAndreas Gohr        $user = $this->auth->cleanUser(preg_replace('/.*[:\/]/', '', $param));
7533a97d936SAndreas Gohr        $userdata = $this->auth->getUserData($user);
75478c7c8c9Schris
75578c7c8c9Schris        // no user found?
75678c7c8c9Schris        if (!$userdata) {
75778c7c8c9Schris            msg($this->lang['edit_usermissing'], -1);
75878c7c8c9Schris            return false;
75978c7c8c9Schris        }
76078c7c8c9Schris
7613a97d936SAndreas Gohr        $this->edit_user = $user;
7623a97d936SAndreas Gohr        $this->edit_userdata = $userdata;
76378c7c8c9Schris
76478c7c8c9Schris        return true;
7650440ff15Schris    }
7660440ff15Schris
7670440ff15Schris    /**
768c5a7c0c6SGerrit Uitslag     * Modify user in the auth backend (modified user data has been recieved)
769c5a7c0c6SGerrit Uitslag     *
770c5a7c0c6SGerrit Uitslag     * @return bool whether succesful
7710440ff15Schris     */
7723a97d936SAndreas Gohr    protected function modifyUser()
7733a97d936SAndreas Gohr    {
77400d58927SMichael Hamann        global $conf, $INPUT;
7759ec82636SAndreas Gohr
776634d7150SAndreas Gohr        if (!checkSecurityToken()) return false;
7773a97d936SAndreas Gohr        if (!$this->auth->canDo('UserMod')) return false;
7780440ff15Schris
77926fb387bSchris        // get currently valid  user data
7803a97d936SAndreas Gohr        $olduser = $this->auth->cleanUser(preg_replace('/.*[:\/]/', '', $INPUT->str('userid_old')));
7813a97d936SAndreas Gohr        $oldinfo = $this->auth->getUserData($olduser);
782073766c6Smatthiasgrimm
78326fb387bSchris        // get new user data subject to change
784*54cc7aa4SAndreas Gohr        [$newuser, $newpass, $newname, $newmail, $newgrps, $passconfirm] = $this->retrieveUser();
785073766c6Smatthiasgrimm        if (empty($newuser)) return false;
7860440ff15Schris
787*54cc7aa4SAndreas Gohr        $changes = [];
788073766c6Smatthiasgrimm        if ($newuser != $olduser) {
7893a97d936SAndreas Gohr            if (!$this->auth->canDo('modLogin')) {        // sanity check, shouldn't be possible
79026fb387bSchris                msg($this->lang['update_fail'], -1);
79126fb387bSchris                return false;
79226fb387bSchris            }
79326fb387bSchris
79426fb387bSchris            // check if $newuser already exists
7953a97d936SAndreas Gohr            if ($this->auth->getUserData($newuser)) {
796073766c6Smatthiasgrimm                msg(sprintf($this->lang['update_exists'], $newuser), -1);
797a6858c6aSchris                $re_edit = true;
7980440ff15Schris            } else {
799073766c6Smatthiasgrimm                $changes['user'] = $newuser;
8000440ff15Schris            }
80193eefc2fSAndreas Gohr        }
8023a97d936SAndreas Gohr        if ($this->auth->canDo('modPass')) {
8032400ddcbSChristopher Smith            if ($newpass || $passconfirm) {
8043a97d936SAndreas Gohr                if ($this->verifyPassword($newpass, $passconfirm)) {
805359e9417SChristopher Smith                    $changes['pass'] = $newpass;
806359e9417SChristopher Smith                } else {
807359e9417SChristopher Smith                    return false;
808359e9417SChristopher Smith                }
809*54cc7aa4SAndreas Gohr            } elseif ($INPUT->has('usernotify')) {
810359e9417SChristopher Smith                // no new password supplied, check if we need to generate one (or it stays unchanged)
811359e9417SChristopher Smith                $changes['pass'] = auth_pwgen($olduser);
812359e9417SChristopher Smith            }
813359e9417SChristopher Smith        }
8140440ff15Schris
8153a97d936SAndreas Gohr        if (!empty($newname) && $this->auth->canDo('modName') && $newname != $oldinfo['name']) {
816073766c6Smatthiasgrimm            $changes['name'] = $newname;
81740d72af6SChristopher Smith        }
8183a97d936SAndreas Gohr        if (!empty($newmail) && $this->auth->canDo('modMail') && $newmail != $oldinfo['mail']) {
819073766c6Smatthiasgrimm            $changes['mail'] = $newmail;
82040d72af6SChristopher Smith        }
8213a97d936SAndreas Gohr        if (!empty($newgrps) && $this->auth->canDo('modGroups') && $newgrps != $oldinfo['grps']) {
822073766c6Smatthiasgrimm            $changes['grps'] = $newgrps;
82340d72af6SChristopher Smith        }
8240440ff15Schris
825*54cc7aa4SAndreas Gohr        if ($ok = $this->auth->triggerUserMod('modify', [$olduser, $changes])) {
8260440ff15Schris            msg($this->lang['update_ok'], 1);
827a6858c6aSchris
8286ed3476bSChristopher Smith            if ($INPUT->has('usernotify') && !empty($changes['pass'])) {
829a6858c6aSchris                $notify = empty($changes['user']) ? $olduser : $newuser;
8303a97d936SAndreas Gohr                $this->notifyUser($notify, $changes['pass']);
831a6858c6aSchris            }
832a6858c6aSchris
8339ec82636SAndreas Gohr            // invalidate all sessions
8349ec82636SAndreas Gohr            io_saveFile($conf['cachedir'].'/sessionpurge', time());
8350440ff15Schris        } else {
8360440ff15Schris            msg($this->lang['update_fail'], -1);
8370440ff15Schris        }
83878c7c8c9Schris
839a6858c6aSchris        if (!empty($re_edit)) {
8403a97d936SAndreas Gohr            $this->editUser($olduser);
8410440ff15Schris        }
8420440ff15Schris
843a6858c6aSchris        return $ok;
844a6858c6aSchris    }
845a6858c6aSchris
846a6858c6aSchris    /**
847c5a7c0c6SGerrit Uitslag     * Send password change notification email
848c5a7c0c6SGerrit Uitslag     *
849c5a7c0c6SGerrit Uitslag     * @param string $user         id of user
850c5a7c0c6SGerrit Uitslag     * @param string $password     plain text
851c5a7c0c6SGerrit Uitslag     * @param bool   $status_alert whether status alert should be shown
852c5a7c0c6SGerrit Uitslag     * @return bool whether succesful
853a6858c6aSchris     */
8543a97d936SAndreas Gohr    protected function notifyUser($user, $password, $status_alert = true)
8553a97d936SAndreas Gohr    {
856a6858c6aSchris
857a6858c6aSchris        if ($sent = auth_sendPassword($user, $password)) {
858328143f8SChristopher Smith            if ($status_alert) {
859a6858c6aSchris                msg($this->lang['notify_ok'], 1);
860328143f8SChristopher Smith            }
861*54cc7aa4SAndreas Gohr        } elseif ($status_alert) {
862a6858c6aSchris            msg($this->lang['notify_fail'], -1);
863a6858c6aSchris        }
864a6858c6aSchris
865a6858c6aSchris        return $sent;
866a6858c6aSchris    }
867a6858c6aSchris
868a6858c6aSchris    /**
869359e9417SChristopher Smith     * Verify password meets minimum requirements
870359e9417SChristopher Smith     * :TODO: extend to support password strength
871359e9417SChristopher Smith     *
872359e9417SChristopher Smith     * @param string  $password   candidate string for new password
873359e9417SChristopher Smith     * @param string  $confirm    repeated password for confirmation
874359e9417SChristopher Smith     * @return bool   true if meets requirements, false otherwise
875359e9417SChristopher Smith     */
8763a97d936SAndreas Gohr    protected function verifyPassword($password, $confirm)
8773a97d936SAndreas Gohr    {
878be9008d3SChristopher Smith        global $lang;
879359e9417SChristopher Smith
8802400ddcbSChristopher Smith        if (empty($password) && empty($confirm)) {
881359e9417SChristopher Smith            return false;
882359e9417SChristopher Smith        }
883359e9417SChristopher Smith
884359e9417SChristopher Smith        if ($password !== $confirm) {
885be9008d3SChristopher Smith            msg($lang['regbadpass'], -1);
886359e9417SChristopher Smith            return false;
887359e9417SChristopher Smith        }
888359e9417SChristopher Smith
889359e9417SChristopher Smith        // :TODO: test password for required strength
890359e9417SChristopher Smith
891359e9417SChristopher Smith        // if we make it this far the password is good
892359e9417SChristopher Smith        return true;
893359e9417SChristopher Smith    }
894359e9417SChristopher Smith
895359e9417SChristopher Smith    /**
896c5a7c0c6SGerrit Uitslag     * Retrieve & clean user data from the form
897a6858c6aSchris     *
898c5a7c0c6SGerrit Uitslag     * @param bool $clean whether the cleanUser method of the authentication backend is applied
899a6858c6aSchris     * @return array (user, password, full name, email, array(groups))
9000440ff15Schris     */
9013a97d936SAndreas Gohr    protected function retrieveUser($clean = true)
9023a97d936SAndreas Gohr    {
903c5a7c0c6SGerrit Uitslag        /** @var DokuWiki_Auth_Plugin $auth */
9047441e340SAndreas Gohr        global $auth;
905fbfbbe8aSHakan Sandell        global $INPUT;
9060440ff15Schris
907*54cc7aa4SAndreas Gohr        $user = [];
908fbfbbe8aSHakan Sandell        $user[0] = ($clean) ? $auth->cleanUser($INPUT->str('userid')) : $INPUT->str('userid');
909fbfbbe8aSHakan Sandell        $user[1] = $INPUT->str('userpass');
910fbfbbe8aSHakan Sandell        $user[2] = $INPUT->str('username');
911fbfbbe8aSHakan Sandell        $user[3] = $INPUT->str('usermail');
912fbfbbe8aSHakan Sandell        $user[4] = explode(',', $INPUT->str('usergroups'));
913359e9417SChristopher Smith        $user[5] = $INPUT->str('userpass2');                // repeated password for confirmation
9140440ff15Schris
9157441e340SAndreas Gohr        $user[4] = array_map('trim', $user[4]);
916*54cc7aa4SAndreas Gohr        if ($clean) $user[4] = array_map([$auth, 'cleanGroup'], $user[4]);
9177441e340SAndreas Gohr        $user[4] = array_filter($user[4]);
9187441e340SAndreas Gohr        $user[4] = array_unique($user[4]);
919*54cc7aa4SAndreas Gohr        if ($user[4] === []) $user[4] = null;
9200440ff15Schris
9210440ff15Schris        return $user;
9220440ff15Schris    }
9230440ff15Schris
924c5a7c0c6SGerrit Uitslag    /**
925c5a7c0c6SGerrit Uitslag     * Set the filter with the current search terms or clear the filter
926c5a7c0c6SGerrit Uitslag     *
927c5a7c0c6SGerrit Uitslag     * @param string $op 'new' or 'clear'
928c5a7c0c6SGerrit Uitslag     */
9293a97d936SAndreas Gohr    protected function setFilter($op)
9303a97d936SAndreas Gohr    {
9310440ff15Schris
932*54cc7aa4SAndreas Gohr        $this->filter = [];
9330440ff15Schris
9340440ff15Schris        if ($op == 'new') {
935*54cc7aa4SAndreas Gohr            [$user, , $name, $mail, $grps] = $this->retrieveUser(false);
9360440ff15Schris
9373a97d936SAndreas Gohr            if (!empty($user)) $this->filter['user'] = $user;
9383a97d936SAndreas Gohr            if (!empty($name)) $this->filter['name'] = $name;
9393a97d936SAndreas Gohr            if (!empty($mail)) $this->filter['mail'] = $mail;
940*54cc7aa4SAndreas Gohr            if (!empty($grps)) $this->filter['grps'] = implode('|', $grps);
9410440ff15Schris        }
9420440ff15Schris    }
9430440ff15Schris
944c5a7c0c6SGerrit Uitslag    /**
945c5a7c0c6SGerrit Uitslag     * Get the current search terms
946c5a7c0c6SGerrit Uitslag     *
947c5a7c0c6SGerrit Uitslag     * @return array
948c5a7c0c6SGerrit Uitslag     */
9493a97d936SAndreas Gohr    protected function retrieveFilter()
9503a97d936SAndreas Gohr    {
951fbfbbe8aSHakan Sandell        global $INPUT;
9520440ff15Schris
953fbfbbe8aSHakan Sandell        $t_filter = $INPUT->arr('filter');
9540440ff15Schris
9550440ff15Schris        // messy, but this way we ensure we aren't getting any additional crap from malicious users
956*54cc7aa4SAndreas Gohr        $filter = [];
9570440ff15Schris
9580440ff15Schris        if (isset($t_filter['user'])) $filter['user'] = $t_filter['user'];
9590440ff15Schris        if (isset($t_filter['name'])) $filter['name'] = $t_filter['name'];
9600440ff15Schris        if (isset($t_filter['mail'])) $filter['mail'] = $t_filter['mail'];
9610440ff15Schris        if (isset($t_filter['grps'])) $filter['grps'] = $t_filter['grps'];
9620440ff15Schris
9630440ff15Schris        return $filter;
9640440ff15Schris    }
9650440ff15Schris
966c5a7c0c6SGerrit Uitslag    /**
967c5a7c0c6SGerrit Uitslag     * Validate and improve the pagination values
968c5a7c0c6SGerrit Uitslag     */
9693a97d936SAndreas Gohr    protected function validatePagination()
9703a97d936SAndreas Gohr    {
9710440ff15Schris
9723a97d936SAndreas Gohr        if ($this->start >= $this->users_total) {
9733a97d936SAndreas Gohr            $this->start = $this->users_total - $this->pagesize;
9740440ff15Schris        }
9753a97d936SAndreas Gohr        if ($this->start < 0) $this->start = 0;
9760440ff15Schris
9773a97d936SAndreas Gohr        $this->last = min($this->users_total, $this->start + $this->pagesize);
9780440ff15Schris    }
9790440ff15Schris
980c5a7c0c6SGerrit Uitslag    /**
981c5a7c0c6SGerrit Uitslag     * Return an array of strings to enable/disable pagination buttons
982c5a7c0c6SGerrit Uitslag     *
983c5a7c0c6SGerrit Uitslag     * @return array with enable/disable attributes
9840440ff15Schris     */
9853a97d936SAndreas Gohr    protected function pagination()
9863a97d936SAndreas Gohr    {
9870440ff15Schris
98851d94d49Schris        $disabled = 'disabled="disabled"';
98951d94d49Schris
990*54cc7aa4SAndreas Gohr        $buttons = [];
9913a97d936SAndreas Gohr        $buttons['start'] = $buttons['prev'] = ($this->start == 0) ? $disabled : '';
99251d94d49Schris
9933a97d936SAndreas Gohr        if ($this->users_total == -1) {
99451d94d49Schris            $buttons['last'] = $disabled;
99551d94d49Schris            $buttons['next'] = '';
99651d94d49Schris        } else {
99764159a61SAndreas Gohr            $buttons['last'] = $buttons['next'] =
9983a97d936SAndreas Gohr                (($this->start + $this->pagesize) >= $this->users_total) ? $disabled : '';
99951d94d49Schris        }
10000440ff15Schris
10013a97d936SAndreas Gohr        if ($this->lastdisabled) {
1002462e9e37SMichael Große            $buttons['last'] = $disabled;
1003462e9e37SMichael Große        }
1004462e9e37SMichael Große
10050440ff15Schris        return $buttons;
10060440ff15Schris    }
10075c967d3dSChristopher Smith
1008c5a7c0c6SGerrit Uitslag    /**
1009c5a7c0c6SGerrit Uitslag     * Export a list of users in csv format using the current filter criteria
10105c967d3dSChristopher Smith     */
10113a97d936SAndreas Gohr    protected function exportCSV()
10123a97d936SAndreas Gohr    {
10135c967d3dSChristopher Smith        // list of users for export - based on current filter criteria
10143a97d936SAndreas Gohr        $user_list = $this->auth->retrieveUsers(0, 0, $this->filter);
1015*54cc7aa4SAndreas Gohr        $column_headings = [
10165c967d3dSChristopher Smith            $this->lang["user_id"],
10175c967d3dSChristopher Smith            $this->lang["user_name"],
10185c967d3dSChristopher Smith            $this->lang["user_mail"],
10195c967d3dSChristopher Smith            $this->lang["user_groups"]
1020*54cc7aa4SAndreas Gohr        ];
10215c967d3dSChristopher Smith
10225c967d3dSChristopher Smith        // ==============================================================================================
10235c967d3dSChristopher Smith        // GENERATE OUTPUT
10245c967d3dSChristopher Smith        // normal headers for downloading...
10255c967d3dSChristopher Smith        header('Content-type: text/csv;charset=utf-8');
10265c967d3dSChristopher Smith        header('Content-Disposition: attachment; filename="wikiusers.csv"');
10275c967d3dSChristopher Smith#       // for debugging assistance, send as text plain to the browser
10285c967d3dSChristopher Smith#       header('Content-type: text/plain;charset=utf-8');
10295c967d3dSChristopher Smith
10305c967d3dSChristopher Smith        // output the csv
10315c967d3dSChristopher Smith        $fd = fopen('php://output', 'w');
10325c967d3dSChristopher Smith        fputcsv($fd, $column_headings);
10335c967d3dSChristopher Smith        foreach ($user_list as $user => $info) {
1034*54cc7aa4SAndreas Gohr            $line = [$user, $info['name'], $info['mail'], implode(',', $info['grps'])];
10355c967d3dSChristopher Smith            fputcsv($fd, $line);
10365c967d3dSChristopher Smith        }
10375c967d3dSChristopher Smith        fclose($fd);
10383a97d936SAndreas Gohr        if (defined('DOKU_UNITTEST')) {
10393a97d936SAndreas Gohr            return;
10403a97d936SAndreas Gohr        }
1041b2c01466SChristopher Smith
10425c967d3dSChristopher Smith        die;
10435c967d3dSChristopher Smith    }
1044ae1afd2fSChristopher Smith
1045c5a7c0c6SGerrit Uitslag    /**
1046c5a7c0c6SGerrit Uitslag     * Import a file of users in csv format
1047ae1afd2fSChristopher Smith     *
1048ae1afd2fSChristopher Smith     * csv file should have 4 columns, user_id, full name, email, groups (comma separated)
1049c5a7c0c6SGerrit Uitslag     *
10505ba64050SChristopher Smith     * @return bool whether successful
1051ae1afd2fSChristopher Smith     */
10523a97d936SAndreas Gohr    protected function importCSV()
10533a97d936SAndreas Gohr    {
1054ae1afd2fSChristopher Smith        // check we are allowed to add users
1055ae1afd2fSChristopher Smith        if (!checkSecurityToken()) return false;
10563a97d936SAndreas Gohr        if (!$this->auth->canDo('addUser')) return false;
1057ae1afd2fSChristopher Smith
1058ae1afd2fSChristopher Smith        // check file uploaded ok.
10593a97d936SAndreas Gohr        if (empty($_FILES['import']['size']) ||
10603a97d936SAndreas Gohr            !empty($_FILES['import']['error']) && $this->isUploadedFile($_FILES['import']['tmp_name'])
106164159a61SAndreas Gohr        ) {
1062ae1afd2fSChristopher Smith            msg($this->lang['import_error_upload'], -1);
1063ae1afd2fSChristopher Smith            return false;
1064ae1afd2fSChristopher Smith        }
1065ae1afd2fSChristopher Smith        // retrieve users from the file
1066*54cc7aa4SAndreas Gohr        $this->import_failures = [];
1067ae1afd2fSChristopher Smith        $import_success_count = 0;
1068ae1afd2fSChristopher Smith        $import_fail_count = 0;
1069ae1afd2fSChristopher Smith        $line = 0;
1070ae1afd2fSChristopher Smith        $fd = fopen($_FILES['import']['tmp_name'], 'r');
1071ae1afd2fSChristopher Smith        if ($fd) {
1072ae1afd2fSChristopher Smith            while ($csv = fgets($fd)) {
1073*54cc7aa4SAndreas Gohr                if (!Clean::isUtf8($csv)) {
1074efcec72bSChristopher Smith                    $csv = utf8_encode($csv);
1075efcec72bSChristopher Smith                }
1076d0c0a5c4SAnika Henke                $raw = str_getcsv($csv);
1077ae1afd2fSChristopher Smith                $error = '';                        // clean out any errors from the previous line
1078ae1afd2fSChristopher Smith                // data checks...
1079ae1afd2fSChristopher Smith                if (1 == ++$line) {
1080ae1afd2fSChristopher Smith                    if ($raw[0] == 'user_id' || $raw[0] == $this->lang['user_id']) continue;    // skip headers
1081ae1afd2fSChristopher Smith                }
1082ae1afd2fSChristopher Smith                if (count($raw) < 4) {                                        // need at least four fields
1083ae1afd2fSChristopher Smith                    $import_fail_count++;
1084ae1afd2fSChristopher Smith                    $error = sprintf($this->lang['import_error_fields'], count($raw));
1085*54cc7aa4SAndreas Gohr                    $this->import_failures[$line] = ['error' => $error, 'user' => $raw, 'orig' => $csv];
1086ae1afd2fSChristopher Smith                    continue;
1087ae1afd2fSChristopher Smith                }
1088ae1afd2fSChristopher Smith                array_splice($raw, 1, 0, auth_pwgen());                          // splice in a generated password
10893a97d936SAndreas Gohr                $clean = $this->cleanImportUser($raw, $error);
10903a97d936SAndreas Gohr                if ($clean && $this->importUser($clean, $error)) {
10913a97d936SAndreas Gohr                    $sent = $this->notifyUser($clean[0], $clean[1], false);
1092328143f8SChristopher Smith                    if (!$sent) {
1093328143f8SChristopher Smith                        msg(sprintf($this->lang['import_notify_fail'], $clean[0], $clean[3]), -1);
1094328143f8SChristopher Smith                    }
1095ae1afd2fSChristopher Smith                    $import_success_count++;
1096ae1afd2fSChristopher Smith                } else {
1097ae1afd2fSChristopher Smith                    $import_fail_count++;
1098e73725baSChristopher Smith                    array_splice($raw, 1, 1);                                  // remove the spliced in password
1099*54cc7aa4SAndreas Gohr                    $this->import_failures[$line] = ['error' => $error, 'user' => $raw, 'orig' => $csv];
1100ae1afd2fSChristopher Smith                }
1101ae1afd2fSChristopher Smith            }
110264159a61SAndreas Gohr            msg(
110364159a61SAndreas Gohr                sprintf(
110464159a61SAndreas Gohr                    $this->lang['import_success_count'],
110564159a61SAndreas Gohr                    ($import_success_count + $import_fail_count),
110664159a61SAndreas Gohr                    $import_success_count
110764159a61SAndreas Gohr                ),
110864159a61SAndreas Gohr                ($import_success_count ? 1 : -1)
110964159a61SAndreas Gohr            );
1110ae1afd2fSChristopher Smith            if ($import_fail_count) {
1111ae1afd2fSChristopher Smith                msg(sprintf($this->lang['import_failure_count'], $import_fail_count), -1);
1112ae1afd2fSChristopher Smith            }
1113ae1afd2fSChristopher Smith        } else {
1114ae1afd2fSChristopher Smith            msg($this->lang['import_error_readfail'], -1);
1115ae1afd2fSChristopher Smith        }
1116ae1afd2fSChristopher Smith
1117ae1afd2fSChristopher Smith        // save import failures into the session
1118ae1afd2fSChristopher Smith        if (!headers_sent()) {
1119ae1afd2fSChristopher Smith            session_start();
11203a97d936SAndreas Gohr            $_SESSION['import_failures'] = $this->import_failures;
1121ae1afd2fSChristopher Smith            session_write_close();
1122ae1afd2fSChristopher Smith        }
1123c5a7c0c6SGerrit Uitslag        return true;
1124ae1afd2fSChristopher Smith    }
1125ae1afd2fSChristopher Smith
1126c5a7c0c6SGerrit Uitslag    /**
1127786dfb0eSGerrit Uitslag     * Returns cleaned user data
1128c5a7c0c6SGerrit Uitslag     *
1129c5a7c0c6SGerrit Uitslag     * @param array $candidate raw values of line from input file
1130253d4b48SGerrit Uitslag     * @param string $error
1131253d4b48SGerrit Uitslag     * @return array|false cleaned data or false
1132c5a7c0c6SGerrit Uitslag     */
11333a97d936SAndreas Gohr    protected function cleanImportUser($candidate, & $error)
11343a97d936SAndreas Gohr    {
1135ae1afd2fSChristopher Smith        global $INPUT;
1136ae1afd2fSChristopher Smith
11373a97d936SAndreas Gohr        // FIXME kludgy ....
1138ae1afd2fSChristopher Smith        $INPUT->set('userid', $candidate[0]);
1139ae1afd2fSChristopher Smith        $INPUT->set('userpass', $candidate[1]);
1140ae1afd2fSChristopher Smith        $INPUT->set('username', $candidate[2]);
1141ae1afd2fSChristopher Smith        $INPUT->set('usermail', $candidate[3]);
1142ae1afd2fSChristopher Smith        $INPUT->set('usergroups', $candidate[4]);
1143ae1afd2fSChristopher Smith
11443a97d936SAndreas Gohr        $cleaned = $this->retrieveUser();
1145*54cc7aa4SAndreas Gohr        [$user, /* pass */ , $name, $mail, /* grps */ ] = $cleaned;
1146ae1afd2fSChristopher Smith        if (empty($user)) {
1147ae1afd2fSChristopher Smith            $error = $this->lang['import_error_baduserid'];
1148ae1afd2fSChristopher Smith            return false;
1149ae1afd2fSChristopher Smith        }
1150ae1afd2fSChristopher Smith
1151ae1afd2fSChristopher Smith        // no need to check password, handled elsewhere
1152ae1afd2fSChristopher Smith
11533a97d936SAndreas Gohr        if (!($this->auth->canDo('modName') xor empty($name))) {
1154ae1afd2fSChristopher Smith            $error = $this->lang['import_error_badname'];
1155ae1afd2fSChristopher Smith            return false;
1156ae1afd2fSChristopher Smith        }
1157ae1afd2fSChristopher Smith
11583a97d936SAndreas Gohr        if ($this->auth->canDo('modMail')) {
1159328143f8SChristopher Smith            if (empty($mail) || !mail_isvalid($mail)) {
1160ae1afd2fSChristopher Smith                $error = $this->lang['import_error_badmail'];
1161ae1afd2fSChristopher Smith                return false;
1162ae1afd2fSChristopher Smith            }
1163*54cc7aa4SAndreas Gohr        } elseif (!empty($mail)) {
1164328143f8SChristopher Smith            $error = $this->lang['import_error_badmail'];
1165328143f8SChristopher Smith            return false;
1166328143f8SChristopher Smith        }
1167ae1afd2fSChristopher Smith
1168ae1afd2fSChristopher Smith        return $cleaned;
1169ae1afd2fSChristopher Smith    }
1170ae1afd2fSChristopher Smith
1171c5a7c0c6SGerrit Uitslag    /**
1172c5a7c0c6SGerrit Uitslag     * Adds imported user to auth backend
1173c5a7c0c6SGerrit Uitslag     *
1174c5a7c0c6SGerrit Uitslag     * Required a check of canDo('addUser') before
1175c5a7c0c6SGerrit Uitslag     *
1176c5a7c0c6SGerrit Uitslag     * @param array  $user   data of user
1177c5a7c0c6SGerrit Uitslag     * @param string &$error reference catched error message
11785ba64050SChristopher Smith     * @return bool whether successful
1179c5a7c0c6SGerrit Uitslag     */
11803a97d936SAndreas Gohr    protected function importUser($user, &$error)
11813a97d936SAndreas Gohr    {
11823a97d936SAndreas Gohr        if (!$this->auth->triggerUserMod('create', $user)) {
1183ae1afd2fSChristopher Smith            $error = $this->lang['import_error_create'];
1184ae1afd2fSChristopher Smith            return false;
1185ae1afd2fSChristopher Smith        }
1186ae1afd2fSChristopher Smith
1187ae1afd2fSChristopher Smith        return true;
1188ae1afd2fSChristopher Smith    }
1189ae1afd2fSChristopher Smith
1190c5a7c0c6SGerrit Uitslag    /**
1191c5a7c0c6SGerrit Uitslag     * Downloads failures as csv file
1192c5a7c0c6SGerrit Uitslag     */
11933a97d936SAndreas Gohr    protected function downloadImportFailures()
11943a97d936SAndreas Gohr    {
1195ae1afd2fSChristopher Smith
1196ae1afd2fSChristopher Smith        // ==============================================================================================
1197ae1afd2fSChristopher Smith        // GENERATE OUTPUT
1198ae1afd2fSChristopher Smith        // normal headers for downloading...
1199ae1afd2fSChristopher Smith        header('Content-type: text/csv;charset=utf-8');
1200ae1afd2fSChristopher Smith        header('Content-Disposition: attachment; filename="importfails.csv"');
1201ae1afd2fSChristopher Smith#       // for debugging assistance, send as text plain to the browser
1202ae1afd2fSChristopher Smith#       header('Content-type: text/plain;charset=utf-8');
1203ae1afd2fSChristopher Smith
1204ae1afd2fSChristopher Smith        // output the csv
1205ae1afd2fSChristopher Smith        $fd = fopen('php://output', 'w');
12063a97d936SAndreas Gohr        foreach ($this->import_failures as $fail) {
1207*54cc7aa4SAndreas Gohr            fwrite($fd, $fail['orig']);
1208ae1afd2fSChristopher Smith        }
1209ae1afd2fSChristopher Smith        fclose($fd);
1210ae1afd2fSChristopher Smith        die;
1211ae1afd2fSChristopher Smith    }
1212ae1afd2fSChristopher Smith
1213b2c01466SChristopher Smith    /**
1214b2c01466SChristopher Smith     * wrapper for is_uploaded_file to facilitate overriding by test suite
1215253d4b48SGerrit Uitslag     *
1216253d4b48SGerrit Uitslag     * @param string $file filename
1217253d4b48SGerrit Uitslag     * @return bool
1218b2c01466SChristopher Smith     */
12193a97d936SAndreas Gohr    protected function isUploadedFile($file)
12203a97d936SAndreas Gohr    {
1221b2c01466SChristopher Smith        return is_uploaded_file($file);
1222b2c01466SChristopher Smith    }
12230440ff15Schris}
1224