Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add user login functionality and queue support #80

Merged
merged 5 commits into from
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions docs/v3/msgraph/queues.md
Original file line number Diff line number Diff line change
@@ -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
<?php

namespace App\Jobs;

use App\Models\User;
use Dcblogdev\MsGraph\Facades\MsGraph;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;

class ExampleMsGraphJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

protected $user;

public function __construct(User $user)
{
$this->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.
5 changes: 1 addition & 4 deletions src/Events/NewMicrosoft365SignInEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,5 @@ class NewMicrosoft365SignInEvent
use InteractsWithSockets;
use SerializesModels;

public function __construct(public array $token)
{

}
public function __construct(public array $token) {}
}
18 changes: 17 additions & 1 deletion src/MsGraph.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 = '';
Expand Down Expand Up @@ -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
*/
Expand Down Expand Up @@ -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'));
}
Expand Down Expand Up @@ -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();
}
Expand Down
78 changes: 78 additions & 0 deletions tests/MsGraphTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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' => '[email protected]']);

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' => '[email protected]']);

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' => '[email protected]']);

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' => '[email protected]']);
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');
});
Loading