fix: iMip reply from outlook.com does not contain organizer property

Signed-off-by: SebastianKrupinski <krupinskis05@gmail.com>
pull/55764/head
SebastianKrupinski 2025-09-02 12:09:30 +07:00
parent bd9aa595e9
commit 9648a3f37e
2 changed files with 88 additions and 5 deletions

@ -227,6 +227,7 @@ class Manager implements IManager {
protected function handleIMip(
string $userId,
string $message,
array $options = [],
): bool {
$userUri = 'principals/users/' . $userId;
@ -258,8 +259,13 @@ class Manager implements IManager {
}
if (!isset($vEvent->ORGANIZER)) {
$this->logger->warning('iMip message event dose not contains an organizer');
return false;
// quirks mode: for Microsoft Exchange Servers use recipient as organizer if no organizer is set
if (isset($options['recipient']) && $options['recipient'] !== '') {
$vEvent->add('ORGANIZER', 'mailto:' . $options['recipient']);
} else {
$this->logger->warning('iMip message event does not contain an organizer and no recipient was provided');
return false;
}
}
if (!isset($vEvent->ATTENDEE)) {
@ -308,7 +314,8 @@ class Manager implements IManager {
return false;
}
$userId = substr($principalUri, 17);
return $this->handleIMip($userId, $calendarData);
$options = ['recipient' => $recipient];
return $this->handleIMip($userId, $calendarData, $options);
}
/**
@ -327,7 +334,8 @@ class Manager implements IManager {
return false;
}
$userId = substr($principalUri, 17);
return $this->handleIMip($userId, $calendarData);
$options = ['recipient' => $recipient];
return $this->handleIMip($userId, $calendarData, $options);
}
/**
@ -347,7 +355,8 @@ class Manager implements IManager {
return false;
}
$userId = substr($principalUri, 17);
return $this->handleIMip($userId, $calendarData);
$options = ['recipient' => $recipient];
return $this->handleIMip($userId, $calendarData, $options);
}
public function createEventBuilder(): ICalendarEventBuilder {

@ -382,6 +382,80 @@ class ManagerTest extends TestCase {
$this->assertFalse($result);
}
public function testHandleImipMissingOrganizerWithRecipient(): void {
// construct mock user calendar
$userCalendar = $this->createMock(ITestCalendar::class);
$userCalendar->expects(self::once())
->method('isDeleted')
->willReturn(false);
$userCalendar->expects(self::once())
->method('isWritable')
->willReturn(true);
$userCalendar->expects(self::once())
->method('search')
->willReturn([['uri' => 'principals/user/attendee1/personal']]);
// construct mock calendar manager and returns
/** @var Manager&MockObject $manager */
$manager = $this->getMockBuilder(Manager::class)
->setConstructorArgs([
$this->coordinator,
$this->container,
$this->logger,
$this->time,
$this->secureRandom,
$this->userManager,
$this->serverFactory,
])
->onlyMethods(['getCalendarsForPrincipal'])
->getMock();
$manager->expects(self::once())
->method('getCalendarsForPrincipal')
->willReturn([$userCalendar]);
// construct parameters
$userId = 'attendee1';
$calendar = $this->vCalendar1a;
$calendar->add('METHOD', 'REQUEST');
$calendar->VEVENT->remove('ORGANIZER');
// construct user calendar returns
$userCalendar->expects(self::once())
->method('handleIMipMessage');
// test method
$result = $this->invokePrivate($manager, 'handleIMip', [$userId, $calendar->serialize(), ['recipient' => 'organizer@testing.com']]);
}
public function testHandleImipMissingOrganizerNoRecipient(): void {
// construct mock user calendar
$userCalendar = $this->createMock(ITestCalendar::class);
// construct mock calendar manager and returns
/** @var Manager&MockObject $manager */
$manager = $this->getMockBuilder(Manager::class)
->setConstructorArgs([
$this->coordinator,
$this->container,
$this->logger,
$this->time,
$this->secureRandom,
$this->userManager,
$this->serverFactory,
])
->onlyMethods(['getCalendarsForPrincipal'])
->getMock();
$manager->expects(self::once())
->method('getCalendarsForPrincipal')
->willReturn([$userCalendar]);
// construct parameters
$userId = 'attendee1';
$calendar = $this->vCalendar1a;
$calendar->add('METHOD', 'REQUEST');
$calendar->VEVENT->remove('ORGANIZER');
// Logger expects warning
$this->logger->expects($this->once())
->method('warning')
->with('iMip message event does not contain an organizer and no recipient was provided');
$result = $this->invokePrivate($manager, 'handleIMip', [$userId, $calendar->serialize(), []]);
}
public function testHandleImipWithNoUid(): void {
// construct mock user calendar
$userCalendar = $this->createMock(ITestCalendar::class);