Skip to content

Commit baad7fa

Browse files
authored
Merge pull request #4987 from BookStackApp/audit_api
Addition of Audit Log API Endpoint
2 parents dd251d9 + d54c7b4 commit baad7fa

21 files changed

+250
-51
lines changed

app/Activity/ActivityQueries.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,14 @@ public function __construct(
2727
public function latest(int $count = 20, int $page = 0): array
2828
{
2929
$activityList = $this->permissions
30-
->restrictEntityRelationQuery(Activity::query(), 'activities', 'entity_id', 'entity_type')
30+
->restrictEntityRelationQuery(Activity::query(), 'activities', 'loggable_id', 'loggable_type')
3131
->orderBy('created_at', 'desc')
3232
->with(['user'])
3333
->skip($count * $page)
3434
->take($count)
3535
->get();
3636

37-
$this->listLoader->loadIntoRelations($activityList->all(), 'entity', false);
37+
$this->listLoader->loadIntoRelations($activityList->all(), 'loggable', false);
3838

3939
return $this->filterSimilar($activityList);
4040
}
@@ -59,14 +59,14 @@ public function entityActivity(Entity $entity, int $count = 20, int $page = 1):
5959
$query->where(function (Builder $query) use ($queryIds) {
6060
foreach ($queryIds as $morphClass => $idArr) {
6161
$query->orWhere(function (Builder $innerQuery) use ($morphClass, $idArr) {
62-
$innerQuery->where('entity_type', '=', $morphClass)
63-
->whereIn('entity_id', $idArr);
62+
$innerQuery->where('loggable_type', '=', $morphClass)
63+
->whereIn('loggable_id', $idArr);
6464
});
6565
}
6666
});
6767

6868
$activity = $query->orderBy('created_at', 'desc')
69-
->with(['entity' => function (Relation $query) {
69+
->with(['loggable' => function (Relation $query) {
7070
$query->withTrashed();
7171
}, 'user.avatar'])
7272
->skip($count * ($page - 1))
@@ -82,7 +82,7 @@ public function entityActivity(Entity $entity, int $count = 20, int $page = 1):
8282
public function userActivity(User $user, int $count = 20, int $page = 0): array
8383
{
8484
$activityList = $this->permissions
85-
->restrictEntityRelationQuery(Activity::query(), 'activities', 'entity_id', 'entity_type')
85+
->restrictEntityRelationQuery(Activity::query(), 'activities', 'loggable_id', 'loggable_type')
8686
->orderBy('created_at', 'desc')
8787
->where('user_id', '=', $user->id)
8888
->skip($count * $page)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
namespace BookStack\Activity\Controllers;
4+
5+
use BookStack\Activity\Models\Activity;
6+
use BookStack\Http\ApiController;
7+
8+
class AuditLogApiController extends ApiController
9+
{
10+
/**
11+
* Get a listing of audit log events in the system.
12+
* The loggable relation fields currently only relates to core
13+
* content types (page, book, bookshelf, chapter) but this may be
14+
* used more in the future across other types.
15+
* Requires permission to manage both users and system settings.
16+
*/
17+
public function list()
18+
{
19+
$this->checkPermission('settings-manage');
20+
$this->checkPermission('users-manage');
21+
22+
$query = Activity::query()->with(['user']);
23+
24+
return $this->apiListingResponse($query, [
25+
'id', 'type', 'detail', 'user_id', 'loggable_id', 'loggable_type', 'ip', 'created_at',
26+
]);
27+
}
28+
}

app/Activity/Controllers/AuditLogController.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public function index(Request $request)
3232

3333
$query = Activity::query()
3434
->with([
35-
'entity' => fn ($query) => $query->withTrashed(),
35+
'loggable' => fn ($query) => $query->withTrashed(),
3636
'user',
3737
])
3838
->orderBy($listOptions->getSort(), $listOptions->getOrder());

app/Activity/Models/Activity.php

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,24 @@
1515
/**
1616
* @property string $type
1717
* @property User $user
18-
* @property Entity $entity
18+
* @property Entity $loggable
1919
* @property string $detail
20-
* @property string $entity_type
21-
* @property int $entity_id
20+
* @property string $loggable_type
21+
* @property int $loggable_id
2222
* @property int $user_id
2323
* @property Carbon $created_at
24-
* @property Carbon $updated_at
2524
*/
2625
class Activity extends Model
2726
{
2827
/**
29-
* Get the entity for this activity.
28+
* Get the loggable model related to this activity.
29+
* Currently only used for entities (previously entity_[id/type] columns).
30+
* Could be used for others but will need an audit of uses where assumed
31+
* to be entities.
3032
*/
31-
public function entity(): MorphTo
33+
public function loggable(): MorphTo
3234
{
33-
if ($this->entity_type === '') {
34-
$this->entity_type = null;
35-
}
36-
37-
return $this->morphTo('entity');
35+
return $this->morphTo('loggable');
3836
}
3937

4038
/**
@@ -47,8 +45,8 @@ public function user(): BelongsTo
4745

4846
public function jointPermissions(): HasMany
4947
{
50-
return $this->hasMany(JointPermission::class, 'entity_id', 'entity_id')
51-
->whereColumn('activities.entity_type', '=', 'joint_permissions.entity_type');
48+
return $this->hasMany(JointPermission::class, 'entity_id', 'loggable_id')
49+
->whereColumn('activities.loggable_type', '=', 'joint_permissions.entity_type');
5250
}
5351

5452
/**
@@ -74,6 +72,6 @@ public function isForEntity(): bool
7472
*/
7573
public function isSimilarTo(self $activityB): bool
7674
{
77-
return [$this->type, $this->entity_type, $this->entity_id] === [$activityB->type, $activityB->entity_type, $activityB->entity_id];
75+
return [$this->type, $this->loggable_type, $this->loggable_id] === [$activityB->type, $activityB->loggable_type, $activityB->loggable_id];
7876
}
7977
}

app/Activity/Tools/ActivityLogger.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ public function add(string $type, string|Loggable $detail = ''): void
3232
$activity->detail = $detailToStore;
3333

3434
if ($detail instanceof Entity) {
35-
$activity->entity_id = $detail->id;
36-
$activity->entity_type = $detail->getMorphClass();
35+
$activity->loggable_id = $detail->id;
36+
$activity->loggable_type = $detail->getMorphClass();
3737
}
3838

3939
$activity->save();
@@ -64,9 +64,9 @@ protected function newActivityForUser(string $type): Activity
6464
public function removeEntity(Entity $entity): void
6565
{
6666
$entity->activity()->update([
67-
'detail' => $entity->name,
68-
'entity_id' => null,
69-
'entity_type' => null,
67+
'detail' => $entity->name,
68+
'loggable_id' => null,
69+
'loggable_type' => null,
7070
]);
7171
}
7272

app/Console/Commands/ClearActivityCommand.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class ClearActivityCommand extends Command
1919
*
2020
* @var string
2121
*/
22-
protected $description = 'Clear user activity from the system';
22+
protected $description = 'Clear user (audit-log) activity from the system';
2323

2424
/**
2525
* Execute the console command.

app/Entities/Models/Entity.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ public function matchesOrContains(self $entity): bool
137137
*/
138138
public function activity(): MorphMany
139139
{
140-
return $this->morphMany(Activity::class, 'entity')
140+
return $this->morphMany(Activity::class, 'loggable')
141141
->orderBy('created_at', 'desc');
142142
}
143143

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
7+
return new class extends Migration
8+
{
9+
/**
10+
* Run the migrations.
11+
*/
12+
public function up(): void
13+
{
14+
Schema::table('activities', function (Blueprint $table) {
15+
$table->renameColumn('entity_id', 'loggable_id');
16+
$table->renameColumn('entity_type', 'loggable_type');
17+
});
18+
}
19+
20+
/**
21+
* Reverse the migrations.
22+
*/
23+
public function down(): void
24+
{
25+
Schema::table('activities', function (Blueprint $table) {
26+
$table->renameColumn('loggable_id', 'entity_id');
27+
$table->renameColumn('loggable_type', 'entity_type');
28+
});
29+
}
30+
};
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
{
2+
"data": [
3+
{
4+
"id": 1,
5+
"type": "bookshelf_create",
6+
"detail": "",
7+
"user_id": 1,
8+
"loggable_id": 1,
9+
"loggable_type": "bookshelf",
10+
"ip": "124.4.x.x",
11+
"created_at": "2021-09-29T12:32:02.000000Z",
12+
"user": {
13+
"id": 1,
14+
"name": "Admins",
15+
"slug": "admins"
16+
}
17+
},
18+
{
19+
"id": 2,
20+
"type": "auth_login",
21+
"detail": "standard; (1) Admin",
22+
"user_id": 1,
23+
"loggable_id": null,
24+
"loggable_type": null,
25+
"ip": "127.0.x.x",
26+
"created_at": "2021-09-29T12:32:04.000000Z",
27+
"user": {
28+
"id": 1,
29+
"name": "Admins",
30+
"slug": "admins"
31+
}
32+
},
33+
{
34+
"id": 3,
35+
"type": "bookshelf_update",
36+
"detail": "",
37+
"user_id": 1,
38+
"loggable_id": 1,
39+
"loggable_type": "bookshelf",
40+
"ip": "127.0.x.x",
41+
"created_at": "2021-09-29T12:32:07.000000Z",
42+
"user": {
43+
"id": 1,
44+
"name": "Admins",
45+
"slug": "admins"
46+
}
47+
},
48+
{
49+
"id": 4,
50+
"type": "page_create",
51+
"detail": "",
52+
"user_id": 1,
53+
"loggable_id": 1,
54+
"loggable_type": "page",
55+
"ip": "127.0.x.x",
56+
"created_at": "2021-09-29T12:32:13.000000Z",
57+
"user": {
58+
"id": 1,
59+
"name": "Admins",
60+
"slug": "admins"
61+
}
62+
},
63+
{
64+
"id": 5,
65+
"type": "page_update",
66+
"detail": "",
67+
"user_id": 1,
68+
"loggable_id": 1,
69+
"loggable_type": "page",
70+
"ip": "127.0.x.x",
71+
"created_at": "2021-09-29T12:37:27.000000Z",
72+
"user": {
73+
"id": 1,
74+
"name": "Admins",
75+
"slug": "admins"
76+
}
77+
}
78+
],
79+
"total": 6088
80+
}

resources/views/common/activity-item.blade.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@
1616

1717
{{ $activity->getText() }}
1818

19-
@if($activity->entity && is_null($activity->entity->deleted_at))
20-
<a href="{{ $activity->entity->getUrl() }}">{{ $activity->entity->name }}</a>
19+
@if($activity->loggable && is_null($activity->loggable->deleted_at))
20+
<a href="{{ $activity->loggable->getUrl() }}">{{ $activity->loggable->name }}</a>
2121
@endif
2222

23-
@if($activity->entity && !is_null($activity->entity->deleted_at))
24-
"{{ $activity->entity->name }}"
23+
@if($activity->loggable && !is_null($activity->loggable->deleted_at))
24+
"{{ $activity->loggable->name }}"
2525
@endif
2626

2727
<br>

0 commit comments

Comments
 (0)