47
common/Settings/Mail/ConnectGmailAccountController.php
Executable file
47
common/Settings/Mail/ConnectGmailAccountController.php
Executable file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Common\Settings\Mail;
|
||||
|
||||
use Common\Auth\Oauth;
|
||||
use Common\Core\BaseController;
|
||||
use Illuminate\Contracts\Filesystem\FileNotFoundException;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Laravel\Socialite\Facades\Socialite;
|
||||
|
||||
class ConnectGmailAccountController extends BaseController
|
||||
{
|
||||
public function connectGmail()
|
||||
{
|
||||
Session::flash(
|
||||
Oauth::OAUTH_CALLBACK_HANDLER_KEY,
|
||||
HandleConnectGmailOauthCallback::class,
|
||||
);
|
||||
|
||||
$driver = Socialite::driver('google')
|
||||
->scopes([
|
||||
'https://www.googleapis.com/auth/gmail.readonly',
|
||||
'https://www.googleapis.com/auth/gmail.send',
|
||||
])
|
||||
->with([
|
||||
'access_type' => 'offline',
|
||||
'prompt' => 'consent select_account',
|
||||
]);
|
||||
|
||||
return $driver->redirect();
|
||||
}
|
||||
|
||||
public static function getConnectedEmail(): ?string
|
||||
{
|
||||
if (!class_exists(GmailClient::class)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
$data = json_decode(File::get(GmailClient::tokenPath()), true);
|
||||
return $data['email'] ?? null;
|
||||
} catch (FileNotFoundException $e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
19
common/Settings/Mail/GmailApiMailTransport.php
Executable file
19
common/Settings/Mail/GmailApiMailTransport.php
Executable file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Common\Settings\Mail;
|
||||
|
||||
use Symfony\Component\Mailer\SentMessage;
|
||||
use Symfony\Component\Mailer\Transport\AbstractTransport;
|
||||
|
||||
class GmailApiMailTransport extends AbstractTransport
|
||||
{
|
||||
public function doSend(SentMessage $message): void
|
||||
{
|
||||
(new GmailClient())->sendEmail($message->toString());
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return 'gmailApi';
|
||||
}
|
||||
}
|
||||
111
common/Settings/Mail/GmailClient.php
Executable file
111
common/Settings/Mail/GmailClient.php
Executable file
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
namespace Common\Settings\Mail;
|
||||
|
||||
use File;
|
||||
use Google\Service\Gmail\Message;
|
||||
use Google\Service\Gmail\WatchRequest;
|
||||
use Google\Service\Gmail\WatchResponse;
|
||||
use Google_Client;
|
||||
use Google_Service_Gmail;
|
||||
|
||||
class GmailClient
|
||||
{
|
||||
private Google_Service_Gmail $gmail;
|
||||
|
||||
private Google_Client $googleClient;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->buildGoogleClient();
|
||||
}
|
||||
|
||||
public static function tokenPath(): string
|
||||
{
|
||||
return storage_path('app/tokens/gmail.json');
|
||||
}
|
||||
|
||||
public static function tokenExists(): bool
|
||||
{
|
||||
return file_exists(self::tokenPath());
|
||||
}
|
||||
|
||||
public function sendEmail(string $rawContent): Message
|
||||
{
|
||||
$encoded = strtr(base64_encode($rawContent), ['+' => '-', '/' => '_']);
|
||||
$msg = new Message();
|
||||
$msg->setRaw($encoded);
|
||||
return $this->gmail->users_messages->send('me', $msg);
|
||||
}
|
||||
|
||||
public function listHistory(int $historyId): array
|
||||
{
|
||||
$response = $this->gmail->users_history->listUsersHistory('me', [
|
||||
'startHistoryId' => $historyId,
|
||||
]);
|
||||
|
||||
$messageIds = collect($response['history'])
|
||||
->map(function ($history) {
|
||||
$msg = $history['messagesAdded'][0]['message'] ?? null;
|
||||
$labels = $msg['labelIds'] ?? [];
|
||||
|
||||
if ($msg && !in_array('SENT', $labels)) {
|
||||
return $msg['id'];
|
||||
}
|
||||
})
|
||||
->filter();
|
||||
|
||||
if ($messageIds->isEmpty()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$this->googleClient->setUseBatch(true);
|
||||
$batch = $this->gmail->createBatch();
|
||||
|
||||
$messageIds->each(function ($msgId) use ($batch) {
|
||||
$request = $this->gmail->users_messages->get('me', $msgId, [
|
||||
'format' => 'raw',
|
||||
]);
|
||||
$batch->add($request);
|
||||
});
|
||||
|
||||
$this->googleClient->setUseBatch(false);
|
||||
|
||||
return array_values($batch->execute());
|
||||
}
|
||||
|
||||
public function watch(): WatchResponse
|
||||
{
|
||||
$payload = new WatchRequest();
|
||||
$payload->topicName = settings('incoming_email.gmail.topicName');
|
||||
$payload->labelIds = ['UNREAD'];
|
||||
$payload->labelFilterAction = 'include';
|
||||
return $this->gmail->users->watch('me', $payload);
|
||||
}
|
||||
|
||||
private function buildGoogleClient(): void
|
||||
{
|
||||
$this->googleClient = new Google_Client();
|
||||
$this->googleClient->setClientId(config('services.google.client_id'));
|
||||
$this->googleClient->setClientSecret(
|
||||
config('services.google.client_secret'),
|
||||
);
|
||||
|
||||
if (self::tokenExists()) {
|
||||
$tokenJson = file_get_contents(self::tokenPath());
|
||||
$accessToken = json_decode($tokenJson, true);
|
||||
$this->googleClient->setAccessToken($accessToken);
|
||||
}
|
||||
|
||||
if ($this->googleClient->isAccessTokenExpired()) {
|
||||
$newToken = $this->googleClient->fetchAccessTokenWithRefreshToken(
|
||||
$this->googleClient->getRefreshToken(),
|
||||
);
|
||||
$oldToken = json_decode(File::get(self::tokenPath()), true);
|
||||
$mergedToken = array_merge($oldToken, $newToken);
|
||||
File::put(self::tokenPath(), json_encode($mergedToken));
|
||||
}
|
||||
|
||||
$this->gmail = new Google_Service_Gmail($this->googleClient);
|
||||
}
|
||||
}
|
||||
36
common/Settings/Mail/HandleConnectGmailOauthCallback.php
Executable file
36
common/Settings/Mail/HandleConnectGmailOauthCallback.php
Executable file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Common\Settings\Mail;
|
||||
|
||||
use Common\Auth\Oauth;
|
||||
use Illuminate\Contracts\View\View as ViewContract;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Laravel\Socialite\Facades\Socialite;
|
||||
|
||||
class HandleConnectGmailOauthCallback
|
||||
{
|
||||
public function execute(string $provider): ViewContract
|
||||
{
|
||||
$profile = Socialite::with('google')->user();
|
||||
|
||||
File::ensureDirectoryExists(dirname(GmailClient::tokenPath()));
|
||||
File::put(
|
||||
GmailClient::tokenPath(),
|
||||
json_encode([
|
||||
'access_token' => $profile->token,
|
||||
'refresh_token' => $profile->refreshToken,
|
||||
'created' => now()->timestamp,
|
||||
'expires_in' => $profile->expiresIn,
|
||||
'email' => $profile->email,
|
||||
]),
|
||||
);
|
||||
|
||||
if (settings('incoming_email.gmail.enabled')) {
|
||||
(new GmailClient())->watch();
|
||||
}
|
||||
|
||||
return (new Oauth())->getPopupResponse('SUCCESS', [
|
||||
'profile' => $profile,
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user