diff --git a/README.md b/README.md index 4c2bd5e..2ea5153 100644 --- a/README.md +++ b/README.md @@ -177,7 +177,7 @@ A sample meta ] ``` -### Custom History +### Custom history Besides the built in `created/updating/deleting/restoring` events, you may store custom history record with `ModelChanged` event. @@ -217,6 +217,28 @@ This will translate your model history into You may set whitelist and blacklist in config file. Please follow the description guide in the published config file. +### Auth guards + +If your users are using non-default auth guards, you might see all `$history->hasUser()` become `false` even though the history sources were generated by authenticated users. + +To fix this, you'll need to enable custom auth guards scanning in config file: + +```php +/* +|-------------------------------------------------------------- +| Enable auth guards scan +|-------------------------------------------------------------- +| +| You only need to enable this if your users are using non-default auth guards. +| In that case, all tracked user operations will be anonymous. +| +| - Set to `true` to use a full scan mode: all auth guards will be checked. However this does not ensure guard priority. +| - Set to an array to scan only specific auth guards(in the given order). e.g. `['web', 'api', 'admin']` +| +*/ +'auth_guards' => null +``` + ### Known issues 1. When updating a model, if its model label(attributes returned from `getModelLabel`) has been modified, the history message will use its new attributes, which might not be what you expect. diff --git a/src/HistoryObserver.php b/src/HistoryObserver.php index 068d7a5..58b28f0 100644 --- a/src/HistoryObserver.php +++ b/src/HistoryObserver.php @@ -3,6 +3,7 @@ namespace Panoscape\History; use Illuminate\Support\Str; +use Illuminate\Support\Facades\Auth; class HistoryObserver { @@ -106,12 +107,12 @@ public static function getModelName($model) public static function getUserID() { - return auth()->check() ? auth()->user()->id : null; + return static::getAuth()->check() ? static::getAuth()->user()->id : null; } public static function getUserType() { - return auth()->check() ? get_class(auth()->user()) : null; + return static::getAuth()->check() ? get_class(static::getAuth()->user()) : null; } public static function isIgnored($model, $key) @@ -124,16 +125,38 @@ public static function isIgnored($model, $key) public static function filter($action) { - if(!auth()->check()) { + if(!static::getAuth()->check()) { if(in_array('nobody', config('history.user_blacklist'))) { return false; } } - elseif(in_array(get_class(auth()->user()), config('history.user_blacklist'))) { + elseif(in_array(get_class(static::getAuth()->user()), config('history.user_blacklist'))) { return false; } return is_null($action) || in_array($action, config('history.events_whitelist')); } + + private static function getAuth() + { + $guards = config('history.auth_guards'); + if(is_bool($guards) && $guards == true) + return auth(static::activeGuard()); + if(is_array($guards)) + { + foreach($guards as $guard) + if(auth($guard)->check()) return auth($guard); + } + return auth(); + } + + private static function activeGuard() + { + foreach(array_keys(config('auth.guards')) as $guard) + { + if(auth($guard)->check()) return $guard; + } + return null; + } } diff --git a/src/config/history.php b/src/config/history.php index b59622e..544aab8 100644 --- a/src/config/history.php +++ b/src/config/history.php @@ -93,5 +93,19 @@ 'env_blacklist' => [ ], + + /* + |-------------------------------------------------------------- + | Enable auth guards scan + |-------------------------------------------------------------- + | + | You only need to enable this if your users are using non-default auth guards. + | In that case, all tracked user operations will be anonymous. + | + | - Set to `true` to use a full scan mode: all auth guards will be checked. However this does not ensure guard priority. + | - Set to an array to scan only specific auth guards(in the given order). e.g. `['web', 'api', 'admin']` + | + */ + 'auth_guards' => null, ]; \ No newline at end of file diff --git a/tests/TestCaseTest.php b/tests/TestCaseTest.php index 8007af4..e656cae 100644 --- a/tests/TestCaseTest.php +++ b/tests/TestCaseTest.php @@ -5,6 +5,7 @@ use Orchestra\Testbench\TestCase; use Illuminate\Database\Schema\Blueprint; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Auth; use Panoscape\History\History; use Panoscape\History\HistoryServiceProvider; use Panoscape\History\Events\ModelChanged; @@ -36,6 +37,12 @@ protected function getEnvironmentSetUp($app) 'password' ] ]); + $app['config']->set('history.auth_guards', ['web','admin']); + // custom auth guard mock + $app['config']->set('auth.guards.admin.driver', 'admin-login'); + Auth::viaRequest('admin-login', function(Request $request) { + return null; + }); $app['router']->post('articles', function(Request $request) { return Article::create(['title' => $request->title]); @@ -58,7 +65,7 @@ protected function getEnvironmentSetUp($app) event(new ModelChanged($model, 'Query Article ' . $model->title, $model->pluck('id')->toArray())); } return $model; - }); + }); } public function setUp(): void @@ -166,6 +173,32 @@ public function testAnonymous() $this->assertNull($history->user()); } + public function testCustomGuard() + { + $user = User::first(); + $this->assertNotNull($user); + + $content = ['title' => 'voluptas ut rem']; + $this->actingAsAdmin($user)->json('POST', '/articles', $content)->assertJson($content); + + $article = Article::first(); + $this->assertNotNull($article); + $histories = $article->histories; + $this->assertNotNull($histories); + $this->assertEquals(1, count($histories)); + $history = $histories[0]; + $this->assertTrue($history->hasUser()); + $this->assertNotNull($history->user()); + $this->assertEquals($user->toJson(), $history->user()->toJson()); + $this->assertEquals($article->makeHidden('histories')->toJson(), $history->model()->toJson()); + + $operations = $user->operations; + $this->assertNotNull($operations); + $this->assertEquals(1, count($operations)); + $operation = $operations[0]; + $this->assertEquals($history->toJson(), $operation->toJson()); + } + public function testCustomEvent() { Article::create(['title' => 'maxime fugit saepe']); @@ -178,4 +211,11 @@ public function testCustomEvent() $this->assertEquals('Query Article ' . $article->title, $history->message); $this->assertEquals([$article->id], $history->meta); } + + private function actingAsAdmin($admin) { + $defaultGuard = config('auth.defaults.guard'); + $this->actingAs($admin, 'admin'); + Auth::shouldUse($defaultGuard); + return $this; + } } \ No newline at end of file