Completed
Pull Request — master (#2)
by Stephen
13:19
created

wpTearDownAfterClass()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 20
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 14
nc 8
nop 0
dl 0
loc 20
rs 9.2
c 0
b 0
f 0
1
<?php
2
/**
3
 * Unit tests covering WP_REST_Users_Controller functionality.
4
 *
5
 * @package WordPress
6
 * @subpackage REST API
7
 */
8
9
/**
10
 * @group restapi
11
 */
12
class WP_Test_REST_Users_Controller extends WP_Test_REST_Controller_Testcase {
13
	protected static $superadmin;
14
	protected static $user;
15
	protected static $editor;
16
	protected static $draft_editor;
17
	protected static $authors = array();
18
	protected static $posts = array();
19
	protected static $site;
20
21
	public static function wpSetUpBeforeClass( $factory ) {
22
		self::$superadmin = $factory->user->create( array(
23
			'role'       => 'administrator',
24
			'user_login' => 'superadmin',
25
		) );
26
		self::$user = $factory->user->create( array(
27
			'role' => 'administrator',
28
		) );
29
		self::$editor = $factory->user->create( array(
30
			'role'       => 'editor',
31
			'user_email' => '[email protected]',
32
		) );
33
		self::$draft_editor = $factory->user->create( array(
34
			'role'       => 'editor',
35
			'user_email' => '[email protected]',
36
		) );
37
38
		foreach ( array( true, false ) as $show_in_rest ) {
39
			foreach ( array( true, false ) as $public ) {
40
				$post_type_name = 'r_' . json_encode( $show_in_rest ) . '_p_' . json_encode( $public );
41
				register_post_type( $post_type_name, array(
42
					'public'                   => $public,
43
					'show_in_rest'             => $show_in_rest,
44
					'tests_no_auto_unregister' => true,
45
				) );
46
				self::$authors[ $post_type_name ] = $factory->user->create( array(
47
					'role'       => 'editor',
48
					'user_email' => 'author_' . $post_type_name . '@example.com',
49
				) );
50
				self::$posts[ $post_type_name ] = $factory->post->create( array(
51
					'post_type'   => $post_type_name,
52
					'post_author' => self::$authors[ $post_type_name ],
53
				) );
54
			}
55
		}
56
57
		self::$posts['post'] = $factory->post->create( array(
58
			'post_type'   => 'post',
59
			'post_author' => self::$editor,
60
		) );
61
		self::$posts['r_true_p_true_DRAFT'] = $factory->post->create( array(
62
			'post_type'   => 'r_true_p_true',
63
			'post_author' => self::$draft_editor,
64
			'post_status' => 'draft',
65
		) );
66
67
		if ( is_multisite() ) {
68
			self::$site = $factory->blog->create( array( 'domain' => 'rest.wordpress.org', 'path' => '/' ) );
69
			update_site_option( 'site_admins', array( 'superadmin' ) );
70
		}
71
	}
72
73
	public static function wpTearDownAfterClass() {
74
		self::delete_user( self::$user );
75
		self::delete_user( self::$editor );
76
		self::delete_user( self::$draft_editor );
77
78
		foreach ( self::$posts as $post ) {
79
			wp_delete_post( $post, true );
80
		}
81
		foreach ( self::$authors as $author ) {
82
			self::delete_user( $author );
83
		}
84
		_unregister_post_type( 'r_true_p_true' );
85
		_unregister_post_type( 'r_true_p_false' );
86
		_unregister_post_type( 'r_false_p_true' );
87
		_unregister_post_type( 'r_false_p_false' );
88
89
		if ( is_multisite() ) {
90
			wpmu_delete_blog( self::$site, true );
91
		}
92
	}
93
94
	/**
95
	 * This function is run before each method
96
	 */
97
	public function setUp() {
98
		parent::setUp();
99
		$this->endpoint = new WP_REST_Users_Controller();
100
	}
101
102
	public function test_register_routes() {
103
		$routes = $this->server->get_routes();
104
105
		$this->assertArrayHasKey( '/wp/v2/users', $routes );
106
		$this->assertCount( 2, $routes['/wp/v2/users'] );
107
		$this->assertArrayHasKey( '/wp/v2/users/(?P<id>[\d]+)', $routes );
108
		$this->assertCount( 3, $routes['/wp/v2/users/(?P<id>[\d]+)'] );
109
		$this->assertArrayHasKey( '/wp/v2/users/me', $routes );
110
	}
111
112
	public function test_context_param() {
113
		// Collection
114
		$request = new WP_REST_Request( 'OPTIONS', '/wp/v2/users' );
115
		$response = $this->server->dispatch( $request );
116
		$data = $response->get_data();
117
		$this->assertEquals( 'view', $data['endpoints'][0]['args']['context']['default'] );
118
		$this->assertEquals( array( 'view', 'embed', 'edit' ), $data['endpoints'][0]['args']['context']['enum'] );
119
		// Single
120
		$request = new WP_REST_Request( 'OPTIONS', '/wp/v2/users/' . self::$user );
121
		$response = $this->server->dispatch( $request );
122
		$data = $response->get_data();
123
		$this->assertEquals( 'view', $data['endpoints'][0]['args']['context']['default'] );
124
		$this->assertEquals( array( 'view', 'embed', 'edit' ), $data['endpoints'][0]['args']['context']['enum'] );
125
	}
126
127
	public function test_registered_query_params() {
128
		$request = new WP_REST_Request( 'OPTIONS', '/wp/v2/users' );
129
		$response = $this->server->dispatch( $request );
130
		$data = $response->get_data();
131
		$keys = array_keys( $data['endpoints'][0]['args'] );
132
		sort( $keys );
133
		$this->assertEquals( array(
134
			'context',
135
			'exclude',
136
			'include',
137
			'offset',
138
			'order',
139
			'orderby',
140
			'page',
141
			'per_page',
142
			'roles',
143
			'search',
144
			'slug',
145
			), $keys );
146
	}
147
148
	public function test_get_items() {
149
		wp_set_current_user( self::$user );
150
151
		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
152
		$request->set_param( 'context', 'view' );
153
		$response = $this->server->dispatch( $request );
154
155
		$this->assertEquals( 200, $response->get_status() );
156
157
		$all_data = $response->get_data();
158
		$data = $all_data[0];
159
		$userdata = get_userdata( $data['id'] );
160
		$this->check_user_data( $userdata, $data, 'view', $data['_links'] );
161
	}
162
163
	public function test_get_items_with_edit_context() {
164
		wp_set_current_user( self::$user );
165
166
		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
167
		$request->set_param( 'context', 'edit' );
168
		$response = $this->server->dispatch( $request );
169
170
		$this->assertEquals( 200, $response->get_status() );
171
172
		$all_data = $response->get_data();
173
		$data = $all_data[0];
174
		$userdata = get_userdata( $data['id'] );
175
		$this->check_user_data( $userdata, $data, 'edit', $data['_links'] );
176
	}
177
178
	public function test_get_items_with_edit_context_without_permission() {
179
		//test with a user not logged in
180
		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
181
		$request->set_param( 'context', 'edit' );
182
		$response = $this->server->dispatch( $request );
183
184
		$this->assertEquals( 401, $response->get_status() );
185
186
		//test with a user logged in but without sufficient capabilities; capability in question: 'list_users'
187
		wp_set_current_user( self::$editor );
188
		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
189
		$request->set_param( 'context', 'edit' );
190
		$response = $this->server->dispatch( $request );
191
192
		$this->assertEquals( 403, $response->get_status() );
193
	}
194
195
	public function test_get_items_unauthenticated_includes_authors_of_post_types_shown_in_rest() {
196
		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
197
		$response = $this->server->dispatch( $request );
198
		$users = $response->get_data();
199
200
		$rest_post_types = array_values( get_post_types( array( 'show_in_rest' => true ), 'names' ) );
201
202
		foreach ( $users as $user ) {
203
			$this->assertTrue( count_user_posts( $user['id'], $rest_post_types ) > 0 );
204
205
			// Ensure we don't expose non-public data.
206
			$this->assertArrayNotHasKey( 'capabilities', $user );
207
			$this->assertArrayNotHasKey( 'registered_date', $user );
208
			$this->assertArrayNotHasKey( 'first_name', $user );
209
			$this->assertArrayNotHasKey( 'last_name', $user );
210
			$this->assertArrayNotHasKey( 'nickname', $user );
211
			$this->assertArrayNotHasKey( 'extra_capabilities', $user );
212
			$this->assertArrayNotHasKey( 'username', $user );
213
			$this->assertArrayNotHasKey( 'email', $user );
214
			$this->assertArrayNotHasKey( 'roles', $user );
215
			$this->assertArrayNotHasKey( 'locale', $user );
216
		}
217
218
		$user_ids = wp_list_pluck( $users, 'id' );
219
220
		$this->assertTrue( in_array( self::$editor                   , $user_ids, true ) );
221
		$this->assertTrue( in_array( self::$authors['r_true_p_true'] , $user_ids, true ) );
222
		$this->assertTrue( in_array( self::$authors['r_true_p_false'], $user_ids, true ) );
223
		$this->assertCount( 3, $user_ids );
224
	}
225
226
	public function test_get_items_unauthenticated_does_not_include_authors_of_post_types_not_shown_in_rest() {
227
		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
228
		$response = $this->server->dispatch( $request );
229
		$users = $response->get_data();
230
		$user_ids = wp_list_pluck( $users, 'id' );
231
232
		$this->assertFalse( in_array( self::$authors['r_false_p_true'] , $user_ids, true ) );
233
		$this->assertFalse( in_array( self::$authors['r_false_p_false'], $user_ids, true ) );
234
	}
235
236
	public function test_get_items_unauthenticated_does_not_include_users_without_published_posts() {
237
		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
238
		$response = $this->server->dispatch( $request );
239
		$users = $response->get_data();
240
		$user_ids = wp_list_pluck( $users, 'id' );
241
242
		$this->assertFalse( in_array( self::$draft_editor, $user_ids, true ) );
243
		$this->assertFalse( in_array( self::$user        , $user_ids, true ) );
244
	}
245
246
	public function test_get_items_pagination_headers() {
247
		wp_set_current_user( self::$user );
248
		for ( $i = 0; $i < 44; $i++ ) {
249
			$this->factory->user->create( array(
250
				'name' => "User {$i}",
251
			) );
252
		}
253
		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
254
		$response = $this->server->dispatch( $request );
255
		$headers = $response->get_headers();
256
		$this->assertEquals( 53, $headers['X-WP-Total'] );
257
		$this->assertEquals( 6, $headers['X-WP-TotalPages'] );
258
		$next_link = add_query_arg( array(
259
			'page'    => 2,
260
			), rest_url( 'wp/v2/users' ) );
261
		$this->assertFalse( stripos( $headers['Link'], 'rel="prev"' ) );
262
		$this->assertContains( '<' . $next_link . '>; rel="next"', $headers['Link'] );
263
		// 3rd page
264
		$this->factory->user->create( array(
265
				'name'   => 'User 51',
266
				) );
267
		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
268
		$request->set_param( 'page', 3 );
269
		$response = $this->server->dispatch( $request );
270
		$headers = $response->get_headers();
271
		$this->assertEquals( 54, $headers['X-WP-Total'] );
272
		$this->assertEquals( 6, $headers['X-WP-TotalPages'] );
273
		$prev_link = add_query_arg( array(
274
			'page'    => 2,
275
			), rest_url( 'wp/v2/users' ) );
276
		$this->assertContains( '<' . $prev_link . '>; rel="prev"', $headers['Link'] );
277
		$next_link = add_query_arg( array(
278
			'page'    => 4,
279
			), rest_url( 'wp/v2/users' ) );
280
		$this->assertContains( '<' . $next_link . '>; rel="next"', $headers['Link'] );
281
		// Last page
282
		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
283
		$request->set_param( 'page', 6 );
284
		$response = $this->server->dispatch( $request );
285
		$headers = $response->get_headers();
286
		$this->assertEquals( 54, $headers['X-WP-Total'] );
287
		$this->assertEquals( 6, $headers['X-WP-TotalPages'] );
288
		$prev_link = add_query_arg( array(
289
			'page'    => 5,
290
			), rest_url( 'wp/v2/users' ) );
291
		$this->assertContains( '<' . $prev_link . '>; rel="prev"', $headers['Link'] );
292
		$this->assertFalse( stripos( $headers['Link'], 'rel="next"' ) );
293
		// Out of bounds
294
		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
295
		$request->set_param( 'page', 8 );
296
		$response = $this->server->dispatch( $request );
297
		$headers = $response->get_headers();
298
		$this->assertEquals( 54, $headers['X-WP-Total'] );
299
		$this->assertEquals( 6, $headers['X-WP-TotalPages'] );
300
		$prev_link = add_query_arg( array(
301
			'page'    => 6,
302
			), rest_url( 'wp/v2/users' ) );
303
		$this->assertContains( '<' . $prev_link . '>; rel="prev"', $headers['Link'] );
304
		$this->assertFalse( stripos( $headers['Link'], 'rel="next"' ) );
305
	}
306
307
	public function test_get_items_per_page() {
308
		wp_set_current_user( self::$user );
309
		for ( $i = 0; $i < 20; $i++ ) {
310
			$this->factory->user->create( array( 'display_name' => "User {$i}" ) );
311
		}
312
		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
313
		$response = $this->server->dispatch( $request );
314
		$this->assertEquals( 10, count( $response->get_data() ) );
315
		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
316
		$request->set_param( 'per_page', 5 );
317
		$response = $this->server->dispatch( $request );
318
		$this->assertEquals( 5, count( $response->get_data() ) );
319
	}
320
321
	public function test_get_items_page() {
322
		wp_set_current_user( self::$user );
323
		for ( $i = 0; $i < 20; $i++ ) {
324
			$this->factory->user->create( array( 'display_name' => "User {$i}" ) );
325
		}
326
		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
327
		$request->set_param( 'per_page', 5 );
328
		$request->set_param( 'page', 2 );
329
		$response = $this->server->dispatch( $request );
330
		$this->assertEquals( 5, count( $response->get_data() ) );
331
		$prev_link = add_query_arg( array(
332
			'per_page'  => 5,
333
			'page'      => 1,
334
			), rest_url( 'wp/v2/users' ) );
335
		$headers = $response->get_headers();
336
		$this->assertContains( '<' . $prev_link . '>; rel="prev"', $headers['Link'] );
337
	}
338
339
	public function test_get_items_orderby_name() {
340
		wp_set_current_user( self::$user );
341
		$low_id = $this->factory->user->create( array( 'display_name' => 'AAAAA' ) );
342
		$mid_id = $this->factory->user->create( array( 'display_name' => 'NNNNN' ) );
0 ignored issues
show
Unused Code introduced by
$mid_id is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
343
		$high_id = $this->factory->user->create( array( 'display_name' => 'ZZZZ' ) );
344
		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
345
		$request->set_param( 'orderby', 'name' );
346
		$request->set_param( 'order', 'desc' );
347
		$request->set_param( 'per_page', 1 );
348
		$response = $this->server->dispatch( $request );
349
		$data = $response->get_data();
350
		$this->assertEquals( $high_id, $data[0]['id'] );
351
		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
352
		$request->set_param( 'orderby', 'name' );
353
		$request->set_param( 'order', 'asc' );
354
		$request->set_param( 'per_page', 1 );
355
		$response = $this->server->dispatch( $request );
356
		$data = $response->get_data();
357
		$this->assertEquals( $low_id, $data[0]['id'] );
358
	}
359
360
	public function test_get_items_orderby_url() {
361
		wp_set_current_user( self::$user );
362
363
		$low_id = $this->factory->user->create( array( 'user_url' => 'http://a.com' ) );
364
		$high_id = $this->factory->user->create( array( 'user_url' => 'http://b.com' ) );
365
366
		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
367
		$request->set_param( 'orderby', 'url' );
368
		$request->set_param( 'order', 'desc' );
369
		$request->set_param( 'per_page', 1 );
370
		$request->set_param( 'include', array( $low_id, $high_id ) );
371
		$response = $this->server->dispatch( $request );
372
		$data = $response->get_data();
373
374
		$this->assertEquals( $high_id, $data[0]['id'] );
375
376
		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
377
		$request->set_param( 'orderby', 'url' );
378
		$request->set_param( 'order', 'asc' );
379
		$request->set_param( 'per_page', 1 );
380
		$request->set_param( 'include', array( $low_id, $high_id ) );
381
		$response = $this->server->dispatch( $request );
382
		$data = $response->get_data();
383
		$this->assertEquals( $low_id, $data[0]['id'] );
384
	}
385
386
	public function test_get_items_orderby_slug() {
387
		wp_set_current_user( self::$user );
388
389
		$high_id = $this->factory->user->create( array( 'user_nicename' => 'blogin' ) );
390
		$low_id = $this->factory->user->create( array( 'user_nicename' => 'alogin' ) );
391
392
		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
393
		$request->set_param( 'orderby', 'slug' );
394
		$request->set_param( 'order', 'desc' );
395
		$request->set_param( 'per_page', 1 );
396
		$request->set_param( 'include', array( $low_id, $high_id ) );
397
		$response = $this->server->dispatch( $request );
398
		$data = $response->get_data();
399
400
		$this->assertEquals( $high_id, $data[0]['id'] );
401
402
		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
403
		$request->set_param( 'orderby', 'slug' );
404
		$request->set_param( 'order', 'asc' );
405
		$request->set_param( 'per_page', 1 );
406
		$request->set_param( 'include', array( $low_id, $high_id ) );
407
		$response = $this->server->dispatch( $request );
408
		$data = $response->get_data();
409
		$this->assertEquals( $low_id, $data[0]['id'] );
410
	}
411
412
	public function test_get_items_orderby_email() {
413
		wp_set_current_user( self::$user );
414
415
		$high_id = $this->factory->user->create( array( 'user_email' => '[email protected]' ) );
416
		$low_id = $this->factory->user->create( array( 'user_email' => '[email protected]' ) );
417
418
		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
419
		$request->set_param( 'orderby', 'email' );
420
		$request->set_param( 'order', 'desc' );
421
		$request->set_param( 'per_page', 1 );
422
		$request->set_param( 'include', array( $low_id, $high_id ) );
423
		$response = $this->server->dispatch( $request );
424
		$data = $response->get_data();
425
		$this->assertEquals( $high_id, $data[0]['id'] );
426
427
		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
428
		$request->set_param( 'orderby', 'email' );
429
		$request->set_param( 'order', 'asc' );
430
		$request->set_param( 'per_page', 1 );
431
		$request->set_param( 'include', array( $low_id, $high_id ) );
432
		$response = $this->server->dispatch( $request );
433
		$data = $response->get_data();
434
		$this->assertEquals( $low_id, $data[0]['id'] );
435
	}
436
437
	public function test_get_items_orderby_email_unauthenticated() {
438
		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
439
		$request->set_param( 'orderby', 'email' );
440
		$request->set_param( 'order', 'desc' );
441
		$response = $this->server->dispatch( $request );
442
		$this->assertErrorResponse( 'rest_forbidden_orderby', $response, 401 );
443
	}
444
445
	public function test_get_items_orderby_registered_date_unauthenticated() {
446
		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
447
		$request->set_param( 'orderby', 'registered_date' );
448
		$request->set_param( 'order', 'desc' );
449
		$response = $this->server->dispatch( $request );
450
		$this->assertErrorResponse( 'rest_forbidden_orderby', $response, 401 );
451
	}
452
453
	public function test_get_items_invalid_order() {
454
		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
455
		$request->set_param( 'order', 'asc,id' );
456
		$response = $this->server->dispatch( $request );
457
		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
458
	}
459
460
	public function test_get_items_invalid_orderby() {
461
		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
462
		$request->set_param( 'orderby', 'invalid' );
463
		$response = $this->server->dispatch( $request );
464
		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
465
	}
466
467
	public function test_get_items_offset() {
468
		wp_set_current_user( self::$user );
469
		// 7 users created in wpSetUpBeforeClass(), plus default user.
470
		$this->factory->user->create();
471
		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
472
		$request->set_param( 'offset', 1 );
473
		$response = $this->server->dispatch( $request );
474
		$this->assertCount( 9, $response->get_data() );
475
		// 'offset' works with 'per_page'
476
		$request->set_param( 'per_page', 2 );
477
		$response = $this->server->dispatch( $request );
478
		$this->assertCount( 2, $response->get_data() );
479
		// 'offset' takes priority over 'page'
480
		$request->set_param( 'page', 3 );
481
		$response = $this->server->dispatch( $request );
482
		$this->assertCount( 2, $response->get_data() );
483
		// 'offset' invalid value should error
484
		$request->set_param( 'offset', 'moreplease' );
485
		$response = $this->server->dispatch( $request );
486
		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
487
	}
488
489
	public function test_get_items_include_query() {
490
		wp_set_current_user( self::$user );
491
		$id1 = $this->factory->user->create();
492
		$id2 = $this->factory->user->create();
0 ignored issues
show
Unused Code introduced by
$id2 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
493
		$id3 = $this->factory->user->create();
494
		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
495
		// Orderby=>asc
496
		$request->set_param( 'include', array( $id3, $id1 ) );
497
		$response = $this->server->dispatch( $request );
498
		$data = $response->get_data();
499
		$this->assertEquals( 2, count( $data ) );
500
		$this->assertEquals( $id1, $data[0]['id'] );
501
		// Orderby=>include
502
		$request->set_param( 'orderby', 'include' );
503
		$response = $this->server->dispatch( $request );
504
		$data = $response->get_data();
505
		$this->assertEquals( 2, count( $data ) );
506
		$this->assertEquals( $id3, $data[0]['id'] );
507
		// Invalid include should fail
508
		$request->set_param( 'include', 'invalid' );
509
		$response = $this->server->dispatch( $request );
510
		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
511
		// No privileges
512
		$request->set_param( 'include', array( $id3, $id1 ) );
513
		wp_set_current_user( 0 );
514
		$response = $this->server->dispatch( $request );
515
		$data = $response->get_data();
516
		$this->assertEquals( 0, count( $data ) );
517
518
	}
519
520
	public function test_get_items_exclude_query() {
521
		wp_set_current_user( self::$user );
522
		$id1 = $this->factory->user->create();
523
		$id2 = $this->factory->user->create();
524
		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
525
		$request->set_param( 'per_page', 20 ); // there are >10 users at this point
526
		$response = $this->server->dispatch( $request );
527
		$data = $response->get_data();
528
		$this->assertTrue( in_array( $id1, wp_list_pluck( $data, 'id' ), true ) );
529
		$this->assertTrue( in_array( $id2, wp_list_pluck( $data, 'id' ), true ) );
530
		$request->set_param( 'exclude', array( $id2 ) );
531
		$response = $this->server->dispatch( $request );
532
		$data = $response->get_data();
533
		$this->assertTrue( in_array( $id1, wp_list_pluck( $data, 'id' ), true ) );
534
		$this->assertFalse( in_array( $id2, wp_list_pluck( $data, 'id' ), true ) );
535
		// Invalid exlude value should error.
536
		$request->set_param( 'exclude', 'none-of-those-please' );
537
		$response = $this->server->dispatch( $request );
538
		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
539
	}
540
541
	public function test_get_items_search() {
542
		wp_set_current_user( self::$user );
543
		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
544
		$request->set_param( 'search', 'yololololo' );
545
		$response = $this->server->dispatch( $request );
546
		$this->assertEquals( 0, count( $response->get_data() ) );
547
		$yolo_id = $this->factory->user->create( array( 'display_name' => 'yololololo' ) );
548
		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
549
		$request->set_param( 'search', (string) $yolo_id );
550
		$response = $this->server->dispatch( $request );
551
		$this->assertEquals( 1, count( $response->get_data() ) );
552
		// default to wildcard search
553
		$adam_id = $this->factory->user->create( array(
554
			'role'          => 'author',
555
			'user_nicename' => 'adam',
556
		) );
557
		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
558
		$request->set_param( 'search', 'ada' );
559
		$response = $this->server->dispatch( $request );
560
		$data = $response->get_data();
561
		$this->assertEquals( 1, count( $data ) );
562
		$this->assertEquals( $adam_id, $data[0]['id'] );
563
	}
564
565
	public function test_get_items_slug_query() {
566
		wp_set_current_user( self::$user );
567
		$this->factory->user->create( array( 'display_name' => 'foo', 'user_login' => 'bar' ) );
568
		$id2 = $this->factory->user->create( array( 'display_name' => 'Moo', 'user_login' => 'foo' ) );
569
		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
570
		$request->set_param( 'slug', 'foo' );
571
		$response = $this->server->dispatch( $request );
572
		$data = $response->get_data();
573
		$this->assertEquals( 1, count( $data ) );
574
		$this->assertEquals( $id2, $data[0]['id'] );
575
	}
576
577
	public function test_get_items_slug_array_query() {
578
		wp_set_current_user( self::$user );
579
		$id1 = $this->factory->user->create( array(
0 ignored issues
show
Unused Code introduced by
$id1 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
580
			'display_name' => 'Taco',
581
			'user_login'   => 'taco'
582
		) );
583
		$id2 = $this->factory->user->create( array(
0 ignored issues
show
Unused Code introduced by
$id2 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
584
			'display_name' => 'Enchilada',
585
			'user_login'   => 'enchilada'
586
		) );
587
		$id3 = $this->factory->user->create( array(
0 ignored issues
show
Unused Code introduced by
$id3 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
588
			'display_name' => 'Burrito',
589
			'user_login'   => 'burrito'
590
		) );
591
		$this->factory->user->create( array(
592
			'display_name' => 'Hon Pizza',
593
			'user_login'   => 'pizza'
594
		) );
595
		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
596
		$request->set_param( 'slug', array(
597
			'taco',
598
			'burrito',
599
			'enchilada',
600
		) );
601
		$request->set_param( 'orderby', 'slug' );
602
		$request->set_param( 'order', 'asc' );
603
		$response = $this->server->dispatch( $request );
604
		$this->assertEquals( 200, $response->get_status() );
605
		$data = $response->get_data();
606
		$slugs = wp_list_pluck( $data, 'slug' );
607
		$this->assertEquals( array( 'burrito', 'enchilada', 'taco' ), $slugs );
608
	}
609
610
	public function test_get_items_slug_csv_query() {
611
		wp_set_current_user( self::$user );
612
		$id1 = $this->factory->user->create( array(
0 ignored issues
show
Unused Code introduced by
$id1 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
613
			'display_name' => 'Taco',
614
			'user_login'   => 'taco'
615
		) );
616
		$id2 = $this->factory->user->create( array(
0 ignored issues
show
Unused Code introduced by
$id2 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
617
			'display_name' => 'Enchilada',
618
			'user_login'   => 'enchilada'
619
		) );
620
		$id3 = $this->factory->user->create( array(
0 ignored issues
show
Unused Code introduced by
$id3 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
621
			'display_name' => 'Burrito',
622
			'user_login'   => 'burrito'
623
		) );
624
		$this->factory->user->create( array(
625
			'display_name' => 'Hon Pizza',
626
			'user_login'   => 'pizza'
627
		) );
628
		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
629
		$request->set_param( 'slug', 'taco,burrito , enchilada');
630
		$request->set_param( 'orderby', 'slug' );
631
		$request->set_param( 'order', 'desc' );
632
		$response = $this->server->dispatch( $request );
633
		$this->assertEquals( 200, $response->get_status() );
634
		$data = $response->get_data();
635
		$slugs = wp_list_pluck( $data, 'slug' );
636
		$this->assertEquals( array( 'taco', 'enchilada', 'burrito' ), $slugs );
637
	}
638
639
	// Note: Do not test using editor role as there is an editor role created in testing and it makes it hard to test this functionality.
640
	public function test_get_items_roles() {
641
		wp_set_current_user( self::$user );
642
		$tango = $this->factory->user->create( array( 'display_name' => 'tango', 'role' => 'subscriber' ) );
643
		$yolo  = $this->factory->user->create( array( 'display_name' => 'yolo', 'role' => 'author' ) );
644
		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
645
		$request->set_param( 'roles', 'author,subscriber' );
646
		$response = $this->server->dispatch( $request );
647
		$data = $response->get_data();
648
		$this->assertEquals( 2, count( $data ) );
649
		$this->assertEquals( $tango, $data[0]['id'] );
650
		$this->assertEquals( $yolo, $data[1]['id'] );
651
		$request->set_param( 'roles', 'author' );
652
		$response = $this->server->dispatch( $request );
653
		$data = $response->get_data();
654
		$this->assertEquals( 1, count( $data ) );
655
		$this->assertEquals( $yolo, $data[0]['id'] );
656
		wp_set_current_user( 0 );
657
		$request->set_param( 'roles', 'author' );
658
		$response = $this->server->dispatch( $request );
659
		$this->assertErrorResponse( 'rest_user_cannot_view', $response, 401 );
660
		wp_set_current_user( self::$editor );
661
		$request->set_param( 'roles', 'author' );
662
		$response = $this->server->dispatch( $request );
663
		$this->assertErrorResponse( 'rest_user_cannot_view', $response, 403 );
664
	}
665
666
	public function test_get_items_invalid_roles() {
667
		wp_set_current_user( self::$user );
668
		$lolz = $this->factory->user->create( array( 'display_name' => 'lolz', 'role' => 'author' ) );
669
		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
670
		$request->set_param( 'roles', 'ilovesteak,author' );
671
		$response = $this->server->dispatch( $request );
672
		$data = $response->get_data();
673
		$this->assertEquals( 1, count( $data ) );
674
		$this->assertEquals( $lolz, $data[0]['id'] );
675
		$request = new WP_REST_Request( 'GET', '/wp/v2/users' );
676
		$request->set_param( 'roles', 'steakisgood' );
677
		$response = $this->server->dispatch( $request );
678
		$data = $response->get_data();
679
		$this->assertEquals( 0, count( $data ) );
680
		$this->assertEquals( array(), $data );
681
	}
682
683
	public function test_get_item() {
684
		$user_id = $this->factory->user->create();
685
		wp_set_current_user( self::$user );
686
687
		$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', $user_id ) );
688
689
		$response = $this->server->dispatch( $request );
690
		$this->check_get_user_response( $response, 'embed' );
691
	}
692
693
	public function test_prepare_item() {
694
		wp_set_current_user( self::$user );
695
		$request = new WP_REST_Request;
696
		$request->set_param( 'context', 'edit' );
697
		$user = get_user_by( 'id', get_current_user_id() );
698
		$data = $this->endpoint->prepare_item_for_response( $user, $request );
699
		$this->check_get_user_response( $data, 'edit' );
700
	}
701
702
	public function test_get_user_avatar_urls() {
703
		wp_set_current_user( self::$user );
704
705
		$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', self::$editor ) );
706
707
		$response = $this->server->dispatch( $request );
708
709
		$data = $response->get_data();
710
		$this->assertArrayHasKey( 24,  $data['avatar_urls'] );
711
		$this->assertArrayHasKey( 48,  $data['avatar_urls'] );
712
		$this->assertArrayHasKey( 96,  $data['avatar_urls'] );
713
714
		$user = get_user_by( 'id', self::$editor );
715
		/**
716
		 * Ignore the subdomain, since 'get_avatar_url randomly sets the Gravatar
717
		 * server when building the url string.
718
		 */
719
		$this->assertEquals( substr( get_avatar_url( $user->user_email ), 9 ), substr( $data['avatar_urls'][96], 9 ) );
720
	}
721
722
	public function test_get_user_invalid_id() {
723
		wp_set_current_user( self::$user );
724
		$request = new WP_REST_Request( 'GET', '/wp/v2/users/100' );
725
		$response = $this->server->dispatch( $request );
726
727
		$this->assertErrorResponse( 'rest_user_invalid_id', $response, 404 );
728
	}
729
730
	public function test_get_user_empty_capabilities() {
731
		wp_set_current_user( self::$user );
732
		$this->allow_user_to_manage_multisite();
733
734
		$lolz = $this->factory->user->create( array( 'display_name' => 'lolz', 'roles' => '' ) );
735
		delete_user_option( $lolz, 'capabilities' );
736
		delete_user_option( $lolz, 'user_level' );
737
		$request = new WP_REST_Request( 'GET', '/wp/v2/users/' . $lolz );
738
		$request->set_param( 'context', 'edit' );
739
		$response = $this->server->dispatch( $request );
740
741
		if ( is_multisite() ) {
742
			$this->assertErrorResponse( 'rest_user_invalid_id', $response, 404 );
743
		} else {
744
			$data = $response->get_data();
745
746
			$this->assertEquals( $data['capabilities'], new stdClass() );
747
			$this->assertEquals( $data['extra_capabilities'], new stdClass() );
748
		}
749
	}
750
751
	public function test_cannot_get_item_without_permission() {
752
		wp_set_current_user( self::$editor );
753
		$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', self::$user ) );
754
		$response = $this->server->dispatch( $request );
755
		$this->assertErrorResponse( 'rest_user_cannot_view', $response, 403 );
756
	}
757
758
	public function test_can_get_item_author_of_rest_true_public_true_unauthenticated() {
759
		$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', self::$authors['r_true_p_true'] ) );
760
		$response = $this->server->dispatch( $request );
761
		$this->assertEquals( 200, $response->get_status() );
762
	}
763
764
	public function test_can_get_item_author_of_rest_true_public_true_authenticated() {
765
		wp_set_current_user( self::$editor );
766
		$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', self::$authors['r_true_p_true'] ) );
767
		$response = $this->server->dispatch( $request );
768
		$this->assertEquals( 200, $response->get_status() );
769
	}
770
771
	public function test_can_get_item_author_of_rest_true_public_false() {
772
		$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', self::$authors['r_true_p_false'] ) );
773
		$response = $this->server->dispatch( $request );
774
		$this->assertEquals( 200, $response->get_status() );
775
	}
776
777
	public function test_cannot_get_item_author_of_rest_false_public_true_unauthenticated() {
778
		$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', self::$authors['r_false_p_true'] ) );
779
		$response = $this->server->dispatch( $request );
780
		$this->assertErrorResponse( 'rest_user_cannot_view', $response, 401 );
781
	}
782
783
	public function test_cannot_get_item_author_of_rest_false_public_true_without_permission() {
784
		wp_set_current_user( self::$editor );
785
		$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', self::$authors['r_false_p_true'] ) );
786
		$response = $this->server->dispatch( $request );
787
		$this->assertErrorResponse( 'rest_user_cannot_view', $response, 403 );
788
	}
789
790
	public function test_cannot_get_item_author_of_rest_false_public_false() {
791
		$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', self::$authors['r_false_p_false'] ) );
792
		$response = $this->server->dispatch( $request );
793
		$this->assertErrorResponse( 'rest_user_cannot_view', $response, 401 );
794
	}
795
796
	public function test_can_get_item_author_of_post() {
797
		$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', self::$editor ) );
798
		$response = $this->server->dispatch( $request );
799
		$this->assertEquals( 200, $response->get_status() );
800
	}
801
802
	public function test_cannot_get_item_author_of_draft() {
803
		$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', self::$draft_editor ) );
804
		$response = $this->server->dispatch( $request );
805
		$this->assertErrorResponse( 'rest_user_cannot_view', $response, 401 );
806
	}
807
808
	public function test_get_item_published_author_post() {
809
		$this->author_id = $this->factory->user->create( array(
810
			'role' => 'author',
811
		) );
812
		$this->post_id = $this->factory->post->create( array(
813
			'post_author' => $this->author_id,
814
		));
815
		wp_set_current_user( 0 );
816
		$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', $this->author_id ) );
817
		$response = $this->server->dispatch( $request );
818
		$this->check_get_user_response( $response, 'embed' );
819
	}
820
821
	public function test_get_item_published_author_pages() {
822
		$this->author_id = $this->factory->user->create( array(
823
			'role' => 'author',
824
		) );
825
		wp_set_current_user( 0 );
826
		$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', $this->author_id ) );
827
		$response = $this->server->dispatch( $request );
828
		$this->assertEquals( 401, $response->get_status() );
829
		$this->post_id = $this->factory->post->create( array(
830
			'post_author' => $this->author_id,
831
			'post_type'   => 'page',
832
		));
833
		$response = $this->server->dispatch( $request );
834
		$this->check_get_user_response( $response, 'embed' );
835
	}
836
837
	public function test_get_user_with_edit_context() {
838
		$user_id = $this->factory->user->create();
839
		$this->allow_user_to_manage_multisite();
840
841
		$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', $user_id ) );
842
		$request->set_param( 'context', 'edit' );
843
844
		$response = $this->server->dispatch( $request );
845
		$this->check_get_user_response( $response, 'edit' );
846
	}
847
848
	public function test_get_item_published_author_wrong_context() {
849
		$this->author_id = $this->factory->user->create( array(
850
			'role' => 'author',
851
		) );
852
		$this->post_id = $this->factory->post->create( array(
853
			'post_author' => $this->author_id,
854
		));
855
		wp_set_current_user( 0 );
856
		$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', $this->author_id ) );
857
		$request->set_param( 'context', 'edit' );
858
		$response = $this->server->dispatch( $request );
859
		$this->assertErrorResponse( 'rest_user_cannot_view', $response, 401 );
860
	}
861
862
	public function test_get_current_user() {
863
		wp_set_current_user( self::$user );
864
865
		$request = new WP_REST_Request( 'GET', '/wp/v2/users/me' );
866
867
		$response = $this->server->dispatch( $request );
868
		$this->assertEquals( 200, $response->get_status() );
869
		$this->check_get_user_response( $response, 'view' );
870
871
		$headers = $response->get_headers();
872
		$this->assertArrayNotHasKey( 'Location', $headers );
873
874
		$links = $response->get_links();
875
		$this->assertEquals( rest_url( 'wp/v2/users/' . self::$user ), $links['self'][0]['href'] );
876
	}
877
878
	public function test_get_current_user_without_permission() {
879
		wp_set_current_user( 0 );
880
		$request = new WP_REST_Request( 'GET', '/wp/v2/users/me' );
881
		$response = $this->server->dispatch( $request );
882
883
		$this->assertErrorResponse( 'rest_not_logged_in', $response, 401 );
884
	}
885
886
	public function test_create_item() {
887
		$this->allow_user_to_manage_multisite();
888
		wp_set_current_user( self::$user );
889
890
		$params = array(
891
			'username'    => 'testuser',
892
			'password'    => 'testpassword',
893
			'email'       => '[email protected]',
894
			'name'        => 'Test User',
895
			'nickname'    => 'testuser',
896
			'slug'        => 'test-user',
897
			'roles'       => array( 'editor' ),
898
			'description' => 'New API User',
899
			'url'         => 'http://example.com',
900
		);
901
902
		$request = new WP_REST_Request( 'POST', '/wp/v2/users' );
903
		$request->add_header( 'content-type', 'application/x-www-form-urlencoded' );
904
		$request->set_body_params( $params );
905
906
		$response = $this->server->dispatch( $request );
907
		$data = $response->get_data();
908
		$this->assertEquals( 'http://example.com', $data['url'] );
909
		$this->assertEquals( array( 'editor' ), $data['roles'] );
910
		$this->check_add_edit_user_response( $response );
911
	}
912
913
	public function test_create_item_invalid_username() {
914
		$this->allow_user_to_manage_multisite();
915
		wp_set_current_user( self::$user );
916
917
		$params = array(
918
			'username'    => '¯\_(ツ)_/¯',
919
			'password'    => 'testpassword',
920
			'email'       => '[email protected]',
921
			'name'        => 'Test User',
922
			'nickname'    => 'testuser',
923
			'slug'        => 'test-user',
924
			'roles'       => array( 'editor' ),
925
			'description' => 'New API User',
926
			'url'         => 'http://example.com',
927
		);
928
929
		// Username rules are different (more strict) for multisite; see `wpmu_validate_user_signup`
930
		if ( is_multisite() ) {
931
			$params['username'] = 'no-dashes-allowed';
932
		}
933
934
		$request = new WP_REST_Request( 'POST', '/wp/v2/users' );
935
		$request->add_header( 'content-type', 'application/x-www-form-urlencoded' );
936
		$request->set_body_params( $params );
937
938
		$response = $this->server->dispatch( $request );
939
		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
940
941
		$data = $response->get_data();
942
		if ( is_multisite() ) {
943
			$this->assertInternalType( 'array', $data['additional_errors'] );
944
			$this->assertCount( 1, $data['additional_errors'] );
945
			$error = $data['additional_errors'][0];
946
			$this->assertEquals( 'user_name', $error['code'] );
947
			$this->assertEquals( 'Usernames can only contain lowercase letters (a-z) and numbers.', $error['message'] );
948
		} else {
949
			$this->assertInternalType( 'array', $data['data']['params'] );
950
			$errors = $data['data']['params'];
951
			$this->assertInternalType( 'string', $errors['username'] );
952
			$this->assertEquals( 'Username contains invalid characters.', $errors['username'] );
953
		}
954
	}
955
956
	function get_illegal_user_logins() {
957
		return array( 'nope' );
958
	}
959
960
	public function test_create_item_illegal_username() {
961
		$this->allow_user_to_manage_multisite();
962
		wp_set_current_user( self::$user );
963
964
		add_filter( 'illegal_user_logins', array( $this, 'get_illegal_user_logins' ) );
965
966
		$params = array(
967
			'username'    => 'nope',
968
			'password'    => 'testpassword',
969
			'email'       => '[email protected]',
970
			'name'        => 'Test User',
971
			'nickname'    => 'testuser',
972
			'slug'        => 'test-user',
973
			'roles'       => array( 'editor' ),
974
			'description' => 'New API User',
975
			'url'         => 'http://example.com',
976
		);
977
978
		$request = new WP_REST_Request( 'POST', '/wp/v2/users' );
979
		$request->add_header( 'content-type', 'application/x-www-form-urlencoded' );
980
		$request->set_body_params( $params );
981
982
		$response = $this->server->dispatch( $request );
983
984
		remove_filter( 'illegal_user_logins', array( $this, 'get_illegal_user_logins' ) );
985
986
		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
987
988
		$data = $response->get_data();
989
		$this->assertInternalType( 'array', $data['data']['params'] );
990
		$errors = $data['data']['params'];
991
		$this->assertInternalType( 'string', $errors['username'] );
992
		$this->assertEquals( 'Sorry, that username is not allowed.', $errors['username'] );
993
	}
994
995
	/**
996
	 * @group ms-required
997
	 */
998
	public function test_create_new_network_user_on_site_does_not_add_user_to_sub_site() {
999
		$this->allow_user_to_manage_multisite();
1000
1001
		$params = array(
1002
			'username' => 'testuser123',
1003
			'password' => 'testpassword',
1004
			'email'    => '[email protected]',
1005
			'name'     => 'Test User 123',
1006
			'roles'    => array( 'editor' ),
1007
		);
1008
1009
		$request = new WP_REST_Request( 'POST', '/wp/v2/users' );
1010
		$request->add_header( 'content-type', 'application/x-www-form-urlencoded' );
1011
		$request->set_body_params( $params );
1012
		$response = $this->server->dispatch( $request );
1013
		$data = $response->get_data();
1014
		$user_id = $data['id'];
1015
1016
		$user_is_member = is_user_member_of_blog( $user_id, self::$site );
1017
1018
		wpmu_delete_user( $user_id );
1019
1020
		$this->assertFalse( $user_is_member );
1021
	}
1022
1023
	/**
1024
	 * @group ms-required
1025
	 */
1026
	public function test_create_new_network_user_on_sub_site_adds_user_to_site() {
1027
		$this->allow_user_to_manage_multisite();
1028
1029
		$params = array(
1030
			'username' => 'testuser123',
1031
			'password' => 'testpassword',
1032
			'email'    => '[email protected]',
1033
			'name'     => 'Test User 123',
1034
			'roles'    => array( 'editor' ),
1035
		);
1036
1037
		switch_to_blog( self::$site );
1038
1039
		$request = new WP_REST_Request( 'POST', '/wp/v2/users' );
1040
		$request->add_header( 'content-type', 'application/x-www-form-urlencoded' );
1041
		$request->set_body_params( $params );
1042
		$response = $this->server->dispatch( $request );
1043
		$data = $response->get_data();
1044
		$user_id = $data['id'];
1045
1046
		restore_current_blog();
1047
1048
		$user_is_member = is_user_member_of_blog( $user_id, self::$site );
1049
1050
		wpmu_delete_user( $user_id );
1051
1052
		$this->assertTrue( $user_is_member );
1053
	}
1054
1055
	/**
1056
	 * @group ms-required
1057
	 */
1058
	public function test_create_existing_network_user_on_sub_site_has_error() {
1059
		$this->allow_user_to_manage_multisite();
1060
1061
		$params = array(
1062
			'username' => 'testuser123',
1063
			'password' => 'testpassword',
1064
			'email'    => '[email protected]',
1065
			'name'     => 'Test User 123',
1066
			'roles'    => array( 'editor' ),
1067
		);
1068
1069
		$request = new WP_REST_Request( 'POST', '/wp/v2/users' );
1070
		$request->add_header( 'content-type', 'application/x-www-form-urlencoded' );
1071
		$request->set_body_params( $params );
1072
		$response = $this->server->dispatch( $request );
1073
		$data = $response->get_data();
1074
		$user_id = $data['id'];
1075
1076
		switch_to_blog( self::$site );
1077
1078
		$request = new WP_REST_Request( 'POST', '/wp/v2/users' );
1079
		$request->add_header( 'content-type', 'application/x-www-form-urlencoded' );
1080
		$request->set_body_params( $params );
1081
		$switched_response = $this->server->dispatch( $request );
1082
1083
		restore_current_blog();
1084
1085
		wpmu_delete_user( $user_id );
1086
1087
		$this->assertErrorResponse( 'rest_invalid_param', $switched_response, 400 );
1088
		$data = $switched_response->get_data();
1089
		$this->assertInternalType( 'array', $data['additional_errors'] );
1090
		$this->assertCount( 2, $data['additional_errors'] );
1091
		$errors = $data['additional_errors'];
1092
		foreach ( $errors as $error ) {
1093
			// Check the code matches one we know.
1094
			$this->assertContains( $error['code'], array( 'user_name', 'user_email' ) );
1095
			if ( 'user_name' === $error['code'] ) {
1096
				$this->assertEquals( 'Sorry, that username already exists!', $error['message'] );
1097
			} else {
1098
				$this->assertEquals( 'Sorry, that email address is already used!', $error['message'] );
1099
			}
1100
		}
1101
	}
1102
1103
	public function test_json_create_user() {
1104
		$this->allow_user_to_manage_multisite();
1105
		wp_set_current_user( self::$user );
1106
1107
		$params = array(
1108
			'username' => 'testjsonuser',
1109
			'password' => 'testjsonpassword',
1110
			'email'    => '[email protected]',
1111
		);
1112
1113
		$request = new WP_REST_Request( 'POST', '/wp/v2/users' );
1114
		$request->add_header( 'content-type', 'application/json' );
1115
		$request->set_body( wp_json_encode( $params ) );
0 ignored issues
show
Security Bug introduced by
It seems like wp_json_encode($params) targeting wp_json_encode() can also be of type false; however, WP_REST_Request::set_body() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
1116
1117
		$response = $this->server->dispatch( $request );
1118
		$this->check_add_edit_user_response( $response );
1119
	}
1120
1121
	public function test_create_user_without_permission() {
1122
		wp_set_current_user( self::$editor );
1123
1124
		$params = array(
1125
			'username' => 'homersimpson',
1126
			'password' => 'stupidsexyflanders',
1127
			'email'    => '[email protected]',
1128
		);
1129
1130
		$request = new WP_REST_Request( 'POST', '/wp/v2/users' );
1131
		$request->add_header( 'content-type', 'application/x-www-form-urlencoded' );
1132
		$request->set_body_params( $params );
1133
		$response = $this->server->dispatch( $request );
1134
1135
		$this->assertErrorResponse( 'rest_cannot_create_user', $response, 403 );
1136
	}
1137
1138
	public function test_create_user_invalid_id() {
1139
		$this->allow_user_to_manage_multisite();
1140
		wp_set_current_user( self::$user );
1141
1142
		$params = array(
1143
			'id'       => '156',
1144
			'username' => 'lisasimpson',
1145
			'password' => 'DavidHasselhoff',
1146
			'email'    => '[email protected]',
1147
		);
1148
1149
		$request = new WP_REST_Request( 'POST', '/wp/v2/users' );
1150
		$request->add_header( 'content-type', 'application/x-www-form-urlencoded' );
1151
		$request->set_body_params( $params );
1152
		$response = $this->server->dispatch( $request );
1153
1154
		$this->assertErrorResponse( 'rest_user_exists', $response, 400 );
1155
	}
1156
1157
	public function test_create_user_invalid_email() {
1158
		$this->allow_user_to_manage_multisite();
1159
		wp_set_current_user( self::$user );
1160
1161
		$params = array(
1162
			'username' => 'lisasimpson',
1163
			'password' => 'DavidHasselhoff',
1164
			'email'    => 'something',
1165
		);
1166
1167
		$request = new WP_REST_Request( 'POST', '/wp/v2/users' );
1168
		$request->add_header( 'content-type', 'application/x-www-form-urlencoded' );
1169
		$request->set_body_params( $params );
1170
		$response = $this->server->dispatch( $request );
1171
1172
		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
1173
	}
1174
1175
	public function test_create_user_invalid_role() {
1176
		$this->allow_user_to_manage_multisite();
1177
		wp_set_current_user( self::$user );
1178
1179
		$params = array(
1180
			'username' => 'maggiesimpson',
1181
			'password' => 'i_shot_mrburns',
1182
			'email'    => '[email protected]',
1183
			'roles'    => array( 'baby' ),
1184
		);
1185
1186
		$request = new WP_REST_Request( 'POST', '/wp/v2/users' );
1187
		$request->add_header( 'content-type', 'application/x-www-form-urlencoded' );
1188
		$request->set_body_params( $params );
1189
		$response = $this->server->dispatch( $request );
1190
1191
		$this->assertErrorResponse( 'rest_user_invalid_role', $response, 400 );
1192
	}
1193
1194
	public function test_update_item() {
1195
		$user_id = $this->factory->user->create( array(
1196
			'user_email' => '[email protected]',
1197
			'user_pass' => 'sjflsfls',
1198
			'user_login' => 'test_update',
1199
			'first_name' => 'Old Name',
1200
			'user_url' => 'http://apple.com',
1201
			'locale' => 'en_US',
1202
		));
1203
		$this->allow_user_to_manage_multisite();
1204
		wp_set_current_user( self::$user );
1205
1206
		$userdata = get_userdata( $user_id );
1207
		$pw_before = $userdata->user_pass;
1208
1209
		$_POST['email'] = $userdata->user_email;
1210
		$_POST['username'] = $userdata->user_login;
1211
		$_POST['first_name'] = 'New Name';
1212
		$_POST['url'] = 'http://google.com';
1213
		$_POST['locale'] = 'de_DE';
1214
1215
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d', $user_id ) );
1216
		$request->add_header( 'content-type', 'application/x-www-form-urlencoded' );
1217
		$request->set_body_params( $_POST );
1218
1219
		$response = $this->server->dispatch( $request );
1220
		$this->check_add_edit_user_response( $response, true );
1221
1222
		// Check that the name has been updated correctly
1223
		$new_data = $response->get_data();
1224
		$this->assertEquals( 'New Name', $new_data['first_name'] );
1225
		$user = get_userdata( $user_id );
1226
		$this->assertEquals( 'New Name', $user->first_name );
1227
1228
		$this->assertEquals( 'http://google.com', $new_data['url'] );
1229
		$this->assertEquals( 'http://google.com', $user->user_url );
1230
		$this->assertEquals( 'de_DE', $user->locale );
1231
1232
		// Check that we haven't inadvertently changed the user's password,
1233
		// as per https://core.trac.wordpress.org/ticket/21429
1234
		$this->assertEquals( $pw_before, $user->user_pass );
1235
	}
1236
1237
	public function test_update_item_no_change() {
1238
		$this->allow_user_to_manage_multisite();
1239
		wp_set_current_user( self::$user );
1240
		$user = get_userdata( self::$editor );
1241
1242
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d', self::$editor ) );
1243
		$request->set_param( 'slug', $user->user_nicename );
1244
1245
		// Run twice to make sure that the update still succeeds even if no DB
1246
		// rows are updated.
1247
		$response = $this->server->dispatch( $request );
1248
		$this->assertEquals( 200, $response->get_status() );
1249
1250
		$response = $this->server->dispatch( $request );
1251
		$this->assertEquals( 200, $response->get_status() );
1252
	}
1253
1254
	public function test_update_item_existing_email() {
1255
		$user1 = $this->factory->user->create( array( 'user_login' => 'test_json_user', 'user_email' => '[email protected]' ) );
0 ignored issues
show
Unused Code introduced by
$user1 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1256
		$user2 = $this->factory->user->create( array( 'user_login' => 'test_json_user2', 'user_email' => '[email protected]' ) );
1257
		$this->allow_user_to_manage_multisite();
1258
		wp_set_current_user( self::$user );
1259
1260
		$request = new WP_REST_Request( 'PUT', '/wp/v2/users/' . $user2 );
1261
		$request->set_param( 'email', '[email protected]' );
1262
		$response = $this->server->dispatch( $request );
1263
		$this->assertInstanceOf( 'WP_Error', $response->as_error() );
1264
		$this->assertEquals( 'rest_user_invalid_email', $response->as_error()->get_error_code() );
1265
	}
1266
1267
	public function test_update_item_invalid_locale() {
1268
		$user1 = $this->factory->user->create( array( 'user_login' => 'test_json_user', 'user_email' => '[email protected]' ) );
1269
		$this->allow_user_to_manage_multisite();
1270
		wp_set_current_user( self::$user );
1271
1272
		$request = new WP_REST_Request( 'PUT', '/wp/v2/users/' . $user1 );
1273
		$request->set_param( 'locale', 'klingon' );
1274
		$response = $this->server->dispatch( $request );
1275
		$this->assertInstanceOf( 'WP_Error', $response->as_error() );
1276
		$this->assertEquals( 'rest_invalid_param', $response->as_error()->get_error_code() );
1277
	}
1278
1279
	public function test_update_item_en_US_locale() {
1280
		$user_id = $this->factory->user->create( array( 'user_login' => 'test_json_user', 'user_email' => '[email protected]' ) );
1281
		$this->allow_user_to_manage_multisite();
1282
		wp_set_current_user( self::$user );
1283
1284
		$request = new WP_REST_Request( 'PUT', '/wp/v2/users/' . $user_id );
1285
		$request->set_param( 'locale', 'en_US' );
1286
		$response = $this->server->dispatch( $request );
1287
		$this->check_add_edit_user_response( $response, true );
1288
1289
		$user = get_userdata( $user_id );
1290
		$this->assertEquals( 'en_US', $user->locale );
1291
	}
1292
1293
	/**
1294
	 * @ticket 38632
1295
	 */
1296
	public function test_update_item_empty_locale() {
1297
		$user_id = $this->factory->user->create( array( 'user_login' => 'test_json_user', 'user_email' => '[email protected]', 'locale' => 'de_DE' ) );
1298
		$this->allow_user_to_manage_multisite();
1299
		wp_set_current_user( self::$user );
1300
1301
		$request = new WP_REST_Request( 'PUT', '/wp/v2/users/' . $user_id );
1302
		$request->set_param( 'locale', '' );
1303
		$response = $this->server->dispatch( $request );
1304
		$this->check_add_edit_user_response( $response, true );
1305
1306
		$data = $response->get_data();
1307
		$this->assertEquals( get_locale(), $data['locale'] );
1308
		$user = get_userdata( $user_id );
1309
		$this->assertEquals( '', $user->locale );
1310
	}
1311
1312
	public function test_update_item_username_attempt() {
1313
		$user1 = $this->factory->user->create( array( 'user_login' => 'test_json_user', 'user_email' => '[email protected]' ) );
0 ignored issues
show
Unused Code introduced by
$user1 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1314
		$user2 = $this->factory->user->create( array( 'user_login' => 'test_json_user2', 'user_email' => '[email protected]' ) );
1315
		$this->allow_user_to_manage_multisite();
1316
		wp_set_current_user( self::$user );
1317
1318
		$request = new WP_REST_Request( 'PUT', '/wp/v2/users/' . $user2 );
1319
		$request->set_param( 'username', 'test_json_user' );
1320
		$response = $this->server->dispatch( $request );
1321
		$this->assertInstanceOf( 'WP_Error', $response->as_error() );
1322
		$this->assertEquals( 'rest_user_invalid_argument', $response->as_error()->get_error_code() );
1323
	}
1324
1325
	public function test_update_item_existing_nicename() {
1326
		$user1 = $this->factory->user->create( array( 'user_login' => 'test_json_user', 'user_email' => '[email protected]' ) );
0 ignored issues
show
Unused Code introduced by
$user1 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1327
		$user2 = $this->factory->user->create( array( 'user_login' => 'test_json_user2', 'user_email' => '[email protected]' ) );
1328
		$this->allow_user_to_manage_multisite();
1329
		wp_set_current_user( self::$user );
1330
1331
		$request = new WP_REST_Request( 'PUT', '/wp/v2/users/' . $user2 );
1332
		$request->set_param( 'slug', 'test_json_user' );
1333
		$response = $this->server->dispatch( $request );
1334
		$this->assertInstanceOf( 'WP_Error', $response->as_error() );
1335
		$this->assertEquals( 'rest_user_invalid_slug', $response->as_error()->get_error_code() );
1336
	}
1337
1338
	public function test_json_update_user() {
1339
		$user_id = $this->factory->user->create( array(
1340
			'user_email' => '[email protected]',
1341
			'user_pass'  => 'sjflsfl3sdjls',
1342
			'user_login' => 'test_json_update',
1343
			'first_name' => 'Old Name',
1344
			'last_name'  => 'Original Last',
1345
		));
1346
		$this->allow_user_to_manage_multisite();
1347
		wp_set_current_user( self::$user );
1348
1349
		$params = array(
1350
			'username'   => 'test_json_update',
1351
			'email'      => '[email protected]',
1352
			'first_name' => 'JSON Name',
1353
			'last_name'  => 'New Last',
1354
		);
1355
1356
		$userdata = get_userdata( $user_id );
1357
		$pw_before = $userdata->user_pass;
1358
1359
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d', $user_id ) );
1360
		$request->add_header( 'content-type', 'application/json' );
1361
		$request->set_body( wp_json_encode( $params ) );
0 ignored issues
show
Security Bug introduced by
It seems like wp_json_encode($params) targeting wp_json_encode() can also be of type false; however, WP_REST_Request::set_body() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
1362
1363
		$response = $this->server->dispatch( $request );
1364
		$this->check_add_edit_user_response( $response, true );
1365
1366
		// Check that the name has been updated correctly
1367
		$new_data = $response->get_data();
1368
		$this->assertEquals( 'JSON Name', $new_data['first_name'] );
1369
		$this->assertEquals( 'New Last', $new_data['last_name'] );
1370
		$user = get_userdata( $user_id );
1371
		$this->assertEquals( 'JSON Name', $user->first_name );
1372
		$this->assertEquals( 'New Last', $user->last_name );
1373
1374
		// Check that we haven't inadvertently changed the user's password,
1375
		// as per https://core.trac.wordpress.org/ticket/21429
1376
		$this->assertEquals( $pw_before, $user->user_pass );
1377
	}
1378
1379
	public function test_update_user_role() {
1380
		$user_id = $this->factory->user->create( array( 'role' => 'administrator' ) );
1381
1382
		wp_set_current_user( self::$user );
1383
		$this->allow_user_to_manage_multisite();
1384
1385
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d', $user_id ) );
1386
		$request->set_param( 'roles', array( 'editor' ) );
1387
		$response = $this->server->dispatch( $request );
1388
1389
		$new_data = $response->get_data();
1390
1391
		$this->assertEquals( 'editor', $new_data['roles'][0] );
1392
		$this->assertNotEquals( 'administrator', $new_data['roles'][0] );
1393
1394
		$user = get_userdata( $user_id );
1395
		$this->assertArrayHasKey( 'editor', $user->caps );
1396
		$this->assertArrayNotHasKey( 'administrator', $user->caps );
1397
	}
1398
1399
	public function test_update_user_multiple_roles() {
1400
		$user_id = $this->factory->user->create( array( 'role' => 'administrator' ) );
1401
1402
		wp_set_current_user( self::$user );
1403
		$this->allow_user_to_manage_multisite();
1404
1405
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d', $user_id ) );
1406
		$request->set_param( 'roles', 'author,editor' );
1407
		$response = $this->server->dispatch( $request );
1408
1409
		$new_data = $response->get_data();
1410
1411
		$this->assertEquals( array( 'author', 'editor' ), $new_data['roles'] );
1412
1413
		$user = get_userdata( $user_id );
1414
		$this->assertArrayHasKey( 'author', $user->caps );
1415
		$this->assertArrayHasKey( 'editor', $user->caps );
1416
		$this->assertArrayNotHasKey( 'administrator', $user->caps );
1417
	}
1418
1419
	public function test_update_user_role_invalid_privilege_escalation() {
1420
		wp_set_current_user( self::$editor );
1421
1422
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d', self::$editor ) );
1423
		$request->set_param( 'roles', array( 'administrator' ) );
1424
		$response = $this->server->dispatch( $request );
1425
1426
		$this->assertErrorResponse( 'rest_cannot_edit_roles', $response, 403 );
1427
		$user = get_userdata( self::$editor );
1428
		$this->assertArrayHasKey( 'editor', $user->caps );
1429
		$this->assertArrayNotHasKey( 'administrator', $user->caps );
1430
1431
		$request = new WP_REST_Request( 'PUT', '/wp/v2/users/me' );
1432
		$request->set_param( 'roles', array( 'administrator' ) );
1433
		$response = $this->server->dispatch( $request );
1434
1435
		$this->assertErrorResponse( 'rest_cannot_edit_roles', $response, 403 );
1436
		$user = get_userdata( self::$editor );
1437
		$this->assertArrayHasKey( 'editor', $user->caps );
1438
		$this->assertArrayNotHasKey( 'administrator', $user->caps );
1439
	}
1440
1441
	/**
1442
	 * @group ms-excluded
1443
	 */
1444
	public function test_update_user_role_invalid_privilege_deescalation() {
1445
		$user_id = $this->factory->user->create( array( 'role' => 'administrator' ) );
1446
1447
		wp_set_current_user( $user_id );
1448
1449
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d', $user_id ) );
1450
		$request->set_param( 'roles', array( 'editor' ) );
1451
		$response = $this->server->dispatch( $request );
1452
1453
		$this->assertErrorResponse( 'rest_user_invalid_role', $response, 403 );
1454
1455
		$user = get_userdata( $user_id );
1456
		$this->assertArrayHasKey( 'administrator', $user->caps );
1457
		$this->assertArrayNotHasKey( 'editor', $user->caps );
1458
1459
		$request = new WP_REST_Request( 'PUT', '/wp/v2/users/me' );
1460
		$request->set_param( 'roles', array( 'editor' ) );
1461
		$response = $this->server->dispatch( $request );
1462
1463
		$this->assertErrorResponse( 'rest_user_invalid_role', $response, 403 );
1464
1465
		$user = get_userdata( $user_id );
1466
		$this->assertArrayHasKey( 'administrator', $user->caps );
1467
		$this->assertArrayNotHasKey( 'editor', $user->caps );
1468
	}
1469
1470
	/**
1471
	 * @group ms-required
1472
	 */
1473
	public function test_update_user_role_privilege_deescalation_multisite() {
1474
		$user_id = $this->factory->user->create( array( 'role' => 'administrator' ) );
1475
1476
		wp_set_current_user( $user_id );
1477
		$user = wp_get_current_user();
1478
		update_site_option( 'site_admins', array( $user->user_login ) );
1479
1480
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d', $user_id ) );
1481
		$request->set_param( 'roles', array( 'editor' ) );
1482
		$response = $this->server->dispatch( $request );
1483
1484
		$new_data = $response->get_data();
1485
		$this->assertEquals( 'editor', $new_data['roles'][0] );
1486
		$this->assertNotEquals( 'administrator', $new_data['roles'][0] );
1487
1488
		$user_id = $this->factory->user->create( array( 'role' => 'administrator' ) );
1489
1490
		wp_set_current_user( $user_id );
1491
		$user = wp_get_current_user();
1492
		update_site_option( 'site_admins', array( $user->user_login ) );
1493
1494
		$request = new WP_REST_Request( 'PUT', '/wp/v2/users/me' );
1495
		$request->set_param( 'roles', array( 'editor' ) );
1496
		$response = $this->server->dispatch( $request );
1497
1498
		$new_data = $response->get_data();
1499
		$this->assertEquals( 'editor', $new_data['roles'][0] );
1500
		$this->assertNotEquals( 'administrator', $new_data['roles'][0] );
1501
	}
1502
1503
1504
	public function test_update_user_role_invalid_role() {
1505
		wp_set_current_user( self::$user );
1506
		$this->allow_user_to_manage_multisite();
1507
1508
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d', self::$editor ) );
1509
		$request->set_param( 'roles', array( 'BeSharp' ) );
1510
		$response = $this->server->dispatch( $request );
1511
1512
		$this->assertErrorResponse( 'rest_user_invalid_role', $response, 400 );
1513
1514
		$user = get_userdata( self::$editor );
1515
		$this->assertArrayHasKey( 'editor', $user->caps );
1516
		$this->assertArrayNotHasKey( 'BeSharp', $user->caps );
1517
1518
		$request = new WP_REST_Request( 'PUT', '/wp/v2/users/me' );
1519
		$request->set_param( 'roles', array( 'BeSharp' ) );
1520
		$response = $this->server->dispatch( $request );
1521
1522
		$this->assertErrorResponse( 'rest_user_invalid_role', $response, 400 );
1523
1524
		$user = get_userdata( self::$editor );
1525
		$this->assertArrayHasKey( 'editor', $user->caps );
1526
		$this->assertArrayNotHasKey( 'BeSharp', $user->caps );
1527
	}
1528
1529
	public function test_update_user_without_permission() {
1530
		wp_set_current_user( self::$editor );
1531
1532
		$params = array(
1533
			'username' => 'homersimpson',
1534
			'password' => 'stupidsexyflanders',
1535
			'email'    => '[email protected]',
1536
		);
1537
1538
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d', self::$user ) );
1539
		$request->add_header( 'content-type', 'application/x-www-form-urlencoded' );
1540
		$request->set_body_params( $params );
1541
		$response = $this->server->dispatch( $request );
1542
1543
		$this->assertErrorResponse( 'rest_cannot_edit', $response, 403 );
1544
1545
		$request = new WP_REST_Request( 'PUT', '/wp/v2/users/me' );
1546
		$request->add_header( 'content-type', 'application/x-www-form-urlencoded' );
1547
		$request->set_body_params( $params );
1548
		$response = $this->server->dispatch( $request );
1549
1550
		$this->assertErrorResponse( 'rest_user_invalid_argument', $response, 400 );
1551
	}
1552
1553
	public function test_update_user_invalid_id() {
1554
		$this->allow_user_to_manage_multisite();
1555
		wp_set_current_user( self::$user );
1556
1557
		$params = array(
1558
			'id'       => '156',
1559
			'username' => 'lisasimpson',
1560
			'password' => 'DavidHasselhoff',
1561
			'email'    => '[email protected]',
1562
		);
1563
1564
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d', self::$editor ) );
1565
		$request->add_header( 'content-type', 'application/x-www-form-urlencoded' );
1566
		$request->set_body_params( $params );
1567
		$response = $this->server->dispatch( $request );
1568
1569
		$this->assertErrorResponse( 'rest_user_invalid_id', $response, 404 );
1570
	}
1571
1572
	public function test_update_item_invalid_password() {
1573
		$this->allow_user_to_manage_multisite();
1574
		wp_set_current_user( self::$user );
1575
1576
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d', self::$editor ) );
1577
1578
		$request->set_param( 'password', 'no\\backslashes\\allowed' );
1579
		$response = $this->server->dispatch( $request );
1580
		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
1581
1582
		$request->set_param( 'password', '' );
1583
		$response = $this->server->dispatch( $request );
1584
		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
1585
	}
1586
1587
	public function verify_user_roundtrip( $input = array(), $expected_output = array() ) {
1588
		if ( isset( $input['id'] ) ) {
1589
			// Existing user; don't try to create one
1590
			$user_id = $input['id'];
1591
		} else {
1592
			// Create a new user
1593
			$request = new WP_REST_Request( 'POST', '/wp/v2/users' );
1594
			foreach ( $input as $name => $value ) {
1595
				$request->set_param( $name, $value );
1596
			}
1597
			$request->set_param( 'email', '[email protected]' );
1598
			$response = $this->server->dispatch( $request );
1599
			$this->assertEquals( 201, $response->get_status() );
1600
			$actual_output = $response->get_data();
1601
1602
			// Compare expected API output to actual API output
1603
			$this->assertEquals( $expected_output['username']   , $actual_output['username'] );
1604
			$this->assertEquals( $expected_output['name']       , $actual_output['name'] );
1605
			$this->assertEquals( $expected_output['first_name'] , $actual_output['first_name'] );
1606
			$this->assertEquals( $expected_output['last_name']  , $actual_output['last_name'] );
1607
			$this->assertEquals( $expected_output['url']        , $actual_output['url'] );
1608
			$this->assertEquals( $expected_output['description'], $actual_output['description'] );
1609
			$this->assertEquals( $expected_output['nickname']   , $actual_output['nickname'] );
1610
1611
			// Compare expected API output to WP internal values
1612
			$user = get_userdata( $actual_output['id'] );
1613
			$this->assertEquals( $expected_output['username']   , $user->user_login );
1614
			$this->assertEquals( $expected_output['name']       , $user->display_name );
1615
			$this->assertEquals( $expected_output['first_name'] , $user->first_name );
1616
			$this->assertEquals( $expected_output['last_name']  , $user->last_name );
1617
			$this->assertEquals( $expected_output['url']        , $user->user_url );
1618
			$this->assertEquals( $expected_output['description'], $user->description );
1619
			$this->assertEquals( $expected_output['nickname']   , $user->nickname );
1620
			$this->assertTrue( wp_check_password( addslashes( $expected_output['password'] ), $user->user_pass ) );
1621
1622
			$user_id = $actual_output['id'];
1623
		}
1624
1625
		// Update the user
1626
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d', $user_id ) );
1627
		foreach ( $input as $name => $value ) {
1628
			if ( 'username' !== $name ) {
1629
				$request->set_param( $name, $value );
1630
			}
1631
		}
1632
		$response = $this->server->dispatch( $request );
1633
		$this->assertEquals( 200, $response->get_status() );
1634
		$actual_output = $response->get_data();
1635
1636
		// Compare expected API output to actual API output
1637
		if ( isset( $expected_output['username'] ) ) {
1638
			$this->assertEquals( $expected_output['username'], $actual_output['username'] );
1639
		}
1640
		$this->assertEquals( $expected_output['name']       , $actual_output['name'] );
1641
		$this->assertEquals( $expected_output['first_name'] , $actual_output['first_name'] );
1642
		$this->assertEquals( $expected_output['last_name']  , $actual_output['last_name'] );
1643
		$this->assertEquals( $expected_output['url']        , $actual_output['url'] );
1644
		$this->assertEquals( $expected_output['description'], $actual_output['description'] );
1645
		$this->assertEquals( $expected_output['nickname']   , $actual_output['nickname'] );
1646
1647
		// Compare expected API output to WP internal values
1648
		$user = get_userdata( $actual_output['id'] );
1649
		if ( isset( $expected_output['username'] ) ) {
1650
			$this->assertEquals( $expected_output['username'], $user->user_login );
1651
		}
1652
		$this->assertEquals( $expected_output['name']       , $user->display_name );
1653
		$this->assertEquals( $expected_output['first_name'] , $user->first_name );
1654
		$this->assertEquals( $expected_output['last_name']  , $user->last_name );
1655
		$this->assertEquals( $expected_output['url']        , $user->user_url );
1656
		$this->assertEquals( $expected_output['description'], $user->description );
1657
		$this->assertEquals( $expected_output['nickname']   , $user->nickname );
1658
		$this->assertTrue( wp_check_password( addslashes( $expected_output['password'] ), $user->user_pass ) );
1659
	}
1660
1661
	public function test_user_roundtrip_as_editor() {
1662
		wp_set_current_user( self::$editor );
1663
		$this->assertEquals( ! is_multisite(), current_user_can( 'unfiltered_html' ) );
1664
		$this->verify_user_roundtrip( array(
1665
			'id'          => self::$editor,
1666
			'name'        => '\o/ ¯\_(ツ)_/¯',
1667
			'first_name'  => '\o/ ¯\_(ツ)_/¯',
1668
			'last_name'   => '\o/ ¯\_(ツ)_/¯',
1669
			'url'         => '\o/ ¯\_(ツ)_/¯',
1670
			'description' => '\o/ ¯\_(ツ)_/¯',
1671
			'nickname'    => '\o/ ¯\_(ツ)_/¯',
1672
			'password'    => 'o/ ¯_(ツ)_/¯ \'"',
1673
		), array(
1674
			'name'        => '\o/ ¯\_(ツ)_/¯',
1675
			'first_name'  => '\o/ ¯\_(ツ)_/¯',
1676
			'last_name'   => '\o/ ¯\_(ツ)_/¯',
1677
			'url'         => 'http://o/%20¯_(ツ)_/¯',
1678
			'description' => '\o/ ¯\_(ツ)_/¯',
1679
			'nickname'    => '\o/ ¯\_(ツ)_/¯',
1680
			'password'    => 'o/ ¯_(ツ)_/¯ \'"',
1681
		) );
1682
	}
1683
1684
	public function test_user_roundtrip_as_editor_html() {
1685
		wp_set_current_user( self::$editor );
1686
		if ( is_multisite() ) {
1687
			$this->assertFalse( current_user_can( 'unfiltered_html' ) );
1688
			$this->verify_user_roundtrip( array(
1689
				'id'          => self::$editor,
1690
				'name'        => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
1691
				'first_name'  => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
1692
				'last_name'   => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
1693
				'url'         => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
1694
				'description' => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
1695
				'nickname'    => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
1696
				'password'    => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
1697
			), array(
1698
				'name'        => 'div strong',
1699
				'first_name'  => 'div strong',
1700
				'last_name'   => 'div strong',
1701
				'url'         => 'http://divdiv/div%20strongstrong/strong%20scriptoh%20noes/script',
1702
				'description' => 'div <strong>strong</strong> oh noes',
1703
				'nickname'    => 'div strong',
1704
				'password'    => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
1705
			) );
1706
		} else {
1707
			$this->assertTrue( current_user_can( 'unfiltered_html' ) );
1708
			$this->verify_user_roundtrip( array(
1709
				'id'          => self::$editor,
1710
				'name'        => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
1711
				'first_name'  => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
1712
				'last_name'   => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
1713
				'url'         => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
1714
				'description' => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
1715
				'nickname'    => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
1716
				'password'    => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
1717
			), array(
1718
				'name'        => 'div strong',
1719
				'first_name'  => 'div strong',
1720
				'last_name'   => 'div strong',
1721
				'url'         => 'http://divdiv/div%20strongstrong/strong%20scriptoh%20noes/script',
1722
				'description' => 'div <strong>strong</strong> oh noes',
1723
				'nickname'    => 'div strong',
1724
				'password'    => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
1725
			) );
1726
		}
1727
	}
1728
1729
	public function test_user_roundtrip_as_superadmin() {
1730
		wp_set_current_user( self::$superadmin );
1731
		$this->assertTrue( current_user_can( 'unfiltered_html' ) );
1732
		$valid_username = is_multisite() ? 'noinvalidcharshere' : 'no-invalid-chars-here';
1733
		$this->verify_user_roundtrip( array(
1734
			'username'    => $valid_username,
1735
			'name'        => '\\\&\\\ &amp; &invalid; < &lt; &amp;lt;',
1736
			'first_name'  => '\\\&\\\ &amp; &invalid; < &lt; &amp;lt;',
1737
			'last_name'   => '\\\&\\\ &amp; &invalid; < &lt; &amp;lt;',
1738
			'url'         => '\\\&\\\ &amp; &invalid; < &lt; &amp;lt;',
1739
			'description' => '\\\&\\\ &amp; &invalid; < &lt; &amp;lt;',
1740
			'nickname'    => '\\\&\\\ &amp; &invalid; < &lt; &amp;lt;',
1741
			'password'    => '& &amp; &invalid; < &lt; &amp;lt;',
1742
		), array(
1743
			'username'    => $valid_username,
1744
			'name'        => '\\\&amp;\\\ &amp; &amp;invalid; &lt; &lt; &amp;lt;',
1745
			'first_name'  => '\\\&amp;\\\ &amp; &amp;invalid; &lt; &lt; &amp;lt;',
1746
			'last_name'   => '\\\&amp;\\\ &amp; &amp;invalid; &lt; &lt; &amp;lt;',
1747
			'url'         => 'http://&amp;%20&amp;%20&amp;invalid;%20%20&lt;%20&amp;lt;',
1748
			'description' => '\\\&amp;\\\ &amp; &amp;invalid; &lt; &lt; &amp;lt;',
1749
			'nickname'    => '\\\&amp;\\\ &amp; &amp;invalid; &lt; &lt; &amp;lt;',
1750
			'password'    => '& &amp; &invalid; < &lt; &amp;lt;',
1751
		) );
1752
	}
1753
1754
	public function test_user_roundtrip_as_superadmin_html() {
1755
		wp_set_current_user( self::$superadmin );
1756
		$this->assertTrue( current_user_can( 'unfiltered_html' ) );
1757
		$valid_username = is_multisite() ? 'noinvalidcharshere' : 'no-invalid-chars-here';
1758
		$this->verify_user_roundtrip( array(
1759
			'username'    => $valid_username,
1760
			'name'        => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
1761
			'first_name'  => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
1762
			'last_name'   => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
1763
			'url'         => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
1764
			'description' => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
1765
			'nickname'    => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
1766
			'password'    => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
1767
		), array(
1768
			'username'    => $valid_username,
1769
			'name'        => 'div strong',
1770
			'first_name'  => 'div strong',
1771
			'last_name'   => 'div strong',
1772
			'url'         => 'http://divdiv/div%20strongstrong/strong%20scriptoh%20noes/script',
1773
			'description' => 'div <strong>strong</strong> oh noes',
1774
			'nickname'    => 'div strong',
1775
			'password'    => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
1776
		) );
1777
	}
1778
1779
	public function test_delete_item() {
1780
		$user_id = $this->factory->user->create( array( 'display_name' => 'Deleted User' ) );
1781
1782
		$this->allow_user_to_manage_multisite();
1783
		wp_set_current_user( self::$user );
1784
1785
		$userdata = get_userdata( $user_id ); // cache for later
0 ignored issues
show
Unused Code introduced by
$userdata is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1786
		$request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/users/%d', $user_id ) );
1787
		$request->set_param( 'force', true );
1788
		$request->set_param( 'reassign', false );
1789
		$response = $this->server->dispatch( $request );
1790
1791
		// Not implemented in multisite.
1792
		if ( is_multisite() ) {
1793
			$this->assertErrorResponse( 'rest_cannot_delete', $response, 501 );
1794
			return;
1795
		}
1796
1797
		$this->assertEquals( 200, $response->get_status() );
1798
		$data = $response->get_data();
1799
		$this->assertTrue( $data['deleted'] );
1800
		$this->assertEquals( 'Deleted User', $data['previous']['name'] );
1801
	}
1802
1803
	public function test_delete_item_no_trash() {
1804
		$user_id = $this->factory->user->create( array( 'display_name' => 'Deleted User' ) );
1805
1806
		$this->allow_user_to_manage_multisite();
1807
		wp_set_current_user( self::$user );
1808
1809
		$userdata = get_userdata( $user_id ); // cache for later
0 ignored issues
show
Unused Code introduced by
$userdata is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1810
1811
		$request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/users/%d', $user_id ) );
1812
		$request->set_param( 'reassign', false );
1813
		$response = $this->server->dispatch( $request );
1814
1815
		// Not implemented in multisite.
1816
		if ( is_multisite() ) {
1817
			$this->assertErrorResponse( 'rest_cannot_delete', $response, 501 );
1818
			return;
1819
		}
1820
1821
		$this->assertErrorResponse( 'rest_trash_not_supported', $response, 501 );
1822
1823
		$request->set_param( 'force', 'false' );
1824
		$response = $this->server->dispatch( $request );
1825
		$this->assertErrorResponse( 'rest_trash_not_supported', $response, 501 );
1826
1827
		// Ensure the user still exists
1828
		$user = get_user_by( 'id', $user_id );
1829
		$this->assertNotEmpty( $user );
1830
	}
1831
1832
	public function test_delete_current_item() {
1833
		$user_id = $this->factory->user->create( array( 'role' => 'administrator', 'display_name' => 'Deleted User' ) );
1834
1835
		wp_set_current_user( $user_id );
1836
		$user = wp_get_current_user();
1837
		update_site_option( 'site_admins', array( $user->user_login ) );
1838
1839
		$request = new WP_REST_Request( 'DELETE', '/wp/v2/users/me' );
1840
		$request['force'] = true;
1841
		$request->set_param( 'reassign', false );
1842
		$response = $this->server->dispatch( $request );
1843
1844
		// Not implemented in multisite.
1845
		if ( is_multisite() ) {
1846
			$this->assertErrorResponse( 'rest_cannot_delete', $response, 501 );
1847
			return;
1848
		}
1849
1850
		$this->assertEquals( 200, $response->get_status() );
1851
		$data = $response->get_data();
1852
		$this->assertTrue( $data['deleted'] );
1853
		$this->assertEquals( 'Deleted User', $data['previous']['name'] );
1854
	}
1855
1856
	public function test_delete_current_item_no_trash() {
1857
		$user_id = $this->factory->user->create( array( 'role' => 'administrator', 'display_name' => 'Deleted User' ) );
1858
1859
		wp_set_current_user( $user_id );
1860
		$user = wp_get_current_user();
1861
		update_site_option( 'site_admins', array( $user->user_login ) );
1862
1863
		$request = new WP_REST_Request( 'DELETE', '/wp/v2/users/me' );
1864
		$request->set_param( 'reassign', false );
1865
		$response = $this->server->dispatch( $request );
1866
1867
		// Not implemented in multisite.
1868
		if ( is_multisite() ) {
1869
			$this->assertErrorResponse( 'rest_cannot_delete', $response, 501 );
1870
			return;
1871
		}
1872
1873
		$this->assertErrorResponse( 'rest_trash_not_supported', $response, 501 );
1874
1875
		$request->set_param( 'force', 'false' );
1876
		$response = $this->server->dispatch( $request );
1877
		$this->assertErrorResponse( 'rest_trash_not_supported', $response, 501 );
1878
1879
		// Ensure the user still exists
1880
		$user = get_user_by( 'id', $user_id );
1881
		$this->assertNotEmpty( $user );
1882
	}
1883
1884
	public function test_delete_user_without_permission() {
1885
		$user_id = $this->factory->user->create();
1886
1887
		$this->allow_user_to_manage_multisite();
1888
		wp_set_current_user( self::$editor );
1889
1890
		$request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/users/%d', $user_id ) );
1891
		$request['force'] = true;
1892
		$request->set_param( 'reassign', false );
1893
		$response = $this->server->dispatch( $request );
1894
1895
		$this->assertErrorResponse( 'rest_user_cannot_delete', $response, 403 );
1896
1897
		$request = new WP_REST_Request( 'DELETE', '/wp/v2/users/me' );
1898
		$request['force'] = true;
1899
		$request->set_param( 'reassign', false );
1900
		$response = $this->server->dispatch( $request );
1901
1902
		$this->assertErrorResponse( 'rest_user_cannot_delete', $response, 403 );
1903
	}
1904
1905
	public function test_delete_user_invalid_id() {
1906
		$this->allow_user_to_manage_multisite();
1907
		wp_set_current_user( self::$user );
1908
1909
		$request = new WP_REST_Request( 'DELETE', '/wp/v2/users/100' );
1910
		$request['force'] = true;
1911
		$request->set_param( 'reassign', false );
1912
		$response = $this->server->dispatch( $request );
1913
1914
		$this->assertErrorResponse( 'rest_user_invalid_id', $response, 404 );
1915
	}
1916
1917
	public function test_delete_user_reassign() {
1918
		$this->allow_user_to_manage_multisite();
1919
1920
		// Test with a new user, to avoid any complications
1921
		$user_id = $this->factory->user->create();
1922
		$reassign_id = $this->factory->user->create();
1923
		$test_post = $this->factory->post->create(array(
1924
			'post_author' => $user_id,
1925
		));
1926
1927
		// Sanity check to ensure the factory created the post correctly
1928
		$post = get_post( $test_post );
1929
		$this->assertEquals( $user_id, $post->post_author );
1930
1931
		// Delete our test user, and reassign to the new author
1932
		wp_set_current_user( self::$user );
1933
		$request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/users/%d', $user_id ) );
1934
		$request['force'] = true;
1935
		$request->set_param( 'reassign', $reassign_id );
1936
		$response = $this->server->dispatch( $request );
1937
1938
		// Not implemented in multisite.
1939
		if ( is_multisite() ) {
1940
			$this->assertErrorResponse( 'rest_cannot_delete', $response, 501 );
1941
			return;
1942
		}
1943
1944
		$this->assertEquals( 200, $response->get_status() );
1945
1946
		// Check that the post has been updated correctly
1947
		$post = get_post( $test_post );
1948
		$this->assertEquals( $reassign_id, $post->post_author );
1949
	}
1950
1951
	public function test_delete_user_invalid_reassign_id() {
1952
		$user_id = $this->factory->user->create();
1953
1954
		$this->allow_user_to_manage_multisite();
1955
		wp_set_current_user( self::$user );
1956
1957
		$request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/users/%d', $user_id ) );
1958
		$request['force'] = true;
1959
		$request->set_param( 'reassign', 100 );
1960
		$response = $this->server->dispatch( $request );
1961
1962
		// Not implemented in multisite.
1963
		if ( is_multisite() ) {
1964
			$this->assertErrorResponse( 'rest_cannot_delete', $response, 501 );
1965
			return;
1966
		}
1967
1968
		$this->assertErrorResponse( 'rest_user_invalid_reassign', $response, 400 );
1969
	}
1970
1971
	public function test_delete_user_invalid_reassign_passed_as_string() {
1972
		$user_id = $this->factory->user->create();
1973
1974
		$this->allow_user_to_manage_multisite();
1975
		wp_set_current_user( self::$user );
1976
1977
		$request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/users/%d', $user_id ) );
1978
		$request['force'] = true;
1979
		$request->set_param( 'reassign', 'null' );
1980
		$response = $this->server->dispatch( $request );
1981
1982
		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
1983
	}
1984
1985
	public function test_delete_user_reassign_passed_as_boolean_false_trashes_post() {
1986
		$user_id = $this->factory->user->create();
1987
1988
		$this->allow_user_to_manage_multisite();
1989
		wp_set_current_user( self::$user );
1990
1991
		$test_post = $this->factory->post->create(array(
1992
			'post_author' => $user_id,
1993
		));
1994
1995
		$request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/users/%d', $user_id ) );
1996
		$request['force'] = true;
1997
		$request->set_param( 'reassign', false );
1998
		$response = $this->server->dispatch( $request );
1999
2000
		// Not implemented in multisite.
2001
		if ( is_multisite() ) {
2002
			$this->assertErrorResponse( 'rest_cannot_delete', $response, 501 );
2003
			return;
2004
		}
2005
2006
		$test_post = get_post( $test_post );
2007
		$this->assertEquals( 'trash', $test_post->post_status );
2008
	}
2009
2010
	public function test_delete_user_reassign_passed_as_string_false_trashes_post() {
2011
		$user_id = $this->factory->user->create();
2012
2013
		$this->allow_user_to_manage_multisite();
2014
		wp_set_current_user( self::$user );
2015
2016
		$test_post = $this->factory->post->create(array(
2017
			'post_author' => $user_id,
2018
		));
2019
2020
		$request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/users/%d', $user_id ) );
2021
		$request['force'] = true;
2022
		$request->set_param( 'reassign', 'false' );
2023
		$response = $this->server->dispatch( $request );
2024
2025
		// Not implemented in multisite.
2026
		if ( is_multisite() ) {
2027
			$this->assertErrorResponse( 'rest_cannot_delete', $response, 501 );
2028
			return;
2029
		}
2030
2031
		$test_post = get_post( $test_post );
2032
		$this->assertEquals( 'trash', $test_post->post_status );
2033
	}
2034
2035
	public function test_delete_user_reassign_passed_as_empty_string_trashes_post() {
2036
		$user_id = $this->factory->user->create();
2037
2038
		$this->allow_user_to_manage_multisite();
2039
		wp_set_current_user( self::$user );
2040
2041
		$test_post = $this->factory->post->create(array(
2042
			'post_author' => $user_id,
2043
		));
2044
2045
		$request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/users/%d', $user_id ) );
2046
		$request['force'] = true;
2047
		$request->set_param( 'reassign', '' );
2048
		$response = $this->server->dispatch( $request );
2049
2050
		// Not implemented in multisite.
2051
		if ( is_multisite() ) {
2052
			$this->assertErrorResponse( 'rest_cannot_delete', $response, 501 );
2053
			return;
2054
		}
2055
2056
		$test_post = get_post( $test_post );
2057
		$this->assertEquals( 'trash', $test_post->post_status );
2058
	}
2059
2060
	public function test_delete_user_reassign_passed_as_0_reassigns_author() {
2061
		$user_id = $this->factory->user->create();
2062
2063
		$this->allow_user_to_manage_multisite();
2064
		wp_set_current_user( self::$user );
2065
2066
		$test_post = $this->factory->post->create(array(
2067
			'post_author' => $user_id,
2068
		));
2069
2070
		$request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/users/%d', $user_id ) );
2071
		$request['force'] = true;
2072
		$request->set_param( 'reassign', 0 );
2073
		$response = $this->server->dispatch( $request );
2074
2075
		// Not implemented in multisite.
2076
		if ( is_multisite() ) {
2077
			$this->assertErrorResponse( 'rest_cannot_delete', $response, 501 );
2078
			return;
2079
		}
2080
2081
		$test_post = get_post( $test_post );
2082
		$this->assertEquals( 0, $test_post->post_author );
2083
	}
2084
2085
	public function test_get_item_schema() {
2086
		$request = new WP_REST_Request( 'OPTIONS', '/wp/v2/users' );
2087
		$response = $this->server->dispatch( $request );
2088
		$data = $response->get_data();
2089
		$properties = $data['schema']['properties'];
2090
2091
		$this->assertEquals( 19, count( $properties ) );
2092
		$this->assertArrayHasKey( 'avatar_urls', $properties );
2093
		$this->assertArrayHasKey( 'capabilities', $properties );
2094
		$this->assertArrayHasKey( 'description', $properties );
2095
		$this->assertArrayHasKey( 'email', $properties );
2096
		$this->assertArrayHasKey( 'extra_capabilities', $properties );
2097
		$this->assertArrayHasKey( 'first_name', $properties );
2098
		$this->assertArrayHasKey( 'id', $properties );
2099
		$this->assertArrayHasKey( 'last_name', $properties );
2100
		$this->assertArrayHasKey( 'link', $properties );
2101
		$this->assertArrayHasKey( 'locale', $properties );
2102
		$this->assertArrayHasKey( 'meta', $properties );
2103
		$this->assertArrayHasKey( 'name', $properties );
2104
		$this->assertArrayHasKey( 'nickname', $properties );
2105
		$this->assertArrayHasKey( 'registered_date', $properties );
2106
		$this->assertArrayHasKey( 'slug', $properties );
2107
		$this->assertArrayHasKey( 'password', $properties );
2108
		$this->assertArrayHasKey( 'url', $properties );
2109
		$this->assertArrayHasKey( 'username', $properties );
2110
		$this->assertArrayHasKey( 'roles', $properties );
2111
2112
	}
2113
2114
	public function test_get_item_schema_show_avatar() {
2115
		update_option( 'show_avatars', false );
2116
		$request = new WP_REST_Request( 'OPTIONS', '/wp/v2/users' );
2117
		$response = $this->server->dispatch( $request );
2118
		$data = $response->get_data();
2119
		$properties = $data['schema']['properties'];
2120
2121
		$this->assertArrayNotHasKey( 'avatar_urls', $properties );
2122
	}
2123
2124
	public function test_get_additional_field_registration() {
2125
2126
		$schema = array(
2127
			'type'        => 'integer',
2128
			'description' => 'Some integer of mine',
2129
			'enum'        => array( 1, 2, 3, 4 ),
2130
			'context'     => array( 'embed', 'view', 'edit' ),
2131
		);
2132
2133
		register_rest_field( 'user', 'my_custom_int', array(
2134
			'schema'          => $schema,
2135
			'get_callback'    => array( $this, 'additional_field_get_callback' ),
2136
			'update_callback' => array( $this, 'additional_field_update_callback' ),
2137
		) );
2138
2139
		$request = new WP_REST_Request( 'OPTIONS', '/wp/v2/users' );
2140
2141
		$response = $this->server->dispatch( $request );
2142
		$data = $response->get_data();
2143
2144
		$this->assertArrayHasKey( 'my_custom_int', $data['schema']['properties'] );
2145
		$this->assertEquals( $schema, $data['schema']['properties']['my_custom_int'] );
2146
2147
		wp_set_current_user( 1 );
2148
		if ( is_multisite() ) {
2149
			$current_user = wp_get_current_user( 1 );
2150
			update_site_option( 'site_admins', array( $current_user->user_login ) );
2151
		}
2152
2153
		$request = new WP_REST_Request( 'GET', '/wp/v2/users/1' );
2154
2155
		$response = $this->server->dispatch( $request );
2156
		$this->assertArrayHasKey( 'my_custom_int', $response->data );
2157
2158
		$request = new WP_REST_Request( 'POST', '/wp/v2/users/1' );
2159
		$request->set_body_params(array(
2160
			'my_custom_int' => 123,
2161
		));
2162
2163
		$response = $this->server->dispatch( $request );
0 ignored issues
show
Unused Code introduced by
$response is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2164
		$this->assertEquals( 123, get_user_meta( 1, 'my_custom_int', true ) );
2165
2166
		$request = new WP_REST_Request( 'POST', '/wp/v2/users' );
2167
		$request->set_body_params(array(
2168
			'my_custom_int' => 123,
2169
			'email' => '[email protected]',
2170
			'username' => 'abc123',
2171
			'password' => 'hello',
2172
		));
2173
2174
		$response = $this->server->dispatch( $request );
2175
2176
		$this->assertEquals( 123, $response->data['my_custom_int'] );
2177
2178
		global $wp_rest_additional_fields;
2179
		$wp_rest_additional_fields = array();
2180
	}
2181
2182
	public function test_additional_field_update_errors() {
2183
		$schema = array(
2184
			'type'        => 'integer',
2185
			'description' => 'Some integer of mine',
2186
			'enum'        => array( 1, 2, 3, 4 ),
2187
			'context'     => array( 'view', 'edit' ),
2188
		);
2189
2190
		register_rest_field( 'user', 'my_custom_int', array(
2191
			'schema'          => $schema,
2192
			'get_callback'    => array( $this, 'additional_field_get_callback' ),
2193
			'update_callback' => array( $this, 'additional_field_update_callback' ),
2194
		) );
2195
2196
		wp_set_current_user( 1 );
2197
		if ( is_multisite() ) {
2198
			$current_user = wp_get_current_user( 1 );
2199
			update_site_option( 'site_admins', array( $current_user->user_login ) );
2200
		}
2201
2202
		// Check for error on update.
2203
		$request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d', self::$user ) );
2204
		$request->set_body_params( array(
2205
			'my_custom_int' => 'returnError',
2206
		) );
2207
2208
		$response = $this->server->dispatch( $request );
2209
2210
		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
2211
2212
		global $wp_rest_additional_fields;
2213
		$wp_rest_additional_fields = array();
2214
	}
2215
2216
	/**
2217
	 * @ticket 39701
2218
	 * @group ms-required
2219
	 */
2220
	public function test_get_item_from_different_site_as_site_administrator() {
2221
		switch_to_blog( self::$site );
2222
		$user_id = $this->factory->user->create( array(
2223
			'role' => 'author',
2224
		) );
2225
		restore_current_blog();
2226
2227
		wp_set_current_user( self::$user );
2228
		$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', $user_id ) );
2229
2230
		$response = $this->server->dispatch( $request );
2231
		$this->assertErrorResponse( 'rest_user_invalid_id', $response, 404 );
2232
	}
2233
2234
	/**
2235
	 * @ticket 39701
2236
	 * @group ms-required
2237
	 */
2238
	public function test_get_item_from_different_site_as_network_administrator() {
2239
		switch_to_blog( self::$site );
2240
		$user_id = $this->factory->user->create( array(
2241
			'role' => 'author',
2242
		) );
2243
		restore_current_blog();
2244
2245
		wp_set_current_user( self::$superadmin );
2246
		$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', $user_id ) );
2247
2248
		$response = $this->server->dispatch( $request );
2249
		$this->assertErrorResponse( 'rest_user_invalid_id', $response, 404 );
2250
	}
2251
2252
	/**
2253
	 * @ticket 39701
2254
	 * @group ms-required
2255
	 */
2256
	public function test_update_item_from_different_site_as_site_administrator() {
2257
		switch_to_blog( self::$site );
2258
		$user_id = $this->factory->user->create( array(
2259
			'role' => 'author',
2260
		) );
2261
		restore_current_blog();
2262
2263
		wp_set_current_user( self::$user );
2264
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d', $user_id ) );
2265
		$request->add_header( 'content-type', 'application/x-www-form-urlencoded' );
2266
		$request->set_body_params( array( 'first_name' => 'New Name' ) );
2267
2268
		$response = $this->server->dispatch( $request );
2269
		$this->assertErrorResponse( 'rest_user_invalid_id', $response, 404 );
2270
	}
2271
2272
	/**
2273
	 * @ticket 39701
2274
	 * @group ms-required
2275
	 */
2276
	public function test_update_item_from_different_site_as_network_administrator() {
2277
		switch_to_blog( self::$site );
2278
		$user_id = $this->factory->user->create( array(
2279
			'role' => 'author',
2280
		) );
2281
		restore_current_blog();
2282
2283
		wp_set_current_user( self::$superadmin );
2284
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d', $user_id ) );
2285
		$request->add_header( 'content-type', 'application/x-www-form-urlencoded' );
2286
		$request->set_body_params( array( 'first_name' => 'New Name' ) );
2287
2288
		$response = $this->server->dispatch( $request );
2289
		$this->assertErrorResponse( 'rest_user_invalid_id', $response, 404 );
2290
	}
2291
2292
	/**
2293
	 * @ticket 39701
2294
	 * @group ms-required
2295
	 */
2296
	public function test_delete_item_from_different_site_as_site_administrator() {
2297
		switch_to_blog( self::$site );
2298
		$user_id = $this->factory->user->create( array(
2299
			'role' => 'author',
2300
		) );
2301
		restore_current_blog();
2302
2303
		wp_set_current_user( self::$user );
2304
		$request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/users/%d', $user_id ) );
2305
		$request->set_param( 'force', true );
2306
		$request->set_param( 'reassign', false );
2307
2308
		$response = $this->server->dispatch( $request );
2309
		$this->assertErrorResponse( 'rest_user_invalid_id', $response, 404 );
2310
	}
2311
2312
	/**
2313
	 * @ticket 39701
2314
	 * @group ms-required
2315
	 */
2316
	public function test_delete_item_from_different_site_as_network_administrator() {
2317
		switch_to_blog( self::$site );
2318
		$user_id = $this->factory->user->create( array(
2319
			'role' => 'author',
2320
		) );
2321
		restore_current_blog();
2322
2323
		wp_set_current_user( self::$superadmin );
2324
		$request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/users/%d', $user_id ) );
2325
		$request->set_param( 'force', true );
2326
		$request->set_param( 'reassign', false );
2327
2328
		$response = $this->server->dispatch( $request );
2329
		$this->assertErrorResponse( 'rest_user_invalid_id', $response, 404 );
2330
	}
2331
2332
	public function additional_field_get_callback( $object ) {
2333
		return get_user_meta( $object['id'], 'my_custom_int', true );
2334
	}
2335
2336
	public function additional_field_update_callback( $value, $user ) {
2337
		if ( 'returnError' === $value ) {
2338
			return new WP_Error( 'rest_invalid_param', 'Testing an error.', array( 'status' => 400 ) );
2339
		}
2340
		update_user_meta( $user->ID, 'my_custom_int', $value );
2341
	}
2342
2343
	public function tearDown() {
2344
		parent::tearDown();
2345
	}
2346
2347
	protected function check_user_data( $user, $data, $context, $links ) {
2348
		$this->assertEquals( $user->ID, $data['id'] );
2349
		$this->assertEquals( $user->display_name, $data['name'] );
2350
		$this->assertEquals( $user->user_url, $data['url'] );
2351
		$this->assertEquals( $user->description, $data['description'] );
2352
		$this->assertEquals( get_author_posts_url( $user->ID ), $data['link'] );
2353
		$this->assertArrayHasKey( 'avatar_urls', $data );
2354
		$this->assertEquals( $user->user_nicename, $data['slug'] );
2355
2356
		if ( 'edit' === $context ) {
2357
			$this->assertEquals( $user->first_name, $data['first_name'] );
2358
			$this->assertEquals( $user->last_name, $data['last_name'] );
2359
			$this->assertEquals( $user->nickname, $data['nickname'] );
2360
			$this->assertEquals( $user->user_email, $data['email'] );
2361
			$this->assertEquals( (object) $user->allcaps, $data['capabilities'] );
2362
			$this->assertEquals( (object) $user->caps, $data['extra_capabilities'] );
2363
			$this->assertEquals( date( 'c', strtotime( $user->user_registered ) ), $data['registered_date'] );
2364
			$this->assertEquals( $user->user_login, $data['username'] );
2365
			$this->assertEquals( $user->roles, $data['roles'] );
2366
			$this->assertEquals( get_user_locale( $user ), $data['locale'] );
2367
		}
2368
2369
		if ( 'edit' !== $context ) {
2370
			$this->assertArrayNotHasKey( 'roles', $data );
2371
			$this->assertArrayNotHasKey( 'capabilities', $data );
2372
			$this->assertArrayNotHasKey( 'registered_date', $data );
2373
			$this->assertArrayNotHasKey( 'first_name', $data );
2374
			$this->assertArrayNotHasKey( 'last_name', $data );
2375
			$this->assertArrayNotHasKey( 'nickname', $data );
2376
			$this->assertArrayNotHasKey( 'email', $data );
2377
			$this->assertArrayNotHasKey( 'extra_capabilities', $data );
2378
			$this->assertArrayNotHasKey( 'username', $data );
2379
			$this->assertArrayNotHasKey( 'locale', $data );
2380
		}
2381
2382
		$this->assertEqualSets( array(
2383
			'self',
2384
			'collection',
2385
		), array_keys( $links ) );
2386
2387
		$this->assertArrayNotHasKey( 'password', $data );
2388
	}
2389
2390
	protected function check_get_user_response( $response, $context = 'view' ) {
2391
		$this->assertEquals( 200, $response->get_status() );
2392
2393
		$data = $response->get_data();
2394
		$userdata = get_userdata( $data['id'] );
2395
		$this->check_user_data( $userdata, $data, $context, $response->get_links() );
2396
	}
2397
2398
	protected function check_add_edit_user_response( $response, $update = false ) {
2399
		if ( $update ) {
2400
			$this->assertEquals( 200, $response->get_status() );
2401
		} else {
2402
			$this->assertEquals( 201, $response->get_status() );
2403
		}
2404
2405
		$data = $response->get_data();
2406
		$userdata = get_userdata( $data['id'] );
2407
		$this->check_user_data( $userdata, $data, 'edit', $response->get_links() );
2408
	}
2409
2410
	protected function allow_user_to_manage_multisite() {
2411
		wp_set_current_user( self::$user );
2412
		$user = wp_get_current_user();
2413
2414
		if ( is_multisite() ) {
2415
			update_site_option( 'site_admins', array( $user->user_login ) );
2416
		}
2417
2418
		return;
2419
	}
2420
}
2421