Нет описания

Services.php 8.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. <?php
  2. namespace MailPoet\API\JSON\v1;
  3. if (!defined('ABSPATH')) exit;
  4. use MailPoet\Analytics\Analytics as AnalyticsHelper;
  5. use MailPoet\API\JSON\Endpoint as APIEndpoint;
  6. use MailPoet\API\JSON\Error as APIError;
  7. use MailPoet\API\JSON\Response;
  8. use MailPoet\Config\AccessControl;
  9. use MailPoet\Config\Installer;
  10. use MailPoet\Config\ServicesChecker;
  11. use MailPoet\Cron\Workers\KeyCheck\PremiumKeyCheck;
  12. use MailPoet\Cron\Workers\KeyCheck\SendingServiceKeyCheck;
  13. use MailPoet\Mailer\MailerLog;
  14. use MailPoet\Services\Bridge;
  15. use MailPoet\Services\CongratulatoryMssEmailController;
  16. use MailPoet\Settings\SettingsController;
  17. use MailPoet\WP\DateTime;
  18. use MailPoet\WP\Functions as WPFunctions;
  19. class Services extends APIEndpoint {
  20. /** @var Bridge */
  21. private $bridge;
  22. /** @var SettingsController */
  23. private $settings;
  24. /** @var AnalyticsHelper */
  25. private $analytics;
  26. /** @var DateTime */
  27. public $dateTime;
  28. /** @var SendingServiceKeyCheck */
  29. private $mssWorker;
  30. /** @var PremiumKeyCheck */
  31. private $premiumWorker;
  32. /** @var ServicesChecker */
  33. private $servicesChecker;
  34. /** @var CongratulatoryMssEmailController */
  35. private $congratulatoryMssEmailController;
  36. /** @var WPFunctions */
  37. private $wp;
  38. public $permissions = [
  39. 'global' => AccessControl::PERMISSION_MANAGE_SETTINGS,
  40. ];
  41. public function __construct(
  42. Bridge $bridge,
  43. SettingsController $settings,
  44. AnalyticsHelper $analytics,
  45. SendingServiceKeyCheck $mssWorker,
  46. PremiumKeyCheck $premiumWorker,
  47. ServicesChecker $servicesChecker,
  48. CongratulatoryMssEmailController $congratulatoryMssEmailController,
  49. WPFunctions $wp
  50. ) {
  51. $this->bridge = $bridge;
  52. $this->settings = $settings;
  53. $this->analytics = $analytics;
  54. $this->mssWorker = $mssWorker;
  55. $this->premiumWorker = $premiumWorker;
  56. $this->dateTime = new DateTime();
  57. $this->servicesChecker = $servicesChecker;
  58. $this->congratulatoryMssEmailController = $congratulatoryMssEmailController;
  59. $this->wp = $wp;
  60. }
  61. public function checkMSSKey($data = []) {
  62. $key = isset($data['key']) ? trim($data['key']) : null;
  63. if (!$key) {
  64. return $this->badRequest([
  65. APIError::BAD_REQUEST => $this->wp->__('Please specify a key.', 'mailpoet'),
  66. ]);
  67. }
  68. $wasPendingApproval = $this->servicesChecker->isMailPoetAPIKeyPendingApproval();
  69. try {
  70. $result = $this->bridge->checkMSSKey($key);
  71. $this->bridge->storeMSSKeyAndState($key, $result);
  72. } catch (\Exception $e) {
  73. return $this->errorResponse([
  74. $e->getCode() => $e->getMessage(),
  75. ]);
  76. }
  77. // pause sending when key is pending approval, resume when not pending anymore
  78. $isPendingApproval = $this->servicesChecker->isMailPoetAPIKeyPendingApproval();
  79. if (!$wasPendingApproval && $isPendingApproval) {
  80. MailerLog::pauseSending(MailerLog::getMailerLog());
  81. } elseif ($wasPendingApproval && !$isPendingApproval) {
  82. MailerLog::resumeSending();
  83. }
  84. $state = !empty($result['state']) ? $result['state'] : null;
  85. $successMessage = null;
  86. if ($state == Bridge::KEY_VALID) {
  87. $successMessage = $this->wp->__('Your MailPoet Sending Service key has been successfully validated', 'mailpoet');
  88. } elseif ($state == Bridge::KEY_EXPIRING) {
  89. $successMessage = sprintf(
  90. $this->wp->__('Your MailPoet Sending Service key expires on %s!', 'mailpoet'),
  91. $this->dateTime->formatDate(strtotime($result['data']['expire_at']))
  92. );
  93. }
  94. if (!empty($result['data']['public_id'])) {
  95. $this->analytics->setPublicId($result['data']['public_id']);
  96. }
  97. if ($successMessage) {
  98. return $this->successResponse(['message' => $successMessage]);
  99. }
  100. switch ($state) {
  101. case Bridge::KEY_INVALID:
  102. $error = $this->wp->__('Your key is not valid for the MailPoet Sending Service', 'mailpoet');
  103. break;
  104. case Bridge::KEY_ALREADY_USED:
  105. $error = $this->wp->__('Your MailPoet Sending Service key is already used on another site', 'mailpoet');
  106. break;
  107. default:
  108. $code = !empty($result['code']) ? $result['code'] : Bridge::CHECK_ERROR_UNKNOWN;
  109. $errorMessage = $this->wp->__('Error validating MailPoet Sending Service key, please try again later (%s).', 'mailpoet');
  110. // If site runs on localhost
  111. if ( 1 === preg_match("/^(http|https)\:\/\/(localhost|127\.0\.0\.1)/", $this->wp->siteUrl()) ) {
  112. $errorMessage .= ' ' . $this->wp->__("Note that it doesn't work on localhost.", 'mailpoet');
  113. }
  114. $error = sprintf(
  115. $errorMessage,
  116. $this->getErrorDescriptionByCode($code)
  117. );
  118. break;
  119. }
  120. return $this->errorResponse([APIError::BAD_REQUEST => $error]);
  121. }
  122. public function checkPremiumKey($data = []) {
  123. $key = isset($data['key']) ? trim($data['key']) : null;
  124. if (!$key) {
  125. return $this->badRequest([
  126. APIError::BAD_REQUEST => $this->wp->__('Please specify a key.', 'mailpoet'),
  127. ]);
  128. }
  129. try {
  130. $result = $this->bridge->checkPremiumKey($key);
  131. $this->bridge->storePremiumKeyAndState($key, $result);
  132. } catch (\Exception $e) {
  133. return $this->errorResponse([
  134. $e->getCode() => $e->getMessage(),
  135. ]);
  136. }
  137. $state = !empty($result['state']) ? $result['state'] : null;
  138. $successMessage = null;
  139. if ($state == Bridge::KEY_VALID) {
  140. $successMessage = $this->wp->__('Your Premium key has been successfully validated', 'mailpoet');
  141. } elseif ($state == Bridge::KEY_EXPIRING) {
  142. $successMessage = sprintf(
  143. $this->wp->__('Your Premium key expires on %s', 'mailpoet'),
  144. $this->dateTime->formatDate(strtotime($result['data']['expire_at']))
  145. );
  146. }
  147. if (!empty($result['data']['public_id'])) {
  148. $this->analytics->setPublicId($result['data']['public_id']);
  149. }
  150. if ($successMessage) {
  151. return $this->successResponse(
  152. ['message' => $successMessage],
  153. Installer::getPremiumStatus()
  154. );
  155. }
  156. switch ($state) {
  157. case Bridge::KEY_INVALID:
  158. $error = $this->wp->__('Your key is not valid for MailPoet Premium', 'mailpoet');
  159. break;
  160. case Bridge::KEY_ALREADY_USED:
  161. $error = $this->wp->__('Your Premium key is already used on another site', 'mailpoet');
  162. break;
  163. default:
  164. $code = !empty($result['code']) ? $result['code'] : Bridge::CHECK_ERROR_UNKNOWN;
  165. $error = sprintf(
  166. $this->wp->__('Error validating Premium key, please try again later (%s)', 'mailpoet'),
  167. $this->getErrorDescriptionByCode($code)
  168. );
  169. break;
  170. }
  171. return $this->errorResponse(
  172. [APIError::BAD_REQUEST => $error],
  173. ['code' => $result['code'] ?? null]
  174. );
  175. }
  176. public function recheckKeys() {
  177. $this->mssWorker->init();
  178. $this->mssWorker->checkKey();
  179. $this->premiumWorker->init();
  180. $this->premiumWorker->checkKey();
  181. return $this->successResponse();
  182. }
  183. public function sendCongratulatoryMssEmail() {
  184. if (!Bridge::isMPSendingServiceEnabled()) {
  185. return $this->createBadRequest(__('MailPoet Sending Service is not active.', 'mailpoet'));
  186. }
  187. $authorizedEmails = $this->bridge->getAuthorizedEmailAddresses();
  188. if (!$authorizedEmails) {
  189. return $this->createBadRequest(__('No FROM email addresses are authorized.', 'mailpoet'));
  190. }
  191. $fromEmail = $this->settings->get('sender.address');
  192. if (!$fromEmail) {
  193. return $this->createBadRequest(__('Sender email address is not set.', 'mailpoet'));
  194. }
  195. if (!in_array($fromEmail, $authorizedEmails, true)) {
  196. return $this->createBadRequest(sprintf(__("Sender email address '%s' is not authorized.", 'mailpoet'), $fromEmail));
  197. }
  198. try {
  199. // congratulatory email is sent to the current FROM address (authorized at this point)
  200. $this->congratulatoryMssEmailController->sendCongratulatoryEmail($fromEmail);
  201. } catch (\Throwable $e) {
  202. return $this->errorResponse([
  203. APIError::UNKNOWN => __('Sending of congratulatory email failed.', 'mailpoet'),
  204. ], [], Response::STATUS_UNKNOWN);
  205. }
  206. return $this->successResponse([
  207. 'email_address' => $fromEmail,
  208. ]);
  209. }
  210. private function getErrorDescriptionByCode($code) {
  211. switch ($code) {
  212. case Bridge::CHECK_ERROR_UNAVAILABLE:
  213. $text = $this->wp->__('Service unavailable', 'mailpoet');
  214. break;
  215. case Bridge::CHECK_ERROR_UNKNOWN:
  216. $text = $this->wp->__('Contact your hosting support to check the connection between your host and https://bridge.mailpoet.com', 'mailpoet');
  217. break;
  218. default:
  219. $text = sprintf(_x('code: %s', 'Error code (inside parentheses)', 'mailpoet'), $code);
  220. break;
  221. }
  222. return $text;
  223. }
  224. private function createBadRequest(string $message) {
  225. return $this->badRequest([
  226. APIError::BAD_REQUEST => $message,
  227. ]);
  228. }
  229. }