]> source.dussan.org Git - nextcloud-server.git/commitdiff
fix(dav): fall back to generated avatar in image export plugin fix/dav/image-export-plugin-fallback 45408/head
authorRichard Steinmetz <richard@steinmetz.cloud>
Mon, 20 May 2024 11:58:56 +0000 (13:58 +0200)
committerRichard Steinmetz <richard@steinmetz.cloud>
Mon, 20 May 2024 12:00:21 +0000 (14:00 +0200)
Signed-off-by: Richard Steinmetz <richard@steinmetz.cloud>
apps/dav/appinfo/v1/carddav.php
apps/dav/lib/CardDAV/ImageExportPlugin.php
apps/dav/lib/Server.php
apps/dav/tests/unit/CardDAV/ImageExportPluginTest.php

index 70e5de1b481d905e6e9359b1b71cceaf0b981e32..5c6d6906fe00238a87509fda33945ee48f448e2c 100644 (file)
@@ -39,6 +39,7 @@ use OCA\DAV\Connector\Sabre\MaintenancePlugin;
 use OCA\DAV\Connector\Sabre\Principal;
 use OCP\Accounts\IAccountManager;
 use OCP\App\IAppManager;
+use OCP\IAvatarManager;
 use Psr\Log\LoggerInterface;
 use Sabre\CardDAV\Plugin;
 
@@ -104,10 +105,13 @@ if ($debugging) {
 
 $server->addPlugin(new \Sabre\DAV\Sync\Plugin());
 $server->addPlugin(new \Sabre\CardDAV\VCFExportPlugin());
-$server->addPlugin(new \OCA\DAV\CardDAV\ImageExportPlugin(new \OCA\DAV\CardDAV\PhotoCache(
-       \OC::$server->getAppDataDir('dav-photocache'),
-       \OC::$server->get(LoggerInterface::class)
-)));
+$server->addPlugin(new \OCA\DAV\CardDAV\ImageExportPlugin(
+       new \OCA\DAV\CardDAV\PhotoCache(
+               \OC::$server->getAppDataDir('dav-photocache'),
+               \OC::$server->get(LoggerInterface::class)
+       ),
+       \OC::$server->get(IAvatarManager::class),
+));
 $server->addPlugin(new ExceptionLoggerPlugin('carddav', \OC::$server->get(LoggerInterface::class)));
 
 // And off we go!
index 3ebc91e55331b6425d78e0b894809a3f46750bbb..e079a54de4aaca37d353b4504db60e91e0365935 100644 (file)
 namespace OCA\DAV\CardDAV;
 
 use OCP\Files\NotFoundException;
+use OCP\IAvatarManager;
 use Sabre\CardDAV\Card;
 use Sabre\DAV\Server;
 use Sabre\DAV\ServerPlugin;
 use Sabre\HTTP\RequestInterface;
 use Sabre\HTTP\ResponseInterface;
+use Sabre\VObject\Reader;
 
 class ImageExportPlugin extends ServerPlugin {
 
@@ -38,13 +40,14 @@ class ImageExportPlugin extends ServerPlugin {
        /** @var PhotoCache */
        private $cache;
 
+       private IAvatarManager $avatarManager;
+
        /**
         * ImageExportPlugin constructor.
-        *
-        * @param PhotoCache $cache
         */
-       public function __construct(PhotoCache $cache) {
+       public function __construct(PhotoCache $cache, IAvatarManager $avatarManager) {
                $this->cache = $cache;
+               $this->avatarManager = $avatarManager;
        }
 
        /**
@@ -99,6 +102,7 @@ class ImageExportPlugin extends ServerPlugin {
                $response->setHeader('Cache-Control', 'private, max-age=3600, must-revalidate');
                $response->setHeader('Etag', $node->getETag());
 
+               // Try to use embedded avatar image
                try {
                        $file = $this->cache->get($addressbook->getResourceId(), $node->getName(), $size, $node);
                        $response->setHeader('Content-Type', $file->getMimeType());
@@ -107,10 +111,29 @@ class ImageExportPlugin extends ServerPlugin {
                        $response->setStatus(200);
 
                        $response->setBody($file->getContent());
+                       return false;
                } catch (NotFoundException $e) {
-                       $response->setStatus(404);
+                       // Fall back to generated avatar
+               }
+
+               $name = '?';
+               $vObject = Reader::read($node->get());
+               if (isset($vObject->FN)) {
+                       $name = $vObject->FN->getValue();
+               } elseif (isset($vObject->N)) {
+                       [$lastName, $firstName] = $vObject->N->getParts();
+                       $name = "$firstName $lastName";
                }
 
+               $avatar = $this->avatarManager->getGuestAvatar($name);
+               $image = $avatar->get($size);
+
+               $response->setHeader('Content-Type', $image->mimeType());
+               $fileName = $node->getName() . '.' . PhotoCache::ALLOWED_CONTENT_TYPES[$image->mimeType()];
+               $response->setHeader('Content-Disposition', "attachment; filename=$fileName");
+               $response->setStatus(200);
+               $response->setBody($image->data());
+
                return false;
        }
 }
index 37d04ba819048a748cf44c6766156c31d44d829f..c166be5be467fee890cf801386bf44e739bff14a 100644 (file)
@@ -80,6 +80,7 @@ use OCP\AppFramework\Http\Response;
 use OCP\Diagnostics\IEventLogger;
 use OCP\EventDispatcher\IEventDispatcher;
 use OCP\FilesMetadata\IFilesMetadataManager;
+use OCP\IAvatarManager;
 use OCP\ICacheFactory;
 use OCP\IRequest;
 use OCP\Profiler\IProfiler;
@@ -204,9 +205,12 @@ class Server {
                        $this->server->addPlugin(new VCFExportPlugin());
                        $this->server->addPlugin(new MultiGetExportPlugin());
                        $this->server->addPlugin(new HasPhotoPlugin());
-                       $this->server->addPlugin(new ImageExportPlugin(new PhotoCache(
-                               \OC::$server->getAppDataDir('dav-photocache'),
-                               $logger)
+                       $this->server->addPlugin(
+                               new ImageExportPlugin(new PhotoCache(
+                                       \OC::$server->getAppDataDir('dav-photocache'),
+                                       $logger,
+                               ),
+                               \OC::$server->get(IAvatarManager::class),
                        ));
                }
 
index 6f48927646ec85e29d6cb0df2c59ea4519e36746..d1b05c5d07e198dbf6d59b3ca61c99d3a7564c9b 100644 (file)
@@ -30,6 +30,7 @@ use OCA\DAV\CardDAV\ImageExportPlugin;
 use OCA\DAV\CardDAV\PhotoCache;
 use OCP\Files\NotFoundException;
 use OCP\Files\SimpleFS\ISimpleFile;
+use OCP\IAvatarManager;
 use Sabre\CardDAV\Card;
 use Sabre\DAV\Node;
 use Sabre\DAV\Server;
@@ -51,6 +52,8 @@ class ImageExportPluginTest extends TestCase {
        private $tree;
        /** @var PhotoCache|\PHPUnit\Framework\MockObject\MockObject */
        private $cache;
+       /** @var IAvatarManager|\PHPUnit\Framework\MockObject\MockObject */
+       private $avatarManager;
 
        protected function setUp(): void {
                parent::setUp();
@@ -61,10 +64,11 @@ class ImageExportPluginTest extends TestCase {
                $this->tree = $this->createMock(Tree::class);
                $this->server->tree = $this->tree;
                $this->cache = $this->createMock(PhotoCache::class);
+               $this->avatarManager = $this->createMock(IAvatarManager::class);
 
                $this->plugin = $this->getMockBuilder(ImageExportPlugin::class)
                        ->setMethods(['getPhoto'])
-                       ->setConstructorArgs([$this->cache])
+                       ->setConstructorArgs([$this->cache, $this->avatarManager])
                        ->getMock();
                $this->plugin->initialize($this->server);
        }