diff options
author | Anna Larch <anna@nextcloud.com> | 2023-12-15 14:51:01 +0100 |
---|---|---|
committer | Anna Larch <anna@nextcloud.com> | 2023-12-19 14:59:00 +0100 |
commit | 4c6eff975f1ea07e0250d0eff921b5ee54eeab3b (patch) | |
tree | da53d6b2fc6ce2818276d60b176fb18147c11d00 /apps/dav | |
parent | 2f647aacc50f949eccbaaa49a30698776e8205bb (diff) | |
download | nextcloud-server-4c6eff975f1ea07e0250d0eff921b5ee54eeab3b.tar.gz nextcloud-server-4c6eff975f1ea07e0250d0eff921b5ee54eeab3b.zip |
fix(userstatus): set user status to 'In a meeting' if calendar is busy
Signed-off-by: Anna Larch <anna@nextcloud.com>
Diffstat (limited to 'apps/dav')
-rw-r--r-- | apps/dav/composer/composer/autoload_classmap.php | 1 | ||||
-rw-r--r-- | apps/dav/composer/composer/autoload_static.php | 1 | ||||
-rw-r--r-- | apps/dav/lib/CalDAV/Status/Status.php | 72 | ||||
-rw-r--r-- | apps/dav/lib/CalDAV/Status/StatusService.php | 209 | ||||
-rw-r--r-- | apps/dav/tests/unit/CalDAV/Status/StatusServiceTest.php | 862 |
5 files changed, 382 insertions, 763 deletions
diff --git a/apps/dav/composer/composer/autoload_classmap.php b/apps/dav/composer/composer/autoload_classmap.php index 5d6b077ad53..72455e6bf67 100644 --- a/apps/dav/composer/composer/autoload_classmap.php +++ b/apps/dav/composer/composer/autoload_classmap.php @@ -99,7 +99,6 @@ return array( 'OCA\\DAV\\CalDAV\\Search\\Xml\\Filter\\PropFilter' => $baseDir . '/../lib/CalDAV/Search/Xml/Filter/PropFilter.php', 'OCA\\DAV\\CalDAV\\Search\\Xml\\Filter\\SearchTermFilter' => $baseDir . '/../lib/CalDAV/Search/Xml/Filter/SearchTermFilter.php', 'OCA\\DAV\\CalDAV\\Search\\Xml\\Request\\CalendarSearchReport' => $baseDir . '/../lib/CalDAV/Search/Xml/Request/CalendarSearchReport.php', - 'OCA\\DAV\\CalDAV\\Status\\Status' => $baseDir . '/../lib/CalDAV/Status/Status.php', 'OCA\\DAV\\CalDAV\\Status\\StatusService' => $baseDir . '/../lib/CalDAV/Status/StatusService.php', 'OCA\\DAV\\CalDAV\\TimezoneService' => $baseDir . '/../lib/CalDAV/TimezoneService.php', 'OCA\\DAV\\CalDAV\\Trashbin\\DeletedCalendarObject' => $baseDir . '/../lib/CalDAV/Trashbin/DeletedCalendarObject.php', diff --git a/apps/dav/composer/composer/autoload_static.php b/apps/dav/composer/composer/autoload_static.php index 2456604a9cb..0d715f510f7 100644 --- a/apps/dav/composer/composer/autoload_static.php +++ b/apps/dav/composer/composer/autoload_static.php @@ -114,7 +114,6 @@ class ComposerStaticInitDAV 'OCA\\DAV\\CalDAV\\Search\\Xml\\Filter\\PropFilter' => __DIR__ . '/..' . '/../lib/CalDAV/Search/Xml/Filter/PropFilter.php', 'OCA\\DAV\\CalDAV\\Search\\Xml\\Filter\\SearchTermFilter' => __DIR__ . '/..' . '/../lib/CalDAV/Search/Xml/Filter/SearchTermFilter.php', 'OCA\\DAV\\CalDAV\\Search\\Xml\\Request\\CalendarSearchReport' => __DIR__ . '/..' . '/../lib/CalDAV/Search/Xml/Request/CalendarSearchReport.php', - 'OCA\\DAV\\CalDAV\\Status\\Status' => __DIR__ . '/..' . '/../lib/CalDAV/Status/Status.php', 'OCA\\DAV\\CalDAV\\Status\\StatusService' => __DIR__ . '/..' . '/../lib/CalDAV/Status/StatusService.php', 'OCA\\DAV\\CalDAV\\TimezoneService' => __DIR__ . '/..' . '/../lib/CalDAV/TimezoneService.php', 'OCA\\DAV\\CalDAV\\Trashbin\\DeletedCalendarObject' => __DIR__ . '/..' . '/../lib/CalDAV/Trashbin/DeletedCalendarObject.php', diff --git a/apps/dav/lib/CalDAV/Status/Status.php b/apps/dav/lib/CalDAV/Status/Status.php deleted file mode 100644 index 46ddf7e47f3..00000000000 --- a/apps/dav/lib/CalDAV/Status/Status.php +++ /dev/null @@ -1,72 +0,0 @@ -<?php - -declare(strict_types=1); - -/** - * @copyright 2023 Anna Larch <anna.larch@gmx.net> - * - * @author Anna Larch <anna.larch@gmx.net> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ - -namespace OCA\DAV\CalDAV\Status; - -class Status { - public function __construct(private string $status = '', private ?string $message = null, private ?string $customMessage = null, private ?int $timestamp = null, private ?string $customEmoji = null) { - } - - public function getStatus(): string { - return $this->status; - } - - public function setStatus(string $status): void { - $this->status = $status; - } - - public function getMessage(): ?string { - return $this->message; - } - - public function setMessage(?string $message): void { - $this->message = $message; - } - - public function getCustomMessage(): ?string { - return $this->customMessage; - } - - public function setCustomMessage(?string $customMessage): void { - $this->customMessage = $customMessage; - } - - public function setEndTime(?int $timestamp): void { - $this->timestamp = $timestamp; - } - - public function getEndTime(): ?int { - return $this->timestamp; - } - - public function getCustomEmoji(): ?string { - return $this->customEmoji; - } - - public function setCustomEmoji(?string $emoji): void { - $this->customEmoji = $emoji; - } -} diff --git a/apps/dav/lib/CalDAV/Status/StatusService.php b/apps/dav/lib/CalDAV/Status/StatusService.php index add8a668f7a..11be9d8b2b8 100644 --- a/apps/dav/lib/CalDAV/Status/StatusService.php +++ b/apps/dav/lib/CalDAV/Status/StatusService.php @@ -25,83 +25,123 @@ declare(strict_types=1); */ namespace OCA\DAV\CalDAV\Status; +use DateTimeImmutable; use OC\Calendar\CalendarQuery; use OCA\DAV\CalDAV\CalendarImpl; -use OCA\DAV\CalDAV\FreeBusy\FreeBusyGenerator; -use OCA\DAV\CalDAV\InvitationResponse\InvitationResponseServer; -use OCA\DAV\CalDAV\Schedule\Plugin as SchedulePlugin; +use OCA\UserStatus\Service\StatusService as UserStatusService; +use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Utility\ITimeFactory; use OCP\Calendar\IManager; -use OCP\IL10N; +use OCP\ICache; +use OCP\ICacheFactory; use OCP\IUser as User; +use OCP\IUserManager; +use OCP\User\IAvailabilityCoordinator; use OCP\UserStatus\IUserStatus; +use Psr\Log\LoggerInterface; use Sabre\CalDAV\Xml\Property\ScheduleCalendarTransp; -use Sabre\DAV\Exception\NotAuthenticated; -use Sabre\DAVACL\Exception\NeedPrivileges; -use Sabre\DAVACL\Plugin as AclPlugin; -use Sabre\VObject\Component; -use Sabre\VObject\Component\VEvent; -use Sabre\VObject\Parameter; -use Sabre\VObject\Property; class StatusService { + private ICache $cache; public function __construct(private ITimeFactory $timeFactory, private IManager $calendarManager, - private InvitationResponseServer $server, - private IL10N $l10n, - private FreeBusyGenerator $generator) { + private IUserManager $userManager, + private UserStatusService $userStatusService, + private IAvailabilityCoordinator $availabilityCoordinator, + private ICacheFactory $cacheFactory, + private LoggerInterface $logger) { + $this->cache = $cacheFactory->createLocal('CalendarStatusService'); } - public function processCalendarAvailability(User $user): ?Status { - $userId = $user->getUID(); - $email = $user->getEMailAddress(); - if($email === null) { - return null; + public function processCalendarStatus(string $userId): void { + $user = $this->userManager->get($userId); + if($user === null) { + return; } - $server = $this->server->getServer(); + $availability = $this->availabilityCoordinator->getCurrentOutOfOfficeData($user); + if($availability !== null && $this->availabilityCoordinator->isInEffect($availability)) { + $this->logger->debug('An Absence is in effect, skipping calendar status check', ['user' => $userId]); + return; + } - /** @var SchedulePlugin $schedulingPlugin */ - $schedulingPlugin = $server->getPlugin('caldav-schedule'); - $caldavNS = '{'.$schedulingPlugin::NS_CALDAV.'}'; + $calendarEvents = $this->cache->get($userId); + if($calendarEvents === null) { + $calendarEvents = $this->getCalendarEvents($user); + $this->cache->set($userId, $calendarEvents, 300); + } - /** @var AclPlugin $aclPlugin */ - $aclPlugin = $server->getPlugin('acl'); - if ('mailto:' === substr($email, 0, 7)) { - $email = substr($email, 7); + if(empty($calendarEvents)) { + $this->userStatusService->revertUserStatus($userId, IUserStatus::MESSAGE_CALENDAR_BUSY); + $this->logger->debug('No calendar events found for status check', ['user' => $userId]); + return; } - $result = $aclPlugin->principalSearch( - ['{http://sabredav.org/ns}email-address' => $email], - [ - '{DAV:}principal-URL', - $caldavNS.'calendar-home-set', - $caldavNS.'schedule-inbox-URL', - '{http://sabredav.org/ns}email-address', - ] - ); + $userStatusTimestamp = null; + $currentStatus = null; + try { + $currentStatus = $this->userStatusService->findByUserId($userId); + $userStatusTimestamp = $currentStatus->getIsUserDefined() ? $currentStatus->getStatusTimestamp() : null; + } catch (DoesNotExistException) { + } - if (!count($result) || !isset($result[0][200][$caldavNS.'schedule-inbox-URL'])) { - return null; + if($currentStatus !== null && $currentStatus->getMessageId() === IUserStatus::MESSAGE_CALL + || $currentStatus !== null && $currentStatus->getStatus() === IUserStatus::DND + || $currentStatus !== null && $currentStatus->getStatus() === IUserStatus::INVISIBLE) { + // We don't overwrite the call status, DND status or Invisible status + $this->logger->debug('Higher priority status detected, skipping calendar status change', ['user' => $userId]); + return; } - $inboxUrl = $result[0][200][$caldavNS.'schedule-inbox-URL']->getHref(); + // Filter events to see if we have any that apply to the calendar status + $applicableEvents = array_filter($calendarEvents, function (array $calendarEvent) use ($userStatusTimestamp) { + $component = $calendarEvent['objects'][0]; + if(isset($component['X-NEXTCLOUD-OUT-OF-OFFICE'])) { + return false; + } + if(isset($component['DTSTART']) && $userStatusTimestamp !== null) { + /** @var DateTimeImmutable $dateTime */ + $dateTime = $component['DTSTART'][0]; + $timestamp = $dateTime->getTimestamp(); + if($userStatusTimestamp > $timestamp) { + return false; + } + } + // Ignore events that are transparent + if(isset($component['TRANSP']) && strcasecmp($component['TRANSP'][0], 'TRANSPARENT') === 0) { + return false; + } + return true; + }); - // Do we have permission? - try { - $aclPlugin->checkPrivileges($inboxUrl, $caldavNS.'schedule-query-freebusy'); - } catch (NeedPrivileges | NotAuthenticated $exception) { - return null; + if(empty($applicableEvents)) { + $this->userStatusService->revertUserStatus($userId, IUserStatus::MESSAGE_CALENDAR_BUSY); + $this->logger->debug('No status relevant events found, skipping calendar status change', ['user' => $userId]); + return; } - $now = $this->timeFactory->now(); - $calendarTimeZone = $now->getTimezone(); - $calendars = $this->calendarManager->getCalendarsForPrincipal('principals/users/' . $userId); + // One event that fulfills all status conditions is enough + // 1. Not an OOO event + // 2. Current user status was not set after the start of this event + // 3. Event is not set to be transparent + $count = count($applicableEvents); + $this->logger->debug("Found $count applicable event(s), changing user status", ['user' => $userId]); + $this->userStatusService->setUserStatus( + $userId, + IUserStatus::AWAY, + IUserStatus::MESSAGE_CALENDAR_BUSY, + true + ); + + } + + private function getCalendarEvents(User $user): array { + $calendars = $this->calendarManager->getCalendarsForPrincipal('principals/users/' . $user->getUID()); if(empty($calendars)) { - return null; + return []; } - $query = $this->calendarManager->newQuery('principals/users/' . $userId); + $query = $this->calendarManager->newQuery('principals/users/' . $user->getUID()); foreach ($calendars as $calendarObject) { // We can only work with a calendar if it exposes its scheduling information if (!$calendarObject instanceof CalendarImpl) { @@ -114,83 +154,20 @@ class StatusService { // ignore it for free-busy purposes. continue; } - - /** @var Component\VTimeZone|null $ctz */ - $ctz = $calendarObject->getSchedulingTimezone(); - if ($ctz !== null) { - $calendarTimeZone = $ctz->getTimeZone(); - } $query->addSearchCalendar($calendarObject->getUri()); } - $calendarEvents = []; - $dtStart = $now; - $dtEnd = \DateTimeImmutable::createFromMutable($this->timeFactory->getDateTime('+10 minutes')); + $dtStart = DateTimeImmutable::createFromMutable($this->timeFactory->getDateTime()); + $dtEnd = DateTimeImmutable::createFromMutable($this->timeFactory->getDateTime('+5 minutes')); // Only query the calendars when there's any to search if($query instanceof CalendarQuery && !empty($query->getCalendarUris())) { // Query the next hour $query->setTimerangeStart($dtStart); $query->setTimerangeEnd($dtEnd); - $calendarEvents = $this->calendarManager->searchForPrincipal($query); + return $this->calendarManager->searchForPrincipal($query); } - // @todo we can cache that - if(empty($calendarEvents)) { - return null; - } - - $calendar = $this->generator->getVCalendar(); - foreach ($calendarEvents as $calendarEvent) { - $vEvent = new VEvent($calendar, 'VEVENT'); - foreach($calendarEvent['objects'] as $component) { - foreach ($component as $key => $value) { - $vEvent->add($key, $value[0]); - } - } - $calendar->add($vEvent); - } - - $calendar->METHOD = 'REQUEST'; - - $this->generator->setObjects($calendar); - $this->generator->setTimeRange($dtStart, $dtEnd); - $this->generator->setTimeZone($calendarTimeZone); - $result = $this->generator->getResult(); - - if (!isset($result->VFREEBUSY)) { - return null; - } - - /** @var Component $freeBusyComponent */ - $freeBusyComponent = $result->VFREEBUSY; - $freeBusyProperties = $freeBusyComponent->select('FREEBUSY'); - // If there is no FreeBusy property, the time-range is empty and available - if (count($freeBusyProperties) === 0) { - return null; - } - - /** @var Property $freeBusyProperty */ - $freeBusyProperty = $freeBusyProperties[0]; - if (!$freeBusyProperty->offsetExists('FBTYPE')) { - // If there is no FBTYPE, it means it's busy from a regular event - return new Status(IUserStatus::BUSY, IUserStatus::MESSAGE_CALENDAR_BUSY); - } - - // If we can't deal with the FBTYPE (custom properties are a possibility) - // we should ignore it and leave the current status - $fbTypeParameter = $freeBusyProperty->offsetGet('FBTYPE'); - if (!($fbTypeParameter instanceof Parameter)) { - return null; - } - $fbType = $fbTypeParameter->getValue(); - switch ($fbType) { - // Ignore BUSY-UNAVAILABLE, that's for the automation - case 'BUSY': - case 'BUSY-TENTATIVE': - return new Status(IUserStatus::BUSY, IUserStatus::MESSAGE_CALENDAR_BUSY, $this->l10n->t('In a meeting')); - default: - return null; - } + return []; } } diff --git a/apps/dav/tests/unit/CalDAV/Status/StatusServiceTest.php b/apps/dav/tests/unit/CalDAV/Status/StatusServiceTest.php index 705298de125..7073c02b8e4 100644 --- a/apps/dav/tests/unit/CalDAV/Status/StatusServiceTest.php +++ b/apps/dav/tests/unit/CalDAV/Status/StatusServiceTest.php @@ -24,31 +24,31 @@ namespace OCA\DAV\Tests\unit\CalDAV\Status; use OC\Calendar\CalendarQuery; use OCA\DAV\CalDAV\CalendarImpl; -use OCA\DAV\CalDAV\FreeBusy\FreeBusyGenerator; -use OCA\DAV\CalDAV\InvitationResponse\InvitationResponseServer; -use OCA\DAV\CalDAV\Schedule\Plugin; use OCA\DAV\CalDAV\Status\StatusService; -use OCA\DAV\Connector\Sabre\Server; +use OCA\UserStatus\Db\UserStatus; +use OCA\UserStatus\Service\StatusService as UserStatusService; +use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Utility\ITimeFactory; use OCP\Calendar\IManager; -use OCP\IL10N; +use OCP\ICache; +use OCP\ICacheFactory; use OCP\IUser; +use OCP\IUserManager; +use OCP\User\IAvailabilityCoordinator; +use OCP\User\IOutOfOfficeData; +use OCP\UserStatus\IUserStatus; use PHPUnit\Framework\MockObject\MockObject; -use Sabre\CalDAV\Xml\Property\ScheduleCalendarTransp; -use Sabre\DAV\Exception\NotAuthenticated; -use Sabre\DAV\Xml\Property\LocalHref; -use Sabre\DAVACL\Exception\NeedPrivileges; -use Sabre\VObject\Component\VCalendar; -use Sabre\VObject\Component\VTimeZone; -use Sabre\VObject\Reader; +use Psr\Log\LoggerInterface; use Test\TestCase; class StatusServiceTest extends TestCase { private ITimeFactory|MockObject $timeFactory; private IManager|MockObject $calendarManager; - private InvitationResponseServer|MockObject $server; - private IL10N|MockObject $l10n; - private FreeBusyGenerator|MockObject $generator; + private IUserManager|MockObject $userManager; + private UserStatusService|MockObject $userStatusService; + private IAvailabilityCoordinator|MockObject $availabilityCoordinator; + private ICacheFactory|MockObject $cacheFactory; + private LoggerInterface|MockObject $logger; private StatusService $service; protected function setUp(): void { @@ -56,644 +56,360 @@ class StatusServiceTest extends TestCase { $this->timeFactory = $this->createMock(ITimeFactory::class); $this->calendarManager = $this->createMock(IManager::class); - $this->server = $this->createMock(InvitationResponseServer::class); - $this->l10n = $this->createMock(IL10N::class); - $this->generator = $this->createMock(FreeBusyGenerator::class); + $this->userManager = $this->createMock(IUserManager::class); + $this->userStatusService = $this->createMock(UserStatusService::class); + $this->availabilityCoordinator = $this->createMock(IAvailabilityCoordinator::class); + $this->cacheFactory = $this->createMock(ICacheFactory::class); + $this->logger = $this->createMock(LoggerInterface::class); + $this->cache = $this->createMock(ICache::class); + $this->cacheFactory->expects(self::once()) + ->method('createLocal') + ->with('CalendarStatusService') + ->willReturn($this->cache); $this->service = new StatusService($this->timeFactory, $this->calendarManager, - $this->server, - $this->l10n, - $this->generator); + $this->userManager, + $this->userStatusService, + $this->availabilityCoordinator, + $this->cacheFactory, + $this->logger, + ); } - public function testNoEmail(): void { - $user = $this->createConfiguredMock(IUser::class, [ - 'getUID' => 'admin', - 'getEMailAddress' => null, - ]); - - $user->expects(self::once()) - ->method('getUID') - ->willReturn('admin'); - $user->expects(self::once()) - ->method('getEMailAddress') + public function testNoUser(): void { + $this->userManager->expects(self::once()) + ->method('get') ->willReturn(null); - $this->server->expects(self::never()) - ->method('getServer'); - $this->timeFactory->expects(self::never()) - ->method('now'); - $this->timeFactory->expects(self::never()) - ->method('getDateTime'); + $this->availabilityCoordinator->expects(self::never()) + ->method('getCurrentOutOfOfficeData'); + $this->availabilityCoordinator->expects(self::never()) + ->method('isInEffect'); + $this->logger->expects(self::never()) + ->method('debug'); + $this->cache->expects(self::never()) + ->method('get'); + $this->cache->expects(self::never()) + ->method('set'); $this->calendarManager->expects(self::never()) ->method('getCalendarsForPrincipal'); $this->calendarManager->expects(self::never()) ->method('newQuery'); + $this->timeFactory->expects(self::never()) + ->method('getDateTime'); $this->calendarManager->expects(self::never()) ->method('searchForPrincipal'); - $this->generator->expects(self::never()) - ->method('getVCalendar'); - $this->generator->expects(self::never()) - ->method('setObjects'); - $this->generator->expects(self::never()) - ->method('setTimeRange'); - $this->generator->expects(self::never()) - ->method('setTimeZone'); - $this->generator->expects(self::never()) - ->method('getResult'); - - $status = $this->service->processCalendarAvailability($user); - $this->assertNull($status); + $this->userStatusService->expects(self::never()) + ->method('revertUserStatus'); + $this->userStatusService->expects(self::never()) + ->method('setUserStatus'); + $this->userStatusService->expects(self::never()) + ->method('findByUserId'); + + $this->service->processCalendarStatus('admin'); } - public function testNoAcl(): void { + public function testOOOInEffect(): void { $user = $this->createConfiguredMock(IUser::class, [ 'getUID' => 'admin', - 'getEMailAddress' => 'test@test.com', ]); - $availability = ''; - $server = $this->createMock(Server::class); - $schedulingPlugin = $this->createMock(Plugin::class); - $aclPlugin = $this->createMock(\Sabre\DAVACL\Plugin::class); - - $user->expects(self::once()) - ->method('getUID') - ->willReturn('admin'); - $user->expects(self::once()) - ->method('getEMailAddress') - ->willReturn('test@test.com'); - $this->server->expects(self::once()) - ->method('getServer') - ->willReturn($server); - $server->expects(self::exactly(2)) - ->method('getPlugin') - ->withConsecutive( - ['caldav-schedule'], - ['acl'], - )->willReturnOnConsecutiveCalls($schedulingPlugin, $aclPlugin); - $aclPlugin->expects(self::once()) - ->method('principalSearch') - ->with([ '{http://sabredav.org/ns}email-address' => 'test@test.com']) - ->willReturn([]); - $aclPlugin->expects(self::never()) - ->method('checkPrivileges'); - $this->timeFactory->expects(self::never()) - ->method('now'); - $this->timeFactory->expects(self::never()) - ->method('getDateTime'); + + $this->userManager->expects(self::once()) + ->method('get') + ->willReturn($user); + $this->availabilityCoordinator->expects(self::once()) + ->method('getCurrentOutOfOfficeData') + ->willReturn($this->createMock(IOutOfOfficeData::class)); + $this->availabilityCoordinator->expects(self::once()) + ->method('isInEffect') + ->willReturn(true); + $this->logger->expects(self::once()) + ->method('debug'); + $this->cache->expects(self::never()) + ->method('get'); + $this->cache->expects(self::never()) + ->method('set'); $this->calendarManager->expects(self::never()) ->method('getCalendarsForPrincipal'); $this->calendarManager->expects(self::never()) ->method('newQuery'); + $this->timeFactory->expects(self::never()) + ->method('getDateTime'); $this->calendarManager->expects(self::never()) ->method('searchForPrincipal'); - $this->generator->expects(self::never()) - ->method('getVCalendar'); - $this->generator->expects(self::never()) - ->method('setObjects'); - $this->generator->expects(self::never()) - ->method('setTimeRange'); - $this->generator->expects(self::never()) - ->method('setTimeZone'); - $this->generator->expects(self::never()) - ->method('getResult'); - - $status = $this->service->processCalendarAvailability($user); - $this->assertNull($status); + $this->userStatusService->expects(self::never()) + ->method('revertUserStatus'); + $this->userStatusService->expects(self::never()) + ->method('setUserStatus'); + $this->userStatusService->expects(self::never()) + ->method('findByUserId'); + + $this->service->processCalendarStatus('admin'); } - public function testNoInbox(): void { + public function testNoCalendars(): void { $user = $this->createConfiguredMock(IUser::class, [ 'getUID' => 'admin', - 'getEMailAddress' => 'test@test.com', ]); - $availability = ''; - $server = $this->createMock(Server::class); - $schedulingPlugin = $this->createMock(Plugin::class); - $aclPlugin = $this->createMock(\Sabre\DAVACL\Plugin::class); - - $user->expects(self::once()) - ->method('getUID') - ->willReturn('admin'); - $user->expects(self::once()) - ->method('getEMailAddress') - ->willReturn('test@test.com'); - $this->server->expects(self::once()) - ->method('getServer') - ->willReturn($server); - $server->expects(self::exactly(2)) - ->method('getPlugin') - ->withConsecutive( - ['caldav-schedule'], - ['acl'], - )->willReturnOnConsecutiveCalls($schedulingPlugin, $aclPlugin); - $aclPlugin->expects(self::once()) - ->method('principalSearch') - ->with([ '{http://sabredav.org/ns}email-address' => 'test@test.com']) + + $this->userManager->expects(self::once()) + ->method('get') + ->willReturn($user); + $this->availabilityCoordinator->expects(self::once()) + ->method('getCurrentOutOfOfficeData') + ->willReturn(null); + $this->availabilityCoordinator->expects(self::never()) + ->method('isInEffect'); + $this->cache->expects(self::once()) + ->method('get') + ->willReturn(null); + $this->cache->expects(self::once()) + ->method('set'); + $this->calendarManager->expects(self::once()) + ->method('getCalendarsForPrincipal') ->willReturn([]); - $aclPlugin->expects(self::never()) - ->method('checkPrivileges'); - $this->timeFactory->expects(self::never()) - ->method('now'); - $this->timeFactory->expects(self::never()) - ->method('getDateTime'); - $this->calendarManager->expects(self::never()) - ->method('getCalendarsForPrincipal'); $this->calendarManager->expects(self::never()) ->method('newQuery'); - $this->calendarManager->expects(self::never()) - ->method('searchForPrincipal'); - $this->generator->expects(self::never()) - ->method('getVCalendar'); - $this->generator->expects(self::never()) - ->method('setObjects'); - $this->generator->expects(self::never()) - ->method('setTimeRange'); - $this->generator->expects(self::never()) - ->method('setTimeZone'); - $this->generator->expects(self::never()) - ->method('getResult'); - - $status = $this->service->processCalendarAvailability($user); - $this->assertNull($status); - } - - public function testNoPrivilegesAcl(): void { - $user = $this->createConfiguredMock(IUser::class, [ - 'getUID' => 'admin', - 'getEMailAddress' => 'test@test.com', - ]); - $availability = ''; - $server = $this->createMock(Server::class); - $schedulingPlugin = $this->createMock(Plugin::class); - $aclPlugin = $this->createMock(\Sabre\DAVACL\Plugin::class); - $principal = 'principals/users/admin'; - $calendarHome = $this->createMock(LocalHref::class); - $acl = [[200 => ['{urn:ietf:params:xml:ns:caldav}schedule-inbox-URL' => $calendarHome]]]; - - $user->expects(self::once()) - ->method('getUID') - ->willReturn('admin'); - $user->expects(self::once()) - ->method('getEMailAddress') - ->willReturn('test@test.com'); - $this->server->expects(self::once()) - ->method('getServer') - ->willReturn($server); - $server->expects(self::exactly(2)) - ->method('getPlugin') - ->withConsecutive( - ['caldav-schedule'], - ['acl'], - )->willReturnOnConsecutiveCalls($schedulingPlugin, $aclPlugin); - $aclPlugin->expects(self::once()) - ->method('principalSearch') - ->with([ '{http://sabredav.org/ns}email-address' => 'test@test.com']) - ->willReturn($acl); - $calendarHome->expects(self::once()) - ->method('getHref') - ->willReturn('calendars/admin/inbox/'); - $aclPlugin->expects(self::once()) - ->method('checkPrivileges') - ->willThrowException(new NeedPrivileges($principal, ['{DAV:}all'])); - $this->timeFactory->expects(self::never()) - ->method('now'); $this->timeFactory->expects(self::never()) ->method('getDateTime'); $this->calendarManager->expects(self::never()) - ->method('getCalendarsForPrincipal'); - $this->calendarManager->expects(self::never()) - ->method('newQuery'); - $this->calendarManager->expects(self::never()) ->method('searchForPrincipal'); - $this->generator->expects(self::never()) - ->method('getVCalendar'); - $this->generator->expects(self::never()) - ->method('setObjects'); - $this->generator->expects(self::never()) - ->method('setTimeRange'); - $this->generator->expects(self::never()) - ->method('setTimeZone'); - $this->generator->expects(self::never()) - ->method('getResult'); - - $status = $this->service->processCalendarAvailability($user); - $this->assertNull($status); + $this->userStatusService->expects(self::once()) + ->method('revertUserStatus'); + $this->logger->expects(self::once()) + ->method('debug'); + $this->userStatusService->expects(self::never()) + ->method('setUserStatus'); + $this->userStatusService->expects(self::never()) + ->method('findByUserId'); + + $this->service->processCalendarStatus('admin'); } - public function testNotAuthenticated(): void { + public function testNoCalendarEvents(): void { $user = $this->createConfiguredMock(IUser::class, [ 'getUID' => 'admin', - 'getEMailAddress' => 'test@test.com', ]); - $availability = ''; - $server = $this->createMock(Server::class); - $schedulingPlugin = $this->createMock(Plugin::class); - $aclPlugin = $this->createMock(\Sabre\DAVACL\Plugin::class); - $calendarHome = $this->createMock(LocalHref::class); - $acl = [[200 => ['{urn:ietf:params:xml:ns:caldav}schedule-inbox-URL' => $calendarHome]]]; - - $user->expects(self::once()) - ->method('getUID') - ->willReturn('admin'); - $user->expects(self::once()) - ->method('getEMailAddress') - ->willReturn('test@test.com'); - $this->server->expects(self::once()) - ->method('getServer') - ->willReturn($server); - $server->expects(self::exactly(2)) - ->method('getPlugin') - ->withConsecutive( - ['caldav-schedule'], - ['acl'], - )->willReturnOnConsecutiveCalls($schedulingPlugin, $aclPlugin); - $aclPlugin->expects(self::once()) - ->method('principalSearch') - ->with([ '{http://sabredav.org/ns}email-address' => 'test@test.com']) - ->willReturn($acl); - $calendarHome->expects(self::once()) - ->method('getHref') - ->willReturn('calendars/admin/inbox/'); - $aclPlugin->expects(self::once()) - ->method('checkPrivileges') - ->willThrowException(new NotAuthenticated()); - $this->timeFactory->expects(self::never()) - ->method('now'); - $this->timeFactory->expects(self::never()) - ->method('getDateTime'); - $this->calendarManager->expects(self::never()) - ->method('getCalendarsForPrincipal'); - $this->calendarManager->expects(self::never()) - ->method('newQuery'); - $this->calendarManager->expects(self::never()) - ->method('searchForPrincipal'); - $this->generator->expects(self::never()) - ->method('getVCalendar'); - $this->generator->expects(self::never()) - ->method('setObjects'); - $this->generator->expects(self::never()) - ->method('setTimeRange'); - $this->generator->expects(self::never()) - ->method('setTimeZone'); - $this->generator->expects(self::never()) - ->method('getResult'); - - $status = $this->service->processCalendarAvailability($user); - $this->assertNull($status); + + $this->userManager->expects(self::once()) + ->method('get') + ->willReturn($user); + $this->availabilityCoordinator->expects(self::once()) + ->method('getCurrentOutOfOfficeData') + ->willReturn(null); + $this->availabilityCoordinator->expects(self::never()) + ->method('isInEffect'); + $this->cache->expects(self::once()) + ->method('get') + ->willReturn(null); + $this->cache->expects(self::once()) + ->method('set'); + $this->calendarManager->expects(self::once()) + ->method('getCalendarsForPrincipal') + ->willReturn([$this->createMock(CalendarImpl::class)]); + $this->calendarManager->expects(self::once()) + ->method('newQuery') + ->willReturn(new CalendarQuery('admin')); + $this->timeFactory->expects(self::exactly(2)) + ->method('getDateTime') + ->willReturn(new \DateTime()); + $this->calendarManager->expects(self::once()) + ->method('searchForPrincipal') + ->willReturn([]); + $this->userStatusService->expects(self::once()) + ->method('revertUserStatus'); + $this->logger->expects(self::once()) + ->method('debug'); + $this->userStatusService->expects(self::never()) + ->method('setUserStatus'); + $this->userStatusService->expects(self::never()) + ->method('findByUserId'); + + $this->service->processCalendarStatus('admin'); } - public function testNoCalendars(): void { + public function testCalendarEvent(): void { $user = $this->createConfiguredMock(IUser::class, [ 'getUID' => 'admin', - 'getEMailAddress' => 'test@test.com', ]); - $availability = ''; - $server = $this->createMock(Server::class); - $schedulingPlugin = $this->createMock(Plugin::class); - $aclPlugin = $this->createMock(\Sabre\DAVACL\Plugin::class); - $calendarHome = $this->createMock(LocalHref::class); - $acl = [[200 => ['{urn:ietf:params:xml:ns:caldav}schedule-inbox-URL' => $calendarHome]]]; - $now = new \DateTimeImmutable('1970-1-1', new \DateTimeZone('UTC')); - $principal = 'principals/users/admin'; - - $user->expects(self::once()) - ->method('getUID') - ->willReturn('admin'); - $user->expects(self::once()) - ->method('getEMailAddress') - ->willReturn('test@test.com'); - $this->server->expects(self::once()) - ->method('getServer') - ->willReturn($server); - $server->expects(self::exactly(2)) - ->method('getPlugin') - ->withConsecutive( - ['caldav-schedule'], - ['acl'], - )->willReturnOnConsecutiveCalls($schedulingPlugin, $aclPlugin); - $aclPlugin->expects(self::once()) - ->method('principalSearch') - ->with([ '{http://sabredav.org/ns}email-address' => 'test@test.com']) - ->willReturn($acl); - $calendarHome->expects(self::once()) - ->method('getHref') - ->willReturn('calendars/admin/inbox/'); - $aclPlugin->expects(self::once()) - ->method('checkPrivileges') - ->willReturn(true); - $this->timeFactory->expects(self::once()) - ->method('now') - ->willReturn($now); + + $this->userManager->expects(self::once()) + ->method('get') + ->willReturn($user); + $this->availabilityCoordinator->expects(self::once()) + ->method('getCurrentOutOfOfficeData') + ->willReturn(null); + $this->availabilityCoordinator->expects(self::never()) + ->method('isInEffect'); + $this->cache->expects(self::once()) + ->method('get') + ->willReturn(null); + $this->cache->expects(self::once()) + ->method('set'); $this->calendarManager->expects(self::once()) ->method('getCalendarsForPrincipal') - ->with($principal) - ->willReturn([]); - $this->timeFactory->expects(self::never()) - ->method('getDateTime'); - $this->calendarManager->expects(self::never()) - ->method('newQuery'); - $this->calendarManager->expects(self::never()) - ->method('searchForPrincipal'); - $this->generator->expects(self::never()) - ->method('getVCalendar'); - $this->generator->expects(self::never()) - ->method('setObjects'); - $this->generator->expects(self::never()) - ->method('setTimeRange'); - $this->generator->expects(self::never()) - ->method('setTimeZone'); - $this->generator->expects(self::never()) - ->method('getResult'); - - $status = $this->service->processCalendarAvailability($user); - $this->assertNull($status); + ->willReturn([$this->createMock(CalendarImpl::class)]); + $this->calendarManager->expects(self::once()) + ->method('newQuery') + ->willReturn(new CalendarQuery('admin')); + $this->timeFactory->expects(self::exactly(2)) + ->method('getDateTime') + ->willReturn(new \DateTime()); + $this->userStatusService->expects(self::once()) + ->method('findByUserId') + ->willThrowException(new DoesNotExistException('')); + $this->calendarManager->expects(self::once()) + ->method('searchForPrincipal') + ->willReturn([['objects' => [[]]]]); + $this->userStatusService->expects(self::never()) + ->method('revertUserStatus'); + $this->logger->expects(self::once()) + ->method('debug'); + $this->userStatusService->expects(self::once()) + ->method('setUserStatus'); + + + $this->service->processCalendarStatus('admin'); } - public function testEmptyAvailabilityAndNoSearchCalendars(): void { + public function testCallStatus(): void { $user = $this->createConfiguredMock(IUser::class, [ 'getUID' => 'admin', - 'getEMailAddress' => 'test@test.com', ]); - $availability = ''; - $server = $this->createMock(Server::class); - $schedulingPlugin = $this->createMock(Plugin::class); - $aclPlugin = $this->createMock(\Sabre\DAVACL\Plugin::class); - $calendarHome = $this->createMock(LocalHref::class); - $now = new \DateTimeImmutable('1970-1-1', new \DateTimeZone('UTC')); - $inTenMinutes = new \DateTime('1970-1-1 01:00'); - $acl = [[200 => ['{urn:ietf:params:xml:ns:caldav}schedule-inbox-URL' => $calendarHome]]]; - $principal = 'principals/users/admin'; - $calendar = $this->createMock(CalendarImpl::class); - $query = $this->createMock(CalendarQuery::class); - - $user->expects(self::once()) - ->method('getUID') - ->willReturn('admin'); - $user->expects(self::once()) - ->method('getEMailAddress') - ->willReturn('test@test.com'); - $this->server->expects(self::once()) - ->method('getServer') - ->willReturn($server); - $server->expects(self::exactly(2)) - ->method('getPlugin') - ->withConsecutive( - ['caldav-schedule'], - ['acl'], - )->willReturnOnConsecutiveCalls($schedulingPlugin, $aclPlugin); - $aclPlugin->expects(self::once()) - ->method('principalSearch') - ->with([ '{http://sabredav.org/ns}email-address' => 'test@test.com']) - ->willReturn($acl); - $calendarHome->expects(self::once()) - ->method('getHref') - ->willReturn('calendars/admin/inbox/'); - $aclPlugin->expects(self::once()) - ->method('checkPrivileges') - ->willReturn(true); - $this->timeFactory->expects(self::once()) - ->method('now') - ->willReturn($now); + + $this->userManager->expects(self::once()) + ->method('get') + ->willReturn($user); + $this->availabilityCoordinator->expects(self::once()) + ->method('getCurrentOutOfOfficeData') + ->willReturn(null); + $this->availabilityCoordinator->expects(self::never()) + ->method('isInEffect'); + $this->cache->expects(self::once()) + ->method('get') + ->willReturn(null); + $this->cache->expects(self::once()) + ->method('set'); $this->calendarManager->expects(self::once()) ->method('getCalendarsForPrincipal') - ->with($principal) - ->willReturn([$calendar]); + ->willReturn([$this->createMock(CalendarImpl::class)]); $this->calendarManager->expects(self::once()) ->method('newQuery') - ->with($principal) - ->willReturn($query); - $calendar->expects(self::once()) - ->method('getSchedulingTransparency') - ->willReturn(new ScheduleCalendarTransp('transparent')); - $this->timeFactory->expects(self::once()) + ->willReturn(new CalendarQuery('admin')); + $this->timeFactory->expects(self::exactly(2)) ->method('getDateTime') - ->with('+10 minutes') - ->willReturn($inTenMinutes); - $this->calendarManager->expects(self::never()) - ->method('searchForPrincipal'); - $this->generator->expects(self::never()) - ->method('getVCalendar'); - $this->generator->expects(self::never()) - ->method('setObjects'); - $this->generator->expects(self::never()) - ->method('setTimeRange'); - $this->generator->expects(self::never()) - ->method('setTimeZone'); - $this->generator->expects(self::never()) - ->method('getResult'); - - $status = $this->service->processCalendarAvailability($user); - $this->assertNull($status); + ->willReturn(new \DateTime()); + $this->calendarManager->expects(self::once()) + ->method('searchForPrincipal') + ->willReturn([['objects' => [[]]]]); + $userStatus = new UserStatus(); + $userStatus->setMessageId(IUserStatus::MESSAGE_CALL); + $userStatus->setStatusTimestamp(123456); + $this->userStatusService->expects(self::once()) + ->method('findByUserId') + ->willReturn($userStatus); + $this->logger->expects(self::once()) + ->method('debug'); + $this->userStatusService->expects(self::never()) + ->method('revertUserStatus'); + $this->userStatusService->expects(self::never()) + ->method('setUserStatus'); + + + $this->service->processCalendarStatus('admin'); } - public function testEmptyAvailabilityAndSearchCalendarsNoResults(): void { + public function testInvisibleStatus(): void { $user = $this->createConfiguredMock(IUser::class, [ 'getUID' => 'admin', - 'getEMailAddress' => 'test@test.com', ]); - $availability = ''; - $server = $this->createMock(Server::class); - $schedulingPlugin = $this->createMock(Plugin::class); - $aclPlugin = $this->createMock(\Sabre\DAVACL\Plugin::class); - $calendarHome = $this->createMock(LocalHref::class); - $acl = [[200 => ['{urn:ietf:params:xml:ns:caldav}schedule-inbox-URL' => $calendarHome]]]; - $now = new \DateTimeImmutable('1970-1-1 00:00', new \DateTimeZone('UTC')); - $inTenMinutes = new \DateTime('1970-1-1 01:00'); - $immutableInTenMinutes = \DateTimeImmutable::createFromMutable($inTenMinutes); - $principal = 'principals/users/admin'; - $query = $this->createMock(CalendarQuery::class); - $timezone = new \DateTimeZone('UTC'); - $timezoneObj = $this->createMock(VTimeZone::class); - $calendar = $this->createMock(CalendarImpl::class); - - $user->expects(self::once()) - ->method('getUID') - ->willReturn('admin'); - $user->expects(self::once()) - ->method('getEMailAddress') - ->willReturn('test@test.com'); - $this->server->expects(self::once()) - ->method('getServer') - ->willReturn($server); - $server->expects(self::exactly(2)) - ->method('getPlugin') - ->withConsecutive( - ['caldav-schedule'], - ['acl'], - )->willReturnOnConsecutiveCalls($schedulingPlugin, $aclPlugin); - $aclPlugin->expects(self::once()) - ->method('principalSearch') - ->with(['{http://sabredav.org/ns}email-address' => 'test@test.com']) - ->willReturn($acl); - $calendarHome->expects(self::once()) - ->method('getHref') - ->willReturn('calendars/admin/inbox/'); - $aclPlugin->expects(self::once()) - ->method('checkPrivileges') - ->willReturn(true); - $this->timeFactory->expects(self::once()) - ->method('now') - ->willReturn($now); + + $this->userManager->expects(self::once()) + ->method('get') + ->willReturn($user); + $this->availabilityCoordinator->expects(self::once()) + ->method('getCurrentOutOfOfficeData') + ->willReturn(null); + $this->availabilityCoordinator->expects(self::never()) + ->method('isInEffect'); + $this->cache->expects(self::once()) + ->method('get') + ->willReturn(null); + $this->cache->expects(self::once()) + ->method('set'); $this->calendarManager->expects(self::once()) ->method('getCalendarsForPrincipal') - ->with($principal) - ->willReturn([$calendar]); + ->willReturn([$this->createMock(CalendarImpl::class)]); $this->calendarManager->expects(self::once()) ->method('newQuery') - ->with($principal) - ->willReturn($query); - $calendar->expects(self::once()) - ->method('getSchedulingTransparency') - ->willReturn(new ScheduleCalendarTransp('opaque')); - $calendar->expects(self::once()) - ->method('getSchedulingTimezone') - ->willReturn($timezoneObj); - $timezoneObj->expects(self::once()) - ->method('getTimeZone') - ->willReturn($timezone); - $calendar->expects(self::once()) - ->method('getUri'); - $query->expects(self::once()) - ->method('addSearchCalendar'); - $query->expects(self::once()) - ->method('getCalendarUris') - ->willReturn([$calendar]); - $this->timeFactory->expects(self::once()) + ->willReturn(new CalendarQuery('admin')); + $this->timeFactory->expects(self::exactly(2)) ->method('getDateTime') - ->with('+10 minutes') - ->willReturn($inTenMinutes); - $query->expects(self::once()) - ->method('setTimerangeStart') - ->with($now); - $query->expects(self::once()) - ->method('setTimerangeEnd') - ->with($immutableInTenMinutes); + ->willReturn(new \DateTime()); $this->calendarManager->expects(self::once()) ->method('searchForPrincipal') - ->with($query) - ->willReturn([]); - $this->generator->expects(self::never()) - ->method('getVCalendar'); - $this->generator->expects(self::never()) - ->method('setObjects'); - $this->generator->expects(self::never()) - ->method('setTimeRange'); - $this->generator->expects(self::never()) - ->method('setTimeZone'); - $this->generator->expects(self::never()) - ->method('getResult'); - - $status = $this->service->processCalendarAvailability($user); - $this->assertNull($status); + ->willReturn([['objects' => [[]]]]); + $userStatus = new UserStatus(); + $userStatus->setStatus(IUserStatus::INVISIBLE); + $userStatus->setStatusTimestamp(123456); + $this->userStatusService->expects(self::once()) + ->method('findByUserId') + ->willReturn($userStatus); + $this->logger->expects(self::once()) + ->method('debug'); + $this->userStatusService->expects(self::never()) + ->method('revertUserStatus'); + $this->userStatusService->expects(self::never()) + ->method('setUserStatus'); + + + $this->service->processCalendarStatus('admin'); } - public function testSearchCalendarsNoResults(): void { + public function testDNDStatus(): void { $user = $this->createConfiguredMock(IUser::class, [ 'getUID' => 'admin', - 'getEMailAddress' => 'test@test.com', ]); - $server = $this->createMock(Server::class); - $schedulingPlugin = $this->createMock(Plugin::class); - $aclPlugin = $this->createMock(\Sabre\DAVACL\Plugin::class); - $calendarHome = $this->createMock(LocalHref::class); - $acl = [[200 => ['{urn:ietf:params:xml:ns:caldav}schedule-inbox-URL' => $calendarHome]]]; - $now = new \DateTimeImmutable('1970-1-1 00:00', new \DateTimeZone('UTC')); - $inTenMinutes = new \DateTime('1970-1-1 01:00'); - $immutableInTenMinutes = \DateTimeImmutable::createFromMutable($inTenMinutes); - $principal = 'principals/users/admin'; - $query = $this->createMock(CalendarQuery::class); - $timezone = new \DateTimeZone('UTC'); - $timezoneObj = $this->createMock(VTimeZone::class); - $calendar = $this->createMock(CalendarImpl::class); - $vCalendar = $this->createMock(VCalendar::class); - $result = Reader::read('BEGIN:VCALENDAR -VERSION:2.0 -PRODID:-//Sabre//Sabre VObject 4.5.3//EN - CALSCALE:GREGORIAN -METHOD:REQUEST -END:VCALENDAR'); - - $user->expects(self::once()) - ->method('getUID') - ->willReturn('admin'); - $user->expects(self::once()) - ->method('getEMailAddress') - ->willReturn('test@test.com'); - $this->server->expects(self::once()) - ->method('getServer') - ->willReturn($server); - $server->expects(self::exactly(2)) - ->method('getPlugin') - ->withConsecutive( - ['caldav-schedule'], - ['acl'], - )->willReturnOnConsecutiveCalls($schedulingPlugin, $aclPlugin); - $aclPlugin->expects(self::once()) - ->method('principalSearch') - ->with(['{http://sabredav.org/ns}email-address' => 'test@test.com']) - ->willReturn($acl); - $calendarHome->expects(self::once()) - ->method('getHref') - ->willReturn('calendars/admin/inbox/'); - $aclPlugin->expects(self::once()) - ->method('checkPrivileges') - ->willReturn(true); - $this->timeFactory->expects(self::once()) - ->method('now') - ->willReturn($now); + + $this->userManager->expects(self::once()) + ->method('get') + ->willReturn($user); + $this->availabilityCoordinator->expects(self::once()) + ->method('getCurrentOutOfOfficeData') + ->willReturn(null); + $this->availabilityCoordinator->expects(self::never()) + ->method('isInEffect'); + $this->cache->expects(self::once()) + ->method('get') + ->willReturn(null); + $this->cache->expects(self::once()) + ->method('set'); $this->calendarManager->expects(self::once()) ->method('getCalendarsForPrincipal') - ->with($principal) - ->willReturn([$calendar]); + ->willReturn([$this->createMock(CalendarImpl::class)]); $this->calendarManager->expects(self::once()) ->method('newQuery') - ->with($principal) - ->willReturn($query); - $calendar->expects(self::once()) - ->method('getSchedulingTransparency') - ->willReturn(new ScheduleCalendarTransp('opaque')); - $calendar->expects(self::once()) - ->method('getSchedulingTimezone') - ->willReturn($timezoneObj); - $timezoneObj->expects(self::once()) - ->method('getTimeZone') - ->willReturn($timezone); - $calendar->expects(self::once()) - ->method('getUri'); - $query->expects(self::once()) - ->method('addSearchCalendar'); - $query->expects(self::once()) - ->method('getCalendarUris') - ->willReturn([$calendar]); - $this->timeFactory->expects(self::once()) + ->willReturn(new CalendarQuery('admin')); + $this->timeFactory->expects(self::exactly(2)) ->method('getDateTime') - ->with('+10 minutes') - ->willReturn($inTenMinutes); - $query->expects(self::once()) - ->method('setTimerangeStart') - ->with($now); - $query->expects(self::once()) - ->method('setTimerangeEnd') - ->with($immutableInTenMinutes); + ->willReturn(new \DateTime()); $this->calendarManager->expects(self::once()) ->method('searchForPrincipal') - ->with($query) - ->willReturn([]); - $this->generator->expects(self::never()) - ->method('getVCalendar'); - $vCalendar->expects(self::never()) - ->method('add'); - $this->generator->expects(self::never()) - ->method('setObjects'); - $this->generator->expects(self::never()) - ->method('setTimeRange'); - $this->generator->expects(self::never()) - ->method('setTimeZone'); - $this->generator->expects(self::never()) - ->method('getResult'); - - $status = $this->service->processCalendarAvailability($user); - $this->assertNull($status); + ->willReturn([['objects' => [[]]]]); + $userStatus = new UserStatus(); + $userStatus->setStatus(IUserStatus::DND); + $userStatus->setStatusTimestamp(123456); + $this->userStatusService->expects(self::once()) + ->method('findByUserId') + ->willReturn($userStatus); + $this->logger->expects(self::once()) + ->method('debug'); + $this->userStatusService->expects(self::never()) + ->method('revertUserStatus'); + $this->userStatusService->expects(self::never()) + ->method('setUserStatus'); + + + $this->service->processCalendarStatus('admin'); } } |