| @@ -15,177 +15,177 @@ | ||
| 15 | 15 | |
| 16 | 16 |  class TipBroker extends Broker { | 
| 17 | 17 | |
| 18 | - public $significantChangeProperties = [ | |
| 19 | - 'DTSTART', | |
| 20 | - 'DTEND', | |
| 21 | - 'DURATION', | |
| 22 | - 'DUE', | |
| 23 | - 'RRULE', | |
| 24 | - 'RDATE', | |
| 25 | - 'EXDATE', | |
| 26 | - 'STATUS', | |
| 27 | - 'SUMMARY', | |
| 28 | - 'DESCRIPTION', | |
| 29 | - 'LOCATION', | |
| 30 | - | |
| 31 | - ]; | |
| 32 | - | |
| 33 | - /** | |
| 34 | - * This method is used in cases where an event got updated, and we | |
| 35 | - * potentially need to send emails to attendees to let them know of updates | |
| 36 | - * in the events. | |
| 37 | - * | |
| 38 | - * We will detect which attendees got added, which got removed and create | |
| 39 | - * specific messages for these situations. | |
| 40 | - * | |
| 41 | - * @return array | |
| 42 | - */ | |
| 43 | -	protected function parseEventForOrganizer(VCalendar $calendar, array $eventInfo, array $oldEventInfo) { | |
| 44 | - // Merging attendee lists. | |
| 45 | - $attendees = []; | |
| 46 | -		foreach ($oldEventInfo['attendees'] as $attendee) { | |
| 47 | - $attendees[$attendee['href']] = [ | |
| 48 | - 'href' => $attendee['href'], | |
| 49 | - 'oldInstances' => $attendee['instances'], | |
| 50 | - 'newInstances' => [], | |
| 51 | - 'name' => $attendee['name'], | |
| 52 | - 'forceSend' => null, | |
| 53 | - ]; | |
| 54 | - } | |
| 55 | -		foreach ($eventInfo['attendees'] as $attendee) { | |
| 56 | -			if (isset($attendees[$attendee['href']])) { | |
| 57 | - $attendees[$attendee['href']]['name'] = $attendee['name']; | |
| 58 | - $attendees[$attendee['href']]['newInstances'] = $attendee['instances']; | |
| 59 | - $attendees[$attendee['href']]['forceSend'] = $attendee['forceSend']; | |
| 60 | -			} else { | |
| 61 | - $attendees[$attendee['href']] = [ | |
| 62 | - 'href' => $attendee['href'], | |
| 63 | - 'oldInstances' => [], | |
| 64 | - 'newInstances' => $attendee['instances'], | |
| 65 | - 'name' => $attendee['name'], | |
| 66 | - 'forceSend' => $attendee['forceSend'], | |
| 67 | - ]; | |
| 68 | - } | |
| 69 | - } | |
| 70 | - | |
| 71 | - $messages = []; | |
| 72 | - | |
| 73 | -		foreach ($attendees as $attendee) { | |
| 74 | - // An organizer can also be an attendee. We should not generate any | |
| 75 | - // messages for those. | |
| 76 | -			if ($attendee['href'] === $eventInfo['organizer']) { | |
| 77 | - continue; | |
| 78 | - } | |
| 79 | - | |
| 80 | - $message = new Message(); | |
| 81 | - $message->uid = $eventInfo['uid']; | |
| 82 | - $message->component = 'VEVENT'; | |
| 83 | - $message->sequence = $eventInfo['sequence']; | |
| 84 | - $message->sender = $eventInfo['organizer']; | |
| 85 | - $message->senderName = $eventInfo['organizerName']; | |
| 86 | - $message->recipient = $attendee['href']; | |
| 87 | - $message->recipientName = $attendee['name']; | |
| 88 | - | |
| 89 | - // Creating the new iCalendar body. | |
| 90 | - $icalMsg = new VCalendar(); | |
| 91 | - | |
| 92 | -			foreach ($calendar->select('VTIMEZONE') as $timezone) { | |
| 93 | - $icalMsg->add(clone $timezone); | |
| 94 | - } | |
| 95 | - // If there are no instances the attendee is a part of, it means | |
| 96 | - // the attendee was removed and we need to send them a CANCEL message. | |
| 97 | - // Also If the meeting STATUS property was changed to CANCELLED | |
| 98 | - // we need to send the attendee a CANCEL message. | |
| 99 | -			if (!$attendee['newInstances'] || $eventInfo['status'] === 'CANCELLED') { | |
| 100 | - | |
| 101 | - $message->method = $icalMsg->METHOD = 'CANCEL'; | |
| 102 | - $message->significantChange = true; | |
| 103 | - // clone base event | |
| 104 | -				if (isset($eventInfo['instances']['master'])) { | |
| 105 | - $event = clone $eventInfo['instances']['master']; | |
| 106 | -				} else { | |
| 107 | - $event = clone $oldEventInfo['instances']['master']; | |
| 108 | - } | |
| 109 | - // alter some properties | |
| 110 | - unset($event->ATTENDEE); | |
| 111 | -				$event->add('ATTENDEE', $attendee['href'], ['CN' => $attendee['name'],]); | |
| 112 | -				$event->DTSTAMP = gmdate('Ymd\\THis\\Z'); | |
| 113 | - $event->SEQUENCE = $message->sequence; | |
| 114 | - $icalMsg->add($event); | |
| 115 | - | |
| 116 | -			} else { | |
| 117 | - // The attendee gets the updated event body | |
| 118 | - $message->method = $icalMsg->METHOD = 'REQUEST'; | |
| 119 | - | |
| 120 | - // We need to find out that this change is significant. If it's | |
| 121 | - // not, systems may opt to not send messages. | |
| 122 | - // | |
| 123 | - // We do this based on the 'significantChangeHash' which is | |
| 124 | - // some value that changes if there's a certain set of | |
| 125 | - // properties changed in the event, or simply if there's a | |
| 126 | - // difference in instances that the attendee is invited to. | |
| 127 | - | |
| 128 | - $oldAttendeeInstances = array_keys($attendee['oldInstances']); | |
| 129 | - $newAttendeeInstances = array_keys($attendee['newInstances']); | |
| 130 | - | |
| 131 | - $message->significantChange | |
| 132 | - = $attendee['forceSend'] === 'REQUEST' | |
| 133 | - || count($oldAttendeeInstances) !== count($newAttendeeInstances) | |
| 134 | - || count(array_diff($oldAttendeeInstances, $newAttendeeInstances)) > 0 | |
| 135 | - || $oldEventInfo['significantChangeHash'] !== $eventInfo['significantChangeHash']; | |
| 136 | - | |
| 137 | -				foreach ($attendee['newInstances'] as $instanceId => $instanceInfo) { | |
| 138 | - $currentEvent = clone $eventInfo['instances'][$instanceId]; | |
| 139 | -					if ($instanceId === 'master') { | |
| 140 | - // We need to find a list of events that the attendee | |
| 141 | - // is not a part of to add to the list of exceptions. | |
| 142 | - $exceptions = []; | |
| 143 | -						foreach ($eventInfo['instances'] as $instanceId => $vevent) { | |
| 144 | -							if (!isset($attendee['newInstances'][$instanceId])) { | |
| 145 | - $exceptions[] = $instanceId; | |
| 146 | - } | |
| 147 | - } | |
| 148 | - | |
| 149 | - // If there were exceptions, we need to add it to an | |
| 150 | - // existing EXDATE property, if it exists. | |
| 151 | -						if ($exceptions) { | |
| 152 | -							if (isset($currentEvent->EXDATE)) { | |
| 153 | - $currentEvent->EXDATE->setParts(array_merge( | |
| 154 | - $currentEvent->EXDATE->getParts(), | |
| 155 | - $exceptions | |
| 156 | - )); | |
| 157 | -							} else { | |
| 158 | - $currentEvent->EXDATE = $exceptions; | |
| 159 | - } | |
| 160 | - } | |
| 161 | - | |
| 162 | - // Cleaning up any scheduling information that | |
| 163 | - // shouldn't be sent along. | |
| 164 | - unset($currentEvent->ORGANIZER['SCHEDULE-FORCE-SEND']); | |
| 165 | - unset($currentEvent->ORGANIZER['SCHEDULE-STATUS']); | |
| 166 | - | |
| 167 | -						foreach ($currentEvent->ATTENDEE as $attendee) { | |
| 168 | - unset($attendee['SCHEDULE-FORCE-SEND']); | |
| 169 | - unset($attendee['SCHEDULE-STATUS']); | |
| 170 | - | |
| 171 | - // We're adding PARTSTAT=NEEDS-ACTION to ensure that | |
| 172 | - // iOS shows an "Inbox Item" | |
| 173 | -							if (!isset($attendee['PARTSTAT'])) { | |
| 174 | - $attendee['PARTSTAT'] = 'NEEDS-ACTION'; | |
| 175 | - } | |
| 176 | - } | |
| 177 | - } | |
| 178 | - | |
| 179 | -					$currentEvent->DTSTAMP = gmdate('Ymd\\THis\\Z'); | |
| 180 | - $icalMsg->add($currentEvent); | |
| 181 | - } | |
| 182 | - } | |
| 183 | - | |
| 184 | - $message->message = $icalMsg; | |
| 185 | - $messages[] = $message; | |
| 186 | - } | |
| 187 | - | |
| 188 | - return $messages; | |
| 189 | - } | |
| 18 | + public $significantChangeProperties = [ | |
| 19 | + 'DTSTART', | |
| 20 | + 'DTEND', | |
| 21 | + 'DURATION', | |
| 22 | + 'DUE', | |
| 23 | + 'RRULE', | |
| 24 | + 'RDATE', | |
| 25 | + 'EXDATE', | |
| 26 | + 'STATUS', | |
| 27 | + 'SUMMARY', | |
| 28 | + 'DESCRIPTION', | |
| 29 | + 'LOCATION', | |
| 30 | + | |
| 31 | + ]; | |
| 32 | + | |
| 33 | + /** | |
| 34 | + * This method is used in cases where an event got updated, and we | |
| 35 | + * potentially need to send emails to attendees to let them know of updates | |
| 36 | + * in the events. | |
| 37 | + * | |
| 38 | + * We will detect which attendees got added, which got removed and create | |
| 39 | + * specific messages for these situations. | |
| 40 | + * | |
| 41 | + * @return array | |
| 42 | + */ | |
| 43 | +    protected function parseEventForOrganizer(VCalendar $calendar, array $eventInfo, array $oldEventInfo) { | |
| 44 | + // Merging attendee lists. | |
| 45 | + $attendees = []; | |
| 46 | +        foreach ($oldEventInfo['attendees'] as $attendee) { | |
| 47 | + $attendees[$attendee['href']] = [ | |
| 48 | + 'href' => $attendee['href'], | |
| 49 | + 'oldInstances' => $attendee['instances'], | |
| 50 | + 'newInstances' => [], | |
| 51 | + 'name' => $attendee['name'], | |
| 52 | + 'forceSend' => null, | |
| 53 | + ]; | |
| 54 | + } | |
| 55 | +        foreach ($eventInfo['attendees'] as $attendee) { | |
| 56 | +            if (isset($attendees[$attendee['href']])) { | |
| 57 | + $attendees[$attendee['href']]['name'] = $attendee['name']; | |
| 58 | + $attendees[$attendee['href']]['newInstances'] = $attendee['instances']; | |
| 59 | + $attendees[$attendee['href']]['forceSend'] = $attendee['forceSend']; | |
| 60 | +            } else { | |
| 61 | + $attendees[$attendee['href']] = [ | |
| 62 | + 'href' => $attendee['href'], | |
| 63 | + 'oldInstances' => [], | |
| 64 | + 'newInstances' => $attendee['instances'], | |
| 65 | + 'name' => $attendee['name'], | |
| 66 | + 'forceSend' => $attendee['forceSend'], | |
| 67 | + ]; | |
| 68 | + } | |
| 69 | + } | |
| 70 | + | |
| 71 | + $messages = []; | |
| 72 | + | |
| 73 | +        foreach ($attendees as $attendee) { | |
| 74 | + // An organizer can also be an attendee. We should not generate any | |
| 75 | + // messages for those. | |
| 76 | +            if ($attendee['href'] === $eventInfo['organizer']) { | |
| 77 | + continue; | |
| 78 | + } | |
| 79 | + | |
| 80 | + $message = new Message(); | |
| 81 | + $message->uid = $eventInfo['uid']; | |
| 82 | + $message->component = 'VEVENT'; | |
| 83 | + $message->sequence = $eventInfo['sequence']; | |
| 84 | + $message->sender = $eventInfo['organizer']; | |
| 85 | + $message->senderName = $eventInfo['organizerName']; | |
| 86 | + $message->recipient = $attendee['href']; | |
| 87 | + $message->recipientName = $attendee['name']; | |
| 88 | + | |
| 89 | + // Creating the new iCalendar body. | |
| 90 | + $icalMsg = new VCalendar(); | |
| 91 | + | |
| 92 | +            foreach ($calendar->select('VTIMEZONE') as $timezone) { | |
| 93 | + $icalMsg->add(clone $timezone); | |
| 94 | + } | |
| 95 | + // If there are no instances the attendee is a part of, it means | |
| 96 | + // the attendee was removed and we need to send them a CANCEL message. | |
| 97 | + // Also If the meeting STATUS property was changed to CANCELLED | |
| 98 | + // we need to send the attendee a CANCEL message. | |
| 99 | +            if (!$attendee['newInstances'] || $eventInfo['status'] === 'CANCELLED') { | |
| 100 | + | |
| 101 | + $message->method = $icalMsg->METHOD = 'CANCEL'; | |
| 102 | + $message->significantChange = true; | |
| 103 | + // clone base event | |
| 104 | +                if (isset($eventInfo['instances']['master'])) { | |
| 105 | + $event = clone $eventInfo['instances']['master']; | |
| 106 | +                } else { | |
| 107 | + $event = clone $oldEventInfo['instances']['master']; | |
| 108 | + } | |
| 109 | + // alter some properties | |
| 110 | + unset($event->ATTENDEE); | |
| 111 | +                $event->add('ATTENDEE', $attendee['href'], ['CN' => $attendee['name'],]); | |
| 112 | +                $event->DTSTAMP = gmdate('Ymd\\THis\\Z'); | |
| 113 | + $event->SEQUENCE = $message->sequence; | |
| 114 | + $icalMsg->add($event); | |
| 115 | + | |
| 116 | +            } else { | |
| 117 | + // The attendee gets the updated event body | |
| 118 | + $message->method = $icalMsg->METHOD = 'REQUEST'; | |
| 119 | + | |
| 120 | + // We need to find out that this change is significant. If it's | |
| 121 | + // not, systems may opt to not send messages. | |
| 122 | + // | |
| 123 | + // We do this based on the 'significantChangeHash' which is | |
| 124 | + // some value that changes if there's a certain set of | |
| 125 | + // properties changed in the event, or simply if there's a | |
| 126 | + // difference in instances that the attendee is invited to. | |
| 127 | + | |
| 128 | + $oldAttendeeInstances = array_keys($attendee['oldInstances']); | |
| 129 | + $newAttendeeInstances = array_keys($attendee['newInstances']); | |
| 130 | + | |
| 131 | + $message->significantChange | |
| 132 | + = $attendee['forceSend'] === 'REQUEST' | |
| 133 | + || count($oldAttendeeInstances) !== count($newAttendeeInstances) | |
| 134 | + || count(array_diff($oldAttendeeInstances, $newAttendeeInstances)) > 0 | |
| 135 | + || $oldEventInfo['significantChangeHash'] !== $eventInfo['significantChangeHash']; | |
| 136 | + | |
| 137 | +                foreach ($attendee['newInstances'] as $instanceId => $instanceInfo) { | |
| 138 | + $currentEvent = clone $eventInfo['instances'][$instanceId]; | |
| 139 | +                    if ($instanceId === 'master') { | |
| 140 | + // We need to find a list of events that the attendee | |
| 141 | + // is not a part of to add to the list of exceptions. | |
| 142 | + $exceptions = []; | |
| 143 | +                        foreach ($eventInfo['instances'] as $instanceId => $vevent) { | |
| 144 | +                            if (!isset($attendee['newInstances'][$instanceId])) { | |
| 145 | + $exceptions[] = $instanceId; | |
| 146 | + } | |
| 147 | + } | |
| 148 | + | |
| 149 | + // If there were exceptions, we need to add it to an | |
| 150 | + // existing EXDATE property, if it exists. | |
| 151 | +                        if ($exceptions) { | |
| 152 | +                            if (isset($currentEvent->EXDATE)) { | |
| 153 | + $currentEvent->EXDATE->setParts(array_merge( | |
| 154 | + $currentEvent->EXDATE->getParts(), | |
| 155 | + $exceptions | |
| 156 | + )); | |
| 157 | +                            } else { | |
| 158 | + $currentEvent->EXDATE = $exceptions; | |
| 159 | + } | |
| 160 | + } | |
| 161 | + | |
| 162 | + // Cleaning up any scheduling information that | |
| 163 | + // shouldn't be sent along. | |
| 164 | + unset($currentEvent->ORGANIZER['SCHEDULE-FORCE-SEND']); | |
| 165 | + unset($currentEvent->ORGANIZER['SCHEDULE-STATUS']); | |
| 166 | + | |
| 167 | +                        foreach ($currentEvent->ATTENDEE as $attendee) { | |
| 168 | + unset($attendee['SCHEDULE-FORCE-SEND']); | |
| 169 | + unset($attendee['SCHEDULE-STATUS']); | |
| 170 | + | |
| 171 | + // We're adding PARTSTAT=NEEDS-ACTION to ensure that | |
| 172 | + // iOS shows an "Inbox Item" | |
| 173 | +                            if (!isset($attendee['PARTSTAT'])) { | |
| 174 | + $attendee['PARTSTAT'] = 'NEEDS-ACTION'; | |
| 175 | + } | |
| 176 | + } | |
| 177 | + } | |
| 178 | + | |
| 179 | +                    $currentEvent->DTSTAMP = gmdate('Ymd\\THis\\Z'); | |
| 180 | + $icalMsg->add($currentEvent); | |
| 181 | + } | |
| 182 | + } | |
| 183 | + | |
| 184 | + $message->message = $icalMsg; | |
| 185 | + $messages[] = $message; | |
| 186 | + } | |
| 187 | + | |
| 188 | + return $messages; | |
| 189 | + } | |
| 190 | 190 | |
| 191 | 191 | } | 
| @@ -108,7 +108,7 @@ | ||
| 108 | 108 | } | 
| 109 | 109 | // alter some properties | 
| 110 | 110 | unset($event->ATTENDEE); | 
| 111 | -				$event->add('ATTENDEE', $attendee['href'], ['CN' => $attendee['name'],]); | |
| 111 | +				$event->add('ATTENDEE', $attendee['href'], ['CN' => $attendee['name'], ]); | |
| 112 | 112 |  				$event->DTSTAMP = gmdate('Ymd\\THis\\Z'); | 
| 113 | 113 | $event->SEQUENCE = $message->sequence; | 
| 114 | 114 | $icalMsg->add($event); |