diff --git a/src/Contracts/TokenRepository.php b/src/Contracts/TokenRepository.php new file mode 100644 index 0000000..0ee6c96 --- /dev/null +++ b/src/Contracts/TokenRepository.php @@ -0,0 +1,16 @@ +app = Container::getInstance(); + $this->tokenRepository = $tokenRepository; + $this->userId = $userId; $this->configConstruct($config); @@ -53,6 +57,11 @@ public function __construct(mixed $config = null, ?string $userId = null) } + public function getTokenRepository(): TokenRepository + { + return $this->tokenRepository; + } + public function getUserId(): ?string { return $this->userId; @@ -60,22 +69,17 @@ public function getUserId(): ?string /** * Check and return true if the user has previously logged in without checking if the token needs to refresh - * - * @return bool */ public function checkPreviouslyLoggedIn(): bool { $fileName = $this->getFileName(); - $file = "gmail/tokens/$fileName.json"; - $disk = Storage::disk('local'); + $allowJsonEncrypt = $this->_config['gmail.allow_json_encrypt']; - if (! $disk->exists($file)) { + if (! $this->tokenRepository->tokenExists($fileName)) { return false; } - $contents = $disk->get($file); - $allowJsonEncrypt = $this->_config['gmail.allow_json_encrypt']; - $savedConfigToken = json_decode($allowJsonEncrypt ? decrypt($contents) : $contents, true); + $savedConfigToken = $this->tokenRepository->getToken($fileName, $allowJsonEncrypt); return ! empty($savedConfigToken['access_token']); } @@ -152,39 +156,14 @@ public function setBothAccessToken(array|string $token): void */ public function saveAccessToken(array $config): void { - $disk = Storage::disk('local'); $fileName = $this->getFileName(); - $file = "gmail/tokens/$fileName.json"; $allowJsonEncrypt = $this->_config['gmail.allow_json_encrypt']; $config['email'] = $this->emailAddress; - if ($disk->exists($file)) { - - if (empty($config['email'])) { - if ($allowJsonEncrypt) { - $savedConfigToken = json_decode(decrypt($disk->get($file)), true); - } else { - $savedConfigToken = json_decode($disk->get($file), true); - } - if (isset($savedConfigToken['email'])) { - $config['email'] = $savedConfigToken['email']; - } - } - - $disk->delete($file); - } - - if ($allowJsonEncrypt) { - $disk->put($file, encrypt(json_encode($config))); - } else { - $disk->put($file, json_encode($config)); - } - + $this->tokenRepository->storeToken($fileName, $config, $allowJsonEncrypt); } /** - * @return array|string - * * @throws \Exception */ public function makeToken(Request $request): array|string @@ -213,8 +192,6 @@ public function makeToken(Request $request): array|string /** * Check - * - * @return bool */ public function check(): bool { @@ -223,8 +200,6 @@ public function check(): bool /** * Gets user profile from Gmail - * - * @return \Google_Service_Gmail_Profile */ public function getProfile(): \Google_Service_Gmail_Profile { @@ -246,22 +221,10 @@ public function logout(): void */ public function deleteAccessToken(): void { - $disk = Storage::disk('local'); $fileName = $this->getFileName(); - $file = "gmail/tokens/$fileName.json"; - $allowJsonEncrypt = $this->_config['gmail.allow_json_encrypt']; - if ($disk->exists($file)) { - $disk->delete($file); - } - - if ($allowJsonEncrypt) { - $disk->put($file, encrypt(json_encode([]))); - } else { - $disk->put($file, json_encode([])); - } - + $this->tokenRepository->deleteToken($fileName, $allowJsonEncrypt); } private function haveReadScope(): bool @@ -275,8 +238,6 @@ private function haveReadScope(): bool * users.stop receiving push notifications for the given user mailbox. * * @param string $userEmail Email address - * @param array $optParams - * @return \Google_Service_Gmail_Stop */ public function stopWatch(string $userEmail, array $optParams = []): \Google_Service_Gmail_Stop { @@ -299,8 +260,6 @@ public function setWatch(string $userEmail, \Google_Service_Gmail_WatchRequest $ /** * Lists the history of all changes to the given mailbox. History results are returned in chronological order (increasing historyId). - * - * @return \Google\Service\Gmail\ListHistoryResponse */ public function historyList(string $userEmail, array $params): \Google\Service\Gmail\ListHistoryResponse { diff --git a/src/LaravelGmailClass.php b/src/LaravelGmailClass.php index 449ddbd..dd99c35 100644 --- a/src/LaravelGmailClass.php +++ b/src/LaravelGmailClass.php @@ -4,6 +4,7 @@ namespace Dacastro4\LaravelGmail; +use Dacastro4\LaravelGmail\Contracts\TokenRepository; use Dacastro4\LaravelGmail\Exceptions\AuthException; use Dacastro4\LaravelGmail\Services\Message; use Illuminate\Http\RedirectResponse; @@ -11,13 +12,13 @@ class LaravelGmailClass extends GmailConnection { - public function __construct(mixed $config, ?string $userId = null) + public function __construct(mixed $config, TokenRepository $tokenRepository, ?string $userId = null) { if (class_basename($config) === 'Application') { $config = $config['config']; } - parent::__construct($config, $userId); + parent::__construct($tokenRepository, $config, $userId); } /** diff --git a/src/LaravelGmailServiceProvider.php b/src/LaravelGmailServiceProvider.php index 5557bf4..2d3e1c3 100644 --- a/src/LaravelGmailServiceProvider.php +++ b/src/LaravelGmailServiceProvider.php @@ -4,6 +4,8 @@ namespace Dacastro4\LaravelGmail; +use Dacastro4\LaravelGmail\Contracts\TokenRepository; +use Dacastro4\LaravelGmail\Repositories\StorageTokenRepository; use Illuminate\Support\Facades\App; use Illuminate\Support\ServiceProvider; @@ -18,9 +20,11 @@ public function register(): void { $this->mergeConfigFrom(__DIR__.'/config/gmail.php', 'gmail'); + $this->app->bind(TokenRepository::class, fn (): TokenRepository => new StorageTokenRepository); + // Main Service $this->app->bind('laravelgmail', function ($app): LaravelGmailClass { - return new LaravelGmailClass($app['config']); + return new LaravelGmailClass($app['config'], $app->make(TokenRepository::class)); }); } } diff --git a/src/Repositories/StorageTokenRepository.php b/src/Repositories/StorageTokenRepository.php new file mode 100644 index 0000000..5637666 --- /dev/null +++ b/src/Repositories/StorageTokenRepository.php @@ -0,0 +1,68 @@ +exists($file); + } + + public function getToken(string $fileName, bool $allowJsonEncrypt): array + { + $file = "gmail/tokens/$fileName.json"; + $disk = Storage::disk('local'); + + if (! $disk->exists($file)) { + return []; + } + + $contents = $disk->get($file); + + return json_decode($allowJsonEncrypt ? decrypt($contents) : $contents, true) ?? []; + } + + public function storeToken(string $fileName, array $config, bool $allowJsonEncrypt): void + { + $disk = Storage::disk('local'); + $file = "gmail/tokens/$fileName.json"; + + if ($disk->exists($file)) { + $savedConfigToken = $this->getToken($fileName, $allowJsonEncrypt); + if (empty($config['email']) && isset($savedConfigToken['email'])) { + $config['email'] = $savedConfigToken['email']; + } + $disk->delete($file); + } + + if ($allowJsonEncrypt) { + $disk->put($file, encrypt(json_encode($config))); + } else { + $disk->put($file, json_encode($config)); + } + } + + public function deleteToken(string $fileName, bool $allowJsonEncrypt): void + { + $disk = Storage::disk('local'); + $file = "gmail/tokens/$fileName.json"; + + if ($disk->exists($file)) { + $disk->delete($file); + } + + if ($allowJsonEncrypt) { + $disk->put($file, encrypt(json_encode([]))); + } else { + $disk->put($file, json_encode([])); + } + } +} diff --git a/src/Services/Message.php b/src/Services/Message.php index 83b9abe..ec25129 100644 --- a/src/Services/Message.php +++ b/src/Services/Message.php @@ -9,7 +9,6 @@ use Dacastro4\LaravelGmail\Traits\Filterable; use Dacastro4\LaravelGmail\Traits\SendsParameters; use Google_Service_Gmail; -use Google_Service_Gmail_ListMessagesResponse; use Google_Service_Gmail_Message; use Illuminate\Support\Collection; @@ -71,7 +70,7 @@ public function all(?string $pageToken = null): Collection if (! $this->preload) { foreach ($messages as $message) { - $mails[] = new Mail($message, $this->preload, $this->client->userId); + $mails[] = new Mail($this->client->getTokenRepository(), $message, $this->preload, $this->client->userId); } } else { $mails = count($messages) > 0 ? $this->batchRequest($messages) : []; @@ -107,7 +106,7 @@ public function get(string $id): Mail { $message = $this->getRequest($id); - return new Mail($message, false, $this->client->userId); + return new Mail($this->client->getTokenRepository(), $message, false, $this->client->userId); } /** @@ -130,7 +129,7 @@ public function batchRequest(array $allMessages): array $messages = []; foreach ($messagesBatch as $message) { - $messages[] = new Mail($message, false, $this->client->userId); + $messages[] = new Mail($this->client->getTokenRepository(), $message, false, $this->client->userId); } return $messages; diff --git a/src/Services/Message/Attachment.php b/src/Services/Message/Attachment.php index e61059f..43e4732 100644 --- a/src/Services/Message/Attachment.php +++ b/src/Services/Message/Attachment.php @@ -4,6 +4,7 @@ namespace Dacastro4\LaravelGmail\Services\Message; +use Dacastro4\LaravelGmail\Contracts\TokenRepository; use Dacastro4\LaravelGmail\GmailConnection; use Dacastro4\LaravelGmail\Traits\HasDecodableBody; use Google_Service_Gmail; @@ -32,9 +33,9 @@ class Attachment extends GmailConnection private string $messageId; - public function __construct(string $singleMessageId, \Google_Service_Gmail_MessagePart $part, ?string $userId = null) + public function __construct(TokenRepository $tokenRepository, string $singleMessageId, \Google_Service_Gmail_MessagePart $part, ?string $userId = null) { - parent::__construct(config(), $userId); + parent::__construct($tokenRepository, config(), $userId); $this->service = new Google_Service_Gmail($this); @@ -50,8 +51,6 @@ public function __construct(string $singleMessageId, \Google_Service_Gmail_Messa /** * Retuns attachment ID - * - * @return string */ public function getId(): string { @@ -60,8 +59,6 @@ public function getId(): string /** * Returns attachment file name - * - * @return string */ public function getFileName(): string { @@ -70,8 +67,6 @@ public function getFileName(): string /** * Returns mime type of the attachment - * - * @return string */ public function getMimeType(): string { @@ -89,11 +84,6 @@ public function getSize(): int } /** - * @param string $path - * @param string|null $filename - * @param string $disk - * @return string - * * @throws \Exception */ public function saveAttachmentTo(?string $path = null, ?string $filename = null, string $disk = 'local'): string @@ -136,8 +126,6 @@ public function getData(): ?string /** * Returns attachment headers * Contains Content-ID and X-Attachment-Id for embedded images - * - * @return array */ public function getHeaderDetails(array $headers): array { diff --git a/src/Services/Message/Mail.php b/src/Services/Message/Mail.php index ebde191..174d649 100644 --- a/src/Services/Message/Mail.php +++ b/src/Services/Message/Mail.php @@ -5,6 +5,7 @@ namespace Dacastro4\LaravelGmail\Services\Message; use Carbon\Carbon; +use Dacastro4\LaravelGmail\Contracts\TokenRepository; use Dacastro4\LaravelGmail\GmailConnection; use Dacastro4\LaravelGmail\Traits\HasDecodableBody; use Dacastro4\LaravelGmail\Traits\HasParts; @@ -46,13 +47,13 @@ class Mail extends GmailConnection protected Google_Service_Gmail $service; - public function __construct(?\Google_Service_Gmail_Message $message = null, bool $preload = false, ?string $userId = null) + public function __construct(TokenRepository $tokenRepository, ?\Google_Service_Gmail_Message $message = null, bool $preload = false, ?string $userId = null) { $this->service = new Google_Service_Gmail($this); $this->__rConstruct(); $this->__mConstruct(); - parent::__construct(config(), $userId); + parent::__construct($tokenRepository, config(), $userId); if (! is_null($message)) { if ($preload) { @@ -389,12 +390,12 @@ public function getAttachmentsWithData(): Collection public function getAttachments(bool $preload = false): Collection { - $attachments = new Collection(); + $attachments = new Collection; $parts = $this->getAllParts($this->parts); foreach ($parts as $part) { if (! empty($part->body->attachmentId)) { - $attachment = (new Attachment($part->body->attachmentId, $part, $this->userId)); + $attachment = new Attachment($this->getTokenRepository(), $part->body->attachmentId, $part, $this->userId); if ($preload) { $attachment = $attachment->getData(); @@ -457,7 +458,7 @@ private function buildHeaders(array $emailHeaders): Collection foreach ($emailHeaders as $header) { /** @var \Google_Service_Gmail_MessagePartHeader $header */ - $head = new \stdClass(); + $head = new \stdClass; $head->key = $header->getName(); $head->value = $header->getValue(); diff --git a/src/Traits/ModifiesLabels.php b/src/Traits/ModifiesLabels.php index 0c05429..c05a97c 100644 --- a/src/Traits/ModifiesLabels.php +++ b/src/Traits/ModifiesLabels.php @@ -13,14 +13,12 @@ trait ModifiesLabels public function __construct() { - $this->messageRequest = new Google_Service_Gmail_ModifyMessageRequest(); + $this->messageRequest = new Google_Service_Gmail_ModifyMessageRequest; } /** * Adds labels to the email * - * @param string|array $labels - * @return Mail|string * * @throws \Exception */ @@ -41,12 +39,10 @@ public function addLabel(string|array $labels): Mail|string /** * Executes the modification - * - * @return Mail */ private function modify(): Mail { - return new Mail($this->service->users_messages->modify('me', $this->getId(), $this->messageRequest)); + return new Mail($this->getTokenRepository(), $this->service->users_messages->modify('me', $this->getId(), $this->messageRequest)); } abstract public function getId(): string; @@ -54,8 +50,6 @@ abstract public function getId(): string; /** * Removes labels from the email * - * @param string|array $labels - * @return Mail|string * * @throws \Exception */ diff --git a/src/Traits/Replyable.php b/src/Traits/Replyable.php index a8cfc71..6799e5e 100644 --- a/src/Traits/Replyable.php +++ b/src/Traits/Replyable.php @@ -50,7 +50,7 @@ trait Replyable public function __construct() { - $this->symfonyEmail = new Email(); + $this->symfonyEmail = new Email; } /** @@ -61,8 +61,6 @@ public function __construct() * If $name is passed and the first parameter is a string, this name will be * associated with the address. * - * @param string|array $to - * @param string|null $name * @return Replyable */ public function to(string|array $to, ?string $name = null): self @@ -127,9 +125,6 @@ public function subject(string $subject): self } /** - * @param string $view - * @param array $data - * @param array $mergeData * @return Replyable * * @throws \Throwable @@ -162,7 +157,6 @@ public function markdown(string $markdown_view, array $data = []): self } /** - * @param string $message * @return Replyable */ public function message(string $message): self @@ -196,7 +190,6 @@ public function attach(string ...$files): self /** * The value is an integer where 1 is the highest priority and 5 is the lowest. * - * @param int $priority * @return Replyable */ public function priority(int $priority): self @@ -229,7 +222,7 @@ public function reply(): Mail $body = $this->getMessageBody(); $body->setThreadId($this->getThreadId()); - return new Mail($this->service->users_messages->send('me', $body, $this->parameters)); + return new Mail($this->getTokenRepository(), $this->service->users_messages->send('me', $body, $this->parameters)); } abstract public function getId(): string; @@ -301,7 +294,7 @@ abstract public function getUser(): ?string; private function getMessageBody(): Google_Service_Gmail_Message { - $body = new Google_Service_Gmail_Message(); + $body = new Google_Service_Gmail_Message; $this->symfonyEmail ->from($this->fromAddress()) diff --git a/tests/GmailServiceTest.php b/tests/GmailServiceTest.php index ee19954..f07b4bb 100644 --- a/tests/GmailServiceTest.php +++ b/tests/GmailServiceTest.php @@ -3,6 +3,7 @@ use Dacastro4\LaravelGmail\Exceptions\AuthException; use Dacastro4\LaravelGmail\GmailConnection; use Dacastro4\LaravelGmail\LaravelGmailClass; +use Dacastro4\LaravelGmail\Repositories\StorageTokenRepository; use Dacastro4\LaravelGmail\Services\Message; use Dacastro4\LaravelGmail\Services\Message\Attachment; use Illuminate\Support\Facades\Storage; @@ -29,7 +30,8 @@ public function test_token_generation_saves_token_file() { Storage::fake('local'); - $connection = new GmailConnection($this->app['config']); + $repository = new StorageTokenRepository; + $connection = new GmailConnection($repository, $this->app['config']); $token = ['access_token' => 'token', 'refresh_token' => 'refresh']; $connection->saveAccessToken($token); @@ -42,7 +44,8 @@ public function test_check_previously_logged_in_returns_false_when_no_token() { Storage::fake('local'); - $connection = new GmailConnection($this->app['config']); + $repository = new StorageTokenRepository; + $connection = new GmailConnection($repository, $this->app['config']); $this->assertFalse($connection->checkPreviouslyLoggedIn()); } @@ -51,10 +54,11 @@ public function test_check_previously_logged_in_returns_false_when_no_token() public function test_message_retrieval_returns_collection() { Storage::fake('local'); - $client = new LaravelGmailClass($this->app['config']); - $service = new \stdClass(); + $repository = new StorageTokenRepository; + $client = new LaravelGmailClass($this->app['config'], $repository); + $service = new \stdClass; - $googleMessage = new \Google_Service_Gmail_Message(); + $googleMessage = new \Google_Service_Gmail_Message; $googleMessage->setId('msg1'); $response = Mockery::mock(); @@ -78,8 +82,9 @@ public function test_message_retrieval_returns_collection() public function test_message_retrieval_handles_empty_response() { Storage::fake('local'); - $client = new LaravelGmailClass($this->app['config']); - $service = new \stdClass(); + $repository = new StorageTokenRepository; + $client = new LaravelGmailClass($this->app['config'], $repository); + $service = new \stdClass; $response = Mockery::mock(); $response->shouldReceive('getMessages')->andReturn([]); @@ -113,14 +118,15 @@ public function test_attachment_can_be_saved() $part->shouldReceive('getMimeType')->andReturn('text/plain'); $part->shouldReceive('getHeaders')->andReturn([]); - $attachment = new Attachment('msg', $part); + $repository = new StorageTokenRepository; + $attachment = new Attachment($repository, 'msg', $part); $attachmentsResource = Mockery::mock(); $attachmentData = Mockery::mock(); $attachmentData->shouldReceive('getData')->andReturn(base64_encode('content')); $attachmentsResource->shouldReceive('get')->with('me', 'msg', 'attach')->andReturn($attachmentData); - $service = new \stdClass(); + $service = new \stdClass; $service->users_messages_attachments = $attachmentsResource; $ref = new ReflectionProperty(Attachment::class, 'service'); $ref->setAccessible(true); @@ -147,14 +153,15 @@ public function test_attachment_save_throws_exception_when_no_data() $part->shouldReceive('getMimeType')->andReturn('text/plain'); $part->shouldReceive('getHeaders')->andReturn([]); - $attachment = new Attachment('msg', $part); + $repository = new StorageTokenRepository; + $attachment = new Attachment($repository, 'msg', $part); $attachmentsResource = Mockery::mock(); $attachmentData = Mockery::mock(); $attachmentData->shouldReceive('getData')->andReturn(null); $attachmentsResource->shouldReceive('get')->andReturn($attachmentData); - $service = new \stdClass(); + $service = new \stdClass; $service->users_messages_attachments = $attachmentsResource; $ref = new ReflectionProperty(Attachment::class, 'service'); $ref->setAccessible(true); @@ -168,7 +175,8 @@ public function test_attachment_save_throws_exception_when_no_data() public function test_message_method_throws_exception_without_credentials() { Storage::fake('local'); - $client = new LaravelGmailClass($this->app['config']); + $repository = new StorageTokenRepository; + $client = new LaravelGmailClass($this->app['config'], $repository); $this->expectException(AuthException::class); $client->message(); diff --git a/tests/LaravelGmailTest.php b/tests/LaravelGmailTest.php index 153a8bf..5827f42 100644 --- a/tests/LaravelGmailTest.php +++ b/tests/LaravelGmailTest.php @@ -1,5 +1,7 @@ 'secret', + 'gmail.client_id' => 'client', + 'gmail.redirect_url' => '/', + 'gmail.credentials_file_name' => 'test-token', + 'gmail.allow_json_encrypt' => false, + ]); + } + /** @test */ public function test_markdown_method() { @@ -24,7 +39,8 @@ public function test_markdown_method() ); // trigger - (new Mail)->markdown( + $repository = new StorageTokenRepository; + (new Mail($repository))->markdown( 'sample-markdown', ['url' => 'https://www.google.com'] ); @@ -35,7 +51,8 @@ public function test_format_email_list_parses_names_and_addresses() { $emails = 'Alice , Bob '; - $formatted = (new Mail)->formatEmailList($emails); + $repository = new StorageTokenRepository; + $formatted = (new Mail($repository))->formatEmailList($emails); $this->assertCount(2, $formatted); $this->assertEquals(['name' => 'Alice', 'email' => 'alice@example.com'], $formatted[0]); diff --git a/tests/MakeTokenTest.php b/tests/MakeTokenTest.php index ffb9f66..a3e40b8 100644 --- a/tests/MakeTokenTest.php +++ b/tests/MakeTokenTest.php @@ -1,6 +1,7 @@ false, ]; - $connection = \Mockery::mock(GmailConnection::class.'[check,fetchAccessTokenWithAuthCode]', [$config]); + $repository = new StorageTokenRepository; + $connection = \Mockery::mock(GmailConnection::class.'[check,fetchAccessTokenWithAuthCode]', [$repository, $config]); $connection->shouldReceive('check')->andReturn(false); $connection->shouldReceive('fetchAccessTokenWithAuthCode') ->with('test-code')