1<?php 2 3namespace dokuwiki\plugin\struct\types; 4 5use dokuwiki\Extension\AuthPlugin; 6use dokuwiki\plugin\struct\meta\QueryBuilder; 7use dokuwiki\plugin\struct\meta\QueryBuilderWhere; 8use dokuwiki\plugin\struct\meta\StructException; 9use dokuwiki\plugin\struct\meta\ValidationException; 10use dokuwiki\Utf8\PhpString; 11 12class User extends AbstractMultiBaseType 13{ 14 protected $config = [ 15 'existingonly' => true, 16 'autocomplete' => [ 17 'fullname' => true, 18 'mininput' => 2, 19 'maxresult' => 5 20 ] 21 ]; 22 23 /** 24 * @param string $rawvalue the user to validate 25 * @return int|string 26 */ 27 public function validate($rawvalue) 28 { 29 $rawvalue = parent::validate($rawvalue); 30 31 if ($this->config['existingonly']) { 32 /** @var AuthPlugin $auth */ 33 global $auth; 34 $info = $auth->getUserData($rawvalue, false); 35 if ($info === false) throw new ValidationException('User not found', $rawvalue); 36 } 37 38 return $rawvalue; 39 } 40 41 /** 42 * @param string $value the user to display 43 * @param \Doku_Renderer $R 44 * @param string $mode 45 * @return bool 46 */ 47 public function renderValue($value, \Doku_Renderer $R, $mode) 48 { 49 if ($mode == 'xhtml') { 50 $name = userlink($value); 51 $R->doc .= $name; 52 } else { 53 $name = userlink($value, true); 54 $R->cdata($name); 55 } 56 return true; 57 } 58 59 /** 60 * Autocompletion for user names 61 * 62 * @return array 63 * @todo should we have any security mechanism? Currently everybody can look up users 64 */ 65 public function handleAjax() 66 { 67 /** @var AuthPlugin $auth */ 68 global $auth; 69 global $INPUT; 70 71 if (!$auth->canDo('getUsers')) { 72 return []; 73 } 74 75 // check minimum length 76 $lookup = trim($INPUT->str('search')); 77 if (PhpString::strlen($lookup) < $this->config['autocomplete']['mininput']) return []; 78 79 // results wanted? 80 $max = $this->config['autocomplete']['maxresult']; 81 if ($max <= 0) return []; 82 83 // find users by login, fill up with names if wanted 84 // Because a value might be interpreted as integer in the 85 // array key, we temporarily pad each key with a space at the 86 // end to enforce string keys. 87 $pad_keys = function ($logins) { 88 $result = []; 89 foreach ($logins as $login => $info) { 90 $result["$login "] = $info; 91 } 92 return $result; 93 }; 94 $logins = $pad_keys($auth->retrieveUsers(0, $max, ['user' => $lookup])); 95 if ((count($logins) < $max) && $this->config['autocomplete']['fullname']) { 96 $logins = array_merge( 97 $logins, 98 $pad_keys($auth->retrieveUsers(0, $max, ['name' => $lookup])) 99 ); 100 } 101 102 // reformat result for jQuery UI Autocomplete 103 $users = []; 104 foreach ($logins as $login => $info) { 105 $true_login = substr($login, 0, -1); 106 $users[] = [ 107 'label' => $info['name'] . ' [' . $true_login . ']', 108 'value' => $true_login 109 ]; 110 } 111 112 return $users; 113 } 114 115 /** 116 * When handling `%lasteditor%` get the data from the `titles` table instead the `data_` table. 117 * 118 * @param QueryBuilder $QB 119 * @param string $tablealias 120 * @param string $colname 121 * @param string $alias 122 */ 123 public function select(QueryBuilder $QB, $tablealias, $colname, $alias) 124 { 125 if (is_a($this->context, 'dokuwiki\plugin\struct\meta\UserColumn')) { 126 $rightalias = $QB->generateTableAlias(); 127 $QB->addLeftJoin($tablealias, 'titles', $rightalias, "$tablealias.pid = $rightalias.pid"); 128 $QB->addSelectStatement("$rightalias.lasteditor", $alias); 129 return; 130 } 131 132 parent::select($QB, $tablealias, $colname, $alias); 133 } 134 135 /** 136 * When sorting `%lasteditor%`, then sort the data from the `titles` table instead the `data_` table. 137 * 138 * @param QueryBuilder $QB 139 * @param string $tablealias 140 * @param string $colname 141 * @param string $order 142 */ 143 public function sort(QueryBuilder $QB, $tablealias, $colname, $order) 144 { 145 if (is_a($this->context, 'dokuwiki\plugin\struct\meta\UserColumn')) { 146 $rightalias = $QB->generateTableAlias(); 147 $QB->addLeftJoin($tablealias, 'titles', $rightalias, "$tablealias.pid = $rightalias.pid"); 148 $QB->addOrderBy("$rightalias.lasteditor $order"); 149 return; 150 } 151 152 $QB->addOrderBy("$tablealias.$colname $order"); 153 } 154 155 /** 156 * When using `%lasteditor%`, we need to compare against the `title` table. 157 * 158 * @param QueryBuilderWhere $add 159 * @param string $tablealias 160 * @param string $colname 161 * @param string $comp 162 * @param string|string[] $value 163 * @param string $op 164 */ 165 public function filter(QueryBuilderWhere $add, $tablealias, $colname, $comp, $value, $op) 166 { 167 if (is_a($this->context, 'dokuwiki\plugin\struct\meta\UserColumn')) { 168 $QB = $add->getQB(); 169 $rightalias = $QB->generateTableAlias(); 170 $QB->addLeftJoin($tablealias, 'titles', $rightalias, "$tablealias.pid = $rightalias.pid"); 171 172 // compare against page and title 173 $sub = $add->where($op); 174 $pl = $QB->addValue($value); 175 $sub->whereOr("$rightalias.lasteditor $comp $pl"); 176 return; 177 } 178 179 parent::filter($add, $tablealias, $colname, $comp, $value, $op); 180 } 181} 182