3 namespace Tests\Actions;
5 use BookStack\Actions\Activity;
6 use BookStack\Actions\ActivityLogger;
7 use BookStack\Actions\ActivityType;
8 use BookStack\Auth\UserRepo;
9 use BookStack\Entities\Repos\PageRepo;
10 use BookStack\Entities\Tools\TrashCan;
14 class AuditLogTest extends TestCase
16 protected ActivityLogger $activityService;
18 protected function setUp(): void
21 $this->activityService = app(ActivityLogger::class);
24 public function test_only_accessible_with_right_permissions()
26 $viewer = $this->users->viewer();
27 $this->actingAs($viewer);
29 $resp = $this->get('/settings/audit');
30 $this->assertPermissionError($resp);
32 $this->permissions->grantUserRolePermissions($viewer, ['settings-manage']);
33 $resp = $this->get('/settings/audit');
34 $this->assertPermissionError($resp);
36 $this->permissions->grantUserRolePermissions($viewer, ['users-manage']);
37 $resp = $this->get('/settings/audit');
38 $resp->assertStatus(200);
39 $resp->assertSeeText('Audit Log');
42 public function test_shows_activity()
44 $admin = $this->users->admin();
45 $this->actingAs($admin);
46 $page = $this->entities->page();
47 $this->activityService->add(ActivityType::PAGE_CREATE, $page);
48 $activity = Activity::query()->orderBy('id', 'desc')->first();
50 $resp = $this->get('settings/audit');
51 $resp->assertSeeText($page->name);
52 $resp->assertSeeText('page_create');
53 $resp->assertSeeText($activity->created_at->toDateTimeString());
54 $this->withHtml($resp)->assertElementContains('a[href*="users/' . $admin->id . '"]', $admin->name);
57 public function test_shows_name_for_deleted_items()
59 $this->actingAs($this->users->admin());
60 $page = $this->entities->page();
61 $pageName = $page->name;
62 $this->activityService->add(ActivityType::PAGE_CREATE, $page);
64 app(PageRepo::class)->destroy($page);
65 app(TrashCan::class)->empty();
67 $resp = $this->get('settings/audit');
68 $resp->assertSeeText('Deleted Item');
69 $resp->assertSeeText('Name: ' . $pageName);
72 public function test_shows_activity_for_deleted_users()
74 $viewer = $this->users->viewer();
75 $this->actingAs($viewer);
76 $page = $this->entities->page();
77 $this->activityService->add(ActivityType::PAGE_CREATE, $page);
79 $this->actingAs($this->users->admin());
80 app(UserRepo::class)->destroy($viewer);
82 $resp = $this->get('settings/audit');
83 $resp->assertSeeText("[ID: {$viewer->id}] Deleted User");
86 public function test_filters_by_key()
88 $this->actingAs($this->users->admin());
89 $page = $this->entities->page();
90 $this->activityService->add(ActivityType::PAGE_CREATE, $page);
92 $resp = $this->get('settings/audit');
93 $resp->assertSeeText($page->name);
95 $resp = $this->get('settings/audit?event=page_delete');
96 $resp->assertDontSeeText($page->name);
99 public function test_date_filters()
101 $this->actingAs($this->users->admin());
102 $page = $this->entities->page();
103 $this->activityService->add(ActivityType::PAGE_CREATE, $page);
105 $yesterday = (Carbon::now()->subDay()->format('Y-m-d'));
106 $tomorrow = (Carbon::now()->addDay()->format('Y-m-d'));
108 $resp = $this->get('settings/audit?date_from=' . $yesterday);
109 $resp->assertSeeText($page->name);
111 $resp = $this->get('settings/audit?date_from=' . $tomorrow);
112 $resp->assertDontSeeText($page->name);
114 $resp = $this->get('settings/audit?date_to=' . $tomorrow);
115 $resp->assertSeeText($page->name);
117 $resp = $this->get('settings/audit?date_to=' . $yesterday);
118 $resp->assertDontSeeText($page->name);
121 public function test_user_filter()
123 $admin = $this->users->admin();
124 $editor = $this->users->editor();
125 $this->actingAs($admin);
126 $page = $this->entities->page();
127 $this->activityService->add(ActivityType::PAGE_CREATE, $page);
129 $this->actingAs($editor);
130 $chapter = $this->entities->chapter();
131 $this->activityService->add(ActivityType::CHAPTER_UPDATE, $chapter);
133 $resp = $this->actingAs($admin)->get('settings/audit?user=' . $admin->id);
134 $resp->assertSeeText($page->name);
135 $resp->assertDontSeeText($chapter->name);
137 $resp = $this->actingAs($admin)->get('settings/audit?user=' . $editor->id);
138 $resp->assertSeeText($chapter->name);
139 $resp->assertDontSeeText($page->name);
142 public function test_ip_address_logged_and_visible()
144 config()->set('app.proxies', '*');
145 $editor = $this->users->editor();
146 $page = $this->entities->page();
148 $this->actingAs($editor)->put($page->getUrl(), [
149 'name' => 'Updated page',
150 'html' => '<p>Updated content</p>',
152 'X-Forwarded-For' => '192.123.45.1',
153 ])->assertRedirect($page->refresh()->getUrl());
155 $this->assertDatabaseHas('activities', [
156 'type' => ActivityType::PAGE_UPDATE,
157 'ip' => '192.123.45.1',
158 'user_id' => $editor->id,
159 'entity_id' => $page->id,
162 $resp = $this->asAdmin()->get('/settings/audit');
163 $resp->assertSee('192.123.45.1');
166 public function test_ip_address_is_searchable()
168 config()->set('app.proxies', '*');
169 $editor = $this->users->editor();
170 $page = $this->entities->page();
172 $this->actingAs($editor)->put($page->getUrl(), [
173 'name' => 'Updated page',
174 'html' => '<p>Updated content</p>',
176 'X-Forwarded-For' => '192.123.45.1',
177 ])->assertRedirect($page->refresh()->getUrl());
179 $this->actingAs($editor)->put($page->getUrl(), [
180 'name' => 'Updated page',
181 'html' => '<p>Updated content</p>',
183 'X-Forwarded-For' => '192.122.45.1',
184 ])->assertRedirect($page->refresh()->getUrl());
186 $resp = $this->asAdmin()->get('/settings/audit?&ip=192.123');
187 $resp->assertSee('192.123.45.1');
188 $resp->assertDontSee('192.122.45.1');
191 public function test_ip_address_not_logged_in_demo_mode()
193 config()->set('app.proxies', '*');
194 config()->set('app.env', 'demo');
195 $editor = $this->users->editor();
196 $page = $this->entities->page();
198 $this->actingAs($editor)->put($page->getUrl(), [
199 'name' => 'Updated page',
200 'html' => '<p>Updated content</p>',
202 'X-Forwarded-For' => '192.123.45.1',
203 'REMOTE_ADDR' => '192.123.45.2',
204 ])->assertRedirect($page->refresh()->getUrl());
206 $this->assertDatabaseHas('activities', [
207 'type' => ActivityType::PAGE_UPDATE,
209 'user_id' => $editor->id,
210 'entity_id' => $page->id,
214 public function test_ip_address_respects_precision_setting()
216 config()->set('app.proxies', '*');
217 config()->set('app.ip_address_precision', 2);
218 $editor = $this->users->editor();
219 $page = $this->entities->page();
221 $this->actingAs($editor)->put($page->getUrl(), [
222 'name' => 'Updated page',
223 'html' => '<p>Updated content</p>',
225 'X-Forwarded-For' => '192.123.45.1',
226 ])->assertRedirect($page->refresh()->getUrl());
228 $this->assertDatabaseHas('activities', [
229 'type' => ActivityType::PAGE_UPDATE,
230 'ip' => '192.123.x.x',
231 'user_id' => $editor->id,
232 'entity_id' => $page->id,