Repository navigation
Expand file tree
/
Copy pathUserAccess.php
More file actions
235 lines (211 loc) · 7.23 KB
/
Copy pathUserAccess.php
File metadata and controls
235 lines (211 loc) · 7.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
<?php
/**
* Class UserAccess.
*
* @since 2.0
*
* @package AMP
*/
namespace AmpProject\AmpWP\DevTools;
use AMP_Options_Manager;
use AMP_Theme_Support;
use AMP_Validation_Manager;
use AmpProject\AmpWP\DependencySupport;
use AmpProject\AmpWP\Infrastructure\Registerable;
use AmpProject\AmpWP\Infrastructure\Service;
use AmpProject\AmpWP\Option;
use WP_Error;
use WP_User;
/**
* Class UserAccess
*
* @since 2.0
* @internal
*/
final class UserAccess implements Service, Registerable {
/** @var DependencySupport */
private $dependency_support;
/**
* Constructor.
*
* @param DependencySupport $dependency_support DependencySupport instance.
*/
public function __construct( DependencySupport $dependency_support ) {
$this->dependency_support = $dependency_support;
}
/**
* User meta key enabling or disabling developer tools.
*
* @var string
*/
const USER_FIELD_DEVELOPER_TOOLS_ENABLED = 'amp_dev_tools_enabled';
/**
* Runs on instantiation.
*/
public function register() {
add_action( 'rest_api_init', [ $this, 'register_rest_field' ] );
add_action( 'personal_options', [ $this, 'print_personal_options' ] );
add_action( 'personal_options_update', [ $this, 'update_user_setting' ] );
add_action( 'edit_user_profile_update', [ $this, 'update_user_setting' ] );
}
/**
* Determine whether developer tools are enabled for the a user and whether they can access them.
*
* @param null|WP_User|int $user User. Defaults to the current user.
* @return bool Whether developer tools are enabled for the user.
*/
public function is_user_enabled( $user = null ) {
// Note: This is somewhat of a shortcut for blocking access to the validation UI on unsupported versions of WP.
// It works because we're already using this method in many places to check if the user interface should be
// shown, and its the user interface which is particularly problematic on older versions of WP due to the
// JavaScript dependencies.
if ( ! $this->dependency_support->has_support() ) {
return false; // @codeCoverageIgnore
}
if ( null === $user ) {
$user = wp_get_current_user();
} elseif ( ! $user instanceof WP_User ) {
$user = new WP_User( $user );
}
if ( ! AMP_Validation_Manager::has_cap( $user ) ) {
return false;
}
return $this->get_user_enabled( $user );
}
/**
* Get user enabled (regardless of whether they have the required capability).
*
* @param int|WP_User $user User.
* @return bool Whether dev tools is enabled.
*/
public function get_user_enabled( $user ) {
if ( ! $user instanceof WP_User ) {
$user = new WP_User( $user );
}
$enabled = $user->get( self::USER_FIELD_DEVELOPER_TOOLS_ENABLED );
if ( '' === $enabled ) {
// Disable Developer Tools by default when in Reader mode.
$enabled = AMP_Theme_Support::READER_MODE_SLUG !== AMP_Options_Manager::get_option( Option::THEME_SUPPORT );
/**
* Filters whether Developer Tools is enabled by default for a user.
*
* When Reader mode is active, Developer Tools is currently disabled by default.
*
* @since 2.0.1
*
* @param bool $enabled DevTools enabled.
* @param int $user_id User ID.
*/
$enabled = (bool) apply_filters( 'amp_dev_tools_user_default_enabled', $enabled, $user->ID );
}
return rest_sanitize_boolean( $enabled );
}
/**
* Set user enabled.
*
* @param int|WP_User $user User.
* @param bool $enabled Whether enabled.
* @return bool Whether update was successful.
*/
public function set_user_enabled( $user, $enabled ) {
if ( $user instanceof WP_User ) {
$user = $user->ID;
}
return (bool) update_user_meta( (int) $user, self::USER_FIELD_DEVELOPER_TOOLS_ENABLED, wp_json_encode( (bool) $enabled ) );
}
/**
* Register REST field.
*/
public function register_rest_field() {
register_rest_field(
'user',
self::USER_FIELD_DEVELOPER_TOOLS_ENABLED,
[
'get_callback' => [ $this, 'rest_get_dev_tools_enabled' ],
'update_callback' => [ $this, 'rest_update_dev_tools_enabled' ],
'schema' => [
'description' => __( 'Whether the user has enabled dev tools.', 'amp' ),
'type' => 'boolean',
],
]
);
}
/**
* Determine whether the option can be modified.
*
* @param int $user_id User ID.
* @return bool Whether the option can be modified.
*/
private function can_modify_option( $user_id ) {
return (
$this->dependency_support->has_support()
&&
current_user_can( 'edit_user', $user_id )
&&
AMP_Validation_Manager::has_cap( $user_id )
);
}
/**
* Add the developer tools checkbox to the user edit screen.
*
* @param WP_User $profile_user Current user being edited.
*/
public function print_personal_options( $profile_user ) {
if ( ! $this->can_modify_option( $profile_user->ID ) ) {
return;
}
?>
<tr>
<th scope="row"><?php esc_html_e( 'AMP Developer Tools', 'amp' ); ?></th>
<td>
<label for="amp_dev_tools_enabled">
<input name="<?php echo esc_attr( self::USER_FIELD_DEVELOPER_TOOLS_ENABLED ); ?>" type="checkbox" id="amp_dev_tools_enabled" value="true" <?php checked( $this->is_user_enabled( $profile_user ) ); ?> />
<?php esc_html_e( 'Enable AMP developer tools to surface validation errors when editing posts and viewing the site.', 'amp' ); ?>
</label>
<p class="description"><?php esc_html_e( 'This presumes you have some experience coding with HTML, CSS, JS, and PHP.', 'amp' ); ?></p>
</td>
</tr>
<?php
}
/**
* Update the user setting from the edit user screen).
*
* @param int $user_id User being edited.
* @return bool Whether update was successful.
*/
public function update_user_setting( $user_id ) {
if ( ! $this->can_modify_option( $user_id ) ) {
return false;
}
// phpcs:disable WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- -- Nonce handled by user-edit.php; sanitization used is sanitized.
$enabled = isset( $_POST[ self::USER_FIELD_DEVELOPER_TOOLS_ENABLED ] ) && rest_sanitize_boolean( wp_unslash( $_POST[ self::USER_FIELD_DEVELOPER_TOOLS_ENABLED ] ) );
// phpcs:enable WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
return $this->set_user_enabled( $user_id, $enabled );
}
/**
* Provides the user's dev tools enabled setting.
*
* @param array $user Array of user data prepared for REST.
* @return bool Whether dev tools are enabled for the user.
*/
public function rest_get_dev_tools_enabled( $user ) {
return $this->is_user_enabled( $user['id'] );
}
/**
* Updates a user's dev tools enabled setting.
*
* @param bool $new_value New setting for whether dev tools are enabled for the user.
* @param WP_User $user The WP user to update.
* @return bool|WP_Error The result of update_user_meta, or WP_Error if the current user lacks permission.
*/
public function rest_update_dev_tools_enabled( $new_value, WP_User $user ) {
if ( ! AMP_Validation_Manager::has_cap( $user ) || ! current_user_can( 'edit_user', $user->ID ) ) {
return new WP_Error(
'amp_rest_cannot_edit_user',
__( 'Sorry, the current user is not allowed to make this change.', 'amp' ),
[ 'status' => rest_authorization_required_code() ]
);
}
return $this->set_user_enabled( $user->ID, $new_value );
}
}