Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions lib/Service/Proposal/ProposalService.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use OCA\Calendar\Objects\Proposal\ProposalObject;
use OCA\Calendar\Objects\Proposal\ProposalParticipantCollection;
use OCA\Calendar\Objects\Proposal\ProposalParticipantObject;
use OCA\Calendar\Objects\Proposal\ProposalParticipantRealm;
use OCA\Calendar\Objects\Proposal\ProposalParticipantStatus;
use OCA\Calendar\Objects\Proposal\ProposalResponseObject;
use OCA\Calendar\Objects\Proposal\ProposalVoteCollection;
Expand All @@ -35,6 +36,7 @@
use OCP\Mail\Provider\IMessageSend;
use Psr\Log\LoggerInterface;
use Sabre\VObject\Component\VCalendar;
use Sabre\VObject\Component\VEvent;
use Symfony\Component\Uid\Uuid;

class ProposalService {
Expand Down Expand Up @@ -193,6 +195,9 @@ public function createProposal(IUser $user, ProposalObject $proposal): ProposalO
// generate notifications for internal and external participants
$this->generateNotifications($user, $proposal, 'C');

// generate iTip for internal participants
$this->generateIMip($user, $proposal, 'C');

return $proposal;
}

Expand Down Expand Up @@ -257,6 +262,9 @@ public function modifyProposal(IUser $user, ProposalObject $mutatedProposal): Pr
// generate notifications for internal and external participants
$this->generateNotifications($user, $proposal, 'M');

// generate iTip for internal participants
$this->generateIMip($user, $proposal, 'M');

return $proposal;
}

Expand All @@ -277,6 +285,9 @@ public function destroyProposal(IUser $user, int $identifier): void {

// generate notifications for internal and external participants
$this->generateNotifications($user, $proposal, 'D');

// generate iTip for internal participants
$this->generateIMip($user, $proposal, 'D');
}

/**
Expand Down Expand Up @@ -548,4 +559,70 @@ private function sendEmailNotifications(IUser $user, ProposalObject $proposal, P
}

}

private function generateIMip(IUser $user, ProposalObject $proposal, string $reason): void {
// if the calendar manager does not have a handleIMip method, we cannot generate iTip messages
if (!method_exists($this->calendarManager, 'handleIMip')) {
return;
}
// if the proposal has no dates or participants, we cannot generate any iTip messages
if ($proposal->getDates()->count() === 0 || $proposal->getParticipants()->count() === 0) {
return;
}
// construct calendar object with events
$template = new VCalendar();
// TODO: change REQUEST to PUBLISH
$template->add('METHOD', $reason !== 'D' ? 'REQUEST' : 'CANCEL');
// create a event for each date in the proposal
// TODO: should we create a new instance for each date or use a recurrence rule? Like RDATE:19970714T083000Z,19970715T083000Z
foreach ($proposal->getDates()->sortByDate() as $proposalDate) {
/** @var VEvent $vEvent */
$vEvent = $template->add('VEVENT', []);
if (isset($baseDate)) {
$vEvent->add('RECURRENCE-ID', $baseDate->getDate()->format('Ymd\THis\Z'));
} else {
$baseDate = $proposalDate;
}
$vEvent->UID->setValue($proposal->getUuid());
$vEvent->add('STATUS', 'TENTATIVE');
$vEvent->add('SEQUENCE', 1);
$vEvent->add('DTSTART', $proposalDate->getDate());
$vEvent->add('DURATION', "PT{$proposal->getDuration()}M");
$vEvent->add('SUMMARY', $proposal->getTitle());
$vEvent->add('DESCRIPTION', $proposal->getDescription());
$vEvent->add('ORGANIZER', 'mailto:' . $user->getEMailAddress(), ['CN' => $user->getDisplayName()]);
// add the participant to the event
foreach ($proposal->getParticipants() as $participant) {
$vEvent->add('ATTENDEE', 'mailto:' . $participant->getAddress(), [
'CN' => $participant->getName(),
'CUTYPE' => 'INDIVIDUAL',
'PARTSTAT' => 'NEEDS-ACTION',
'ROLE' => 'REQ-PARTICIPANT'
]);
}
}

foreach ($proposal->getParticipants()->filterByRealm(ProposalParticipantRealm::Internal) as $participant) {
// TODO: this is stupid, we send the internal users email address from the UI then convert it back to a user name
// should probably be sent from the UI as a user name, or send and store both the user name and email address
// maybe send the address as a special schema "local:{user name}/{email address}", this would allow us to later extend this to federated users
// with a different special schema like "federated:{user name}@{server}/{email address}"
$participantUsers = $this->userManager->getByEmail($participant->getAddress());
if ($participantUsers === []) {
continue;
}
$participantUser = $participantUsers[0];
try {
$this->calendarManager->handleIMip(
$participantUser->getUID(),
$template->serialize(),
$reason !== 'D' ? ['absent' => 'create'] : []
);
} catch (Exception $e) {
$this->logger->error($e->getMessage(), ['app' => 'calendar', 'exception' => $e]);
}
}

}

}
Loading