3 namespace Tests\Actions;
6 use BookStack\Actions\Activity;
7 use BookStack\Actions\ActivityLogger;
8 use BookStack\Actions\ActivityType;
9 use BookStack\Auth\UserRepo;
10 use BookStack\Entities\Models\Chapter;
11 use BookStack\Entities\Models\Page;
12 use BookStack\Entities\Repos\PageRepo;
13 use BookStack\Entities\Tools\TrashCan;
18 class AuditLogTest extends TestCase
20 /** @var ActivityLogger */
21 protected $activityService;
23 protected function setUp(): void
26 $this->activityService = app(ActivityLogger::class);
29 public function test_only_accessible_with_right_permissions()
31 $viewer = $this->getViewer();
32 $this->actingAs($viewer);
34 $resp = $this->get('/settings/audit');
35 $this->assertPermissionError($resp);
37 $this->giveUserPermissions($viewer, ['settings-manage']);
38 $resp = $this->get('/settings/audit');
39 $this->assertPermissionError($resp);
41 $this->giveUserPermissions($viewer, ['users-manage']);
42 $resp = $this->get('/settings/audit');
43 $resp->assertStatus(200);
44 $resp->assertSeeText('Audit Log');
47 public function test_shows_activity()
49 $admin = $this->getAdmin();
50 $this->actingAs($admin);
51 $page = Page::query()->first();
52 $this->activityService->add(ActivityType::PAGE_CREATE, $page);
53 $activity = Activity::query()->orderBy('id', 'desc')->first();
55 $resp = $this->get('settings/audit');
56 $resp->assertSeeText($page->name);
57 $resp->assertSeeText('page_create');
58 $resp->assertSeeText($activity->created_at->toDateTimeString());
59 $resp->assertElementContains('.table-user-item', $admin->name);
62 public function test_shows_name_for_deleted_items()
64 $this->actingAs($this->getAdmin());
65 $page = Page::query()->first();
66 $pageName = $page->name;
67 $this->activityService->add(ActivityType::PAGE_CREATE, $page);
69 app(PageRepo::class)->destroy($page);
70 app(TrashCan::class)->empty();
72 $resp = $this->get('settings/audit');
73 $resp->assertSeeText('Deleted Item');
74 $resp->assertSeeText('Name: ' . $pageName);
77 public function test_shows_activity_for_deleted_users()
79 $viewer = $this->getViewer();
80 $this->actingAs($viewer);
81 $page = Page::query()->first();
82 $this->activityService->add(ActivityType::PAGE_CREATE, $page);
84 $this->actingAs($this->getAdmin());
85 app(UserRepo::class)->destroy($viewer);
87 $resp = $this->get('settings/audit');
88 $resp->assertSeeText("[ID: {$viewer->id}] Deleted User");
91 public function test_filters_by_key()
93 $this->actingAs($this->getAdmin());
94 $page = Page::query()->first();
95 $this->activityService->add(ActivityType::PAGE_CREATE, $page);
97 $resp = $this->get('settings/audit');
98 $resp->assertSeeText($page->name);
100 $resp = $this->get('settings/audit?event=page_delete');
101 $resp->assertDontSeeText($page->name);
104 public function test_date_filters()
106 $this->actingAs($this->getAdmin());
107 $page = Page::query()->first();
108 $this->activityService->add(ActivityType::PAGE_CREATE, $page);
110 $yesterday = (Carbon::now()->subDay()->format('Y-m-d'));
111 $tomorrow = (Carbon::now()->addDay()->format('Y-m-d'));
113 $resp = $this->get('settings/audit?date_from=' . $yesterday);
114 $resp->assertSeeText($page->name);
116 $resp = $this->get('settings/audit?date_from=' . $tomorrow);
117 $resp->assertDontSeeText($page->name);
119 $resp = $this->get('settings/audit?date_to=' . $tomorrow);
120 $resp->assertSeeText($page->name);
122 $resp = $this->get('settings/audit?date_to=' . $yesterday);
123 $resp->assertDontSeeText($page->name);
126 public function test_user_filter()
128 $admin = $this->getAdmin();
129 $editor = $this->getEditor();
130 $this->actingAs($admin);
131 $page = Page::query()->first();
132 $this->activityService->add(ActivityType::PAGE_CREATE, $page);
134 $this->actingAs($editor);
135 $chapter = Chapter::query()->first();
136 $this->activityService->add(ActivityType::CHAPTER_UPDATE, $chapter);
138 $resp = $this->actingAs($admin)->get('settings/audit?user=' . $admin->id);
139 $resp->assertSeeText($page->name);
140 $resp->assertDontSeeText($chapter->name);
142 $resp = $this->actingAs($admin)->get('settings/audit?user=' . $editor->id);
143 $resp->assertSeeText($chapter->name);
144 $resp->assertDontSeeText($page->name);
147 public function test_ip_address_logged_and_visible()
149 config()->set('app.proxies', '*');
150 $editor = $this->getEditor();
151 /** @var Page $page */
152 $page = Page::query()->first();
154 $this->actingAs($editor)->put($page->getUrl(), [
155 'name' => 'Updated page',
156 'html' => '<p>Updated content</p>',
158 'X-Forwarded-For' => '192.123.45.1',
159 ])->assertRedirect($page->refresh()->getUrl());
161 $this->assertDatabaseHas('activities', [
162 'type' => ActivityType::PAGE_UPDATE,
163 'ip' => '192.123.45.1',
164 'user_id' => $editor->id,
165 'entity_id' => $page->id,
168 $resp = $this->asAdmin()->get('/settings/audit');
169 $resp->assertSee('192.123.45.1');
172 public function test_ip_address_is_searchable()
174 config()->set('app.proxies', '*');
175 $editor = $this->getEditor();
176 /** @var Page $page */
177 $page = Page::query()->first();
179 $this->actingAs($editor)->put($page->getUrl(), [
180 'name' => 'Updated page',
181 'html' => '<p>Updated content</p>',
183 'X-Forwarded-For' => '192.123.45.1',
184 ])->assertRedirect($page->refresh()->getUrl());
186 $this->actingAs($editor)->put($page->getUrl(), [
187 'name' => 'Updated page',
188 'html' => '<p>Updated content</p>',
190 'X-Forwarded-For' => '192.122.45.1',
191 ])->assertRedirect($page->refresh()->getUrl());
193 $resp = $this->asAdmin()->get('/settings/audit?&ip=192.123');
194 $resp->assertSee('192.123.45.1');
195 $resp->assertDontSee('192.122.45.1');
198 public function test_ip_address_not_logged_in_demo_mode()
200 config()->set('app.proxies', '*');
201 config()->set('app.env', 'demo');
202 $editor = $this->getEditor();
203 /** @var Page $page */
204 $page = Page::query()->first();
206 $this->actingAs($editor)->put($page->getUrl(), [
207 'name' => 'Updated page',
208 'html' => '<p>Updated content</p>',
210 'X-Forwarded-For' => '192.123.45.1',
211 'REMOTE_ADDR' => '192.123.45.2',
212 ])->assertRedirect($page->refresh()->getUrl());
214 $this->assertDatabaseHas('activities', [
215 'type' => ActivityType::PAGE_UPDATE,
217 'user_id' => $editor->id,
218 'entity_id' => $page->id,
222 public function test_ip_address_respects_precision_setting()
224 config()->set('app.proxies', '*');
225 config()->set('app.ip_address_precision', 2);
226 $editor = $this->getEditor();
227 /** @var Page $page */
228 $page = Page::query()->first();
230 $this->actingAs($editor)->put($page->getUrl(), [
231 'name' => 'Updated page',
232 'html' => '<p>Updated content</p>',
234 'X-Forwarded-For' => '192.123.45.1',
235 ])->assertRedirect($page->refresh()->getUrl());
237 $this->assertDatabaseHas('activities', [
238 'type' => ActivityType::PAGE_UPDATE,
239 'ip' => '192.123.x.x',
240 'user_id' => $editor->id,
241 'entity_id' => $page->id,