xref: /plugin/struct/types/User.php (revision 9c1b8e31a3bbb364624b348e1f1b303399f7f049)
1914921fbSAndreas Gohr<?php
2d6d97f60SAnna Dabrowska
3ba766201SAndreas Gohrnamespace dokuwiki\plugin\struct\types;
4914921fbSAndreas Gohr
57234bfb1Ssplitbrainuse dokuwiki\Extension\AuthPlugin;
62e12ac22SMichael Grosseuse dokuwiki\plugin\struct\meta\QueryBuilder;
7af993d55SMichael Grosseuse dokuwiki\plugin\struct\meta\QueryBuilderWhere;
8ba766201SAndreas Gohruse dokuwiki\plugin\struct\meta\StructException;
9ba766201SAndreas Gohruse dokuwiki\plugin\struct\meta\ValidationException;
106a819106SAndreas Gohruse dokuwiki\Utf8\PhpString;
11914921fbSAndreas Gohr
12d6d97f60SAnna Dabrowskaclass User extends AbstractMultiBaseType
13d6d97f60SAnna Dabrowska{
147fe2cdf2SAndreas Gohr    protected $config = [
157fe2cdf2SAndreas Gohr        'existingonly' => true,
167fe2cdf2SAndreas Gohr        'autocomplete' => [
177fe2cdf2SAndreas Gohr            'fullname' => true,
187fe2cdf2SAndreas Gohr            'mininput' => 2,
197fe2cdf2SAndreas Gohr            'maxresult' => 5
207fe2cdf2SAndreas Gohr        ]
217fe2cdf2SAndreas Gohr    ];
22914921fbSAndreas Gohr
23914921fbSAndreas Gohr    /**
2423169abeSAndreas Gohr     * @param string $rawvalue the user to validate
256a819106SAndreas Gohr     * @return int|string
26f0d4d769SAndreas Gohr     */
27d6d97f60SAnna Dabrowska    public function validate($rawvalue)
28d6d97f60SAnna Dabrowska    {
2923169abeSAndreas Gohr        $rawvalue = parent::validate($rawvalue);
30806eec82SAndreas Gohr
318e3a19b5SAndreas Gohr        if ($this->config['existingonly']) {
327234bfb1Ssplitbrain            /** @var AuthPlugin $auth */
33f0d4d769SAndreas Gohr            global $auth;
3423169abeSAndreas Gohr            $info = $auth->getUserData($rawvalue, false);
3523169abeSAndreas Gohr            if ($info === false) throw new ValidationException('User not found', $rawvalue);
368e3a19b5SAndreas Gohr        }
378e3a19b5SAndreas Gohr
3823169abeSAndreas Gohr        return $rawvalue;
39b7413aefSAndreas Gohr    }
40b7413aefSAndreas Gohr
41b7413aefSAndreas Gohr    /**
42b7413aefSAndreas Gohr     * @param string $value the user to display
43b7413aefSAndreas Gohr     * @param \Doku_Renderer $R
44b7413aefSAndreas Gohr     * @param string $mode
45b7413aefSAndreas Gohr     * @return bool
46b7413aefSAndreas Gohr     */
47d6d97f60SAnna Dabrowska    public function renderValue($value, \Doku_Renderer $R, $mode)
48d6d97f60SAnna Dabrowska    {
49b7413aefSAndreas Gohr        if ($mode == 'xhtml') {
50b7413aefSAndreas Gohr            $name = userlink($value);
51b7413aefSAndreas Gohr            $R->doc .= $name;
52b7413aefSAndreas Gohr        } else {
53b7413aefSAndreas Gohr            $name = userlink($value, true);
54b7413aefSAndreas Gohr            $R->cdata($name);
55b7413aefSAndreas Gohr        }
56b7413aefSAndreas Gohr        return true;
57f0d4d769SAndreas Gohr    }
58f0d4d769SAndreas Gohr
59f0d4d769SAndreas Gohr    /**
60914921fbSAndreas Gohr     * Autocompletion for user names
61914921fbSAndreas Gohr     *
62914921fbSAndreas Gohr     * @return array
630549dcc5SAndreas Gohr     * @todo should we have any security mechanism? Currently everybody can look up users
64914921fbSAndreas Gohr     */
65d6d97f60SAnna Dabrowska    public function handleAjax()
66d6d97f60SAnna Dabrowska    {
677234bfb1Ssplitbrain        /** @var AuthPlugin $auth */
68914921fbSAndreas Gohr        global $auth;
69914921fbSAndreas Gohr        global $INPUT;
70914921fbSAndreas Gohr
71914921fbSAndreas Gohr        if (!$auth->canDo('getUsers')) {
725827d737SAnna Dabrowska            return [];
73914921fbSAndreas Gohr        }
74914921fbSAndreas Gohr
75914921fbSAndreas Gohr        // check minimum length
76914921fbSAndreas Gohr        $lookup = trim($INPUT->str('search'));
777234bfb1Ssplitbrain        if (PhpString::strlen($lookup) < $this->config['autocomplete']['mininput']) return [];
78914921fbSAndreas Gohr
7916a4ba5bSAndreas Gohr        // results wanted?
80914921fbSAndreas Gohr        $max = $this->config['autocomplete']['maxresult'];
817234bfb1Ssplitbrain        if ($max <= 0) return [];
8216a4ba5bSAndreas Gohr
8316a4ba5bSAndreas Gohr        // find users by login, fill up with names if wanted
84*9c1b8e31SChris MacMackin        // Because a value might be interpreted as integer in the
85*9c1b8e31SChris MacMackin        // array key, we temporarily pad each key with a space at the
86*9c1b8e31SChris MacMackin        // end to enforce string keys.
87*9c1b8e31SChris MacMackin        $pad_keys = function ($logins) {
88*9c1b8e31SChris MacMackin            $result = [];
89*9c1b8e31SChris MacMackin            foreach ($logins as $login => $info) {
90*9c1b8e31SChris MacMackin                $result["$login "] = $info;
91*9c1b8e31SChris MacMackin            }
92*9c1b8e31SChris MacMackin            return $result;
93*9c1b8e31SChris MacMackin        };
94*9c1b8e31SChris MacMackin        $logins = $pad_keys($auth->retrieveUsers(0, $max, ['user' => $lookup]));
954fea3d0aSAndreas Gohr        if ((count($logins) < $max) && $this->config['autocomplete']['fullname']) {
96*9c1b8e31SChris MacMackin            $logins = array_merge(
97*9c1b8e31SChris MacMackin                $logins,
98*9c1b8e31SChris MacMackin                $pad_keys($auth->retrieveUsers(0, $max, ['name' => $lookup]))
99*9c1b8e31SChris MacMackin            );
100914921fbSAndreas Gohr        }
101914921fbSAndreas Gohr
10225ae1d89SAndreas Gohr        // reformat result for jQuery UI Autocomplete
1037234bfb1Ssplitbrain        $users = [];
104914921fbSAndreas Gohr        foreach ($logins as $login => $info) {
105*9c1b8e31SChris MacMackin            $true_login = substr($login, 0, -1);
1067fe2cdf2SAndreas Gohr            $users[] = [
107*9c1b8e31SChris MacMackin                'label' => $info['name'] . ' [' . $true_login . ']',
108*9c1b8e31SChris MacMackin                'value' => $true_login
1097fe2cdf2SAndreas Gohr            ];
110914921fbSAndreas Gohr        }
111914921fbSAndreas Gohr
112914921fbSAndreas Gohr        return $users;
113914921fbSAndreas Gohr    }
114914921fbSAndreas Gohr
1152e12ac22SMichael Grosse    /**
1162e12ac22SMichael Grosse     * When handling `%lasteditor%` get the data from the `titles` table instead the `data_` table.
1172e12ac22SMichael Grosse     *
1182e12ac22SMichael Grosse     * @param QueryBuilder $QB
1192e12ac22SMichael Grosse     * @param string $tablealias
1202e12ac22SMichael Grosse     * @param string $colname
1212e12ac22SMichael Grosse     * @param string $alias
1222e12ac22SMichael Grosse     */
123d6d97f60SAnna Dabrowska    public function select(QueryBuilder $QB, $tablealias, $colname, $alias)
124d6d97f60SAnna Dabrowska    {
1252e12ac22SMichael Grosse        if (is_a($this->context, 'dokuwiki\plugin\struct\meta\UserColumn')) {
1262e12ac22SMichael Grosse            $rightalias = $QB->generateTableAlias();
1272e12ac22SMichael Grosse            $QB->addLeftJoin($tablealias, 'titles', $rightalias, "$tablealias.pid = $rightalias.pid");
1282e12ac22SMichael Grosse            $QB->addSelectStatement("$rightalias.lasteditor", $alias);
1292e12ac22SMichael Grosse            return;
1302e12ac22SMichael Grosse        }
1312e12ac22SMichael Grosse
1322e12ac22SMichael Grosse        parent::select($QB, $tablealias, $colname, $alias);
1332e12ac22SMichael Grosse    }
1342e12ac22SMichael Grosse
1352e12ac22SMichael Grosse    /**
1362e12ac22SMichael Grosse     * When sorting `%lasteditor%`, then sort the data from the `titles` table instead the `data_` table.
1372e12ac22SMichael Grosse     *
1382e12ac22SMichael Grosse     * @param QueryBuilder $QB
1392e12ac22SMichael Grosse     * @param string $tablealias
1402e12ac22SMichael Grosse     * @param string $colname
1412e12ac22SMichael Grosse     * @param string $order
1422e12ac22SMichael Grosse     */
143d6d97f60SAnna Dabrowska    public function sort(QueryBuilder $QB, $tablealias, $colname, $order)
144d6d97f60SAnna Dabrowska    {
1452e12ac22SMichael Grosse        if (is_a($this->context, 'dokuwiki\plugin\struct\meta\UserColumn')) {
1462e12ac22SMichael Grosse            $rightalias = $QB->generateTableAlias();
1472e12ac22SMichael Grosse            $QB->addLeftJoin($tablealias, 'titles', $rightalias, "$tablealias.pid = $rightalias.pid");
1482e12ac22SMichael Grosse            $QB->addOrderBy("$rightalias.lasteditor $order");
1492e12ac22SMichael Grosse            return;
1502e12ac22SMichael Grosse        }
1512e12ac22SMichael Grosse
1522e12ac22SMichael Grosse        $QB->addOrderBy("$tablealias.$colname $order");
1532e12ac22SMichael Grosse    }
1542e12ac22SMichael Grosse
1552e12ac22SMichael Grosse    /**
1562e12ac22SMichael Grosse     * When using `%lasteditor%`, we need to compare against the `title` table.
1572e12ac22SMichael Grosse     *
158af993d55SMichael Grosse     * @param QueryBuilderWhere $add
1592e12ac22SMichael Grosse     * @param string $tablealias
1602e12ac22SMichael Grosse     * @param string $colname
1612e12ac22SMichael Grosse     * @param string $comp
1626a819106SAndreas Gohr     * @param string|string[] $value
1632e12ac22SMichael Grosse     * @param string $op
1642e12ac22SMichael Grosse     */
165d6d97f60SAnna Dabrowska    public function filter(QueryBuilderWhere $add, $tablealias, $colname, $comp, $value, $op)
166d6d97f60SAnna Dabrowska    {
1672e12ac22SMichael Grosse        if (is_a($this->context, 'dokuwiki\plugin\struct\meta\UserColumn')) {
168af993d55SMichael Grosse            $QB = $add->getQB();
1692e12ac22SMichael Grosse            $rightalias = $QB->generateTableAlias();
1702e12ac22SMichael Grosse            $QB->addLeftJoin($tablealias, 'titles', $rightalias, "$tablealias.pid = $rightalias.pid");
1712e12ac22SMichael Grosse
1722e12ac22SMichael Grosse            // compare against page and title
173af993d55SMichael Grosse            $sub = $add->where($op);
1742e12ac22SMichael Grosse            $pl = $QB->addValue($value);
1752e12ac22SMichael Grosse            $sub->whereOr("$rightalias.lasteditor $comp $pl");
1762e12ac22SMichael Grosse            return;
1772e12ac22SMichael Grosse        }
1782e12ac22SMichael Grosse
179af993d55SMichael Grosse        parent::filter($add, $tablealias, $colname, $comp, $value, $op);
1802e12ac22SMichael Grosse    }
181914921fbSAndreas Gohr}
182