Skip to content

Instantly share code, notes, and snippets.

@rubypirate
Created September 29, 2016 11:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rubypirate/8946bf4a6b8b1b045622a292c86e35a7 to your computer and use it in GitHub Desktop.
Save rubypirate/8946bf4a6b8b1b045622a292c86e35a7 to your computer and use it in GitHub Desktop.
module EwsCore
def ews_watch
if params["Envelope"]
cal_ids = []
subscription_id = find_all_values_for(params, 'SubscriptionId').first
if subscription_id
exchange_subscription = Exchange::Subscription.where(subscription_id: subscription_id).first
if exchange_subscription
exchange_subscription.update_attributes(push_count: exchange_subscription.push_count.to_i+1, last_push: Time.now)
cal = exchange_subscription.cal
if cal.ews_email && cal.ews_email != ''
EwsGetCalJob.perform_async(cal.id)
end
end
end
######## this is important because if we didn't respond OK EWS is not going to move the que
render text: %{<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope">
<soap:Body>
<SendNotificationResult xmlns="http://schemas.microsoft.com/exchange/services/2006/messages">
<SubscriptionStatus>OK</SubscriptionStatus>
</SendNotificationResult>
</soap:Body>
</soap:Envelope>}
else
render text: ''
end
end
# returns an array of folders ids
def ews_folder_ids params
if params['Envelope'] && params['Envelope']['Body'] &&
params['Envelope']['Body']['SendNotification'] &&
params['Envelope']['Body']['SendNotification']['ResponseMessages'] &&
params['Envelope']['Body']['SendNotification']['ResponseMessages']['SendNotificationResponseMessage'] &&
params['Envelope']['Body']['SendNotification']['ResponseMessages']['SendNotificationResponseMessage']['ResponseClass'] == 'Success' &&
params['Envelope']['Body']['SendNotification']['ResponseMessages']['SendNotificationResponseMessage']['Notification']
notification = params['Envelope']['Body']['SendNotification']['ResponseMessages']['SendNotificationResponseMessage']['Notification']
all_events = {}
folder_ids = []
if notification['CreatedEvent'] && notification['CreatedEvent'].any?
folder_ids << notification['CreatedEvent']['ParentFolderId']['Id']
#all_events['created_events'] = notification['CreatedEvent'].map {|event| event }
end
if notification['ModifiedEvent'] && notification['ModifiedEvent'].any?
folder_ids << notification['ModifiedEvent']['ParentFolderId']['Id']
#all_events['modified_events'] = notification['ModifiedEvent'].map {|event| event }
end
if notification['DeletedEvent'] && notification['DeletedEvent'].any?
folder_ids << notification['DeletedEvent']['ParentFolderId']['Id']
#all_events['deleted_events'] = notification['DeletedEvent'].map {|event| event }
end
#return all_events
return folder_ids.uniq
end
return false
end
# returns a hash of created_events, modified_events and deleted_events
def ews_extract_events params
if params['Envelope'] && params['Envelope']['Body'] &&
params['Envelope']['Body']['SendNotification'] &&
params['Envelope']['Body']['SendNotification']['ResponseMessages'] &&
params['Envelope']['Body']['SendNotification']['ResponseMessages']['SendNotificationResponseMessage'] &&
params['Envelope']['Body']['SendNotification']['ResponseMessages']['SendNotificationResponseMessage']['ResponseClass'] == 'Success' &&
params['Envelope']['Body']['SendNotification']['ResponseMessages']['SendNotificationResponseMessage']['Notification']
notification = params['Envelope']['Body']['SendNotification']['ResponseMessages']['SendNotificationResponseMessage']['Notification']
all_events = {}
if notification['CreatedEvent'] && notification['CreatedEvent'].any?
all_events['created_events'] = notification['CreatedEvent'].map {|event| event }
end
if notification['ModifiedEvent'] && notification['ModifiedEvent'].any?
all_events['modified_events'] = notification['ModifiedEvent'].map {|event| event }
end
if notification['DeletedEvent'] && notification['DeletedEvent'].any?
all_events['deleted_events'] = notification['DeletedEvent'].map {|event| event }
end
return all_events
end
return false
end
# returns push subscription request confirmation watermark
def ews_subscription_confirmation_watermark params
if params['Envelope'] && params['Envelope']['Body'] &&
params['Envelope']['Body']['SendNotification'] &&
params['Envelope']['Body']['SendNotification']['ResponseMessages'] &&
params['Envelope']['Body']['SendNotification']['ResponseMessages']['SendNotificationResponseMessage'] &&
params['Envelope']['Body']['SendNotification']['ResponseMessages']['SendNotificationResponseMessage']['ResponseClass'] == 'Success' &&
params['Envelope']['Body']['SendNotification']['ResponseMessages']['SendNotificationResponseMessage']['Notification'] &&
params['Envelope']['Body']['SendNotification']['ResponseMessages']['SendNotificationResponseMessage']['Notification'] &&
params['Envelope']['Body']['SendNotification']['ResponseMessages']['SendNotificationResponseMessage']['Notification']['StatusEvent'] &&
params['Envelope']['Body']['SendNotification']['ResponseMessages']['SendNotificationResponseMessage']['Notification']['StatusEvent']['Watermark']
return params['Envelope']['Body']['SendNotification']['ResponseMessages']['SendNotificationResponseMessage']['Notification']['StatusEvent']['Watermark']
end
return false
end
def subscribe_to_calendar(cal)
client = cal.company.base_company.conf_connection.init_viewpoint_client(cal.ews_email) if cal.company.base_company.conf_connection
return [] unless client
# delete existing subscription if it's old enough
if cal.exchange_subscription
cal.exchange_subscription.destroy if cal.exchange_subscription.last_push && (cal.exchange_subscription.last_push <= (Time.now - 2.days))
end
if cal.company && cal.company.conf_connection && cal.company.conf_connection.ews_impersonation?
calendar_folder = client.get_folder(:calendar)
else
calendar_folder = client.get_folder(:calendar, opts = {act_as: ews_email})
end
if calendar_folder && calendar_folder.id && !calendar_folder.id.empty?
subscription_response = client.ews.push_subscribe_folder(
{id: calendar_folder.id, change_key: calendar_folder.change_key},
%w{CopiedEvent CreatedEvent DeletedEvent MovedEvent}, "https://#{get_domain}/ews_watch", 1)
if subscription_response && subscription_response.response_messages && subscription_response.response_messages.any?
ex_sub = cal.exchange_subscription ? cal.exchange_subscription : Exchange::Subscription.new
ex_sub.subscription_id = subscription_response.response_messages.first.subscription_id
ex_sub.folder_id = calendar_folder.id
ex_sub.cal_id = cal.id
ex_sub.save!
end
end
end
### client.get_user_availability works fine directly or as a delegate
def ews_busy cal
return nil if cal.ews_email.blank? || !cal.company.base_company.conf_connection
base_conn = cal.company.base_company.conf_connection
if base_conn.email && base_conn.email["ews"] && base_conn.email["ews"]["last_sync"] && base_conn.email["ews"]["last_sync"] != ''
cache_time_in_seconds = Rails.env.development? ? (Time.now-5) : (Time.now-10)
conf_last_sync = base_conn.email["ews"]["last_sync"].to_datetime
end
### initialize EWS client
ignore_impersonation = base_conn.email["ews"]["ignore_impersonation_for_user_availability"]
client = base_conn.init_viewpoint_client(cal.ews_email, ignore_impersonation) if base_conn
out = ""
if client
step = base_conn.ews_availability_range
(-base_conn.ews_days_in_past).step(base_conn.ews_days_in_future, step) do |start_day|
start_time = (Time.now + start_day.days).utc.iso8601
end_day = start_day + step
end_day = base_conn.ews_days_in_future if end_day > base_conn.ews_days_in_future
end_time = end_day.days.from_now.utc.iso8601
time_zone_opts = {:bias => base_conn.email['ews']['time_zone_bias'].to_i, :standard_time => {:bias => 0},
:daylight_time => {:bias => (base_conn.ews_do_daylight_saving? ? -60 : 0)}}
Rails.logger.info "Params for EWS call: ews_busy"
Rails.logger.info [[cal.ews_email], ({start_time: start_time, end_time: end_time, requested_view: :detailed, time_zone: time_zone_opts})]
begin
busy_times = client.get_user_availability([cal.ews_email], start_time: start_time, end_time: end_time, requested_view: :detailed, time_zone: time_zone_opts)
rescue => error
if Rails.env.production?
# catch errors and only tell airbrake
Rails.logger.info 'Error - ews_busy'
Rails.logger.info error
Airbrake.notify(error,
{:backtrace => error.backtrace,
:error_class => error.class,
:error_message => error.message,
:parameters => {:username => client.username, :ews_email => cal.ews_email}
}
)
else
raise error
end
return ""
end
Rails.logger.info "EWS Response:"
Rails.logger.info busy_times.inspect
begin
busy_times.calendar_event_array.each do |event|
Rails.logger.info "EWS Event:"
Rails.logger.info event.inspect
if event[:calendar_event][:elems][2] &&
event[:calendar_event][:elems][2][:busy_type] &&
event[:calendar_event][:elems][2][:busy_type][:text].present? &&
event[:calendar_event][:elems][2][:busy_type][:text] == "Free"
next
end
if base_conn.skip_tentative? && event[:calendar_event][:elems][2] &&
event[:calendar_event][:elems][2][:busy_type] &&
event[:calendar_event][:elems][2][:busy_type][:text].present? &&
event[:calendar_event][:elems][2][:busy_type][:text] == "Tentative"
next
end
if event[:calendar_event][:elems][3] && event[:calendar_event][:elems][3][:calendar_event_details][:elems] && event[:calendar_event][:elems][3][:calendar_event_details][:elems][1] && event[:calendar_event][:elems][3][:calendar_event_details][:elems][1][:subject]
subject = event[:calendar_event][:elems][3][:calendar_event_details][:elems][1][:subject][:text].to_s.gsub(/\n/, " ")
else
subject = 'Blocked'
end
if subject.include? "BBID:"
next
id = subject.split(" - ")[0][5..-1]
space = Space.find_by_id(id)
if space && space.slot && space.slot.person_id
person = Person.where(cal_id: cal.id).first
next if person && (space.slot.person_id == person.id)
end
end
if subject.include? "BBEID:"
next
id = subject.split(" - ")[0][6..-1]
session = Session.find_by_id(id)
if session && session.person_id
person = Person.where(cal_id: cal.id).first
next if person && (session.person_id == person.id)
end
end
if [1, 2].include?(base_conn.email["ews"]["ignore_daylight_saving"])
if base_conn.ews_do_daylight_saving?
offset = -60.minutes
else
offset = 0.minutes
end
else
### auto detect
offset = Time.parse(client.event_start_time(event)).isdst ? -60.minutes : 0.minutes
end
d1 = client.event_start_time(event).to_datetime+offset
d2 = client.event_end_time(event).to_datetime+offset
out += d1.utc.strftime("%Y%m%dT%H%M") + "-" + d2.utc.strftime("%Y%m%dT%H%M") + "\n"
out += "-" + subject + "\n"
end
rescue => error
if Rails.env.production?
Rails.logger.info "EWS Error - ews_busy"
Rails.logger.info error.inspect
# catch errors and only tell airbrake
Airbrake.notify(error,
{:backtrace => error.backtrace,
:error_class => error.class,
:error_message => error.message,
:parameters =>([[cal.ews_email], ({start_time: start_time, end_time:end_time, requested_view: :detailed, time_zone: time_zone_opts})])}
)
else
Rails.logger.info "EWS Response2:"
Rails.logger.info out.inspect
end
return ""
end
end
return out
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment