Skip to content

Commit b2aa11a

Browse files
authored
Merge pull request #65 from binafy/feat/add-callback
[1.x] Feat/Add custom conditions
2 parents 41952fa + 32fde43 commit b2aa11a

File tree

7 files changed

+213
-1
lines changed

7 files changed

+213
-1
lines changed

README.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,12 @@
2222
- [Views](#visit-monitoring-views)
2323
- [Ajax Requests](#ajax-requests)
2424
- [Visit Monitoring Guest Mode](#visit-monitoring-guest-mode)
25+
- [Visit Monitoring Custom Conditions](#visit-monitoring-custom-conditions)
2526
- [Action Monitoring](#action-monitoring)
2627
- [Views](#action-monitoring-views)
2728
- [Reverse Proxy Config](#action-monitoring-reverse-proxy-config)
2829
- [Action Monitoring Guest Mode](#action-monitoring-guest-mode)
30+
- [Action Monitoring Custom Conditions](#action-monitoring-custom-conditions)
2931
- [Authentication Monitoring](#authentication-monitoring)
3032
- [Views](#authentication-monitoring-views)
3133
- [How to use in big projects](#how-to-use-in-big-projects)
@@ -366,6 +368,34 @@ When set to `false`, only authenticated user visits will be recorded.
366368
],
367369
```
368370

371+
<a name="visit-monitoring-custom-conditions"></a>
372+
### Visit Monitoring Custom Conditions
373+
374+
The `Laravel User Monitoring` package allows you to define custom conditions for visit monitoring.
375+
Conditions give you full control over when a visit should be logged.
376+
377+
#### 🔧 How It Works
378+
379+
- Conditions are checked before a visit is stored.
380+
- If any condition returns false, the visit will be skipped.
381+
- You can define conditions as closures or as class-based rules.
382+
383+
```php
384+
'visit_monitoring' => [
385+
'conditions' => [
386+
// Class-based condition (must implement MonitoringCondition interface)
387+
\App\Monitoring\YourCustomCondition::class,
388+
389+
// Closure-based condition (receives the Request and authenticated User)
390+
function (Illuminate\Http\Request $request) {
391+
$user = $request->user();
392+
393+
return $user && $user->isAdmin();
394+
},
395+
],
396+
],
397+
```
398+
369399
<a name="action-monitoring"></a>
370400
## Action Monitoring
371401

@@ -457,6 +487,34 @@ When set to `false`, only authenticated user visits will be recorded.
457487
],
458488
```
459489

490+
<a name="action-monitoring-custom-conditions"></a>
491+
### Action Monitoring Custom Conditions
492+
493+
The `Laravel User Monitoring` package lets you define custom conditions for action monitoring (create, update, delete events on models).
494+
Conditions give you control over when model actions should be logged.
495+
496+
#### 🔧 How It Works
497+
498+
- Conditions are checked before an action is stored.
499+
- If any condition returns false, the action will be skipped.
500+
- You can define conditions as closures or class-based rules.
501+
502+
```php
503+
'action_monitoring' => [
504+
'conditions' => [
505+
// Class-based condition (must implement MonitoringCondition interface)
506+
\App\Monitoring\YourCustomCondition::class,
507+
508+
// Closure-based condition (receives the Request and authenticated User)
509+
function (Illuminate\Http\Request $request) {
510+
$user = $request->user();
511+
512+
return $user && $user->isAdmin();
513+
},
514+
],
515+
],
516+
```
517+
460518
<a name="authentication-monitoring"></a>
461519
## Authentication Monitoring
462520

config/user-monitoring.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,16 @@
9898
* Determines whether to store `visits` even when the user is not logged in.
9999
*/
100100
'guest_mode' => true,
101+
102+
/*
103+
| Here you can define one or more conditions that determine whether a visit
104+
| should be logged. Each condition must return a boolean (true = log visit,
105+
| false = skip logging).
106+
|
107+
| All conditions are evaluated before monitoring. If any condition returns
108+
| false, the visit will NOT be recorded.
109+
*/
110+
'conditions' => [],
101111
],
102112

103113
/*
@@ -136,6 +146,13 @@
136146
* Determines whether to store `actions` even when the user is not logged in.
137147
*/
138148
'guest_mode' => true,
149+
150+
/*
151+
* Here you can define one or more conditions that determine whether an action
152+
* should be logged. Each condition must return a boolean (true = log action,
153+
* false = skip logging).
154+
*/
155+
'conditions' => [],
139156
],
140157

141158
/*
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace Binafy\LaravelUserMonitoring\Contracts;
4+
5+
use Illuminate\Http\Request;
6+
7+
interface MonitoringCondition
8+
{
9+
public function shouldMonitor(Request $request): bool;
10+
}

src/Middlewares/VisitMonitoringMiddleware.php

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Binafy\LaravelUserMonitoring\Middlewares;
44

5+
use Binafy\LaravelUserMonitoring\Contracts\MonitoringCondition;
56
use Binafy\LaravelUserMonitoring\Utills\Detector;
67
use Binafy\LaravelUserMonitoring\Utills\UserUtils;
78
use Closure;
@@ -25,7 +26,12 @@ public function handle(Request $request, Closure $next): mixed
2526
return $next($request);
2627
}
2728

28-
$detector = new Detector();
29+
// Custom conditions from config
30+
if (! $this->shouldMonitor($request)) {
31+
return $next($request);
32+
}
33+
34+
$detector = new Detector;
2935
$exceptPages = config('user-monitoring.visit_monitoring.except_pages', []);
3036

3137
if (empty($exceptPages) || !$this->checkIsExceptPages($request->path(), $exceptPages)) {
@@ -53,4 +59,30 @@ protected function checkIsExceptPages(string $page, array $exceptPages): bool
5359
{
5460
return collect($exceptPages)->contains($page);
5561
}
62+
63+
/**
64+
* Determine if monitoring should be performed for the given request and user.
65+
*/
66+
protected function shouldMonitor(Request $request): bool
67+
{
68+
$config = config('user-monitoring.visit_monitoring.conditions', []);
69+
70+
foreach ($config as $condition) {
71+
if (is_callable($condition)) {
72+
if (! $condition($request)) {
73+
return false;
74+
}
75+
} elseif (is_string($condition)) {
76+
$instance = new $condition;
77+
if (! $instance instanceof MonitoringCondition) {
78+
continue;
79+
}
80+
if (! $instance->shouldMonitor($request)) {
81+
return false;
82+
}
83+
}
84+
}
85+
86+
return true;
87+
}
5688
}

src/Traits/Actionable.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22

33
namespace Binafy\LaravelUserMonitoring\Traits;
44

5+
use Binafy\LaravelUserMonitoring\Contracts\MonitoringCondition;
56
use Binafy\LaravelUserMonitoring\Utills\ActionType;
67
use Binafy\LaravelUserMonitoring\Utills\Detector;
78
use Binafy\LaravelUserMonitoring\Utills\UserUtils;
9+
use Illuminate\Http\Request;
810
use Illuminate\Support\Facades\DB;
911

1012
trait Actionable
@@ -20,6 +22,11 @@ protected static function boot(): void
2022
return;
2123
}
2224

25+
// Custom conditions from config
26+
if (! static::shouldMonitor(request())) {
27+
return;
28+
}
29+
2330
if (config('user-monitoring.action_monitoring.on_store', false)) {
2431
static::created(function (mixed $model) {
2532
static::insertActionMonitoring($model, ActionType::ACTION_STORE);
@@ -94,4 +101,30 @@ private static function getRealIP(): string
94101
? request()->header(config('user-monitoring.real_ip_header'))
95102
: request()->ip();
96103
}
104+
105+
/**
106+
* Determine if monitoring should be performed for the given request and user.
107+
*/
108+
protected static function shouldMonitor(Request $request): bool
109+
{
110+
$config = config('user-monitoring.action_monitoring.conditions', []);
111+
112+
foreach ($config as $condition) {
113+
if (is_callable($condition)) {
114+
if (! $condition($request)) {
115+
return false;
116+
}
117+
} elseif (is_string($condition)) {
118+
$instance = new $condition;
119+
if (! $instance instanceof MonitoringCondition) {
120+
continue;
121+
}
122+
if (! $instance->shouldMonitor($request)) {
123+
return false;
124+
}
125+
}
126+
}
127+
128+
return true;
129+
}
97130
}

tests/Feature/ActionMonitoringTest.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
use Binafy\LaravelUserMonitoring\Utills\ActionType;
55
use Binafy\LaravelUserMonitoring\Utills\UserUtils;
66
use Illuminate\Foundation\Testing\RefreshDatabase;
7+
use Illuminate\Http\Request;
78
use Illuminate\Support\Facades\DB;
89
use Tests\SetUp\Models\Product;
910
use Tests\SetUp\Models\ProductSoftDelete;
@@ -361,3 +362,35 @@
361362
// DB Assertions
362363
assertDatabaseCount(config('user-monitoring.action_monitoring.table'), 2);
363364
});
365+
366+
test('action is stored when config conditions are true', function () {
367+
config()->set('user-monitoring.action_monitoring.conditions', [
368+
function (Request $request) {
369+
return true;
370+
},
371+
]);
372+
373+
Product::query()->create([
374+
'title' => 'milwad',
375+
'description' => 'WE ARE HELPING TO OPEN-SOURCE WORLD'
376+
]);
377+
378+
// DB Assertions
379+
assertDatabaseCount(config('user-monitoring.action_monitoring.table'), 1);
380+
});
381+
382+
test('action is not stored when config conditions are false', function () {
383+
config()->set('user-monitoring.action_monitoring.conditions', [
384+
function (Request $request) {
385+
return false;
386+
},
387+
]);
388+
389+
Product::query()->create([
390+
'title' => 'milwad',
391+
'description' => 'WE ARE HELPING TO OPEN-SOURCE WORLD'
392+
]);
393+
394+
// DB Assertions
395+
assertDatabaseCount(config('user-monitoring.action_monitoring.table'), 0);
396+
});

tests/Feature/VisitMonitoringTest.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
use Binafy\LaravelUserMonitoring\Models\VisitMonitoring;
44
use Illuminate\Foundation\Testing\RefreshDatabase;
5+
use Illuminate\Http\Request;
56
use Tests\SetUp\Models\User;
67
use function Pest\Laravel\{actingAs, get};
78
use function Pest\Laravel\{assertDatabaseCount, assertDatabaseHas, assertDatabaseMissing};
@@ -122,6 +123,34 @@
122123
assertDatabaseCount(config('user-monitoring.visit_monitoring.table'), 1);
123124
});
124125

126+
test('visit monitoring is store when config conditions are true', function () {
127+
config()->set('user-monitoring.visit_monitoring.conditions', [
128+
function (Request $request) {
129+
return true;
130+
},
131+
]);
132+
133+
$response = get('/');
134+
$response->assertContent('milwad');
135+
136+
// DB Assertions
137+
assertDatabaseCount(config('user-monitoring.visit_monitoring.table'), 1);
138+
});
139+
140+
test('visit monitoring is not store when config conditions are false', function () {
141+
config()->set('user-monitoring.visit_monitoring.conditions', [
142+
function (Request $request) {
143+
return false;
144+
},
145+
]);
146+
147+
$response = get('/');
148+
$response->assertContent('milwad');
149+
150+
// DB Assertions
151+
assertDatabaseCount(config('user-monitoring.visit_monitoring.table'), 0);
152+
});
153+
125154
/**
126155
* Create user and return it.
127156
*/

0 commit comments

Comments
 (0)