PluginProbe ʕ •ᴥ•ʔ
Backup Migration / 2.1.7
Backup Migration v2.1.7
2.1.7 2.1.6 2.1.5.2 trunk 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.6.1 1.4.7 1.4.8 1.4.9 1.4.9.1 2.0.0 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.5.1
backup-backup / analyst / src / Account / Account.php
backup-backup / analyst / src / Account Last commit date
Account.php 2 weeks ago AccountData.php 2 weeks ago AccountDataFactory.php 2 weeks ago
Account.php
633 lines
1 <?php
2
3
4 namespace Account;
5
6 use Analyst\Analyst;
7 use Analyst\ApiRequestor;
8 use Analyst\Cache\DatabaseCache;
9 use Analyst\Collector;
10 use Analyst\Http\Requests\ActivateRequest;
11 use Analyst\Http\Requests\DeactivateRequest;
12 use Analyst\Http\Requests\InstallRequest;
13 use Analyst\Http\Requests\OptInRequest;
14 use Analyst\Http\Requests\OptOutRequest;
15 use Analyst\Http\Requests\UninstallRequest;
16 use Analyst\Notices\Notice;
17 use Analyst\Notices\NoticeFactory;
18 use Analyst\Contracts\TrackerContract;
19 use Analyst\Contracts\RequestorContract;
20
21 if ( ! defined( 'ABSPATH' ) ) exit;
22
23 /**
24 * Class Account
25 *
26 * This is plugin's account object
27 */
28 class Account implements TrackerContract
29 {
30 /**
31 * Account id
32 *
33 * @var string
34 */
35 protected $id;
36
37 /**
38 * Basename of plugin
39 *
40 * @var string
41 */
42 protected $path;
43
44 /**
45 * Whether plugin is active or not
46 *
47 * @var bool
48 */
49 protected $isInstalled = false;
50
51 /**
52 * Is user sign in for data tracking
53 *
54 * @var bool
55 */
56 protected $isOptedIn = false;
57
58 /**
59 * Is user accepted permissions grant
60 * for collection site data
61 *
62 * @var bool
63 */
64 protected $isSigned = false;
65
66 /**
67 * Is user ever resolved install modal window?
68 *
69 * @var bool
70 */
71 protected $isInstallResolved = false;
72
73 /**
74 * Public secret code
75 *
76 * @var string
77 */
78 protected $clientSecret;
79
80 /**
81 * @var AccountData
82 */
83 protected $data;
84
85 /**
86 * Base plugin path
87 *
88 * @var string
89 */
90 protected $basePluginPath;
91
92 /**
93 * @var RequestorContract
94 */
95 protected $requestor;
96
97 /**
98 * @var Collector
99 */
100 protected $collector;
101
102 /**
103 * Account constructor.
104 * @param $id
105 * @param $secret
106 * @param $baseDir
107 */
108 public function __construct($id, $secret, $baseDir)
109 {
110 $this->id = $id;
111 $this->clientSecret = $secret;
112
113 $this->path = $baseDir;
114
115 $this->basePluginPath = plugin_basename($baseDir);
116 }
117
118 /**
119 * @return string
120 */
121 public function getPath()
122 {
123 return $this->path;
124 }
125
126 /**
127 * @param string $path
128 */
129 public function setPath($path)
130 {
131 $this->data->setPath($path);
132
133 $this->path = $path;
134 }
135
136 /**
137 * @return bool
138 */
139 public function isOptedIn()
140 {
141 return $this->isOptedIn;
142 }
143
144 /**
145 * @param bool $isOptedIn
146 */
147 public function setIsOptedIn($isOptedIn)
148 {
149 $this->data->setIsOptedIn($isOptedIn);
150
151 $this->isOptedIn = $isOptedIn;
152 }
153
154 /**
155 * Whether plugin is active
156 *
157 * @return bool
158 */
159 public function isActive()
160 {
161 return is_plugin_active($this->path);
162 }
163
164 /**
165 * @param string $id
166 */
167 public function setId($id)
168 {
169 $this->id = $id;
170 }
171
172 /**
173 * @return string
174 */
175 public function getId()
176 {
177 return $this->id;
178 }
179
180 /**
181 * @return bool
182 */
183 public function isInstalled()
184 {
185 return $this->isInstalled;
186 }
187
188 /**
189 * @param bool $isInstalled
190 */
191 public function setIsInstalled($isInstalled)
192 {
193 $this->data->setIsInstalled($isInstalled);
194
195 $this->isInstalled = $isInstalled;
196 }
197
198 protected function verifyNonceAndPerms() {
199
200 $capabilities = [
201 'activate_plugins',
202 'edit_plugins',
203 'install_plugins',
204 'update_plugins',
205 'delete_plugins',
206 'manage_network_plugins',
207 'upload_plugins'
208 ];
209
210 // Allow if has any of above permissions
211 $hasPerms = false;
212 foreach ($capabilities as $i => $cap) {
213 if (current_user_can($cap)) {
214 $hasPerms = true;
215 break;
216 }
217 }
218
219 if ($hasPerms == false) {
220 wp_send_json_error(['message' => 'no_permissions']);
221 die;
222 }
223
224 if (!isset($_POST['analyst_nonce']) || !wp_verify_nonce(sanitize_text_field($_POST['analyst_nonce']), 'analyst_opt_ajax_nonce')) {
225 wp_send_json_error(['message' => 'invalid_nonce']);
226 die;
227 }
228
229 }
230
231 /**
232 * Should register activation and deactivation
233 * event hooks
234 *
235 * @return void
236 */
237 public function registerHooks()
238 {
239 register_activation_hook($this->basePluginPath, [&$this, 'onActivePluginListener']);
240 register_uninstall_hook($this->basePluginPath, ['Account\Account', 'onUninstallPluginListener']);
241
242 $this->addFilter('plugin_action_links', [&$this, 'onRenderActionLinksHook']);
243
244 $this->addAjax('analyst_opt_in', [&$this, 'onOptInListener']);
245 $this->addAjax('analyst_opt_out', [&$this, 'onOptOutListener']);
246 $this->addAjax('analyst_plugin_deactivate', [&$this, 'onDeactivatePluginListener']);
247 $this->addAjax('analyst_install', [&$this, 'onInstallListener']);
248 $this->addAjax('analyst_skip_install', [&$this, 'onSkipInstallListener']);
249 $this->addAjax('analyst_install_verified', [&$this, 'onInstallVerifiedListener']);
250 }
251
252 /**
253 * Will fire when admin activates plugin
254 *
255 * @return void
256 */
257 public function onActivePluginListener()
258 {
259 if (!$this->isInstallResolved()) {
260 DatabaseCache::getInstance()->put('plugin_to_install', $this->id);
261 }
262
263 if (!$this->isAllowingLogging()) return;
264
265 ActivateRequest::make($this->collector, $this->id, $this->path)
266 ->execute($this->requestor);
267
268 $this->setIsInstalled(true);
269
270 AccountDataFactory::syncData();
271 }
272
273 /**
274 * Will fire when admin deactivates plugin
275 *
276 * @return void
277 */
278 public function onDeactivatePluginListener()
279 {
280 $this->verifyNonceAndPerms();
281
282 if (!$this->isAllowingLogging()) return;
283
284 $question = isset($_POST['question']) ? sanitize_text_field(stripslashes($_POST['question'])) : null;
285 $reason = isset($_POST['reason']) ? sanitize_text_field(stripslashes($_POST['reason'])) : null;
286
287 DeactivateRequest::make($this->collector, $this->id, $this->path, $question, $reason)
288 ->execute($this->requestor);
289
290 $this->setIsInstalled(false);
291
292 AccountDataFactory::syncData();
293
294 wp_send_json_success();
295 }
296
297 /**
298 * Will fire when user opted in
299 *
300 * @return void
301 */
302 public function onOptInListener()
303 {
304 $this->verifyNonceAndPerms();
305
306 OptInRequest::make($this->collector, $this->id, $this->path)->execute($this->requestor);
307
308 $this->setIsOptedIn(true);
309
310 AccountDataFactory::syncData();
311
312 wp_die();
313 }
314
315 /**
316 * Will fire when user opted out
317 *
318 * @return void
319 */
320 public function onOptOutListener()
321 {
322 $this->verifyNonceAndPerms();
323
324 OptOutRequest::make($this->collector, $this->id, $this->path)->execute($this->requestor);
325
326 $this->setIsOptedIn(false);
327
328 AccountDataFactory::syncData();
329
330 wp_send_json_success();
331 }
332
333 /**
334 * Will fire when user accept opt-in
335 * at first time
336 *
337 * @return void
338 */
339 public function onInstallListener()
340 {
341 $this->verifyNonceAndPerms();
342
343 $cache = DatabaseCache::getInstance();
344
345 // Set flag to true which indicates that install is resolved
346 // also remove install plugin id from cache
347 $this->setIsInstallResolved(true);
348 $cache->delete('plugin_to_install');
349
350 InstallRequest::make($this->collector, $this->id, $this->path)->execute($this->requestor);
351
352 $this->setIsSigned(true);
353
354 $this->setIsOptedIn(true);
355
356 $factory = NoticeFactory::instance();
357
358 $message = sprintf('Please confirm your email by clicking on the link we sent to %s. This makes sure you’re not a bot.', $this->collector->getGeneralEmailAddress());
359
360 $notificationId = uniqid();
361
362 $notice = Notice::make(
363 $notificationId,
364 $this->getId(),
365 $message,
366 $this->collector->getPluginName($this->path)
367 );
368
369 $factory->addNotice($notice);
370
371 AccountDataFactory::syncData();
372
373 // Set email confirmation notification id to cache
374 // se we can extract and remove it when user confirmed email
375 $cache->put(
376 sprintf('account_email_confirmation_%s', $this->getId()),
377 $notificationId
378 );
379
380 wp_send_json_success();
381 }
382
383 /**
384 * Will fire when user skipped installation
385 *
386 * @return void
387 */
388 public function onSkipInstallListener()
389 {
390 $this->verifyNonceAndPerms();
391
392 // Set flag to true which indicates that install is resolved
393 // also remove install plugin id from cache
394 $this->setIsInstallResolved(true);
395 DatabaseCache::getInstance()->delete('plugin_to_install');
396 }
397
398 /**
399 * Will fire when user delete plugin through admin panel.
400 * This action will happen if admin at least once
401 * activated the plugin.
402 *
403 * @return void
404 * @throws \Exception
405 */
406 public static function onUninstallPluginListener()
407 {
408 $factory = AccountDataFactory::instance();
409
410 $pluginFile = substr(current_filter(), strlen( 'uninstall_' ));
411
412 $account = $factory->getAccountDataByBasePath($pluginFile);
413
414 // If account somehow is not found, exit the execution
415 if (!$account) return;
416
417 $analyst = Analyst::getInstance();
418
419 $collector = new Collector($analyst);
420
421 $requestor = new ApiRequestor($account->getId(), $account->getSecret(), $analyst->getApiBase());
422
423 // Just send request to log uninstall event not caring about response
424 UninstallRequest::make($collector, $account->getId(), $account->getPath())->execute($requestor);
425
426 $factory->sync();
427 }
428
429 /**
430 * Fires when used verified his account
431 */
432 public function onInstallVerifiedListener()
433 {
434 $this->verifyNonceAndPerms();
435
436 $factory = NoticeFactory::instance();
437
438 $notice = Notice::make(
439 uniqid(),
440 $this->getId(),
441 'Thank you for confirming your email.',
442 $this->collector->getPluginName($this->path)
443 );
444
445 $factory->addNotice($notice);
446
447 // Remove confirmation notification
448 $confirmationNotificationId = DatabaseCache::getInstance()->pop(sprintf('account_email_confirmation_%s', $this->getId()));
449 $factory->remove($confirmationNotificationId);
450
451 AccountDataFactory::syncData();
452
453 wp_send_json_success();
454 }
455
456 /**
457 * Will fire when wp renders plugin
458 * action buttons
459 *
460 * @param $defaultLinks
461 * @return array
462 */
463 public function onRenderActionLinksHook($defaultLinks)
464 {
465 $customLinks = [];
466
467 $customLinks[] = $this->isOptedIn()
468 ? '<a class="analyst-action-opt analyst-opt-out" analyst-plugin-id="' . $this->getId() . '" analyst-plugin-signed="' . (int) $this->isSigned() . '">Opt Out</a>'
469 : '<a class="analyst-action-opt analyst-opt-in" analyst-plugin-id="' . $this->getId() . '" analyst-plugin-signed="' . (int) $this->isSigned() . '">Opt In</a>';
470
471 // Append anchor to find specific deactivation link
472 if (isset($defaultLinks['deactivate'])) {
473 $defaultLinks['deactivate'] .= '<span analyst-plugin-id="' . $this->getId() . '" analyst-plugin-opted-in="' . (int) $this->isOptedIn() . '"></span>';
474 }
475
476 return array_merge($customLinks, $defaultLinks);
477 }
478
479 /**
480 * @return AccountData
481 */
482 public function getData()
483 {
484 return $this->data;
485 }
486
487 /**
488 * @param AccountData $data
489 */
490 public function setData(AccountData $data)
491 {
492 $this->data = $data;
493
494 $this->setIsOptedIn($data->isOptedIn());
495 $this->setIsInstalled($data->isInstalled());
496 $this->setIsSigned($data->isSigned());
497 $this->setIsInstallResolved($data->isInstallResolved());
498 }
499
500 /**
501 * Resolves valid action name
502 * based on client id
503 *
504 * @param $action
505 * @return string
506 */
507 private function resolveActionName($action)
508 {
509 return sprintf('%s_%s', $action, $this->id);
510 }
511
512 /**
513 * Register action for current plugin
514 *
515 * @param $action
516 * @param $callback
517 */
518 private function addFilter($action, $callback)
519 {
520 $validAction = sprintf('%s_%s', $action, $this->basePluginPath);
521
522 add_filter($validAction, $callback, 10);
523 }
524
525 /**
526 * Add ajax action for current plugin
527 *
528 * @param $action
529 * @param $callback
530 * @param bool $raw Format action ??
531 */
532 private function addAjax($action, $callback, $raw = false)
533 {
534 $validAction = $raw ? $action : sprintf('%s%s', 'wp_ajax_', $this->resolveActionName($action));
535
536 add_action($validAction, $callback);
537 }
538
539 /**
540 * @return bool
541 */
542 public function isSigned()
543 {
544 return $this->isSigned;
545 }
546
547 /**
548 * @param bool $isSigned
549 */
550 public function setIsSigned($isSigned)
551 {
552 $this->data->setIsSigned($isSigned);
553
554 $this->isSigned = $isSigned;
555 }
556
557 /**
558 * @return RequestorContract
559 */
560 public function getRequestor()
561 {
562 return $this->requestor;
563 }
564
565 /**
566 * @param RequestorContract $requestor
567 */
568 public function setRequestor(RequestorContract $requestor)
569 {
570 $this->requestor = $requestor;
571 }
572
573 /**
574 * @return string
575 */
576 public function getClientSecret()
577 {
578 return $this->clientSecret;
579 }
580
581 /**
582 * @return Collector
583 */
584 public function getCollector()
585 {
586 return $this->collector;
587 }
588
589 /**
590 * @param Collector $collector
591 */
592 public function setCollector(Collector $collector)
593 {
594 $this->collector = $collector;
595 }
596
597 /**
598 * Do we allowing logging
599 *
600 * @return bool
601 */
602 public function isAllowingLogging()
603 {
604 return $this->isOptedIn;
605 }
606
607 /**
608 * @return string
609 */
610 public function getBasePluginPath()
611 {
612 return $this->basePluginPath;
613 }
614
615 /**
616 * @return bool
617 */
618 public function isInstallResolved()
619 {
620 return $this->isInstallResolved;
621 }
622
623 /**
624 * @param bool $isInstallResolved
625 */
626 public function setIsInstallResolved($isInstallResolved)
627 {
628 $this->data->setIsInstallResolved($isInstallResolved);
629
630 $this->isInstallResolved = $isInstallResolved;
631 }
632 }
633