first commit
Some checks failed
Build / run (push) Has been cancelled

This commit is contained in:
maher
2025-10-29 11:42:25 +01:00
commit 703f50a09d
4595 changed files with 385164 additions and 0 deletions

View 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;
}
}
}

View 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';
}
}

View 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);
}
}

View 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,
]);
}
}