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