diff --git a/docs/v3/msgraph/queues.md b/docs/v3/msgraph/queues.md new file mode 100644 index 0000000..801a61e --- /dev/null +++ b/docs/v3/msgraph/queues.md @@ -0,0 +1,53 @@ +--- +title: Queues +--- + +When using `MsGraph` within jobs, commands, or other queued processes, you need to authenticate the user explicitly. Ensure the user model has `access_token` and `refresh_token` stored in the database. Use the `login` method to authenticate the user before making any API calls: + +```php +MsGraph::login(User::find(1)); +MsGraph::get('me'); +``` + +Here's an example of how to structure a job that uses `MsGraph`: + +```php +user = $user; + } + + public function handle(): void + { + MsGraph::login($this->user); + $userData = MsGraph::get('me'); + // Process $userData as needed + } +} +``` + +Dispatch this job with a user instance: + +```php +ExampleMsGraphJob::dispatch($user); +``` + +This approach ensures that the Microsoft Graph API calls are made with the correct user context, even in background processes. \ No newline at end of file diff --git a/src/Events/NewMicrosoft365SignInEvent.php b/src/Events/NewMicrosoft365SignInEvent.php index 2998c18..270b910 100644 --- a/src/Events/NewMicrosoft365SignInEvent.php +++ b/src/Events/NewMicrosoft365SignInEvent.php @@ -12,8 +12,5 @@ class NewMicrosoft365SignInEvent use InteractsWithSockets; use SerializesModels; - public function __construct(public array $token) - { - - } + public function __construct(public array $token) {} } diff --git a/src/MsGraph.php b/src/MsGraph.php index 070515a..8567e20 100755 --- a/src/MsGraph.php +++ b/src/MsGraph.php @@ -56,6 +56,8 @@ public function tasks(): Tasks return new Tasks(); } + protected static $user; + protected static string $baseUrl = 'https://graph.microsoft.com/v1.0/'; protected static string $userModel = ''; @@ -86,6 +88,16 @@ public static function setUserModel(string $model): static return new static(); } + public static function login($user) + { + self::$user = $user; + } + + public static function getUser() + { + return self::$user; + } + /** * @throws Exception */ @@ -171,7 +183,7 @@ public function getAccessToken(?string $id = null, bool $redirectWhenNotConnecte $token = $this->getTokenData($id); $id = $this->getUserId($id); - if ($redirectWhenNotConnected) { + if ($this->getUser() === null && $redirectWhenNotConnected) { if (! $this->isConnected()) { return redirect()->away(config('msgraph.redirectUri')); } @@ -324,6 +336,10 @@ protected function isJson(string $string): bool protected function getUserId(?string $id = null): ?string { + if ($this->getUser() !== null) { + $id = $this->getUser()->id; + } + if ($id === null) { $id = auth()->id(); } diff --git a/tests/MsGraphTest.php b/tests/MsGraphTest.php index 2032352..1dcd6b0 100644 --- a/tests/MsGraphTest.php +++ b/tests/MsGraphTest.php @@ -3,8 +3,10 @@ use Dcblogdev\MsGraph\Facades\MsGraph as MsGraphFacade; use Dcblogdev\MsGraph\Models\MsGraphToken; use Dcblogdev\MsGraph\MsGraph; +use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Http\RedirectResponse; use Illuminate\Routing\Redirector; +use Illuminate\Support\Facades\Auth; use League\OAuth2\Client\Provider\Exception\IdentityProviderException; use League\OAuth2\Client\Provider\GenericProvider; use League\OAuth2\Client\Token\AccessToken; @@ -171,3 +173,79 @@ 'refresh_token' => $refreshToken, ]); }); + +class TestUser extends Authenticatable +{ + protected $fillable = ['id', 'email']; +} + +test('can login and set user', function () { + $user = new TestUser(['id' => 1, 'email' => 'test@example.com']); + + MsGraphFacade::login($user); + + expect(MsGraphFacade::getUser())->toBe($user); +}); + +test('getUser returns null when no user is logged in', function () { + MsGraphFacade::login(null); // Reset the user + expect(MsGraphFacade::getUser())->toBeNull(); +}); + +test('getAccessToken uses logged in user when available', function () { + $user = new TestUser(['id' => 1, 'email' => 'test@example.com']); + + MsGraphFacade::login($user); + + MsGraphToken::create([ + 'user_id' => $user->id, + 'access_token' => 'test_token', + 'refresh_token' => 'refresh_token', + 'expires' => strtotime('+1 day'), + ]); + + $token = MsGraphFacade::getAccessToken(); + + expect($token)->toBe('test_token'); +}); + +test('getUserId returns logged in user id when available', function () { + $user = new TestUser(['id' => 1, 'email' => 'test@example.com']); + + MsGraphFacade::login($user); + + $reflection = new ReflectionClass(MsGraphFacade::getFacadeRoot()); + $method = $reflection->getMethod('getUserId'); + $method->setAccessible(true); + + $userId = $method->invoke(MsGraphFacade::getFacadeRoot()); + + expect($userId)->toBe('1'); +}); + +test('getUserId falls back to auth id when no user is logged in', function () { + MsGraphFacade::login(null); // Reset the user + + $user = new TestUser(['id' => 2, 'email' => 'test2@example.com']); + Auth::shouldReceive('id')->andReturn(2); + + $reflection = new ReflectionClass(MsGraphFacade::getFacadeRoot()); + $method = $reflection->getMethod('getUserId'); + $method->setAccessible(true); + + $userId = $method->invoke(MsGraphFacade::getFacadeRoot()); + + expect($userId)->toBe('2'); +}); + +test('getAccessToken redirects when user is not connected and redirectWhenNotConnected is true', function () { + config(['msgraph.redirectUri' => 'http://example.com/redirect']); + + MsGraphFacade::login(null); // Reset the user + Auth::shouldReceive('id')->andReturn(null); + + $response = MsGraphFacade::getAccessToken(null, true); + + expect($response)->toBeInstanceOf(RedirectResponse::class) + ->and($response->getTargetUrl())->toBe('http://example.com/redirect'); +});