aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/Controller/AvatarController.php1
-rw-r--r--core/Controller/GuestAvatarController.php107
-rw-r--r--core/routes.php1
-rw-r--r--lib/composer/composer/autoload_classmap.php8
-rw-r--r--lib/composer/composer/autoload_static.php8
-rw-r--r--lib/private/Avatar/Avatar.php (renamed from lib/private/Avatar.php)287
-rw-r--r--lib/private/Avatar/AvatarManager.php (renamed from lib/private/AvatarManager.php)14
-rw-r--r--lib/private/Avatar/GuestAvatar.php119
-rw-r--r--lib/private/Avatar/UserAvatar.php336
-rw-r--r--lib/private/Repair.php2
-rw-r--r--lib/private/Repair/ClearGeneratedAvatarCache.php3
-rw-r--r--lib/private/Server.php1
-rw-r--r--lib/public/AppFramework/Http/FileDisplayResponse.php9
-rw-r--r--lib/public/Files/SimpleFS/InMemoryFile.php137
-rw-r--r--lib/public/IAvatarManager.php9
-rw-r--r--tests/Core/Controller/AvatarControllerTest.php4
-rw-r--r--tests/Core/Controller/GuestAvatarControllerTest.php90
-rw-r--r--tests/data/guest_avatar_einstein_32.svg5
-rw-r--r--tests/data/test.pdfbin0 -> 7083 bytes
-rw-r--r--tests/lib/Avatar/AvatarManagerTest.php (renamed from tests/lib/AvatarManagerTest.php)12
-rw-r--r--tests/lib/Avatar/GuestAvatarTest.php80
-rw-r--r--tests/lib/Avatar/UserAvatarTest.php (renamed from tests/lib/AvatarTest.php)8
-rw-r--r--tests/lib/Files/SimpleFS/InMemoryFileTest.php145
-rw-r--r--tests/lib/Repair/ClearGeneratedAvatarCacheTest.php2
-rw-r--r--tests/lib/ServerTest.php2
25 files changed, 1130 insertions, 260 deletions
diff --git a/core/Controller/AvatarController.php b/core/Controller/AvatarController.php
index 03efe4d1e52..9ee344f7ed8 100644
--- a/core/Controller/AvatarController.php
+++ b/core/Controller/AvatarController.php
@@ -42,7 +42,6 @@ use OCP\IL10N;
use OCP\IRequest;
use OCP\IUserManager;
use OCP\IUserSession;
-use OCP\AppFramework\Http\DataResponse;
/**
* Class AvatarController
diff --git a/core/Controller/GuestAvatarController.php b/core/Controller/GuestAvatarController.php
new file mode 100644
index 00000000000..76e140fee30
--- /dev/null
+++ b/core/Controller/GuestAvatarController.php
@@ -0,0 +1,107 @@
+<?php
+/**
+ * @copyright Copyright (c) 2019, Michael Weimann <mail@michael-weimann.eu>
+ *
+ * @author Michael Weimann <mail@michael-weimann.eu>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ */
+
+namespace OC\Core\Controller;
+
+use OCP\AppFramework\Controller;
+use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\FileDisplayResponse;
+use OCP\IAvatarManager;
+use OCP\ILogger;
+use OCP\IRequest;
+
+/**
+ * This controller handles guest avatar requests.
+ */
+class GuestAvatarController extends Controller {
+
+ /**
+ * @var ILogger
+ */
+ private $logger;
+
+ /**
+ * @var IAvatarManager
+ */
+ private $avatarManager;
+
+ /**
+ * GuestAvatarController constructor.
+ *
+ * @param $appName
+ * @param IRequest $request
+ * @param IAvatarManager $avatarManager
+ * @param ILogger $logger
+ */
+ public function __construct(
+ $appName,
+ IRequest $request,
+ IAvatarManager $avatarManager,
+ ILogger $logger
+ ) {
+ parent::__construct($appName, $request);
+ $this->avatarManager = $avatarManager;
+ $this->logger = $logger;
+ }
+
+ /**
+ * Returns a guest avatar image response.
+ *
+ * @PublicPage
+ * @NoCSRFRequired
+ *
+ * @param string $guestName The guest name, e.g. "Albert"
+ * @param string $size The desired avatar size, e.g. 64 for 64x64px
+ * @return FileDisplayResponse|Http\Response
+ */
+ public function getAvatar($guestName, $size) {
+ $size = (int) $size;
+
+ // min/max size
+ if ($size > 2048) {
+ $size = 2048;
+ } elseif ($size <= 0) {
+ $size = 64;
+ }
+
+ try {
+ $avatar = $this->avatarManager->getGuestAvatar($guestName);
+ $avatarFile = $avatar->getFile($size);
+
+ $resp = new FileDisplayResponse(
+ $avatarFile,
+ $avatar->isCustomAvatar() ? Http::STATUS_OK : Http::STATUS_CREATED,
+ ['Content-Type' => $avatarFile->getMimeType()]
+ );
+ } catch (\Exception $e) {
+ $this->logger->error('error while creating guest avatar', [
+ 'err' => $e,
+ ]);
+ $resp = new Http\Response();
+ $resp->setStatus(Http::STATUS_INTERNAL_SERVER_ERROR);
+ return $resp;
+ }
+
+ // Cache for 30 minutes
+ $resp->cacheFor(1800);
+ return $resp;
+ }
+}
diff --git a/core/routes.php b/core/routes.php
index f00e75cec89..c5de63b8f33 100644
--- a/core/routes.php
+++ b/core/routes.php
@@ -46,6 +46,7 @@ $application->registerRoutes($this, [
['name' => 'avatar#postCroppedAvatar', 'url' => '/avatar/cropped', 'verb' => 'POST'],
['name' => 'avatar#getTmpAvatar', 'url' => '/avatar/tmp', 'verb' => 'GET'],
['name' => 'avatar#postAvatar', 'url' => '/avatar/', 'verb' => 'POST'],
+ ['name' => 'GuestAvatar#getAvatar', 'url' => '/avatar/guest/{guestName}/{size}', 'verb' => 'GET'],
['name' => 'CSRFToken#index', 'url' => '/csrftoken', 'verb' => 'GET'],
['name' => 'login#tryLogin', 'url' => '/login', 'verb' => 'POST'],
['name' => 'login#confirmPassword', 'url' => '/login/confirm', 'verb' => 'POST'],
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php
index 5997825289e..8e1c1787226 100644
--- a/lib/composer/composer/autoload_classmap.php
+++ b/lib/composer/composer/autoload_classmap.php
@@ -221,6 +221,7 @@ return array(
'OCP\\Files\\SimpleFS\\ISimpleFile' => $baseDir . '/lib/public/Files/SimpleFS/ISimpleFile.php',
'OCP\\Files\\SimpleFS\\ISimpleFolder' => $baseDir . '/lib/public/Files/SimpleFS/ISimpleFolder.php',
'OCP\\Files\\SimpleFS\\ISimpleRoot' => $baseDir . '/lib/public/Files/SimpleFS/ISimpleRoot.php',
+ 'OCP\\Files\\SimpleFS\\InMemoryFile' => $baseDir . '/lib/public/Files/SimpleFS/InMemoryFile.php',
'OCP\\Files\\Storage' => $baseDir . '/lib/public/Files/Storage.php',
'OCP\\Files\\StorageAuthException' => $baseDir . '/lib/public/Files/StorageAuthException.php',
'OCP\\Files\\StorageBadConfigException' => $baseDir . '/lib/public/Files/StorageBadConfigException.php',
@@ -510,8 +511,10 @@ return array(
'OC\\Authentication\\TwoFactorAuth\\ProviderManager' => $baseDir . '/lib/private/Authentication/TwoFactorAuth/ProviderManager.php',
'OC\\Authentication\\TwoFactorAuth\\ProviderSet' => $baseDir . '/lib/private/Authentication/TwoFactorAuth/ProviderSet.php',
'OC\\Authentication\\TwoFactorAuth\\Registry' => $baseDir . '/lib/private/Authentication/TwoFactorAuth/Registry.php',
- 'OC\\Avatar' => $baseDir . '/lib/private/Avatar.php',
- 'OC\\AvatarManager' => $baseDir . '/lib/private/AvatarManager.php',
+ 'OC\\Avatar\\Avatar' => $baseDir . '/lib/private/Avatar/Avatar.php',
+ 'OC\\Avatar\\AvatarManager' => $baseDir . '/lib/private/Avatar/AvatarManager.php',
+ 'OC\\Avatar\\GuestAvatar' => $baseDir . '/lib/private/Avatar/GuestAvatar.php',
+ 'OC\\Avatar\\UserAvatar' => $baseDir . '/lib/private/Avatar/UserAvatar.php',
'OC\\BackgroundJob\\Job' => $baseDir . '/lib/private/BackgroundJob/Job.php',
'OC\\BackgroundJob\\JobList' => $baseDir . '/lib/private/BackgroundJob/JobList.php',
'OC\\BackgroundJob\\Legacy\\QueuedJob' => $baseDir . '/lib/private/BackgroundJob/Legacy/QueuedJob.php',
@@ -648,6 +651,7 @@ return array(
'OC\\Core\\Controller\\ClientFlowLoginController' => $baseDir . '/core/Controller/ClientFlowLoginController.php',
'OC\\Core\\Controller\\ContactsMenuController' => $baseDir . '/core/Controller/ContactsMenuController.php',
'OC\\Core\\Controller\\CssController' => $baseDir . '/core/Controller/CssController.php',
+ 'OC\\Core\\Controller\\GuestAvatarController' => $baseDir . '/core/Controller/GuestAvatarController.php',
'OC\\Core\\Controller\\JsController' => $baseDir . '/core/Controller/JsController.php',
'OC\\Core\\Controller\\LoginController' => $baseDir . '/core/Controller/LoginController.php',
'OC\\Core\\Controller\\LostController' => $baseDir . '/core/Controller/LostController.php',
diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php
index ff8bea3bd90..55604114bf4 100644
--- a/lib/composer/composer/autoload_static.php
+++ b/lib/composer/composer/autoload_static.php
@@ -251,6 +251,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OCP\\Files\\SimpleFS\\ISimpleFile' => __DIR__ . '/../../..' . '/lib/public/Files/SimpleFS/ISimpleFile.php',
'OCP\\Files\\SimpleFS\\ISimpleFolder' => __DIR__ . '/../../..' . '/lib/public/Files/SimpleFS/ISimpleFolder.php',
'OCP\\Files\\SimpleFS\\ISimpleRoot' => __DIR__ . '/../../..' . '/lib/public/Files/SimpleFS/ISimpleRoot.php',
+ 'OCP\\Files\\SimpleFS\\InMemoryFile' => __DIR__ . '/../../..' . '/lib/public/Files/SimpleFS/InMemoryFile.php',
'OCP\\Files\\Storage' => __DIR__ . '/../../..' . '/lib/public/Files/Storage.php',
'OCP\\Files\\StorageAuthException' => __DIR__ . '/../../..' . '/lib/public/Files/StorageAuthException.php',
'OCP\\Files\\StorageBadConfigException' => __DIR__ . '/../../..' . '/lib/public/Files/StorageBadConfigException.php',
@@ -540,8 +541,10 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\Authentication\\TwoFactorAuth\\ProviderManager' => __DIR__ . '/../../..' . '/lib/private/Authentication/TwoFactorAuth/ProviderManager.php',
'OC\\Authentication\\TwoFactorAuth\\ProviderSet' => __DIR__ . '/../../..' . '/lib/private/Authentication/TwoFactorAuth/ProviderSet.php',
'OC\\Authentication\\TwoFactorAuth\\Registry' => __DIR__ . '/../../..' . '/lib/private/Authentication/TwoFactorAuth/Registry.php',
- 'OC\\Avatar' => __DIR__ . '/../../..' . '/lib/private/Avatar.php',
- 'OC\\AvatarManager' => __DIR__ . '/../../..' . '/lib/private/AvatarManager.php',
+ 'OC\\Avatar\\Avatar' => __DIR__ . '/../../..' . '/lib/private/Avatar/Avatar.php',
+ 'OC\\Avatar\\AvatarManager' => __DIR__ . '/../../..' . '/lib/private/Avatar/AvatarManager.php',
+ 'OC\\Avatar\\GuestAvatar' => __DIR__ . '/../../..' . '/lib/private/Avatar/GuestAvatar.php',
+ 'OC\\Avatar\\UserAvatar' => __DIR__ . '/../../..' . '/lib/private/Avatar/UserAvatar.php',
'OC\\BackgroundJob\\Job' => __DIR__ . '/../../..' . '/lib/private/BackgroundJob/Job.php',
'OC\\BackgroundJob\\JobList' => __DIR__ . '/../../..' . '/lib/private/BackgroundJob/JobList.php',
'OC\\BackgroundJob\\Legacy\\QueuedJob' => __DIR__ . '/../../..' . '/lib/private/BackgroundJob/Legacy/QueuedJob.php',
@@ -678,6 +681,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\Core\\Controller\\ClientFlowLoginController' => __DIR__ . '/../../..' . '/core/Controller/ClientFlowLoginController.php',
'OC\\Core\\Controller\\ContactsMenuController' => __DIR__ . '/../../..' . '/core/Controller/ContactsMenuController.php',
'OC\\Core\\Controller\\CssController' => __DIR__ . '/../../..' . '/core/Controller/CssController.php',
+ 'OC\\Core\\Controller\\GuestAvatarController' => __DIR__ . '/../../..' . '/core/Controller/GuestAvatarController.php',
'OC\\Core\\Controller\\JsController' => __DIR__ . '/../../..' . '/core/Controller/JsController.php',
'OC\\Core\\Controller\\LoginController' => __DIR__ . '/../../..' . '/core/Controller/LoginController.php',
'OC\\Core\\Controller\\LostController' => __DIR__ . '/../../..' . '/core/Controller/LostController.php',
diff --git a/lib/private/Avatar.php b/lib/private/Avatar/Avatar.php
index 821ceb7d170..4468af82053 100644
--- a/lib/private/Avatar.php
+++ b/lib/private/Avatar/Avatar.php
@@ -1,4 +1,5 @@
<?php
+declare(strict_types=1);
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
* @copyright 2018 John Molakvoæ <skjnldsv@protonmail.com>
@@ -29,36 +30,22 @@
*
*/
-namespace OC;
+namespace OC\Avatar;
+use OC\Color;
use OCP\Files\NotFoundException;
-use OCP\Files\NotPermittedException;
-use OCP\Files\SimpleFS\ISimpleFile;
-use OCP\Files\SimpleFS\ISimpleFolder;
use OCP\IAvatar;
-use OCP\IConfig;
-use OCP\IImage;
-use OCP\IL10N;
use OCP\ILogger;
-use OC\User\User;
use OC_Image;
use Imagick;
/**
* This class gets and sets users avatars.
*/
+abstract class Avatar implements IAvatar {
-class Avatar implements IAvatar {
- /** @var ISimpleFolder */
- private $folder;
- /** @var IL10N */
- private $l;
- /** @var User */
- private $user;
/** @var ILogger */
- private $logger;
- /** @var IConfig */
- private $config;
+ protected $logger;
/**
* https://github.com/sebdesign/cap-height -- for 500px height
@@ -77,216 +64,50 @@ class Avatar implements IAvatar {
</svg>';
/**
- * constructor
+ * The base avatar constructor.
*
- * @param ISimpleFolder $folder The folder where the avatars are
- * @param IL10N $l
- * @param User $user
- * @param ILogger $logger
- * @param IConfig $config
+ * @param ILogger $logger The logger
*/
- public function __construct(ISimpleFolder $folder,
- IL10N $l,
- $user,
- ILogger $logger,
- IConfig $config) {
- $this->folder = $folder;
- $this->l = $l;
- $this->user = $user;
+ public function __construct(ILogger $logger) {
$this->logger = $logger;
- $this->config = $config;
}
/**
- * @inheritdoc
- */
- public function get($size = 64) {
- try {
- $file = $this->getFile($size);
- } catch (NotFoundException $e) {
- return false;
- }
-
- $avatar = new OC_Image();
- $avatar->loadFromData($file->getContent());
- return $avatar;
- }
-
- /**
- * Check if an avatar exists for the user
+ * Returns the user display name.
*
- * @return bool
+ * @return string
*/
- public function exists() {
-
- return $this->folder->fileExists('avatar.jpg') || $this->folder->fileExists('avatar.png');
- }
+ abstract public function getDisplayName(): string;
/**
- * Check if the avatar of a user is a custom uploaded one
+ * Returns the first letter of the display name, or "?" if no name given.
*
- * @return bool
- */
- public function isCustomAvatar(): bool {
- return $this->config->getUserValue($this->user->getUID(), 'avatar', 'generated', 'false') !== 'true';
- }
-
- /**
- * sets the users avatar
- * @param IImage|resource|string $data An image object, imagedata or path to set a new avatar
- * @throws \Exception if the provided file is not a jpg or png image
- * @throws \Exception if the provided image is not valid
- * @throws NotSquareException if the image is not square
- * @return void
+ * @return string
*/
- public function set($data) {
-
- if ($data instanceof IImage) {
- $img = $data;
- $data = $img->data();
+ private function getAvatarLetter(): string {
+ $displayName = $this->getDisplayName();
+ if (empty($displayName) === true) {
+ return '?';
} else {
- $img = new OC_Image();
- if (is_resource($data) && get_resource_type($data) === "gd") {
- $img->setResource($data);
- } elseif (is_resource($data)) {
- $img->loadFromFileHandle($data);
- } else {
- try {
- // detect if it is a path or maybe the images as string
- $result = @realpath($data);
- if ($result === false || $result === null) {
- $img->loadFromData($data);
- } else {
- $img->loadFromFile($data);
- }
- } catch (\Error $e) {
- $img->loadFromData($data);
- }
- }
- }
- $type = substr($img->mimeType(), -3);
- if ($type === 'peg') {
- $type = 'jpg';
- }
- if ($type !== 'jpg' && $type !== 'png') {
- throw new \Exception($this->l->t('Unknown filetype'));
- }
-
- if (!$img->valid()) {
- throw new \Exception($this->l->t('Invalid image'));
- }
-
- if (!($img->height() === $img->width())) {
- throw new NotSquareException($this->l->t('Avatar image is not square'));
- }
-
- $this->remove();
- $file = $this->folder->newFile('avatar.' . $type);
- $file->putContent($data);
-
- try {
- $generated = $this->folder->getFile('generated');
- $this->config->setUserValue($this->user->getUID(), 'avatar', 'generated', 'false');
- $generated->delete();
- } catch (NotFoundException $e) {
- //
- }
- $this->user->triggerChange('avatar', $file);
- }
-
- /**
- * remove the users avatar
- * @return void
- */
- public function remove() {
- $avatars = $this->folder->getDirectoryListing();
-
- $this->config->setUserValue($this->user->getUID(), 'avatar', 'version',
- (int) $this->config->getUserValue($this->user->getUID(), 'avatar', 'version', 0) + 1);
-
- foreach ($avatars as $avatar) {
- $avatar->delete();
+ return mb_strtoupper(mb_substr($displayName, 0, 1), 'UTF-8');
}
- $this->config->setUserValue($this->user->getUID(), 'avatar', 'generated', 'true');
- $this->user->triggerChange('avatar', '');
}
/**
* @inheritdoc
*/
- public function getFile($size) {
- try {
- $ext = $this->getExtension();
- } catch (NotFoundException $e) {
- if (!$data = $this->generateAvatarFromSvg(1024)) {
- $data = $this->generateAvatar($this->user->getDisplayName(), 1024);
- }
- $avatar = $this->folder->newFile('avatar.png');
- $avatar->putContent($data);
- $ext = 'png';
-
- $this->folder->newFile('generated');
- $this->config->setUserValue($this->user->getUID(), 'avatar', 'generated', 'true');
- }
-
- if ($size === -1) {
- $path = 'avatar.' . $ext;
- } else {
- $path = 'avatar.' . $size . '.' . $ext;
- }
+ public function get($size = 64) {
+ $size = (int) $size;
try {
- $file = $this->folder->getFile($path);
+ $file = $this->getFile($size);
} catch (NotFoundException $e) {
- if ($size <= 0) {
- throw new NotFoundException;
- }
-
- if ($this->folder->fileExists('generated')) {
- if (!$data = $this->generateAvatarFromSvg($size)) {
- $data = $this->generateAvatar($this->user->getDisplayName(), $size);
- }
-
- } else {
- $avatar = new OC_Image();
- /** @var ISimpleFile $file */
- $file = $this->folder->getFile('avatar.' . $ext);
- $avatar->loadFromData($file->getContent());
- $avatar->resize($size);
- $data = $avatar->data();
- }
-
- try {
- $file = $this->folder->newFile($path);
- $file->putContent($data);
- } catch (NotPermittedException $e) {
- $this->logger->error('Failed to save avatar for ' . $this->user->getUID());
- throw new NotFoundException();
- }
-
- }
-
- if ($this->config->getUserValue($this->user->getUID(), 'avatar', 'generated', null) === null) {
- $generated = $this->folder->fileExists('generated') ? 'true' : 'false';
- $this->config->setUserValue($this->user->getUID(), 'avatar', 'generated', $generated);
+ return false;
}
- return $file;
- }
-
- /**
- * Get the extension of the avatar. If there is no avatar throw Exception
- *
- * @return string
- * @throws NotFoundException
- */
- private function getExtension() {
- if ($this->folder->fileExists('avatar.jpg')) {
- return 'jpg';
- } elseif ($this->folder->fileExists('avatar.png')) {
- return 'png';
- }
- throw new NotFoundException;
+ $avatar = new OC_Image();
+ $avatar->loadFromData($file->getContent());
+ return $avatar;
}
/**
@@ -295,16 +116,16 @@ class Avatar implements IAvatar {
* {letter} = Letter to display
*
* Generate SVG avatar
+ *
+ * @param int $size The requested image size in pixel
* @return string
*
*/
- private function getAvatarVector(int $size): string {
- $userDisplayName = $this->user->getDisplayName();
-
+ protected function getAvatarVector(int $size): string {
+ $userDisplayName = $this->getDisplayName();
$bgRGB = $this->avatarBackgroundColor($userDisplayName);
$bgHEX = sprintf("%02x%02x%02x", $bgRGB->r, $bgRGB->g, $bgRGB->b);
- $letter = mb_strtoupper(mb_substr($userDisplayName, 0, 1), 'UTF-8');
-
+ $letter = $this->getAvatarLetter();
$toReplace = ['{size}', '{fill}', '{letter}'];
return str_replace($toReplace, [$size, $bgHEX, $letter], $this->svgTemplate);
}
@@ -315,7 +136,7 @@ class Avatar implements IAvatar {
* @param int $size
* @return string|boolean
*/
- private function generateAvatarFromSvg(int $size) {
+ protected function generateAvatarFromSvg(int $size) {
if (!extension_loaded('imagick')) {
return false;
}
@@ -341,22 +162,28 @@ class Avatar implements IAvatar {
* @param int $size
* @return string
*/
- private function generateAvatar($userDisplayName, $size) {
- $text = mb_strtoupper(mb_substr($userDisplayName, 0, 1), 'UTF-8');
+ protected function generateAvatar($userDisplayName, $size) {
+ $letter = $this->getAvatarLetter();
$backgroundColor = $this->avatarBackgroundColor($userDisplayName);
$im = imagecreatetruecolor($size, $size);
- $background = imagecolorallocate($im, $backgroundColor->r, $backgroundColor->g, $backgroundColor->b);
+ $background = imagecolorallocate(
+ $im,
+ $backgroundColor->r,
+ $backgroundColor->g,
+ $backgroundColor->b
+ );
$white = imagecolorallocate($im, 255, 255, 255);
imagefilledrectangle($im, 0, 0, $size, $size, $background);
- $font = __DIR__ . '/../../core/fonts/Nunito-Regular.ttf';
+ $font = __DIR__ . '/../../../core/fonts/Nunito-Regular.ttf';
$fontSize = $size * 0.4;
+ list($x, $y) = $this->imageTTFCenter(
+ $im, $letter, $font, (int)$fontSize
+ );
- list($x, $y) = $this->imageTTFCenter($im, $text, $font, $fontSize);
-
- imagettftext($im, $fontSize, 0, $x, $y, $white, $font, $text);
+ imagettftext($im, $fontSize, 0, $x, $y, $white, $font, $letter);
ob_start();
imagepng($im);
@@ -376,7 +203,13 @@ class Avatar implements IAvatar {
* @param int $angle
* @return array
*/
- protected function imageTTFCenter($image, string $text, string $font, int $size, $angle = 0): array {
+ protected function imageTTFCenter(
+ $image,
+ string $text,
+ string $font,
+ int $size,
+ $angle = 0
+ ): array {
// Image width & height
$xi = imagesx($image);
$yi = imagesy($image);
@@ -413,10 +246,9 @@ class Avatar implements IAvatar {
* Convert a string to an integer evenly
* @param string $hash the text to parse
* @param int $maximum the maximum range
- * @return int between 0 and $maximum
+ * @return int[] between 0 and $maximum
*/
private function mixPalette($steps, $color1, $color2) {
- $count = $steps + 1;
$palette = array($color1);
$step = $this->stepCalc($steps, [$color1, $color2]);
for ($i = 1; $i < $steps; $i++) {
@@ -483,19 +315,4 @@ class Avatar implements IAvatar {
return $finalPalette[$this->hashToInt($hash, $steps * 3)];
}
-
- public function userChanged($feature, $oldValue, $newValue) {
- // We only change the avatar on display name changes
- if ($feature !== 'displayName') {
- return;
- }
-
- // If the avatar is not generated (so an uploaded image) we skip this
- if (!$this->folder->fileExists('generated')) {
- return;
- }
-
- $this->remove();
- }
-
}
diff --git a/lib/private/AvatarManager.php b/lib/private/Avatar/AvatarManager.php
index 8fd64bc2206..567ed3aec1e 100644
--- a/lib/private/AvatarManager.php
+++ b/lib/private/Avatar/AvatarManager.php
@@ -26,7 +26,7 @@ declare(strict_types=1);
*
*/
-namespace OC;
+namespace OC\Avatar;
use OC\User\Manager;
use OCP\Files\IAppData;
@@ -102,7 +102,7 @@ class AvatarManager implements IAvatarManager {
$folder = $this->appData->newFolder($userId);
}
- return new Avatar($folder, $this->l, $user, $this->logger, $this->config);
+ return new UserAvatar($folder, $this->l, $user, $this->logger, $this->config);
}
/**
@@ -120,4 +120,14 @@ class AvatarManager implements IAvatarManager {
$this->config->setUserValue($userId, 'avatar', 'generated', 'false');
}
}
+
+ /**
+ * Returns a GuestAvatar.
+ *
+ * @param string $name The guest name, e.g. "Albert".
+ * @return IAvatar
+ */
+ public function getGuestAvatar(string $name): IAvatar {
+ return new GuestAvatar($name, $this->logger);
+ }
}
diff --git a/lib/private/Avatar/GuestAvatar.php b/lib/private/Avatar/GuestAvatar.php
new file mode 100644
index 00000000000..e0eefa47b6b
--- /dev/null
+++ b/lib/private/Avatar/GuestAvatar.php
@@ -0,0 +1,119 @@
+<?php
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2018, Michael Weimann <mail@michael-weimann.eu>
+ *
+ * @author Michael Weimann <mail@michael-weimann.eu>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ */
+
+namespace OC\Avatar;
+
+use OCP\Files\SimpleFS\InMemoryFile;
+use OCP\ILogger;
+
+/**
+ * This class represents a guest user's avatar.
+ */
+class GuestAvatar extends Avatar {
+ /**
+ * Holds the guest user display name.
+ *
+ * @var string
+ */
+ private $userDisplayName;
+
+ /**
+ * GuestAvatar constructor.
+ *
+ * @param string $userDisplayName The guest user display name
+ * @param ILogger $logger The logger
+ */
+ public function __construct(string $userDisplayName, ILogger $logger) {
+ parent::__construct($logger);
+ $this->userDisplayName = $userDisplayName;
+ }
+
+ /**
+ * Tests if the user has an avatar.
+ *
+ * @return true Guests always have an avatar.
+ */
+ public function exists() {
+ return true;
+ }
+
+ /**
+ * Returns the guest user display name.
+ *
+ * @return string
+ */
+ public function getDisplayName(): string {
+ return $this->userDisplayName;
+ }
+
+ /**
+ * Setting avatars isn't implemented for guests.
+ *
+ * @param \OCP\IImage|resource|string $data
+ * @return void
+ */
+ public function set($data) {
+ // unimplemented for guest user avatars
+ }
+
+ /**
+ * Removing avatars isn't implemented for guests.
+ */
+ public function remove() {
+ // unimplemented for guest user avatars
+ }
+
+ /**
+ * Generates an avatar for the guest.
+ *
+ * @param int $size The desired image size.
+ * @return InMemoryFile
+ */
+ public function getFile($size) {
+ $avatar = $this->getAvatarVector($size);
+ return new InMemoryFile('avatar.svg', $avatar);
+ }
+
+ /**
+ * Updates the display name if changed.
+ *
+ * @param string $feature The changed feature
+ * @param mixed $oldValue The previous value
+ * @param mixed $newValue The new value
+ * @return void
+ */
+ public function userChanged($feature, $oldValue, $newValue) {
+ if ($feature === 'displayName') {
+ $this->userDisplayName = $newValue;
+ }
+ }
+
+ /**
+ * Guests don't have custom avatars.
+ *
+ * @return bool
+ */
+ public function isCustomAvatar(): bool {
+ return false;
+ }
+}
diff --git a/lib/private/Avatar/UserAvatar.php b/lib/private/Avatar/UserAvatar.php
new file mode 100644
index 00000000000..db5e041d66c
--- /dev/null
+++ b/lib/private/Avatar/UserAvatar.php
@@ -0,0 +1,336 @@
+<?php
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2018, Michael Weimann <mail@michael-weimann.eu>
+ *
+ * @author Michael Weimann <mail@michael-weimann.eu>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ */
+
+namespace OC\Avatar;
+
+use OC\NotSquareException;
+use OC\User\User;
+use OC_Image;
+use OCP\Files\NotFoundException;
+use OCP\Files\NotPermittedException;
+use OCP\Files\SimpleFS\ISimpleFile;
+use OCP\Files\SimpleFS\ISimpleFolder;
+use OCP\IConfig;
+use OCP\IImage;
+use OCP\IL10N;
+use OCP\ILogger;
+
+/**
+ * This class represents a registered user's avatar.
+ */
+class UserAvatar extends Avatar {
+ /** @var IConfig */
+ private $config;
+
+ /** @var ISimpleFolder */
+ private $folder;
+
+ /** @var IL10N */
+ private $l;
+
+ /** @var User */
+ private $user;
+
+ /**
+ * UserAvatar constructor.
+ *
+ * @param IConfig $config The configuration
+ * @param ISimpleFolder $folder The avatar files folder
+ * @param IL10N $l The localization helper
+ * @param User $user The user this class manages the avatar for
+ * @param ILogger $logger The logger
+ */
+ public function __construct(
+ ISimpleFolder $folder,
+ IL10N $l,
+ $user,
+ ILogger $logger,
+ IConfig $config) {
+ parent::__construct($logger);
+ $this->folder = $folder;
+ $this->l = $l;
+ $this->user = $user;
+ $this->config = $config;
+ }
+
+ /**
+ * Check if an avatar exists for the user
+ *
+ * @return bool
+ */
+ public function exists() {
+ return $this->folder->fileExists('avatar.jpg') || $this->folder->fileExists('avatar.png');
+ }
+
+ /**
+ * Sets the users avatar.
+ *
+ * @param IImage|resource|string $data An image object, imagedata or path to set a new avatar
+ * @throws \Exception if the provided file is not a jpg or png image
+ * @throws \Exception if the provided image is not valid
+ * @throws NotSquareException if the image is not square
+ * @return void
+ */
+ public function set($data) {
+ $img = $this->getAvatarImage($data);
+ $data = $img->data();
+
+ $this->validateAvatar($img);
+
+ $this->remove();
+ $type = $this->getAvatarImageType($img);
+ $file = $this->folder->newFile('avatar.' . $type);
+ $file->putContent($data);
+
+ try {
+ $generated = $this->folder->getFile('generated');
+ $this->config->setUserValue($this->user->getUID(), 'avatar', 'generated', 'false');
+ $generated->delete();
+ } catch (NotFoundException $e) {
+ //
+ }
+
+ $this->user->triggerChange('avatar', $file);
+ }
+
+ /**
+ * Returns an image from several sources.
+ *
+ * @param IImage|resource|string $data An image object, imagedata or path to the avatar
+ * @return IImage
+ */
+ private function getAvatarImage($data) {
+ if ($data instanceof IImage) {
+ return $data;
+ }
+
+ $img = new OC_Image();
+ if (is_resource($data) && get_resource_type($data) === 'gd') {
+ $img->setResource($data);
+ } elseif (is_resource($data)) {
+ $img->loadFromFileHandle($data);
+ } else {
+ try {
+ // detect if it is a path or maybe the images as string
+ $result = @realpath($data);
+ if ($result === false || $result === null) {
+ $img->loadFromData($data);
+ } else {
+ $img->loadFromFile($data);
+ }
+ } catch (\Error $e) {
+ $img->loadFromData($data);
+ }
+ }
+
+ return $img;
+ }
+
+ /**
+ * Returns the avatar image type.
+ *
+ * @param IImage $avatar
+ * @return string
+ */
+ private function getAvatarImageType(IImage $avatar) {
+ $type = substr($avatar->mimeType(), -3);
+ if ($type === 'peg') {
+ $type = 'jpg';
+ }
+ return $type;
+ }
+
+ /**
+ * Validates an avatar image:
+ * - must be "png" or "jpg"
+ * - must be "valid"
+ * - must be in square format
+ *
+ * @param IImage $avatar The avatar to validate
+ * @throws \Exception if the provided file is not a jpg or png image
+ * @throws \Exception if the provided image is not valid
+ * @throws NotSquareException if the image is not square
+ */
+ private function validateAvatar(IImage $avatar) {
+ $type = $this->getAvatarImageType($avatar);
+
+ if ($type !== 'jpg' && $type !== 'png') {
+ throw new \Exception($this->l->t('Unknown filetype'));
+ }
+
+ if (!$avatar->valid()) {
+ throw new \Exception($this->l->t('Invalid image'));
+ }
+
+ if (!($avatar->height() === $avatar->width())) {
+ throw new NotSquareException($this->l->t('Avatar image is not square'));
+ }
+ }
+
+ /**
+ * Removes the users avatar.
+ * @return void
+ * @throws \OCP\Files\NotPermittedException
+ * @throws \OCP\PreConditionNotMetException
+ */
+ public function remove() {
+ $avatars = $this->folder->getDirectoryListing();
+
+ $this->config->setUserValue($this->user->getUID(), 'avatar', 'version',
+ (int) $this->config->getUserValue($this->user->getUID(), 'avatar', 'version', 0) + 1);
+
+ foreach ($avatars as $avatar) {
+ $avatar->delete();
+ }
+ $this->config->setUserValue($this->user->getUID(), 'avatar', 'generated', 'true');
+ $this->user->triggerChange('avatar', '');
+ }
+
+ /**
+ * Get the extension of the avatar. If there is no avatar throw Exception
+ *
+ * @return string
+ * @throws NotFoundException
+ */
+ private function getExtension() {
+ if ($this->folder->fileExists('avatar.jpg')) {
+ return 'jpg';
+ } elseif ($this->folder->fileExists('avatar.png')) {
+ return 'png';
+ }
+ throw new NotFoundException;
+ }
+
+ /**
+ * Returns the avatar for an user.
+ *
+ * If there is no avatar file yet, one is generated.
+ *
+ * @param int $size
+ * @return ISimpleFile
+ * @throws NotFoundException
+ * @throws \OCP\Files\NotPermittedException
+ * @throws \OCP\PreConditionNotMetException
+ */
+ public function getFile($size) {
+ $size = (int) $size;
+
+ try {
+ $ext = $this->getExtension();
+ } catch (NotFoundException $e) {
+ if (!$data = $this->generateAvatarFromSvg(1024)) {
+ $data = $this->generateAvatar($this->getDisplayName(), 1024);
+ }
+ $avatar = $this->folder->newFile('avatar.png');
+ $avatar->putContent($data);
+ $ext = 'png';
+
+ $this->folder->newFile('generated');
+ $this->config->setUserValue($this->user->getUID(), 'avatar', 'generated', 'true');
+ }
+
+ if ($size === -1) {
+ $path = 'avatar.' . $ext;
+ } else {
+ $path = 'avatar.' . $size . '.' . $ext;
+ }
+
+ try {
+ $file = $this->folder->getFile($path);
+ } catch (NotFoundException $e) {
+ if ($size <= 0) {
+ throw new NotFoundException;
+ }
+
+ if ($this->folder->fileExists('generated')) {
+ if (!$data = $this->generateAvatarFromSvg($size)) {
+ $data = $this->generateAvatar($this->getDisplayName(), $size);
+ }
+
+ } else {
+ $avatar = new OC_Image();
+ $file = $this->folder->getFile('avatar.' . $ext);
+ $avatar->loadFromData($file->getContent());
+ $avatar->resize($size);
+ $data = $avatar->data();
+ }
+
+ try {
+ $file = $this->folder->newFile($path);
+ $file->putContent($data);
+ } catch (NotPermittedException $e) {
+ $this->logger->error('Failed to save avatar for ' . $this->user->getUID());
+ throw new NotFoundException();
+ }
+
+ }
+
+ if ($this->config->getUserValue($this->user->getUID(), 'avatar', 'generated', null) === null) {
+ $generated = $this->folder->fileExists('generated') ? 'true' : 'false';
+ $this->config->setUserValue($this->user->getUID(), 'avatar', 'generated', $generated);
+ }
+
+ return $file;
+ }
+
+ /**
+ * Returns the user display name.
+ *
+ * @return string
+ */
+ public function getDisplayName(): string {
+ return $this->user->getDisplayName();
+ }
+
+ /**
+ * Handles user changes.
+ *
+ * @param string $feature The changed feature
+ * @param mixed $oldValue The previous value
+ * @param mixed $newValue The new value
+ * @throws NotPermittedException
+ * @throws \OCP\PreConditionNotMetException
+ */
+ public function userChanged($feature, $oldValue, $newValue) {
+ // We only change the avatar on display name changes
+ if ($feature !== 'displayName') {
+ return;
+ }
+
+ // If the avatar is not generated (so an uploaded image) we skip this
+ if (!$this->folder->fileExists('generated')) {
+ return;
+ }
+
+ $this->remove();
+ }
+
+ /**
+ * Check if the avatar of a user is a custom uploaded one
+ *
+ * @return bool
+ */
+ public function isCustomAvatar(): bool {
+ return $this->config->getUserValue($this->user->getUID(), 'avatar', 'generated', 'false') !== 'true';
+ }
+}
diff --git a/lib/private/Repair.php b/lib/private/Repair.php
index 8bb3d3327a6..641475cf386 100644
--- a/lib/private/Repair.php
+++ b/lib/private/Repair.php
@@ -33,7 +33,7 @@ namespace OC;
use OCP\AppFramework\QueryException;
use OCP\Migration\IOutput;
use OCP\Migration\IRepairStep;
-use OC\AvatarManager;
+use OC\Avatar\AvatarManager;
use OC\Repair\AddCleanupUpdaterBackupsJob;
use OC\Repair\CleanTags;
use OC\Repair\ClearGeneratedAvatarCache;
diff --git a/lib/private/Repair/ClearGeneratedAvatarCache.php b/lib/private/Repair/ClearGeneratedAvatarCache.php
index 631e793de3e..528cea4c00f 100644
--- a/lib/private/Repair/ClearGeneratedAvatarCache.php
+++ b/lib/private/Repair/ClearGeneratedAvatarCache.php
@@ -23,11 +23,10 @@
namespace OC\Repair;
-use OC\AvatarManager;
+use OC\Avatar\AvatarManager;
use OCP\IConfig;
use OCP\Migration\IOutput;
use OCP\Migration\IRepairStep;
-use OCP\Util;
class ClearGeneratedAvatarCache implements IRepairStep {
diff --git a/lib/private/Server.php b/lib/private/Server.php
index 86d304af5ef..89f55fcc9f3 100644
--- a/lib/private/Server.php
+++ b/lib/private/Server.php
@@ -58,6 +58,7 @@ use OC\AppFramework\Utility\SimpleContainer;
use OC\AppFramework\Utility\TimeFactory;
use OC\Authentication\LoginCredentials\Store;
use OC\Authentication\Token\IProvider;
+use OC\Avatar\AvatarManager;
use OC\Collaboration\Collaborators\GroupPlugin;
use OC\Collaboration\Collaborators\MailPlugin;
use OC\Collaboration\Collaborators\RemoteGroupPlugin;
diff --git a/lib/public/AppFramework/Http/FileDisplayResponse.php b/lib/public/AppFramework/Http/FileDisplayResponse.php
index ab23701f893..f5b9a1cf2b9 100644
--- a/lib/public/AppFramework/Http/FileDisplayResponse.php
+++ b/lib/public/AppFramework/Http/FileDisplayResponse.php
@@ -66,4 +66,13 @@ class FileDisplayResponse extends Response implements ICallbackResponse {
$output->setOutput($this->file->getContent());
}
}
+
+ /**
+ * Returns the response file.
+ *
+ * @return \OCP\Files\File|\OCP\Files\SimpleFS\ISimpleFile
+ */
+ public function getFile() {
+ return $this->file;
+ }
}
diff --git a/lib/public/Files/SimpleFS/InMemoryFile.php b/lib/public/Files/SimpleFS/InMemoryFile.php
new file mode 100644
index 00000000000..378fece3e94
--- /dev/null
+++ b/lib/public/Files/SimpleFS/InMemoryFile.php
@@ -0,0 +1,137 @@
+<?php
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2018, Michael Weimann <mail@michael-weimann.eu>
+ *
+ * @author Michael Weimann <mail@michael-weimann.eu>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ */
+
+namespace OCP\Files\SimpleFS;
+
+use OCP\Files\NotPermittedException;
+
+/**
+ * This class represents a file that is only hold in memory.
+ *
+ * @package OC\Files\SimpleFS
+ */
+class InMemoryFile implements ISimpleFile {
+ /**
+ * Holds the file name.
+ *
+ * @var string
+ */
+ private $name;
+
+ /**
+ * Holds the file contents.
+ *
+ * @var string
+ */
+ private $contents;
+
+ /**
+ * InMemoryFile constructor.
+ *
+ * @param string $name The file name
+ * @param string $contents The file contents
+ */
+ public function __construct(string $name, string $contents) {
+ $this->name = $name;
+ $this->contents = $contents;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getName() {
+ return $this->name;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getSize() {
+ return strlen($this->contents);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getETag() {
+ return '';
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getMTime() {
+ return time();
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getContent() {
+ return $this->contents;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function putContent($data) {
+ $this->contents = $data;
+ }
+
+ /**
+ * In memory files can't be deleted.
+ */
+ public function delete() {
+ // unimplemented for in memory files
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getMimeType() {
+ $fileInfo = new \finfo(FILEINFO_MIME_TYPE);
+ return $fileInfo->buffer($this->contents);
+ }
+
+ /**
+ * Stream reading is unsupported for in memory files.
+ *
+ * @throws NotPermittedException
+ */
+ public function read() {
+ throw new NotPermittedException(
+ 'Stream reading is unsupported for in memory files'
+ );
+ }
+
+ /**
+ * Stream writing isn't available for in memory files.
+ *
+ * @throws NotPermittedException
+ */
+ public function write() {
+ throw new NotPermittedException(
+ 'Stream writing is unsupported for in memory files'
+ );
+ }
+}
diff --git a/lib/public/IAvatarManager.php b/lib/public/IAvatarManager.php
index 4b89173d88b..890bcd1e6dd 100644
--- a/lib/public/IAvatarManager.php
+++ b/lib/public/IAvatarManager.php
@@ -45,4 +45,13 @@ interface IAvatarManager {
*/
public function getAvatar(string $user) : IAvatar;
+ /**
+ * Returns a guest user avatar instance.
+ *
+ * @param string $name The guest name, e.g. "Albert".
+ * @return IAvatar
+ * @since 16.0.0
+ */
+ public function getGuestAvatar(string $name): IAvatar;
+
}
diff --git a/tests/Core/Controller/AvatarControllerTest.php b/tests/Core/Controller/AvatarControllerTest.php
index 3369fa882c8..5fce8fc6359 100644
--- a/tests/Core/Controller/AvatarControllerTest.php
+++ b/tests/Core/Controller/AvatarControllerTest.php
@@ -53,7 +53,7 @@ use OCP\IUserManager;
* @package OC\Core\Controller
*/
class AvatarControllerTest extends \Test\TestCase {
- /** @var \OC\Core\Controller\AvatarController */
+ /** @var AvatarController */
private $avatarController;
/** @var IAvatar|\PHPUnit_Framework_MockObject_MockObject */
private $avatarMock;
@@ -78,7 +78,7 @@ class AvatarControllerTest extends \Test\TestCase {
private $request;
/** @var TimeFactory|\PHPUnit_Framework_MockObject_MockObject */
private $timeFactory;
-
+
protected function setUp() {
parent::setUp();
diff --git a/tests/Core/Controller/GuestAvatarControllerTest.php b/tests/Core/Controller/GuestAvatarControllerTest.php
new file mode 100644
index 00000000000..a7c67c684cc
--- /dev/null
+++ b/tests/Core/Controller/GuestAvatarControllerTest.php
@@ -0,0 +1,90 @@
+<?php
+
+namespace Core\Controller;
+
+use OC\Core\Controller\GuestAvatarController;
+use OCP\AppFramework\Http\FileDisplayResponse;
+use OCP\Files\SimpleFS\ISimpleFile;
+use OCP\IAvatar;
+use OCP\IAvatarManager;
+use OCP\ILogger;
+use OCP\IRequest;
+
+/**
+ * This class provides tests for the guest avatar controller.
+ */
+class GuestAvatarControllerTest extends \Test\TestCase {
+
+ /**
+ * @var GuestAvatarController
+ */
+ private $guestAvatarController;
+
+ /**
+ * @var IRequest|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $request;
+
+ /**
+ * @var IAvatarManager|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $avatarManager;
+
+ /**
+ * @var IAvatar|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $avatar;
+
+ /**
+ * @var \OCP\Files\File|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $file;
+
+ /**
+ * @var ILogger|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $logger;
+
+ /**
+ * Sets up the test environment.
+ */
+ protected function setUp() {
+ parent::setUp();
+
+ $this->logger = $this->getMockBuilder(ILogger::class)->getMock();
+ $this->request = $this->getMockBuilder(IRequest::class)->getMock();
+ $this->avatar = $this->getMockBuilder(IAvatar::class)->getMock();
+ $this->avatarManager = $this->getMockBuilder(IAvatarManager::class)->getMock();
+ $this->file = $this->getMockBuilder(ISimpleFile::class)->getMock();
+ $this->guestAvatarController = new GuestAvatarController(
+ 'core',
+ $this->request,
+ $this->avatarManager,
+ $this->logger
+ );
+ }
+
+ /**
+ * Tests getAvatar returns the guest avatar.
+ */
+ public function testGetAvatar() {
+ $this->avatarManager->expects($this->once())
+ ->method('getGuestAvatar')
+ ->with('Peter')
+ ->willReturn($this->avatar);
+
+ $this->avatar->expects($this->once())
+ ->method('getFile')
+ ->with(128)
+ ->willReturn($this->file);
+
+ $this->file->method('getMimeType')
+ ->willReturn('image/svg+xml');
+
+ $response = $this->guestAvatarController->getAvatar('Peter', 128);
+
+ $this->assertGreaterThanOrEqual(201, $response->getStatus());
+ $this->assertInstanceOf(FileDisplayResponse::class, $response);
+ $this->assertSame($this->file, $response->getFile());
+ }
+}
diff --git a/tests/data/guest_avatar_einstein_32.svg b/tests/data/guest_avatar_einstein_32.svg
new file mode 100644
index 00000000000..d007f962f24
--- /dev/null
+++ b/tests/data/guest_avatar_einstein_32.svg
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <svg width="32" height="32" version="1.1" viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg">
+ <rect width="100%" height="100%" fill="#499aa2"></rect>
+ <text x="50%" y="350" style="font-weight:normal;font-size:279px;font-family:'Nunito';text-anchor:middle;fill:#fff">E</text>
+ </svg>
diff --git a/tests/data/test.pdf b/tests/data/test.pdf
new file mode 100644
index 00000000000..241e1e85d41
--- /dev/null
+++ b/tests/data/test.pdf
Binary files differ
diff --git a/tests/lib/AvatarManagerTest.php b/tests/lib/Avatar/AvatarManagerTest.php
index 9f2a4f4f337..7466f664eb5 100644
--- a/tests/lib/AvatarManagerTest.php
+++ b/tests/lib/Avatar/AvatarManagerTest.php
@@ -22,11 +22,10 @@
*
*/
-namespace Test;
+namespace Test\Avatar;
-use OC\Avatar;
-use OC\AvatarManager;
-use OC\Files\AppData\AppData;
+use OC\Avatar\UserAvatar;
+use OC\Avatar\AvatarManager;
use OC\User\Manager;
use OCP\Files\IAppData;
use OCP\Files\SimpleFS\ISimpleFolder;
@@ -34,7 +33,6 @@ use OCP\IConfig;
use OCP\IL10N;
use OCP\ILogger;
use OCP\IUser;
-use OCP\IUserManager;
/**
* Class AvatarManagerTest
@@ -103,7 +101,7 @@ class AvatarManagerTest extends \Test\TestCase {
->with('valid-user')
->willReturn($folder);
- $expected = new Avatar($folder, $this->l10n, $user, $this->logger, $this->config);
+ $expected = new UserAvatar($folder, $this->l10n, $user, $this->logger, $this->config);
$this->assertEquals($expected, $this->avatarManager->getAvatar('valid-user'));
}
@@ -125,7 +123,7 @@ class AvatarManagerTest extends \Test\TestCase {
->with('valid-user')
->willReturn($folder);
- $expected = new Avatar($folder, $this->l10n, $user, $this->logger, $this->config);
+ $expected = new UserAvatar($folder, $this->l10n, $user, $this->logger, $this->config);
$this->assertEquals($expected, $this->avatarManager->getAvatar('vaLid-USER'));
}
}
diff --git a/tests/lib/Avatar/GuestAvatarTest.php b/tests/lib/Avatar/GuestAvatarTest.php
new file mode 100644
index 00000000000..8762d063f5d
--- /dev/null
+++ b/tests/lib/Avatar/GuestAvatarTest.php
@@ -0,0 +1,80 @@
+<?php
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2018, Michael Weimann <mail@michael-weimann.eu>
+ *
+ * @author Michael Weimann <mail@michael-weimann.eu>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ */
+
+namespace Test\Avatar;
+
+use OC\Avatar\GuestAvatar;
+use OCP\Files\SimpleFS\InMemoryFile;
+use OCP\ILogger;
+use PHPUnit\Framework\MockObject\MockObject;
+use Test\TestCase;
+
+/**
+ * This class provides test cases for the GuestAvatar class.
+ *
+ * @package Test\Avatar
+ */
+class GuestAvatarTest extends TestCase {
+ /**
+ * @var GuestAvatar
+ */
+ private $guestAvatar;
+
+ /**
+ * Setups a guest avatar instance for tests.
+ *
+ * @before
+ * @return void
+ */
+ public function setupGuestAvatar() {
+ /* @var MockObject|ILogger $logger */
+ $logger = $this->getMockBuilder(ILogger::class)->getMock();
+ $this->guestAvatar = new GuestAvatar('einstein', $logger);
+ }
+
+ /**
+ * Asserts that testGet() returns the expected avatar.
+ *
+ * For the test a static name "einstein" is used and
+ * the generated image is compared with an expected one.
+ *
+ * @return void
+ */
+ public function testGet() {
+ $avatar = $this->guestAvatar->getFile(32);
+ self::assertInstanceOf(InMemoryFile::class, $avatar);
+ $expectedFile = file_get_contents(
+ __DIR__ . '/../../data/guest_avatar_einstein_32.svg'
+ );
+ self::assertEquals(trim($expectedFile), trim($avatar->getContent()));
+ }
+
+ /**
+ * Asserts that "testIsCustomAvatar" returns false for guests.
+ *
+ * @return void
+ */
+ public function testIsCustomAvatar() {
+ self::assertFalse($this->guestAvatar->isCustomAvatar());
+ }
+}
diff --git a/tests/lib/AvatarTest.php b/tests/lib/Avatar/UserAvatarTest.php
index c8c9d3b8317..049725c78c9 100644
--- a/tests/lib/AvatarTest.php
+++ b/tests/lib/Avatar/UserAvatarTest.php
@@ -6,7 +6,7 @@
* See the COPYING-README file.
*/
-namespace Test;
+namespace Test\Avatar;
use OC\Files\SimpleFS\SimpleFolder;
use OC\User\User;
@@ -18,11 +18,11 @@ use OCP\IConfig;
use OCP\IL10N;
use OCP\ILogger;
-class AvatarTest extends \Test\TestCase {
+class UserAvatarTest extends \Test\TestCase {
/** @var Folder | \PHPUnit_Framework_MockObject_MockObject */
private $folder;
- /** @var \OC\Avatar */
+ /** @var \OC\Avatar\UserAvatar */
private $avatar;
/** @var \OC\User\User | \PHPUnit_Framework_MockObject_MockObject $user */
@@ -41,7 +41,7 @@ class AvatarTest extends \Test\TestCase {
$this->user = $this->createMock(User::class);
$this->config = $this->createMock(IConfig::class);
- $this->avatar = new \OC\Avatar(
+ $this->avatar = new \OC\Avatar\UserAvatar(
$this->folder,
$l,
$this->user,
diff --git a/tests/lib/Files/SimpleFS/InMemoryFileTest.php b/tests/lib/Files/SimpleFS/InMemoryFileTest.php
new file mode 100644
index 00000000000..195a5d04a8f
--- /dev/null
+++ b/tests/lib/Files/SimpleFS/InMemoryFileTest.php
@@ -0,0 +1,145 @@
+<?php
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2018, Michael Weimann <mail@michael-weimann.eu>
+ *
+ * @author Michael Weimann <mail@michael-weimann.eu>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ */
+
+namespace Test\File\SimpleFS;
+
+use OCP\Files\NotPermittedException;
+use OCP\Files\SimpleFS\InMemoryFile;
+use Test\TestCase;
+
+/**
+ * This class provide test casesf or the InMemoryFile.
+ *
+ * @package Test\File\SimpleFS
+ */
+class InMemoryFileTest extends TestCase {
+ /**
+ * Holds a pdf file with know attributes for tests.
+ *
+ * @var InMemoryFile
+ */
+ private $testPdf;
+
+ /**
+ * Sets the test file from "./resources/test.pdf".
+ *
+ * @before
+ * @return void
+ */
+ public function setupTestPdf() {
+ $fileContents = file_get_contents(
+ __DIR__ . '/../../../data/test.pdf'
+ );
+ $this->testPdf = new InMemoryFile('test.pdf', $fileContents);
+ }
+
+ /**
+ * Asserts that putContent replaces the file contents.
+ *
+ * @return void
+ */
+ public function testPutContent() {
+ $this->testPdf->putContent('test');
+ self::assertEquals('test', $this->testPdf->getContent());
+ }
+
+ /**
+ * Asserts that delete() doesn't rise an exception.
+ *
+ * @return void
+ */
+ public function testDelete() {
+ $this->testPdf->delete();
+ // assert true, otherwise phpunit complains about not doing any assert
+ self::assertTrue(true);
+ }
+
+ /**
+ * Asserts that getName returns the name passed on file creation.
+ *
+ * @return void
+ */
+ public function testGetName() {
+ self::assertEquals('test.pdf', $this->testPdf->getName());
+ }
+
+ /**
+ * Asserts that the file size is the size of the test file.
+ *
+ * @return void
+ */
+ public function testGetSize() {
+ self::assertEquals(7083, $this->testPdf->getSize());
+ }
+
+ /**
+ * Asserts the file contents are the same than the original file contents.
+ *
+ * @return void
+ */
+ public function testGetContent() {
+ self::assertEquals(
+ file_get_contents(__DIR__ . '/../../../data/test.pdf'),
+ $this->testPdf->getContent()
+ );
+ }
+
+ /**
+ * Asserts the test file modification time is an integer.
+ *
+ * @return void
+ */
+ public function testGetMTime() {
+ self::assertTrue(is_int($this->testPdf->getMTime()));
+ }
+
+ /**
+ * Asserts the test file mime type is "application/json".
+ *
+ * @return void
+ */
+ public function testGetMimeType() {
+ self::assertEquals('application/pdf', $this->testPdf->getMimeType());
+ }
+
+
+ /**
+ * Asserts that read() raises an NotPermittedException.
+ *
+ * @return void
+ */
+ public function testRead() {
+ self::expectException(NotPermittedException::class);
+ $this->testPdf->read();
+ }
+
+ /**
+ * Asserts that write() raises an NotPermittedException.
+ *
+ * @return void
+ */
+ public function testWrite() {
+ self::expectException(NotPermittedException::class);
+ $this->testPdf->write();
+ }
+}
diff --git a/tests/lib/Repair/ClearGeneratedAvatarCacheTest.php b/tests/lib/Repair/ClearGeneratedAvatarCacheTest.php
index ec107d300d6..dd98307993f 100644
--- a/tests/lib/Repair/ClearGeneratedAvatarCacheTest.php
+++ b/tests/lib/Repair/ClearGeneratedAvatarCacheTest.php
@@ -25,7 +25,7 @@ namespace Test\Repair;
use OCP\IConfig;
use OCP\Migration\IOutput;
-use OC\AvatarManager;
+use OC\Avatar\AvatarManager;
use OC\Repair\ClearGeneratedAvatarCache;
class ClearGeneratedAvatarCacheTest extends \Test\TestCase {
diff --git a/tests/lib/ServerTest.php b/tests/lib/ServerTest.php
index e76b2b96db7..604e11ec11e 100644
--- a/tests/lib/ServerTest.php
+++ b/tests/lib/ServerTest.php
@@ -57,7 +57,7 @@ class ServerTest extends \Test\TestCase {
['AppManager', '\OCP\App\IAppManager'],
['AsyncCommandBus', '\OC\Command\AsyncBus'],
['AsyncCommandBus', '\OCP\Command\IBus'],
- ['AvatarManager', '\OC\AvatarManager'],
+ ['AvatarManager', '\OC\Avatar\AvatarManager'],
['AvatarManager', '\OCP\IAvatarManager'],
['CategoryFetcher', CategoryFetcher::class],