]> BookStack Code Mirror - bookstack/blob - tests/Uploads/AvatarTest.php
Opensearch: Fixed XML declaration when php short tags enabled
[bookstack] / tests / Uploads / AvatarTest.php
1 <?php
2
3 namespace Tests\Uploads;
4
5 use BookStack\Exceptions\HttpFetchException;
6 use BookStack\Uploads\UserAvatars;
7 use BookStack\Users\Models\User;
8 use GuzzleHttp\Exception\ConnectException;
9 use GuzzleHttp\Psr7\Request;
10 use GuzzleHttp\Psr7\Response;
11 use Tests\TestCase;
12
13 class AvatarTest extends TestCase
14 {
15     protected function createUserRequest($user): User
16     {
17         $this->asAdmin()->post('/settings/users/create', [
18             'name'             => $user->name,
19             'email'            => $user->email,
20             'password'         => 'testing101',
21             'password-confirm' => 'testing101',
22         ]);
23
24         return User::query()->where('email', '=', $user->email)->first();
25     }
26
27     protected function deleteUserImage(User $user): void
28     {
29         $this->files->deleteAtRelativePath($user->avatar->path);
30     }
31
32     public function test_gravatar_fetched_on_user_create()
33     {
34         $requests = $this->mockHttpClient([new Response(200, ['Content-Type' => 'image/png'], $this->files->pngImageData())]);
35         config()->set(['services.disable_services' => false]);
36         $user = User::factory()->make();
37
38         $user = $this->createUserRequest($user);
39         $this->assertDatabaseHas('images', [
40             'type'       => 'user',
41             'created_by' => $user->id,
42         ]);
43         $this->deleteUserImage($user);
44
45         $expectedUri = 'https://www.gravatar.com/avatar/' . md5(strtolower($user->email)) . '?s=500&d=identicon';
46         $this->assertEquals($expectedUri, $requests->latestRequest()->getUri());
47     }
48
49     public function test_custom_url_used_if_set()
50     {
51         config()->set([
52             'services.disable_services' => false,
53             'services.avatar_url'       => 'https://example.com/${email}/${hash}/${size}',
54         ]);
55
56         $user = User::factory()->make();
57         $url = 'https://example.com/' . urlencode(strtolower($user->email)) . '/' . md5(strtolower($user->email)) . '/500';
58         $requests = $this->mockHttpClient([new Response(200, ['Content-Type' => 'image/png'], $this->files->pngImageData())]);
59
60         $user = $this->createUserRequest($user);
61         $this->assertEquals($url, $requests->latestRequest()->getUri());
62         $this->deleteUserImage($user);
63     }
64
65     public function test_avatar_not_fetched_if_no_custom_url_and_services_disabled()
66     {
67         config()->set(['services.disable_services' => true]);
68         $user = User::factory()->make();
69         $requests = $this->mockHttpClient([new Response()]);
70
71         $this->createUserRequest($user);
72
73         $this->assertEquals(0, $requests->requestCount());
74     }
75
76     public function test_avatar_not_fetched_if_avatar_url_option_set_to_false()
77     {
78         config()->set([
79             'services.disable_services' => false,
80             'services.avatar_url'       => false,
81         ]);
82
83         $user = User::factory()->make();
84         $requests = $this->mockHttpClient([new Response()]);
85
86         $this->createUserRequest($user);
87
88         $this->assertEquals(0, $requests->requestCount());
89     }
90
91     public function test_no_failure_but_error_logged_on_failed_avatar_fetch()
92     {
93         config()->set(['services.disable_services' => false]);
94
95         $this->mockHttpClient([new ConnectException('Failed to connect', new Request('GET', ''))]);
96
97         $logger = $this->withTestLogger();
98
99         $user = User::factory()->make();
100         $this->createUserRequest($user);
101         $this->assertTrue($logger->hasError('Failed to save user avatar image'));
102     }
103
104     public function test_exception_message_on_failed_fetch()
105     {
106         // set wrong url
107         config()->set([
108             'services.disable_services' => false,
109             'services.avatar_url'       => 'http_malformed_url/${email}/${hash}/${size}',
110         ]);
111
112         $user = User::factory()->make();
113         $avatar = app()->make(UserAvatars::class);
114         $logger = $this->withTestLogger();
115         $this->mockHttpClient([new ConnectException('Could not resolve host http_malformed_url', new Request('GET', ''))]);
116
117         $avatar->fetchAndAssignToUser($user);
118
119         $url = 'http_malformed_url/' . urlencode(strtolower($user->email)) . '/' . md5(strtolower($user->email)) . '/500';
120         $this->assertTrue($logger->hasError('Failed to save user avatar image'));
121         $exception = $logger->getRecords()[0]['context']['exception'];
122         $this->assertInstanceOf(HttpFetchException::class, $exception);
123         $this->assertEquals('Cannot get image from ' . $url, $exception->getMessage());
124         $this->assertEquals('Could not resolve host http_malformed_url', $exception->getPrevious()->getMessage());
125     }
126 }