PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.8.13
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.8.13
1.8.13 1.8.12.3 1.8.12.2 1.8.12.1 1.8.12 1.8.11.3 1.8.11.2 1.8.11.1 1.8.11 1.6.6 1.6.60 1.6.7 1.6.8 1.6.9 1.7.0 1.7.0.1 1.7.0.11 1.7.0.12 1.7.0.14 1.7.0.2 1.7.0.3 1.7.0.5 1.7.0.6 1.7.0.7 1.7.0.9 All 211 releases
charitable / includes / square / admin / class-charitable-square-connection.php

class-charitable-square-connection.php in Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) 1.8.13, at includes/square/admin/class-charitable-square-connection.php

625 lines 12.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * The class responsible for adding & saving extra settings in the Charitable admin.
4 *
5 * @package Charitable Square/Classes/Charitable_Square_Connection
6 * @author David Bisset
7 * @copyright Copyright (c) 2021-2022, WP Charitable LLC
8 * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
9 * @since 1.8.7
10 */
11
12 // Exit if accessed directly.
13 if ( ! defined( 'ABSPATH' ) ) {
14 exit;
15 }
16
17 if ( ! class_exists( 'Charitable_Square_Connection' ) ) :
18
19 /**
20 * Charitable_Square_Connection
21 *
22 * @since 1.8.7
23 */
24 class Charitable_Square_Connection {
25
26 /**
27 * Valid connection status.
28 *
29 * @since 1.8.7
30 */
31 const STATUS_VALID = 'valid';
32
33 /**
34 * Invalid connection status.
35 *
36 * @since 1.8.7
37 */
38 const STATUS_INVALID = 'invalid';
39
40 /**
41 * Determine if a connection for production mode.
42 *
43 * @since 1.8.7
44 *
45 * @var bool
46 */
47 private $live_mode;
48
49 /**
50 * Access token.
51 *
52 * @since 1.8.7
53 *
54 * @var string
55 */
56 private $access_token;
57
58 /**
59 * Refresh token.
60 *
61 * @since 1.8.7
62 *
63 * @var string
64 */
65 private $refresh_token;
66
67 /**
68 * Square-issued ID of an application.
69 *
70 * @since 1.8.7
71 *
72 * @var string
73 */
74 private $client_id;
75
76 /**
77 * Square-issued ID of the merchant.
78 *
79 * @since 1.8.7
80 *
81 * @var string
82 */
83 private $merchant_id;
84
85 /**
86 * Currency associated with a merchant account.
87 *
88 * @since 1.8.7
89 *
90 * @var string
91 */
92 private $currency;
93
94 /**
95 * Connection status.
96 *
97 * @since 1.8.7
98 *
99 * @var string
100 */
101 private $status;
102
103 /**
104 * Date when tokens should be renewed.
105 *
106 * @since 1.8.7
107 *
108 * @var int
109 */
110 private $renew_at;
111
112 /**
113 * Determine if connection tokens are encrypted.
114 *
115 * @since 1.8.7
116 *
117 * @var bool
118 */
119 private $encrypted;
120
121 /**
122 * Determine if scopes were updated.
123 *
124 * @since 1.8.7
125 *
126 * @var int
127 */
128 private $scopes_updated = 0;
129
130 /**
131 * Connection constructor.
132 *
133 * @since 1.8.7
134 *
135 * @param array $data Connection data.
136 * @param bool $encrypted Optional. Default true. Use false when connection tokens were not encrypted.
137 */
138 public function __construct( array $data, bool $encrypted = true ) {
139
140 $data = (array) $data;
141 $status = self::STATUS_VALID;
142
143 if ( ! empty( $data['access_token'] ) ) {
144 $this->access_token = $data['access_token'];
145 }
146
147 if ( ! empty( $data['refresh_token'] ) ) {
148 $this->refresh_token = $data['refresh_token'];
149 }
150
151 if ( ! empty( $data['client_id'] ) ) {
152 $this->client_id = $data['client_id'];
153 }
154
155 if ( ! empty( $data['merchant_id'] ) ) {
156 $this->merchant_id = $data['merchant_id'];
157 }
158
159 if ( ! empty( $data['scopes_updated'] ) ) {
160 $this->scopes_updated = $data['scopes_updated'];
161 }
162
163 // We must have an access token, client_id, merchant_id and refresh token to be valid.
164 if ( empty( $data['access_token'] ) || empty( $data['client_id'] ) || empty( $data['merchant_id'] ) || empty( $data['refresh_token'] ) ) {
165 $status = self::STATUS_INVALID;
166 }
167
168 $this->set_status( empty( $data['status'] ) ? $status : $data['status'] );
169
170 $this->currency = empty( $data['currency'] ) ? '' : strtoupper( (string) $data['currency'] );
171 $this->renew_at = empty( $data['renew_at'] ) ? time() : (int) $data['renew_at'];
172 $this->live_mode = ! empty( $data['live_mode'] );
173 $this->encrypted = (bool) $encrypted;
174 }
175
176 /**
177 * Retrieve a connection instance if it exists.
178 *
179 * @since 1.8.7
180 *
181 * @param string $mode Square mode.
182 * @param bool $encrypted Optional. Default true. Use false when connection tokens were not encrypted.
183 *
184 * @return Connection|null
185 */
186 public static function get( string $mode = '', bool $encrypted = true ) {
187
188 $settings = get_option( 'charitable_settings' );
189
190 if ( '' === $mode ) {
191 $mode = charitable_get_option( 'test_mode' ) ? 'test' : 'live';
192 }
193
194 if ( empty( $settings['gateways_square'][ $mode ] ) ) {
195 return null;
196 }
197
198 return new self( (array) $settings['gateways_square'][ $mode ], $encrypted );
199 }
200
201 /**
202 * Save connection data into DB.
203 *
204 * @since 1.8.7
205 */
206 public function save() {
207 global $wpdb;
208
209 $settings = get_option( 'charitable_settings' );
210
211 $settings['gateways_square'][ $this->get_mode() ] = $this->get_data();
212
213 $data = array(
214 'option_value' => maybe_serialize( $settings ),
215 );
216
217 $where = array(
218 'option_name' => 'charitable_settings',
219 );
220
221 $ret = $wpdb->update( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
222 $wpdb->options,
223 $data,
224 $where,
225 array( '%s' ),
226 array( '%s' )
227 );
228
229 return $ret;
230 }
231
232 /**
233 * Delete connection data from DB.
234 *
235 * @since 1.8.7
236 */
237 public function delete() {
238
239 $connections = (array) get_option( 'charitable_square_connections', array() );
240 unset( $connections[ $this->get_mode() ] );
241 empty( $connections ) ? delete_option( 'charitable_square_connections' ) : update_option( 'charitable_square_connections', $connections );
242
243 $settings = get_option( 'charitable_settings' );
244 unset( $settings['gateways_square'][ $this->get_mode() ] );
245 $ret = update_option( 'charitable_settings', $settings );
246
247 return $ret;
248 }
249
250 /**
251 * Revoke tokens from DB.
252 *
253 * @since 1.8.7
254 */
255 public function revoke_tokens() {
256
257 $connections = (array) get_option( 'charitable_square_connections', array() );
258 $mode = $this->get_mode();
259
260 $connections[ $mode ] = $this->get_data();
261 $connections[ $mode ]['access_token'] = '';
262 $connections[ $mode ]['refresh_token'] = '';
263
264 update_option( 'charitable_square_connections', $connections );
265 }
266
267 /**
268 * Retrieve true if a connection for production mode.
269 *
270 * @since 1.8.7
271 *
272 * @return bool
273 */
274 public function get_live_mode(): bool {
275
276 return $this->live_mode;
277 }
278
279 /**
280 * Retrieve a connection mode.
281 *
282 * @since 1.8.7
283 *
284 * @return string
285 */
286 public function get_mode(): string {
287
288 return $this->live_mode ? 'live' : 'test';
289 }
290
291 /**
292 * Retrieve an un-encrypted access token.
293 *
294 * @since 1.8.7
295 *
296 * @return string
297 */
298 public function get_access_token(): string {
299 if ( empty( $this->access_token ) ) {
300 return '';
301 }
302
303 return $this->encrypted ? charitable_crypto_decrypt( $this->access_token ) : $this->access_token;
304 }
305
306 /**
307 * Retrieve an un-encrypted refresh token.
308 *
309 * @since 1.8.7
310 *
311 * @return string
312 */
313 public function get_refresh_token(): string {
314
315 return $this->encrypted ? charitable_crypto_decrypt( $this->refresh_token ) : $this->refresh_token;
316 }
317
318 /**
319 * Retrieve a client ID.
320 *
321 * @since 1.8.7
322 *
323 * @return string
324 */
325 public function get_client_id(): string {
326
327 if ( empty( $this->client_id ) ) {
328 return '';
329 }
330
331 return $this->client_id;
332 }
333
334 /**
335 * Retrieve an ID of the authorized merchant.
336 *
337 * @since 1.8.7
338 *
339 * @return string
340 */
341 public function get_merchant_id(): string {
342
343 if ( empty( $this->merchant_id ) ) {
344 return '';
345 }
346
347 return $this->merchant_id;
348 }
349
350 /**
351 * Retrieve a currency code of the authorized merchant.
352 *
353 * @since 1.8.7
354 *
355 * @return string
356 */
357 public function get_currency(): string {
358
359 if ( empty( $this->currency ) ) {
360 return '';
361 }
362
363 return $this->currency;
364 }
365
366 /**
367 * Set a currency code.
368 *
369 * @since 1.8.7
370 *
371 * @param string $code Currency code.
372 *
373 * @return Connection
374 */
375 public function set_currency( string $code ) {
376
377 $this->currency = strtoupper( $code );
378
379 return $this;
380 }
381
382 /**
383 * Retrieve a connection status.
384 *
385 * @since 1.8.7
386 *
387 * @return string
388 */
389 public function get_status(): string {
390
391 return $this->status;
392 }
393
394 /**
395 * Set a connection status if it valid.
396 *
397 * @since 1.8.7
398 *
399 * @param string $status The connection status.
400 *
401 * @return Connection
402 */
403 public function set_status( string $status ) {
404
405 if ( in_array( $status, $this->get_statuses(), true ) ) {
406 $this->status = $status;
407 }
408
409 return $this;
410 }
411
412 /**
413 * Retrieve a renewal timestamp.
414 *
415 * @since 1.8.7
416 *
417 * @return int
418 */
419 public function get_renew_at(): int {
420
421 return $this->renew_at;
422 }
423
424 /**
425 * Set/update a renewal timestamp.
426 *
427 * @since 1.8.7
428 *
429 * @return Connection
430 */
431 public function set_renew_at() {
432
433 // Tokens must automatically renew every 7 days or less.
434 $this->renew_at = time() + wp_rand( 5, 8 ) * DAY_IN_SECONDS;
435
436 return $this;
437 }
438
439 /**
440 * Retrieve a scopes updated timestamp.
441 *
442 * @since 1.8.7
443 *
444 * @return int
445 */
446 public function get_scopes_updated(): int {
447
448 return $this->scopes_updated;
449 }
450
451 /**
452 * Set/update a scopes updated timestamp.
453 *
454 * @since 1.8.7
455 *
456 * @return Connection
457 */
458 public function set_scopes_updated() {
459
460 $this->scopes_updated = time();
461
462 return $this;
463 }
464
465 /**
466 * Encrypt tokens, if it needed.
467 *
468 * @since 1.8.7
469 *
470 * @return Connection
471 */
472 public function encrypt_tokens() {
473
474 // Bail if tokens have already encrypted.
475 if ( $this->encrypted ) {
476 return $this;
477 }
478
479 // Bail if tokens are not passed.
480 if ( empty( $this->access_token ) || empty( $this->refresh_token ) ) {
481 return $this;
482 }
483
484 // Prepare encrypted tokens.
485 $encrypted_access_token = charitable_crypto_encrypt( $this->access_token );
486 $encrypted_refresh_token = charitable_crypto_encrypt( $this->refresh_token );
487
488 // Bail if encrypted tokens are invalid.
489 if ( empty( $encrypted_access_token ) || empty( $encrypted_refresh_token ) ) {
490 return $this;
491 }
492
493 $this->encrypted = true;
494 $this->access_token = $encrypted_access_token;
495 $this->refresh_token = $encrypted_refresh_token;
496
497 return $this;
498 }
499
500 /**
501 * Retrieve available statuses.
502 *
503 * @since 1.8.7
504 *
505 * @return array
506 */
507 private function get_statuses(): array {
508
509 return array( self::STATUS_VALID, self::STATUS_INVALID );
510 }
511
512 /**
513 * Retrieve a connection in array format, simply like `toArray` method.
514 *
515 * @since 1.8.7
516 *
517 * @return array
518 */
519 private function get_data(): array {
520
521 return array(
522 'live_mode' => $this->live_mode,
523 'access_token' => $this->access_token,
524 'refresh_token' => $this->refresh_token,
525 'client_id' => $this->client_id,
526 'merchant_id' => $this->merchant_id,
527 'currency' => $this->currency,
528 'status' => $this->status,
529 'renew_at' => $this->renew_at,
530 'scopes_updated' => $this->scopes_updated,
531 );
532 }
533
534 /**
535 * Determine whether connection tokens is encrypted.
536 *
537 * @since 1.8.7
538 *
539 * @return bool
540 */
541 private function is_encrypted(): bool {
542
543 return $this->encrypted;
544 }
545
546 /**
547 * Determine whether a connection is configured fully.
548 *
549 * @since 1.8.7
550 *
551 * @return bool
552 */
553 public function is_configured(): bool {
554
555 return ! empty( $this->get_access_token() ) && ! empty( $this->get_refresh_token() ) && ! empty( $this->client_id ) && ! empty( $this->merchant_id );
556 }
557
558 /**
559 * Determine whether a connection is expired.
560 *
561 * @since 1.8.7
562 *
563 * @return bool
564 */
565 public function is_expired(): bool {
566
567 return ( $this->renew_at - time() ) < HOUR_IN_SECONDS;
568 }
569
570 /**
571 * Determine whether a connection currency is matched with Charitable currency.
572 *
573 * @since 1.8.7
574 *
575 * @return bool
576 */
577 public function is_currency_matched(): bool {
578
579 if ( empty( $this->currency ) ) {
580 $currency = get_option( 'charitable_square_location_currency_' . $this->get_mode() );
581 $this->currency = $currency;
582 }
583
584 return $this->currency === strtoupper( charitable_get_currency() );
585 }
586
587 /**
588 * Determine whether a connection is valid.
589 *
590 * @since 1.8.7
591 *
592 * @return bool
593 */
594 public function is_valid(): bool {
595
596 return $this->get_status() === self::STATUS_VALID;
597 }
598
599 /**
600 * Determine whether a connection is ready for save.
601 *
602 * @since 1.8.7
603 *
604 * @return bool
605 */
606 public function is_saveable(): bool {
607
608 return $this->is_configured() && ! $this->is_expired() && $this->is_encrypted();
609 }
610
611 /**
612 * Determine whether a connection is ready for use.
613 *
614 * @since 1.8.7
615 *
616 * @return bool
617 */
618 public function is_usable(): bool {
619
620 return $this->is_configured() && $this->is_valid() && $this->is_currency_matched();
621 }
622 }
623
624 endif;
625