PluginProbe
AutomatorWP – No-Code Workflow Automation, Integration & Webhooks Plugin, now with AI / 5.8.5
AutomatorWP – No-Code Workflow Automation, Integration & Webhooks Plugin, now with AI v5.8.5
6.0.3 6.0.2 6.0.1 6.0.0 5.8.6 5.8.5 5.8.4 5.8.3 5.8.2 5.8.1 5.8.0 5.7.9.2 5.7.9.1 5.7.8 5.7.9 5.7.6 5.7.7 5.7.5 5.7.4 5.7.3 5.7.2 5.7.1 trunk 5.6.0 5.6.1 All 34 releases
automatorwp / integrations / bluesky / includes / functions.php

functions.php in AutomatorWP – No-Code Workflow Automation, Integration & Webhooks Plugin, now with AI 5.8.5, at integrations/bluesky/includes/functions.php

486 lines 12.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Helper function to get the Bluesky API parameters
5 *
6 * @since 1.0.0
7 *
8 * @return array|false
9 */
10 function automatorwp_bluesky_get_api() {
11
12 $user_handle = automatorwp_bluesky_get_option( 'user_handle', '' );
13 $user_password = automatorwp_bluesky_get_option( 'user_password', '' );
14 $base_url = 'https://bsky.social/xrpc';
15 $chat_url = 'https://api.bsky.chat/xrpc';
16
17 if( empty( $user_handle ) || empty( $user_password ) ) {
18 return false;
19 }
20
21 return array(
22 'user_handle' => $user_handle,
23 'user_password' => $user_password,
24 'base_url' => $base_url,
25 'chat_url' => $chat_url,
26 );
27 }
28
29 /**
30 * Function to check the user credentials with a POST request to the Bluesky API
31 * Also saving the refresh token and user DID
32 *
33 * @param mixed $credentials - User credentials
34 *
35 * @return bool - True if the credentials are correct, false otherwise
36 */
37 function automatorwp_bluesky_check_settings_status( $credentials ) {
38
39 $return = false;
40
41 // Preparar los datos en formato JSON
42 $body = json_encode( array(
43 'identifier' => $credentials['user_handle'],
44 'password' => $credentials['user_password'],
45 ) );
46
47 // Arguments for the POST request
48 $args = array(
49 'body' => $body,
50 'headers' => array(
51 'Content-Type' => 'application/json',
52 ),
53 'timeout' => 20,
54 'data_format' => 'body',
55 );
56
57
58 // POST request to the Bluesky API
59 $response = wp_remote_post( 'https://bsky.social/xrpc/com.atproto.server.createSession', $args );
60
61 $status_code = wp_remote_retrieve_response_code( $response );
62
63 if ( 200 !== $status_code ) {
64 wp_send_json_error( array( 'message' => __( 'Please, check your API credentials', 'automatorwp' ) ) );
65 return $return;
66 } else {
67 $data = json_decode( wp_remote_retrieve_body( $response ), true );
68
69 // Check if the response has the refresh token
70 if ( isset( $data['refreshJwt'] ) ) {
71 // Update refresh token and user did
72 update_option( 'bluesky_refresh_token', $data['refreshJwt'] );
73 update_option( 'bluesky_did', $data['did'] );
74 $return = true;
75 } else {
76 wp_send_json_error( array( 'message' => __( 'Refresh token not found in the response.', 'automatorwp' ) ) );
77 return $return;
78 }
79 $return = true;
80 }
81
82 return $return;
83 }
84
85 /**
86 * Get access token from Bluesky and save the new refresh token
87 *
88 * @return string|false - Access token
89 */
90 function automatorwp_bluesky_get_access_token( ) {
91 $api = automatorwp_bluesky_get_api();
92
93 $refresh_token = get_option( 'bluesky_refresh_token' );
94
95 if ( !$refresh_token || !$api ) {
96 return false;
97 }
98
99 $args = array(
100 'headers' => array(
101 'Content-Type' => 'application/json',
102 'Authorization' => 'Bearer ' . $refresh_token,
103 ),
104 'timeout' => 20,
105 'data_format' => 'body',
106 );
107
108 $response = wp_remote_post( $api["base_url"] . '/com.atproto.server.refreshSession', $args );
109
110 $status_code = wp_remote_retrieve_response_code( $response );
111
112 if ( 200 !== $status_code ) {
113 return false;
114 }
115
116 $data = json_decode( wp_remote_retrieve_body( $response ), true );
117
118 if ( isset( $data['accessJwt'] ) ) {
119 if ( isset( $data['refreshJwt'] ) ) {
120 update_option( 'bluesky_refresh_token', $data['refreshJwt'] );
121 }
122 return $data['accessJwt'];
123 } else {
124 return false;
125 }
126 }
127
128 /**
129 * Add post to bluesky
130 *
131 * @since 1.0.0
132 *
133 * @param string $post_content Content of the post
134 *
135 * @return int - Status code
136 */
137 function automatorwp_bluesky_create_post( $post_content ) {
138
139 $api = automatorwp_bluesky_get_api();
140
141 if( ! $api ) {
142 return;
143 }
144
145 $access_token = automatorwp_bluesky_get_access_token();
146
147 if ( ! $access_token ) {
148 return;
149 }
150
151 $date = new DateTime( 'now', new DateTimeZone('UTC'));
152 $created_at = $date->format('Y-m-d\TH:i:s\Z');
153
154 $body = array(
155 'repo' => $api['user_handle'],
156 'collection'=> 'app.bsky.feed.post',
157 'record' => array(
158 'text' => $post_content,
159 'createdAt' => $created_at,
160 ),
161 );
162
163 $args = array(
164 'body' => json_encode( $body ),
165 'headers' => array(
166 'Content-Type' => 'application/json',
167 'Authorization' => 'Bearer ' . $access_token,
168 ),
169 'timeout' => 20,
170 );
171
172 $response = wp_remote_post( $api['base_url'] . '/com.atproto.repo.createRecord', $args );
173
174 $status_code = wp_remote_retrieve_response_code( $response );
175
176 return $status_code;
177 }
178
179 /**
180 * Get user DID from bluesky
181 *
182 * @param mixed $handle - User handle
183 * @param mixed $access_token - Access token
184 *
185 * @return string|false - User DID
186 */
187 function automatorwp_bluesky_get_user_did($handle, $access_token) {
188 $api = automatorwp_bluesky_get_api();
189
190 if (!$handle || !$access_token) {
191 return false;
192 }
193
194 $args = array(
195 'headers' => array(
196 'Content-Type' => 'application/json',
197 'Authorization' => 'Bearer ' . $access_token,
198 ),
199 'timeout' => 20,
200 );
201
202 $response = wp_remote_get( $api["base_url"] . "/app.bsky.actor.getProfile?actor=" . $handle, $args );
203
204 if ( is_wp_error( $response ) ) {
205 return false;
206 }
207
208 $status_code = wp_remote_retrieve_response_code( $response );
209
210 if ($status_code != 200) {
211 return false;
212 }
213
214 $data = json_decode( wp_remote_retrieve_body( $response ), true );
215
216 if ( isset( $data['did'] ) ) {
217 return $data['did'];
218 }
219 }
220
221 /**
222 * Get conversation ID from bluesky
223 *
224 * @param mixed $to_handle - User handle to send the message
225 * @param mixed $access_token - Access token
226 *
227 * @return string|false - Convo ID
228 */
229 function automatorwp_bluesky_get_convo($to_handle, $access_token) {
230 $api = automatorwp_bluesky_get_api();
231 $from_did = get_option( 'bluesky_did' );
232 $to_did = automatorwp_bluesky_get_user_did( $to_handle, $access_token );
233
234 if (!$to_did || !$from_did) {
235 return false;
236 }
237
238 $url = $api["chat_url"] . '/chat.bsky.convo.getConvoForMembers?members=' . $from_did . '&members=' . $to_did;
239
240 $args = array(
241 'headers' => array(
242 'Content-Type' => 'application/json',
243 'Authorization' => 'Bearer ' . $access_token,
244 ),
245 'timeout' => 20,
246 );
247
248 $response = wp_remote_get( $url, $args );
249
250 if ( is_wp_error( $response ) ) {
251 $error_message = $response->get_error_message();
252 return false;
253 }
254
255 $status_code = wp_remote_retrieve_response_code( $response );
256
257 if ( 200 !== $status_code ) {
258 return false;
259 }
260
261 $body = wp_remote_retrieve_body( $response );
262 $data = json_decode( $body, true );
263
264 if ( null === $data ) {
265 return false;
266 }
267
268 // Check if data is array
269 if ( !is_array(($data)) ) {
270 return false;
271 }
272
273 if (isset($data['convo']) && isset($data['convo']['id'])) {
274 return $data['convo']['id'];
275 } else {
276 return false;
277 }
278 }
279
280 /**
281 * Send a menssage on bluesky
282 *
283 * @since 1.0.0
284 *
285 * @param string $message_content Content of the message
286 * @param string $to_user User handle to send the message
287 *
288 * @return int - Status code
289 */
290 function automatorwp_bluesky_send_message( $message_content, $to_user ) {
291
292 $api = automatorwp_bluesky_get_api();
293
294 if( ! $api ) {
295 return;
296 }
297
298 $access_token = automatorwp_bluesky_get_access_token();
299
300 if ( !$access_token ) {
301 return;
302 }
303
304 $convo = automatorwp_bluesky_get_convo($to_user, $access_token);
305
306 if (!$convo) {
307 return;
308 }
309
310 $body = array(
311 'convoId' => $convo,
312 'message' => array(
313 'text' => $message_content,
314 ),
315 );
316
317 $args = array(
318 'body' => json_encode( $body ),
319 'headers' => array(
320 'Content-Type' => 'application/json',
321 'Authorization' => 'Bearer ' . $access_token,
322 ),
323 'timeout' => 20,
324 );
325
326 $response = wp_remote_post( $api["chat_url"] . '/chat.bsky.convo.sendMessage', $args );
327
328 $status_code = wp_remote_retrieve_response_code( $response );
329
330 return $status_code;
331 }
332
333 /**
334 * Function to download an image from URI and upload it to bluesky
335 *
336 * @param mixed $post_image - Image URI
337 * @param mixed $access_token - Access token
338 *
339 * @return object|false - Blob object
340 */
341 function automatorwp_bluesky_upload_image_to_blob( $post_image, $access_token ) {
342 $api = automatorwp_bluesky_get_api();
343
344 if (!$post_image || !$access_token || !$api) {
345 return;
346 }
347
348 $image_response = wp_remote_get( $post_image, array( 'timeout' => 20 ) );
349
350 if ( is_wp_error( $image_response ) ) {
351 return;
352 }
353
354 $image_data = wp_remote_retrieve_body( $image_response );
355
356 if ( empty( $image_data ) ) {
357 return;
358 }
359
360 $image_size = strlen( $image_data );
361 // 1,000,000 bytes limit
362 if ( $image_size > 1000000 ) {
363 return;
364 }
365
366 $image_mime = wp_remote_retrieve_header( $image_response, 'content-type' );
367
368 if ( empty( $image_mime ) ) {
369 $image_mime = 'image/jpeg';
370 }
371
372 $upload_args = array(
373 'body' => $image_data,
374 'headers' => array(
375 'Content-Type' => $image_mime,
376 'Authorization' => 'Bearer ' . $access_token,
377 ),
378 'timeout' => 20,
379 );
380
381 $upload_response = wp_remote_post( $api['base_url'] . '/com.atproto.repo.uploadBlob', $upload_args );
382 if ( is_wp_error( $upload_response ) ) {
383 return $upload_response;
384 }
385
386 $upload_body = wp_remote_retrieve_body( $upload_response );
387 $upload_data = json_decode( $upload_body, true );
388
389 if ( ! isset( $upload_data['blob'] ) ) {
390 return new WP_Error( 'upload_failed', 'Error uploading file.' );
391 }
392
393 $blob = $upload_data['blob'];
394
395 return $blob;
396 }
397
398 /**
399 * Create a post with an image on bluesky
400 *
401 * @since 1.0.0
402 *
403 * @param string $post_content Content of the post
404 * @param string $post_image Image uri
405 *
406 * @return int - Status code
407 */
408 function automatorwp_bluesky_create_post_with_image( $post_content, $image ) {
409
410 $api = automatorwp_bluesky_get_api();
411
412 if( ! $api ) {
413 return;
414 }
415
416 $access_token = automatorwp_bluesky_get_access_token();
417
418 if ( ! $access_token ) {
419 return;
420 }
421
422 $image_blob = automatorwp_bluesky_upload_image_to_blob( $image, $access_token );
423
424 if ( ! $image_blob ) {
425 return;
426 }
427
428 // Get current date in UTC
429 $date = new DateTime( 'now', new DateTimeZone('UTC'));
430 $created_at = $date->format('Y-m-d\TH:i:s\Z');
431
432 // Prepare data to send on post request
433 $embed = array(
434 '$type' => 'app.bsky.embed.images',
435 'images' => array(
436 array(
437 'image' => $image_blob,
438 'alt' => 'post image',
439 ),
440 ),
441 );
442
443 $body = array(
444 'repo' => $api['user_handle'],
445 'collection'=> 'app.bsky.feed.post',
446 'record' => array(
447 '$type' => "app.bsky.feed.post",
448 'text' => $post_content,
449 'createdAt' => $created_at,
450 'embed' => $embed,
451 ),
452 );
453
454 $args = array(
455 'body' => json_encode( $body ),
456 'headers' => array(
457 'Content-Type' => 'application/json',
458 'Authorization' => 'Bearer ' . $access_token,
459 ),
460 'timeout' => 20,
461 );
462
463 $response = wp_remote_post( $api['base_url'] . '/com.atproto.repo.createRecord', $args );
464
465 $status_code = wp_remote_retrieve_response_code( $response );
466
467 return $status_code;
468 }
469
470 /**
471 * Sanitize name account
472 *
473 * @param string $account The name account
474 *
475 * @since 1.0.0
476 *
477 * @return string|false|WP_Error
478 */
479 function automatorwp_bluesky_validate_name_account( $account ) {
480
481 // Filter the characters from string
482 $account = preg_replace('/[^a-zA-Z0-9.]/', '', $account);
483
484 return $account;
485
486 }