diff --git a/lib/Controller/AvatarController.php b/lib/Controller/AvatarController.php index 7edebf977d..876f0dc22b 100644 --- a/lib/Controller/AvatarController.php +++ b/lib/Controller/AvatarController.php @@ -86,6 +86,7 @@ class AvatarController extends AEnvironmentAwareController { $response = new FileDisplayResponse($file); $response->addHeader('Content-Type', $file->getMimeType()); + $response->addHeader('X-NC-IsCustomAvatar', $this->avatarService->isCustomAvatar($this->getRoom()) ? '1' : '0'); // Cache for 1 day $response->cacheFor(60 * 60 * 24, false, true); return $response; diff --git a/lib/Service/AvatarService.php b/lib/Service/AvatarService.php index 5dd942fc47..2a05137612 100644 --- a/lib/Service/AvatarService.php +++ b/lib/Service/AvatarService.php @@ -185,19 +185,26 @@ class AvatarService { } elseif ($this->emojiHelper->isValidSingleEmoji(mb_substr($room->getName(), 0, 1))) { $file = new InMemoryFile($token, $this->getEmojiAvatar($room->getName(), $darkTheme)); } elseif ($room->getType() === Room::TYPE_CHANGELOG) { - $file = new InMemoryFile($token, file_get_contents(__DIR__ . '/../../img/changelog.svg')); + $fileName = 'changelog.svg'; + $file = new InMemoryFile($fileName, file_get_contents(__DIR__ . '/../../img/' . $fileName)); } elseif ($room->getObjectType() === 'file') { - $file = new InMemoryFile($token, file_get_contents(__DIR__ . '/../../img/icon-conversation-text-' . $colorTone . '.svg')); + $fileName = 'icon-conversation-text-' . $colorTone . '.svg'; + $file = new InMemoryFile($fileName, file_get_contents(__DIR__ . '/../../img/' . $fileName)); } elseif ($room->getObjectType() === 'share:password') { - $file = new InMemoryFile($token, file_get_contents(__DIR__ . '/../../img/icon-conversation-password-' . $colorTone . '.svg')); + $fileName = 'icon-conversation-password-' . $colorTone . '.svg'; + $file = new InMemoryFile($fileName, file_get_contents(__DIR__ . '/../../img/' . $fileName)); } elseif ($room->getObjectType() === 'emails') { - $file = new InMemoryFile($token, file_get_contents(__DIR__ . '/../../img/icon-conversation-mail-' . $colorTone . '.svg')); + $fileName = 'icon-conversation-mail-' . $colorTone . '.svg'; + $file = new InMemoryFile($fileName, file_get_contents(__DIR__ . '/../../img/' . $fileName)); } elseif ($room->getType() === Room::TYPE_PUBLIC) { - $file = new InMemoryFile($token, file_get_contents(__DIR__ . '/../../img/icon-conversation-public-' . $colorTone . '.svg')); + $fileName = 'icon-conversation-public-' . $colorTone . '.svg'; + $file = new InMemoryFile($fileName, file_get_contents(__DIR__ . '/../../img/' . $fileName)); } elseif ($room->getType() === Room::TYPE_ONE_TO_ONE_FORMER) { - $file = new InMemoryFile($token, file_get_contents(__DIR__ . '/../../img/icon-conversation-user-' . $colorTone . '.svg')); + $fileName = 'icon-conversation-user-' . $colorTone . '.svg'; + $file = new InMemoryFile($fileName, file_get_contents(__DIR__ . '/../../img/' . $fileName)); } else { - $file = new InMemoryFile($token, file_get_contents(__DIR__ . '/../../img/icon-conversation-group-' . $colorTone . '.svg')); + $fileName = 'icon-conversation-group-' . $colorTone . '.svg'; + $file = new InMemoryFile($fileName, file_get_contents(__DIR__ . '/../../img/' . $fileName)); } } return $file; @@ -245,6 +252,11 @@ class AvatarService { return ''; } + public function isCustomAvatar(Room $room): bool { + return $room->getAvatar() !== '' + || $this->getFirstCombinedEmoji($room->getName()); + } + public function deleteAvatar(Room $room): void { try { $folder = $this->appData->getFolder('room-avatar'); @@ -270,7 +282,11 @@ class AvatarService { public function getAvatarVersion(Room $room): string { $avatarVersion = $room->getAvatar(); - [$version] = explode('.', $avatarVersion); - return $version; + if ($avatarVersion) { + [$version] = explode('.', $avatarVersion); + return $version; + } + $file = $this->getAvatar($room, null); + return substr(md5($file->getName()), 0, 8); } } diff --git a/tests/integration/features/bootstrap/FeatureContext.php b/tests/integration/features/bootstrap/FeatureContext.php index 6276e1bbaf..924dac174c 100644 --- a/tests/integration/features/bootstrap/FeatureContext.php +++ b/tests/integration/features/bootstrap/FeatureContext.php @@ -1200,6 +1200,10 @@ class FeatureContext implements Context, SnippetAcceptingContext { $xpectedAttributes = $formData->getColumnsHash()[0]; $actual = $this->getDataFromResponse($this->response); foreach ($xpectedAttributes as $attribute => $expectedValue) { + if ($expectedValue === 'NOT_EMPTY') { + Assert::assertNotEmpty($actual[$attribute]); + continue; + } Assert::assertEquals($expectedValue, $actual[$attribute]); } } @@ -3485,4 +3489,27 @@ class FeatureContext implements Context, SnippetAcceptingContext { Assert::assertEquals($statusCode, $response->getStatusCode(), $message); } } + + /** + * @Then The following headers should be set + * @param TableNode $table + * @throws \Exception + */ + public function theFollowingHeadersShouldBeSet(TableNode $table) { + foreach ($table->getTable() as $header) { + $headerName = $header[0]; + $expectedHeaderValue = $header[1]; + $returnedHeader = $this->response->getHeader($headerName)[0]; + if ($returnedHeader !== $expectedHeaderValue) { + throw new \Exception( + sprintf( + "Expected value '%s' for header '%s', got '%s'", + $expectedHeaderValue, + $headerName, + $returnedHeader + ) + ); + } + } + } } diff --git a/tests/integration/features/conversation/avatar.feature b/tests/integration/features/conversation/avatar.feature index 00965c6e59..605eecbff0 100644 --- a/tests/integration/features/conversation/avatar.feature +++ b/tests/integration/features/conversation/avatar.feature @@ -17,6 +17,8 @@ Feature: conversation/avatar | roomName | room2 | When user "participant1" uploads file "/img/favicon.png" as avatar of room "room2" with 200 Then the room "room2" has an avatar with 200 + And The following headers should be set + | X-NC-IsCustomAvatar | 1 | And user "participant1" sees the following system messages in room "room2" with 200 | room | actorType | actorId | systemMessage | message | | room2 | users | participant1 | avatar_set | You set the conversation picture | @@ -27,6 +29,12 @@ Feature: conversation/avatar | room2 | users | participant1 | avatar_removed | You removed the conversation picture | | room2 | users | participant1 | avatar_set | You set the conversation picture | | room2 | users | participant1 | conversation_created | You created the conversation | + And user "participant1" gets room "room2" with 200 (v4) + | avatarVersion | + | NOT_EMPTY | + Then the room "room2" has an avatar with 200 + And The following headers should be set + | X-NC-IsCustomAvatar | 0 | Scenario: Get avatar of conversation without custom avatar (fallback) Given user "participant1" creates room "room3" (v4) diff --git a/tests/php/Service/AvatarServiceTest.php b/tests/php/Service/AvatarServiceTest.php index 97cfc80feb..44fa822aee 100644 --- a/tests/php/Service/AvatarServiceTest.php +++ b/tests/php/Service/AvatarServiceTest.php @@ -83,16 +83,19 @@ class AvatarServiceTest extends TestCase { public function testGetAvatarVersion(string $avatar, string $expected): void { /** @var Room|MockObject $room */ $room = $this->createMock(Room::class); - $room->expects($this->once()) - ->method('getAvatar') + $room->method('getAvatar') ->willReturn($avatar); $actual = $this->service->getAvatarVersion($room); - $this->assertEquals($expected, $actual); + if ($expected === 'STRING WITH 8 CHARS') { + $this->assertEquals(8, strlen($actual)); + } else { + $this->assertEquals($expected, $actual); + } } public function dataGetAvatarVersion(): array { return [ - ['', ''], + ['', 'STRING WITH 8 CHARS'], ['1', '1'], ['1.png', '1'], ];