Class: Tilia::VObject::ITip::Broker
- Inherits:
-
Object
- Object
- Tilia::VObject::ITip::Broker
- Defined in:
- lib/tilia/v_object/i_tip/broker.rb
Overview
The ITipBroker class is a utility class that helps with processing so-called iTip messages.
iTip is defined in rfc5546, stands for iCalendar Transport-Independent Interoperability Protocol, and describes the underlying mechanism for using iCalendar for scheduling for for example through email (also known as IMip) and CalDAV Scheduling.
This class helps by:
-
Creating individual invites based on an iCalendar event for each attendee.
-
Generating invite updates based on an iCalendar update. This may result in new invites, updates and cancellations for attendees, if that list changed.
-
On the receiving end, it can create a local iCalendar event based on a received invite.
-
It can also process an invite update on a local event, ensuring that any overridden properties from attendees are retained.
-
It can create a accepted or declined iTip reply based on an invite.
-
It can process a reply from an invite and update an events attendee
status based on a reply.
Instance Attribute Summary collapse
-
#schedule_agent_server_rules ⇒ Boolean
This setting determines whether the rules for the SCHEDULE-AGENT parameter should be followed.
-
#significant_change_properties ⇒ Array<String>
The broker will try during ‘parseEvent’ figure out whether the change was significant.
Instance Method Summary collapse
-
#initialize ⇒ Broker
constructor
Sets instance variables.
-
#parse_event(calendar, user_href, old_calendar = nil) ⇒ Array
This function parses a VCALENDAR object and figure out if any messages need to be sent.
-
#process_message(itip_message, existing_object = nil) ⇒ VCalendar?
This method is used to process an incoming itip message.
Constructor Details
#initialize ⇒ Broker
Sets instance variables
911 912 913 914 915 916 917 918 919 920 921 922 923 |
# File 'lib/tilia/v_object/i_tip/broker.rb', line 911 def initialize @schedule_agent_server_rules = true @significant_change_properties = [ 'DTSTART', 'DTEND', 'DURATION', 'DUE', 'RRULE', 'RDATE', 'EXDATE', 'STATUS' ] end |
Instance Attribute Details
#schedule_agent_server_rules ⇒ Boolean
This setting determines whether the rules for the SCHEDULE-AGENT parameter should be followed.
This is a parameter defined on ATTENDEE properties, introduced by RFC
-
This parameter allows a caldav client to tell the server ‘Don’t do
any scheduling operations’.
If this setting is turned on, any attendees with SCHEDULE-AGENT set to CLIENT will be ignored. This is the desired behavior for a CalDAV server, but if you’re writing an iTip application that doesn’t deal with CalDAV, you may want to ignore this parameter.
41 42 43 |
# File 'lib/tilia/v_object/i_tip/broker.rb', line 41 def schedule_agent_server_rules @schedule_agent_server_rules end |
#significant_change_properties ⇒ Array<String>
The broker will try during ‘parseEvent’ figure out whether the change was significant.
It uses a few different ways to do this. One of these ways is seeing if certain properties changed values. This list of specified here.
This list is taken from:
53 54 55 |
# File 'lib/tilia/v_object/i_tip/broker.rb', line 53 def significant_change_properties @significant_change_properties end |
Instance Method Details
#parse_event(calendar, user_href, old_calendar = nil) ⇒ Array
This function parses a VCALENDAR object and figure out if any messages need to be sent.
A VCALENDAR object will be created from the perspective of either an attendee, or an organizer. You must pass a string identifying the current user, so we can figure out who in the list of attendees or the organizer we are sending this message on behalf of.
It’s possible to specify the current user as an array, in case the user has more than one identifying href (such as multiple emails).
It old_calendar is specified, it is assumed that the operation is updating an existing event, which means that we need to look at the differences between events, and potentially send old attendees cancellations, and current attendees updates.
If calendar is null, but old_calendar is specified, we treat the operation as if the user has deleted an event. If the user was an organizer, this means that we need to send cancellation notices to people. If the user was an attendee, we need to make sure that the organizer gets the ‘declined’ message.
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 |
# File 'lib/tilia/v_object/i_tip/broker.rb', line 126 def parse_event(calendar, user_href, old_calendar = nil) if old_calendar if old_calendar.is_a?(String) old_calendar = Tilia::VObject::Reader.read(old_calendar) end unless old_calendar.key?('VEVENT') # We only support events at the moment return [] end old_event_info = parse_event_info(old_calendar) else old_event_info = { 'organizer' => nil, 'significant_change_hash' => '', 'attendees' => {} } end user_href = [user_href] unless user_href.is_a?(Array) if calendar if calendar.is_a?(String) calendar = Tilia::VObject::Reader.read(calendar) end unless calendar.key?('VEVENT') # We only support events at the moment return [] end event_info = parse_event_info(calendar) if (!event_info['attendees'] || event_info['attendees'].empty?) && (!old_event_info['attendees'] || old_event_info['attendees'].empty?) # If there were no attendees on either side of the equation, # we don't need to do anything. return [] end if event_info['organizer'].blank? && old_event_info['organizer'].blank? # There was no organizer before or after the change. return [] end base_calendar = calendar # If the new object didn't have an organizer, the organizer # changed the object from a scheduling object to a non-scheduling # object. We just copy the info from the old object. if event_info['organizer'].blank? && !old_event_info['organizer'].blank? event_info['organizer'] = old_event_info['organizer'] event_info['organizer_name'] = old_event_info['organizer_name'] end else # The calendar object got deleted, we need to process this as a # cancellation / decline. unless old_calendar # No old and no new calendar, there's no thing to do. return [] end event_info = old_event_info.deep_dup if user_href.include?(event_info['organizer']) # This is an organizer deleting the event. event_info['attendees'] = {} # Increasing the sequence, but only if the organizer deleted # the event. event_info['sequence'] = event_info['sequence'].to_i + 1 else # This is an attendee deleting the event. event_info['attendees'].each do |key, attendee| next unless user_href.include?(attendee['href']) event_info['attendees'][key]['instances'] = { 'master' => { 'id' => 'master', 'partstat' => 'DECLINED' } } end end base_calendar = old_calendar end if user_href.include?(event_info['organizer']) return parse_event_for_organizer(base_calendar, event_info, old_event_info) elsif old_calendar # We need to figure out if the user is an attendee, but we're only # doing so if there's an oldCalendar, because we only want to # process updates, not creation of new events. event_info['attendees'].each do |_, attendee| if user_href.include?(attendee['href']) return parse_event_for_attendee(base_calendar, event_info, old_event_info, attendee['href']) end end end [] end |
#process_message(itip_message, existing_object = nil) ⇒ VCalendar?
This method is used to process an incoming itip message.
Examples:
-
A user is an attendee to an event. The organizer sends an updated
meeting using a new iTip message with METHOD:REQUEST. This function will process the message and update the attendee’s event accordingly.
-
The organizer cancelled the event using METHOD:CANCEL. We will update
the users event to state STATUS:CANCELLED.
-
An attendee sent a reply to an invite using METHOD:REPLY. We can
update the organizers event to update the ATTENDEE with its correct PARTSTAT.
The existing_object is updated in-place. If there is no existing object (because it’s a new invite for example) a new object will be created.
If an existing object does not exist, and the method was CANCEL or REPLY, the message effectively gets ignored, and no ‘existingObject’ will be created.
The updated existing_object is also returned from this function.
If the iTip message was not supported, we will always return false.
85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/tilia/v_object/i_tip/broker.rb', line 85 def (, existing_object = nil) # We only support events at the moment. return false unless .component == 'VEVENT' case .method when 'REQUEST' (, existing_object) when 'CANCEL' (, existing_object) when 'REPLY' (, existing_object) end end |