Move IDatabase/IMaintainableDatabase to Rdbms namespace
[lhc/web/wiklou.git] / includes / user / UserRightsProxy.php
1 <?php
2 /**
3 * Representation of an user on a other locally-hosted wiki.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 * @file
21 */
22
23 use Wikimedia\Rdbms\IDatabase;
24
25 /**
26 * Cut-down copy of User interface for local-interwiki-database
27 * user rights manipulation.
28 */
29 class UserRightsProxy {
30
31 /**
32 * Constructor.
33 *
34 * @see newFromId()
35 * @see newFromName()
36 * @param IDatabase $db Db connection
37 * @param string $database Database name
38 * @param string $name User name
39 * @param int $id User ID
40 */
41 private function __construct( $db, $database, $name, $id ) {
42 $this->db = $db;
43 $this->database = $database;
44 $this->name = $name;
45 $this->id = intval( $id );
46 $this->newOptions = [];
47 }
48
49 /**
50 * Accessor for $this->database
51 *
52 * @return string Database name
53 */
54 public function getDBName() {
55 return $this->database;
56 }
57
58 /**
59 * Confirm the selected database name is a valid local interwiki database name.
60 *
61 * @param string $database Database name
62 * @return bool
63 */
64 public static function validDatabase( $database ) {
65 global $wgLocalDatabases;
66 return in_array( $database, $wgLocalDatabases );
67 }
68
69 /**
70 * Same as User::whoIs()
71 *
72 * @param string $database Database name
73 * @param int $id User ID
74 * @param bool $ignoreInvalidDB If true, don't check if $database is in $wgLocalDatabases
75 * @return string User name or false if the user doesn't exist
76 */
77 public static function whoIs( $database, $id, $ignoreInvalidDB = false ) {
78 $user = self::newFromId( $database, $id, $ignoreInvalidDB );
79 if ( $user ) {
80 return $user->name;
81 } else {
82 return false;
83 }
84 }
85
86 /**
87 * Factory function; get a remote user entry by ID number.
88 *
89 * @param string $database Database name
90 * @param int $id User ID
91 * @param bool $ignoreInvalidDB If true, don't check if $database is in $wgLocalDatabases
92 * @return UserRightsProxy|null If doesn't exist
93 */
94 public static function newFromId( $database, $id, $ignoreInvalidDB = false ) {
95 return self::newFromLookup( $database, 'user_id', intval( $id ), $ignoreInvalidDB );
96 }
97
98 /**
99 * Factory function; get a remote user entry by name.
100 *
101 * @param string $database Database name
102 * @param string $name User name
103 * @param bool $ignoreInvalidDB If true, don't check if $database is in $wgLocalDatabases
104 * @return UserRightsProxy|null If doesn't exist
105 */
106 public static function newFromName( $database, $name, $ignoreInvalidDB = false ) {
107 return self::newFromLookup( $database, 'user_name', $name, $ignoreInvalidDB );
108 }
109
110 /**
111 * @param string $database
112 * @param string $field
113 * @param string $value
114 * @param bool $ignoreInvalidDB
115 * @return null|UserRightsProxy
116 */
117 private static function newFromLookup( $database, $field, $value, $ignoreInvalidDB = false ) {
118 global $wgSharedDB, $wgSharedTables;
119 // If the user table is shared, perform the user query on it,
120 // but don't pass it to the UserRightsProxy,
121 // as user rights are normally not shared.
122 if ( $wgSharedDB && in_array( 'user', $wgSharedTables ) ) {
123 $userdb = self::getDB( $wgSharedDB, $ignoreInvalidDB );
124 } else {
125 $userdb = self::getDB( $database, $ignoreInvalidDB );
126 }
127
128 $db = self::getDB( $database, $ignoreInvalidDB );
129
130 if ( $db && $userdb ) {
131 $row = $userdb->selectRow( 'user',
132 [ 'user_id', 'user_name' ],
133 [ $field => $value ],
134 __METHOD__ );
135
136 if ( $row !== false ) {
137 return new UserRightsProxy( $db, $database,
138 $row->user_name,
139 intval( $row->user_id ) );
140 }
141 }
142 return null;
143 }
144
145 /**
146 * Open a database connection to work on for the requested user.
147 * This may be a new connection to another database for remote users.
148 *
149 * @param string $database
150 * @param bool $ignoreInvalidDB If true, don't check if $database is in $wgLocalDatabases
151 * @return IDatabase|null If invalid selection
152 */
153 public static function getDB( $database, $ignoreInvalidDB = false ) {
154 global $wgDBname;
155 if ( $ignoreInvalidDB || self::validDatabase( $database ) ) {
156 if ( $database == $wgDBname ) {
157 // Hmm... this shouldn't happen though. :)
158 return wfGetDB( DB_MASTER );
159 } else {
160 return wfGetDB( DB_MASTER, [], $database );
161 }
162 }
163 return null;
164 }
165
166 /**
167 * @return int
168 */
169 public function getId() {
170 return $this->id;
171 }
172
173 /**
174 * @return bool
175 */
176 public function isAnon() {
177 return $this->getId() == 0;
178 }
179
180 /**
181 * Same as User::getName()
182 *
183 * @return string
184 */
185 public function getName() {
186 return $this->name . '@' . $this->database;
187 }
188
189 /**
190 * Same as User::getUserPage()
191 *
192 * @return Title
193 */
194 public function getUserPage() {
195 return Title::makeTitle( NS_USER, $this->getName() );
196 }
197
198 /**
199 * Replaces User::getUserGroups()
200 * @return array
201 */
202 function getGroups() {
203 return array_keys( self::getGroupMemberships() );
204 }
205
206 /**
207 * Replaces User::getGroupMemberships()
208 *
209 * @return array
210 * @since 1.29
211 */
212 function getGroupMemberships() {
213 return UserGroupMembership::getMembershipsForUser( $this->id, $this->db );
214 }
215
216 /**
217 * Replaces User::addGroup()
218 *
219 * @param string $group
220 * @param string|null $expiry
221 * @return bool
222 */
223 function addGroup( $group, $expiry = null ) {
224 if ( $expiry ) {
225 $expiry = wfTimestamp( TS_MW, $expiry );
226 }
227
228 $ugm = new UserGroupMembership( $this->id, $group, $expiry );
229 return $ugm->insert( true, $this->db );
230 }
231
232 /**
233 * Replaces User::removeGroup()
234 *
235 * @param string $group
236 * @return bool
237 */
238 function removeGroup( $group ) {
239 $ugm = UserGroupMembership::getMembership( $this->id, $group, $this->db );
240 if ( !$ugm ) {
241 return false;
242 }
243 return $ugm->delete( $this->db );
244 }
245
246 /**
247 * Replaces User::setOption()
248 * @param string $option
249 * @param mixed $value
250 */
251 public function setOption( $option, $value ) {
252 $this->newOptions[$option] = $value;
253 }
254
255 public function saveSettings() {
256 $rows = [];
257 foreach ( $this->newOptions as $option => $value ) {
258 $rows[] = [
259 'up_user' => $this->id,
260 'up_property' => $option,
261 'up_value' => $value,
262 ];
263 }
264 $this->db->replace( 'user_properties',
265 [ [ 'up_user', 'up_property' ] ],
266 $rows, __METHOD__
267 );
268 $this->invalidateCache();
269 }
270
271 /**
272 * Replaces User::touchUser()
273 */
274 function invalidateCache() {
275 $this->db->update(
276 'user',
277 [ 'user_touched' => $this->db->timestamp() ],
278 [ 'user_id' => $this->id ],
279 __METHOD__
280 );
281
282 $wikiId = $this->db->getWikiID();
283 $userId = $this->id;
284 $this->db->onTransactionPreCommitOrIdle(
285 function () use ( $wikiId, $userId ) {
286 User::purge( $wikiId, $userId );
287 },
288 __METHOD__
289 );
290 }
291 }