PluginProbe
WP-Stateless – Google Cloud Storage / trunk
WP-Stateless – Google Cloud Storage vtrunk
4.4.3 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.2.7 2.3.0 2.3.1 2.3.2 3.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.2.0 3.2.1 3.2.2 All 62 releases
← All changes | lib/classes/class-api.php +252 -147 2.1.7trunk View file →
@@ -1,5 +1,6 @@
1 1 <?php
2 +
2 3 /**
3 4 * API Handler
4 5 *
5 6 *
@@ -5,226 +6,330 @@
5 6 *
6 7 *
7 8 * @since 1.0.0
8 9 */
10 +
9 11 namespace wpCloud\StatelessMedia {
10 12
11 - if( !class_exists( 'wpCloud\StatelessMedia\API' ) ) {
13 + use wpCloud\StatelessMedia\Sync\FileSync;
14 + use wpCloud\StatelessMedia\Sync\ImageSync;
15 + use wpCloud\StatelessMedia\Sync\NonLibrarySync;
12 16
17 + if (!class_exists('wpCloud\StatelessMedia\API')) {
13 18
19 + /**
20 + * Class API
21 + *
22 + * @package wpCloud\StatelessMedia
23 + */
14 24 final class API {
15 25
16 26 /**
27 + * Decoded auth_token data
28 + *
29 + * @var null|\stdClass
30 + */
31 + static private $tokenData = null;
32 +
33 + /**
34 + * Validate auth token and save data for further processing
35 + *
36 + * @param \WP_REST_Request $request
37 + * @return bool|\WP_Error
38 + */
39 + static public function authCheck(\WP_REST_Request $request) {
40 + $auth_token = $request->get_header('authorization');
41 + // Allow using custom `x-wps-auth` header if authorization hedaer is disabled
42 + if (!$auth_token) $auth_token = $request->get_header('x-wps-auth');
43 +
44 + if (!$auth_token) return false;
45 +
46 + try {
47 + self::$tokenData = Utility::verify_jwt_token($auth_token);
48 + } catch (\Exception $e) {
49 + self::$tokenData = null;
50 + return new \WP_Error('auth_failed', $e->getMessage(), ['status' => 401]);
51 + }
52 + return true;
53 + }
54 +
55 + /**
17 56 * API Status Endpoint.
18 57 *
19 - * @return array
58 + * @return \WP_REST_Response
20 59 */
21 60 static public function status() {
22 -
23 - return array(
61 + return new \WP_REST_Response(array(
24 62 "ok" => true,
25 63 "message" => "API up."
26 - );
27 -
64 + ), 200);
28 65 }
29 66
30 67 /**
31 - * Jobs Endpoint.
68 + * Get settings
32 69 *
33 - * @return array
70 + * @todo Implement this if needed
71 + * @param \WP_REST_Request $request
72 + * @return \WP_REST_Response|\WP_Error
34 73 */
35 - static public function jobs() {
36 -
37 - return array(
38 - "ok" => true,
39 - "message" => "Job endpoint up.",
40 - "jobs" => array()
41 - );
42 -
74 + static public function getSettings(\WP_REST_Request $request) {
75 + return new \WP_Error('not_implemented', 'Method not implemented', ['status' => 501]);
43 76 }
44 77
45 78 /**
46 - * Get settings Endpoint.
79 + * Update settings
47 80 *
48 - * @param $request
49 - * @return array
81 + * @param \WP_REST_Request $request
82 + * @return \WP_REST_Response|\WP_Error
50 83 */
51 - static public function getSettings( $request ) {
84 + static public function updateSettings(\WP_REST_Request $request) {
85 + if (self::$tokenData === null || empty(self::$tokenData->user_id)) {
86 + return new \WP_Error('unauthorized', 'Auth token looks incorrect', ['status' => 401]);
87 + }
88 + $is_gae = apply_filters('wp_stateless_is_app_engine', false);
89 + $upload_dir = wp_upload_dir();
90 + $is_upload_dir_writable = is_writable($upload_dir['basedir']);
52 91
53 - if( !self::authRequest( $request ) ) {
54 - return array("ok" => false, "message" => __( "Auth fail." ));
55 - }
92 + try {
93 + $queryParams = $request->get_json_params();
94 + if (empty($queryParams)) throw new \Exception('Query is empty');
56 95
57 - $settings = apply_filters('stateless::get_settings', array());
96 + $bucketName = isset($queryParams['bucket_name']) ? $queryParams['bucket_name'] : null;
97 + $privateKeyData = isset($queryParams['private_key_data']) ? $queryParams['private_key_data'] : null;
58 98
59 - return array(
60 - "ok" => true,
61 - "message" => "getSettings endpoint.",
62 - "settings" => $settings
63 - );
99 + if (!$bucketName || !$privateKeyData) {
100 + throw new \Exception('bucket_name and private_key_data are required');
101 + }
64 102
65 - }
103 + if ($privateKeyData) {
104 + $privateKeyData = base64_decode($privateKeyData);
105 + }
66 106
67 - /**
68 - * Get media library Endpoint.
69 - *
70 - * @param $request
71 - * @return array
72 - */
73 - static public function getMediaLibrary( $request ) {
107 + switch (self::$tokenData->is_network) {
108 + case true:
109 + if (!user_can(self::$tokenData->user_id, 'manage_network_options')) {
110 + return new \WP_Error('not_allowed', 'Sorry, you are not allowed to perform this action', ['status' => 403]);
111 + }
112 + /**
113 + * If Google App Engine detected - set Stateless mode
114 + * and Google App Engine compatibility by default
115 + */
116 + if ($is_gae || !$is_upload_dir_writable) {
117 + update_site_option('sm_mode', 'stateless');
74 118
75 - if( !self::authRequest( $request ) ) {
76 - return array("ok" => false, "message" => __( "Auth fail." ));
77 - }
119 + $modules = get_site_option('stateless-modules', array());
120 + if ($is_gae && empty($modules['google-app-engine']) || $modules['google-app-engine'] != 'true') {
121 + $modules['google-app-engine'] = 'true';
122 + update_site_option('stateless-modules', $modules);
123 + }
124 + } elseif (get_site_option('sm_mode', 'disabled') == 'disabled') {
125 + update_site_option('sm_mode', 'ephemeral');
126 + }
127 + update_site_option('sm_bucket', $bucketName);
128 + update_site_option('sm_key_json', $privateKeyData);
129 + break;
78 130
79 - if( !self::switchBlog( $request ) ){
80 - return array("ok" => false, "message" => __( "Missed blog param." ));
81 - }
131 + case false:
132 + if (!user_can(self::$tokenData->user_id, 'manage_options')) {
133 + return new \WP_Error('not_allowed', 'Sorry, you are not allowed to perform this action', ['status' => 403]);
134 + }
135 + /**
136 + * If Google App Engine detected - set Stateless mode
137 + * and Google App Engine compatibility by default
138 + */
139 + if ($is_gae || !$is_upload_dir_writable) {
140 + update_option('sm_mode', 'stateless');
82 141
83 - $query_images_args = array(
84 - 'post_type' => 'attachment',
85 - 'post_mime_type' =>'image',
86 - 'post_status' => 'inherit',
87 - 'posts_per_page' => -1,
88 - );
142 + $modules = get_option('stateless-modules', array());
143 + if ($is_gae && empty($modules['google-app-engine']) || $modules['google-app-engine'] != 'true') {
144 + $modules['google-app-engine'] = 'true';
145 + update_option('stateless-modules', $modules);
146 + }
147 + } elseif (get_option('sm_mode', 'disabled') == 'disabled') {
148 + update_option('sm_mode', 'ephemeral');
149 + }
150 + update_option('sm_bucket', $bucketName);
151 + update_option('sm_key_json', $privateKeyData);
152 + break;
153 + }
89 154
90 - $query_images = new \WP_Query( $query_images_args );
91 - $media = array();
92 - foreach ( $query_images->posts as $image) {
93 - $media[] = self::mediaMapping($image);
155 + return new \WP_REST_Response(array(
156 + 'ok' => true,
157 + 'message' => 'Settings updated successfully'
158 + ));
159 + } catch (\Throwable $e) {
160 + return new \WP_Error('internal_server_error', $e->getMessage(), ['status' => 500]);
94 161 }
162 + }
95 163
96 - return array(
97 - "ok" => true,
98 - "message" => "getMediaLibrary endpoint.",
99 - "mediaLibrary" => $media
100 - );
164 + /**
165 + * Get all available processes with their states
166 + *
167 + * @return \WP_REST_Response|\WP_Error
168 + */
169 + static public function syncGetProcesses() {
170 + try {
171 + if (!user_can(self::$tokenData->user_id, 'manage_options')) {
172 + return new \WP_Error('not_allowed', 'Sorry, you are not allowed to perform this action', ['status' => 403]);
173 + }
101 174
175 + return new \WP_REST_Response(array(
176 + 'ok' => true,
177 + 'data' => Utility::get_available_sync_classes()
178 + ));
179 + } catch (\Throwable $e) {
180 + return new \WP_Error('internal_server_error', $e->getMessage(), ['status' => 500]);
181 + }
102 182 }
103 183
104 184 /**
105 - * Get media item Endpoint.
106 - *
107 - * @param $request
108 - * @return array
185 + * Get a single process by id (base64 encoded class name)
186 + *
187 + * @param \WP_REST_Request $request
188 + * @return \WP_Error|\WP_REST_Response
109 189 */
110 - static public function getMediaItem( $request ) {
190 + static public function syncGetProcess(\WP_REST_Request $request) {
191 + try {
192 + if (!user_can(self::$tokenData->user_id, 'manage_options')) {
193 + return new \WP_Error('not_allowed', 'Sorry, you are not allowed to perform this action', ['status' => 403]);
194 + }
111 195
112 - if( !self::authRequest( $request ) ) {
113 - return array("ok" => false, "message" => __( "Auth fail." ));
114 - }
196 + $id = base64_decode($request->get_param('id'));
197 + if (!class_exists($id)) {
198 + throw new \Exception(sprintf('Could not get process by id %s', $id));
199 + }
115 200
116 - if( !self::switchBlog( $request ) ){
117 - return array("ok" => false, "message" => __( "Missed blog param." ));
118 - }
201 + $syncClasses = Utility::get_available_sync_classes();
119 202
120 - $attachment_id = $request->get_param('attachment_id');
121 - if(!$attachment_id){
122 - return array("ok" => false, "message" => __( "Missing attachment id." ));
203 + if (!array_key_exists($id, $syncClasses)) {
204 + throw new \Exception(sprintf('Could not get process by id %s', $id));
205 + }
206 +
207 + return new \WP_REST_Response(array(
208 + 'ok' => true,
209 + 'data' => $syncClasses[$id]
210 + ));
211 + } catch (\Throwable $e) {
212 + return new \WP_Error('internal_server_error', $e->getMessage(), ['status' => 500]);
123 213 }
214 + }
124 215
125 - $attachment = get_post($attachment_id);
216 + /**
217 + * Run sync by processing class id
218 + *
219 + * @param \WP_REST_Request $request
220 + * @return \WP_Error|\WP_REST_Response
221 + */
222 + static public function syncRun(\WP_REST_Request $request) {
223 + try {
224 + if (!user_can(self::$tokenData->user_id, 'manage_options')) {
225 + return new \WP_Error('not_allowed', 'Sorry, you are not allowed to perform this action', ['status' => 403]);
226 + }
126 227
127 - if(!$attachment){
128 - return array("ok" => false, "message" => __( "Wrong attachment id." ));
129 - }
228 + $params = wp_parse_args($request->get_params(), [
229 + 'id' => null,
230 + 'limit' => null,
231 + 'order' => null,
232 + ]);
130 233
131 - $item = self::mediaMapping($attachment);
234 + if (empty($params['id']) || !class_exists($params['id'])) {
235 + throw new \Exception(sprintf('Processing class not found: %s', $params['id']));
236 + }
132 237
133 - return array(
134 - "ok" => true,
135 - "message" => "getMediaItem endpoint.",
136 - "mediaItem" => $item
137 - );
238 + $processingClass = $params['id'];
138 239
240 + return new \WP_REST_Response(array(
241 + 'ok' => $processingClass::instance()->start($params)
242 + ));
243 + } catch (\Throwable $e) {
244 + return new \WP_Error('internal_server_error', $e->getMessage(), ['status' => 500]);
245 + }
139 246 }
140 247
141 248 /**
142 - * Handle Auth.
143 - *
144 - * @param $request
145 - * @return bool
249 + * Stop sync by processing class id
250 + *
251 + * @param \WP_REST_Request $request
252 + * @return \WP_Error|\WP_REST_Response
146 253 */
147 - static public function authRequest( $request = false ) {
254 + static public function syncStop(\WP_REST_Request $request) {
255 + try {
256 + if (!user_can(self::$tokenData->user_id, 'manage_options')) {
257 + return new \WP_Error('not_allowed', 'Sorry, you are not allowed to perform this action', ['status' => 403]);
258 + }
148 259
149 - //die( '<pre>' . print_r($request->get_param('key'),true) . '</pre>' );
260 + $params = wp_parse_args($request->get_params(), [
261 + 'id' => null
262 + ]);
150 263
151 - if( !$request ) {
152 - return false;
153 - }
264 + if (empty($params['id']) || !class_exists($params['id'])) {
265 + throw new \Exception(sprintf('Processing class not found: %s', $params['id']));
266 + }
154 267
155 - if( !$request->get_param('key') ) {
156 - return false;
157 - }
268 + $processingClass = $params['id'];
158 269
159 - $settings = apply_filters('stateless::get_settings', array());
160 -
161 - if( !$settings[ 'api_key' ] ) {
162 - return false;
270 + return new \WP_REST_Response(array(
271 + 'ok' => $processingClass::instance()->stop()
272 + ));
273 + } catch (\Throwable $e) {
274 + return new \WP_Error('internal_server_error', $e->getMessage(), ['status' => 500]);
163 275 }
276 + }
164 277
165 - if( $request->get_param('key') !== $settings[ 'api_key' ] ) {
166 - return false;
278 + /**
279 + * Batch Status Endpoint.
280 + *
281 + * @param \WP_REST_Request $request
282 + * @return \WP_REST_Response
283 + */
284 + static public function batchState(\WP_REST_Request $request) {
285 + try {
286 + return new \WP_REST_Response(array(
287 + 'ok' => true,
288 + 'data' => apply_filters('wp_stateless_batch_state', [], $request->get_params()),
289 + ));
290 + } catch (\Throwable $e) {
291 + return new \WP_Error('internal_server_error', $e->getMessage(), ['status' => 500]);
167 292 }
168 -
169 - return true;
170 -
171 -
172 293 }
173 294
174 295 /**
175 - * Check blog param and switch to requested blog
176 - *
177 - * @param bool $request
178 - * @return bool
296 + * Batch action (start/pause/resume)
297 + *
298 + * @param \WP_REST_Request $request
299 + * @return \WP_Error|\WP_REST_Response
179 300 */
180 - static public function switchBlog( $request = false ){
301 + static public function batchAction(\WP_REST_Request $request) {
302 + try {
303 + if (!user_can(self::$tokenData->user_id, 'manage_options')) {
304 + return new \WP_Error('not_allowed', 'Sorry, you are not allowed to perform this action', ['status' => 403]);
305 + }
181 306
182 - if(!is_multisite()){
183 - return true;
184 - }
307 + wp_set_current_user(self::$tokenData->user_id);
185 308
186 - if( !$request ) {
187 - return false;
188 - }
309 + $params = wp_parse_args($request->get_params(), [
310 + 'action' => '',
311 + ]);
189 312
190 - $blog_id = $request->get_param('blog');
191 - if( !$blog_id ) {
192 - return false;
193 - }
313 + if ( empty($params['action']) ) {
314 + throw new \Exception('Batch action not set');
315 + }
194 316
195 - $current_blog_id = get_current_blog_id();
196 - if($current_blog_id == $blog_id){
197 - return true;
198 - }
317 + $action = $params['action'];
199 318
200 - return switch_to_blog( $blog_id );
201 - }
319 + $data = apply_filters("wp_stateless_batch_action_$action", [], $params);
202 320
203 - /**
204 - * Applying mapping for media item
205 - *
206 - * @param $image
207 - * @return array
208 - */
209 - static private function mediaMapping($image){
321 + $data = array_merge(
322 + $data,
323 + apply_filters("wp_stateless_batch_state", [], ['force_migrations' => true]),
324 + );
210 325
211 - if(!$image){
212 - return array();
326 + return new \WP_REST_Response(array(
327 + 'data' => $data,
328 + ));
329 + } catch (\Throwable $e) {
330 + return new \WP_Error('internal_server_error', $e->getMessage(), ['status' => 500]);
213 331 }
214 -
215 - return array(
216 - 'attachment_id' => $image->ID,
217 - 'date_create' => $image->post_date,
218 - 'parent' => $image->post_parent,
219 - 'link' => wp_get_attachment_url($image->ID),
220 - 'title' => $image->post_title,
221 - 'description' => $image->post_content,
222 - 'thumbnail' => wp_get_attachment_image_src($image->ID)[0]
223 - );
224 332 }
225 -
226 333 }
227 -
228 334 }
229 -
230 335 }