From 3c67295a65594d0f58b2138490b02ffbc5d8ca79 Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Sat, 5 Feb 2022 19:55:23 +0100 Subject: [PATCH] Expose additional emails in {DAV:}alternate-URI-set This allows iMip invitations to be send with an alternative email as "Reply-To" field. Closes #27201 Signed-off-by: Thomas Citharel --- apps/dav/appinfo/v1/caldav.php | 2 + apps/dav/appinfo/v1/carddav.php | 2 + apps/dav/lib/Command/CreateCalendar.php | 2 + apps/dav/lib/Connector/Sabre/Principal.php | 17 +++++++ apps/dav/lib/RootCollection.php | 2 + .../unit/Connector/Sabre/PrincipalTest.php | 49 +++++++++++++++++++ .../lib/AppInfo/Application.php | 2 + 7 files changed, 76 insertions(+) diff --git a/apps/dav/appinfo/v1/caldav.php b/apps/dav/appinfo/v1/caldav.php index 28840fcef4cf1..22dbc717dc75a 100644 --- a/apps/dav/appinfo/v1/caldav.php +++ b/apps/dav/appinfo/v1/caldav.php @@ -34,6 +34,7 @@ use OCA\DAV\Connector\Sabre\ExceptionLoggerPlugin; use OCA\DAV\Connector\Sabre\MaintenancePlugin; use OCA\DAV\Connector\Sabre\Principal; +use OCP\Accounts\IAccountManager; $authBackend = new Auth( \OC::$server->getSession(), @@ -46,6 +47,7 @@ $principalBackend = new Principal( \OC::$server->getUserManager(), \OC::$server->getGroupManager(), + \OC::$server->get(IAccountManager::class), \OC::$server->getShareManager(), \OC::$server->getUserSession(), \OC::$server->getAppManager(), diff --git a/apps/dav/appinfo/v1/carddav.php b/apps/dav/appinfo/v1/carddav.php index 53449b91c4bff..190677a9f6617 100644 --- a/apps/dav/appinfo/v1/carddav.php +++ b/apps/dav/appinfo/v1/carddav.php @@ -35,6 +35,7 @@ use OCA\DAV\Connector\Sabre\ExceptionLoggerPlugin; use OCA\DAV\Connector\Sabre\MaintenancePlugin; use OCA\DAV\Connector\Sabre\Principal; +use OCP\Accounts\IAccountManager; use OCP\App\IAppManager; use Sabre\CardDAV\Plugin; @@ -49,6 +50,7 @@ $principalBackend = new Principal( \OC::$server->getUserManager(), \OC::$server->getGroupManager(), + \OC::$server->get(IAccountManager::class), \OC::$server->getShareManager(), \OC::$server->getUserSession(), \OC::$server->getAppManager(), diff --git a/apps/dav/lib/Command/CreateCalendar.php b/apps/dav/lib/Command/CreateCalendar.php index 1d81880924537..577adcd2d8220 100644 --- a/apps/dav/lib/Command/CreateCalendar.php +++ b/apps/dav/lib/Command/CreateCalendar.php @@ -29,6 +29,7 @@ use OCA\DAV\CalDAV\CalDavBackend; use OCA\DAV\CalDAV\Proxy\ProxyMapper; use OCA\DAV\Connector\Sabre\Principal; +use OCP\Accounts\IAccountManager; use OCP\EventDispatcher\IEventDispatcher; use OCP\IConfig; use OCP\IDBConnection; @@ -82,6 +83,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $principalBackend = new Principal( $this->userManager, $this->groupManager, + \OC::$server->get(IAccountManager::class), \OC::$server->getShareManager(), \OC::$server->getUserSession(), \OC::$server->getAppManager(), diff --git a/apps/dav/lib/Connector/Sabre/Principal.php b/apps/dav/lib/Connector/Sabre/Principal.php index 8002f96379880..53ac79530ba45 100644 --- a/apps/dav/lib/Connector/Sabre/Principal.php +++ b/apps/dav/lib/Connector/Sabre/Principal.php @@ -41,6 +41,9 @@ use OCA\Circles\Exceptions\CircleNotFoundException; use OCA\DAV\CalDAV\Proxy\ProxyMapper; use OCA\DAV\Traits\PrincipalProxyTrait; +use OCP\Accounts\IAccountManager; +use OCP\Accounts\IAccountProperty; +use OCP\Accounts\PropertyDoesNotExistException; use OCP\App\IAppManager; use OCP\AppFramework\QueryException; use OCP\Constants; @@ -64,6 +67,9 @@ class Principal implements BackendInterface { /** @var IGroupManager */ private $groupManager; + /** @var IAccountManager */ + private $accountManager; + /** @var IShareManager */ private $shareManager; @@ -95,6 +101,7 @@ class Principal implements BackendInterface { public function __construct(IUserManager $userManager, IGroupManager $groupManager, + IAccountManager $accountManager, IShareManager $shareManager, IUserSession $userSession, IAppManager $appManager, @@ -105,6 +112,7 @@ public function __construct(IUserManager $userManager, string $principalPrefix = 'principals/users/') { $this->userManager = $userManager; $this->groupManager = $groupManager; + $this->accountManager = $accountManager; $this->shareManager = $shareManager; $this->userSession = $userSession; $this->appManager = $appManager; @@ -502,6 +510,7 @@ public function findByUri($uri, $principalPrefix) { /** * @param IUser $user * @return array + * @throws PropertyDoesNotExistException */ protected function userToPrincipal($user) { $userId = $user->getUID(); @@ -513,9 +522,17 @@ protected function userToPrincipal($user) { '{http://nextcloud.com/ns}language' => $this->languageFactory->getUserLanguage($user), ]; + $account = $this->accountManager->getAccount($user); + $alternativeEmails = array_map(fn (IAccountProperty $property) => 'mailto:' . $property->getValue(), $account->getPropertyCollection(IAccountManager::COLLECTION_EMAIL)->getProperties()); + $email = $user->getSystemEMailAddress(); if (!empty($email)) { $principal['{http://sabredav.org/ns}email-address'] = $email; + $alternativeEmails = array_values(array_filter($alternativeEmails, fn ($alternativeEmail) => $alternativeEmail !== 'mailto:' . $email)); + } + + if (!empty($alternativeEmails)) { + $principal['{DAV:}alternate-URI-set'] = $alternativeEmails; } return $principal; diff --git a/apps/dav/lib/RootCollection.php b/apps/dav/lib/RootCollection.php index d307b5d2488ff..33cbb140d8baf 100644 --- a/apps/dav/lib/RootCollection.php +++ b/apps/dav/lib/RootCollection.php @@ -43,6 +43,7 @@ use OCA\DAV\DAV\SystemPrincipalBackend; use OCA\DAV\Provisioning\Apple\AppleProvisioningNode; use OCA\DAV\Upload\CleanupService; +use OCP\Accounts\IAccountManager; use OCP\App\IAppManager; use OCP\AppFramework\Utility\ITimeFactory; use OCP\EventDispatcher\IEventDispatcher; @@ -67,6 +68,7 @@ public function __construct() { $userPrincipalBackend = new Principal( $userManager, $groupManager, + \OC::$server->get(IAccountManager::class), $shareManager, \OC::$server->getUserSession(), \OC::$server->getAppManager(), diff --git a/apps/dav/tests/unit/Connector/Sabre/PrincipalTest.php b/apps/dav/tests/unit/Connector/Sabre/PrincipalTest.php index d7c074c9e3b45..b467577d7b9e2 100644 --- a/apps/dav/tests/unit/Connector/Sabre/PrincipalTest.php +++ b/apps/dav/tests/unit/Connector/Sabre/PrincipalTest.php @@ -34,6 +34,10 @@ use OCA\DAV\CalDAV\Proxy\Proxy; use OCA\DAV\CalDAV\Proxy\ProxyMapper; use OCA\DAV\Connector\Sabre\Principal; +use OCP\Accounts\IAccount; +use OCP\Accounts\IAccountManager; +use OCP\Accounts\IAccountProperty; +use OCP\Accounts\IAccountPropertyCollection; use OCP\App\IAppManager; use OCP\IConfig; use OCP\IGroup; @@ -59,6 +63,9 @@ class PrincipalTest extends TestCase { /** @var IGroupManager | MockObject */ private $groupManager; + /** @var IAccountManager|MockObject */ + private $accountManager; + /** @var IManager | MockObject */ private $shareManager; @@ -81,6 +88,7 @@ class PrincipalTest extends TestCase { protected function setUp(): void { $this->userManager = $this->createMock(IUserManager::class); $this->groupManager = $this->createMock(IGroupManager::class); + $this->accountManager = $this->createMock(IAccountManager::class); $this->shareManager = $this->createMock(IManager::class); $this->userSession = $this->createMock(IUserSession::class); $this->appManager = $this->createMock(IAppManager::class); @@ -92,6 +100,7 @@ protected function setUp(): void { $this->connector = new Principal( $this->userManager, $this->groupManager, + $this->accountManager, $this->shareManager, $this->userSession, $this->appManager, @@ -143,6 +152,45 @@ public function testGetPrincipalsByPrefixWithUsers(): void { ->withConsecutive([$fooUser], [$barUser]) ->willReturnOnConsecutiveCalls('de', 'en'); + $fooAccountPropertyCollection = $this->createMock(IAccountPropertyCollection::class); + $fooAccountPropertyCollection->expects($this->once()) + ->method('getProperties') + ->with() + ->willReturn([]); + $fooAccount = $this->createMock(IAccount::class); + $fooAccount->expects($this->once()) + ->method('getPropertyCollection') + ->with(IAccountManager::COLLECTION_EMAIL) + ->willReturn($fooAccountPropertyCollection); + + $emailPropertyOne = $this->createMock(IAccountProperty::class); + $emailPropertyOne->expects($this->once()) + ->method('getValue') + ->with() + ->willReturn('bar@nextcloud.com'); + $emailPropertyTwo = $this->createMock(IAccountProperty::class); + $emailPropertyTwo->expects($this->once()) + ->method('getValue') + ->with() + ->willReturn('alias@nextcloud.com'); + + $barAccountPropertyCollection = $this->createMock(IAccountPropertyCollection::class); + $barAccountPropertyCollection->expects($this->once()) + ->method('getProperties') + ->with() + ->willReturn([$emailPropertyOne, $emailPropertyTwo]); + $barAccount = $this->createMock(IAccount::class); + $barAccount->expects($this->once()) + ->method('getPropertyCollection') + ->with(IAccountManager::COLLECTION_EMAIL) + ->willReturn($barAccountPropertyCollection); + + $this->accountManager + ->expects($this->exactly(2)) + ->method('getAccount') + ->withConsecutive([$fooUser], [$barUser]) + ->willReturnOnConsecutiveCalls($fooAccount, $barAccount); + $expectedResponse = [ 0 => [ 'uri' => 'principals/users/foo', @@ -156,6 +204,7 @@ public function testGetPrincipalsByPrefixWithUsers(): void { '{urn:ietf:params:xml:ns:caldav}calendar-user-type' => 'INDIVIDUAL', '{http://nextcloud.com/ns}language' => 'en', '{http://sabredav.org/ns}email-address' => 'bar@nextcloud.com', + '{DAV:}alternate-URI-set' => ['mailto:alias@nextcloud.com'] ] ]; $response = $this->connector->getPrincipalsByPrefix('principals/users'); diff --git a/apps/files_versions/lib/AppInfo/Application.php b/apps/files_versions/lib/AppInfo/Application.php index c994cd2f54ada..357a4179666e2 100644 --- a/apps/files_versions/lib/AppInfo/Application.php +++ b/apps/files_versions/lib/AppInfo/Application.php @@ -38,6 +38,7 @@ use OCA\Files_Versions\Listener\LoadSidebarListener; use OCA\Files_Versions\Versions\IVersionManager; use OCA\Files_Versions\Versions\VersionManager; +use OCP\Accounts\IAccountManager; use OCP\App\IAppManager; use OCP\AppFramework\App; use OCP\AppFramework\Bootstrap\IBootContext; @@ -75,6 +76,7 @@ public function register(IRegistrationContext $context): void { return new Principal( $server->get(IUserManager::class), $server->get(IGroupManager::class), + \OC::$server->get(IAccountManager::class), $server->get(IShareManager::class), $server->get(IUserSession::class), $server->get(IAppManager::class),